diff options
-rw-r--r-- | drivers/mfd/tps80031.c | 309 |
1 files changed, 175 insertions, 134 deletions
diff --git a/drivers/mfd/tps80031.c b/drivers/mfd/tps80031.c index 5b287eb12241..691c9d2ee798 100644 --- a/drivers/mfd/tps80031.c +++ b/drivers/mfd/tps80031.c @@ -30,6 +30,7 @@ #include <linux/gpio.h> #include <linux/i2c.h> #include <linux/pm.h> +#include <linux/regmap.h> #include <linux/mfd/core.h> #include <linux/mfd/tps80031.h> @@ -108,6 +109,43 @@ #define TPS80031_BBSPOR_CFG 0xE6 #define TPS80031_BBSPOR_CHG_EN 0x8 +/* Valid Address ranges */ +#define TPS80031_ID0_PMIC_SLAVE_SMPS_DVS 0x55 ... 0x5C + +#define TPS80031_ID1_RTC 0x00 ... 0x16 +#define TPS80031_ID1_MEMORY 0x17 ... 0x1E +#define TPS80031_ID1_PMC_MASTER 0x1F ... 0x2D +#define TPS80031_ID1_PMC_SLAVE_MISC 0x31 ... 0x34 +#define TPS80031_ID1_PMC_SLAVE_SMPS 0x40 ... 0x68 +#define TPS80031_ID1_PMC_SLAVE_LDO 0x80 ... 0xA7 +#define TPS80031_ID1_PMC_SLAVE_REOSURCES 0XAD ... 0xD0 +#define TPS80031_ID1_PMC_PREQ_ASSIGN 0XD7 ... 0xDF +#define TPS80031_ID1_PMC_MISC 0xE2 ... 0xEF +#define TPS80031_ID1_PMC_PU_PD_HZ 0xF0 ... 0xF6 +#define TPS80031_ID1_PMC_BACKUP 0xFA + +#define TPS80031_ID2_USB 0x00 ... 0x1A +#define TPS80031_ID2_GPADC_CONTROL 0x2E ... 0x36 +#define TPS80031_ID2_GPADC_RESULTS 0x37 ... 0x3C +#define TPS80031_ID2_AUXILLIARIES 0x90 ... 0x9C +#define TPS80031_ID2_CUSTOM 0xA0 ... 0xB9 +#define TPS80031_ID2_PWM 0xBA ... 0xBE +#define TPS80031_ID2_FUEL_GAUSE 0xC0 ... 0xCB +#define TPS80031_ID2_INTERFACE_INTERRUPTS 0xD0 ... 0xD8 +#define TPS80031_ID2_CHARGER 0xE0 ... 0xF5 + +#define TPS80031_ID3_TEST_LDO 0x00 ... 0x09 +#define TPS80031_ID3_TEST_SMPS 0x10 ... 0x2B +#define TPS80031_ID3_TEST_POWER 0x30 ... 0x36 +#define TPS80031_ID3_TEST_CHARGER 0x40 ... 0x48 +#define TPS80031_ID3_TEST_AUXILIIARIES 0x50 ... 0xB1 + +#define TPS80031_ID3_DIEID 0xC0 ... 0xC8 +#define TPS80031_ID3_TRIM_PHOENIX 0xCC ... 0xEA +#define TPS80031_ID3_TRIM_CUSTOM 0xEC ... 0xED + +#define TPS80031_MAX_REGISTER 0x100 + struct tps80031_pupd_data { u8 reg; u8 pullup_bit; @@ -256,159 +294,64 @@ struct tps80031 { u8 cont_int_en; u8 prev_cont_stat1; struct tps80031_client tps_clients[TPS_NUM_SLAVES]; + struct regmap *regmap[TPS_NUM_SLAVES]; }; -static inline int __tps80031_read(struct i2c_client *client, - int reg, uint8_t *val) -{ - int ret; - - ret = i2c_smbus_read_byte_data(client, reg); - if (ret < 0) { - dev_err(&client->dev, - "failed reading from addr 0x%02x, reg 0x%02x\n", - client->addr, reg); - return ret; - } - - *val = (uint8_t)ret; - - return 0; -} - -static inline int __tps80031_reads(struct i2c_client *client, int reg, - int len, uint8_t *val) -{ - int ret; - - ret = i2c_smbus_read_i2c_block_data(client, reg, len, val); - if (ret < 0) { - dev_err(&client->dev, - "failed reading from addr 0x%02x, reg 0x%02x\n", - client->addr, reg); - return ret; - } - - return 0; -} - -static inline int __tps80031_write(struct i2c_client *client, - int reg, uint8_t val) -{ - int ret; - ret = i2c_smbus_write_byte_data(client, reg, val); - if (ret < 0) { - dev_err(&client->dev, - "failed writing 0x%02x to 0x%02x\n", val, reg); - return ret; - } - - return 0; -} - -static inline int __tps80031_writes(struct i2c_client *client, int reg, - int len, uint8_t *val) -{ - int ret; - - ret = i2c_smbus_write_i2c_block_data(client, reg, len, val); - if (ret < 0) { - dev_err(&client->dev, "failed writings to 0x%02x\n", reg); - return ret; - } - - return 0; -} - int tps80031_write(struct device *dev, int sid, int reg, uint8_t val) { struct tps80031 *tps80031 = dev_get_drvdata(dev); - struct tps80031_client *tps = &tps80031->tps_clients[sid]; - int ret; - - mutex_lock(&tps->lock); - ret = __tps80031_write(tps->client, reg, val); - mutex_unlock(&tps->lock); - return ret; + return regmap_write(tps80031->regmap[sid], reg, val); } EXPORT_SYMBOL_GPL(tps80031_write); int tps80031_writes(struct device *dev, int sid, int reg, int len, uint8_t *val) { struct tps80031 *tps80031 = dev_get_drvdata(dev); - struct tps80031_client *tps = &tps80031->tps_clients[sid]; - int ret; - - mutex_lock(&tps->lock); - ret = __tps80031_writes(tps->client, reg, len, val); - mutex_unlock(&tps->lock); - return ret; + return regmap_bulk_write(tps80031->regmap[sid], reg, val, len); } EXPORT_SYMBOL_GPL(tps80031_writes); int tps80031_read(struct device *dev, int sid, int reg, uint8_t *val) { struct tps80031 *tps80031 = dev_get_drvdata(dev); - struct tps80031_client *tps = &tps80031->tps_clients[sid]; + unsigned int ival; + int ret; - return __tps80031_read(tps->client, reg, val); + ret = regmap_read(tps80031->regmap[sid], reg, &ival); + if (ret < 0) { + dev_err(dev, "failed reading from reg 0x%02x\n", reg); + return ret; + } + + *val = ival; + return ret; } EXPORT_SYMBOL_GPL(tps80031_read); int tps80031_reads(struct device *dev, int sid, int reg, int len, uint8_t *val) { struct tps80031 *tps80031 = dev_get_drvdata(dev); - struct tps80031_client *tps = &tps80031->tps_clients[sid]; - return __tps80031_reads(tps->client, reg, len, val); + return regmap_bulk_read(tps80031->regmap[sid], reg, val, len); } EXPORT_SYMBOL_GPL(tps80031_reads); int tps80031_set_bits(struct device *dev, int sid, int reg, uint8_t bit_mask) { struct tps80031 *tps80031 = dev_get_drvdata(dev); - struct tps80031_client *tps = &tps80031->tps_clients[sid]; - uint8_t reg_val; - int ret = 0; - - mutex_lock(&tps->lock); - - ret = __tps80031_read(tps->client, reg, ®_val); - if (ret) - goto out; - if ((reg_val & bit_mask) != bit_mask) { - reg_val |= bit_mask; - ret = __tps80031_write(tps->client, reg, reg_val); - } -out: - mutex_unlock(&tps->lock); - return ret; + return regmap_update_bits(tps80031->regmap[sid], reg, + bit_mask, bit_mask); } EXPORT_SYMBOL_GPL(tps80031_set_bits); int tps80031_clr_bits(struct device *dev, int sid, int reg, uint8_t bit_mask) { struct tps80031 *tps80031 = dev_get_drvdata(dev); - struct tps80031_client *tps = &tps80031->tps_clients[sid]; - uint8_t reg_val; - int ret = 0; - mutex_lock(&tps->lock); - - ret = __tps80031_read(tps->client, reg, ®_val); - if (ret) - goto out; - - if (reg_val & bit_mask) { - reg_val &= ~bit_mask; - ret = __tps80031_write(tps->client, reg, reg_val); - } -out: - mutex_unlock(&tps->lock); - return ret; + return regmap_update_bits(tps80031->regmap[sid], reg, bit_mask, 0); } EXPORT_SYMBOL_GPL(tps80031_clr_bits); @@ -416,23 +359,8 @@ int tps80031_update(struct device *dev, int sid, int reg, uint8_t val, uint8_t mask) { struct tps80031 *tps80031 = dev_get_drvdata(dev); - struct tps80031_client *tps = &tps80031->tps_clients[sid]; - uint8_t reg_val; - int ret = 0; - - mutex_lock(&tps->lock); - - ret = __tps80031_read(tps->client, reg, ®_val); - if (ret) - goto out; - if ((reg_val & mask) != val) { - reg_val = (reg_val & ~mask) | (val & mask); - ret = __tps80031_write(tps->client, reg, reg_val); - } -out: - mutex_unlock(&tps->lock); - return ret; + return regmap_update_bits(tps80031->regmap[sid], reg, mask, val); } EXPORT_SYMBOL_GPL(tps80031_update); @@ -446,12 +374,12 @@ int tps80031_force_update(struct device *dev, int sid, int reg, uint8_t val, mutex_lock(&tps->lock); - ret = __tps80031_read(tps->client, reg, ®_val); + ret = tps80031_read(dev, sid, reg, ®_val); if (ret) goto out; reg_val = (reg_val & ~mask) | (val & mask); - ret = __tps80031_write(tps->client, reg, reg_val); + ret = tps80031_write(dev, sid, reg, reg_val); out: mutex_unlock(&tps->lock); @@ -544,7 +472,8 @@ static void tps80031_power_off(void) if (!tps->client) return; dev_info(&tps->client->dev, "switching off PMU\n"); - __tps80031_write(tps->client, TPS80031_PHOENIX_DEV_ON, DEVOFF); + tps80031_write(&tps->client->dev, SLAVE_ID1, + TPS80031_PHOENIX_DEV_ON, DEVOFF); } static void tps80031_pupd_init(struct tps80031 *tps80031, @@ -613,14 +542,14 @@ static int tps80031_gpio_get(struct gpio_chip *gc, unsigned offset) uint8_t trans; int ret; - ret = __tps80031_read(tps->client, + ret = tps80031_read(&tps->client->dev, SLAVE_ID1, pmc_ext_control_base[offset] + EXT_CONTROL_CFG_STATE, &state); if (ret) return ret; if (state != 0) { - ret = __tps80031_read(tps->client, + ret = tps80031_read(&tps->client->dev, SLAVE_ID1, pmc_ext_control_base[offset] + EXT_CONTROL_CFG_TRANS, &trans); if (ret) @@ -1115,7 +1044,7 @@ static void print_regs(const char *header, struct seq_file *s, seq_printf(s, "%s\n", header); for (i = start_offset; i <= end_offset; ++i) { - ret = __tps80031_read(tps->client, i, ®_val); + ret = tps80031_read(&tps->client->dev, sid, i, ®_val); if (ret >= 0) seq_printf(s, "Addr = 0x%02x Reg 0x%02x Value 0x%02x\n", tps->client->addr, i, reg_val); @@ -1189,6 +1118,109 @@ static void __init tps80031_debuginit(struct tps80031 *tpsi) } #endif +static bool rd_wr_reg_id0(struct device *dev, unsigned int reg) +{ + switch(reg) { + case TPS80031_ID0_PMIC_SLAVE_SMPS_DVS: + return true; + default: + pr_err("non-existing reg %s() %d reg %x\n", __func__, __LINE__, reg); + BUG(); + return false; + } +} + +static bool rd_wr_reg_id1(struct device *dev, unsigned int reg) +{ + switch(reg) { + case TPS80031_ID1_RTC: + case TPS80031_ID1_MEMORY: + case TPS80031_ID1_PMC_MASTER: + case TPS80031_ID1_PMC_SLAVE_SMPS: + case TPS80031_ID1_PMC_SLAVE_MISC: + case TPS80031_ID1_PMC_SLAVE_LDO: + case TPS80031_ID1_PMC_SLAVE_REOSURCES: + case TPS80031_ID1_PMC_PREQ_ASSIGN: + case TPS80031_ID1_PMC_MISC: + case TPS80031_ID1_PMC_PU_PD_HZ: + case TPS80031_ID1_PMC_BACKUP: + return true; + default: + pr_err("non-existing reg %s() %d reg %x\n", __func__, __LINE__, reg); + BUG(); + return false; + } +} + +static bool rd_wr_reg_id2(struct device *dev, unsigned int reg) +{ + switch(reg) { + case TPS80031_ID2_USB: + case TPS80031_ID2_GPADC_CONTROL: + case TPS80031_ID2_GPADC_RESULTS: + case TPS80031_ID2_AUXILLIARIES: + case TPS80031_ID2_CUSTOM: + case TPS80031_ID2_PWM: + case TPS80031_ID2_FUEL_GAUSE: + case TPS80031_ID2_INTERFACE_INTERRUPTS: + case TPS80031_ID2_CHARGER: + return true; + default: + pr_err("non-existing reg %s() %d reg %x\n", __func__, __LINE__, reg); + BUG(); + return false; + } +} +static bool rd_wr_reg_id3(struct device *dev, unsigned int reg) +{ + switch(reg) { + case TPS80031_ID3_TEST_LDO: + case TPS80031_ID3_TEST_SMPS: + case TPS80031_ID3_TEST_POWER: + case TPS80031_ID3_TEST_CHARGER: + case TPS80031_ID3_TEST_AUXILIIARIES: + case TPS80031_ID3_DIEID: + case TPS80031_ID3_TRIM_PHOENIX: + case TPS80031_ID3_TRIM_CUSTOM: + return true; + default: + pr_err("non-existing reg %s() %d reg %x\n", __func__, __LINE__, reg); + BUG(); + return false; + } +} + +static const struct regmap_config tps80031_regmap_configs[] = { + { + .reg_bits = 8, + .val_bits = 8, + .writeable_reg = rd_wr_reg_id0, + .readable_reg = rd_wr_reg_id0, + .max_register = TPS80031_MAX_REGISTER - 1, + }, + { + .reg_bits = 8, + .val_bits = 8, + .writeable_reg = rd_wr_reg_id1, + .readable_reg = rd_wr_reg_id1, + .max_register = TPS80031_MAX_REGISTER - 1, + }, + { + .reg_bits = 8, + .val_bits = 8, + .writeable_reg = rd_wr_reg_id2, + .readable_reg = rd_wr_reg_id2, + .max_register = TPS80031_MAX_REGISTER - 1, + }, + { + .reg_bits = 8, + .val_bits = 8, + .writeable_reg = rd_wr_reg_id3, + .readable_reg = rd_wr_reg_id3, + .max_register = TPS80031_MAX_REGISTER - 1, + }, +}; + static int __devexit tps80031_i2c_remove(struct i2c_client *client) { struct tps80031 *tps80031 = i2c_get_clientdata(client); @@ -1275,6 +1307,15 @@ static int __devinit tps80031_i2c_probe(struct i2c_client *client, } i2c_set_clientdata(tps->client, tps80031); mutex_init(&tps->lock); + + tps80031->regmap[i] = devm_regmap_init_i2c(tps->client, + &tps80031_regmap_configs[i]); + if (IS_ERR(tps80031->regmap[i])) { + ret = PTR_ERR(tps80031->regmap[i]); + dev_err(&client->dev, + "regmap %d init failed, err %d\n", i, ret); + goto fail; + } } if (client->irq) { |