Merge branches 'for-3.15/upstream-fixes' and 'for-3.16/upstream' into for-linus
[firefly-linux-kernel-4.4.55.git] / drivers / mfd / sec-core.c
index 714e2135210ec2ddc989efcd44f3e800b80f5bcf..1cf27521fff4f2fe4a2892d651b5d47e4721286e 100644 (file)
@@ -26,7 +26,9 @@
 #include <linux/mfd/samsung/core.h>
 #include <linux/mfd/samsung/irq.h>
 #include <linux/mfd/samsung/rtc.h>
+#include <linux/mfd/samsung/s2mpa01.h>
 #include <linux/mfd/samsung/s2mps11.h>
+#include <linux/mfd/samsung/s2mps14.h>
 #include <linux/mfd/samsung/s5m8763.h>
 #include <linux/mfd/samsung/s5m8767.h>
 #include <linux/regmap.h>
@@ -58,6 +60,7 @@ static const struct mfd_cell s5m8767_devs[] = {
                .name = "s5m-rtc",
        }, {
                .name = "s5m8767-clk",
+               .of_compatible = "samsung,s5m8767-clk",
        }
 };
 
@@ -66,21 +69,58 @@ static const struct mfd_cell s2mps11_devs[] = {
                .name = "s2mps11-pmic",
        }, {
                .name = "s2mps11-clk",
+               .of_compatible = "samsung,s2mps11-clk",
        }
 };
 
+static const struct mfd_cell s2mps14_devs[] = {
+       {
+               .name = "s2mps14-pmic",
+       }, {
+               .name = "s2mps14-rtc",
+       }, {
+               .name = "s2mps14-clk",
+               .of_compatible = "samsung,s2mps14-clk",
+       }
+};
+
+static const struct mfd_cell s2mpa01_devs[] = {
+       {
+               .name = "s2mpa01-pmic",
+       },
+};
+
 #ifdef CONFIG_OF
 static struct of_device_id sec_dt_match[] = {
        {       .compatible = "samsung,s5m8767-pmic",
                .data = (void *)S5M8767X,
-       },
-       {       .compatible = "samsung,s2mps11-pmic",
+       }, {
+               .compatible = "samsung,s2mps11-pmic",
                .data = (void *)S2MPS11X,
+       }, {
+               .compatible = "samsung,s2mps14-pmic",
+               .data = (void *)S2MPS14X,
+       }, {
+               .compatible = "samsung,s2mpa01-pmic",
+               .data = (void *)S2MPA01,
+       }, {
+               /* Sentinel */
        },
-       {},
 };
 #endif
 
+static bool s2mpa01_volatile(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case S2MPA01_REG_INT1M:
+       case S2MPA01_REG_INT2M:
+       case S2MPA01_REG_INT3M:
+               return false;
+       default:
+               return true;
+       }
+}
+
 static bool s2mps11_volatile(struct device *dev, unsigned int reg)
 {
        switch (reg) {
@@ -111,6 +151,15 @@ static const struct regmap_config sec_regmap_config = {
        .val_bits = 8,
 };
 
+static const struct regmap_config s2mpa01_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = S2MPA01_REG_LDO_OVCB4,
+       .volatile_reg = s2mpa01_volatile,
+       .cache_type = REGCACHE_FLAT,
+};
+
 static const struct regmap_config s2mps11_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
@@ -120,6 +169,15 @@ static const struct regmap_config s2mps11_regmap_config = {
        .cache_type = REGCACHE_FLAT,
 };
 
+static const struct regmap_config s2mps14_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = S2MPS14_REG_LDODSCH3,
+       .volatile_reg = s2mps11_volatile,
+       .cache_type = REGCACHE_FLAT,
+};
+
 static const struct regmap_config s5m8763_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
@@ -138,9 +196,18 @@ static const struct regmap_config s5m8767_regmap_config = {
        .cache_type = REGCACHE_FLAT,
 };
 
-static const struct regmap_config sec_rtc_regmap_config = {
+static const struct regmap_config s5m_rtc_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+
+       .max_register = SEC_RTC_REG_MAX,
+};
+
+static const struct regmap_config s2mps14_rtc_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
+
+       .max_register = S2MPS_RTC_REG_MAX,
 };
 
 #ifdef CONFIG_OF
@@ -180,24 +247,24 @@ static struct sec_platform_data *sec_pmic_i2c_parse_dt_pdata(
 }
 #endif
 
