Chinaunix首页 | 论坛 | 博客
  • 博客访问: 203225
  • 博文数量: 68
  • 博客积分: 529
  • 博客等级: 中士
  • 技术积分: 721
  • 用 户 组: 普通用户
  • 注册时间: 2007-08-10 16:38
文章分类

全部博文(68)

文章存档

2014年(2)

2013年(4)

2012年(16)

2011年(34)

2010年(4)

2009年(8)

分类: LINUX

2011-09-05 17:18:31

1) 在board-4430sdp.c 定义了twl6030 的i2c board info
 

    {
        I2C_BOARD_INFO("twl6030", 0x48),
        .flags = I2C_CLIENT_WAKE,
        .irq = OMAP44XX_IRQ_SYS_1N,
        .platform_data = &sdp4430_twldata,
    },


    定义sdp4430_twldata 为 如下所示

static struct twl4030_platform_data sdp4430_twldata = {
    .irq_base    = TWL6030_IRQ_BASE,
    .irq_end    = TWL6030_IRQ_END,

    /* Regulators */
    .vmmc        = &sdp4430_vmmc,
    .vpp        = &sdp4430_vpp,
    .vusim        = &sdp4430_vusim,
    .vana        = &sdp4430_vana,
    .vcxio        = &sdp4430_vcxio,
    .vdac        = &sdp4430_vdac,
    .vusb        = &sdp4430_vusb,
    .vaux1        = &sdp4430_vaux1,
    .vaux2        = &sdp4430_vaux2,
    .vaux3        = &sdp4430_vaux3,
    .usb        = &omap4_usbphy_data,
    .clk32kg = &sdp4430_clk32kg,
    .madc = &sdp4430_gpadc_data,
    .bci = &sdp4430_bci_data,

    /* children */
    .codec = &twl6040_codec,
};

所有这些数据将在函数omap4_i2c_init 中被注册。

2) 在twl-core.c中,将设置时钟, 并init Interrupt,最后调用add_children 创建

    各个子模块的设备。 

