diff options
Diffstat (limited to 'drivers/mfd/twl-core.c')
-rw-r--r-- | drivers/mfd/twl-core.c | 210 |
1 files changed, 94 insertions, 116 deletions
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 1c32afed28a..4ae64232020 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -63,70 +63,6 @@ #define DRIVER_NAME "twl" -#if defined(CONFIG_KEYBOARD_TWL4030) || defined(CONFIG_KEYBOARD_TWL4030_MODULE) -#define twl_has_keypad() true -#else -#define twl_has_keypad() false -#endif - -#if defined(CONFIG_GPIO_TWL4030) || defined(CONFIG_GPIO_TWL4030_MODULE) -#define twl_has_gpio() true -#else -#define twl_has_gpio() false -#endif - -#if defined(CONFIG_REGULATOR_TWL4030) \ - || defined(CONFIG_REGULATOR_TWL4030_MODULE) -#define twl_has_regulator() true -#else -#define twl_has_regulator() false -#endif - -#if defined(CONFIG_TWL4030_MADC) || defined(CONFIG_TWL4030_MADC_MODULE) -#define twl_has_madc() true -#else -#define twl_has_madc() false -#endif - -#ifdef CONFIG_TWL4030_POWER -#define twl_has_power() true -#else -#define twl_has_power() false -#endif - -#if defined(CONFIG_RTC_DRV_TWL4030) || defined(CONFIG_RTC_DRV_TWL4030_MODULE) -#define twl_has_rtc() true -#else -#define twl_has_rtc() false -#endif - -#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE) ||\ - defined(CONFIG_TWL6030_USB) || defined(CONFIG_TWL6030_USB_MODULE) -#define twl_has_usb() true -#else -#define twl_has_usb() false -#endif - -#if defined(CONFIG_TWL4030_WATCHDOG) || \ - defined(CONFIG_TWL4030_WATCHDOG_MODULE) -#define twl_has_watchdog() true -#else -#define twl_has_watchdog() false -#endif - -#if defined(CONFIG_MFD_TWL4030_AUDIO) || \ - defined(CONFIG_MFD_TWL4030_AUDIO_MODULE) -#define twl_has_codec() true -#else -#define twl_has_codec() false -#endif - -#if defined(CONFIG_CHARGER_TWL4030) || defined(CONFIG_CHARGER_TWL4030_MODULE) -#define twl_has_bci() true -#else -#define twl_has_bci() false -#endif - /* Triton Core internal information (BEGIN) */ /* Last - for index max*/ @@ -134,13 +70,6 @@ #define TWL_NUM_SLAVES 4 -#if defined(CONFIG_INPUT_TWL4030_PWRBUTTON) \ - || defined(CONFIG_INPUT_TWL4030_PWRBUTTON_MODULE) -#define twl_has_pwrbutton() true -#else -#define twl_has_pwrbutton() false -#endif - #define SUB_CHIP_ID0 0 #define SUB_CHIP_ID1 1 #define SUB_CHIP_ID2 2 @@ -552,6 +481,38 @@ int twl_get_version(void) } EXPORT_SYMBOL_GPL(twl_get_version); +/** + * twl_get_hfclk_rate - API to get TWL external HFCLK clock rate. + * + * Api to get the TWL HFCLK rate based on BOOT_CFG register. + */ +int twl_get_hfclk_rate(void) +{ + u8 ctrl; + int rate; + + twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &ctrl, R_CFG_BOOT); + + switch (ctrl & 0x3) { + case HFCLK_FREQ_19p2_MHZ: + rate = 19200000; + break; + case HFCLK_FREQ_26_MHZ: + rate = 26000000; + break; + case HFCLK_FREQ_38p4_MHZ: + rate = 38400000; + break; + default: + pr_err("TWL4030: HFCLK is not configured\n"); + rate = -EINVAL; + break; + } + + return rate; +} +EXPORT_SYMBOL_GPL(twl_get_hfclk_rate); + static struct device * add_numbered_child(unsigned chip, const char *name, int num, void *pdata, unsigned pdata_len, @@ -669,7 +630,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, struct device *child; unsigned sub_chip_id; - if (twl_has_gpio() && pdata->gpio) { + if (IS_ENABLED(CONFIG_GPIO_TWL4030) && pdata->gpio) { child = add_child(SUB_CHIP_ID1, "twl4030_gpio", pdata->gpio, sizeof(*pdata->gpio), false, irq_base + GPIO_INTR_OFFSET, 0); @@ -677,7 +638,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); } - if (twl_has_keypad() && pdata->keypad) { + if (IS_ENABLED(CONFIG_KEYBOARD_TWL4030) && pdata->keypad) { child = add_child(SUB_CHIP_ID2, "twl4030_keypad", pdata->keypad, sizeof(*pdata->keypad), true, irq_base + KEYPAD_INTR_OFFSET, 0); @@ -685,7 +646,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); } - if (twl_has_madc() && pdata->madc) { + if (IS_ENABLED(CONFIG_TWL4030_MADC) && pdata->madc) { child = add_child(2, "twl4030_madc", pdata->madc, sizeof(*pdata->madc), true, irq_base + MADC_INTR_OFFSET, 0); @@ -693,7 +654,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); } - if (twl_has_rtc()) { + if (IS_ENABLED(CONFIG_RTC_DRV_TWL4030)) { /* * REVISIT platform_data here currently might expose the * "msecure" line ... but for now we just expect board @@ -709,7 +670,15 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); } - if (twl_has_usb() && pdata->usb && twl_class_is_4030()) { + if (IS_ENABLED(CONFIG_PWM_TWL6030) && twl_class_is_6030()) { + child = add_child(TWL6030_MODULE_ID1, "twl6030-pwm", NULL, 0, + false, 0, 0); + if (IS_ERR(child)) + return PTR_ERR(child); + } + + if (IS_ENABLED(CONFIG_TWL4030_USB) && pdata->usb && + twl_class_is_4030()) { static struct regulator_consumer_supply usb1v5 = { .supply = "usb1v5", @@ -723,7 +692,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, }; /* First add the regulators so that they can be used by transceiver */ - if (twl_has_regulator()) { + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030)) { /* this is a template that gets copied */ struct regulator_init_data usb_fixed = { .constraints.valid_modes_mask = @@ -765,18 +734,19 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); /* we need to connect regulators to this transceiver */ - if (twl_has_regulator() && child) { + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && child) { usb1v5.dev_name = dev_name(child); usb1v8.dev_name = dev_name(child); usb3v1[0].dev_name = dev_name(child); } } - if (twl_has_usb() && pdata->usb && twl_class_is_6030()) { + if (IS_ENABLED(CONFIG_TWL6030_USB) && pdata->usb && + twl_class_is_6030()) { static struct regulator_consumer_supply usb3v3; int regulator; - if (twl_has_regulator()) { + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030)) { /* this is a template that gets copied */ struct regulator_init_data usb_fixed = { .constraints.valid_modes_mask = @@ -813,9 +783,10 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, if (IS_ERR(child)) return PTR_ERR(child); /* we need to connect regulators to this transceiver */ - if (twl_has_regulator() && child) + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && child) usb3v3.dev_name = dev_name(child); - } else if (twl_has_regulator() && twl_class_is_6030()) { + } else if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && + twl_class_is_6030()) { if (features & TWL6025_SUBCLASS) child = add_regulator(TWL6025_REG_LDOUSB, pdata->ldousb, features); @@ -827,20 +798,21 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); } - if (twl_has_watchdog() && twl_class_is_4030()) { + if (IS_ENABLED(CONFIG_TWL4030_WATCHDOG) && twl_class_is_4030()) { child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0); if (IS_ERR(child)) return PTR_ERR(child); } - if (twl_has_pwrbutton() && twl_class_is_4030()) { + if (IS_ENABLED(CONFIG_INPUT_TWL4030_PWRBUTTON) && twl_class_is_4030()) { child = add_child(1, "twl4030_pwrbutton", NULL, 0, true, irq_base + 8 + 0, 0); if (IS_ERR(child)) return PTR_ERR(child); } - if (twl_has_codec() && pdata->audio && twl_class_is_4030()) { + if (IS_ENABLED(CONFIG_MFD_TWL4030_AUDIO) && pdata->audio && + twl_class_is_4030()) { sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid; child = add_child(sub_chip_id, "twl4030-audio", pdata->audio, sizeof(*pdata->audio), @@ -850,7 +822,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, } /* twl4030 regulators */ - if (twl_has_regulator() && twl_class_is_4030()) { + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_4030()) { child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1, features); if (IS_ERR(child)) @@ -905,7 +877,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, } /* maybe add LDOs that are omitted on cost-reduced parts */ - if (twl_has_regulator() && !(features & TPS_SUBSET) + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && !(features & TPS_SUBSET) && twl_class_is_4030()) { child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2, features); @@ -939,7 +911,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, } /* twl6030 regulators */ - if (twl_has_regulator() && twl_class_is_6030() && + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030() && !(features & TWL6025_SUBCLASS)) { child = add_regulator(TWL6030_REG_VDD1, pdata->vdd1, features); @@ -1013,7 +985,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, } /* 6030 and 6025 share this regulator */ - if (twl_has_regulator() && twl_class_is_6030()) { + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030()) { child = add_regulator(TWL6030_REG_VANA, pdata->vana, features); if (IS_ERR(child)) @@ -1021,7 +993,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, } /* twl6025 regulators */ - if (twl_has_regulator() && twl_class_is_6030() && + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030() && (features & TWL6025_SUBCLASS)) { child = add_regulator(TWL6025_REG_LDO5, pdata->ldo5, features); @@ -1080,7 +1052,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, } - if (twl_has_bci() && pdata->bci && + if (IS_ENABLED(CONFIG_CHARGER_TWL4030) && pdata->bci && !(features & (TPS_SUBSET | TWL5031))) { child = add_child(3, "twl4030_bci", pdata->bci, sizeof(*pdata->bci), false, @@ -1132,12 +1104,7 @@ static void clocks_init(struct device *dev, u32 rate; u8 ctrl = HFCLK_FREQ_26_MHZ; -#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) - if (cpu_is_omap2430()) - osc = clk_get(dev, "osc_ck"); - else - osc = clk_get(dev, "osc_sys_ck"); - + osc = clk_get(dev, "fck"); if (IS_ERR(osc)) { printk(KERN_WARNING "Skipping twl internal clock init and " "using bootloader value (unknown osc rate)\n"); @@ -1147,18 +1114,6 @@ static void clocks_init(struct device *dev, rate = clk_get_rate(osc); clk_put(osc); -#else - /* REVISIT for non-OMAP systems, pass the clock rate from - * board init code, using platform_data. - */ - osc = ERR_PTR(-EIO); - - printk(KERN_WARNING "Skipping twl internal clock init and " - "using bootloader value (unknown osc rate)\n"); - - return; -#endif - switch (rate) { case 19200000: ctrl = HFCLK_FREQ_19p2_MHZ; @@ -1220,10 +1175,23 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct twl4030_platform_data *pdata = client->dev.platform_data; struct device_node *node = client->dev.of_node; + struct platform_device *pdev; int irq_base = 0; int status; unsigned i, num_slaves; + pdev = platform_device_alloc(DRIVER_NAME, -1); + if (!pdev) { + dev_err(&client->dev, "can't alloc pdev\n"); + return -ENOMEM; + } + + status = platform_device_add(pdev); + if (status) { + platform_device_put(pdev); + return status; + } + if (node && !pdata) { /* * XXX: Temporary pdata until the information is correctly @@ -1232,23 +1200,30 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) pdata = devm_kzalloc(&client->dev, sizeof(struct twl4030_platform_data), GFP_KERNEL); - if (!pdata) - return -ENOMEM; + if (!pdata) { + status = -ENOMEM; + goto free; + } } if (!pdata) { dev_dbg(&client->dev, "no platform data?\n"); - return -EINVAL; + status = -EINVAL; + goto free; } + platform_set_drvdata(pdev, pdata); + if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) { dev_dbg(&client->dev, "can't talk I2C?\n"); - return -EIO; + status = -EIO; + goto free; } if (inuse) { dev_dbg(&client->dev, "driver is already in use\n"); - return -EBUSY; + status = -EBUSY; + goto free; } if ((id->driver_data) & TWL6030_CLASS) { @@ -1283,7 +1258,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) inuse = true; /* setup clock framework */ - clocks_init(&client->dev, pdata->clock); + clocks_init(&pdev->dev, pdata->clock); /* read TWL IDCODE Register */ if (twl_id == TWL4030_CLASS_ID) { @@ -1292,7 +1267,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) } /* load power event scripts */ - if (twl_has_power() && pdata->power) + if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata->power) twl4030_power_init(pdata->power); /* Maybe init the T2 Interrupt subsystem */ @@ -1333,6 +1308,9 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) fail: if (status < 0) twl_remove(client); +free: + if (status < 0) + platform_device_unregister(pdev); return status; } |