-static inline int sec_i2c_get_driver_data(struct i2c_client *i2c,
+static inline unsigned long sec_i2c_get_driver_data(struct i2c_client *i2c,
                                                const struct i2c_device_id *id)
 {
 #ifdef CONFIG_OF
        if (i2c->dev.of_node) {
                const struct of_device_id *match;
                match = of_match_node(sec_dt_match, i2c->dev.of_node);
-               return (int)match->data;
+               return (unsigned long)match->data;
        }
 #endif
-       return (int)id->driver_data;
+       return id->driver_data;
 }
 
 static int sec_pmic_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev);
-       const struct regmap_config *regmap;
+       const struct regmap_config *regmap, *regmap_rtc;
        struct sec_pmic_dev *sec_pmic;
        int ret;
 
@@ -229,17 +296,41 @@ static int sec_pmic_probe(struct i2c_client *i2c,
        }
 
        switch (sec_pmic->device_type) {
+       case S2MPA01:
+               regmap = &s2mpa01_regmap_config;
+               /*
+                * The rtc-s5m driver does not support S2MPA01 and there
+                * is no mfd_cell for S2MPA01 RTC device.
+                * However we must pass something to devm_regmap_init_i2c()
+                * so use S5M-like regmap config even though it wouldn't work.
+                */
+               regmap_rtc = &s5m_rtc_regmap_config;
+               break;
        case S2MPS11X:
                regmap = &s2mps11_regmap_config;
+               /*
+                * The rtc-s5m driver does not support S2MPS11 and there
+                * is no mfd_cell for S2MPS11 RTC device.
+                * However we must pass something to devm_regmap_init_i2c()
+                * so use S5M-like regmap config even though it wouldn't work.
+                */
+               regmap_rtc = &s5m_rtc_regmap_config;
+               break;
+       case S2MPS14X:
+               regmap = &s2mps14_regmap_config;
+               regmap_rtc = &s2mps14_rtc_regmap_config;
                break;
        case S5M8763X:
                regmap = &s5m8763_regmap_config;
+               regmap_rtc = &s5m_rtc_regmap_config;
                break;
        case S5M8767X:
                regmap = &s5m8767_regmap_config;
+               regmap_rtc = &s5m_rtc_regmap_config;
                break;
        default:
                regmap = &sec_regmap_config;
+               regmap_rtc = &s5m_rtc_regmap_config;
                break;
        }
 
@@ -252,15 +343,18 @@ static int sec_pmic_probe(struct i2c_client *i2c,
        }
 
        sec_pmic->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
+       if (!sec_pmic->rtc) {
+               dev_err(&i2c->dev, "Failed to allocate I2C for RTC\n");
+               return -ENODEV;
+       }
        i2c_set_clientdata(sec_pmic->rtc, sec_pmic);
 
-       sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc,
-                       &sec_rtc_regmap_config);
+       sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc, regmap_rtc);
        if (IS_ERR(sec_pmic->regmap_rtc)) {
                ret = PTR_ERR(sec_pmic->regmap_rtc);
                dev_err(&i2c->dev, "Failed to allocate RTC register map: %d\n",
                        ret);
-               return ret;
+               goto err_regmap_rtc;
        }
 
        if (pdata && pdata->cfg_pmic_irq)
@@ -283,24 +377,33 @@ static int sec_pmic_probe(struct i2c_client *i2c,
                ret = mfd_add_devices(sec_pmic->dev, -1, s5m8767_devs,
                                      ARRAY_SIZE(s5m8767_devs), NULL, 0, NULL);
                break;
+       case S2MPA01:
+               ret = mfd_add_devices(sec_pmic->dev, -1, s2mpa01_devs,
+                                     ARRAY_SIZE(s2mpa01_devs), NULL, 0, NULL);
+               break;
        case S2MPS11X:
                ret = mfd_add_devices(sec_pmic->dev, -1, s2mps11_devs,
                                      ARRAY_SIZE(s2mps11_devs), NULL, 0, NULL);
                break;
+       case S2MPS14X:
+               ret = mfd_add_devices(sec_pmic->dev, -1, s2mps14_devs,
+                                     ARRAY_SIZE(s2mps14_devs), NULL, 0, NULL);
+               break;
        default:
                /* If this happens the probe function is problem */
                BUG();
        }
 
        if (ret)
-               goto err;
+               goto err_mfd;
 
        device_init_wakeup(sec_pmic->dev, sec_pmic->wakeup);
 
        return ret;
 
-err:
+err_mfd:
        sec_irq_exit(sec_pmic);
+err_regmap_rtc:
        i2c_unregister_device(sec_pmic->rtc);
        return ret;
 }