static int
add_children(struct twl4030_platform_data *pdata, unsigned long features)
{
    struct device    *child;
    unsigned sub_chip_id;

    if (twl_has_gpio() && pdata->gpio) {
        child = add_child(SUB_CHIP_ID1, "twl4030_gpio",
                pdata->gpio, sizeof(*pdata->gpio),
                false, pdata->irq_base + GPIO_INTR_OFFSET, 0);
        if (IS_ERR(child))
            return PTR_ERR(child);
    }

    if (twl_has_keypad() && pdata->keypad) {
        child = add_child(SUB_CHIP_ID2, "twl4030_keypad",
                pdata->keypad, sizeof(*pdata->keypad),
                true, pdata->irq_base + KEYPAD_INTR_OFFSET, 0);
        if (IS_ERR(child))
            return PTR_ERR(child);
    }
        if (twl_has_bci() && pdata->bci &&
            !(features & (TPS_SUBSET | TWL5031))) {
            child = add_child(3, "twl4030_bci",
            pdata->bci, sizeof(*pdata->bci),
            false,
            /* irq0 = CHG_PRES, irq1 = BCI */
            pdata->irq_base + BCI_PRES_INTR_OFFSET,
            pdata->irq_base + BCI_INTR_OFFSET);
            if (IS_ERR(child))
                return PTR_ERR(child);
        }
    if (twl_has_bci() && pdata->bci &&
     (features & TWL6030_CLASS)) {
        child = add_child(1, "twl6030_bci",
                pdata->bci, sizeof(*pdata->bci),
                false,
                pdata->irq_base + CHARGER_INTR_OFFSET,
                pdata->irq_base + CHARGERFAULT_INTR_OFFSET);
    }


    if (twl_has_madc() && pdata->madc && twl_class_is_4030()) {
        child = add_child(2, "twl4030_madc",
                pdata->madc, sizeof(*pdata->madc),
                true, pdata->irq_base + MADC_INTR_OFFSET, 0);
        if (IS_ERR(child))
            return PTR_ERR(child);
    }

    if (twl_has_madc() && pdata->madc && twl_class_is_6030()) {
        child = add_child(1, "twl6030_gpadc",
                pdata->madc, sizeof(*pdata->madc),
                true, pdata->irq_base + MADC_INTR_OFFSET,
                pdata->irq_base + GPADCSW_INTR_OFFSET);
        if (IS_ERR(child))
            return PTR_ERR(child);
    }

    if (twl_has_rtc()) {
        /*
         * REVISIT platform_data here currently might expose the
         * "msecure" line ... but for now we just expect board
         * setup to tell the chip "it's always ok to SET_TIME".
         * Eventually, Linux might become more aware of such
         * HW security concerns, and "least privilege".
         */

        sub_chip_id = twl_map[TWL_MODULE_RTC].sid;
        child = add_child(sub_chip_id, "twl_rtc",
                NULL, 0,
                true, pdata->irq_base + RTC_INTR_OFFSET, 0);
        if (IS_ERR(child))
            return PTR_ERR(child);
    }

    if (twl_has_usb() && pdata->usb && twl_class_is_4030()) {

        static struct regulator_consumer_supply usb1v5 = {
            .supply =    "usb1v5",
        };
        static struct regulator_consumer_supply usb1v8 = {
            .supply =    "usb1v8",
        };
        static struct regulator_consumer_supply usb3v1 = {
            .supply =    "usb3v1",
        };

    /* First add the regulators so that they can be used by transceiver */
        if (twl_has_regulator()) {
            /* this is a template that gets copied */
            struct regulator_init_data usb_fixed = {
                .constraints.valid_modes_mask =
                    REGULATOR_MODE_NORMAL
                    | REGULATOR_MODE_STANDBY,
                .constraints.valid_ops_mask =
                    REGULATOR_CHANGE_MODE
                    | REGULATOR_CHANGE_STATUS,
            };

            child = add_regulator_linked(TWL4030_REG_VUSB1V5,
                         &usb_fixed, &usb1v5, 1);
            if (IS_ERR(child))
                return PTR_ERR(child);

            child = add_regulator_linked(TWL4030_REG_VUSB1V8,
                         &usb_fixed, &usb1v8, 1);
            if (IS_ERR(child))
                return PTR_ERR(child);

            child = add_regulator_linked(TWL4030_REG_VUSB3V1,
                         &usb_fixed, &usb3v1, 1);
            if (IS_ERR(child))
                return PTR_ERR(child);

        }

        child = add_child(0, "twl4030_usb",
                pdata->usb, sizeof(*pdata->usb),
                true,
                /* irq0 = USB_PRES, irq1 = USB */
                pdata->irq_base + USB_PRES_INTR_OFFSET,
                pdata->irq_base + USB_INTR_OFFSET);

        if (IS_ERR(child))
            return PTR_ERR(child);

        /* we need to connect regulators to this transceiver */
        if (twl_has_regulator() && child) {
            usb1v5.dev = child;
            usb1v8.dev = child;
            usb3v1.dev = child;
        }
    }
    if (twl_has_usb() && pdata->usb && twl_class_is_6030()) {

        static struct regulator_consumer_supply usb3v3 = {
            .supply =    "vusb",
        };

        if (twl_has_regulator()) {
            /* this is a template that gets copied */
            struct regulator_init_data usb_fixed = {
                .constraints.valid_modes_mask =
                    REGULATOR_MODE_NORMAL
                    | REGULATOR_MODE_STANDBY,
                .constraints.valid_ops_mask =
                    REGULATOR_CHANGE_MODE
                    | REGULATOR_CHANGE_STATUS,
            };

            child = add_regulator_linked(TWL6030_REG_VUSB,
                         &usb_fixed, &usb3v3, 1);
            if (IS_ERR(child))
                return PTR_ERR(child);
        }

        child = add_child(0, "twl6030_usb",
            pdata->usb, sizeof(*pdata->usb),
            true,
            /* irq1 = VBUS_PRES, irq0 = USB ID */
            pdata->irq_base + USBOTG_INTR_OFFSET,
            pdata->irq_base + USB_PRES_INTR_OFFSET);

        if (IS_ERR(child))
            return PTR_ERR(child);
        /* we need to connect regulators to this transceiver */
        if (twl_has_regulator() && child)
            usb3v3.dev = child;

    }

    if (twl_has_watchdog()) {
        child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0);
        if (IS_ERR(child))
            return PTR_ERR(child);
    }

    if (twl4030_has_pwrbutton()) {
        child = add_child(1, "twl4030_pwrbutton",
                NULL, 0, true, pdata->irq_base + 8 + 0, 0);
        if (IS_ERR(child))
            return PTR_ERR(child);
    }

    if (twl6030_has_pwrbutton()) {
        child = add_child(1, "twl6030_pwrbutton",
                NULL, 0, true, pdata->irq_base, 0);
        if (IS_ERR(child))
            return PTR_ERR(child);
    }

    if (twl_has_codec() && pdata->codec && twl_class_is_4030()) {
        sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
        child = add_child(sub_chip_id, "twl4030-audio",
                pdata->codec, sizeof(*pdata->codec),
                false, 0, 0);
        if (IS_ERR(child))
            return PTR_ERR(child);
    }

    /* Phoenix codec driver is probed directly atm */
    if (twl_has_codec() && pdata->codec && twl_class_is_6030()) {
        sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
        child = add_child(sub_chip_id, "twl6040_audio",
                pdata->codec, sizeof(*pdata->codec),
                false, 0, 0);
        if (IS_ERR(child))
            return PTR_ERR(child);
    }

    /* twl4030 regulators */
    if (twl_has_regulator() && twl_class_is_4030()) {
        child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL4030_REG_VIO, pdata->vio);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL4030_REG_VDAC, pdata->vdac);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator((features & TWL4030_VAUX2)
                    ? TWL4030_REG_VAUX2_4030
                    : TWL4030_REG_VAUX2,
                pdata->vaux2);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig);
        if (IS_ERR(child))
            return PTR_ERR(child);
    }

    /* maybe add LDOs that are omitted on cost-reduced parts */
    if (twl_has_regulator() && !(features & TPS_SUBSET)
     && twl_class_is_4030()) {
        child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL4030_REG_VSIM, pdata->vsim);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL6030_REG_CLK32KG, pdata->clk32kg);
        if (IS_ERR(child))
            return PTR_ERR(child);
    }

    /* twl6030 regulators */
    if (twl_has_regulator() && twl_class_is_6030()) {
        child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL6030_REG_VPP, pdata->vpp);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL6030_REG_VUSIM, pdata->vusim);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL6030_REG_VANA, pdata->vana);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL6030_REG_VCXIO, pdata->vcxio);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL6030_REG_VDAC, pdata->vdac);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL6030_REG_VAUX2_6030, pdata->vaux2);
        if (IS_ERR(child))
            return PTR_ERR(child);

        child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3);
        if (IS_ERR(child))
            return PTR_ERR(child);
    }

    return 0;
}


 

