diff options
Diffstat (limited to 'drivers/mfd/twl-core.c')
-rw-r--r-- | drivers/mfd/twl-core.c | 403 |
1 files changed, 175 insertions, 228 deletions
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 29473c2c95ae..ed718328eff1 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -47,6 +47,9 @@ #include <linux/i2c.h> #include <linux/i2c/twl.h> +/* Register descriptions for audio */ +#include <linux/mfd/twl4030-audio.h> + #include "twl-core.h" /* @@ -200,6 +203,105 @@ static struct twl_mapping twl4030_map[] = { { 2, TWL5031_BASEADD_INTERRUPTS }, }; +static struct reg_default twl4030_49_defaults[] = { + /* Audio Registers */ + { 0x01, 0x00}, /* CODEC_MODE */ + { 0x02, 0x00}, /* OPTION */ + /* 0x03 Unused */ + { 0x04, 0x00}, /* MICBIAS_CTL */ + { 0x05, 0x00}, /* ANAMICL */ + { 0x06, 0x00}, /* ANAMICR */ + { 0x07, 0x00}, /* AVADC_CTL */ + { 0x08, 0x00}, /* ADCMICSEL */ + { 0x09, 0x00}, /* DIGMIXING */ + { 0x0a, 0x0f}, /* ATXL1PGA */ + { 0x0b, 0x0f}, /* ATXR1PGA */ + { 0x0c, 0x0f}, /* AVTXL2PGA */ + { 0x0d, 0x0f}, /* AVTXR2PGA */ + { 0x0e, 0x00}, /* AUDIO_IF */ + { 0x0f, 0x00}, /* VOICE_IF */ + { 0x10, 0x3f}, /* ARXR1PGA */ + { 0x11, 0x3f}, /* ARXL1PGA */ + { 0x12, 0x3f}, /* ARXR2PGA */ + { 0x13, 0x3f}, /* ARXL2PGA */ + { 0x14, 0x25}, /* VRXPGA */ + { 0x15, 0x00}, /* VSTPGA */ + { 0x16, 0x00}, /* VRX2ARXPGA */ + { 0x17, 0x00}, /* AVDAC_CTL */ + { 0x18, 0x00}, /* ARX2VTXPGA */ + { 0x19, 0x32}, /* ARXL1_APGA_CTL*/ + { 0x1a, 0x32}, /* ARXR1_APGA_CTL*/ + { 0x1b, 0x32}, /* ARXL2_APGA_CTL*/ + { 0x1c, 0x32}, /* ARXR2_APGA_CTL*/ + { 0x1d, 0x00}, /* ATX2ARXPGA */ + { 0x1e, 0x00}, /* BT_IF */ + { 0x1f, 0x55}, /* BTPGA */ + { 0x20, 0x00}, /* BTSTPGA */ + { 0x21, 0x00}, /* EAR_CTL */ + { 0x22, 0x00}, /* HS_SEL */ + { 0x23, 0x00}, /* HS_GAIN_SET */ + { 0x24, 0x00}, /* HS_POPN_SET */ + { 0x25, 0x00}, /* PREDL_CTL */ + { 0x26, 0x00}, /* PREDR_CTL */ + { 0x27, 0x00}, /* PRECKL_CTL */ + { 0x28, 0x00}, /* PRECKR_CTL */ + { 0x29, 0x00}, /* HFL_CTL */ + { 0x2a, 0x00}, /* HFR_CTL */ + { 0x2b, 0x05}, /* ALC_CTL */ + { 0x2c, 0x00}, /* ALC_SET1 */ + { 0x2d, 0x00}, /* ALC_SET2 */ + { 0x2e, 0x00}, /* BOOST_CTL */ + { 0x2f, 0x00}, /* SOFTVOL_CTL */ + { 0x30, 0x13}, /* DTMF_FREQSEL */ + { 0x31, 0x00}, /* DTMF_TONEXT1H */ + { 0x32, 0x00}, /* DTMF_TONEXT1L */ + { 0x33, 0x00}, /* DTMF_TONEXT2H */ + { 0x34, 0x00}, /* DTMF_TONEXT2L */ + { 0x35, 0x79}, /* DTMF_TONOFF */ + { 0x36, 0x11}, /* DTMF_WANONOFF */ + { 0x37, 0x00}, /* I2S_RX_SCRAMBLE_H */ + { 0x38, 0x00}, /* I2S_RX_SCRAMBLE_M */ + { 0x39, 0x00}, /* I2S_RX_SCRAMBLE_L */ + { 0x3a, 0x06}, /* APLL_CTL */ + { 0x3b, 0x00}, /* DTMF_CTL */ + { 0x3c, 0x44}, /* DTMF_PGA_CTL2 (0x3C) */ + { 0x3d, 0x69}, /* DTMF_PGA_CTL1 (0x3D) */ + { 0x3e, 0x00}, /* MISC_SET_1 */ + { 0x3f, 0x00}, /* PCMBTMUX */ + /* 0x40 - 0x42 Unused */ + { 0x43, 0x00}, /* RX_PATH_SEL */ + { 0x44, 0x32}, /* VDL_APGA_CTL */ + { 0x45, 0x00}, /* VIBRA_CTL */ + { 0x46, 0x00}, /* VIBRA_SET */ + { 0x47, 0x00}, /* VIBRA_PWM_SET */ + { 0x48, 0x00}, /* ANAMIC_GAIN */ + { 0x49, 0x00}, /* MISC_SET_2 */ + /* End of Audio Registers */ +}; + +static bool twl4030_49_nop_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0: + case 3: + case 40: + case 41: + case 42: + return false; + default: + return true; + } +} + +static const struct regmap_range twl4030_49_volatile_ranges[] = { + regmap_reg_range(TWL4030_BASEADD_TEST, 0xff), +}; + +static const struct regmap_access_table twl4030_49_volatile_table = { + .yes_ranges = twl4030_49_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(twl4030_49_volatile_ranges), +}; + static struct regmap_config twl4030_regmap_config[4] = { { /* Address 0x48 */ @@ -212,6 +314,15 @@ static struct regmap_config twl4030_regmap_config[4] = { .reg_bits = 8, .val_bits = 8, .max_register = 0xff, + + .readable_reg = twl4030_49_nop_reg, + .writeable_reg = twl4030_49_nop_reg, + + .volatile_table = &twl4030_49_volatile_table, + + .reg_defaults = twl4030_49_defaults, + .num_reg_defaults = ARRAY_SIZE(twl4030_49_defaults), + .cache_type = REGCACHE_RBTREE, }, { /* Address 0x4a */ @@ -302,35 +413,50 @@ unsigned int twl_rev(void) EXPORT_SYMBOL(twl_rev); /** - * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0 + * twl_get_regmap - Get the regmap associated with the given module * @mod_no: module number - * @value: an array of num_bytes+1 containing data to write - * @reg: register address (just offset will do) - * @num_bytes: number of bytes to transfer * - * Returns the result of operation - 0 is success + * Returns the regmap pointer or NULL in case of failure. */ -int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) +static struct regmap *twl_get_regmap(u8 mod_no) { - int ret; int sid; struct twl_client *twl; if (unlikely(!twl_priv || !twl_priv->ready)) { pr_err("%s: not initialized\n", DRIVER_NAME); - return -EPERM; + return NULL; } if (unlikely(mod_no >= twl_get_last_module())) { pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); - return -EPERM; + return NULL; } sid = twl_priv->twl_map[mod_no].sid; twl = &twl_priv->twl_modules[sid]; - ret = regmap_bulk_write(twl->regmap, - twl_priv->twl_map[mod_no].base + reg, value, - num_bytes); + return twl->regmap; +} + +/** + * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0 + * @mod_no: module number + * @value: an array of num_bytes+1 containing data to write + * @reg: register address (just offset will do) + * @num_bytes: number of bytes to transfer + * + * Returns the result of operation - 0 is success + */ +int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) +{ + struct regmap *regmap = twl_get_regmap(mod_no); + int ret; + + if (!regmap) + return -EPERM; + + ret = regmap_bulk_write(regmap, twl_priv->twl_map[mod_no].base + reg, + value, num_bytes); if (ret) pr_err("%s: Write failed (mod %d, reg 0x%02x count %d)\n", @@ -351,25 +477,14 @@ EXPORT_SYMBOL(twl_i2c_write); */ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) { + struct regmap *regmap = twl_get_regmap(mod_no); int ret; - int sid; - struct twl_client *twl; - if (unlikely(!twl_priv || !twl_priv->ready)) { - pr_err("%s: not initialized\n", DRIVER_NAME); - return -EPERM; - } - if (unlikely(mod_no >= twl_get_last_module())) { - pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); + if (!regmap) return -EPERM; - } - sid = twl_priv->twl_map[mod_no].sid; - twl = &twl_priv->twl_modules[sid]; - - ret = regmap_bulk_read(twl->regmap, - twl_priv->twl_map[mod_no].base + reg, value, - num_bytes); + ret = regmap_bulk_read(regmap, twl_priv->twl_map[mod_no].base + reg, + value, num_bytes); if (ret) pr_err("%s: Read failed (mod %d, reg 0x%02x count %d)\n", @@ -379,6 +494,27 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) } EXPORT_SYMBOL(twl_i2c_read); +/** + * twl_regcache_bypass - Configure the regcache bypass for the regmap associated + * with the module + * @mod_no: module number + * @enable: Regcache bypass state + * + * Returns 0 else failure. + */ +int twl_set_regcache_bypass(u8 mod_no, bool enable) +{ + struct regmap *regmap = twl_get_regmap(mod_no); + + if (!regmap) + return -EPERM; + + regcache_cache_bypass(regmap, enable); + + return 0; +} +EXPORT_SYMBOL(twl_set_regcache_bypass); + /*----------------------------------------------------------------------*/ /** @@ -701,62 +837,6 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, usb3v1[0].dev_name = dev_name(child); } } - if (IS_ENABLED(CONFIG_TWL6030_USB) && pdata->usb && - twl_class_is_6030()) { - - static struct regulator_consumer_supply usb3v3; - int regulator; - - if (IS_ENABLED(CONFIG_REGULATOR_TWL4030)) { - /* this is a template that gets copied */ - struct regulator_init_data usb_fixed = { - .constraints.valid_modes_mask = - REGULATOR_MODE_NORMAL - | REGULATOR_MODE_STANDBY, - .constraints.valid_ops_mask = - REGULATOR_CHANGE_MODE - | REGULATOR_CHANGE_STATUS, - }; - - if (features & TWL6032_SUBCLASS) { - usb3v3.supply = "ldousb"; - regulator = TWL6032_REG_LDOUSB; - } else { - usb3v3.supply = "vusb"; - regulator = TWL6030_REG_VUSB; - } - child = add_regulator_linked(regulator, &usb_fixed, - &usb3v3, 1, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - } - - pdata->usb->features = features; - - child = add_child(TWL_MODULE_USB, "twl6030_usb", - pdata->usb, sizeof(*pdata->usb), true, - /* irq1 = VBUS_PRES, irq0 = USB ID */ - irq_base + USBOTG_INTR_OFFSET, - irq_base + USB_PRES_INTR_OFFSET); - - if (IS_ERR(child)) - return PTR_ERR(child); - /* we need to connect regulators to this transceiver */ - if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && child) - usb3v3.dev_name = dev_name(child); - } else if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && - twl_class_is_6030()) { - if (features & TWL6032_SUBCLASS) - child = add_regulator(TWL6032_REG_LDOUSB, - pdata->ldousb, features); - else - child = add_regulator(TWL6030_REG_VUSB, - pdata->vusb, features); - - if (IS_ERR(child)) - return PTR_ERR(child); - } if (IS_ENABLED(CONFIG_TWL4030_WATCHDOG) && twl_class_is_4030()) { child = add_child(TWL_MODULE_PM_RECEIVER, "twl4030_wdt", NULL, @@ -870,148 +950,6 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); } - /* twl6030 regulators */ - if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030() && - !(features & TWL6032_SUBCLASS)) { - child = add_regulator(TWL6030_REG_VDD1, pdata->vdd1, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6030_REG_VDD2, pdata->vdd2, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6030_REG_VDD3, pdata->vdd3, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6030_REG_V1V8, pdata->v1v8, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6030_REG_V2V1, pdata->v2v1, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6030_REG_VPP, pdata->vpp, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6030_REG_VUSIM, pdata->vusim, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6030_REG_VCXIO, pdata->vcxio, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6030_REG_VDAC, pdata->vdac, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6030_REG_VAUX2_6030, pdata->vaux2, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6030_REG_CLK32KG, pdata->clk32kg, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - } - - /* 6030 and 6025 share this regulator */ - if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030()) { - child = add_regulator(TWL6030_REG_VANA, pdata->vana, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - } - - /* twl6032 regulators */ - if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030() && - (features & TWL6032_SUBCLASS)) { - child = add_regulator(TWL6032_REG_LDO5, pdata->ldo5, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6032_REG_LDO1, pdata->ldo1, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6032_REG_LDO7, pdata->ldo7, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6032_REG_LDO6, pdata->ldo6, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6032_REG_LDOLN, pdata->ldoln, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6032_REG_LDO2, pdata->ldo2, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6032_REG_LDO4, pdata->ldo4, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6032_REG_LDO3, pdata->ldo3, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6032_REG_SMPS3, pdata->smps3, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6032_REG_SMPS4, pdata->smps4, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - child = add_regulator(TWL6032_REG_VIO, pdata->vio6025, - features); - if (IS_ERR(child)) - return PTR_ERR(child); - - } - if (IS_ENABLED(CONFIG_CHARGER_TWL4030) && pdata->bci && !(features & (TPS_SUBSET | TWL5031))) { child = add_child(TWL_MODULE_MAIN_CHARGE, "twl4030_bci", @@ -1133,6 +1071,11 @@ static int twl_remove(struct i2c_client *client) return 0; } +static struct of_dev_auxdata twl_auxdata_lookup[] = { + OF_DEV_AUXDATA("ti,twl4030-gpio", 0, "twl4030-gpio", NULL), + { /* sentinel */ }, +}; + /* NOTE: This driver only handles a single twl4030/tps659x0 chip */ static int twl_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -1271,10 +1214,14 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1); } - if (node) - status = of_platform_populate(node, NULL, NULL, &client->dev); - else + if (node) { + if (pdata) + twl_auxdata_lookup[0].platform_data = pdata->gpio; + status = of_platform_populate(node, NULL, twl_auxdata_lookup, + &client->dev); + } else { status = add_children(pdata, irq_base, id->driver_data); + } fail: if (status < 0) |