From d5252b48f3c2c0a4be383311cae25752bcdc07b7 Mon Sep 17 00:00:00 2001 From: Steve Kuo Date: Fri, 30 Mar 2012 15:00:38 +0800 Subject: mfd: tps80031: fix missed irq issue We found missed irq could be happened if clear all INT_STS_x register in one time. Shadow register pushes the irq status after the first byte of INT_STS_x was cleared The proposed way to clear interrupt is to write only one INT_STS_x register. It will also clear the other two ones. Bug 952476 Reviewed-on: http://git-master/r/93453 Signed-off-by: Steve Kuo (cherry picked from commit 0c92f32e9e03defaeac991518b26134e59ef4db6) Change-Id: I76179be4847f59a1687926b9b0dde6ebd3f58aa4 Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/100306 --- drivers/mfd/tps80031.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/tps80031.c b/drivers/mfd/tps80031.c index e8ea75c424c6..94ba777bcdb3 100644 --- a/drivers/mfd/tps80031.c +++ b/drivers/mfd/tps80031.c @@ -874,8 +874,22 @@ static irqreturn_t tps80031_irq(int irq, void *data) acks = (tmp[2] << 16) | (tmp[1] << 8) | tmp[0]; if (acks) { - ret = tps80031_writes(tps80031->dev, SLAVE_ID2, - TPS80031_INT_STS_A, 3, tmp); + /* + * Hardware behavior: hardware have the shadow register for + * interrupt status register which is updated if interrupt + * comes just after the interrupt status read. This shadow + * register gets written to main status register and cleared + * if any byte write happens in any of status register like + * STS_A, STS_B or STS_C. + * Hence here to clear the original interrupt status and + * updating the STS register with the shadow register, it is + * require to write only one byte in any of STS register. + * Having multiple register write can cause the STS register + * to clear without handling those interrupt and can cause + * interrupt miss. + */ + ret = tps80031_write(tps80031->dev, SLAVE_ID2, + TPS80031_INT_STS_A, 0); if (ret < 0) { dev_err(tps80031->dev, "failed to write " "interrupt status\n"); -- cgit v1.2.3 From 4bcf4d1cb69470362fa2cbb7691d016513fa8e4d Mon Sep 17 00:00:00 2001 From: Jinyoung Park Date: Wed, 25 Apr 2012 15:21:42 +0900 Subject: mfd: max77663: Unmask EN0 rising interrupt Unmasked EN0 rising interrupt to generate fast PMU_INT by EN0(POWER_KEY). Bug 930883 Change-Id: I9a3d8c4f564e83deea86fbd3d05f14933a0b0f65 Signed-off-by: Jinyoung Park Reviewed-on: http://git-master/r/98665 Reviewed-by: Simone Willett Tested-by: Simone Willett --- drivers/mfd/max77663-core.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/max77663-core.c b/drivers/mfd/max77663-core.c index ff47cb123d0d..dbd4fff37e75 100644 --- a/drivers/mfd/max77663-core.c +++ b/drivers/mfd/max77663-core.c @@ -118,6 +118,8 @@ #define ONOFF_SLP_LPM_MASK (1 << 5) +#define ONOFF_IRQ_EN0_RISING (1 << 3) + enum { CACHE_IRQ_LBT, CACHE_IRQ_SD, @@ -1132,6 +1134,10 @@ static int max77663_irq_init(struct max77663_chip *chip) max77663_write(chip->dev, MAX77663_REG_LBT_IRQ_MASK, &chip->cache_irq_mask[CACHE_IRQ_LBT], 1, 0); + chip->cache_irq_mask[CACHE_IRQ_ONOFF] &= ~ONOFF_IRQ_EN0_RISING; + max77663_write(chip->dev, MAX77663_REG_ONOFF_IRQ_MASK, + &chip->cache_irq_mask[CACHE_IRQ_ONOFF], 1, 0); + return 0; } -- cgit v1.2.3 From e0ce2e5ff81e3825b89babadd784baba96166949 Mon Sep 17 00:00:00 2001 From: Jinyoung Park Date: Mon, 23 Apr 2012 18:49:33 +0900 Subject: mfd: max77663: Add gpio irq masking in irq_sync_unlock Add gpio irq masking in irq_sync_unlock. Change-Id: I008caf58ae82d9ed888f4720f54675e9106f027d Signed-off-by: Jinyoung Park Reviewed-on: http://git-master/r/98664 Reviewed-by: Simone Willett Tested-by: Simone Willett --- drivers/mfd/max77663-core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/max77663-core.c b/drivers/mfd/max77663-core.c index dbd4fff37e75..46728c331f83 100644 --- a/drivers/mfd/max77663-core.c +++ b/drivers/mfd/max77663-core.c @@ -905,6 +905,8 @@ static void max77663_irq_sync_unlock(struct irq_data *data) irq_mask = irq_data->trigger_type; else irq_mask = GPIO_REFE_IRQ_EDGE_FALLING << shift; + } else { + irq_mask = GPIO_REFE_IRQ_NONE << shift; } ret = max77663_cache_write(chip->dev, GPIO_REG_ADDR(offset), -- cgit v1.2.3 From 64bcd65388b34c8832125b44c0f9b95b0ca755a0 Mon Sep 17 00:00:00 2001 From: Tom Cherry Date: Fri, 18 May 2012 14:00:51 -0700 Subject: mfd: tps80031: turn on backup battery charger circuit The backup battery for the RTC circuit needs to be manually turned on. This change turns it on when the driver is first probed, off during LP0 to prevent excess power draw, and back on again upon resume. Bug 986402 Change-Id: Id4768929d6a73546662806f04d98d714997174b0 Signed-off-by: Tom Cherry Reviewed-on: http://git-master/r/103425 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Laxman Dewangan --- drivers/mfd/tps80031.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/tps80031.c b/drivers/mfd/tps80031.c index 94ba777bcdb3..f0f2ce1f6840 100644 --- a/drivers/mfd/tps80031.c +++ b/drivers/mfd/tps80031.c @@ -105,6 +105,9 @@ #define TPS80031_CFG_INPUT_PUPD3 0xF2 #define TPS80031_CFG_INPUT_PUPD4 0xF3 +#define TPS80031_BBSPOR_CFG 0xE6 +#define TPS80031_BBSPOR_CHG_EN 0x8 + struct tps80031_pupd_data { u8 reg; u8 pullup_bit; @@ -568,6 +571,17 @@ static void tps80031_pupd_init(struct tps80031 *tps80031, } } +static void tps80031_backup_battery_charger_control(struct tps80031 *tps80031, + int enable) +{ + if (enable) + tps80031_update(tps80031->dev, SLAVE_ID1, TPS80031_BBSPOR_CFG, + TPS80031_BBSPOR_CHG_EN, TPS80031_BBSPOR_CHG_EN); + else + tps80031_update(tps80031->dev, SLAVE_ID1, TPS80031_BBSPOR_CFG, + 0, TPS80031_BBSPOR_CHG_EN); +} + static void tps80031_init_ext_control(struct tps80031 *tps80031, struct tps80031_platform_data *pdata) { int ret; @@ -1287,6 +1301,8 @@ static int __devinit tps80031_i2c_probe(struct i2c_client *client, tps80031_debuginit(tps80031); + tps80031_backup_battery_charger_control(tps80031, 1); + if (pdata->use_power_off && !pm_power_off) pm_power_off = tps80031_power_off; @@ -1302,13 +1318,17 @@ fail: #ifdef CONFIG_PM static int tps80031_i2c_suspend(struct i2c_client *client, pm_message_t state) { + struct tps80031 *tps80031 = i2c_get_clientdata(client); if (client->irq) disable_irq(client->irq); + tps80031_backup_battery_charger_control(tps80031, 0); return 0; } static int tps80031_i2c_resume(struct i2c_client *client) { + struct tps80031 *tps80031 = i2c_get_clientdata(client); + tps80031_backup_battery_charger_control(tps80031, 1); if (client->irq) enable_irq(client->irq); return 0; -- cgit v1.2.3 From a086ad2223ef653b2f4e0c223e87bb701d969584 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 16 Apr 2012 21:24:32 +0200 Subject: mfd: Fix modular builds of rc5t583 regulator support The combination of commit 1b1247dd75aa5cf5fae54a3bec7280046e9c7957 "mfd: Add support for RICOH PMIC RC5T583" and commit 6ffc3270210efa2bea526953a142ffc908f5bd86 "regulator: Add support for RICOH PMIC RC5T583 regulator" are causing the i386 allmodconfig builds to fail with this: ERROR: "rc5t583_update" [drivers/regulator/rc5t583-regulator.ko] undefined! ERROR: "rc5t583_set_bits" [drivers/regulator/rc5t583-regulator.ko] undefined! ERROR: "rc5t583_clear_bits" [drivers/regulator/rc5t583-regulator.ko] undefined! ERROR: "rc5t583_read" [drivers/regulator/rc5t583-regulator.ko] undefined! and this: ERROR: "rc5t583_ext_power_req_config" [drivers/regulator/rc5t583-regulator.ko] undefined! For the 1st four, make the simple ops static inline, instead of polluting the namespace with trivial exports. For the last one, add an EXPORT_SYMBOL. Signed-off-by: Paul Gortmaker Signed-off-by: Samuel Ortiz (cherry picked from commit 82ea267f7dc853a5e6a724916a70a10656efdfc2) Change-Id: I7f03cc5c0005883eb8355170cdc7996a9c392091 Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105878 GVS: Gerrit_Virtual_Submit Reviewed-by: Bitan Biswas --- drivers/mfd/rc5t583.c | 39 +-------------------------------------- 1 file changed, 1 insertion(+), 38 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c index 99ef944c621d..44afae0a69ce 100644 --- a/drivers/mfd/rc5t583.c +++ b/drivers/mfd/rc5t583.c @@ -80,44 +80,6 @@ static struct mfd_cell rc5t583_subdevs[] = { {.name = "rc5t583-key", } }; -int rc5t583_write(struct device *dev, uint8_t reg, uint8_t val) -{ - struct rc5t583 *rc5t583 = dev_get_drvdata(dev); - return regmap_write(rc5t583->regmap, reg, val); -} - -int rc5t583_read(struct device *dev, uint8_t reg, uint8_t *val) -{ - struct rc5t583 *rc5t583 = dev_get_drvdata(dev); - unsigned int ival; - int ret; - ret = regmap_read(rc5t583->regmap, reg, &ival); - if (!ret) - *val = (uint8_t)ival; - return ret; -} - -int rc5t583_set_bits(struct device *dev, unsigned int reg, - unsigned int bit_mask) -{ - struct rc5t583 *rc5t583 = dev_get_drvdata(dev); - return regmap_update_bits(rc5t583->regmap, reg, bit_mask, bit_mask); -} - -int rc5t583_clear_bits(struct device *dev, unsigned int reg, - unsigned int bit_mask) -{ - struct rc5t583 *rc5t583 = dev_get_drvdata(dev); - return regmap_update_bits(rc5t583->regmap, reg, bit_mask, 0); -} - -int rc5t583_update(struct device *dev, unsigned int reg, - unsigned int val, unsigned int mask) -{ - struct rc5t583 *rc5t583 = dev_get_drvdata(dev); - return regmap_update_bits(rc5t583->regmap, reg, mask, val); -} - static int __rc5t583_set_ext_pwrreq1_control(struct device *dev, int id, int ext_pwr, int slots) { @@ -197,6 +159,7 @@ int rc5t583_ext_power_req_config(struct device *dev, int ds_id, ds_id, ext_pwr_req); return 0; } +EXPORT_SYMBOL(rc5t583_ext_power_req_config); static int rc5t583_clear_ext_power_req(struct rc5t583 *rc5t583, struct rc5t583_platform_data *pdata) -- cgit v1.2.3 From 068ea29689e8de70af6a3e7271375058351f7d5f Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Mon, 9 Apr 2012 13:55:55 +0530 Subject: mfd: Add rc5t583's gpio in mfd device list Adding the gpio of RC583 in the list of rc583 mfd devices to register the gpio driver of RC5T583. Signed-off-by: Laxman Dewangan Signed-off-by: Samuel Ortiz (cherry picked from commit e1277f45d8748ff59608b140780f75390cb5400c) Change-Id: Iea2ccf7831c331d1ad08f96100d4222cce31224f Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105879 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Bitan Biswas --- drivers/mfd/rc5t583.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c index 44afae0a69ce..1cb4c356afd5 100644 --- a/drivers/mfd/rc5t583.c +++ b/drivers/mfd/rc5t583.c @@ -75,6 +75,7 @@ static struct deepsleep_control_data deepsleep_data[] = { (RC5T583_EXT_PWRREQ1_CONTROL | RC5T583_EXT_PWRREQ2_CONTROL) static struct mfd_cell rc5t583_subdevs[] = { + {.name = "rc5t583-gpio",}, {.name = "rc5t583-regulator",}, {.name = "rc5t583-rtc", }, {.name = "rc5t583-key", } -- cgit v1.2.3 From 70b58068435b0801e4c15742c7c758c3cb9b6e52 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 25 Apr 2012 10:01:55 +0800 Subject: mfd: Convert rc5t583 to devm_regmap_init_i2c() Signed-off-by: Axel Lin Acked-by: Laxman Dewangan Signed-off-by: Samuel Ortiz (cherry picked from commit f8dddc0cfe9f56ed74fd5efde8d0754f5fb73a3f) Change-Id: I72d44f59c79abbbdac95398a5d4da2bedf19d8f1 Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105880 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Bitan Biswas --- drivers/mfd/rc5t583.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c index 1cb4c356afd5..cdc1df7fa0e9 100644 --- a/drivers/mfd/rc5t583.c +++ b/drivers/mfd/rc5t583.c @@ -268,7 +268,7 @@ static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c, rc5t583->dev = &i2c->dev; i2c_set_clientdata(i2c, rc5t583); - rc5t583->regmap = regmap_init_i2c(i2c, &rc5t583_regmap_config); + rc5t583->regmap = devm_regmap_init_i2c(i2c, &rc5t583_regmap_config); if (IS_ERR(rc5t583->regmap)) { ret = PTR_ERR(rc5t583->regmap); dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret); @@ -277,7 +277,7 @@ static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c, ret = rc5t583_clear_ext_power_req(rc5t583, pdata); if (ret < 0) - goto err_irq_init; + return ret; if (i2c->irq) { ret = rc5t583_irq_init(rc5t583, i2c->irq, pdata->irq_base); @@ -300,8 +300,6 @@ static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c, err_add_devs: if (irq_init_success) rc5t583_irq_exit(rc5t583); -err_irq_init: - regmap_exit(rc5t583->regmap); return ret; } @@ -311,7 +309,6 @@ static int __devexit rc5t583_i2c_remove(struct i2c_client *i2c) mfd_remove_devices(rc5t583->dev); rc5t583_irq_exit(rc5t583); - regmap_exit(rc5t583->regmap); return 0; } -- cgit v1.2.3 From 40721853b55aeeb61d35227c40d4a7ed64dbdc6d Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 7 Mar 2012 18:46:05 +0530 Subject: mfd: Use correct variable name for tps65910 regmap config This was the copy-paste issue in reg cache support code where variable name for regmap config was not really starting from the device name, it was starting from some other device name. Fixing this so that variable name contains actual device name. Signed-off-by: Laxman Dewangan Signed-off-by: Samuel Ortiz (cherry picked from commit 39ecb0376508b5cd20a951388d10aed2d719a77f) Change-Id: Ife11f77952d847ae7918f11cf1e936bf5008feb4 Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105918 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit --- drivers/mfd/tps65910.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 1c4f53efee74..bf2b25ebf2ca 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -81,7 +81,7 @@ static bool is_volatile_reg(struct device *dev, unsigned int reg) return true; } -static const struct regmap_config rc5t583_regmap_config = { +static const struct regmap_config tps65910_regmap_config = { .reg_bits = 8, .val_bits = 8, .volatile_reg = is_volatile_reg, @@ -120,7 +120,7 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, tps65910->write = tps65910_i2c_write; mutex_init(&tps65910->io_mutex); - tps65910->regmap = regmap_init_i2c(i2c, &rc5t583_regmap_config); + tps65910->regmap = regmap_init_i2c(i2c, &tps65910_regmap_config); if (IS_ERR(tps65910->regmap)) { ret = PTR_ERR(tps65910->regmap); dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret); -- cgit v1.2.3 From 5650a157b1255dd53784a71d41946810a92ef804 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 18 Apr 2012 12:13:51 +0200 Subject: mfd: Add support for tps65910 device sleep Adding support for device sleep through the external input control signal "SLEEP". Changing the SLEEP signal state can switch the device into SLEEP and ACTIVE state. Also adding sleep configuration for different resources so that they should be keep on during sleep state of device. Signed-off-by: Laxman Dewangan Signed-off-by: Samuel Ortiz (Cherry-picked from mainline 201cf052810d20814a77ca0e0045a2c1a3508a1f) Change-Id: Iec18bfcc7a1df6442e833dccaa1d39407918f710 Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105920 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit --- drivers/mfd/tps65910.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index bf2b25ebf2ca..ae7f47b6e71b 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -90,6 +90,66 @@ static const struct regmap_config tps65910_regmap_config = { .cache_type = REGCACHE_RBTREE, }; +static int __init tps65910_sleepinit(struct tps65910 *tps65910, + struct tps65910_board *pmic_pdata) +{ + struct device *dev = NULL; + int ret = 0; + + dev = tps65910->dev; + + if (!pmic_pdata->en_dev_slp) + return 0; + + /* enabling SLEEP device state */ + ret = tps65910_set_bits(tps65910, TPS65910_DEVCTRL, + DEVCTRL_DEV_SLP_MASK); + if (ret < 0) { + dev_err(dev, "set dev_slp failed: %d\n", ret); + goto err_sleep_init; + } + + /* Return if there is no sleep keepon data. */ + if (!pmic_pdata->slp_keepon) + return 0; + + if (pmic_pdata->slp_keepon->therm_keepon) { + ret = tps65910_set_bits(tps65910, TPS65910_SLEEP_KEEP_RES_ON, + SLEEP_KEEP_RES_ON_THERM_KEEPON_MASK); + if (ret < 0) { + dev_err(dev, "set therm_keepon failed: %d\n", ret); + goto disable_dev_slp; + } + } + + if (pmic_pdata->slp_keepon->clkout32k_keepon) { + ret = tps65910_set_bits(tps65910, TPS65910_SLEEP_KEEP_RES_ON, + SLEEP_KEEP_RES_ON_CLKOUT32K_KEEPON_MASK); + if (ret < 0) { + dev_err(dev, "set clkout32k_keepon failed: %d\n", ret); + goto disable_dev_slp; + } + } + + if (pmic_pdata->slp_keepon->i2chs_keepon) { + ret = tps65910_set_bits(tps65910, TPS65910_SLEEP_KEEP_RES_ON, + SLEEP_KEEP_RES_ON_I2CHS_KEEPON_MASK); + if (ret < 0) { + dev_err(dev, "set i2chs_keepon failed: %d\n", ret); + goto disable_dev_slp; + } + } + + return 0; + +disable_dev_slp: + tps65910_clear_bits(tps65910, TPS65910_DEVCTRL, DEVCTRL_DEV_SLP_MASK); + +err_sleep_init: + return ret; +} + + static int tps65910_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -140,6 +200,8 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, tps65910_irq_init(tps65910, init_data->irq, init_data); + tps65910_sleepinit(tps65910, pmic_plat_data); + kfree(init_data); return ret; -- cgit v1.2.3 From 30d1e63baee88c54c4093279b8653682a11cbaca Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 7 May 2012 10:03:19 +0100 Subject: mfd: Fix tps65910 section annotations A warning was being generated by the reference from tps65910_i2c_probe() to tps65910_sleepinit() since the latter was annotated as __init but the former was unannotated. Since these functions can only be called during device init make them both __devinit, and while we're at it also annotate tps65910_i2c_remove() __devexit for symmetry. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz (cherry picked from commit 63745d4068de8ccea3580214c6dbfdca0ec37859) Change-Id: I9e85e31e770c7ea68524d046b87036d6d0264523 Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105921 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit --- drivers/mfd/tps65910.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index ae7f47b6e71b..7a55af921e25 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -90,7 +90,7 @@ static const struct regmap_config tps65910_regmap_config = { .cache_type = REGCACHE_RBTREE, }; -static int __init tps65910_sleepinit(struct tps65910 *tps65910, +static int __devinit tps65910_sleepinit(struct tps65910 *tps65910, struct tps65910_board *pmic_pdata) { struct device *dev = NULL; @@ -150,8 +150,8 @@ err_sleep_init: } -static int tps65910_i2c_probe(struct i2c_client *i2c, - const struct i2c_device_id *id) +static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) { struct tps65910 *tps65910; struct tps65910_board *pmic_plat_data; @@ -213,7 +213,7 @@ regmap_err: return ret; } -static int tps65910_i2c_remove(struct i2c_client *i2c) +static __devexit int tps65910_i2c_remove(struct i2c_client *i2c) { struct tps65910 *tps65910 = i2c_get_clientdata(i2c); @@ -239,7 +239,7 @@ static struct i2c_driver tps65910_i2c_driver = { .owner = THIS_MODULE, }, .probe = tps65910_i2c_probe, - .remove = tps65910_i2c_remove, + .remove = __devexit_p(tps65910_i2c_remove), .id_table = tps65910_i2c_id, }; -- cgit v1.2.3 From d167de5fef02520c5dfd924eeeb5fb9fae671729 Mon Sep 17 00:00:00 2001 From: Rhyland Klein Date: Tue, 8 May 2012 11:42:38 -0700 Subject: mfd: Commonize tps65910 regmap access through header This change removes the read/write callback functions in favor of common regmap accessors inside the header file. This change also makes use of regmap_read/write for single register access which maps better onto what this driver actually needs. Signed-off-by: Rhyland Klein Signed-off-by: Samuel Ortiz (Cherry-pick from mainline 3f7e82759c692df473675ed06fb90b20f1f225c3) Change-Id: Ida79b196acf65ed14ff9fd2cc1f7c0048f99ba2b Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105922 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Rhyland Klein GVS: Gerrit_Virtual_Submit --- drivers/mfd/tps65910-irq.c | 34 +++++++++++++++++----------------- drivers/mfd/tps65910.c | 40 +++++++++------------------------------- 2 files changed, 26 insertions(+), 48 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c index c9ed5c00a621..0f1ff7fbdc74 100644 --- a/drivers/mfd/tps65910-irq.c +++ b/drivers/mfd/tps65910-irq.c @@ -41,28 +41,28 @@ static inline int irq_to_tps65910_irq(struct tps65910 *tps65910, static irqreturn_t tps65910_irq(int irq, void *irq_data) { struct tps65910 *tps65910 = irq_data; + unsigned int reg; u32 irq_sts; u32 irq_mask; - u8 reg; int i; - tps65910->read(tps65910, TPS65910_INT_STS, 1, ®); + tps65910_reg_read(tps65910, TPS65910_INT_STS, ®); irq_sts = reg; - tps65910->read(tps65910, TPS65910_INT_STS2, 1, ®); + tps65910_reg_read(tps65910, TPS65910_INT_STS2, ®); irq_sts |= reg << 8; switch (tps65910_chip_id(tps65910)) { case TPS65911: - tps65910->read(tps65910, TPS65910_INT_STS3, 1, ®); + tps65910_reg_read(tps65910, TPS65910_INT_STS3, ®); irq_sts |= reg << 16; } - tps65910->read(tps65910, TPS65910_INT_MSK, 1, ®); + tps65910_reg_read(tps65910, TPS65910_INT_MSK, ®); irq_mask = reg; - tps65910->read(tps65910, TPS65910_INT_MSK2, 1, ®); + tps65910_reg_read(tps65910, TPS65910_INT_MSK2, ®); irq_mask |= reg << 8; switch (tps65910_chip_id(tps65910)) { case TPS65911: - tps65910->read(tps65910, TPS65910_INT_MSK3, 1, ®); + tps65910_reg_read(tps65910, TPS65910_INT_MSK3, ®); irq_mask |= reg << 16; } @@ -82,13 +82,13 @@ static irqreturn_t tps65910_irq(int irq, void *irq_data) /* Write the STS register back to clear IRQs we handled */ reg = irq_sts & 0xFF; irq_sts >>= 8; - tps65910->write(tps65910, TPS65910_INT_STS, 1, ®); + tps65910_reg_write(tps65910, TPS65910_INT_STS, reg); reg = irq_sts & 0xFF; - tps65910->write(tps65910, TPS65910_INT_STS2, 1, ®); + tps65910_reg_write(tps65910, TPS65910_INT_STS2, reg); switch (tps65910_chip_id(tps65910)) { case TPS65911: reg = irq_sts >> 8; - tps65910->write(tps65910, TPS65910_INT_STS3, 1, ®); + tps65910_reg_write(tps65910, TPS65910_INT_STS3, reg); } return IRQ_HANDLED; @@ -105,27 +105,27 @@ static void tps65910_irq_sync_unlock(struct irq_data *data) { struct tps65910 *tps65910 = irq_data_get_irq_chip_data(data); u32 reg_mask; - u8 reg; + unsigned int reg; - tps65910->read(tps65910, TPS65910_INT_MSK, 1, ®); + tps65910_reg_read(tps65910, TPS65910_INT_MSK, ®); reg_mask = reg; - tps65910->read(tps65910, TPS65910_INT_MSK2, 1, ®); + tps65910_reg_read(tps65910, TPS65910_INT_MSK2, ®); reg_mask |= reg << 8; switch (tps65910_chip_id(tps65910)) { case TPS65911: - tps65910->read(tps65910, TPS65910_INT_MSK3, 1, ®); + tps65910_reg_read(tps65910, TPS65910_INT_MSK3, ®); reg_mask |= reg << 16; } if (tps65910->irq_mask != reg_mask) { reg = tps65910->irq_mask & 0xFF; - tps65910->write(tps65910, TPS65910_INT_MSK, 1, ®); + tps65910_reg_write(tps65910, TPS65910_INT_MSK, reg); reg = tps65910->irq_mask >> 8 & 0xFF; - tps65910->write(tps65910, TPS65910_INT_MSK2, 1, ®); + tps65910_reg_write(tps65910, TPS65910_INT_MSK2, reg); switch (tps65910_chip_id(tps65910)) { case TPS65911: reg = tps65910->irq_mask >> 16; - tps65910->write(tps65910, TPS65910_INT_MSK3, 1, ®); + tps65910_reg_write(tps65910, TPS65910_INT_MSK3, reg); } } mutex_unlock(&tps65910->irq_lock); diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 7a55af921e25..7dffbe1a50c6 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -37,30 +37,6 @@ static struct mfd_cell tps65910s[] = { }; -static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg, - int bytes, void *dest) -{ - return regmap_bulk_read(tps65910->regmap, reg, dest, bytes); -} - -static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg, - int bytes, void *src) -{ - return regmap_bulk_write(tps65910->regmap, reg, src, bytes); -} - -int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask) -{ - return regmap_update_bits(tps65910->regmap, reg, mask, mask); -} -EXPORT_SYMBOL_GPL(tps65910_set_bits); - -int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask) -{ - return regmap_update_bits(tps65910->regmap, reg, mask, 0); -} -EXPORT_SYMBOL_GPL(tps65910_clear_bits); - static bool is_volatile_reg(struct device *dev, unsigned int reg) { struct tps65910 *tps65910 = dev_get_drvdata(dev); @@ -102,7 +78,7 @@ static int __devinit tps65910_sleepinit(struct tps65910 *tps65910, return 0; /* enabling SLEEP device state */ - ret = tps65910_set_bits(tps65910, TPS65910_DEVCTRL, + ret = tps65910_reg_set_bits(tps65910, TPS65910_DEVCTRL, DEVCTRL_DEV_SLP_MASK); if (ret < 0) { dev_err(dev, "set dev_slp failed: %d\n", ret); @@ -114,7 +90,8 @@ static int __devinit tps65910_sleepinit(struct tps65910 *tps65910, return 0; if (pmic_pdata->slp_keepon->therm_keepon) { - ret = tps65910_set_bits(tps65910, TPS65910_SLEEP_KEEP_RES_ON, + ret = tps65910_reg_set_bits(tps65910, + TPS65910_SLEEP_KEEP_RES_ON, SLEEP_KEEP_RES_ON_THERM_KEEPON_MASK); if (ret < 0) { dev_err(dev, "set therm_keepon failed: %d\n", ret); @@ -123,7 +100,8 @@ static int __devinit tps65910_sleepinit(struct tps65910 *tps65910, } if (pmic_pdata->slp_keepon->clkout32k_keepon) { - ret = tps65910_set_bits(tps65910, TPS65910_SLEEP_KEEP_RES_ON, + ret = tps65910_reg_set_bits(tps65910, + TPS65910_SLEEP_KEEP_RES_ON, SLEEP_KEEP_RES_ON_CLKOUT32K_KEEPON_MASK); if (ret < 0) { dev_err(dev, "set clkout32k_keepon failed: %d\n", ret); @@ -132,7 +110,8 @@ static int __devinit tps65910_sleepinit(struct tps65910 *tps65910, } if (pmic_pdata->slp_keepon->i2chs_keepon) { - ret = tps65910_set_bits(tps65910, TPS65910_SLEEP_KEEP_RES_ON, + ret = tps65910_reg_set_bits(tps65910, + TPS65910_SLEEP_KEEP_RES_ON, SLEEP_KEEP_RES_ON_I2CHS_KEEPON_MASK); if (ret < 0) { dev_err(dev, "set i2chs_keepon failed: %d\n", ret); @@ -143,7 +122,8 @@ static int __devinit tps65910_sleepinit(struct tps65910 *tps65910, return 0; disable_dev_slp: - tps65910_clear_bits(tps65910, TPS65910_DEVCTRL, DEVCTRL_DEV_SLP_MASK); + tps65910_reg_clear_bits(tps65910, TPS65910_DEVCTRL, + DEVCTRL_DEV_SLP_MASK); err_sleep_init: return ret; @@ -176,8 +156,6 @@ static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, tps65910->dev = &i2c->dev; tps65910->i2c_client = i2c; tps65910->id = id->driver_data; - tps65910->read = tps65910_i2c_read; - tps65910->write = tps65910_i2c_write; mutex_init(&tps65910->io_mutex); tps65910->regmap = regmap_init_i2c(i2c, &tps65910_regmap_config); -- cgit v1.2.3 From f5f14b545e0ba9bf74c3803793632080e14df43e Mon Sep 17 00:00:00 2001 From: Rhyland Klein Date: Fri, 11 May 2012 11:36:26 +0200 Subject: mfd: Add tps65910 device-tree support Add device tree based initialization support for TI's tps65910 pmic. Signed-off-by: Rhyland Klein Signed-off-by: Samuel Ortiz (cherry picked from commit cd4209ced4d3936cfe51b7b8833260457e2d9995) Change-Id: I6f211ebcee135fd0c52662f296eee9f47f801e7a Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105923 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit --- drivers/mfd/tps65910.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 7dffbe1a50c6..a00c09ea0793 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -23,6 +23,7 @@ #include #include #include +#include static struct mfd_cell tps65910s[] = { { @@ -129,6 +130,77 @@ err_sleep_init: return ret; } +#ifdef CONFIG_OF +static struct of_device_id tps65910_of_match[] = { + { .compatible = "ti,tps65910", .data = (void *)TPS65910}, + { .compatible = "ti,tps65911", .data = (void *)TPS65911}, + { }, +}; +MODULE_DEVICE_TABLE(of, tps65910_of_match); + +static struct tps65910_board *tps65910_parse_dt(struct i2c_client *client, + int *chip_id) +{ + struct device_node *np = client->dev.of_node; + struct tps65910_board *board_info; + unsigned int prop; + const struct of_device_id *match; + unsigned int prop_array[TPS6591X_MAX_NUM_GPIO]; + int ret = 0; + int idx; + + match = of_match_device(tps65910_of_match, &client->dev); + if (!match) { + dev_err(&client->dev, "Failed to find matching dt id\n"); + return NULL; + } + + *chip_id = (int)match->data; + + board_info = devm_kzalloc(&client->dev, sizeof(*board_info), + GFP_KERNEL); + if (!board_info) { + dev_err(&client->dev, "Failed to allocate pdata\n"); + return NULL; + } + + ret = of_property_read_u32(np, "ti,vmbch-threshold", &prop); + if (!ret) + board_info->vmbch_threshold = prop; + else if (*chip_id == TPS65911) + dev_warn(&client->dev, "VMBCH-Threshold not specified"); + + ret = of_property_read_u32(np, "ti,vmbch2-threshold", &prop); + if (!ret) + board_info->vmbch2_threshold = prop; + else if (*chip_id == TPS65911) + dev_warn(&client->dev, "VMBCH2-Threshold not specified"); + + ret = of_property_read_u32_array(np, "ti,en-gpio-sleep", + prop_array, TPS6591X_MAX_NUM_GPIO); + if (!ret) + for (idx = 0; idx < ARRAY_SIZE(prop_array); idx++) + board_info->en_gpio_sleep[idx] = (prop_array[idx] != 0); + else if (ret != -EINVAL) { + dev_err(&client->dev, + "error reading property ti,en-gpio-sleep: %d\n.", ret); + return NULL; + } + + + board_info->irq = client->irq; + board_info->irq_base = -1; + board_info->gpio_base = -1; + + return board_info; +} +#else +static inline struct tps65910_board *tps65910_parse_dt( + struct i2c_client *client) +{ + return NULL; +} +#endif static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) @@ -137,8 +209,13 @@ static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, struct tps65910_board *pmic_plat_data; struct tps65910_platform_data *init_data; int ret = 0; + int chip_id = id->driver_data; pmic_plat_data = dev_get_platdata(&i2c->dev); + + if (!pmic_plat_data && i2c->dev.of_node) + pmic_plat_data = tps65910_parse_dt(i2c, &chip_id); + if (!pmic_plat_data) return -EINVAL; @@ -155,7 +232,7 @@ static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, tps65910); tps65910->dev = &i2c->dev; tps65910->i2c_client = i2c; - tps65910->id = id->driver_data; + tps65910->id = chip_id; mutex_init(&tps65910->io_mutex); tps65910->regmap = regmap_init_i2c(i2c, &tps65910_regmap_config); @@ -215,6 +292,7 @@ static struct i2c_driver tps65910_i2c_driver = { .driver = { .name = "tps65910", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tps65910_of_match), }, .probe = tps65910_i2c_probe, .remove = __devexit_p(tps65910_i2c_remove), -- cgit v1.2.3 From 32622a1c656323bc3c5db5177dadd773de9f1978 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 9 May 2012 18:40:54 +0530 Subject: mfd: Cache tps65910 register when we need it During regmap initialization, we do not provide the default value and hence in place of caching register during regmap_init(), cache it when actually we need it i.e. after reading of that register. Signed-off-by: Laxman Dewangan Reviewed-by: Mark Brown Signed-off-by: Samuel Ortiz (cherry picked from commit 3bf6bf9be51a0195c6b1604454fdd28ed1cc1770) Change-Id: I151f52436162a328b8d683fc06beba0587d6bda3 Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105924 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit --- drivers/mfd/tps65910.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index a00c09ea0793..01570a789cf1 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -62,8 +62,7 @@ static const struct regmap_config tps65910_regmap_config = { .reg_bits = 8, .val_bits = 8, .volatile_reg = is_volatile_reg, - .max_register = TPS65910_MAX_REGISTER, - .num_reg_defaults_raw = TPS65910_MAX_REGISTER, + .max_register = TPS65910_MAX_REGISTER - 1, .cache_type = REGCACHE_RBTREE, }; -- cgit v1.2.3 From 4e2e5176256f52fcb282dfbe40c3773dd1356ccb Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 11 May 2012 12:36:57 +0200 Subject: mfd: Convert all tps65910 allocation to devm_* Convert memory allocation and regmap initialization to use devm_* functions. Signed-off-by: Laxman Dewangan Reviewed-by: Mark Brown Signed-off-by: Samuel Ortiz (cherry picked from commit 63fe7dee9183118716078a9f2503f5f805d37c12) Change-Id: I9b21c63031afffd1d9d1a37abf80895824f7fc7b Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105925 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit --- drivers/mfd/tps65910.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 01570a789cf1..22fa43070659 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -218,15 +218,13 @@ static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, if (!pmic_plat_data) return -EINVAL; - init_data = kzalloc(sizeof(struct tps65910_platform_data), GFP_KERNEL); + init_data = devm_kzalloc(&i2c->dev, sizeof(*init_data), GFP_KERNEL); if (init_data == NULL) return -ENOMEM; - tps65910 = kzalloc(sizeof(struct tps65910), GFP_KERNEL); - if (tps65910 == NULL) { - kfree(init_data); + tps65910 = devm_kzalloc(&i2c->dev, sizeof(*tps65910), GFP_KERNEL); + if (tps65910 == NULL) return -ENOMEM; - } i2c_set_clientdata(i2c, tps65910); tps65910->dev = &i2c->dev; @@ -234,18 +232,20 @@ static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, tps65910->id = chip_id; mutex_init(&tps65910->io_mutex); - tps65910->regmap = regmap_init_i2c(i2c, &tps65910_regmap_config); + tps65910->regmap = devm_regmap_init_i2c(i2c, &tps65910_regmap_config); if (IS_ERR(tps65910->regmap)) { ret = PTR_ERR(tps65910->regmap); dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret); - goto regmap_err; + return ret; } ret = mfd_add_devices(tps65910->dev, -1, tps65910s, ARRAY_SIZE(tps65910s), NULL, 0); - if (ret < 0) - goto err; + if (ret < 0) { + dev_err(&i2c->dev, "mfd_add_devices failed: %d\n", ret); + return ret; + } init_data->irq = pmic_plat_data->irq; init_data->irq_base = pmic_plat_data->irq_base; @@ -256,14 +256,6 @@ static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, tps65910_sleepinit(tps65910, pmic_plat_data); - kfree(init_data); - return ret; - -err: - regmap_exit(tps65910->regmap); -regmap_err: - kfree(tps65910); - kfree(init_data); return ret; } @@ -273,8 +265,6 @@ static __devexit int tps65910_i2c_remove(struct i2c_client *i2c) tps65910_irq_exit(tps65910); mfd_remove_devices(tps65910->dev); - regmap_exit(tps65910->regmap); - kfree(tps65910); return 0; } -- cgit v1.2.3 From 68b0ec09c985a41aebe42e181d55170bd9962105 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 11 May 2012 15:07:44 +0200 Subject: mfd: Register tps65910 gpios as an mfd device As gpio support for tps65910 is on gpio driver, registering gpio support as the mfd sub devices instead of calling gpio_init() from the core probe. Signed-off-by: Laxman Dewangan Signed-off-by: Samuel Ortiz (cherry picked from commit 32df986e985921386b75b4bd1117102bf65fe095) Change-Id: I631596313528ab192d7d8c2f376965ccc989c313 Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105926 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit --- drivers/mfd/Kconfig | 1 - drivers/mfd/tps65910.c | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index f89c3eedee36..a4931c756205 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -175,7 +175,6 @@ config MFD_TPS65910 bool "TPS65910 Power Management chip" depends on I2C=y && GPIOLIB select MFD_CORE - select GPIO_TPS65910 select REGMAP_I2C help if you say yes here you get support for the TPS65910 series of diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 22fa43070659..553574da3611 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -19,13 +19,15 @@ #include #include #include -#include #include #include #include #include static struct mfd_cell tps65910s[] = { + { + .name = "tps65910-gpio", + }, { .name = "tps65910-pmic", }, @@ -250,8 +252,6 @@ static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, init_data->irq = pmic_plat_data->irq; init_data->irq_base = pmic_plat_data->irq_base; - tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base); - tps65910_irq_init(tps65910, init_data->irq, init_data); tps65910_sleepinit(tps65910, pmic_plat_data); -- cgit v1.2.3 From 2dbbe1fe96871cffbc1b734b67d54385eb522ff8 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 11 May 2012 15:10:28 +0200 Subject: mfd: Fix tps65910 build failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tps65910_parse_dt() prototype for !CONFIG_OF was not correct, leading to: drivers/mfd/tps65910.c: In function ‘tps65910_i2c_probe’: drivers/mfd/tps65910.c:218:3: error: too many arguments to function ‘tps65910_parse_dt’ Signed-off-by: Samuel Ortiz (cherry picked from commit 7f65f74ccee15f6eb0009921a428e3c5d5d06ae0) Change-Id: I1592020268c408effc331069b7ae241c6da248bb Signed-off-by: Laxman Dewangan Reviewed-on: http://git-master/r/105927 GVS: Gerrit_Virtual_Submit --- drivers/mfd/tps65910.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 553574da3611..18b30cf45e5b 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -196,8 +196,9 @@ static struct tps65910_board *tps65910_parse_dt(struct i2c_client *client, return board_info; } #else -static inline struct tps65910_board *tps65910_parse_dt( - struct i2c_client *client) +static inline +struct tps65910_board *tps65910_parse_dt(struct i2c_client *client, + int *chip_id) { return NULL; } -- cgit v1.2.3 From 07f26014a90ab06cdb52b86146194e1b28f54486 Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Tue, 15 May 2012 15:48:56 +0900 Subject: mfd: palmas PMIC device support Palmas is a PMIC from Texas Instruments and this is the MFD part of the driver for this chip. The PMIC has SMPS and LDO regulators, a general purpose ADC, GPIO, USB OTG mode detection, watchdog and RTC features. Signed-off-by: Graeme Gregory Acked-by: Samuel Ortiz Signed-off-by: Mark Brown (cherry picked from commit 2945fbc2fcd83df03165342c1bc3ab83d0fe9c04) Change-Id: I0bdebbef55d91d2293806355dced43b4c2decad8 Reviewed-on: http://git-master/r/111485 Reviewed-by: Automatic_Commit_Validation_User Tested-by: Pradeep Goudagunta GVS: Gerrit_Virtual_Submit Reviewed-by: Laxman Dewangan --- drivers/mfd/palmas.c | 509 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 509 insertions(+) create mode 100644 drivers/mfd/palmas.c (limited to 'drivers/mfd') diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c new file mode 100644 index 000000000000..00c0aba7eba0 --- /dev/null +++ b/drivers/mfd/palmas.c @@ -0,0 +1,509 @@ +/* + * TI Palmas MFD Driver + * + * Copyright 2011-2012 Texas Instruments Inc. + * + * Author: Graeme Gregory + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const struct resource gpadc_resource[] = { + { + .name = "EOC_SW", + .start = PALMAS_GPADC_EOC_SW_IRQ, + .end = PALMAS_GPADC_EOC_SW_IRQ, + .flags = IORESOURCE_IRQ, + } +}; + +static const struct resource usb_resource[] = { + { + .name = "ID", + .start = PALMAS_ID_OTG_IRQ, + .end = PALMAS_ID_OTG_IRQ, + .flags = IORESOURCE_IRQ, + }, + { + .name = "ID_WAKEUP", + .start = PALMAS_ID_IRQ, + .end = PALMAS_ID_IRQ, + .flags = IORESOURCE_IRQ, + }, + { + .name = "VBUS", + .start = PALMAS_VBUS_OTG_IRQ, + .end = PALMAS_VBUS_OTG_IRQ, + .flags = IORESOURCE_IRQ, + }, + { + .name = "VBUS_WAKEUP", + .start = PALMAS_VBUS_IRQ, + .end = PALMAS_VBUS_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static const struct resource rtc_resource[] = { + { + .name = "RTC_ALARM", + .start = PALMAS_RTC_ALARM_IRQ, + .end = PALMAS_RTC_ALARM_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static const struct resource pwron_resource[] = { + { + .name = "PWRON_BUTTON", + .start = PALMAS_PWRON_IRQ, + .end = PALMAS_PWRON_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +enum palmas_ids { + PALMAS_PMIC_ID, + PALMAS_GPIO_ID, + PALMAS_LEDS_ID, + PALMAS_WDT_ID, + PALMAS_RTC_ID, + PALMAS_PWRBUTTON_ID, + PALMAS_GPADC_ID, + PALMAS_RESOURCE_ID, + PALMAS_CLK_ID, + PALMAS_PWM_ID, + PALMAS_USB_ID, +}; + +static const struct mfd_cell palmas_children[] = { + { + .name = "palmas-pmic", + .id = PALMAS_PMIC_ID, + }, + { + .name = "palmas-gpio", + .id = PALMAS_GPIO_ID, + }, + { + .name = "palmas-leds", + .id = PALMAS_LEDS_ID, + }, + { + .name = "palmas-wdt", + .id = PALMAS_WDT_ID, + }, + { + .name = "palmas-rtc", + .num_resources = ARRAY_SIZE(rtc_resource), + .resources = rtc_resource, + .id = PALMAS_RTC_ID, + }, + { + .name = "palmas-pwrbutton", + .num_resources = ARRAY_SIZE(pwron_resource), + .resources = pwron_resource, + .id = PALMAS_PWRBUTTON_ID, + }, + { + .name = "palmas-gpadc", + .num_resources = ARRAY_SIZE(gpadc_resource), + .resources = gpadc_resource, + .id = PALMAS_GPADC_ID, + }, + { + .name = "palmas-resource", + .id = PALMAS_RESOURCE_ID, + }, + { + .name = "palmas-clk", + .id = PALMAS_CLK_ID, + }, + { + .name = "palmas-pwm", + .id = PALMAS_PWM_ID, + }, + { + .name = "palmas-usb", + .num_resources = ARRAY_SIZE(usb_resource), + .resources = usb_resource, + .id = PALMAS_USB_ID, + } +}; + +static const struct regmap_config palmas_regmap_config[PALMAS_NUM_CLIENTS] = { + { + .reg_bits = 8, + .val_bits = 8, + .max_register = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE, + PALMAS_PRIMARY_SECONDARY_PAD3), + }, + { + .reg_bits = 8, + .val_bits = 8, + .max_register = PALMAS_BASE_TO_REG(PALMAS_GPADC_BASE, + PALMAS_GPADC_SMPS_VSEL_MONITORING), + }, + { + .reg_bits = 8, + .val_bits = 8, + .max_register = PALMAS_BASE_TO_REG(PALMAS_TRIM_GPADC_BASE, + PALMAS_GPADC_TRIM16), + }, +}; + +static const struct regmap_irq palmas_irqs[] = { + /* INT1 IRQs */ + [PALMAS_CHARG_DET_N_VBUS_OVV_IRQ] = { + .mask = PALMAS_INT1_STATUS_CHARG_DET_N_VBUS_OVV, + }, + [PALMAS_PWRON_IRQ] = { + .mask = PALMAS_INT1_STATUS_PWRON, + }, + [PALMAS_LONG_PRESS_KEY_IRQ] = { + .mask = PALMAS_INT1_STATUS_LONG_PRESS_KEY, + }, + [PALMAS_RPWRON_IRQ] = { + .mask = PALMAS_INT1_STATUS_RPWRON, + }, + [PALMAS_PWRDOWN_IRQ] = { + .mask = PALMAS_INT1_STATUS_PWRDOWN, + }, + [PALMAS_HOTDIE_IRQ] = { + .mask = PALMAS_INT1_STATUS_HOTDIE, + }, + [PALMAS_VSYS_MON_IRQ] = { + .mask = PALMAS_INT1_STATUS_VSYS_MON, + }, + [PALMAS_VBAT_MON_IRQ] = { + .mask = PALMAS_INT1_STATUS_VBAT_MON, + }, + /* INT2 IRQs*/ + [PALMAS_RTC_ALARM_IRQ] = { + .mask = PALMAS_INT2_STATUS_RTC_ALARM, + .reg_offset = 1, + }, + [PALMAS_RTC_TIMER_IRQ] = { + .mask = PALMAS_INT2_STATUS_RTC_TIMER, + .reg_offset = 1, + }, + [PALMAS_WDT_IRQ] = { + .mask = PALMAS_INT2_STATUS_WDT, + .reg_offset = 1, + }, + [PALMAS_BATREMOVAL_IRQ] = { + .mask = PALMAS_INT2_STATUS_BATREMOVAL, + .reg_offset = 1, + }, + [PALMAS_RESET_IN_IRQ] = { + .mask = PALMAS_INT2_STATUS_RESET_IN, + .reg_offset = 1, + }, + [PALMAS_FBI_BB_IRQ] = { + .mask = PALMAS_INT2_STATUS_FBI_BB, + .reg_offset = 1, + }, + [PALMAS_SHORT_IRQ] = { + .mask = PALMAS_INT2_STATUS_SHORT, + .reg_offset = 1, + }, + [PALMAS_VAC_ACOK_IRQ] = { + .mask = PALMAS_INT2_STATUS_VAC_ACOK, + .reg_offset = 1, + }, + /* INT3 IRQs */ + [PALMAS_GPADC_AUTO_0_IRQ] = { + .mask = PALMAS_INT3_STATUS_GPADC_AUTO_0, + .reg_offset = 2, + }, + [PALMAS_GPADC_AUTO_1_IRQ] = { + .mask = PALMAS_INT3_STATUS_GPADC_AUTO_1, + .reg_offset = 2, + }, + [PALMAS_GPADC_EOC_SW_IRQ] = { + .mask = PALMAS_INT3_STATUS_GPADC_EOC_SW, + .reg_offset = 2, + }, + [PALMAS_GPADC_EOC_RT_IRQ] = { + .mask = PALMAS_INT3_STATUS_GPADC_EOC_RT, + .reg_offset = 2, + }, + [PALMAS_ID_OTG_IRQ] = { + .mask = PALMAS_INT3_STATUS_ID_OTG, + .reg_offset = 2, + }, + [PALMAS_ID_IRQ] = { + .mask = PALMAS_INT3_STATUS_ID, + .reg_offset = 2, + }, + [PALMAS_VBUS_OTG_IRQ] = { + .mask = PALMAS_INT3_STATUS_VBUS_OTG, + .reg_offset = 2, + }, + [PALMAS_VBUS_IRQ] = { + .mask = PALMAS_INT3_STATUS_VBUS, + .reg_offset = 2, + }, + /* INT4 IRQs */ + [PALMAS_GPIO_0_IRQ] = { + .mask = PALMAS_INT4_STATUS_GPIO_0, + .reg_offset = 3, + }, + [PALMAS_GPIO_1_IRQ] = { + .mask = PALMAS_INT4_STATUS_GPIO_1, + .reg_offset = 3, + }, + [PALMAS_GPIO_2_IRQ] = { + .mask = PALMAS_INT4_STATUS_GPIO_2, + .reg_offset = 3, + }, + [PALMAS_GPIO_3_IRQ] = { + .mask = PALMAS_INT4_STATUS_GPIO_3, + .reg_offset = 3, + }, + [PALMAS_GPIO_4_IRQ] = { + .mask = PALMAS_INT4_STATUS_GPIO_4, + .reg_offset = 3, + }, + [PALMAS_GPIO_5_IRQ] = { + .mask = PALMAS_INT4_STATUS_GPIO_5, + .reg_offset = 3, + }, + [PALMAS_GPIO_6_IRQ] = { + .mask = PALMAS_INT4_STATUS_GPIO_6, + .reg_offset = 3, + }, + [PALMAS_GPIO_7_IRQ] = { + .mask = PALMAS_INT4_STATUS_GPIO_7, + .reg_offset = 3, + }, +}; + +static struct regmap_irq_chip palmas_irq_chip = { + .name = "palmas", + .irqs = palmas_irqs, + .num_irqs = ARRAY_SIZE(palmas_irqs), + + .num_regs = 4, + .irq_reg_stride = 5, + .status_base = PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE, + PALMAS_INT1_STATUS), + .mask_base = PALMAS_BASE_TO_REG(PALMAS_INTERRUPT_BASE, + PALMAS_INT1_MASK), +}; + +static int __devinit palmas_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct palmas *palmas; + struct palmas_platform_data *pdata; + int ret = 0, i; + unsigned int reg, addr; + int slave; + struct mfd_cell *children; + + pdata = dev_get_platdata(&i2c->dev); + if (!pdata) + return -EINVAL; + + palmas = devm_kzalloc(&i2c->dev, sizeof(struct palmas), GFP_KERNEL); + if (palmas == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, palmas); + palmas->dev = &i2c->dev; + palmas->id = id->driver_data; + palmas->irq = i2c->irq; + + for (i = 0; i < PALMAS_NUM_CLIENTS; i++) { + if (i == 0) + palmas->i2c_clients[i] = i2c; + else { + palmas->i2c_clients[i] = + i2c_new_dummy(i2c->adapter, + i2c->addr + i); + if (!palmas->i2c_clients[i]) { + dev_err(palmas->dev, + "can't attach client %d\n", i); + ret = -ENOMEM; + goto err; + } + } + palmas->regmap[i] = devm_regmap_init_i2c(palmas->i2c_clients[i], + &palmas_regmap_config[i]); + if (IS_ERR(palmas->regmap[i])) { + ret = PTR_ERR(palmas->regmap[i]); + dev_err(palmas->dev, + "Failed to allocate regmap %d, err: %d\n", + i, ret); + goto err; + } + } + + ret = regmap_add_irq_chip(palmas->regmap[1], palmas->irq, + IRQF_ONESHOT | IRQF_TRIGGER_LOW, -1, &palmas_irq_chip, + &palmas->irq_data); + if (ret < 0) + goto err; + + slave = PALMAS_BASE_TO_SLAVE(PALMAS_PU_PD_OD_BASE); + addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE, + PALMAS_PRIMARY_SECONDARY_PAD1); + + if (pdata->mux_from_pdata) { + reg = pdata->pad1; + ret = regmap_write(palmas->regmap[slave], addr, reg); + if (ret) + goto err; + } else { + ret = regmap_read(palmas->regmap[slave], addr, ®); + if (ret) + goto err; + } + + if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_0)) + palmas->gpio_muxed |= PALMAS_GPIO_0_MUXED; + if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK)) + palmas->gpio_muxed |= PALMAS_GPIO_1_MUXED; + else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK) == + (2 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT)) + palmas->led_muxed |= PALMAS_LED1_MUXED; + else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_MASK) == + (3 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_1_SHIFT)) + palmas->pwm_muxed |= PALMAS_PWM1_MUXED; + if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK)) + palmas->gpio_muxed |= PALMAS_GPIO_2_MUXED; + else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK) == + (2 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT)) + palmas->led_muxed |= PALMAS_LED2_MUXED; + else if ((reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_MASK) == + (3 << PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_2_SHIFT)) + palmas->pwm_muxed |= PALMAS_PWM2_MUXED; + if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_3)) + palmas->gpio_muxed |= PALMAS_GPIO_3_MUXED; + + addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE, + PALMAS_PRIMARY_SECONDARY_PAD2); + + if (pdata->mux_from_pdata) { + reg = pdata->pad2; + ret = regmap_write(palmas->regmap[slave], addr, reg); + if (ret) + goto err; + } else { + ret = regmap_read(palmas->regmap[slave], addr, ®); + if (ret) + goto err; + } + + if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_4)) + palmas->gpio_muxed |= PALMAS_GPIO_4_MUXED; + if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_5_MASK)) + palmas->gpio_muxed |= PALMAS_GPIO_5_MUXED; + if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_6)) + palmas->gpio_muxed |= PALMAS_GPIO_6_MUXED; + if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_MASK)) + palmas->gpio_muxed |= PALMAS_GPIO_7_MUXED; + + dev_info(palmas->dev, "Muxing GPIO %x, PWM %x, LED %x\n", + palmas->gpio_muxed, palmas->pwm_muxed, + palmas->led_muxed); + + reg = pdata->power_ctrl; + + slave = PALMAS_BASE_TO_SLAVE(PALMAS_PMU_CONTROL_BASE); + addr = PALMAS_BASE_TO_REG(PALMAS_PMU_CONTROL_BASE, PALMAS_POWER_CTRL); + + ret = regmap_write(palmas->regmap[slave], addr, reg); + if (ret) + goto err; + + children = kmemdup(palmas_children, sizeof(palmas_children), + GFP_KERNEL); + if (!children) { + ret = -ENOMEM; + goto err; + } + + ret = mfd_add_devices(palmas->dev, -1, + children, ARRAY_SIZE(palmas_children), + NULL, regmap_irq_chip_get_base(palmas->irq_data)); + kfree(children); + + if (ret < 0) + goto err; + + return ret; + +err: + mfd_remove_devices(palmas->dev); + kfree(palmas); + return ret; +} + +static int palmas_i2c_remove(struct i2c_client *i2c) +{ + struct palmas *palmas = i2c_get_clientdata(i2c); + + mfd_remove_devices(palmas->dev); + regmap_del_irq_chip(palmas->irq, palmas->irq_data); + + return 0; +} + +static const struct i2c_device_id palmas_i2c_id[] = { + { "palmas", }, + { "twl6035", }, + { "twl6037", }, + { "tps65913", }, +}; +MODULE_DEVICE_TABLE(i2c, palmas_i2c_id); + +static struct of_device_id __devinitdata of_palmas_match_tbl[] = { + { .compatible = "ti,palmas", }, + { /* end */ } +}; + +static struct i2c_driver palmas_i2c_driver = { + .driver = { + .name = "palmas", + .of_match_table = of_palmas_match_tbl, + .owner = THIS_MODULE, + }, + .probe = palmas_i2c_probe, + .remove = palmas_i2c_remove, + .id_table = palmas_i2c_id, +}; + +static int __init palmas_i2c_init(void) +{ + return i2c_add_driver(&palmas_i2c_driver); +} +/* init early so consumer devices can complete system boot */ +subsys_initcall(palmas_i2c_init); + +static void __exit palmas_i2c_exit(void) +{ + i2c_del_driver(&palmas_i2c_driver); +} +module_exit(palmas_i2c_exit); + +MODULE_AUTHOR("Graeme Gregory "); +MODULE_DESCRIPTION("Palmas chip family multi-function driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 41d24628639d381fba35c292000bc34338a303fa Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Tue, 15 May 2012 15:48:57 +0900 Subject: mfd: palmas PMIC device support Kconfig Add the new palmas MFD to Kconfig and Makefile Signed-off-by: Graeme Gregory Signed-off-by: Mark Brown (cherry picked from commit c948ef3ae71c18c1079333b65d6887ceb4577618) Change-Id: I779faf7f0e110ba80761136eebeb7193b1826b4f Reviewed-on: http://git-master/r/111486 Reviewed-by: Automatic_Commit_Validation_User Tested-by: Pradeep Goudagunta GVS: Gerrit_Virtual_Submit Reviewed-by: Laxman Dewangan --- drivers/mfd/Kconfig | 10 ++++++++++ drivers/mfd/Makefile | 2 ++ 2 files changed, 12 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index a4931c756205..f37d3ec02123 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -867,6 +867,16 @@ config MFD_RICOH583 additional drivers must be enabled in order to use the functionality of the device. +config MFD_PALMAS + bool "Support for the TI Palmas series chips" + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ + depends on I2C=y + help + If you say yes here you get support for the Palmas + series of PMIC chips from Texas Instruments. + endif # MFD_SUPPORT menu "Multimedia Capabilities Port drivers" diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 90f02cdc538a..6634515b64e4 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -111,3 +111,5 @@ obj-$(CONFIG_MFD_MAX8907C) += max8907c-irq.o obj-$(CONFIG_MFD_MAX77663) += max77663-core.o obj-$(CONFIG_MFD_RICOH583) += ricoh583.o obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o +obj-$(CONFIG_MFD_PALMAS) += palmas.o +obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o -- cgit v1.2.3