3)   batter driver

 在TWL4030_bci_battery.c 中,在函数twl4030_bci_battery_probe 中注册四种类型的电池, 分别是主电池,备份电池和usb 电池和AC电池。

 主电池的定义
 di->dev = &pdev->dev;
 di->bat.name = "twl4030_bci_battery";
 di->bat.supplied_to = twl4030_bci_supplied_to;
 di->bat.num_supplicants = ARRAY_SIZE(twl4030_bci_supplied_to);
 di->bat.type = POWER_SUPPLY_TYPE_BATTERY;
 di->bat.properties = twl4030_bci_battery_props;
 di->bat.num_properties = ARRAY_SIZE(twl4030_bci_battery_props);
 di->bat.get_property = twl4030_bci_battery_get_property;
 di->bat.external_power_changed =
   twl4030_bci_battery_external_power_changed;

 di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;

 

 备份电池的定义

 di->bk_bat.name = "twl4030_bci_bk_battery";
 di->bk_bat.type = POWER_SUPPLY_TYPE_BATTERY;
 di->bk_bat.properties = twl4030_bk_bci_battery_props;
 di->bk_bat.num_properties = ARRAY_SIZE(twl4030_bk_bci_battery_props);
 di->bk_bat.get_property = twl4030_bk_bci_battery_get_property;
 di->bk_bat.external_power_changed = NULL;

 /*
  * Android expects a battery type POWER_SUPPLY_TYPE_USB
  * as a usb charger battery. This battery
  * and its "online" property are used to determine if the
  * usb cable is plugged in or not.
  */

 usb 电池的定义
 di->usb_bat.name = "twl4030_bci_usb_src";
 di->usb_bat.supplied_to = twl4030_bci_supplied_to;
 di->usb_bat.type = POWER_SUPPLY_TYPE_USB;
 di->usb_bat.properties = twl4030_usb_battery_props;
 di->usb_bat.num_properties = ARRAY_SIZE(twl4030_usb_battery_props);
 di->usb_bat.get_property = twl4030_usb_battery_get_property;
 di->usb_bat.external_power_changed = NULL;

 AC 电池的定义

 di->ac.name = "twl6030_ac";
 di->ac.type = POWER_SUPPLY_TYPE_MAINS;
 di->ac.properties = twl6030_ac_props;
 di->ac.num_properties = ARRAY_SIZE(twl6030_ac_props);
 di->ac.get_property = twl6030_ac_get_property;

 /* REVISIT do we need to request both IRQs ?? */

 注册主电池

 ret = power_supply_register(&pdev->dev, &di->bat);
 if (ret) {
  dev_dbg(&pdev->dev, "failed to register main battery\n");
  goto batt_failed;
 }

 INIT_DELAYED_WORK_DEFERRABLE(&di->twl4030_bci_monitor_work,
    twl4030_bci_battery_work);
 schedule_delayed_work(&di->twl4030_bci_monitor_work, 0);

