diff options
Diffstat (limited to 'drivers/mfd/twl-core.c')
| -rw-r--r-- | drivers/mfd/twl-core.c | 132 |
1 files changed, 60 insertions, 72 deletions
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 62be2326c9b2..f89eda4a17fe 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -31,6 +31,8 @@ #include <linux/regulator/machine.h> #include <linux/i2c.h> + +#include <linux/mfd/core.h> #include <linux/mfd/twl.h> /* Register descriptions for audio */ @@ -110,8 +112,8 @@ #define TWL6030_BASEADD_PWM 0x00BA #define TWL6030_BASEADD_GASGAUGE 0x00C0 #define TWL6030_BASEADD_PIH 0x00D0 -#define TWL6030_BASEADD_CHARGER 0x00E0 #define TWL6032_BASEADD_CHARGER 0x00DA +#define TWL6030_BASEADD_CHARGER 0x00E0 #define TWL6030_BASEADD_LED 0x00F4 /* subchip/slave 2 0x4A - DFT */ @@ -122,6 +124,11 @@ #define TWL6030_BASEADD_RSV 0x0000 #define TWL6030_BASEADD_ZERO 0x0000 +/* Some fields in TWL6030_PHOENIX_DEV_ON */ +#define TWL6030_APP_DEVOFF BIT(0) +#define TWL6030_CON_DEVOFF BIT(1) +#define TWL6030_MOD_DEVOFF BIT(2) + /* Few power values */ #define R_CFG_BOOT 0x05 @@ -312,7 +319,7 @@ static const struct regmap_config twl4030_regmap_config[4] = { .reg_defaults = twl4030_49_defaults, .num_reg_defaults = ARRAY_SIZE(twl4030_49_defaults), - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_MAPLE, }, { /* Address 0x4a */ @@ -353,6 +360,9 @@ static struct twl_mapping twl6030_map[] = { { 2, TWL6030_BASEADD_ZERO }, { 1, TWL6030_BASEADD_GPADC_CTRL }, { 1, TWL6030_BASEADD_GASGAUGE }, + + /* TWL6032 specific charger registers */ + { 1, TWL6032_BASEADD_CHARGER }, }; static const struct regmap_config twl6030_regmap_config[3] = { @@ -591,71 +601,6 @@ int twl_get_hfclk_rate(void) } EXPORT_SYMBOL_GPL(twl_get_hfclk_rate); -static struct device * -add_numbered_child(unsigned mod_no, const char *name, int num, - void *pdata, unsigned pdata_len, - bool can_wakeup, int irq0, int irq1) -{ - struct platform_device *pdev; - struct twl_client *twl; - int status, sid; - - if (unlikely(mod_no >= twl_get_last_module())) { - pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); - return ERR_PTR(-EPERM); - } - sid = twl_priv->twl_map[mod_no].sid; - twl = &twl_priv->twl_modules[sid]; - - pdev = platform_device_alloc(name, num); - if (!pdev) - return ERR_PTR(-ENOMEM); - - pdev->dev.parent = &twl->client->dev; - - if (pdata) { - status = platform_device_add_data(pdev, pdata, pdata_len); - if (status < 0) { - dev_dbg(&pdev->dev, "can't add platform_data\n"); - goto put_device; - } - } - - if (irq0) { - struct resource r[2] = { - { .start = irq0, .flags = IORESOURCE_IRQ, }, - { .start = irq1, .flags = IORESOURCE_IRQ, }, - }; - - status = platform_device_add_resources(pdev, r, irq1 ? 2 : 1); - if (status < 0) { - dev_dbg(&pdev->dev, "can't add irqs\n"); - goto put_device; - } - } - - status = platform_device_add(pdev); - if (status) - goto put_device; - - device_init_wakeup(&pdev->dev, can_wakeup); - - return &pdev->dev; - -put_device: - platform_device_put(pdev); - dev_err(&twl->client->dev, "failed to add device %s\n", name); - return ERR_PTR(status); -} - -static inline struct device *add_child(unsigned mod_no, const char *name, - void *pdata, unsigned pdata_len, - bool can_wakeup, int irq0, int irq1) -{ - return add_numbered_child(mod_no, name, -1, pdata, pdata_len, - can_wakeup, irq0, irq1); -} - /*----------------------------------------------------------------------*/ /* @@ -747,11 +692,33 @@ static void twl_remove(struct i2c_client *client) twl_priv->ready = false; } +static void twl6030_power_off(void) +{ + int err; + u8 val; + + err = twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &val, TWL6030_PHOENIX_DEV_ON); + if (err) + return; + + val |= TWL6030_APP_DEVOFF | TWL6030_CON_DEVOFF | TWL6030_MOD_DEVOFF; + twl_i2c_write_u8(TWL_MODULE_PM_MASTER, val, TWL6030_PHOENIX_DEV_ON); +} + + static struct of_dev_auxdata twl_auxdata_lookup[] = { OF_DEV_AUXDATA("ti,twl4030-gpio", 0, "twl4030-gpio", NULL), { /* sentinel */ }, }; +static const struct mfd_cell twl6030_cells[] = { + { .name = "twl6030-clk" }, +}; + +static const struct mfd_cell twl6032_cells[] = { + { .name = "twl6032-clk" }, +}; + /* NOTE: This driver only handles a single twl4030/tps659x0 chip */ static int twl_probe(struct i2c_client *client) @@ -803,10 +770,6 @@ twl_probe(struct i2c_client *client) if ((id->driver_data) & TWL6030_CLASS) { twl_priv->twl_id = TWL6030_CLASS_ID; twl_priv->twl_map = &twl6030_map[0]; - /* The charger base address is different in twl6032 */ - if ((id->driver_data) & TWL6032_SUBCLASS) - twl_priv->twl_map[TWL_MODULE_MAIN_CHARGE].base = - TWL6032_BASEADD_CHARGER; twl_regmap_config = twl6030_regmap_config; } else { twl_priv->twl_id = TWL4030_CLASS_ID; @@ -902,6 +865,31 @@ twl_probe(struct i2c_client *client) TWL4030_DCDC_GLOBAL_CFG); } + if (twl_class_is_6030()) { + const struct mfd_cell *cells; + int num_cells; + + if (id->driver_data & TWL6032_SUBCLASS) { + cells = twl6032_cells; + num_cells = ARRAY_SIZE(twl6032_cells); + } else { + cells = twl6030_cells; + num_cells = ARRAY_SIZE(twl6030_cells); + } + + status = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE, + cells, num_cells, NULL, 0, NULL); + if (status < 0) + goto free; + + if (of_device_is_system_power_controller(node)) { + if (!pm_power_off) + pm_power_off = twl6030_power_off; + else + dev_warn(&client->dev, "Poweroff callback already assigned\n"); + } + } + status = of_platform_populate(node, NULL, twl_auxdata_lookup, &client->dev); @@ -956,7 +944,7 @@ static struct i2c_driver twl_driver = { .driver.name = DRIVER_NAME, .driver.pm = &twl_dev_pm_ops, .id_table = twl_ids, - .probe_new = twl_probe, + .probe = twl_probe, .remove = twl_remove, }; builtin_i2c_driver(twl_driver); |
