]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/mfd/twl-core.c
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[karo-tx-linux.git] / drivers / mfd / twl-core.c
index f462ff226c8d2df8bf8908223935b1151c1e09eb..4ae6423202058c0e1e7d7c9c262b8c25fd38d917 100644 (file)
@@ -46,8 +46,6 @@
 #include <linux/i2c.h>
 #include <linux/i2c/twl.h>
 
-#include <plat/cpu.h>
-
 #include "twl-core.h"
 
 /*
 
 #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*/
 
 #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
@@ -554,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,
@@ -671,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);
@@ -679,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);
@@ -687,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);
@@ -695,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
@@ -711,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",
@@ -725,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 =
@@ -767,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 =
@@ -815,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);
@@ -829,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),
@@ -852,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))
@@ -907,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);
@@ -941,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);
@@ -1015,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))
@@ -1023,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);
@@ -1082,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,
@@ -1134,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");
@@ -1149,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;
@@ -1222,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
@@ -1234,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) {
@@ -1285,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) {
@@ -1294,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 */
@@ -1335,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;
 }