注册备份电池

 ret = power_supply_register(&pdev->dev, &di->bk_bat);
 if (ret) {
  dev_dbg(&pdev->dev, "failed to register backup battery\n");
  goto bk_batt_failed;
 }

 INIT_DELAYED_WORK_DEFERRABLE(&di->twl4030_bk_bci_monitor_work,
    twl4030_bk_bci_battery_work);
 schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 500);

 注册usb 电池

 ret = power_supply_register(&pdev->dev, &di->usb_bat);
 if (ret) {
  dev_dbg(&pdev->dev, "failed to register usb battery\n");
  goto usb_batt_failed;
 }

 di->nb.notifier_call = twl4030battery_charger_event;
 ret = otg_register_notifier(otg_get_transceiver(), &di->nb);
 if (ret) {
  dev_dbg(&pdev->dev, "failed to register usb battery\n");
  goto otg_notify_failed;
 }

注册AC电池

 ret = power_supply_register(&pdev->dev, &di->ac);
 if (ret) {
  dev_dbg(&pdev->dev, "failed to register ac power supply\n");
  goto ac_failed;
 }

3.1 主电池分析:

 

POWER_SUPPLY_PROP_STATUS: 充电状态

enum {
    POWER_SUPPLY_STATUS_UNKNOWN = 0,
    POWER_SUPPLY_STATUS_CHARGING,
    POWER_SUPPLY_STATUS_DISCHARGING,
    POWER_SUPPLY_STATUS_NOT_CHARGING,
    POWER_SUPPLY_STATUS_FULL,
};

POWER_SUPPLY_PROP_ONLINE: 充电源 

enum power_supply_type {
    POWER_SUPPLY_TYPE_BATTERY = 0,
    POWER_SUPPLY_TYPE_UPS,
    POWER_SUPPLY_TYPE_MAINS,
    POWER_SUPPLY_TYPE_USB,        /* Standard Downstream Port */
    POWER_SUPPLY_TYPE_USB_DCP,    /* Dedicated Charging Port */
    POWER_SUPPLY_TYPE_USB_CDP,    /* Charging Downstream Port */
    POWER_SUPPLY_TYPE_USB_ACA,    /* Accessory Charger Adapters */
};

目前只支持 USB和AC

POWER_SUPPLY_PROP_VOLTAGE_NOW:  充电电压 通过ADC channel 7 获取既VBAT

POWER_SUPPLY_PROP_CURRENT_NOW : 充电电流  通过GASGAUGE 获取。

POWER_SUPPLY_PROP_TEMP        : 充电温度

POWER_SUPPLY_PROP_CURRENT_AVG : 平均电流

POWER_SUPPLY_PROP_HEALTH      : 电池健康状态

POWER_SUPPLY_PROP_CAPACITY    : 电池容量

 

 

AC 电池分析:

POWER_SUPPLY_PROP_ONLINE

POWER_SUPPLY_PROP_VOLTAGE_NOW  :通过ADC channel 9 获取

 

BackupBattery 电池分析:

POWER_SUPPLY_PROP_VOLTAGE_NOW :  备份电池的电压

 

 

 

 

 

 

 

 


 

阅读(1335) | 评论(0) | 转发(0) |
0

上一篇:omap4430 mem

下一篇:omap4430 cpuidle

给主人留下些什么吧!~~