From aa32acadcf0acc9c0017f084363048a3cc3e683d Mon Sep 17 00:00:00 2001 From: Yadwinder Singh Brar Date: Sat, 29 Jun 2013 18:21:20 +0530 Subject: mfd: s2mps11: Add device tree support This patch adds DT compatible string for s2mps11 and binding documentation. Reviewed-by: Mark Brown Signed-off-by: Yadwinder Singh Brar Signed-off-by: Lee Jones Signed-off-by: Samuel Ortiz --- drivers/mfd/sec-core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 79767681483a..e4930018005e 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -69,6 +69,9 @@ static struct of_device_id sec_dt_match[] = { { .compatible = "samsung,s5m8767-pmic", .data = (void *)S5M8767X, }, + { .compatible = "samsung,s2mps11-pmic", + .data = (void *)S2MPS11X, + }, {}, }; #endif -- cgit v1.2.3 From 4b3b4a501dee3cee869f8bacb55f2cd30044cc9b Mon Sep 17 00:00:00 2001 From: Ankur Raina Date: Fri, 5 Jul 2013 18:48:30 +0530 Subject: mfd: Fix for DA9055 driver initialization This patch clears all the events received while powering up DA9055. While powering up DA9055, both power sequencer and gpio events are received. These events remain uncleared after boot up, due to which further event handling also fails. DA9055 has three event registers. The event register bits are set to '1' on receiving an event. The events can be cleared on writing a '1' to the set bit, which would then clear that bit to '0'. After applying this patch we have a clean state after boot up. Signed-off-by: Ankur Raina Signed-off-by: Lee Jones Signed-off-by: Samuel Ortiz --- drivers/mfd/da9055-core.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/da9055-core.c b/drivers/mfd/da9055-core.c index 49cb23d37469..e4c0596723ab 100644 --- a/drivers/mfd/da9055-core.c +++ b/drivers/mfd/da9055-core.c @@ -381,6 +381,7 @@ int da9055_device_init(struct da9055 *da9055) { struct da9055_pdata *pdata = da9055->dev->platform_data; int ret; + uint8_t clear_events[3] = {0xFF, 0xFF, 0xFF}; if (pdata && pdata->init != NULL) pdata->init(da9055); @@ -390,6 +391,10 @@ int da9055_device_init(struct da9055 *da9055) else da9055->irq_base = pdata->irq_base; + ret = da9055_group_write(da9055, DA9055_REG_EVENT_A, 3, clear_events); + if (ret < 0) + return ret; + ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT, da9055->irq_base, &da9055_regmap_irq_chip, -- cgit v1.2.3 From 1d057b853962a84a2c41a0a0a7fc15a631ac96e8 Mon Sep 17 00:00:00 2001 From: Ankur Raina Date: Fri, 5 Jul 2013 16:48:14 +0530 Subject: mfd: Update DA9055 i2c device id name DA9055 is a combination of pmic and codec. This patch updates the DA9055 i2c device id name to match the standard naming convention followed for such chips. Signed-off-by: Ankur Raina Signed-off-by: Lee Jones Signed-off-by: Samuel Ortiz --- drivers/mfd/da9055-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/da9055-i2c.c b/drivers/mfd/da9055-i2c.c index 607387ffe8ca..13af7e50021e 100644 --- a/drivers/mfd/da9055-i2c.c +++ b/drivers/mfd/da9055-i2c.c @@ -54,7 +54,7 @@ static int da9055_i2c_remove(struct i2c_client *i2c) } static struct i2c_device_id da9055_i2c_id[] = { - {"da9055-pmic", 0}, + {"da9055", 0}, { } }; -- cgit v1.2.3 From 6b845ba934cc425e43615032a2f046709b95a76c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 2 Jul 2013 18:51:16 +0100 Subject: mfd: sec: Add register cache for interrupt mask registers The performance of regmap-irq is improved if the interrupt mask registers can be cached since it does read/modify/update cycles so start using the register cache infrastructure for those registers. We should use this more widely but I don't have a datasheet and this is a nice, conservative starting point. Signed-off-by: Mark Brown Signed-off-by: Lee Jones Signed-off-by: Samuel Ortiz --- drivers/mfd/sec-core.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index e4930018005e..79c07502db52 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -106,6 +106,31 @@ int sec_reg_update(struct sec_pmic_dev *sec_pmic, u8 reg, u8 val, u8 mask) } EXPORT_SYMBOL_GPL(sec_reg_update); +static bool s2mps11_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case S2MPS11_REG_INT1M: + case S2MPS11_REG_INT2M: + case S2MPS11_REG_INT3M: + return false; + default: + return true; + } +} + +static bool s5m8763_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case S5M8763_REG_IRQM1: + case S5M8763_REG_IRQM2: + case S5M8763_REG_IRQM3: + case S5M8763_REG_IRQM4: + return false; + default: + return true; + } +} + static struct regmap_config sec_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -116,6 +141,8 @@ static struct regmap_config s2mps11_regmap_config = { .val_bits = 8, .max_register = S2MPS11_REG_L38CTRL, + .volatile_reg = s2mps11_volatile, + .cache_type = REGCACHE_FLAT, }; static struct regmap_config s5m8763_regmap_config = { @@ -123,6 +150,8 @@ static struct regmap_config s5m8763_regmap_config = { .val_bits = 8, .max_register = S5M8763_REG_LBCNFG2, + .volatile_reg = s5m8763_volatile, + .cache_type = REGCACHE_FLAT, }; static struct regmap_config s5m8767_regmap_config = { @@ -130,6 +159,8 @@ static struct regmap_config s5m8767_regmap_config = { .val_bits = 8, .max_register = S5M8767_REG_LDO28CTRL, + .volatile_reg = s2mps11_volatile, + .cache_type = REGCACHE_FLAT, }; #ifdef CONFIG_OF -- cgit v1.2.3 From df04b6242a584ab3dcfe89221775085f60ba83dd Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 12 Jul 2013 13:32:02 +0200 Subject: mfd: twl6040: Remove support for legacy (pdata) mode TWL6040 is used only with OMAP4/5 SoCs and they can only boot in in DT mode. The support for pdata/legacy boot can be removed. Add TODO comment to the header file that all pdata struct can be removed in the next merge window (after the sub driver updates are in). Signed-off-by: Peter Ujfalusi Signed-off-by: Lee Jones Signed-off-by: Samuel Ortiz --- drivers/mfd/twl6040.c | 55 +++++++++++---------------------------------- include/linux/mfd/twl6040.h | 1 + 2 files changed, 14 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index 492ee2cd3400..a4034ed66dc0 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -44,17 +44,12 @@ #define VIBRACTRL_MEMBER(reg) ((reg == TWL6040_REG_VIBCTLL) ? 0 : 1) #define TWL6040_NUM_SUPPLIES (2) -static bool twl6040_has_vibra(struct twl6040_platform_data *pdata, - struct device_node *node) +static bool twl6040_has_vibra(struct device_node *node) { - if (pdata && pdata->vibra) - return true; - #ifdef CONFIG_OF if (of_find_node_by_name(node, "vibra")) return true; #endif - return false; } @@ -520,14 +515,13 @@ static struct regmap_irq_chip twl6040_irq_chip = { static int twl6040_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct twl6040_platform_data *pdata = client->dev.platform_data; struct device_node *node = client->dev.of_node; struct twl6040 *twl6040; struct mfd_cell *cell = NULL; int irq, ret, children = 0; - if (!pdata && !node) { - dev_err(&client->dev, "Platform data is missing\n"); + if (!node) { + dev_err(&client->dev, "of node is missing\n"); return -EINVAL; } @@ -576,13 +570,10 @@ static int twl6040_probe(struct i2c_client *client, twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV); /* ERRATA: Automatic power-up is not possible in ES1.0 */ - if (twl6040_get_revid(twl6040) > TWL6040_REV_ES1_0) { - if (pdata) - twl6040->audpwron = pdata->audpwron_gpio; - else - twl6040->audpwron = of_get_named_gpio(node, - "ti,audpwron-gpio", 0); - } else + if (twl6040_get_revid(twl6040) > TWL6040_REV_ES1_0) + twl6040->audpwron = of_get_named_gpio(node, + "ti,audpwron-gpio", 0); + else twl6040->audpwron = -EINVAL; if (gpio_is_valid(twl6040->audpwron)) { @@ -625,8 +616,6 @@ static int twl6040_probe(struct i2c_client *client, /* * The main functionality of twl6040 to provide audio on OMAP4+ systems. * We can add the ASoC codec child whenever this driver has been loaded. - * The ASoC codec can work without pdata, pass the platform_data only if - * it has been provided. */ irq = regmap_irq_get_virq(twl6040->irq_data, TWL6040_IRQ_PLUG); cell = &twl6040->cells[children]; @@ -635,13 +624,10 @@ static int twl6040_probe(struct i2c_client *client, twl6040_codec_rsrc[0].end = irq; cell->resources = twl6040_codec_rsrc; cell->num_resources = ARRAY_SIZE(twl6040_codec_rsrc); - if (pdata && pdata->codec) { - cell->platform_data = pdata->codec; - cell->pdata_size = sizeof(*pdata->codec); - } children++; - if (twl6040_has_vibra(pdata, node)) { + /* Vibra input driver support */ + if (twl6040_has_vibra(node)) { irq = regmap_irq_get_virq(twl6040->irq_data, TWL6040_IRQ_VIB); cell = &twl6040->cells[children]; @@ -650,28 +636,13 @@ static int twl6040_probe(struct i2c_client *client, twl6040_vibra_rsrc[0].end = irq; cell->resources = twl6040_vibra_rsrc; cell->num_resources = ARRAY_SIZE(twl6040_vibra_rsrc); - - if (pdata && pdata->vibra) { - cell->platform_data = pdata->vibra; - cell->pdata_size = sizeof(*pdata->vibra); - } children++; } - /* - * Enable the GPO driver in the following cases: - * DT booted kernel or legacy boot with valid gpo platform_data - */ - if (!pdata || (pdata && pdata->gpo)) { - cell = &twl6040->cells[children]; - cell->name = "twl6040-gpo"; - - if (pdata) { - cell->platform_data = pdata->gpo; - cell->pdata_size = sizeof(*pdata->gpo); - } - children++; - } + /* GPO support */ + cell = &twl6040->cells[children]; + cell->name = "twl6040-gpo"; + children++; ret = mfd_add_devices(&client->dev, -1, twl6040->cells, children, NULL, 0, NULL); diff --git a/include/linux/mfd/twl6040.h b/include/linux/mfd/twl6040.h index 7e7fbce7a308..6dd8893b2a56 100644 --- a/include/linux/mfd/twl6040.h +++ b/include/linux/mfd/twl6040.h @@ -185,6 +185,7 @@ #define TWL6040_GPO_MAX 3 +/* TODO: All platform data struct can be removed */ struct twl6040_codec_data { u16 hs_left_step; u16 hs_right_step; -- cgit v1.2.3 From 37aefe9f05a802a2f6f39642ae9f6ca8538df3a9 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 12 Jul 2013 13:32:03 +0200 Subject: mfd: twl6040: Cosmetic, parameter alignment change To comply with coding style. Signed-off-by: Peter Ujfalusi Signed-off-by: Lee Jones Signed-off-by: Samuel Ortiz --- drivers/mfd/twl6040.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index a4034ed66dc0..3bd110e7f518 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -549,7 +549,7 @@ static int twl6040_probe(struct i2c_client *client, twl6040->supplies[0].supply = "vio"; twl6040->supplies[1].supply = "v2v1"; ret = devm_regulator_bulk_get(&client->dev, TWL6040_NUM_SUPPLIES, - twl6040->supplies); + twl6040->supplies); if (ret != 0) { dev_err(&client->dev, "Failed to get supplies: %d\n", ret); goto regulator_get_err; @@ -578,33 +578,32 @@ static int twl6040_probe(struct i2c_client *client, if (gpio_is_valid(twl6040->audpwron)) { ret = devm_gpio_request_one(&client->dev, twl6040->audpwron, - GPIOF_OUT_INIT_LOW, "audpwron"); + GPIOF_OUT_INIT_LOW, "audpwron"); if (ret) goto gpio_err; } - ret = regmap_add_irq_chip(twl6040->regmap, twl6040->irq, - IRQF_ONESHOT, 0, &twl6040_irq_chip, - &twl6040->irq_data); + ret = regmap_add_irq_chip(twl6040->regmap, twl6040->irq, IRQF_ONESHOT, + 0, &twl6040_irq_chip,&twl6040->irq_data); if (ret < 0) goto gpio_err; twl6040->irq_ready = regmap_irq_get_virq(twl6040->irq_data, - TWL6040_IRQ_READY); + TWL6040_IRQ_READY); twl6040->irq_th = regmap_irq_get_virq(twl6040->irq_data, - TWL6040_IRQ_TH); + TWL6040_IRQ_TH); ret = devm_request_threaded_irq(twl6040->dev, twl6040->irq_ready, NULL, - twl6040_readyint_handler, IRQF_ONESHOT, - "twl6040_irq_ready", twl6040); + twl6040_readyint_handler, IRQF_ONESHOT, + "twl6040_irq_ready", twl6040); if (ret) { dev_err(twl6040->dev, "READY IRQ request failed: %d\n", ret); goto readyirq_err; } ret = devm_request_threaded_irq(twl6040->dev, twl6040->irq_th, NULL, - twl6040_thint_handler, IRQF_ONESHOT, - "twl6040_irq_th", twl6040); + twl6040_thint_handler, IRQF_ONESHOT, + "twl6040_irq_th", twl6040); if (ret) { dev_err(twl6040->dev, "Thermal IRQ request failed: %d\n", ret); goto thirq_err; -- cgit v1.2.3 From ecc8fa1c85853a7d8736a920b1b3611c2333a190 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 12 Jul 2013 13:32:04 +0200 Subject: mfd: twl6040: Cleanup in early error handling in probe function The err: label is not needed we can just return instead of the jump there. Signed-off-by: Peter Ujfalusi Signed-off-by: Lee Jones Signed-off-by: Samuel Ortiz --- drivers/mfd/twl6040.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index 3bd110e7f518..4d8d3b74d4e3 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -533,16 +533,12 @@ static int twl6040_probe(struct i2c_client *client, twl6040 = devm_kzalloc(&client->dev, sizeof(struct twl6040), GFP_KERNEL); - if (!twl6040) { - ret = -ENOMEM; - goto err; - } + if (!twl6040) + return -ENOMEM; twl6040->regmap = devm_regmap_init_i2c(client, &twl6040_regmap_config); - if (IS_ERR(twl6040->regmap)) { - ret = PTR_ERR(twl6040->regmap); - goto err; - } + if (IS_ERR(twl6040->regmap)) + return PTR_ERR(twl6040->regmap); i2c_set_clientdata(client, twl6040); @@ -660,7 +656,7 @@ gpio_err: regulator_bulk_disable(TWL6040_NUM_SUPPLIES, twl6040->supplies); regulator_get_err: i2c_set_clientdata(client, NULL); -err: + return ret; } -- cgit v1.2.3 From f10111cc83b07251e4f8788343c952a5742d748e Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sun, 14 Jul 2013 10:39:42 +0400 Subject: mfd: syscon: Remove "base" field from private driver data During a move to use managed resources, the .remove function all was deemed superfluous which subsequently led to its deletion. As there are no remaining users of the stored 'base' address we only have to use it locally during probe. Signed-off-by: Alexander Shiyan Signed-off-by: Lee Jones Signed-off-by: Samuel Ortiz --- drivers/mfd/syscon.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index 1a31512369f9..27db1f92bb26 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -25,7 +25,6 @@ static struct platform_driver syscon_driver; struct syscon { - void __iomem *base; struct regmap *regmap; }; @@ -129,6 +128,7 @@ static int syscon_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct syscon *syscon; struct resource *res; + void __iomem *base; syscon = devm_kzalloc(dev, sizeof(*syscon), GFP_KERNEL); if (!syscon) @@ -138,12 +138,12 @@ static int syscon_probe(struct platform_device *pdev) if (!res) return -ENOENT; - syscon->base = devm_ioremap(dev, res->start, resource_size(res)); - if (!syscon->base) + base = devm_ioremap(dev, res->start, resource_size(res)); + if (!base) return -ENOMEM; syscon_regmap_config.max_register = res->end - res->start - 3; - syscon->regmap = devm_regmap_init_mmio(dev, syscon->base, + syscon->regmap = devm_regmap_init_mmio(dev, base, &syscon_regmap_config); if (IS_ERR(syscon->regmap)) { dev_err(dev, "regmap init failed\n"); -- cgit v1.2.3 From ca16ecbccb718c8ba3a5d896f160831a10f8cdfb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 17 Jul 2013 12:21:09 +0100 Subject: mfd: wm8997: Make Kconfig prompt for WM8997 more consistent The Kconfig prompt for WM8997 says "Support for..." while the other MFD Kconfigs (including the adjacent ones for other Arizona devices) just list the device name which sticks out like a sore thumb when doing configuration. Signed-off-by: Mark Brown Signed-off-by: Lee Jones Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index aecd6ddcbbbf..633ee43efae6 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1070,7 +1070,7 @@ config MFD_WM5110 Support for Wolfson Microelectronics WM5110 low power audio SoC config MFD_WM8997 - bool "Support Wolfson Microelectronics WM8997" + bool "Wolfson Microelectronics WM8997" depends on MFD_ARIZONA help Support for Wolfson Microelectronics WM8997 low power audio SoC -- cgit v1.2.3 From 4dd0b2ba1d8c96d18c4a5624b167e267671d047f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 17 Jul 2013 13:16:08 +0100 Subject: mfd: wm8994: Remove unneeded check for JACKDET The jack detection code holds runtime PM references when required so there is no need for suspend to do any checks. Signed-off-by: Mark Brown Signed-off-by: Lee Jones Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8994-core.c | 14 -------------- 1 file changed, 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 781115e8dca9..e8ecb8e218d7 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -245,20 +245,6 @@ static int wm8994_suspend(struct device *dev) break; } - switch (wm8994->type) { - case WM1811: - ret = wm8994_reg_read(wm8994, WM8994_ANTIPOP_2); - if (ret < 0) { - dev_err(dev, "Failed to read jackdet: %d\n", ret); - } else if (ret & WM1811_JACKDET_MODE_MASK) { - dev_dbg(dev, "CODEC still active, ignoring suspend\n"); - return 0; - } - break; - default: - break; - } - /* Disable LDO pulldowns while the device is suspended if we * don't know that something will be driving them. */ if (!wm8994->ldo_ena_always_driven) -- cgit v1.2.3 From ebe38f80b290fe6d86404d0b21eae479d4aeb21f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 17 Jul 2013 13:16:09 +0100 Subject: mfd: wm8994: Remove check for active audio in runtime suspend Since enabling VMID takes a runtime PM reference there is no need to suppress suspend when doing a runtime suspend. Similarly the digital inputs and outputs are DAPM widgets and therefore the ASoC core will be holding a reference for them. This used to be required when integration with system suspend was being bodged. Signed-off-by: Mark Brown Signed-off-by: Lee Jones Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8994-core.c | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index e8ecb8e218d7..e1c283e6d4e5 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -201,35 +201,7 @@ static int wm8994_suspend(struct device *dev) int ret; /* Don't actually go through with the suspend if the CODEC is - * still active (eg, for audio passthrough from CP. */ - ret = wm8994_reg_read(wm8994, WM8994_POWER_MANAGEMENT_1); - if (ret < 0) { - dev_err(dev, "Failed to read power status: %d\n", ret); - } else if (ret & WM8994_VMID_SEL_MASK) { - dev_dbg(dev, "CODEC still active, ignoring suspend\n"); - return 0; - } - - ret = wm8994_reg_read(wm8994, WM8994_POWER_MANAGEMENT_4); - if (ret < 0) { - dev_err(dev, "Failed to read power status: %d\n", ret); - } else if (ret & (WM8994_AIF2ADCL_ENA | WM8994_AIF2ADCR_ENA | - WM8994_AIF1ADC2L_ENA | WM8994_AIF1ADC2R_ENA | - WM8994_AIF1ADC1L_ENA | WM8994_AIF1ADC1R_ENA)) { - dev_dbg(dev, "CODEC still active, ignoring suspend\n"); - return 0; - } - - ret = wm8994_reg_read(wm8994, WM8994_POWER_MANAGEMENT_5); - if (ret < 0) { - dev_err(dev, "Failed to read power status: %d\n", ret); - } else if (ret & (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA | - WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA | - WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA)) { - dev_dbg(dev, "CODEC still active, ignoring suspend\n"); - return 0; - } - + * still active for accessory detect. */ switch (wm8994->type) { case WM8958: case WM1811: -- cgit v1.2.3 From efe3126afce32e3100af3029a80701d47e1b6999 Mon Sep 17 00:00:00 2001 From: "Patil, Rachna" Date: Sat, 20 Jul 2013 17:27:35 +0100 Subject: MFD: ti_tscadc: ADC Clock check not required ADC is ideally expected to work at a frequency of 3MHz. The present code had a check, which returned error if the frequency went below the threshold value. But since AM335x supports various working frequencies, this check is not required. Now the code just uses the internal ADC clock divider to set the ADC frequency w.r.t the sys clock. Signed-off-by: Patil, Rachna Signed-off-by: Zubair Lutfullah Signed-off-by: Lee Jones Signed-off-by: Samuel Ortiz --- drivers/mfd/ti_am335x_tscadc.c | 6 +----- include/linux/mfd/ti_am335x_tscadc.h | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index b003a16ba227..e0852ecbc767 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -197,11 +197,7 @@ static int ti_tscadc_probe(struct platform_device *pdev) clock_rate = clk_get_rate(clk); clk_put(clk); clk_value = clock_rate / ADC_CLK; - if (clk_value < MAX_CLK_DIV) { - dev_err(&pdev->dev, "clock input less than min clock requirement\n"); - err = -EINVAL; - goto err_disable_clk; - } + /* TSCADC_CLKDIV needs to be configured to the value minus 1 */ clk_value = clk_value - 1; tscadc_writel(tscadc, REG_CLKDIV, clk_value); diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h index 8d73fe29796a..71bb41c32a64 100644 --- a/include/linux/mfd/ti_am335x_tscadc.h +++ b/include/linux/mfd/ti_am335x_tscadc.h @@ -114,7 +114,6 @@ #define CNTRLREG_TSCENB BIT(7) #define ADC_CLK 3000000 -#define MAX_CLK_DIV 7 #define TOTAL_STEPS 16 #define TOTAL_CHANNELS 8 -- cgit v1.2.3 From b5f8b7632c4fc43d42a715a1658588acc24115a9 Mon Sep 17 00:00:00 2001 From: "Patil, Rachna" Date: Sat, 20 Jul 2013 17:27:34 +0100 Subject: MFD: ti_tscadc: Disable TSC config registers in adc mode AFE Pen Ctrl and TouchScreen transistors enabling is not required when only ADC mode is being used, so check for availability of TSC driver before accessing control register. Signed-off-by: Patil, Rachna Acked-by: Vaibhav Hiremath Signed-off-by: Zubair Lutfullah Signed-off-by: Lee Jones Signed-off-by: Samuel Ortiz --- drivers/mfd/ti_am335x_tscadc.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index e0852ecbc767..cd74d594c563 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -204,13 +204,14 @@ static int ti_tscadc_probe(struct platform_device *pdev) /* Set the control register bits */ ctrl = CNTRLREG_STEPCONFIGWRT | - CNTRLREG_TSCENB | - CNTRLREG_STEPID | - CNTRLREG_4WIRE; + CNTRLREG_STEPID; + if (tsc_wires > 0) + ctrl |= CNTRLREG_4WIRE | CNTRLREG_TSCENB; tscadc_writel(tscadc, REG_CTRL, ctrl); /* Set register bits for Idle Config Mode */ - tscadc_idle_config(tscadc); + if (tsc_wires > 0) + tscadc_idle_config(tscadc); /* Enable the TSC module enable bit */ ctrl = tscadc_readl(tscadc, REG_CTRL); @@ -290,10 +291,13 @@ static int tscadc_resume(struct device *dev) pm_runtime_get_sync(dev); /* context restore */ - ctrl = CNTRLREG_STEPCONFIGWRT | CNTRLREG_TSCENB | - CNTRLREG_STEPID | CNTRLREG_4WIRE; + ctrl = CNTRLREG_STEPCONFIGWRT | CNTRLREG_STEPID; + if (tscadc_dev->tsc_cell != -1) + ctrl |= CNTRLREG_TSCENB | CNTRLREG_4WIRE; tscadc_writel(tscadc_dev, REG_CTRL, ctrl); - tscadc_idle_config(tscadc_dev); + + if (tscadc_dev->tsc_cell != -1) + tscadc_idle_config(tscadc_dev); am335x_tsc_se_update(tscadc_dev); restore = tscadc_readl(tscadc_dev, REG_CTRL); tscadc_writel(tscadc_dev, REG_CTRL, -- cgit v1.2.3 From 3e4f8789946de61c61ce6a373d069d55725d956c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 30 Jul 2013 13:19:55 +0100 Subject: mfd: wm831x: Remove erronious bits per word set Since the conversion to the regmap API setting bits per word will lead to data corruption since the regmap API already configures the bits per word appropriately. Signed-off-by: Mark Brown Signed-off-by: Lee Jones --- drivers/mfd/wm831x-spi.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c index e7ed14f661d8..07de3cc5a0d9 100644 --- a/drivers/mfd/wm831x-spi.c +++ b/drivers/mfd/wm831x-spi.c @@ -34,7 +34,6 @@ static int wm831x_spi_probe(struct spi_device *spi) if (wm831x == NULL) return -ENOMEM; - spi->bits_per_word = 16; spi->mode = SPI_MODE_0; spi_set_drvdata(spi, wm831x); -- cgit v1.2.3 From 334a41ce9b753ec615e8c6c50ee07d6197190610 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 30 Jul 2013 17:10:05 +0900 Subject: mfd: Use dev_get_platdata() Use the wrapper function for retrieving the platform data instead of accessing dev->platform_data directly. Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/88pm800.c | 2 +- drivers/mfd/88pm805.c | 2 +- drivers/mfd/88pm860x-core.c | 2 +- drivers/mfd/aat2870-core.c | 2 +- drivers/mfd/ab3100-core.c | 2 +- drivers/mfd/adp5520.c | 2 +- drivers/mfd/as3711.c | 2 +- drivers/mfd/asic3.c | 2 +- drivers/mfd/da903x.c | 2 +- drivers/mfd/da9052-core.c | 2 +- drivers/mfd/da9055-core.c | 2 +- drivers/mfd/dm355evm_msp.c | 4 ++-- drivers/mfd/ezx-pcap.c | 6 +++--- drivers/mfd/htc-egpio.c | 2 +- drivers/mfd/htc-i2cpld.c | 10 +++++----- drivers/mfd/htc-pasic3.c | 2 +- drivers/mfd/intel_msic.c | 4 ++-- drivers/mfd/kempld-core.c | 12 ++++++------ drivers/mfd/lm3533-core.c | 8 ++++---- drivers/mfd/lp8788.c | 2 +- drivers/mfd/max77686.c | 2 +- drivers/mfd/max77693.c | 2 +- drivers/mfd/max8925-i2c.c | 2 +- drivers/mfd/max8997.c | 2 +- drivers/mfd/max8998.c | 2 +- drivers/mfd/mcp-sa11x0.c | 2 +- drivers/mfd/menelaus.c | 2 +- drivers/mfd/omap-usb-host.c | 4 ++-- drivers/mfd/pcf50633-core.c | 2 +- drivers/mfd/pm8921-core.c | 2 +- drivers/mfd/rc5t583.c | 2 +- drivers/mfd/sec-core.c | 2 +- drivers/mfd/si476x-i2c.c | 2 +- drivers/mfd/sm501.c | 6 +++--- drivers/mfd/sta2x11-mfd.c | 4 ++-- drivers/mfd/t7l66xb.c | 8 ++++---- drivers/mfd/tc3589x.c | 2 +- drivers/mfd/tc6387xb.c | 6 +++--- drivers/mfd/tc6393xb.c | 8 ++++---- drivers/mfd/ti-ssp.c | 2 +- drivers/mfd/tps6105x.c | 2 +- drivers/mfd/tps65010.c | 4 ++-- drivers/mfd/tps65090.c | 2 +- drivers/mfd/tps6586x.c | 2 +- drivers/mfd/tps65912-core.c | 2 +- drivers/mfd/tps80031.c | 2 +- drivers/mfd/twl-core.c | 2 +- drivers/mfd/twl4030-audio.c | 2 +- drivers/mfd/twl4030-madc.c | 2 +- drivers/mfd/twl4030-power.c | 2 +- drivers/mfd/ucb1400_core.c | 2 +- drivers/mfd/ucb1x00-core.c | 4 ++-- drivers/mfd/wl1273-core.c | 2 +- drivers/mfd/wm831x-core.c | 2 +- drivers/mfd/wm831x-irq.c | 2 +- drivers/mfd/wm8350-i2c.c | 3 ++- drivers/mfd/wm8400-core.c | 2 +- drivers/mfd/wm8994-irq.c | 2 +- 58 files changed, 89 insertions(+), 88 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c index 6c954835d61e..cd9e17471232 100644 --- a/drivers/mfd/88pm800.c +++ b/drivers/mfd/88pm800.c @@ -541,7 +541,7 @@ static int pm800_probe(struct i2c_client *client, { int ret = 0; struct pm80x_chip *chip; - struct pm80x_platform_data *pdata = client->dev.platform_data; + struct pm80x_platform_data *pdata = dev_get_platdata(&client->dev); struct pm80x_subchip *subchip; ret = pm80x_init(client); diff --git a/drivers/mfd/88pm805.c b/drivers/mfd/88pm805.c index 521602231c7b..0686cdb06b3e 100644 --- a/drivers/mfd/88pm805.c +++ b/drivers/mfd/88pm805.c @@ -227,7 +227,7 @@ static int pm805_probe(struct i2c_client *client, { int ret = 0; struct pm80x_chip *chip; - struct pm80x_platform_data *pdata = client->dev.platform_data; + struct pm80x_platform_data *pdata = dev_get_platdata(&client->dev); ret = pm80x_init(client); if (ret) { diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index eeb481d426b5..7ebe9ef1eba6 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -1130,7 +1130,7 @@ static int pm860x_dt_init(struct device_node *np, static int pm860x_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct pm860x_platform_data *pdata = client->dev.platform_data; + struct pm860x_platform_data *pdata = dev_get_platdata(&client->dev); struct device_node *node = client->dev.of_node; struct pm860x_chip *chip; int ret; diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c index d4f594517521..6f68472e0ca6 100644 --- a/drivers/mfd/aat2870-core.c +++ b/drivers/mfd/aat2870-core.c @@ -363,7 +363,7 @@ static inline void aat2870_uninit_debugfs(struct aat2870_data *aat2870) static int aat2870_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct aat2870_platform_data *pdata = client->dev.platform_data; + struct aat2870_platform_data *pdata = dev_get_platdata(&client->dev); struct aat2870_data *aat2870; int i, j; int ret = 0; diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index ddc669d19530..b348ae520629 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -854,7 +854,7 @@ static int ab3100_probe(struct i2c_client *client, { struct ab3100 *ab3100; struct ab3100_platform_data *ab3100_plf_data = - client->dev.platform_data; + dev_get_platdata(&client->dev); int err; int i; diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c index 28346ad0b4a6..62501553d63c 100644 --- a/drivers/mfd/adp5520.c +++ b/drivers/mfd/adp5520.c @@ -207,7 +207,7 @@ static int adp5520_remove_subdevs(struct adp5520_chip *chip) static int adp5520_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct adp5520_platform_data *pdata = client->dev.platform_data; + struct adp5520_platform_data *pdata = dev_get_platdata(&client->dev); struct platform_device *pdev; struct adp5520_chip *chip; int ret; diff --git a/drivers/mfd/as3711.c b/drivers/mfd/as3711.c index 01e414162702..abd3ab7c0908 100644 --- a/drivers/mfd/as3711.c +++ b/drivers/mfd/as3711.c @@ -129,7 +129,7 @@ static int as3711_i2c_probe(struct i2c_client *client, int ret; if (!client->dev.of_node) { - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); if (!pdata) dev_dbg(&client->dev, "Platform data not found\n"); } else { diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 9532f749412f..fa22154c84e4 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -952,7 +952,7 @@ static void asic3_mfd_remove(struct platform_device *pdev) /* Core */ static int __init asic3_probe(struct platform_device *pdev) { - struct asic3_platform_data *pdata = pdev->dev.platform_data; + struct asic3_platform_data *pdata = dev_get_platdata(&pdev->dev); struct asic3 *asic; struct resource *mem; unsigned long clksel; diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c index f1a316e0d6a6..e0a2e0ee603b 100644 --- a/drivers/mfd/da903x.c +++ b/drivers/mfd/da903x.c @@ -494,7 +494,7 @@ failed: static int da903x_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct da903x_platform_data *pdata = client->dev.platform_data; + struct da903x_platform_data *pdata = dev_get_platdata(&client->dev); struct da903x_chip *chip; unsigned int tmp; int ret; diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c index a3c9613f9166..ea28a33576e4 100644 --- a/drivers/mfd/da9052-core.c +++ b/drivers/mfd/da9052-core.c @@ -534,7 +534,7 @@ EXPORT_SYMBOL_GPL(da9052_regmap_config); int da9052_device_init(struct da9052 *da9052, u8 chip_id) { - struct da9052_pdata *pdata = da9052->dev->platform_data; + struct da9052_pdata *pdata = dev_get_platdata(da9052->dev); int ret; mutex_init(&da9052->auxadc_lock); diff --git a/drivers/mfd/da9055-core.c b/drivers/mfd/da9055-core.c index e4c0596723ab..d3670cd3c3c6 100644 --- a/drivers/mfd/da9055-core.c +++ b/drivers/mfd/da9055-core.c @@ -379,7 +379,7 @@ static struct regmap_irq_chip da9055_regmap_irq_chip = { int da9055_device_init(struct da9055 *da9055) { - struct da9055_pdata *pdata = da9055->dev->platform_data; + struct da9055_pdata *pdata = dev_get_platdata(da9055->dev); int ret; uint8_t clear_events[3] = {0xFF, 0xFF, 0xFF}; diff --git a/drivers/mfd/dm355evm_msp.c b/drivers/mfd/dm355evm_msp.c index 7710227d284e..7a55c0071fa8 100644 --- a/drivers/mfd/dm355evm_msp.c +++ b/drivers/mfd/dm355evm_msp.c @@ -315,8 +315,8 @@ static int add_children(struct i2c_client *client) } /* MMC/SD inputs -- right after the last config input */ - if (client->dev.platform_data) { - void (*mmcsd_setup)(unsigned) = client->dev.platform_data; + if (dev_get_platdata(&client->dev)) { + void (*mmcsd_setup)(unsigned) = dev_get_platdata(&client->dev); mmcsd_setup(dm355evm_msp_gpio.base + 8 + 5); } diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index 5502106ad515..7245b0c5b794 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c @@ -177,7 +177,7 @@ static void pcap_msr_work(struct work_struct *work) static void pcap_isr_work(struct work_struct *work) { struct pcap_chip *pcap = container_of(work, struct pcap_chip, isr_work); - struct pcap_platform_data *pdata = pcap->spi->dev.platform_data; + struct pcap_platform_data *pdata = dev_get_platdata(&pcap->spi->dev); u32 msr, isr, int_sel, service; int irq; @@ -394,7 +394,7 @@ static int pcap_add_subdev(struct pcap_chip *pcap, static int ezx_pcap_remove(struct spi_device *spi) { struct pcap_chip *pcap = spi_get_drvdata(spi); - struct pcap_platform_data *pdata = spi->dev.platform_data; + struct pcap_platform_data *pdata = dev_get_platdata(&spi->dev); int i, adc_irq; /* remove all registered subdevs */ @@ -420,7 +420,7 @@ static int ezx_pcap_remove(struct spi_device *spi) static int ezx_pcap_probe(struct spi_device *spi) { - struct pcap_platform_data *pdata = spi->dev.platform_data; + struct pcap_platform_data *pdata = dev_get_platdata(&spi->dev); struct pcap_chip *pcap; int i, adc_irq; int ret = -ENODEV; diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c index 26aca545084b..49f39feca784 100644 --- a/drivers/mfd/htc-egpio.c +++ b/drivers/mfd/htc-egpio.c @@ -261,7 +261,7 @@ static void egpio_write_cache(struct egpio_info *ei) static int __init egpio_probe(struct platform_device *pdev) { - struct htc_egpio_platform_data *pdata = pdev->dev.platform_data; + struct htc_egpio_platform_data *pdata = dev_get_platdata(&pdev->dev); struct resource *res; struct egpio_info *ei; struct gpio_chip *chip; diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c index c9dfce6ae0c2..d7b2a75aca3e 100644 --- a/drivers/mfd/htc-i2cpld.c +++ b/drivers/mfd/htc-i2cpld.c @@ -340,7 +340,7 @@ static int htcpld_setup_chip_irq( int ret = 0; /* Get the platform and driver data */ - pdata = dev->platform_data; + pdata = dev_get_platdata(dev); htcpld = platform_get_drvdata(pdev); chip = &htcpld->chip[chip_index]; plat_chip_data = &pdata->chip[chip_index]; @@ -375,7 +375,7 @@ static int htcpld_register_chip_i2c( struct i2c_board_info info; /* Get the platform and driver data */ - pdata = dev->platform_data; + pdata = dev_get_platdata(dev); htcpld = platform_get_drvdata(pdev); chip = &htcpld->chip[chip_index]; plat_chip_data = &pdata->chip[chip_index]; @@ -447,7 +447,7 @@ static int htcpld_register_chip_gpio( int ret = 0; /* Get the platform and driver data */ - pdata = dev->platform_data; + pdata = dev_get_platdata(dev); htcpld = platform_get_drvdata(pdev); chip = &htcpld->chip[chip_index]; plat_chip_data = &pdata->chip[chip_index]; @@ -509,7 +509,7 @@ static int htcpld_setup_chips(struct platform_device *pdev) int i; /* Get the platform and driver data */ - pdata = dev->platform_data; + pdata = dev_get_platdata(dev); htcpld = platform_get_drvdata(pdev); /* Setup each chip's output GPIOs */ @@ -574,7 +574,7 @@ static int htcpld_core_probe(struct platform_device *pdev) if (!dev) return -ENODEV; - pdata = dev->platform_data; + pdata = dev_get_platdata(dev); if (!pdata) { dev_warn(dev, "Platform data not found for htcpld core!\n"); return -ENXIO; diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c index 0a5e85fd8517..6bf92a507b95 100644 --- a/drivers/mfd/htc-pasic3.c +++ b/drivers/mfd/htc-pasic3.c @@ -126,7 +126,7 @@ static struct mfd_cell ds1wm_cell __initdata = { static int __init pasic3_probe(struct platform_device *pdev) { - struct pasic3_platform_data *pdata = pdev->dev.platform_data; + struct pasic3_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device *dev = &pdev->dev; struct pasic3_data *asic; struct resource *r; diff --git a/drivers/mfd/intel_msic.c b/drivers/mfd/intel_msic.c index 4f2462f0963e..9203d47cdbb1 100644 --- a/drivers/mfd/intel_msic.c +++ b/drivers/mfd/intel_msic.c @@ -310,7 +310,7 @@ EXPORT_SYMBOL_GPL(intel_msic_irq_read); static int intel_msic_init_devices(struct intel_msic *msic) { struct platform_device *pdev = msic->pdev; - struct intel_msic_platform_data *pdata = pdev->dev.platform_data; + struct intel_msic_platform_data *pdata = dev_get_platdata(&pdev->dev); int ret, i; if (pdata->gpio) { @@ -372,7 +372,7 @@ static void intel_msic_remove_devices(struct intel_msic *msic) static int intel_msic_probe(struct platform_device *pdev) { - struct intel_msic_platform_data *pdata = pdev->dev.platform_data; + struct intel_msic_platform_data *pdata = dev_get_platdata(&pdev->dev); struct intel_msic *msic; struct resource *res; u8 id0, id1; diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c index 686a4565acb6..ab36e6ebbf8b 100644 --- a/drivers/mfd/kempld-core.c +++ b/drivers/mfd/kempld-core.c @@ -258,7 +258,7 @@ EXPORT_SYMBOL_GPL(kempld_write32); */ void kempld_get_mutex(struct kempld_device_data *pld) { - struct kempld_platform_data *pdata = pld->dev->platform_data; + struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); mutex_lock(&pld->lock); pdata->get_hardware_mutex(pld); @@ -271,7 +271,7 @@ EXPORT_SYMBOL_GPL(kempld_get_mutex); */ void kempld_release_mutex(struct kempld_device_data *pld) { - struct kempld_platform_data *pdata = pld->dev->platform_data; + struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); pdata->release_hardware_mutex(pld); mutex_unlock(&pld->lock); @@ -288,7 +288,7 @@ EXPORT_SYMBOL_GPL(kempld_release_mutex); */ static int kempld_get_info(struct kempld_device_data *pld) { - struct kempld_platform_data *pdata = pld->dev->platform_data; + struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); return pdata->get_info(pld); } @@ -302,7 +302,7 @@ static int kempld_get_info(struct kempld_device_data *pld) */ static int kempld_register_cells(struct kempld_device_data *pld) { - struct kempld_platform_data *pdata = pld->dev->platform_data; + struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); return pdata->register_cells(pld); } @@ -357,7 +357,7 @@ static int kempld_detect_device(struct kempld_device_data *pld) static int kempld_probe(struct platform_device *pdev) { - struct kempld_platform_data *pdata = pdev->dev.platform_data; + struct kempld_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device *dev = &pdev->dev; struct kempld_device_data *pld; struct resource *ioport; @@ -394,7 +394,7 @@ static int kempld_probe(struct platform_device *pdev) static int kempld_remove(struct platform_device *pdev) { struct kempld_device_data *pld = platform_get_drvdata(pdev); - struct kempld_platform_data *pdata = pld->dev->platform_data; + struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); mfd_remove_devices(&pdev->dev); pdata->release_hardware_mutex(pld); diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c index 4b7e6dac1de8..8c29f7b27324 100644 --- a/drivers/mfd/lm3533-core.c +++ b/drivers/mfd/lm3533-core.c @@ -384,7 +384,7 @@ static struct attribute_group lm3533_attribute_group = { static int lm3533_device_als_init(struct lm3533 *lm3533) { - struct lm3533_platform_data *pdata = lm3533->dev->platform_data; + struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev); int ret; if (!pdata->als) @@ -407,7 +407,7 @@ static int lm3533_device_als_init(struct lm3533 *lm3533) static int lm3533_device_bl_init(struct lm3533 *lm3533) { - struct lm3533_platform_data *pdata = lm3533->dev->platform_data; + struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev); int i; int ret; @@ -436,7 +436,7 @@ static int lm3533_device_bl_init(struct lm3533 *lm3533) static int lm3533_device_led_init(struct lm3533 *lm3533) { - struct lm3533_platform_data *pdata = lm3533->dev->platform_data; + struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev); int i; int ret; @@ -481,7 +481,7 @@ static int lm3533_device_setup(struct lm3533 *lm3533, static int lm3533_device_init(struct lm3533 *lm3533) { - struct lm3533_platform_data *pdata = lm3533->dev->platform_data; + struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev); int ret; dev_dbg(lm3533->dev, "%s\n", __func__); diff --git a/drivers/mfd/lp8788.c b/drivers/mfd/lp8788.c index c3d3c9b4d3ad..0f1221911018 100644 --- a/drivers/mfd/lp8788.c +++ b/drivers/mfd/lp8788.c @@ -173,7 +173,7 @@ static const struct regmap_config lp8788_regmap_config = { static int lp8788_probe(struct i2c_client *cl, const struct i2c_device_id *id) { struct lp8788 *lp; - struct lp8788_platform_data *pdata = cl->dev.platform_data; + struct lp8788_platform_data *pdata = dev_get_platdata(&cl->dev); int ret; lp = devm_kzalloc(&cl->dev, sizeof(struct lp8788), GFP_KERNEL); diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index f27a21831583..522be67b2e68 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -77,7 +77,7 @@ static int max77686_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct max77686_dev *max77686 = NULL; - struct max77686_platform_data *pdata = i2c->dev.platform_data; + struct max77686_platform_data *pdata = dev_get_platdata(&i2c->dev); unsigned int data; int ret = 0; diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c index 9e60fed5ff82..c04723efc707 100644 --- a/drivers/mfd/max77693.c +++ b/drivers/mfd/max77693.c @@ -110,7 +110,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct max77693_dev *max77693; - struct max77693_platform_data *pdata = i2c->dev.platform_data; + struct max77693_platform_data *pdata = dev_get_platdata(&i2c->dev); u8 reg_data; int ret = 0; diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c index 8042b3205eaa..de7fb80a6052 100644 --- a/drivers/mfd/max8925-i2c.c +++ b/drivers/mfd/max8925-i2c.c @@ -151,7 +151,7 @@ static int max8925_dt_init(struct device_node *np, struct device *dev, static int max8925_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct max8925_platform_data *pdata = client->dev.platform_data; + struct max8925_platform_data *pdata = dev_get_platdata(&client->dev); static struct max8925_chip *chip; struct device_node *node = client->dev.of_node; diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c index 14714058f2d2..ae55dd43d09c 100644 --- a/drivers/mfd/max8997.c +++ b/drivers/mfd/max8997.c @@ -188,7 +188,7 @@ static int max8997_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct max8997_dev *max8997; - struct max8997_platform_data *pdata = i2c->dev.platform_data; + struct max8997_platform_data *pdata = dev_get_platdata(&i2c->dev); int ret = 0; max8997 = kzalloc(sizeof(struct max8997_dev), GFP_KERNEL); diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index 21af51a499f4..45bffb8c7236 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c @@ -184,7 +184,7 @@ static inline int max8998_i2c_get_driver_data(struct i2c_client *i2c, static int max8998_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct max8998_platform_data *pdata = i2c->dev.platform_data; + struct max8998_platform_data *pdata = dev_get_platdata(&i2c->dev); struct max8998_dev *max8998; int ret = 0; diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c index 13198d937e36..41c31b3ac940 100644 --- a/drivers/mfd/mcp-sa11x0.c +++ b/drivers/mfd/mcp-sa11x0.c @@ -156,7 +156,7 @@ static struct mcp_ops mcp_sa11x0 = { static int mcp_sa11x0_probe(struct platform_device *dev) { - struct mcp_plat_data *data = dev->dev.platform_data; + struct mcp_plat_data *data = dev_get_platdata(&dev->dev); struct resource *mem0, *mem1; struct mcp_sa11x0 *m; struct mcp *mcp; diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c index 998ce8cb3065..9b72a44ab60b 100644 --- a/drivers/mfd/menelaus.c +++ b/drivers/mfd/menelaus.c @@ -1189,7 +1189,7 @@ static int menelaus_probe(struct i2c_client *client, int rev = 0, val; int err = 0; struct menelaus_platform_data *menelaus_pdata = - client->dev.platform_data; + dev_get_platdata(&client->dev); if (the_menelaus) { dev_dbg(&client->dev, "only one %s for now\n", diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 759fae3ca7fb..d2b8e7189907 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -232,7 +232,7 @@ err_end: static int omap_usbhs_alloc_children(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct usbhs_omap_platform_data *pdata = dev->platform_data; + struct usbhs_omap_platform_data *pdata = dev_get_platdata(dev); struct platform_device *ehci; struct platform_device *ohci; struct resource *res; @@ -571,7 +571,7 @@ static struct of_device_id usbhs_child_match_table[] = { static int usbhs_omap_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct usbhs_omap_platform_data *pdata = dev->platform_data; + struct usbhs_omap_platform_data *pdata = dev_get_platdata(dev); struct usbhs_hcd_omap *omap; struct resource *res; int ret = 0; diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index d11567307fbe..6841d6805fd6 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -195,7 +195,7 @@ static int pcf50633_probe(struct i2c_client *client, const struct i2c_device_id *ids) { struct pcf50633 *pcf; - struct pcf50633_platform_data *pdata = client->dev.platform_data; + struct pcf50633_platform_data *pdata = dev_get_platdata(&client->dev); int i, ret; int version, variant; diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c index ecc137ffa8c3..9be6840e88ee 100644 --- a/drivers/mfd/pm8921-core.c +++ b/drivers/mfd/pm8921-core.c @@ -106,7 +106,7 @@ static int pm8921_add_subdevices(const struct pm8921_platform_data static int pm8921_probe(struct platform_device *pdev) { - const struct pm8921_platform_data *pdata = pdev->dev.platform_data; + const struct pm8921_platform_data *pdata = dev_get_platdata(&pdev->dev); struct pm8921 *pmic; int rc; u8 val; diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c index 14bdaccefbec..346330176afc 100644 --- a/drivers/mfd/rc5t583.c +++ b/drivers/mfd/rc5t583.c @@ -250,7 +250,7 @@ static int rc5t583_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct rc5t583 *rc5t583; - struct rc5t583_platform_data *pdata = i2c->dev.platform_data; + struct rc5t583_platform_data *pdata = dev_get_platdata(&i2c->dev); int ret; bool irq_init_success = false; diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 79c07502db52..86a7d611f71b 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -216,7 +216,7 @@ static inline int sec_i2c_get_driver_data(struct i2c_client *i2c, static int sec_pmic_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct sec_platform_data *pdata = i2c->dev.platform_data; + struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev); const struct regmap_config *regmap; struct sec_pmic_dev *sec_pmic; int ret; diff --git a/drivers/mfd/si476x-i2c.c b/drivers/mfd/si476x-i2c.c index f5bc8e4bd4bf..0e4a76daf187 100644 --- a/drivers/mfd/si476x-i2c.c +++ b/drivers/mfd/si476x-i2c.c @@ -718,7 +718,7 @@ static int si476x_core_probe(struct i2c_client *client, atomic_set(&core->is_alive, 0); core->power_state = SI476X_POWER_DOWN; - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); if (pdata) { memcpy(&core->power_up_parameters, &pdata->power_up_parameters, diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 9816c232e583..33f040c558d0 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -840,7 +840,7 @@ static int sm501_register_uart(struct sm501_devdata *sm, int devices) if (!pdev) return -ENOMEM; - uart_data = pdev->dev.platform_data; + uart_data = dev_get_platdata(&pdev->dev); if (devices & SM501_USE_UART0) { sm501_setup_uart_data(sm, uart_data++, 0x30000); @@ -1167,7 +1167,7 @@ static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm, if (!pdev) return -ENOMEM; - icd = pdev->dev.platform_data; + icd = dev_get_platdata(&pdev->dev); /* We keep the pin_sda and pin_scl fields relative in case the * same platform data is passed to >1 SM501. @@ -1403,7 +1403,7 @@ static int sm501_plat_probe(struct platform_device *dev) sm->dev = &dev->dev; sm->pdev_id = dev->id; - sm->platdata = dev->dev.platform_data; + sm->platdata = dev_get_platdata(&dev->dev); ret = platform_get_irq(dev, 0); if (ret < 0) { diff --git a/drivers/mfd/sta2x11-mfd.c b/drivers/mfd/sta2x11-mfd.c index d70a343078fd..65c6fa671acb 100644 --- a/drivers/mfd/sta2x11-mfd.c +++ b/drivers/mfd/sta2x11-mfd.c @@ -133,7 +133,7 @@ int sta2x11_mfd_get_regs_data(struct platform_device *dev, void __iomem **regs, spinlock_t **lock) { - struct pci_dev *pdev = *(struct pci_dev **)(dev->dev.platform_data); + struct pci_dev *pdev = *(struct pci_dev **)dev_get_platdata(&dev->dev); struct sta2x11_mfd *mfd; if (!pdev) @@ -312,7 +312,7 @@ static int sta2x11_mfd_platform_probe(struct platform_device *dev, const char *name = sta2x11_mfd_names[index]; struct regmap_config *regmap_config = sta2x11_mfd_regmap_configs[index]; - pdev = dev->dev.platform_data; + pdev = dev_get_platdata(&dev->dev); mfd = sta2x11_mfd_find(*pdev); if (!mfd) return -ENODEV; diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index a21bff283a98..9e04a7485981 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -281,7 +281,7 @@ static void t7l66xb_detach_irq(struct platform_device *dev) static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state) { struct t7l66xb *t7l66xb = platform_get_drvdata(dev); - struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev); if (pdata && pdata->suspend) pdata->suspend(dev); @@ -293,7 +293,7 @@ static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state) static int t7l66xb_resume(struct platform_device *dev) { struct t7l66xb *t7l66xb = platform_get_drvdata(dev); - struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev); clk_enable(t7l66xb->clk48m); if (pdata && pdata->resume) @@ -313,7 +313,7 @@ static int t7l66xb_resume(struct platform_device *dev) static int t7l66xb_probe(struct platform_device *dev) { - struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev); struct t7l66xb *t7l66xb; struct resource *iomem, *rscr; int ret; @@ -409,7 +409,7 @@ err_noirq: static int t7l66xb_remove(struct platform_device *dev) { - struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev); struct t7l66xb *t7l66xb = platform_get_drvdata(dev); int ret; diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index 4cb92bb2aea2..70f4909fee13 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c @@ -325,7 +325,7 @@ static int tc3589x_of_probe(struct device_node *np, static int tc3589x_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct tc3589x_platform_data *pdata = i2c->dev.platform_data; + struct tc3589x_platform_data *pdata = dev_get_platdata(&i2c->dev); struct device_node *np = i2c->dev.of_node; struct tc3589x *tc3589x; int ret; diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c index 65c425a517c5..acd0f3a41044 100644 --- a/drivers/mfd/tc6387xb.c +++ b/drivers/mfd/tc6387xb.c @@ -48,7 +48,7 @@ static struct resource tc6387xb_mmc_resources[] = { static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state) { struct tc6387xb *tc6387xb = platform_get_drvdata(dev); - struct tc6387xb_platform_data *pdata = dev->dev.platform_data; + struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev); if (pdata && pdata->suspend) pdata->suspend(dev); @@ -60,7 +60,7 @@ static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state) static int tc6387xb_resume(struct platform_device *dev) { struct tc6387xb *tc6387xb = platform_get_drvdata(dev); - struct tc6387xb_platform_data *pdata = dev->dev.platform_data; + struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev); clk_enable(tc6387xb->clk32k); if (pdata && pdata->resume) @@ -140,7 +140,7 @@ static struct mfd_cell tc6387xb_cells[] = { static int tc6387xb_probe(struct platform_device *dev) { - struct tc6387xb_platform_data *pdata = dev->dev.platform_data; + struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev); struct resource *iomem, *rscr; struct clk *clk32k; struct tc6387xb *tc6387xb; diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index a563dfa3cf87..11c19e538551 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -604,7 +604,7 @@ static void tc6393xb_detach_irq(struct platform_device *dev) static int tc6393xb_probe(struct platform_device *dev) { - struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; + struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev); struct tc6393xb *tc6393xb; struct resource *iomem, *rscr; int ret, temp; @@ -733,7 +733,7 @@ err_kzalloc: static int tc6393xb_remove(struct platform_device *dev) { - struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; + struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev); struct tc6393xb *tc6393xb = platform_get_drvdata(dev); int ret; @@ -765,7 +765,7 @@ static int tc6393xb_remove(struct platform_device *dev) #ifdef CONFIG_PM static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state) { - struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; + struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev); struct tc6393xb *tc6393xb = platform_get_drvdata(dev); int i, ret; @@ -788,7 +788,7 @@ static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state) static int tc6393xb_resume(struct platform_device *dev) { - struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; + struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev); struct tc6393xb *tc6393xb = platform_get_drvdata(dev); int ret; int i; diff --git a/drivers/mfd/ti-ssp.c b/drivers/mfd/ti-ssp.c index 09a14cec351b..1c2b994e1f6c 100644 --- a/drivers/mfd/ti-ssp.c +++ b/drivers/mfd/ti-ssp.c @@ -318,7 +318,7 @@ static irqreturn_t ti_ssp_interrupt(int irq, void *dev_data) static int ti_ssp_probe(struct platform_device *pdev) { static struct ti_ssp *ssp; - const struct ti_ssp_data *pdata = pdev->dev.platform_data; + const struct ti_ssp_data *pdata = dev_get_platdata(&pdev->dev); int error = 0, prediv = 0xff, id; unsigned long sysclk; struct device *dev = &pdev->dev; diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c index 1d302f583adf..b5dfa6e4e692 100644 --- a/drivers/mfd/tps6105x.c +++ b/drivers/mfd/tps6105x.c @@ -147,7 +147,7 @@ static int tps6105x_probe(struct i2c_client *client, i2c_set_clientdata(client, tps6105x); tps6105x->client = client; - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); tps6105x->pdata = pdata; mutex_init(&tps6105x->lock); diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c index da2691f22e11..4d6769268739 100644 --- a/drivers/mfd/tps65010.c +++ b/drivers/mfd/tps65010.c @@ -517,7 +517,7 @@ static struct tps65010 *the_tps; static int __exit tps65010_remove(struct i2c_client *client) { struct tps65010 *tps = i2c_get_clientdata(client); - struct tps65010_board *board = client->dev.platform_data; + struct tps65010_board *board = dev_get_platdata(&client->dev); if (board && board->teardown) { int status = board->teardown(client, board->context); @@ -539,7 +539,7 @@ static int tps65010_probe(struct i2c_client *client, { struct tps65010 *tps; int status; - struct tps65010_board *board = client->dev.platform_data; + struct tps65010_board *board = dev_get_platdata(&client->dev); if (the_tps) { dev_dbg(&client->dev, "only one tps6501x chip allowed\n"); diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c index fbd6ee67b5a5..e6f03a733879 100644 --- a/drivers/mfd/tps65090.c +++ b/drivers/mfd/tps65090.c @@ -172,7 +172,7 @@ MODULE_DEVICE_TABLE(of, tps65090_of_match); static int tps65090_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct tps65090_platform_data *pdata = client->dev.platform_data; + struct tps65090_platform_data *pdata = dev_get_platdata(&client->dev); int irq_base = 0; struct tps65090 *tps65090; int ret; diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 4b93ed4d5cd6..f54fe4d4f77b 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -462,7 +462,7 @@ static void tps6586x_power_off(void) static int tps6586x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct tps6586x_platform_data *pdata = client->dev.platform_data; + struct tps6586x_platform_data *pdata = dev_get_platdata(&client->dev); struct tps6586x *tps6586x; int ret; diff --git a/drivers/mfd/tps65912-core.c b/drivers/mfd/tps65912-core.c index 479886a4cf80..925a044cbdf6 100644 --- a/drivers/mfd/tps65912-core.c +++ b/drivers/mfd/tps65912-core.c @@ -123,7 +123,7 @@ EXPORT_SYMBOL_GPL(tps65912_reg_write); int tps65912_device_init(struct tps65912 *tps65912) { - struct tps65912_board *pmic_plat_data = tps65912->dev->platform_data; + struct tps65912_board *pmic_plat_data = dev_get_platdata(tps65912->dev); struct tps65912_platform_data *init_data; int ret, dcdc_avs, value; diff --git a/drivers/mfd/tps80031.c b/drivers/mfd/tps80031.c index c90a2c450f51..f15ee6d5cfbf 100644 --- a/drivers/mfd/tps80031.c +++ b/drivers/mfd/tps80031.c @@ -418,7 +418,7 @@ static const struct regmap_config tps80031_regmap_configs[] = { static int tps80031_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct tps80031_platform_data *pdata = client->dev.platform_data; + struct tps80031_platform_data *pdata = dev_get_platdata(&client->dev); struct tps80031 *tps80031; int ret; uint8_t es_version; diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 7f150d94d295..29473c2c95ae 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -1137,7 +1137,7 @@ static int twl_remove(struct i2c_client *client) static int twl_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct twl4030_platform_data *pdata = client->dev.platform_data; + struct twl4030_platform_data *pdata = dev_get_platdata(&client->dev); struct device_node *node = client->dev.of_node; struct platform_device *pdev; struct regmap_config *twl_regmap_config; diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index a31fba96ef43..07fe542e6fc0 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -187,7 +187,7 @@ static bool twl4030_audio_has_vibra(struct twl4030_audio_data *pdata, static int twl4030_audio_probe(struct platform_device *pdev) { struct twl4030_audio *audio; - struct twl4030_audio_data *pdata = pdev->dev.platform_data; + struct twl4030_audio_data *pdata = dev_get_platdata(&pdev->dev); struct device_node *node = pdev->dev.of_node; struct mfd_cell *cell = NULL; int ret, childs = 0; diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index 1ea54d4d003a..4c583e471339 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c @@ -701,7 +701,7 @@ static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on) static int twl4030_madc_probe(struct platform_device *pdev) { struct twl4030_madc_data *madc; - struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data; + struct twl4030_madc_platform_data *pdata = dev_get_platdata(&pdev->dev); int ret; u8 regval; diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index a5fd3c738211..275ec5704c71 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -555,7 +555,7 @@ static bool twl4030_power_use_poweroff(struct twl4030_power_data *pdata, int twl4030_power_probe(struct platform_device *pdev) { - struct twl4030_power_data *pdata = pdev->dev.platform_data; + struct twl4030_power_data *pdata = dev_get_platdata(&pdev->dev); struct device_node *node = pdev->dev.of_node; int err = 0; int err2 = 0; diff --git a/drivers/mfd/ucb1400_core.c b/drivers/mfd/ucb1400_core.c index e9031fa9d53d..ebb20edf9c17 100644 --- a/drivers/mfd/ucb1400_core.c +++ b/drivers/mfd/ucb1400_core.c @@ -52,7 +52,7 @@ static int ucb1400_core_probe(struct device *dev) struct ucb1400_ts ucb_ts; struct ucb1400_gpio ucb_gpio; struct snd_ac97 *ac97; - struct ucb1400_pdata *pdata = dev->platform_data; + struct ucb1400_pdata *pdata = dev_get_platdata(dev); memset(&ucb_ts, 0, sizeof(ucb_ts)); memset(&ucb_gpio, 0, sizeof(ucb_gpio)); diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index 70f02daeb22a..48ad48c2ef25 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c @@ -671,7 +671,7 @@ void ucb1x00_unregister_driver(struct ucb1x00_driver *drv) static int ucb1x00_suspend(struct device *dev) { - struct ucb1x00_plat_data *pdata = dev->platform_data; + struct ucb1x00_plat_data *pdata = dev_get_platdata(dev); struct ucb1x00 *ucb = dev_get_drvdata(dev); struct ucb1x00_dev *udev; @@ -703,7 +703,7 @@ static int ucb1x00_suspend(struct device *dev) static int ucb1x00_resume(struct device *dev) { - struct ucb1x00_plat_data *pdata = dev->platform_data; + struct ucb1x00_plat_data *pdata = dev_get_platdata(dev); struct ucb1x00 *ucb = dev_get_drvdata(dev); struct ucb1x00_dev *udev; diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c index edbe6c1b755a..1288e9943f01 100644 --- a/drivers/mfd/wl1273-core.c +++ b/drivers/mfd/wl1273-core.c @@ -185,7 +185,7 @@ static int wl1273_core_remove(struct i2c_client *client) static int wl1273_core_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct wl1273_fm_platform_data *pdata = client->dev.platform_data; + struct wl1273_fm_platform_data *pdata = dev_get_platdata(&client->dev); struct wl1273_core *core; struct mfd_cell *cell; int children = 0; diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 521340a708d3..5c459f469224 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -1618,7 +1618,7 @@ EXPORT_SYMBOL_GPL(wm831x_regmap_config); */ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) { - struct wm831x_pdata *pdata = wm831x->dev->platform_data; + struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev); int rev, wm831x_num; enum wm831x_parent parent; int ret, i; diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index 804e56ec99eb..64e512eadf17 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c @@ -571,7 +571,7 @@ static struct irq_domain_ops wm831x_irq_domain_ops = { int wm831x_irq_init(struct wm831x *wm831x, int irq) { - struct wm831x_pdata *pdata = wm831x->dev->platform_data; + struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev); struct irq_domain *domain; int i, ret, irq_base; diff --git a/drivers/mfd/wm8350-i2c.c b/drivers/mfd/wm8350-i2c.c index 2e57101c8d3d..f919def05e24 100644 --- a/drivers/mfd/wm8350-i2c.c +++ b/drivers/mfd/wm8350-i2c.c @@ -27,6 +27,7 @@ static int wm8350_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct wm8350 *wm8350; + struct wm8350_platform_data *pdata = dev_get_platdata(&i2c->dev); int ret = 0; wm8350 = devm_kzalloc(&i2c->dev, sizeof(struct wm8350), GFP_KERNEL); @@ -44,7 +45,7 @@ static int wm8350_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm8350); wm8350->dev = &i2c->dev; - return wm8350_device_init(wm8350, i2c->irq, i2c->dev.platform_data); + return wm8350_device_init(wm8350, i2c->irq, pdata); } static int wm8350_i2c_remove(struct i2c_client *i2c) diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index 639ca359242f..d66d256551fb 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c @@ -178,7 +178,7 @@ static int wm8400_i2c_probe(struct i2c_client *i2c, wm8400->dev = &i2c->dev; i2c_set_clientdata(i2c, wm8400); - ret = wm8400_init(wm8400, i2c->dev.platform_data); + ret = wm8400_init(wm8400, dev_get_platdata(&i2c->dev)); if (ret != 0) goto err; diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c index d3a184a240f5..e74dedda5b55 100644 --- a/drivers/mfd/wm8994-irq.c +++ b/drivers/mfd/wm8994-irq.c @@ -193,7 +193,7 @@ int wm8994_irq_init(struct wm8994 *wm8994) { int ret; unsigned long irqflags; - struct wm8994_pdata *pdata = wm8994->dev->platform_data; + struct wm8994_pdata *pdata = dev_get_platdata(wm8994->dev); if (!wm8994->irq) { dev_warn(wm8994->dev, -- cgit v1.2.3 From a9c4055da8ee86e96cb34ad754f4f49028c8de4f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 28 Jul 2013 15:03:48 +0100 Subject: mfd: stmpe: Staticise stmpe_of_probe() It is only called from this file so there is no need for it to be in the global namespace and cause sparse to warn. Signed-off-by: Mark Brown Signed-off-by: Lee Jones --- drivers/mfd/stmpe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 5d5e6f90424a..fff63a41862c 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -1106,7 +1106,8 @@ static int stmpe_devices_init(struct stmpe *stmpe) return ret; } -void stmpe_of_probe(struct stmpe_platform_data *pdata, struct device_node *np) +static void stmpe_of_probe(struct stmpe_platform_data *pdata, + struct device_node *np) { struct device_node *child; -- cgit v1.2.3 From ed6ccdc67f0722dfe817ebb2e16ccc8d2c30187a Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 1 Aug 2013 11:01:27 +0900 Subject: mfd: max8997: Cast void pointer to data of max8997_pmic_dt_match Casting (void *) data of max8997_pmic_dt_match is necessary, because variable 'data' of struct 'of_device_id' is defined as 'const void *data'. Thus, pointer should be used instead of value. Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/max8997.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c index ae55dd43d09c..15230476dc73 100644 --- a/drivers/mfd/max8997.c +++ b/drivers/mfd/max8997.c @@ -51,7 +51,7 @@ static struct mfd_cell max8997_devs[] = { #ifdef CONFIG_OF static struct of_device_id max8997_pmic_dt_match[] = { - { .compatible = "maxim,max8997-pmic", .data = TYPE_MAX8997 }, + { .compatible = "maxim,max8997-pmic", .data = (void *)TYPE_MAX8997 }, {}, }; #endif -- cgit v1.2.3 From a1ca138ff05f1f7b5f752fae0df6e34f0f58f16c Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 1 Aug 2013 10:59:11 +0900 Subject: mfd: lpc_ich: Staticize struct 'lpc_chipset_info' 'lpc_chipset_info' is used only in this file. Fix the following sparse warning: drivers/mfd/lpc_ich.c:216:21: warning: symbol 'lpc_chipset_info' was not declared. Should it be static? Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/lpc_ich.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 24033324c17a..9483bc8472a5 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -213,7 +213,7 @@ enum lpc_chipsets { LPC_COLETO, /* Coleto Creek */ }; -struct lpc_ich_info lpc_chipset_info[] = { +static struct lpc_ich_info lpc_chipset_info[] = { [LPC_ICH] = { .name = "ICH", .iTCO_version = 1, -- cgit v1.2.3 From fae01582ce9e01283514e00073868635865b8fb4 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 1 Aug 2013 10:52:55 +0900 Subject: mfd: twl4030-power: Staticize local functions twl4030_power_configure_scripts(), twl4030_power_configure_resources(), twl4030_power_probe() are used only in this file. Fix the following sparse warnings: drivers/mfd/twl4030-power.c:496:5: warning: symbol 'twl4030_power_configure_scripts' was not declared. Should it be static? drivers/mfd/twl4030-power.c:512:5: warning: symbol 'twl4030_power_configure_resources' was not declared. Should it be static? drivers/mfd/twl4030-power.c:556:5: warning: symbol 'twl4030_power_probe' was not declared. Should it be static? Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/twl4030-power.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index 275ec5704c71..96162b62f3c0 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -493,7 +493,7 @@ int twl4030_remove_script(u8 flags) return err; } -int twl4030_power_configure_scripts(struct twl4030_power_data *pdata) +static int twl4030_power_configure_scripts(struct twl4030_power_data *pdata) { int err; int i; @@ -509,7 +509,7 @@ int twl4030_power_configure_scripts(struct twl4030_power_data *pdata) return 0; } -int twl4030_power_configure_resources(struct twl4030_power_data *pdata) +static int twl4030_power_configure_resources(struct twl4030_power_data *pdata) { struct twl4030_resconfig *resconfig = pdata->resource_config; int err; @@ -553,7 +553,7 @@ static bool twl4030_power_use_poweroff(struct twl4030_power_data *pdata, return false; } -int twl4030_power_probe(struct platform_device *pdev) +static int twl4030_power_probe(struct platform_device *pdev) { struct twl4030_power_data *pdata = dev_get_platdata(&pdev->dev); struct device_node *node = pdev->dev.of_node; -- cgit v1.2.3 From 59a9f7a32adf6537b4e4db8ca204eeb77d7a634e Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 2 Aug 2013 15:01:01 +0900 Subject: mfd: menelaus: Use NULL instead of 0 'mmc_callback_data' and 'vtg' are pointers. Fix the following sparse warning: drivers/mfd/menelaus.c:445:43: warning: Using plain integer as NULL pointer drivers/mfd/menelaus.c:469:20: warning: Using plain integer as NULL pointer Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/menelaus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c index 9b72a44ab60b..f24df8c9b02e 100644 --- a/drivers/mfd/menelaus.c +++ b/drivers/mfd/menelaus.c @@ -442,7 +442,7 @@ void menelaus_unregister_mmc_callback(void) menelaus_remove_irq_work(MENELAUS_MMC_S2D1_IRQ); the_menelaus->mmc_callback = NULL; - the_menelaus->mmc_callback_data = 0; + the_menelaus->mmc_callback_data = NULL; } EXPORT_SYMBOL(menelaus_unregister_mmc_callback); @@ -466,7 +466,7 @@ static int menelaus_set_voltage(const struct menelaus_vtg *vtg, int mV, struct i2c_client *c = the_menelaus->client; mutex_lock(&the_menelaus->lock); - if (vtg == 0) + if (!vtg) goto set_voltage; ret = menelaus_read_reg(vtg->vtg_reg); -- cgit v1.2.3 From 9924713a77a23b4bc6ac2bc8f31f08a15f0b04e1 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 2 Aug 2013 14:45:25 +0900 Subject: MFD: ucb1x00-core: Add CONFIG_PM_SLEEP to suspend/resume Add CONFIG_PM_SLEEP to suspend/resume functions to fix the build warnings when CONFIG_PM_SLEEP is not selected. This is because sleep PM callbacks defined by SET_SYSTEM_SLEEP_PM_OPS are only used when the CONFIG_PM_SLEEP is enabled. drivers/mfd/ucb1x00-core.c:672:12: warning: 'ucb1x00_suspend' defined but not used [-Wunused-function] drivers/mfd/ucb1x00-core.c:704:12: warning: 'ucb1x00_resume' defined but not used [-Wunused-function] Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/ucb1x00-core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index 48ad48c2ef25..b7cf98f75e7c 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c @@ -669,6 +669,7 @@ void ucb1x00_unregister_driver(struct ucb1x00_driver *drv) mutex_unlock(&ucb1x00_mutex); } +#ifdef CONFIG_PM_SLEEP static int ucb1x00_suspend(struct device *dev) { struct ucb1x00_plat_data *pdata = dev_get_platdata(dev); @@ -736,6 +737,7 @@ static int ucb1x00_resume(struct device *dev) mutex_unlock(&ucb1x00_mutex); return 0; } +#endif static const struct dev_pm_ops ucb1x00_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(ucb1x00_suspend, ucb1x00_resume) -- cgit v1.2.3 From f28d7ed0a54f593939758bc8d4a61134596094b1 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 2 Aug 2013 14:20:51 +0900 Subject: mfd: ab8500-gpadc: Add CONFIG_PM_RUNTIME to runtime_suspend/runtime_resume Add CONFIG_PM_RUNTIME to runtime_suspend/runtime_resume functions to fix the build warnings when CONFIG_PM_RUNTIME is not selected. This is because runtime PM callbacks defined by SET_RUNTIME_PM_OPS are only used when the CONFIG_PM_RUNTIME is enabled. drivers/mfd/ab8500-gpadc.c:870:12: warning: 'ab8500_gpadc_runtime_suspend' defined but not used [-Wunused-function] drivers/mfd/ab8500-gpadc.c:878:12: warning: 'ab8500_gpadc_runtime_resume' defined but not used [-Wunused-function] Acked-by: Linus Walleij Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/ab8500-gpadc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index 7623e9123828..77c616fd3802 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c @@ -867,6 +867,7 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc) gpadc->cal_data[ADC_INPUT_VBAT].offset); } +#ifdef CONFIG_PM_RUNTIME static int ab8500_gpadc_runtime_suspend(struct device *dev) { struct ab8500_gpadc *gpadc = dev_get_drvdata(dev); @@ -885,6 +886,7 @@ static int ab8500_gpadc_runtime_resume(struct device *dev) dev_err(dev, "Failed to enable vtvout LDO: %d\n", ret); return ret; } +#endif static int ab8500_gpadc_suspend(struct device *dev) { -- cgit v1.2.3 From e0e2e6ec5dec3a86697588cc2bea2ce07da28d5b Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Fri, 2 Aug 2013 14:21:26 +0900 Subject: mfd: ab8500-gpadc: Add CONFIG_PM_SLEEP to suspend/resume Add CONFIG_PM_SLEEP to suspend/resume functions to fix the build warnings when CONFIG_PM_SLEEP is not selected. This is because sleep PM callbacks defined by SET_SYSTEM_SLEEP_PM_OPS are only used when the CONFIG_PM_SLEEP is enabled. drivers/mfd/ab8500-gpadc.c:891:12: warning: 'ab8500_gpadc_suspend' defined but not used [-Wunused-function] drivers/mfd/ab8500-gpadc.c:903:12: warning: 'ab8500_gpadc_resume' defined but not used [-Wunused-function] Acked-by: Linus Walleij Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/ab8500-gpadc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index 77c616fd3802..36000f920981 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c @@ -888,6 +888,7 @@ static int ab8500_gpadc_runtime_resume(struct device *dev) } #endif +#ifdef CONFIG_PM_SLEEP static int ab8500_gpadc_suspend(struct device *dev) { struct ab8500_gpadc *gpadc = dev_get_drvdata(dev); @@ -915,6 +916,7 @@ static int ab8500_gpadc_resume(struct device *dev) mutex_unlock(&gpadc->ab8500_gpadc_lock); return ret; } +#endif static int ab8500_gpadc_probe(struct platform_device *pdev) { -- cgit v1.2.3 From e293e847275b2d1a4768ca25f0933a70b2383016 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 6 Aug 2013 17:18:35 +0100 Subject: mfd: arizona: Move regulator disable to after marking cache only If we disable DCVDD before we mark the cache as cache only, we might attempt to write to the chip whilst it is powered down and lose a write. Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/arizona-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 89a115301a0c..5ac3aa48473b 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -438,9 +438,9 @@ static int arizona_runtime_suspend(struct device *dev) } } - regulator_disable(arizona->dcvdd); regcache_cache_only(arizona->regmap, true); regcache_mark_dirty(arizona->regmap); + regulator_disable(arizona->dcvdd); return 0; } -- cgit v1.2.3 From 45491ada9830cd22e386499cbeb7cab2f24a1136 Mon Sep 17 00:00:00 2001 From: Zubair Lutfullah Date: Mon, 5 Aug 2013 20:10:45 +0100 Subject: mfd: ti_am335x_tscadc: Fix spin lock and reg_cache Reg_cache variable is used to lock step enable register from being accessed and written by both TSC and ADC at the same time. However, it isn't updated anywhere in the code at all. If both TSC and ADC are used, eventually 1FFFF is always written enabling all 16 steps uselessly causing a mess. Patch fixes it by correcting the locks and updates the variable by reading the step enable register Signed-off-by: Zubair Lutfullah Signed-off-by: Lee Jones --- drivers/mfd/ti_am335x_tscadc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index cd74d594c563..9f3f07ad54bd 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -57,10 +57,10 @@ EXPORT_SYMBOL_GPL(am335x_tsc_se_update); void am335x_tsc_se_set(struct ti_tscadc_dev *tsadc, u32 val) { spin_lock(&tsadc->reg_lock); + tsadc->reg_se_cache = tscadc_readl(tsadc, REG_SE); tsadc->reg_se_cache |= val; - spin_unlock(&tsadc->reg_lock); - am335x_tsc_se_update(tsadc); + spin_unlock(&tsadc->reg_lock); } EXPORT_SYMBOL_GPL(am335x_tsc_se_set); -- cgit v1.2.3 From c78d20350d682267ed48c2f907d18f2b413f3c66 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 6 Aug 2013 16:42:27 +0100 Subject: mfd: wm5110: Mark register containing FLL gains as readable The FLL gains are present on all devices and controlled from common code shared between them. This patch adds these registers into defaults list for wm5110 and marks them as readable. Reported-by: D.J. Barrow Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/wm5110-tables.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 2a7972349159..c04324d18426 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -468,12 +468,14 @@ static const struct reg_default wm5110_reg_default[] = { { 0x00000176, 0x0000 }, /* R374 - FLL1 Control 6 */ { 0x00000177, 0x0281 }, /* R375 - FLL1 Loop Filter Test 1 */ { 0x00000178, 0x0000 }, /* R376 - FLL1 NCO Test 0 */ + { 0x00000179, 0x0000 }, /* R376 - FLL1 Control 7 */ { 0x00000181, 0x0000 }, /* R385 - FLL1 Synchroniser 1 */ { 0x00000182, 0x0000 }, /* R386 - FLL1 Synchroniser 2 */ { 0x00000183, 0x0000 }, /* R387 - FLL1 Synchroniser 3 */ { 0x00000184, 0x0000 }, /* R388 - FLL1 Synchroniser 4 */ { 0x00000185, 0x0000 }, /* R389 - FLL1 Synchroniser 5 */ { 0x00000186, 0x0000 }, /* R390 - FLL1 Synchroniser 6 */ + { 0x00000187, 0x0001 }, /* R390 - FLL1 Synchroniser 7 */ { 0x00000189, 0x0000 }, /* R393 - FLL1 Spread Spectrum */ { 0x0000018A, 0x0004 }, /* R394 - FLL1 GPIO Clock */ { 0x00000191, 0x0000 }, /* R401 - FLL2 Control 1 */ @@ -484,12 +486,14 @@ static const struct reg_default wm5110_reg_default[] = { { 0x00000196, 0x0000 }, /* R406 - FLL2 Control 6 */ { 0x00000197, 0x0000 }, /* R407 - FLL2 Loop Filter Test 1 */ { 0x00000198, 0x0000 }, /* R408 - FLL2 NCO Test 0 */ + { 0x00000199, 0x0000 }, /* R408 - FLL2 Control 7 */ { 0x000001A1, 0x0000 }, /* R417 - FLL2 Synchroniser 1 */ { 0x000001A2, 0x0000 }, /* R418 - FLL2 Synchroniser 2 */ { 0x000001A3, 0x0000 }, /* R419 - FLL2 Synchroniser 3 */ { 0x000001A4, 0x0000 }, /* R420 - FLL2 Synchroniser 4 */ { 0x000001A5, 0x0000 }, /* R421 - FLL2 Synchroniser 5 */ { 0x000001A6, 0x0000 }, /* R422 - FLL2 Synchroniser 6 */ + { 0x000001A7, 0x0001 }, /* R422 - FLL2 Synchroniser 7 */ { 0x000001A9, 0x0000 }, /* R425 - FLL2 Spread Spectrum */ { 0x000001AA, 0x0004 }, /* R426 - FLL2 GPIO Clock */ { 0x00000200, 0x0006 }, /* R512 - Mic Charge Pump 1 */ @@ -1392,6 +1396,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_FLL1_CONTROL_4: case ARIZONA_FLL1_CONTROL_5: case ARIZONA_FLL1_CONTROL_6: + case ARIZONA_FLL1_CONTROL_7: case ARIZONA_FLL1_LOOP_FILTER_TEST_1: case ARIZONA_FLL1_NCO_TEST_0: case ARIZONA_FLL1_SYNCHRONISER_1: @@ -1400,6 +1405,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_FLL1_SYNCHRONISER_4: case ARIZONA_FLL1_SYNCHRONISER_5: case ARIZONA_FLL1_SYNCHRONISER_6: + case ARIZONA_FLL1_SYNCHRONISER_7: case ARIZONA_FLL1_SPREAD_SPECTRUM: case ARIZONA_FLL1_GPIO_CLOCK: case ARIZONA_FLL2_CONTROL_1: @@ -1408,6 +1414,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_FLL2_CONTROL_4: case ARIZONA_FLL2_CONTROL_5: case ARIZONA_FLL2_CONTROL_6: + case ARIZONA_FLL2_CONTROL_7: case ARIZONA_FLL2_LOOP_FILTER_TEST_1: case ARIZONA_FLL2_NCO_TEST_0: case ARIZONA_FLL2_SYNCHRONISER_1: @@ -1416,6 +1423,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_FLL2_SYNCHRONISER_4: case ARIZONA_FLL2_SYNCHRONISER_5: case ARIZONA_FLL2_SYNCHRONISER_6: + case ARIZONA_FLL2_SYNCHRONISER_7: case ARIZONA_FLL2_SPREAD_SPECTRUM: case ARIZONA_FLL2_GPIO_CLOCK: case ARIZONA_MIC_CHARGE_PUMP_1: -- cgit v1.2.3 From acf0be17836c42b5cba25eda42f5eae5d417f318 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 6 Aug 2013 16:42:28 +0100 Subject: mfd: wm5110: Add mic detect level registers The mic detect level registers are used from common code to configure the button detection code. Add these registers to the defaults list and mark them as readable for wm5110. Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/wm5110-tables.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index c04324d18426..172e9bfc4fac 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -507,6 +507,10 @@ static const struct reg_default wm5110_reg_default[] = { { 0x0000029C, 0x0000 }, /* R668 - Headphone Detect 2 */ { 0x000002A3, 0x1102 }, /* R675 - Mic Detect 1 */ { 0x000002A4, 0x009F }, /* R676 - Mic Detect 2 */ + { 0x000002A6, 0x3737 }, /* R678 - Mic Detect Level 1 */ + { 0x000002A7, 0x372C }, /* R679 - Mic Detect Level 2 */ + { 0x000002A8, 0x1422 }, /* R680 - Mic Detect Level 3 */ + { 0x000002A9, 0x300A }, /* R681 - Mic Detect Level 4 */ { 0x000002C3, 0x0000 }, /* R707 - Mic noise mix control 1 */ { 0x000002D3, 0x0000 }, /* R723 - Jack detect analogue */ { 0x00000300, 0x0000 }, /* R768 - Input Enables */ @@ -1438,6 +1442,10 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_MIC_DETECT_1: case ARIZONA_MIC_DETECT_2: case ARIZONA_MIC_DETECT_3: + case ARIZONA_MIC_DETECT_LEVEL_1: + case ARIZONA_MIC_DETECT_LEVEL_2: + case ARIZONA_MIC_DETECT_LEVEL_3: + case ARIZONA_MIC_DETECT_LEVEL_4: case ARIZONA_MIC_NOISE_MIX_CONTROL_1: case ARIZONA_JACK_DETECT_ANALOGUE: case ARIZONA_INPUT_ENABLES: -- cgit v1.2.3 From f5abfaa4396869bac41443dbe9a67dd05a52c283 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 6 Aug 2013 16:42:29 +0100 Subject: mfd: wm5110: Add missing Mic Detect 3 register into defaults Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/wm5110-tables.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 172e9bfc4fac..49032651a545 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -507,6 +507,7 @@ static const struct reg_default wm5110_reg_default[] = { { 0x0000029C, 0x0000 }, /* R668 - Headphone Detect 2 */ { 0x000002A3, 0x1102 }, /* R675 - Mic Detect 1 */ { 0x000002A4, 0x009F }, /* R676 - Mic Detect 2 */ + { 0x000002A5, 0x0000 }, /* R677 - Mic Detect 3 */ { 0x000002A6, 0x3737 }, /* R678 - Mic Detect Level 1 */ { 0x000002A7, 0x372C }, /* R679 - Mic Detect Level 2 */ { 0x000002A8, 0x1422 }, /* R680 - Mic Detect Level 3 */ -- cgit v1.2.3 From 44955ab50af17ac23ca2c5c17d91eb19daadae8b Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 6 Aug 2013 16:42:30 +0100 Subject: mfd: wm5110: Set FX_CTRL2 to volatile FX_CTRL2 is a volatile register and should be marked as such, this patch does so. Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/wm5110-tables.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 49032651a545..3113e39b318e 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -2349,6 +2349,7 @@ static bool wm5110_volatile_register(struct device *dev, unsigned int reg) case ARIZONA_IRQ_PIN_STATUS: case ARIZONA_AOD_IRQ1: case ARIZONA_AOD_IRQ2: + case ARIZONA_FX_CTRL2: case ARIZONA_ASRC_STATUS: case ARIZONA_DSP_STATUS: case ARIZONA_DSP1_CONTROL_1: -- cgit v1.2.3 From 3134bcae4f70d56df31a5b024c54115d4f504727 Mon Sep 17 00:00:00 2001 From: Yadwinder Singh Brar Date: Sun, 7 Jul 2013 17:14:21 +0530 Subject: mfd: sec: Add clock cell for s2mps11 This patch adds clock to list of mfd cells for s2mps11 and DT documentation for clock part. Reviewed-by: Mike Turquette Signed-off-by: Yadwinder Singh Brar Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/s2mps11.txt | 20 ++++++++++++++++++++ drivers/mfd/sec-core.c | 4 +++- 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/mfd/s2mps11.txt b/Documentation/devicetree/bindings/mfd/s2mps11.txt index 36e051b223c8..c9332c626021 100644 --- a/Documentation/devicetree/bindings/mfd/s2mps11.txt +++ b/Documentation/devicetree/bindings/mfd/s2mps11.txt @@ -16,6 +16,21 @@ Optional properties: - interrupts: Interrupt specifiers for interrupt sources. Optional nodes: +- clocks: s2mps11 provides three(AP/CP/BT) buffered 32.768 KHz outputs, so to + register these as clocks with common clock framework instantiate a sub-node + named "clocks". It uses the common clock binding documented in : + [Documentation/devicetree/bindings/clock/clock-bindings.txt] + - #clock-cells: should be 1. + + - The following is the list of clocks generated by the controller. Each clock + is assigned an identifier and client nodes use this identifier to specify + the clock which they consume. + Clock ID + ---------------------- + 32KhzAP 0 + 32KhzCP 1 + 32KhzBT 2 + - regulators: The regulators of s2mps11 that have to be instantiated should be included in a sub-node named 'regulators'. Regulator nodes included in this sub-node should be of the format as listed below. @@ -55,6 +70,11 @@ Example: compatible = "samsung,s2mps11-pmic"; reg = <0x66>; + s2m_osc: clocks{ + #clock-cells = 1; + clock-output-names = "xx", "yy", "zz"; + }; + regulators { ldo1_reg: LDO1 { regulator-name = "VDD_ABB_3.3V"; diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 86a7d611f71b..f530e4b73f19 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -61,7 +61,9 @@ static struct mfd_cell s5m8767_devs[] = { static struct mfd_cell s2mps11_devs[] = { { .name = "s2mps11-pmic", - }, + }, { + .name = "s2mps11-clk", + } }; #ifdef CONFIG_OF -- cgit v1.2.3 From b81eec09a484c588ead035003ce7555ca8a9963a Mon Sep 17 00:00:00 2001 From: Bill Huang Date: Thu, 8 Aug 2013 04:45:05 -0700 Subject: mfd: palmas: Add power off control Hook up "pm_power_off" to palmas power off routine if there is DT property "ti,system-power-controller" defined, so platform which is powered by this regulator can be powered off properly. Acked-by: Nishanth Menon Signed-off-by: Mallikarjun Kasoju Signed-off-by: Bill Huang Signed-off-by: Lee Jones --- .../devicetree/bindings/regulator/palmas-pmic.txt | 5 ++++ drivers/mfd/palmas.c | 33 ++++++++++++++++++++-- include/linux/mfd/palmas.h | 1 + 3 files changed, 37 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/regulator/palmas-pmic.txt b/Documentation/devicetree/bindings/regulator/palmas-pmic.txt index d5a308629c57..02f4c0eb601e 100644 --- a/Documentation/devicetree/bindings/regulator/palmas-pmic.txt +++ b/Documentation/devicetree/bindings/regulator/palmas-pmic.txt @@ -37,6 +37,9 @@ Optional nodes: ti,smps-range - OTP has the wrong range set for the hardware so override 0 - low range, 1 - high range. +- ti,system-power-controller: Telling whether or not this pmic is controlling + the system power. + Example: #include @@ -49,6 +52,8 @@ pmic { ti,ldo6-vibrator; + ti,system-power-controller; + regulators { smps12_reg : smps12 { regulator-name = "smps12"; diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index e4d1c706df8b..220a34d71f8d 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c @@ -229,6 +229,32 @@ static void palmas_dt_to_pdata(struct i2c_client *i2c, PALMAS_POWER_CTRL_ENABLE2_MASK; if (i2c->irq) palmas_set_pdata_irq_flag(i2c, pdata); + + pdata->pm_off = of_property_read_bool(node, + "ti,system-power-controller"); +} + +static struct palmas *palmas_dev; +static void palmas_power_off(void) +{ + unsigned int addr; + int ret, slave; + + if (!palmas_dev) + return; + + slave = PALMAS_BASE_TO_SLAVE(PALMAS_PMU_CONTROL_BASE); + addr = PALMAS_BASE_TO_REG(PALMAS_PMU_CONTROL_BASE, PALMAS_DEV_CTRL); + + ret = regmap_update_bits( + palmas_dev->regmap[slave], + addr, + PALMAS_DEV_CTRL_DEV_ON, + 0); + + if (ret) + pr_err("%s: Unable to write to DEV_CTRL_DEV_ON: %d\n", + __func__, ret); } static unsigned int palmas_features = PALMAS_PMIC_FEATURE_SMPS10_BOOST; @@ -423,10 +449,13 @@ no_irq: */ if (node) { ret = of_platform_populate(node, NULL, NULL, &i2c->dev); - if (ret < 0) + if (ret < 0) { goto err_irq; - else + } else if (pdata->pm_off && !pm_power_off) { + palmas_dev = palmas; + pm_power_off = palmas_power_off; return ret; + } } return ret; diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h index 1a8dd7afe084..061cce0b119a 100644 --- a/include/linux/mfd/palmas.h +++ b/include/linux/mfd/palmas.h @@ -258,6 +258,7 @@ struct palmas_platform_data { */ int mux_from_pdata; u8 pad1, pad2; + bool pm_off; struct palmas_pmic_platform_data *pmic_pdata; struct palmas_gpadc_platform_data *gpadc_pdata; -- cgit v1.2.3 From c1d33b1b188ccf70e5c9526fa293cbc783245eee Mon Sep 17 00:00:00 2001 From: Michael Brunner Date: Fri, 9 Aug 2013 17:33:43 +0200 Subject: mfd: Add support for COMe-bHL6 and COMe-cTH6 to Kontron PLD driver This patch adds DMI system IDs for the new Kontron modules COMe-bHL6 and COMe-cTH6 to the Kontron PLD driver. Acked-by: Kevin Strasser Signed-off-by: Michael Brunner Signed-off-by: Lee Jones --- drivers/mfd/kempld-core.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c index ab36e6ebbf8b..d3e23278d299 100644 --- a/drivers/mfd/kempld-core.c +++ b/drivers/mfd/kempld-core.c @@ -412,6 +412,15 @@ static struct platform_driver kempld_driver = { }; static struct dmi_system_id __initdata kempld_dmi_table[] = { + { + .ident = "BHL6", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), + DMI_MATCH(DMI_BOARD_NAME, "COMe-bHL6"), + }, + .driver_data = (void *)&kempld_platform_data_generic, + .callback = kempld_create_platform_device, + }, { .ident = "CCR2", .matches = { @@ -596,6 +605,15 @@ static struct dmi_system_id __initdata kempld_dmi_table[] = { .driver_data = (void *)&kempld_platform_data_generic, .callback = kempld_create_platform_device, }, + { + .ident = "UTH6", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), + DMI_MATCH(DMI_BOARD_NAME, "COMe-cTH6"), + }, + .driver_data = (void *)&kempld_platform_data_generic, + .callback = kempld_create_platform_device, + }, {} }; MODULE_DEVICE_TABLE(dmi, kempld_dmi_table); -- cgit v1.2.3 From bb3d5934201607d8514c9a481bd68b2bd9e5510d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 9 Aug 2013 18:25:02 +0100 Subject: mfd: tps65010: Use power efficient workqueue for power polling There is no need to use a per CPU workqueue to poll, especially with the 5s delay used, so allow the scheduler to use any CPU. Signed-off-by: Mark Brown Signed-off-by: Lee Jones --- drivers/mfd/tps65010.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c index 4d6769268739..8114567e0695 100644 --- a/drivers/mfd/tps65010.c +++ b/drivers/mfd/tps65010.c @@ -242,8 +242,8 @@ static int dbg_show(struct seq_file *s, void *_) seq_printf(s, "mask2 %s\n", buf); /* ignore ackint2 */ - schedule_delayed_work(&tps->work, POWER_POLL_DELAY); - + queue_delayed_work(system_power_efficient_wq, &tps->work, + POWER_POLL_DELAY); /* VMAIN voltage, enable lowpower, etc */ value = i2c_smbus_read_byte_data(tps->client, TPS_VDCDC1); @@ -400,7 +400,8 @@ static void tps65010_interrupt(struct tps65010 *tps) && (tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC))) poll = 1; if (poll) - schedule_delayed_work(&tps->work, POWER_POLL_DELAY); + queue_delayed_work(system_power_efficient_wq, &tps->work, + POWER_POLL_DELAY); /* also potentially gpio-in rise or fall */ } @@ -448,7 +449,7 @@ static irqreturn_t tps65010_irq(int irq, void *_tps) disable_irq_nosync(irq); set_bit(FLAG_IRQ_ENABLE, &tps->flags); - schedule_delayed_work(&tps->work, 0); + queue_delayed_work(system_power_efficient_wq, &tps->work, 0); return IRQ_HANDLED; } @@ -718,7 +719,8 @@ int tps65010_set_vbus_draw(unsigned mA) && test_and_set_bit( FLAG_VBUS_CHANGED, &the_tps->flags)) { /* gadget drivers call this in_irq() */ - schedule_delayed_work(&the_tps->work, 0); + queue_delayed_work(system_power_efficient_wq, &the_tps->work, + 0); } local_irq_restore(flags); -- cgit v1.2.3 From b018e1361bad361b47294fd09ae1f33f707dd933 Mon Sep 17 00:00:00 2001 From: Benedikt Spranger Date: Tue, 13 Aug 2013 11:08:38 +0200 Subject: mfd: core: Copy DMA mask and params from parent The child device intends to perform DMA operations then it needs a dma mask and params set. This patches copies them from the parent device. Signed-off-by: Benedikt Spranger Signed-off-by: Holger Dengler Signed-off-by: Lee Jones --- drivers/mfd/mfd-core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 7604f4e5df40..f421586f29fb 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -96,6 +96,8 @@ static int mfd_add_device(struct device *parent, int id, pdev->dev.parent = parent; pdev->dev.type = &mfd_dev_type; + pdev->dev.dma_mask = parent->dma_mask; + pdev->dev.dma_parms = parent->dma_parms; if (parent->of_node && cell->of_compatible) { for_each_child_of_node(parent->of_node, np) { -- cgit v1.2.3 From 5d945d94a15435d2a3a3b99e538fc8fc7558afc5 Mon Sep 17 00:00:00 2001 From: Zubair Lutfullah Date: Tue, 13 Aug 2013 17:40:56 +0100 Subject: mfd: ti_am335x_tscadc: Update reg_cache variable in clr function The reg_cache variable should be updated with current steps in the reg_se register. Then the mask should apply and clear the register. Previously, the reg_cache can be an old redundant value that isn't updated. Signed-off-by: Zubair Lutfullah Signed-off-by: Lee Jones --- drivers/mfd/ti_am335x_tscadc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index 9f3f07ad54bd..baaf5a8123bb 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -67,10 +67,10 @@ EXPORT_SYMBOL_GPL(am335x_tsc_se_set); void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val) { spin_lock(&tsadc->reg_lock); + tsadc->reg_se_cache = tscadc_readl(tsadc, REG_SE); tsadc->reg_se_cache &= ~val; - spin_unlock(&tsadc->reg_lock); - am335x_tsc_se_update(tsadc); + spin_unlock(&tsadc->reg_lock); } EXPORT_SYMBOL_GPL(am335x_tsc_se_clr); -- cgit v1.2.3 From 8e685483b0ba17fe08cfc36fb86b3688a24b2090 Mon Sep 17 00:00:00 2001 From: Krystian Garbaciak Date: Mon, 29 Jul 2013 19:00:43 +0200 Subject: mfd: da9063: Add Dialog DA9063 core driver This is MFD module providing access to registers and interrupts of DA906x series PMIC. It is used by other functional modules, registered as MFD cells. Driver uses regmap with paging to access extended register list. Register map is divided into two pages, where the second page is used during initialisation. This module provides support to following functional cells: - Regulators - RTC - HWMON - OnKey (power key misc input device) - Vibration (force-feedback input device) - Watchdog - LEDs Signed-off-by: Krystian Garbaciak Signed-off-by: Philipp Zabel Reviewed-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 12 +++ drivers/mfd/Makefile | 3 + drivers/mfd/da9063-core.c | 129 +++++++++++++++++++++++++++ drivers/mfd/da9063-i2c.c | 182 +++++++++++++++++++++++++++++++++++++++ include/linux/mfd/da9063/core.h | 55 ++++++++++++ include/linux/mfd/da9063/pdata.h | 111 ++++++++++++++++++++++++ 6 files changed, 492 insertions(+) create mode 100644 drivers/mfd/da9063-core.c create mode 100644 drivers/mfd/da9063-i2c.c create mode 100644 include/linux/mfd/da9063/core.h create mode 100644 include/linux/mfd/da9063/pdata.h (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 633ee43efae6..e0e46f50f95d 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -139,6 +139,18 @@ config MFD_DA9055 This driver can be built as a module. If built as a module it will be called "da9055" +config MFD_DA9063 + bool "Dialog Semiconductor DA9063 PMIC Support" + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ + depends on I2C=y && GENERIC_HARDIRQS + help + Say yes here for support for the Dialog Semiconductor DA9063 PMIC. + This includes the I2C driver and core APIs. + Additional drivers must be enabled in order to use the functionality + of the device. + config MFD_MC13783 tristate diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 3c90051ffa5a..0bb84d59f3fa 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -107,6 +107,9 @@ obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o da9055-objs := da9055-core.o da9055-i2c.o obj-$(CONFIG_MFD_DA9055) += da9055.o +da9063-objs := da9063-core.o da9063-i2c.o +obj-$(CONFIG_MFD_DA9063) += da9063.o + obj-$(CONFIG_MFD_MAX77686) += max77686.o max77686-irq.o obj-$(CONFIG_MFD_MAX77693) += max77693.o max77693-irq.o obj-$(CONFIG_MFD_MAX8907) += max8907.o diff --git a/drivers/mfd/da9063-core.c b/drivers/mfd/da9063-core.c new file mode 100644 index 000000000000..29f3ed1f076c --- /dev/null +++ b/drivers/mfd/da9063-core.c @@ -0,0 +1,129 @@ +/* + * da9063-core.c: Device access for Dialog DA9063 modules + * + * Copyright 2012 Dialog Semiconductors Ltd. + * Copyright 2013 Philipp Zabel, Pengutronix + * + * Author: Krystian Garbaciak , + * Michal Hajduk + * + * 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 +#include +#include + +#include +#include +#include + + +static struct mfd_cell da9063_devs[] = { + { + .name = DA9063_DRVNAME_REGULATORS, + }, + { + .name = DA9063_DRVNAME_LEDS, + }, + { + .name = DA9063_DRVNAME_WATCHDOG, + }, + { + .name = DA9063_DRVNAME_HWMON, + }, + { + .name = DA9063_DRVNAME_ONKEY, + }, + { + .name = DA9063_DRVNAME_RTC, + }, + { + .name = DA9063_DRVNAME_VIBRATION, + }, +}; + +int da9063_device_init(struct da9063 *da9063, unsigned int irq) +{ + struct da9063_pdata *pdata = da9063->dev->platform_data; + int model, revision; + int ret; + + if (pdata) { + da9063->flags = pdata->flags; + da9063->irq_base = pdata->irq_base; + } else { + da9063->flags = 0; + da9063->irq_base = 0; + } + da9063->chip_irq = irq; + + if (pdata && pdata->init != NULL) { + ret = pdata->init(da9063); + if (ret != 0) { + dev_err(da9063->dev, + "Platform initialization failed.\n"); + return ret; + } + } + + ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_ID, &model); + if (ret < 0) { + dev_err(da9063->dev, "Cannot read chip model id.\n"); + return -EIO; + } + if (model != PMIC_DA9063) { + dev_err(da9063->dev, "Invalid chip model id: 0x%02x\n", model); + return -ENODEV; + } + + ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_VARIANT, &revision); + if (ret < 0) { + dev_err(da9063->dev, "Cannot read chip revision id.\n"); + return -EIO; + } + revision >>= DA9063_CHIP_VARIANT_SHIFT; + if (revision != 3) { + dev_err(da9063->dev, "Unknown chip revision: %d\n", revision); + return -ENODEV; + } + + da9063->model = model; + da9063->revision = revision; + + dev_info(da9063->dev, + "Device detected (model-ID: 0x%02X rev-ID: 0x%02X)\n", + model, revision); + + ret = mfd_add_devices(da9063->dev, -1, da9063_devs, + ARRAY_SIZE(da9063_devs), NULL, da9063->irq_base, + NULL); + if (ret) + dev_err(da9063->dev, "Cannot add MFD cells\n"); + + return ret; +} + +void da9063_device_exit(struct da9063 *da9063) +{ + mfd_remove_devices(da9063->dev); +} + +MODULE_DESCRIPTION("PMIC driver for Dialog DA9063"); +MODULE_AUTHOR("Krystian Garbaciak , Michal Hajduk "); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/da9063-i2c.c b/drivers/mfd/da9063-i2c.c new file mode 100644 index 000000000000..8db5c805c64f --- /dev/null +++ b/drivers/mfd/da9063-i2c.c @@ -0,0 +1,182 @@ +/* da9063-i2c.c: Interrupt support for Dialog DA9063 + * + * Copyright 2012 Dialog Semiconductor Ltd. + * Copyright 2013 Philipp Zabel, Pengutronix + * + * Author: Krystian Garbaciak + * + * 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 regmap_range da9063_readable_ranges[] = { + { + .range_min = DA9063_REG_PAGE_CON, + .range_max = DA9063_REG_SECOND_D, + }, { + .range_min = DA9063_REG_SEQ, + .range_max = DA9063_REG_ID_32_31, + }, { + .range_min = DA9063_REG_SEQ_A, + .range_max = DA9063_REG_AUTO3_LOW, + }, { + .range_min = DA9063_REG_T_OFFSET, + .range_max = DA9063_REG_GP_ID_19, + }, { + .range_min = DA9063_REG_CHIP_ID, + .range_max = DA9063_REG_CHIP_VARIANT, + }, +}; + +static const struct regmap_range da9063_writeable_ranges[] = { + { + .range_min = DA9063_REG_PAGE_CON, + .range_max = DA9063_REG_PAGE_CON, + }, { + .range_min = DA9063_REG_FAULT_LOG, + .range_max = DA9063_REG_VSYS_MON, + }, { + .range_min = DA9063_REG_COUNT_S, + .range_max = DA9063_REG_ALARM_Y, + }, { + .range_min = DA9063_REG_SEQ, + .range_max = DA9063_REG_ID_32_31, + }, { + .range_min = DA9063_REG_SEQ_A, + .range_max = DA9063_REG_AUTO3_LOW, + }, { + .range_min = DA9063_REG_CONFIG_I, + .range_max = DA9063_REG_MON_REG_4, + }, { + .range_min = DA9063_REG_GP_ID_0, + .range_max = DA9063_REG_GP_ID_19, + }, +}; + +static const struct regmap_range da9063_volatile_ranges[] = { + { + .range_min = DA9063_REG_STATUS_A, + .range_max = DA9063_REG_EVENT_D, + }, { + .range_min = DA9063_REG_CONTROL_F, + .range_max = DA9063_REG_CONTROL_F, + }, { + .range_min = DA9063_REG_ADC_MAN, + .range_max = DA9063_REG_ADC_MAN, + }, { + .range_min = DA9063_REG_ADC_RES_L, + .range_max = DA9063_REG_SECOND_D, + }, { + .range_min = DA9063_REG_MON_REG_5, + .range_max = DA9063_REG_MON_REG_6, + }, +}; + +static const struct regmap_access_table da9063_readable_table = { + .yes_ranges = da9063_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(da9063_readable_ranges), +}; + +static const struct regmap_access_table da9063_writeable_table = { + .yes_ranges = da9063_writeable_ranges, + .n_yes_ranges = ARRAY_SIZE(da9063_writeable_ranges), +}; + +static const struct regmap_access_table da9063_volatile_table = { + .yes_ranges = da9063_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(da9063_volatile_ranges), +}; + +static const struct regmap_range_cfg da9063_range_cfg[] = { + { + .range_min = DA9063_REG_PAGE_CON, + .range_max = DA9063_REG_CHIP_VARIANT, + .selector_reg = DA9063_REG_PAGE_CON, + .selector_mask = 1 << DA9063_I2C_PAGE_SEL_SHIFT, + .selector_shift = DA9063_I2C_PAGE_SEL_SHIFT, + .window_start = 0, + .window_len = 256, + } +}; + +static struct regmap_config da9063_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .ranges = da9063_range_cfg, + .num_ranges = ARRAY_SIZE(da9063_range_cfg), + .max_register = DA9063_REG_CHIP_VARIANT, + + .cache_type = REGCACHE_RBTREE, + + .rd_table = &da9063_readable_table, + .wr_table = &da9063_writeable_table, + .volatile_table = &da9063_volatile_table, +}; + +static int da9063_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct da9063 *da9063; + int ret; + + da9063 = devm_kzalloc(&i2c->dev, sizeof(struct da9063), GFP_KERNEL); + if (da9063 == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, da9063); + da9063->dev = &i2c->dev; + da9063->chip_irq = i2c->irq; + + da9063->regmap = devm_regmap_init_i2c(i2c, &da9063_regmap_config); + if (IS_ERR(da9063->regmap)) { + ret = PTR_ERR(da9063->regmap); + dev_err(da9063->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + return da9063_device_init(da9063, i2c->irq); +} + +static int da9063_i2c_remove(struct i2c_client *i2c) +{ + struct da9063 *da9063 = i2c_get_clientdata(i2c); + + da9063_device_exit(da9063); + + return 0; +} + +static const struct i2c_device_id da9063_i2c_id[] = { + {"da9063", PMIC_DA9063}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, da9063_i2c_id); + +static struct i2c_driver da9063_i2c_driver = { + .driver = { + .name = "da9063", + .owner = THIS_MODULE, + }, + .probe = da9063_i2c_probe, + .remove = da9063_i2c_remove, + .id_table = da9063_i2c_id, +}; + +module_i2c_driver(da9063_i2c_driver); diff --git a/include/linux/mfd/da9063/core.h b/include/linux/mfd/da9063/core.h new file mode 100644 index 000000000000..ec2fd2aa24ae --- /dev/null +++ b/include/linux/mfd/da9063/core.h @@ -0,0 +1,55 @@ +/* + * Definitions for DA9063 MFD driver + * + * Copyright 2012 Dialog Semiconductor Ltd. + * + * Author: Michal Hajduk + * Krystian Garbaciak + * + * 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. + * + */ + +#ifndef __MFD_DA9063_CORE_H__ +#define __MFD_DA9063_CORE_H__ + +#include +#include + +/* DA9063 modules */ +#define DA9063_DRVNAME_CORE "da9063-core" +#define DA9063_DRVNAME_REGULATORS "da9063-regulators" +#define DA9063_DRVNAME_LEDS "da9063-leds" +#define DA9063_DRVNAME_WATCHDOG "da9063-watchdog" +#define DA9063_DRVNAME_HWMON "da9063-hwmon" +#define DA9063_DRVNAME_ONKEY "da9063-onkey" +#define DA9063_DRVNAME_RTC "da9063-rtc" +#define DA9063_DRVNAME_VIBRATION "da9063-vibration" + +enum da9063_models { + PMIC_DA9063 = 0x61, +}; + +struct da9063 { + /* Device */ + struct device *dev; + unsigned short model; + unsigned short revision; + unsigned int flags; + + /* Control interface */ + struct regmap *regmap; + + /* Interrupts */ + int chip_irq; + unsigned int irq_base; +}; + +int da9063_device_init(struct da9063 *da9063, unsigned int irq); + +void da9063_device_exit(struct da9063 *da9063); + +#endif /* __MFD_DA9063_CORE_H__ */ diff --git a/include/linux/mfd/da9063/pdata.h b/include/linux/mfd/da9063/pdata.h new file mode 100644 index 000000000000..95c8742215a7 --- /dev/null +++ b/include/linux/mfd/da9063/pdata.h @@ -0,0 +1,111 @@ +/* + * Platform configuration options for DA9063 + * + * Copyright 2012 Dialog Semiconductor Ltd. + * + * Author: Michal Hajduk + * Author: Krystian Garbaciak + * + * 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. + * + */ + +#ifndef __MFD_DA9063_PDATA_H__ +#define __MFD_DA9063_PDATA_H__ + +#include + +/* + * Regulator configuration + */ +/* DA9063 regulator IDs */ +enum { + /* BUCKs */ + DA9063_ID_BCORE1, + DA9063_ID_BCORE2, + DA9063_ID_BPRO, + DA9063_ID_BMEM, + DA9063_ID_BIO, + DA9063_ID_BPERI, + + /* BCORE1 and BCORE2 in merged mode */ + DA9063_ID_BCORES_MERGED, + /* BMEM and BIO in merged mode */ + DA9063_ID_BMEM_BIO_MERGED, + /* When two BUCKs are merged, they cannot be reused separately */ + + /* LDOs */ + DA9063_ID_LDO1, + DA9063_ID_LDO2, + DA9063_ID_LDO3, + DA9063_ID_LDO4, + DA9063_ID_LDO5, + DA9063_ID_LDO6, + DA9063_ID_LDO7, + DA9063_ID_LDO8, + DA9063_ID_LDO9, + DA9063_ID_LDO10, + DA9063_ID_LDO11, +}; + +/* Regulators platform data */ +struct da9063_regulator_data { + int id; + struct regulator_init_data *initdata; +}; + +struct da9063_regulators_pdata { + unsigned n_regulators; + struct da9063_regulator_data *regulator_data; +}; + + +/* + * RGB LED configuration + */ +/* LED IDs for flags in struct led_info. */ +enum { + DA9063_GPIO11_LED, + DA9063_GPIO14_LED, + DA9063_GPIO15_LED, + + DA9063_LED_NUM +}; +#define DA9063_LED_ID_MASK 0x3 + +/* LED polarity for flags in struct led_info. */ +#define DA9063_LED_HIGH_LEVEL_ACTIVE 0x0 +#define DA9063_LED_LOW_LEVEL_ACTIVE 0x4 + + +/* + * General PMIC configuration + */ +/* HWMON ADC channels configuration */ +#define DA9063_FLG_FORCE_IN0_MANUAL_MODE 0x0010 +#define DA9063_FLG_FORCE_IN0_AUTO_MODE 0x0020 +#define DA9063_FLG_FORCE_IN1_MANUAL_MODE 0x0040 +#define DA9063_FLG_FORCE_IN1_AUTO_MODE 0x0080 +#define DA9063_FLG_FORCE_IN2_MANUAL_MODE 0x0100 +#define DA9063_FLG_FORCE_IN2_AUTO_MODE 0x0200 +#define DA9063_FLG_FORCE_IN3_MANUAL_MODE 0x0400 +#define DA9063_FLG_FORCE_IN3_AUTO_MODE 0x0800 + +/* Disable register caching. */ +#define DA9063_FLG_NO_CACHE 0x0008 + +struct da9063; + +/* DA9063 platform data */ +struct da9063_pdata { + int (*init)(struct da9063 *da9063); + int irq_base; + unsigned flags; + struct da9063_regulators_pdata *regulators_pdata; + struct led_platform_data *leds_pdata; +}; + +#endif /* __MFD_DA9063_PDATA_H__ */ -- cgit v1.2.3 From a0e08b8606f3c0722b235a09b537264e5b14f748 Mon Sep 17 00:00:00 2001 From: Krystian Garbaciak Date: Mon, 29 Jul 2013 19:00:44 +0200 Subject: mfd: da9063: Add IRQ support This patch adds a regmap irqchip for DA9063 IRQs. It depends on git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap.git tags/regmap-irq-ack-mask Signed-off-by: Krystian Garbaciak Signed-off-by: Philipp Zabel Reviewed-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/Makefile | 2 +- drivers/mfd/da9063-core.c | 56 ++++++++++++ drivers/mfd/da9063-irq.c | 193 ++++++++++++++++++++++++++++++++++++++++ include/linux/mfd/da9063/core.h | 38 ++++++++ 4 files changed, 288 insertions(+), 1 deletion(-) create mode 100644 drivers/mfd/da9063-irq.c (limited to 'drivers') diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 0bb84d59f3fa..15b905c6553c 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -107,7 +107,7 @@ obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o da9055-objs := da9055-core.o da9055-i2c.o obj-$(CONFIG_MFD_DA9055) += da9055.o -da9063-objs := da9063-core.o da9063-i2c.o +da9063-objs := da9063-core.o da9063-irq.o da9063-i2c.o obj-$(CONFIG_MFD_DA9063) += da9063.o obj-$(CONFIG_MFD_MAX77686) += max77686.o max77686-irq.o diff --git a/drivers/mfd/da9063-core.c b/drivers/mfd/da9063-core.c index 29f3ed1f076c..c9cf8d988406 100644 --- a/drivers/mfd/da9063-core.c +++ b/drivers/mfd/da9063-core.c @@ -34,9 +34,52 @@ #include +static struct resource da9063_regulators_resources[] = { + { + .name = "LDO_LIM", + .start = DA9063_IRQ_LDO_LIM, + .end = DA9063_IRQ_LDO_LIM, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource da9063_rtc_resources[] = { + { + .name = "ALARM", + .start = DA9063_IRQ_ALARM, + .end = DA9063_IRQ_ALARM, + .flags = IORESOURCE_IRQ, + }, + { + .name = "TICK", + .start = DA9063_IRQ_TICK, + .end = DA9063_IRQ_TICK, + .flags = IORESOURCE_IRQ, + } +}; + +static struct resource da9063_onkey_resources[] = { + { + .start = DA9063_IRQ_ONKEY, + .end = DA9063_IRQ_ONKEY, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource da9063_hwmon_resources[] = { + { + .start = DA9063_IRQ_ADC_RDY, + .end = DA9063_IRQ_ADC_RDY, + .flags = IORESOURCE_IRQ, + }, +}; + + static struct mfd_cell da9063_devs[] = { { .name = DA9063_DRVNAME_REGULATORS, + .num_resources = ARRAY_SIZE(da9063_regulators_resources), + .resources = da9063_regulators_resources, }, { .name = DA9063_DRVNAME_LEDS, @@ -46,12 +89,18 @@ static struct mfd_cell da9063_devs[] = { }, { .name = DA9063_DRVNAME_HWMON, + .num_resources = ARRAY_SIZE(da9063_hwmon_resources), + .resources = da9063_hwmon_resources, }, { .name = DA9063_DRVNAME_ONKEY, + .num_resources = ARRAY_SIZE(da9063_onkey_resources), + .resources = da9063_onkey_resources, }, { .name = DA9063_DRVNAME_RTC, + .num_resources = ARRAY_SIZE(da9063_rtc_resources), + .resources = da9063_rtc_resources, }, { .name = DA9063_DRVNAME_VIBRATION, @@ -110,6 +159,12 @@ int da9063_device_init(struct da9063 *da9063, unsigned int irq) "Device detected (model-ID: 0x%02X rev-ID: 0x%02X)\n", model, revision); + ret = da9063_irq_init(da9063); + if (ret) { + dev_err(da9063->dev, "Cannot initialize interrupts.\n"); + return ret; + } + ret = mfd_add_devices(da9063->dev, -1, da9063_devs, ARRAY_SIZE(da9063_devs), NULL, da9063->irq_base, NULL); @@ -122,6 +177,7 @@ int da9063_device_init(struct da9063 *da9063, unsigned int irq) void da9063_device_exit(struct da9063 *da9063) { mfd_remove_devices(da9063->dev); + da9063_irq_exit(da9063); } MODULE_DESCRIPTION("PMIC driver for Dialog DA9063"); diff --git a/drivers/mfd/da9063-irq.c b/drivers/mfd/da9063-irq.c new file mode 100644 index 000000000000..822922602ce9 --- /dev/null +++ b/drivers/mfd/da9063-irq.c @@ -0,0 +1,193 @@ +/* da9063-irq.c: Interrupts support for Dialog DA9063 + * + * Copyright 2012 Dialog Semiconductor Ltd. + * Copyright 2013 Philipp Zabel, Pengutronix + * + * Author: Michal Hajduk + * + * 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 + +#define DA9063_REG_EVENT_A_OFFSET 0 +#define DA9063_REG_EVENT_B_OFFSET 1 +#define DA9063_REG_EVENT_C_OFFSET 2 +#define DA9063_REG_EVENT_D_OFFSET 3 +#define EVENTS_BUF_LEN 4 + +static const u8 mask_events_buf[] = { [0 ... (EVENTS_BUF_LEN - 1)] = ~0 }; + +struct da9063_irq_data { + u16 reg; + u8 mask; +}; + +static struct regmap_irq da9063_irqs[] = { + /* DA9063 event A register */ + [DA9063_IRQ_ONKEY] = { + .reg_offset = DA9063_REG_EVENT_A_OFFSET, + .mask = DA9063_M_ONKEY, + }, + [DA9063_IRQ_ALARM] = { + .reg_offset = DA9063_REG_EVENT_A_OFFSET, + .mask = DA9063_M_ALARM, + }, + [DA9063_IRQ_TICK] = { + .reg_offset = DA9063_REG_EVENT_A_OFFSET, + .mask = DA9063_M_TICK, + }, + [DA9063_IRQ_ADC_RDY] = { + .reg_offset = DA9063_REG_EVENT_A_OFFSET, + .mask = DA9063_M_ADC_RDY, + }, + [DA9063_IRQ_SEQ_RDY] = { + .reg_offset = DA9063_REG_EVENT_A_OFFSET, + .mask = DA9063_M_SEQ_RDY, + }, + /* DA9063 event B register */ + [DA9063_IRQ_WAKE] = { + .reg_offset = DA9063_REG_EVENT_B_OFFSET, + .mask = DA9063_M_WAKE, + }, + [DA9063_IRQ_TEMP] = { + .reg_offset = DA9063_REG_EVENT_B_OFFSET, + .mask = DA9063_M_TEMP, + }, + [DA9063_IRQ_COMP_1V2] = { + .reg_offset = DA9063_REG_EVENT_B_OFFSET, + .mask = DA9063_M_COMP_1V2, + }, + [DA9063_IRQ_LDO_LIM] = { + .reg_offset = DA9063_REG_EVENT_B_OFFSET, + .mask = DA9063_M_LDO_LIM, + }, + [DA9063_IRQ_REG_UVOV] = { + .reg_offset = DA9063_REG_EVENT_B_OFFSET, + .mask = DA9063_M_UVOV, + }, + [DA9063_IRQ_VDD_MON] = { + .reg_offset = DA9063_REG_EVENT_B_OFFSET, + .mask = DA9063_M_VDD_MON, + }, + [DA9063_IRQ_WARN] = { + .reg_offset = DA9063_REG_EVENT_B_OFFSET, + .mask = DA9063_M_VDD_WARN, + }, + /* DA9063 event C register */ + [DA9063_IRQ_GPI0] = { + .reg_offset = DA9063_REG_EVENT_C_OFFSET, + .mask = DA9063_M_GPI0, + }, + [DA9063_IRQ_GPI1] = { + .reg_offset = DA9063_REG_EVENT_C_OFFSET, + .mask = DA9063_M_GPI1, + }, + [DA9063_IRQ_GPI2] = { + .reg_offset = DA9063_REG_EVENT_C_OFFSET, + .mask = DA9063_M_GPI2, + }, + [DA9063_IRQ_GPI3] = { + .reg_offset = DA9063_REG_EVENT_C_OFFSET, + .mask = DA9063_M_GPI3, + }, + [DA9063_IRQ_GPI4] = { + .reg_offset = DA9063_REG_EVENT_C_OFFSET, + .mask = DA9063_M_GPI4, + }, + [DA9063_IRQ_GPI5] = { + .reg_offset = DA9063_REG_EVENT_C_OFFSET, + .mask = DA9063_M_GPI5, + }, + [DA9063_IRQ_GPI6] = { + .reg_offset = DA9063_REG_EVENT_C_OFFSET, + .mask = DA9063_M_GPI6, + }, + [DA9063_IRQ_GPI7] = { + .reg_offset = DA9063_REG_EVENT_C_OFFSET, + .mask = DA9063_M_GPI7, + }, + /* DA9063 event D register */ + [DA9063_IRQ_GPI8] = { + .reg_offset = DA9063_REG_EVENT_D_OFFSET, + .mask = DA9063_M_GPI8, + }, + [DA9063_IRQ_GPI9] = { + .reg_offset = DA9063_REG_EVENT_D_OFFSET, + .mask = DA9063_M_GPI9, + }, + [DA9063_IRQ_GPI10] = { + .reg_offset = DA9063_REG_EVENT_D_OFFSET, + .mask = DA9063_M_GPI10, + }, + [DA9063_IRQ_GPI11] = { + .reg_offset = DA9063_REG_EVENT_D_OFFSET, + .mask = DA9063_M_GPI11, + }, + [DA9063_IRQ_GPI12] = { + .reg_offset = DA9063_REG_EVENT_D_OFFSET, + .mask = DA9063_M_GPI12, + }, + [DA9063_IRQ_GPI13] = { + .reg_offset = DA9063_REG_EVENT_D_OFFSET, + .mask = DA9063_M_GPI13, + }, + [DA9063_IRQ_GPI14] = { + .reg_offset = DA9063_REG_EVENT_D_OFFSET, + .mask = DA9063_M_GPI14, + }, + [DA9063_IRQ_GPI15] = { + .reg_offset = DA9063_REG_EVENT_D_OFFSET, + .mask = DA9063_M_GPI15, + }, +}; + +static struct regmap_irq_chip da9063_irq_chip = { + .name = "da9063-irq", + .irqs = da9063_irqs, + .num_irqs = DA9063_NUM_IRQ, + + .num_regs = 4, + .status_base = DA9063_REG_EVENT_A, + .mask_base = DA9063_REG_IRQ_MASK_A, + .ack_base = DA9063_REG_EVENT_A, + .init_ack_masked = true, +}; + +int da9063_irq_init(struct da9063 *da9063) +{ + int ret; + + if (!da9063->chip_irq) { + dev_err(da9063->dev, "No IRQ configured\n"); + return -EINVAL; + } + + ret = regmap_add_irq_chip(da9063->regmap, da9063->chip_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED, + da9063->irq_base, &da9063_irq_chip, + &da9063->regmap_irq); + if (ret) { + dev_err(da9063->dev, "Failed to reguest IRQ %d: %d\n", + da9063->chip_irq, ret); + return ret; + } + + return 0; +} + +void da9063_irq_exit(struct da9063 *da9063) +{ + regmap_del_irq_chip(da9063->chip_irq, da9063->regmap_irq); +} diff --git a/include/linux/mfd/da9063/core.h b/include/linux/mfd/da9063/core.h index ec2fd2aa24ae..2d2a0af675fd 100644 --- a/include/linux/mfd/da9063/core.h +++ b/include/linux/mfd/da9063/core.h @@ -33,6 +33,41 @@ enum da9063_models { PMIC_DA9063 = 0x61, }; +/* Interrupts */ +enum da9063_irqs { + DA9063_IRQ_ONKEY = 0, + DA9063_IRQ_ALARM, + DA9063_IRQ_TICK, + DA9063_IRQ_ADC_RDY, + DA9063_IRQ_SEQ_RDY, + DA9063_IRQ_WAKE, + DA9063_IRQ_TEMP, + DA9063_IRQ_COMP_1V2, + DA9063_IRQ_LDO_LIM, + DA9063_IRQ_REG_UVOV, + DA9063_IRQ_VDD_MON, + DA9063_IRQ_WARN, + DA9063_IRQ_GPI0, + DA9063_IRQ_GPI1, + DA9063_IRQ_GPI2, + DA9063_IRQ_GPI3, + DA9063_IRQ_GPI4, + DA9063_IRQ_GPI5, + DA9063_IRQ_GPI6, + DA9063_IRQ_GPI7, + DA9063_IRQ_GPI8, + DA9063_IRQ_GPI9, + DA9063_IRQ_GPI10, + DA9063_IRQ_GPI11, + DA9063_IRQ_GPI12, + DA9063_IRQ_GPI13, + DA9063_IRQ_GPI14, + DA9063_IRQ_GPI15, +}; + +#define DA9063_IRQ_BASE_OFFSET 0 +#define DA9063_NUM_IRQ (DA9063_IRQ_GPI15 + 1 - DA9063_IRQ_BASE_OFFSET) + struct da9063 { /* Device */ struct device *dev; @@ -46,10 +81,13 @@ struct da9063 { /* Interrupts */ int chip_irq; unsigned int irq_base; + struct regmap_irq_chip_data *regmap_irq; }; int da9063_device_init(struct da9063 *da9063, unsigned int irq); +int da9063_irq_init(struct da9063 *da9063); void da9063_device_exit(struct da9063 *da9063); +void da9063_irq_exit(struct da9063 *da9063); #endif /* __MFD_DA9063_CORE_H__ */ -- cgit v1.2.3 From cc01b4639c94b1732995a9909a8973bfed67db2b Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Tue, 13 Aug 2013 13:23:11 +0530 Subject: mfd: palmas: Add support for external control configuration Some of Palmas resources like clock, SMPSs, LDOs etc can be controlled by external pins ENABLE1, ENABLE2 or NSLEEP. Add support to configure these resources to externally controlled. Signed-off-by: Laxman Dewangan Acked-by: Lee Jones Signed-off-by: Samuel Ortiz --- drivers/mfd/palmas.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/mfd/palmas.h | 49 +++++++++++++++++++++++ 2 files changed, 146 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index e4d1c706df8b..e71fa289eb01 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c @@ -25,6 +25,52 @@ #include #include +#define PALMAS_EXT_REQ (PALMAS_EXT_CONTROL_ENABLE1 | \ + PALMAS_EXT_CONTROL_ENABLE2 | \ + PALMAS_EXT_CONTROL_NSLEEP) + +struct palmas_sleep_requestor_info { + int id; + int reg_offset; + int bit_pos; +}; + +#define EXTERNAL_REQUESTOR(_id, _offset, _pos) \ + [PALMAS_EXTERNAL_REQSTR_ID_##_id] = { \ + .id = PALMAS_EXTERNAL_REQSTR_ID_##_id, \ + .reg_offset = _offset, \ + .bit_pos = _pos, \ + } + +static struct palmas_sleep_requestor_info sleep_req_info[] = { + EXTERNAL_REQUESTOR(REGEN1, 0, 0), + EXTERNAL_REQUESTOR(REGEN2, 0, 1), + EXTERNAL_REQUESTOR(SYSEN1, 0, 2), + EXTERNAL_REQUESTOR(SYSEN2, 0, 3), + EXTERNAL_REQUESTOR(CLK32KG, 0, 4), + EXTERNAL_REQUESTOR(CLK32KGAUDIO, 0, 5), + EXTERNAL_REQUESTOR(REGEN3, 0, 6), + EXTERNAL_REQUESTOR(SMPS12, 1, 0), + EXTERNAL_REQUESTOR(SMPS3, 1, 1), + EXTERNAL_REQUESTOR(SMPS45, 1, 2), + EXTERNAL_REQUESTOR(SMPS6, 1, 3), + EXTERNAL_REQUESTOR(SMPS7, 1, 4), + EXTERNAL_REQUESTOR(SMPS8, 1, 5), + EXTERNAL_REQUESTOR(SMPS9, 1, 6), + EXTERNAL_REQUESTOR(SMPS10, 1, 7), + EXTERNAL_REQUESTOR(LDO1, 2, 0), + EXTERNAL_REQUESTOR(LDO2, 2, 1), + EXTERNAL_REQUESTOR(LDO3, 2, 2), + EXTERNAL_REQUESTOR(LDO4, 2, 3), + EXTERNAL_REQUESTOR(LDO5, 2, 4), + EXTERNAL_REQUESTOR(LDO6, 2, 5), + EXTERNAL_REQUESTOR(LDO7, 2, 6), + EXTERNAL_REQUESTOR(LDO8, 2, 7), + EXTERNAL_REQUESTOR(LDO9, 3, 0), + EXTERNAL_REQUESTOR(LDOLN, 3, 1), + EXTERNAL_REQUESTOR(LDOUSB, 3, 2), +}; + static const struct regmap_config palmas_regmap_config[PALMAS_NUM_CLIENTS] = { { .reg_bits = 8, @@ -186,6 +232,57 @@ static struct regmap_irq_chip palmas_irq_chip = { PALMAS_INT1_MASK), }; +int palmas_ext_control_req_config(struct palmas *palmas, + enum palmas_external_requestor_id id, int ext_ctrl, bool enable) +{ + int preq_mask_bit = 0; + int reg_add = 0; + int bit_pos; + int ret; + + if (!(ext_ctrl & PALMAS_EXT_REQ)) + return 0; + + if (id >= PALMAS_EXTERNAL_REQSTR_ID_MAX) + return 0; + + if (ext_ctrl & PALMAS_EXT_CONTROL_NSLEEP) { + reg_add = PALMAS_NSLEEP_RES_ASSIGN; + preq_mask_bit = 0; + } else if (ext_ctrl & PALMAS_EXT_CONTROL_ENABLE1) { + reg_add = PALMAS_ENABLE1_RES_ASSIGN; + preq_mask_bit = 1; + } else if (ext_ctrl & PALMAS_EXT_CONTROL_ENABLE2) { + reg_add = PALMAS_ENABLE2_RES_ASSIGN; + preq_mask_bit = 2; + } + + bit_pos = sleep_req_info[id].bit_pos; + reg_add += sleep_req_info[id].reg_offset; + if (enable) + ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE, + reg_add, BIT(bit_pos), BIT(bit_pos)); + else + ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE, + reg_add, BIT(bit_pos), 0); + if (ret < 0) { + dev_err(palmas->dev, "Resource reg 0x%02x update failed %d\n", + reg_add, ret); + return ret; + } + + /* Unmask the PREQ */ + ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE, + PALMAS_POWER_CTRL, BIT(preq_mask_bit), 0); + if (ret < 0) { + dev_err(palmas->dev, "POWER_CTRL register update failed %d\n", + ret); + return ret; + } + return ret; +} +EXPORT_SYMBOL_GPL(palmas_ext_control_req_config); + static int palmas_set_pdata_irq_flag(struct i2c_client *i2c, struct palmas_platform_data *pdata) { diff --git a/include/linux/mfd/palmas.h b/include/linux/mfd/palmas.h index 1a8dd7afe084..d2fca1c6f7df 100644 --- a/include/linux/mfd/palmas.h +++ b/include/linux/mfd/palmas.h @@ -183,6 +183,50 @@ enum palmas_regulators { PALMAS_NUM_REGS, }; +/* External controll signal name */ +enum { + PALMAS_EXT_CONTROL_ENABLE1 = 0x1, + PALMAS_EXT_CONTROL_ENABLE2 = 0x2, + PALMAS_EXT_CONTROL_NSLEEP = 0x4, +}; + +/* + * Palmas device resources can be controlled externally for + * enabling/disabling it rather than register write through i2c. + * Add the external controlled requestor ID for different resources. + */ +enum palmas_external_requestor_id { + PALMAS_EXTERNAL_REQSTR_ID_REGEN1, + PALMAS_EXTERNAL_REQSTR_ID_REGEN2, + PALMAS_EXTERNAL_REQSTR_ID_SYSEN1, + PALMAS_EXTERNAL_REQSTR_ID_SYSEN2, + PALMAS_EXTERNAL_REQSTR_ID_CLK32KG, + PALMAS_EXTERNAL_REQSTR_ID_CLK32KGAUDIO, + PALMAS_EXTERNAL_REQSTR_ID_REGEN3, + PALMAS_EXTERNAL_REQSTR_ID_SMPS12, + PALMAS_EXTERNAL_REQSTR_ID_SMPS3, + PALMAS_EXTERNAL_REQSTR_ID_SMPS45, + PALMAS_EXTERNAL_REQSTR_ID_SMPS6, + PALMAS_EXTERNAL_REQSTR_ID_SMPS7, + PALMAS_EXTERNAL_REQSTR_ID_SMPS8, + PALMAS_EXTERNAL_REQSTR_ID_SMPS9, + PALMAS_EXTERNAL_REQSTR_ID_SMPS10, + PALMAS_EXTERNAL_REQSTR_ID_LDO1, + PALMAS_EXTERNAL_REQSTR_ID_LDO2, + PALMAS_EXTERNAL_REQSTR_ID_LDO3, + PALMAS_EXTERNAL_REQSTR_ID_LDO4, + PALMAS_EXTERNAL_REQSTR_ID_LDO5, + PALMAS_EXTERNAL_REQSTR_ID_LDO6, + PALMAS_EXTERNAL_REQSTR_ID_LDO7, + PALMAS_EXTERNAL_REQSTR_ID_LDO8, + PALMAS_EXTERNAL_REQSTR_ID_LDO9, + PALMAS_EXTERNAL_REQSTR_ID_LDOLN, + PALMAS_EXTERNAL_REQSTR_ID_LDOUSB, + + /* Last entry */ + PALMAS_EXTERNAL_REQSTR_ID_MAX, +}; + struct palmas_pmic_platform_data { /* An array of pointers to regulator init data indexed by regulator * ID @@ -2866,4 +2910,9 @@ static inline int palmas_irq_get_virq(struct palmas *palmas, int irq) return regmap_irq_get_virq(palmas->irq_data, irq); } + +int palmas_ext_control_req_config(struct palmas *palmas, + enum palmas_external_requestor_id ext_control_req_id, + int ext_ctrl, bool enable); + #endif /* __LINUX_MFD_PALMAS_H */ -- cgit v1.2.3 From ef310f4bbf3e0a99129e8fa6acc1d45623a4ad68 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 20 Aug 2013 16:01:26 +0900 Subject: mfd: pm8921: Include missing linux/module.h Include in order to fix the following errors. drivers/mfd/pm8921-core.c:209:16: error: expected declaration specifiers or '...' before string constant drivers/mfd/pm8921-core.c:210:20: error: expected declaration specifiers or '...' before string constant drivers/mfd/pm8921-core.c:211:16: error: expected declaration specifiers or '...' before string constant drivers/mfd/pm8921-core.c:212:14: error: expected declaration specifiers or '...' before string constant Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/pm8921-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c index 9be6840e88ee..bd4b37ce254e 100644 --- a/drivers/mfd/pm8921-core.c +++ b/drivers/mfd/pm8921-core.c @@ -14,6 +14,7 @@ #define pr_fmt(fmt) "%s: " fmt, __func__ #include +#include #include #include #include -- cgit v1.2.3 From 5cddd5de8cc8b3bcf11ecd530f7e0cbcb283d968 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 20 Aug 2013 16:02:05 +0900 Subject: mfd: pm8921: Remove unnecessary platform_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure, since commit 0998d0631001288a5974afc0b2a5f568bcdecb4d (device-core: Ensure drvdata = NULL when no driver is bound). Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/pm8921-core.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c index bd4b37ce254e..9a7c991a3826 100644 --- a/drivers/mfd/pm8921-core.c +++ b/drivers/mfd/pm8921-core.c @@ -160,7 +160,6 @@ static int pm8921_probe(struct platform_device *pdev) err: mfd_remove_devices(pmic->dev); - platform_set_drvdata(pdev, NULL); err_read_rev: kfree(pmic); return rc; @@ -180,7 +179,6 @@ static int pm8921_remove(struct platform_device *pdev) pm8xxx_irq_exit(pmic->irq_chip); pmic->irq_chip = NULL; } - platform_set_drvdata(pdev, NULL); kfree(pmic); return 0; -- cgit v1.2.3 From b2cdcfacfe4bafaaeeba54db5940eef6452d1161 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 20 Aug 2013 16:02:26 +0900 Subject: mfd: pm8921: Use devm_*() functions Use devm_*() functions to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/pm8921-core.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c index 9a7c991a3826..a6841f77aa5e 100644 --- a/drivers/mfd/pm8921-core.c +++ b/drivers/mfd/pm8921-core.c @@ -118,7 +118,7 @@ static int pm8921_probe(struct platform_device *pdev) return -EINVAL; } - pmic = kzalloc(sizeof(struct pm8921), GFP_KERNEL); + pmic = devm_kzalloc(&pdev->dev, sizeof(struct pm8921), GFP_KERNEL); if (!pmic) { pr_err("Cannot alloc pm8921 struct\n"); return -ENOMEM; @@ -128,7 +128,7 @@ static int pm8921_probe(struct platform_device *pdev) rc = ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val)); if (rc) { pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc); - goto err_read_rev; + return rc; } pr_info("PMIC revision 1: %02X\n", val); rev = val; @@ -138,7 +138,7 @@ static int pm8921_probe(struct platform_device *pdev) if (rc) { pr_err("Failed to read hw rev 2 reg %d:rc=%d\n", REG_HWREV_2, rc); - goto err_read_rev; + return rc; } pr_info("PMIC revision 2: %02X\n", val); rev |= val << BITS_PER_BYTE; @@ -160,8 +160,6 @@ static int pm8921_probe(struct platform_device *pdev) err: mfd_remove_devices(pmic->dev); -err_read_rev: - kfree(pmic); return rc; } @@ -179,7 +177,6 @@ static int pm8921_remove(struct platform_device *pdev) pm8xxx_irq_exit(pmic->irq_chip); pmic->irq_chip = NULL; } - kfree(pmic); return 0; } -- cgit v1.2.3 From 6922ffcfad1a5ff8cd0e44bbcee3686dd6caf13c Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 20 Aug 2013 16:03:20 +0900 Subject: mfd: max8997: Use devm_*() functions Use devm_*() functions to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/max8997.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c index 15230476dc73..cee098c0dae3 100644 --- a/drivers/mfd/max8997.c +++ b/drivers/mfd/max8997.c @@ -191,7 +191,8 @@ static int max8997_i2c_probe(struct i2c_client *i2c, struct max8997_platform_data *pdata = dev_get_platdata(&i2c->dev); int ret = 0; - max8997 = kzalloc(sizeof(struct max8997_dev), GFP_KERNEL); + max8997 = devm_kzalloc(&i2c->dev, sizeof(struct max8997_dev), + GFP_KERNEL); if (max8997 == NULL) return -ENOMEM; @@ -203,14 +204,12 @@ static int max8997_i2c_probe(struct i2c_client *i2c, if (max8997->dev->of_node) { pdata = max8997_i2c_parse_dt_pdata(max8997->dev); - if (IS_ERR(pdata)) { - ret = PTR_ERR(pdata); - goto err; - } + if (IS_ERR(pdata)) + return PTR_ERR(pdata); } if (!pdata) - goto err; + return ret; max8997->pdata = pdata; max8997->ono = pdata->ono; @@ -250,8 +249,6 @@ err_mfd: i2c_unregister_device(max8997->muic); i2c_unregister_device(max8997->haptic); i2c_unregister_device(max8997->rtc); -err: - kfree(max8997); return ret; } @@ -263,7 +260,6 @@ static int max8997_i2c_remove(struct i2c_client *i2c) i2c_unregister_device(max8997->muic); i2c_unregister_device(max8997->haptic); i2c_unregister_device(max8997->rtc); - kfree(max8997); return 0; } -- cgit v1.2.3 From 0010dd3883b8a5e99c7d4093b97e9e34300a2f03 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 20 Aug 2013 16:04:42 +0900 Subject: mfd: max8998: Use devm_*() functions Use devm_*() functions to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/max8998.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index 45bffb8c7236..fe6332dcabee 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c @@ -188,7 +188,8 @@ static int max8998_i2c_probe(struct i2c_client *i2c, struct max8998_dev *max8998; int ret = 0; - max8998 = kzalloc(sizeof(struct max8998_dev), GFP_KERNEL); + max8998 = devm_kzalloc(&i2c->dev, sizeof(struct max8998_dev), + GFP_KERNEL); if (max8998 == NULL) return -ENOMEM; @@ -246,7 +247,6 @@ err: mfd_remove_devices(max8998->dev); max8998_irq_exit(max8998); i2c_unregister_device(max8998->rtc); - kfree(max8998); return ret; } @@ -257,7 +257,6 @@ static int max8998_i2c_remove(struct i2c_client *i2c) mfd_remove_devices(max8998->dev); max8998_irq_exit(max8998); i2c_unregister_device(max8998->rtc); - kfree(max8998); return 0; } -- cgit v1.2.3 From 7a4043112778c8ba7169b3006c8b7789213c878a Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 20 Aug 2013 16:05:11 +0900 Subject: mfd: menelaus: Use devm_*() functions Use devm_*() functions to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/menelaus.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c index f24df8c9b02e..ad25bfa3fb02 100644 --- a/drivers/mfd/menelaus.c +++ b/drivers/mfd/menelaus.c @@ -1197,7 +1197,7 @@ static int menelaus_probe(struct i2c_client *client, return -ENODEV; } - menelaus = kzalloc(sizeof *menelaus, GFP_KERNEL); + menelaus = devm_kzalloc(&client->dev, sizeof(*menelaus), GFP_KERNEL); if (!menelaus) return -ENOMEM; @@ -1210,8 +1210,7 @@ static int menelaus_probe(struct i2c_client *client, rev = menelaus_read_reg(MENELAUS_REV); if (rev < 0) { pr_err(DRIVER_NAME ": device not found"); - err = -ENODEV; - goto fail1; + return -ENODEV; } /* Ack and disable all Menelaus interrupts */ @@ -1231,7 +1230,7 @@ static int menelaus_probe(struct i2c_client *client, if (err) { dev_dbg(&client->dev, "can't get IRQ %d, err %d\n", client->irq, err); - goto fail1; + return err; } } @@ -1242,7 +1241,7 @@ static int menelaus_probe(struct i2c_client *client, val = menelaus_read_reg(MENELAUS_VCORE_CTRL1); if (val < 0) - goto fail2; + goto fail; if (val & (1 << 7)) menelaus->vcore_hw_mode = 1; else @@ -1251,17 +1250,15 @@ static int menelaus_probe(struct i2c_client *client, if (menelaus_pdata != NULL && menelaus_pdata->late_init != NULL) { err = menelaus_pdata->late_init(&client->dev); if (err < 0) - goto fail2; + goto fail; } menelaus_rtc_init(menelaus); return 0; -fail2: +fail: free_irq(client->irq, menelaus); flush_work(&menelaus->work); -fail1: - kfree(menelaus); return err; } @@ -1271,7 +1268,6 @@ static int __exit menelaus_remove(struct i2c_client *client) free_irq(client->irq, menelaus); flush_work(&menelaus->work); - kfree(menelaus); the_menelaus = NULL; return 0; } -- cgit v1.2.3 From eac1dcbd3e211998fb8342902b3acee149a9271d Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 20 Aug 2013 16:05:54 +0900 Subject: mfd: tps65010: Use devm_*() functions Use devm_*() functions to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/tps65010.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c index 8114567e0695..743fb524fc8a 100644 --- a/drivers/mfd/tps65010.c +++ b/drivers/mfd/tps65010.c @@ -530,7 +530,6 @@ static int __exit tps65010_remove(struct i2c_client *client) free_irq(client->irq, tps); cancel_delayed_work_sync(&tps->work); debugfs_remove(tps->file); - kfree(tps); the_tps = NULL; return 0; } @@ -550,7 +549,7 @@ static int tps65010_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EINVAL; - tps = kzalloc(sizeof *tps, GFP_KERNEL); + tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); if (!tps) return -ENOMEM; @@ -568,7 +567,7 @@ static int tps65010_probe(struct i2c_client *client, if (status < 0) { dev_dbg(&client->dev, "can't get IRQ %d, err %d\n", client->irq, status); - goto fail1; + return status; } /* annoying race here, ideally we'd have an option * to claim the irq now and enable it later. @@ -668,9 +667,6 @@ static int tps65010_probe(struct i2c_client *client, } return 0; -fail1: - kfree(tps); - return status; } static const struct i2c_device_id tps65010_id[] = { -- cgit v1.2.3 From bba078273e259c7eff729ac00a1476987ad5413a Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 20 Aug 2013 16:06:17 +0900 Subject: mfd: wl1273: Use devm_*() functions Use devm_*() functions to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/wl1273-core.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c index 1288e9943f01..f7c52d901040 100644 --- a/drivers/mfd/wl1273-core.c +++ b/drivers/mfd/wl1273-core.c @@ -172,12 +172,9 @@ static int wl1273_fm_set_volume(struct wl1273_core *core, unsigned int volume) static int wl1273_core_remove(struct i2c_client *client) { - struct wl1273_core *core = i2c_get_clientdata(client); - dev_dbg(&client->dev, "%s\n", __func__); mfd_remove_devices(&client->dev); - kfree(core); return 0; } @@ -203,7 +200,7 @@ static int wl1273_core_probe(struct i2c_client *client, return -EINVAL; } - core = kzalloc(sizeof(*core), GFP_KERNEL); + core = devm_kzalloc(&client->dev, sizeof(*core), GFP_KERNEL); if (!core) return -ENOMEM; @@ -249,7 +246,6 @@ static int wl1273_core_probe(struct i2c_client *client, err: pdata->free_resources(); - kfree(core); dev_dbg(&client->dev, "%s\n", __func__); -- cgit v1.2.3 From 87343e534117c2932adfb394351dc83d7c378af6 Mon Sep 17 00:00:00 2001 From: Naga Venkata Srikanth V Date: Thu, 25 Jul 2013 16:15:47 +0300 Subject: mfd: twl6030-irq: Migrate to IRQ threaded handler 1) Removed request_irq() and replaced it with request_threaded_irq(). 2) Removed generic_handle_irq() and replaced it with handle_nested_irq(). Handling of these interrupts is nested, as we are handling an interrupt (for e.g rtc, mmc1) when we are still servicing TWL irq. 3) Removed I2C read-retry logic for the case when twl_i2c_read() is failed inside IRQ handler - there is no sense to do that, so just report an error and return. 4) Each nested IRQ is configured with corresponding parent_irq, which need to be retriggered in case if nested IRQ is marked as IRQS_PENDING. Signed-off-by: Naga Venkata Srikanth V Signed-off-by: Oleg_Kosheliev Signed-off-by: Grygorii Strashko Acked-by: Graeme Gregory Signed-off-by: Samuel Ortiz --- drivers/mfd/twl6030-irq.c | 150 ++++++++++++++++------------------------------ 1 file changed, 50 insertions(+), 100 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 277a8dba42d5..1606cedbbff4 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -90,7 +90,6 @@ static unsigned twl6030_irq_base; static int twl_irq; static bool twl_irq_wake_enabled; -static struct completion irq_event; static atomic_t twl6030_wakeirqs = ATOMIC_INIT(0); static int twl6030_irq_pm_notifier(struct notifier_block *notifier, @@ -131,95 +130,57 @@ static struct notifier_block twl6030_irq_pm_notifier_block = { }; /* - * This thread processes interrupts reported by the Primary Interrupt Handler. - */ -static int twl6030_irq_thread(void *data) +* Threaded irq handler for the twl6030 interrupt. +* We query the interrupt controller in the twl6030 to determine +* which module is generating the interrupt request and call +* handle_nested_irq for that module. +*/ +static irqreturn_t twl6030_irq_thread(int irq, void *data) { - long irq = (long)data; - static unsigned i2c_errors; - static const unsigned max_i2c_errors = 100; - int ret; - - while (!kthread_should_stop()) { - int i; - union { + int i, ret; + union { u8 bytes[4]; u32 int_sts; - } sts; - - /* Wait for IRQ, then read PIH irq status (also blocking) */ - wait_for_completion_interruptible(&irq_event); - - /* read INT_STS_A, B and C in one shot using a burst read */ - ret = twl_i2c_read(TWL_MODULE_PIH, sts.bytes, - REG_INT_STS_A, 3); - if (ret) { - pr_warning("twl6030: I2C error %d reading PIH ISR\n", - ret); - if (++i2c_errors >= max_i2c_errors) { - printk(KERN_ERR "Maximum I2C error count" - " exceeded. Terminating %s.\n", - __func__); - break; - } - complete(&irq_event); - continue; - } - + } sts; + /* read INT_STS_A, B and C in one shot using a burst read */ + ret = twl_i2c_read(TWL_MODULE_PIH, sts.bytes, REG_INT_STS_A, 3); + if (ret) { + pr_warn("twl6030_irq: I2C error %d reading PIH ISR\n", ret); + return IRQ_HANDLED; + } - sts.bytes[3] = 0; /* Only 24 bits are valid*/ + sts.bytes[3] = 0; /* Only 24 bits are valid*/ - /* - * Since VBUS status bit is not reliable for VBUS disconnect - * use CHARGER VBUS detection status bit instead. - */ - if (sts.bytes[2] & 0x10) - sts.bytes[2] |= 0x08; + /* + * Since VBUS status bit is not reliable for VBUS disconnect + * use CHARGER VBUS detection status bit instead. + */ + if (sts.bytes[2] & 0x10) + sts.bytes[2] |= 0x08; - for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) { - local_irq_disable(); - if (sts.int_sts & 0x1) { - int module_irq = twl6030_irq_base + + for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) + if (sts.int_sts & 0x1) { + int module_irq = twl6030_irq_base + twl6030_interrupt_mapping[i]; - generic_handle_irq(module_irq); - - } - local_irq_enable(); + handle_nested_irq(module_irq); + pr_debug("twl6030_irq: PIH ISR %u, virq%u\n", + i, module_irq); } - /* - * NOTE: - * Simulation confirms that documentation is wrong w.r.t the - * interrupt status clear operation. A single *byte* write to - * any one of STS_A to STS_C register results in all three - * STS registers being reset. Since it does not matter which - * value is written, all three registers are cleared on a - * single byte write, so we just use 0x0 to clear. - */ - ret = twl_i2c_write_u8(TWL_MODULE_PIH, 0x00, REG_INT_STS_A); - if (ret) - pr_warning("twl6030: I2C error in clearing PIH ISR\n"); - - enable_irq(irq); - } - - return 0; -} + /* + * NOTE: + * Simulation confirms that documentation is wrong w.r.t the + * interrupt status clear operation. A single *byte* write to + * any one of STS_A to STS_C register results in all three + * STS registers being reset. Since it does not matter which + * value is written, all three registers are cleared on a + * single byte write, so we just use 0x0 to clear. + */ + ret = twl_i2c_write_u8(TWL_MODULE_PIH, 0x00, REG_INT_STS_A); + if (ret) + pr_warn("twl6030_irq: I2C error in clearing PIH ISR\n"); -/* - * handle_twl6030_int() is the desc->handle method for the twl6030 interrupt. - * This is a chained interrupt, so there is no desc->action method for it. - * Now we need to query the interrupt controller in the twl6030 to determine - * which module is generating the interrupt request. However, we can't do i2c - * transactions in interrupt context, so we must defer that work to a kernel - * thread. All we do here is acknowledge and mask the interrupt and wakeup - * the kernel thread. - */ -static irqreturn_t handle_twl6030_pih(int irq, void *devid) -{ - disable_irq_nosync(irq); - complete(devid); return IRQ_HANDLED; } @@ -351,7 +312,6 @@ int twl6030_init_irq(struct device *dev, int irq_num) { struct device_node *node = dev->of_node; int nr_irqs, irq_base, irq_end; - struct task_struct *task; static struct irq_chip twl6030_irq_chip; int status = 0; int i; @@ -396,36 +356,26 @@ int twl6030_init_irq(struct device *dev, int irq_num) irq_set_chip_and_handler(i, &twl6030_irq_chip, handle_simple_irq); irq_set_chip_data(i, (void *)irq_num); + irq_set_nested_thread(i, true); + irq_set_parent(i, irq_num); activate_irq(i); } - dev_info(dev, "PIH (irq %d) chaining IRQs %d..%d\n", - irq_num, irq_base, irq_end); + dev_info(dev, "PIH (irq %d) nested IRQs %d..%d\n", + irq_num, irq_base, irq_end); /* install an irq handler to demultiplex the TWL6030 interrupt */ - init_completion(&irq_event); - - status = request_irq(irq_num, handle_twl6030_pih, 0, "TWL6030-PIH", - &irq_event); + status = request_threaded_irq(irq_num, NULL, twl6030_irq_thread, + IRQF_ONESHOT, "TWL6030-PIH", NULL); if (status < 0) { dev_err(dev, "could not claim irq %d: %d\n", irq_num, status); goto fail_irq; } - task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq"); - if (IS_ERR(task)) { - dev_err(dev, "could not create irq %d thread!\n", irq_num); - status = PTR_ERR(task); - goto fail_kthread; - } - twl_irq = irq_num; register_pm_notifier(&twl6030_irq_pm_notifier_block); return irq_base; -fail_kthread: - free_irq(irq_num, &irq_event); - fail_irq: for (i = irq_base; i < irq_end; i++) irq_set_chip_and_handler(i, NULL, NULL); @@ -435,12 +385,12 @@ fail_irq: int twl6030_exit_irq(void) { - unregister_pm_notifier(&twl6030_irq_pm_notifier_block); - if (twl6030_irq_base) { - pr_err("twl6030: can't yet clean up IRQs?\n"); - return -ENOSYS; + if (twl_irq) { + unregister_pm_notifier(&twl6030_irq_pm_notifier_block); + free_irq(twl_irq, NULL); } + return 0; } -- cgit v1.2.3 From a820e5686f5f048494f71a394edb55f1c24603c5 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Thu, 25 Jul 2013 16:15:48 +0300 Subject: mfd: twl6030-irq: Add error check when IRQs are masked initially Add a missed check for errors when TWL IRQs are masked initially on probe and report an error in case of failure. Signed-off-by: Grygorii Strashko Acked-by: Graeme Gregory Signed-off-by: Samuel Ortiz --- drivers/mfd/twl6030-irq.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 1606cedbbff4..f7da2614de80 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -313,7 +313,7 @@ int twl6030_init_irq(struct device *dev, int irq_num) struct device_node *node = dev->of_node; int nr_irqs, irq_base, irq_end; static struct irq_chip twl6030_irq_chip; - int status = 0; + int status; int i; u8 mask[3]; @@ -335,11 +335,16 @@ int twl6030_init_irq(struct device *dev, int irq_num) mask[2] = 0xFF; /* mask all int lines */ - twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3); + status = twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3); /* mask all int sts */ - twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_STS_A, 3); + status |= twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_STS_A, 3); /* clear INT_STS_A,B,C */ - twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_STS_A, 3); + status |= twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_STS_A, 3); + + if (status < 0) { + dev_err(dev, "I2C err writing TWL_MODULE_PIH: %d\n", status); + return status; + } twl6030_irq_base = irq_base; -- cgit v1.2.3 From b32408f64427096d9cc81066875345397bae0269 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Thu, 25 Jul 2013 16:15:49 +0300 Subject: mfd: twl6030-irq: Convert to use linear irq_domain Since the TWL6030 PMIC is used with OMAP4 SoCs only and OMAP4 legacy boot is dropped there are no needs to allocate the range of IRQ descriptors during system boot to support TWL6030 IRQs. Hence, convert it to use linear irq_domain and move IRQ configuration in .map()/.unmap() callbacks of irq_domain. So, IRQ mapping and descriptors allocation will be performed dynamically basing on DT configuration. The error message will be reported in case if unmapped IRQ is received by TWL6030 (virq==0). Signed-off-by: Grygorii Strashko Acked-by: Graeme Gregory Signed-off-by: Samuel Ortiz --- drivers/mfd/twl6030-irq.c | 119 +++++++++++++++++++++++++++------------------- 1 file changed, 69 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index f7da2614de80..1b03ce9e9f15 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -86,11 +86,11 @@ static int twl6030_interrupt_mapping[24] = { }; /*----------------------------------------------------------------------*/ -static unsigned twl6030_irq_base; static int twl_irq; static bool twl_irq_wake_enabled; static atomic_t twl6030_wakeirqs = ATOMIC_INIT(0); +struct irq_domain *irq_domain; static int twl6030_irq_pm_notifier(struct notifier_block *notifier, unsigned long pm_event, void *unused) @@ -138,6 +138,7 @@ static struct notifier_block twl6030_irq_pm_notifier_block = { static irqreturn_t twl6030_irq_thread(int irq, void *data) { int i, ret; + struct irq_domain *irq_domain = (struct irq_domain *)data; union { u8 bytes[4]; u32 int_sts; @@ -161,9 +162,14 @@ static irqreturn_t twl6030_irq_thread(int irq, void *data) for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) if (sts.int_sts & 0x1) { - int module_irq = twl6030_irq_base + - twl6030_interrupt_mapping[i]; - handle_nested_irq(module_irq); + int module_irq = + irq_find_mapping(irq_domain, + twl6030_interrupt_mapping[i]); + if (module_irq) + handle_nested_irq(module_irq); + else + pr_err("twl6030_irq: Unmapped PIH ISR %u detected\n", + i); pr_debug("twl6030_irq: PIH ISR %u, virq%u\n", i, module_irq); } @@ -186,19 +192,6 @@ static irqreturn_t twl6030_irq_thread(int irq, void *data) /*----------------------------------------------------------------------*/ -static inline void activate_irq(int irq) -{ -#ifdef CONFIG_ARM - /* ARM requires an extra step to clear IRQ_NOREQUEST, which it - * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE. - */ - set_irq_flags(irq, IRQF_VALID); -#else - /* same effect on other architectures */ - irq_set_noprobe(irq); -#endif -} - static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on) { if (on) @@ -279,7 +272,7 @@ int twl6030_mmc_card_detect_config(void) return ret; } - return twl6030_irq_base + MMCDETECT_INTR_OFFSET; + return irq_find_mapping(irq_domain, MMCDETECT_INTR_OFFSET); } EXPORT_SYMBOL(twl6030_mmc_card_detect_config); @@ -308,28 +301,54 @@ int twl6030_mmc_card_detect(struct device *dev, int slot) } EXPORT_SYMBOL(twl6030_mmc_card_detect); +static struct irq_chip twl6030_irq_chip; + +static int twl6030_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hwirq) +{ + irq_set_chip_data(virq, &twl6030_irq_chip); + irq_set_chip_and_handler(virq, &twl6030_irq_chip, handle_simple_irq); + irq_set_nested_thread(virq, true); + irq_set_parent(virq, twl_irq); + +#ifdef CONFIG_ARM + /* + * ARM requires an extra step to clear IRQ_NOREQUEST, which it + * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE. + */ + set_irq_flags(virq, IRQF_VALID); +#else + /* same effect on other architectures */ + irq_set_noprobe(virq); +#endif + + return 0; +} + +static void twl6030_irq_unmap(struct irq_domain *d, unsigned int virq) +{ +#ifdef CONFIG_ARM + set_irq_flags(virq, 0); +#endif + irq_set_chip_and_handler(virq, NULL, NULL); + irq_set_chip_data(virq, NULL); +} + +static struct irq_domain_ops twl6030_irq_domain_ops = { + .map = twl6030_irq_map, + .unmap = twl6030_irq_unmap, + .xlate = irq_domain_xlate_onetwocell, +}; + int twl6030_init_irq(struct device *dev, int irq_num) { struct device_node *node = dev->of_node; - int nr_irqs, irq_base, irq_end; - static struct irq_chip twl6030_irq_chip; + int nr_irqs; int status; - int i; u8 mask[3]; nr_irqs = TWL6030_NR_IRQS; - irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0); - if (IS_ERR_VALUE(irq_base)) { - dev_err(dev, "Fail to allocate IRQ descs\n"); - return irq_base; - } - - irq_domain_add_legacy(node, nr_irqs, irq_base, 0, - &irq_domain_simple_ops, NULL); - - irq_end = irq_base + nr_irqs; - mask[0] = 0xFF; mask[1] = 0xFF; mask[2] = 0xFF; @@ -346,8 +365,6 @@ int twl6030_init_irq(struct device *dev, int irq_num) return status; } - twl6030_irq_base = irq_base; - /* * install an irq handler for each of the modules; * clone dummy irq_chip since PIH can't *do* anything @@ -357,21 +374,18 @@ int twl6030_init_irq(struct device *dev, int irq_num) twl6030_irq_chip.irq_set_type = NULL; twl6030_irq_chip.irq_set_wake = twl6030_irq_set_wake; - for (i = irq_base; i < irq_end; i++) { - irq_set_chip_and_handler(i, &twl6030_irq_chip, - handle_simple_irq); - irq_set_chip_data(i, (void *)irq_num); - irq_set_nested_thread(i, true); - irq_set_parent(i, irq_num); - activate_irq(i); + irq_domain = irq_domain_add_linear(node, nr_irqs, + &twl6030_irq_domain_ops, NULL); + if (!irq_domain) { + dev_err(dev, "Can't add irq_domain\n"); + return -ENOMEM; } - dev_info(dev, "PIH (irq %d) nested IRQs %d..%d\n", - irq_num, irq_base, irq_end); + dev_info(dev, "PIH (irq %d) nested IRQs\n", irq_num); /* install an irq handler to demultiplex the TWL6030 interrupt */ status = request_threaded_irq(irq_num, NULL, twl6030_irq_thread, - IRQF_ONESHOT, "TWL6030-PIH", NULL); + IRQF_ONESHOT, "TWL6030-PIH", irq_domain); if (status < 0) { dev_err(dev, "could not claim irq %d: %d\n", irq_num, status); goto fail_irq; @@ -379,23 +393,28 @@ int twl6030_init_irq(struct device *dev, int irq_num) twl_irq = irq_num; register_pm_notifier(&twl6030_irq_pm_notifier_block); - return irq_base; + return 0; fail_irq: - for (i = irq_base; i < irq_end; i++) - irq_set_chip_and_handler(i, NULL, NULL); - + irq_domain_remove(irq_domain); return status; } int twl6030_exit_irq(void) { - if (twl_irq) { unregister_pm_notifier(&twl6030_irq_pm_notifier_block); free_irq(twl_irq, NULL); + /* + * TODO: IRQ domain and allocated nested IRQ descriptors + * should be freed somehow here. Now It can't be done, because + * child devices will not be deleted during removing of + * TWL Core driver and they will still contain allocated + * virt IRQs in their Resources tables. + * The same prevents us from using devm_request_threaded_irq() + * in this module. + */ } - return 0; } -- cgit v1.2.3 From 0aa8c6853121a05bea297f21a6f72dda8e61949f Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Thu, 25 Jul 2013 16:15:50 +0300 Subject: mfd: twl6030-irq: Create struct twl6030_irq Create "struct twl6030_irq" and place all local variables inside it. Also allocate twl6030_irq structure dynamically during initialization. Signed-off-by: Grygorii Strashko Acked-by: Graeme Gregory Signed-off-by: Samuel Ortiz --- drivers/mfd/twl6030-irq.c | 101 +++++++++++++++++++++++++++------------------- 1 file changed, 59 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 1b03ce9e9f15..e3c54f80b9f0 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -86,36 +86,44 @@ static int twl6030_interrupt_mapping[24] = { }; /*----------------------------------------------------------------------*/ -static int twl_irq; -static bool twl_irq_wake_enabled; +struct twl6030_irq { + unsigned int irq_base; + int twl_irq; + bool irq_wake_enabled; + atomic_t wakeirqs; + struct notifier_block pm_nb; + struct irq_chip irq_chip; + struct irq_domain *irq_domain; +}; -static atomic_t twl6030_wakeirqs = ATOMIC_INIT(0); -struct irq_domain *irq_domain; +static struct twl6030_irq *twl6030_irq; static int twl6030_irq_pm_notifier(struct notifier_block *notifier, unsigned long pm_event, void *unused) { int chained_wakeups; + struct twl6030_irq *pdata = container_of(notifier, struct twl6030_irq, + pm_nb); switch (pm_event) { case PM_SUSPEND_PREPARE: - chained_wakeups = atomic_read(&twl6030_wakeirqs); + chained_wakeups = atomic_read(&pdata->wakeirqs); - if (chained_wakeups && !twl_irq_wake_enabled) { - if (enable_irq_wake(twl_irq)) + if (chained_wakeups && !pdata->irq_wake_enabled) { + if (enable_irq_wake(pdata->twl_irq)) pr_err("twl6030 IRQ wake enable failed\n"); else - twl_irq_wake_enabled = true; - } else if (!chained_wakeups && twl_irq_wake_enabled) { - disable_irq_wake(twl_irq); - twl_irq_wake_enabled = false; + pdata->irq_wake_enabled = true; + } else if (!chained_wakeups && pdata->irq_wake_enabled) { + disable_irq_wake(pdata->twl_irq); + pdata->irq_wake_enabled = false; } - disable_irq(twl_irq); + disable_irq(pdata->twl_irq); break; case PM_POST_SUSPEND: - enable_irq(twl_irq); + enable_irq(pdata->twl_irq); break; default: @@ -125,10 +133,6 @@ static int twl6030_irq_pm_notifier(struct notifier_block *notifier, return NOTIFY_DONE; } -static struct notifier_block twl6030_irq_pm_notifier_block = { - .notifier_call = twl6030_irq_pm_notifier, -}; - /* * Threaded irq handler for the twl6030 interrupt. * We query the interrupt controller in the twl6030 to determine @@ -138,11 +142,11 @@ static struct notifier_block twl6030_irq_pm_notifier_block = { static irqreturn_t twl6030_irq_thread(int irq, void *data) { int i, ret; - struct irq_domain *irq_domain = (struct irq_domain *)data; union { u8 bytes[4]; u32 int_sts; } sts; + struct twl6030_irq *pdata = data; /* read INT_STS_A, B and C in one shot using a burst read */ ret = twl_i2c_read(TWL_MODULE_PIH, sts.bytes, REG_INT_STS_A, 3); @@ -163,7 +167,7 @@ static irqreturn_t twl6030_irq_thread(int irq, void *data) for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) if (sts.int_sts & 0x1) { int module_irq = - irq_find_mapping(irq_domain, + irq_find_mapping(pdata->irq_domain, twl6030_interrupt_mapping[i]); if (module_irq) handle_nested_irq(module_irq); @@ -194,10 +198,12 @@ static irqreturn_t twl6030_irq_thread(int irq, void *data) static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on) { + struct twl6030_irq *pdata = irq_get_chip_data(d->irq); + if (on) - atomic_inc(&twl6030_wakeirqs); + atomic_inc(&pdata->wakeirqs); else - atomic_dec(&twl6030_wakeirqs); + atomic_dec(&pdata->wakeirqs); return 0; } @@ -272,7 +278,8 @@ int twl6030_mmc_card_detect_config(void) return ret; } - return irq_find_mapping(irq_domain, MMCDETECT_INTR_OFFSET); + return irq_find_mapping(twl6030_irq->irq_domain, + MMCDETECT_INTR_OFFSET); } EXPORT_SYMBOL(twl6030_mmc_card_detect_config); @@ -301,15 +308,15 @@ int twl6030_mmc_card_detect(struct device *dev, int slot) } EXPORT_SYMBOL(twl6030_mmc_card_detect); -static struct irq_chip twl6030_irq_chip; - static int twl6030_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq) { - irq_set_chip_data(virq, &twl6030_irq_chip); - irq_set_chip_and_handler(virq, &twl6030_irq_chip, handle_simple_irq); + struct twl6030_irq *pdata = d->host_data; + + irq_set_chip_data(virq, pdata); + irq_set_chip_and_handler(virq, &pdata->irq_chip, handle_simple_irq); irq_set_nested_thread(virq, true); - irq_set_parent(virq, twl_irq); + irq_set_parent(virq, pdata->twl_irq); #ifdef CONFIG_ARM /* @@ -349,6 +356,12 @@ int twl6030_init_irq(struct device *dev, int irq_num) nr_irqs = TWL6030_NR_IRQS; + twl6030_irq = devm_kzalloc(dev, sizeof(*twl6030_irq), GFP_KERNEL); + if (!twl6030_irq) { + dev_err(dev, "twl6030_irq: Memory allocation failed\n"); + return -ENOMEM; + } + mask[0] = 0xFF; mask[1] = 0xFF; mask[2] = 0xFF; @@ -369,14 +382,18 @@ int twl6030_init_irq(struct device *dev, int irq_num) * install an irq handler for each of the modules; * clone dummy irq_chip since PIH can't *do* anything */ - twl6030_irq_chip = dummy_irq_chip; - twl6030_irq_chip.name = "twl6030"; - twl6030_irq_chip.irq_set_type = NULL; - twl6030_irq_chip.irq_set_wake = twl6030_irq_set_wake; - - irq_domain = irq_domain_add_linear(node, nr_irqs, - &twl6030_irq_domain_ops, NULL); - if (!irq_domain) { + twl6030_irq->irq_chip = dummy_irq_chip; + twl6030_irq->irq_chip.name = "twl6030"; + twl6030_irq->irq_chip.irq_set_type = NULL; + twl6030_irq->irq_chip.irq_set_wake = twl6030_irq_set_wake; + + twl6030_irq->pm_nb.notifier_call = twl6030_irq_pm_notifier; + atomic_set(&twl6030_irq->wakeirqs, 0); + + twl6030_irq->irq_domain = + irq_domain_add_linear(node, nr_irqs, + &twl6030_irq_domain_ops, twl6030_irq); + if (!twl6030_irq->irq_domain) { dev_err(dev, "Can't add irq_domain\n"); return -ENOMEM; } @@ -385,26 +402,26 @@ int twl6030_init_irq(struct device *dev, int irq_num) /* install an irq handler to demultiplex the TWL6030 interrupt */ status = request_threaded_irq(irq_num, NULL, twl6030_irq_thread, - IRQF_ONESHOT, "TWL6030-PIH", irq_domain); + IRQF_ONESHOT, "TWL6030-PIH", twl6030_irq); if (status < 0) { dev_err(dev, "could not claim irq %d: %d\n", irq_num, status); goto fail_irq; } - twl_irq = irq_num; - register_pm_notifier(&twl6030_irq_pm_notifier_block); + twl6030_irq->twl_irq = irq_num; + register_pm_notifier(&twl6030_irq->pm_nb); return 0; fail_irq: - irq_domain_remove(irq_domain); + irq_domain_remove(twl6030_irq->irq_domain); return status; } int twl6030_exit_irq(void) { - if (twl_irq) { - unregister_pm_notifier(&twl6030_irq_pm_notifier_block); - free_irq(twl_irq, NULL); + if (twl6030_irq && twl6030_irq->twl_irq) { + unregister_pm_notifier(&twl6030_irq->pm_nb); + free_irq(twl6030_irq->twl_irq, NULL); /* * TODO: IRQ domain and allocated nested IRQ descriptors * should be freed somehow here. Now It can't be done, because -- cgit v1.2.3 From 74d85e47ab8a7cdeffde6373cf1550bfbd2feaa6 Mon Sep 17 00:00:00 2001 From: Oleksandr Dmytryshyn Date: Thu, 25 Jul 2013 16:15:51 +0300 Subject: mfd: twl6030-irq: Add interrupt mapping table for the twl6032 The TWL6032 PMIC has different IRQ status bits meaning. Hence, add interrupt mapping table for the twl6032. Signed-off-by: Oleksandr Dmytryshyn Signed-off-by: Grygorii Strashko Acked-by: Graeme Gregory Signed-off-by: Samuel Ortiz --- drivers/mfd/twl6030-irq.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index e3c54f80b9f0..517eda832f79 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "twl-core.h" @@ -84,6 +85,36 @@ static int twl6030_interrupt_mapping[24] = { CHARGERFAULT_INTR_OFFSET, /* Bit 22 INT_CHRG */ RSV_INTR_OFFSET, /* Bit 23 Reserved */ }; + +static int twl6032_interrupt_mapping[24] = { + PWR_INTR_OFFSET, /* Bit 0 PWRON */ + PWR_INTR_OFFSET, /* Bit 1 RPWRON */ + PWR_INTR_OFFSET, /* Bit 2 SYS_VLOW */ + RTC_INTR_OFFSET, /* Bit 3 RTC_ALARM */ + RTC_INTR_OFFSET, /* Bit 4 RTC_PERIOD */ + HOTDIE_INTR_OFFSET, /* Bit 5 HOT_DIE */ + SMPSLDO_INTR_OFFSET, /* Bit 6 VXXX_SHORT */ + PWR_INTR_OFFSET, /* Bit 7 SPDURATION */ + + PWR_INTR_OFFSET, /* Bit 8 WATCHDOG */ + BATDETECT_INTR_OFFSET, /* Bit 9 BAT */ + SIMDETECT_INTR_OFFSET, /* Bit 10 SIM */ + MMCDETECT_INTR_OFFSET, /* Bit 11 MMC */ + MADC_INTR_OFFSET, /* Bit 12 GPADC_RT_EOC */ + MADC_INTR_OFFSET, /* Bit 13 GPADC_SW_EOC */ + GASGAUGE_INTR_OFFSET, /* Bit 14 CC_EOC */ + GASGAUGE_INTR_OFFSET, /* Bit 15 CC_AUTOCAL */ + + USBOTG_INTR_OFFSET, /* Bit 16 ID_WKUP */ + USBOTG_INTR_OFFSET, /* Bit 17 VBUS_WKUP */ + USBOTG_INTR_OFFSET, /* Bit 18 ID */ + USB_PRES_INTR_OFFSET, /* Bit 19 VBUS */ + CHARGER_INTR_OFFSET, /* Bit 20 CHRG_CTRL */ + CHARGERFAULT_INTR_OFFSET, /* Bit 21 EXT_CHRG */ + CHARGERFAULT_INTR_OFFSET, /* Bit 22 INT_CHRG */ + RSV_INTR_OFFSET, /* Bit 23 Reserved */ +}; + /*----------------------------------------------------------------------*/ struct twl6030_irq { @@ -94,6 +125,7 @@ struct twl6030_irq { struct notifier_block pm_nb; struct irq_chip irq_chip; struct irq_domain *irq_domain; + const int *irq_mapping_tbl; }; static struct twl6030_irq *twl6030_irq; @@ -168,7 +200,7 @@ static irqreturn_t twl6030_irq_thread(int irq, void *data) if (sts.int_sts & 0x1) { int module_irq = irq_find_mapping(pdata->irq_domain, - twl6030_interrupt_mapping[i]); + pdata->irq_mapping_tbl[i]); if (module_irq) handle_nested_irq(module_irq); else @@ -347,12 +379,25 @@ static struct irq_domain_ops twl6030_irq_domain_ops = { .xlate = irq_domain_xlate_onetwocell, }; +static const struct of_device_id twl6030_of_match[] = { + {.compatible = "ti,twl6030", &twl6030_interrupt_mapping}, + {.compatible = "ti,twl6032", &twl6032_interrupt_mapping}, + { }, +}; + int twl6030_init_irq(struct device *dev, int irq_num) { struct device_node *node = dev->of_node; int nr_irqs; int status; u8 mask[3]; + const struct of_device_id *of_id; + + of_id = of_match_device(twl6030_of_match, dev); + if (!of_id || !of_id->data) { + dev_err(dev, "Unknown TWL device model\n"); + return -EINVAL; + } nr_irqs = TWL6030_NR_IRQS; @@ -389,6 +434,7 @@ int twl6030_init_irq(struct device *dev, int irq_num) twl6030_irq->pm_nb.notifier_call = twl6030_irq_pm_notifier; atomic_set(&twl6030_irq->wakeirqs, 0); + twl6030_irq->irq_mapping_tbl = of_id->data; twl6030_irq->irq_domain = irq_domain_add_linear(node, nr_irqs, -- cgit v1.2.3 From 773ccdfd9cc6f9bf8ec75a59fa742d7a663a5903 Mon Sep 17 00:00:00 2001 From: Wei WANG Date: Tue, 20 Aug 2013 14:18:51 +0800 Subject: mfd: rtsx: Read vendor setting from config space Normally OEMs will set vendor setting to the config space of Realtek card reader in BIOS stage. This patch reads the setting at the first, and configure the internal registers according to it, to improve card reader's compatibility condition. Signed-off-by: Wei WANG Signed-off-by: Samuel Ortiz --- drivers/mfd/rtl8411.c | 77 ++++++++++++++++++++++++++++++++++--- drivers/mfd/rts5209.c | 48 +++++++++++++++-------- drivers/mfd/rts5227.c | 91 ++++++++++++++++++++++++++++++++++---------- drivers/mfd/rts5229.c | 38 ++++++++++++++++-- drivers/mfd/rts5249.c | 90 +++++++++++++++++++++++++++++++++---------- drivers/mfd/rtsx_pcr.c | 26 +++++++++++-- drivers/mfd/rtsx_pcr.h | 29 ++++++++++++++ include/linux/mfd/rtsx_pci.h | 34 ++++++++++++++++- 8 files changed, 365 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/rtl8411.c b/drivers/mfd/rtl8411.c index c436bf27e78d..5a68c9bdeddf 100644 --- a/drivers/mfd/rtl8411.c +++ b/drivers/mfd/rtl8411.c @@ -47,19 +47,70 @@ static int rtl8411b_is_qfn48(struct rtsx_pcr *pcr) return 0; } +static void rtl8411_fetch_vendor_settings(struct rtsx_pcr *pcr) +{ + u32 reg1; + u8 reg3; + + rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®1); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg1); + + if (!rtsx_vendor_setting_valid(reg1)) + return; + + pcr->aspm_en = rtsx_reg_to_aspm(reg1); + pcr->sd30_drive_sel_1v8 = + map_sd_drive(rtsx_reg_to_sd30_drive_sel_1v8(reg1)); + pcr->card_drive_sel &= 0x3F; + pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg1); + + rtsx_pci_read_config_byte(pcr, PCR_SETTING_REG3, ®3); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG3, reg3); + pcr->sd30_drive_sel_3v3 = rtl8411_reg_to_sd30_drive_sel_3v3(reg3); +} + +static void rtl8411b_fetch_vendor_settings(struct rtsx_pcr *pcr) +{ + u32 reg; + + rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg); + + if (!rtsx_vendor_setting_valid(reg)) + return; + + pcr->aspm_en = rtsx_reg_to_aspm(reg); + pcr->sd30_drive_sel_1v8 = + map_sd_drive(rtsx_reg_to_sd30_drive_sel_1v8(reg)); + pcr->sd30_drive_sel_3v3 = + map_sd_drive(rtl8411b_reg_to_sd30_drive_sel_3v3(reg)); +} + static int rtl8411_extra_init_hw(struct rtsx_pcr *pcr) { - return rtsx_pci_write_register(pcr, CD_PAD_CTL, + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL, + 0xFF, pcr->sd30_drive_sel_3v3); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CD_PAD_CTL, CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE); + + return rtsx_pci_send_cmd(pcr, 100); } static int rtl8411b_extra_init_hw(struct rtsx_pcr *pcr) { - if (rtl8411b_is_qfn48(pcr)) - rtsx_pci_write_register(pcr, CARD_PULL_CTL3, 0xFF, 0xF5); + rtsx_pci_init_cmd(pcr); - return rtsx_pci_write_register(pcr, CD_PAD_CTL, + if (rtl8411b_is_qfn48(pcr)) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + CARD_PULL_CTL3, 0xFF, 0xF5); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL, + 0xFF, pcr->sd30_drive_sel_3v3); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CD_PAD_CTL, CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE); + + return rtsx_pci_send_cmd(pcr, 100); } static int rtl8411_turn_on_led(struct rtsx_pcr *pcr) @@ -141,13 +192,13 @@ static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) mask = (BPP_REG_TUNED18 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_MASK; if (voltage == OUTPUT_3V3) { err = rtsx_pci_write_register(pcr, - SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_D); + SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3); if (err < 0) return err; val = (BPP_ASIC_3V3 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_3V3; } else if (voltage == OUTPUT_1V8) { err = rtsx_pci_write_register(pcr, - SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B); + SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8); if (err < 0) return err; val = (BPP_ASIC_1V8 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_1V8; @@ -222,6 +273,7 @@ static int rtl8411_conv_clk_and_div_n(int input, int dir) } static const struct pcr_ops rtl8411_pcr_ops = { + .fetch_vendor_settings = rtl8411_fetch_vendor_settings, .extra_init_hw = rtl8411_extra_init_hw, .optimize_phy = NULL, .turn_on_led = rtl8411_turn_on_led, @@ -236,6 +288,7 @@ static const struct pcr_ops rtl8411_pcr_ops = { }; static const struct pcr_ops rtl8411b_pcr_ops = { + .fetch_vendor_settings = rtl8411b_fetch_vendor_settings, .extra_init_hw = rtl8411b_extra_init_hw, .optimize_phy = NULL, .turn_on_led = rtl8411_turn_on_led, @@ -385,6 +438,12 @@ void rtl8411_init_params(struct rtsx_pcr *pcr) pcr->num_slots = 2; pcr->ops = &rtl8411_pcr_ops; + pcr->flags = 0; + pcr->card_drive_sel = RTL8411_CARD_DRIVE_DEFAULT; + pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B; + pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D; + pcr->aspm_en = ASPM_L1_EN; + pcr->ic_version = rtl8411_get_ic_version(pcr); pcr->sd_pull_ctl_enable_tbl = rtl8411_sd_pull_ctl_enable_tbl; pcr->sd_pull_ctl_disable_tbl = rtl8411_sd_pull_ctl_disable_tbl; @@ -398,6 +457,12 @@ void rtl8411b_init_params(struct rtsx_pcr *pcr) pcr->num_slots = 2; pcr->ops = &rtl8411b_pcr_ops; + pcr->flags = 0; + pcr->card_drive_sel = RTL8411_CARD_DRIVE_DEFAULT; + pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B; + pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D; + pcr->aspm_en = ASPM_L1_EN; + pcr->ic_version = rtl8411_get_ic_version(pcr); if (rtl8411b_is_qfn48(pcr)) { diff --git a/drivers/mfd/rts5209.c b/drivers/mfd/rts5209.c index ec78d9fb0879..2170449bd7e5 100644 --- a/drivers/mfd/rts5209.c +++ b/drivers/mfd/rts5209.c @@ -34,18 +34,28 @@ static u8 rts5209_get_ic_version(struct rtsx_pcr *pcr) return val & 0x0F; } -static void rts5209_init_vendor_cfg(struct rtsx_pcr *pcr) +static void rts5209_fetch_vendor_settings(struct rtsx_pcr *pcr) { - u32 val; + u32 reg; - rtsx_pci_read_config_dword(pcr, 0x724, &val); - dev_dbg(&(pcr->pci->dev), "Cfg 0x724: 0x%x\n", val); + rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg); - if (!(val & 0x80)) { - if (val & 0x08) - pcr->ms_pmos = false; - else - pcr->ms_pmos = true; + if (rts5209_vendor_setting1_valid(reg)) { + if (rts5209_reg_check_ms_pmos(reg)) + pcr->flags |= PCR_MS_PMOS; + pcr->aspm_en = rts5209_reg_to_aspm(reg); + } + + rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, ®); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg); + + if (rts5209_vendor_setting2_valid(reg)) { + pcr->sd30_drive_sel_1v8 = + rts5209_reg_to_sd30_drive_sel_1v8(reg); + pcr->sd30_drive_sel_3v3 = + rts5209_reg_to_sd30_drive_sel_3v3(reg); + pcr->card_drive_sel = rts5209_reg_to_card_drive_sel(reg); } } @@ -57,6 +67,9 @@ static int rts5209_extra_init_hw(struct rtsx_pcr *pcr) rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO, 0xFF, 0x03); /* Configure GPIO as output */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO_DIR, 0xFF, 0x03); + /* Configure driving */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL, + 0xFF, pcr->sd30_drive_sel_3v3); return rtsx_pci_send_cmd(pcr, 100); } @@ -95,7 +108,7 @@ static int rts5209_card_power_on(struct rtsx_pcr *pcr, int card) partial_pwr_on = SD_PARTIAL_POWER_ON; pwr_on = SD_POWER_ON; - if (pcr->ms_pmos && (card == RTSX_MS_CARD)) { + if ((pcr->flags & PCR_MS_PMOS) && (card == RTSX_MS_CARD)) { pwr_mask = MS_POWER_MASK; partial_pwr_on = MS_PARTIAL_POWER_ON; pwr_on = MS_POWER_ON; @@ -131,7 +144,7 @@ static int rts5209_card_power_off(struct rtsx_pcr *pcr, int card) pwr_mask = SD_POWER_MASK; pwr_off = SD_POWER_OFF; - if (pcr->ms_pmos && (card == RTSX_MS_CARD)) { + if ((pcr->flags & PCR_MS_PMOS) && (card == RTSX_MS_CARD)) { pwr_mask = MS_POWER_MASK; pwr_off = MS_POWER_OFF; } @@ -140,7 +153,7 @@ static int rts5209_card_power_off(struct rtsx_pcr *pcr, int card) rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, pwr_mask | PMOS_STRG_MASK, pwr_off | PMOS_STRG_400mA); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, - LDO3318_PWR_MASK, 0X06); + LDO3318_PWR_MASK, 0x06); return rtsx_pci_send_cmd(pcr, 100); } @@ -150,7 +163,7 @@ static int rts5209_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) if (voltage == OUTPUT_3V3) { err = rtsx_pci_write_register(pcr, - SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_D); + SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3); if (err < 0) return err; err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24); @@ -158,7 +171,7 @@ static int rts5209_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) return err; } else if (voltage == OUTPUT_1V8) { err = rtsx_pci_write_register(pcr, - SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B); + SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8); if (err < 0) return err; err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24); @@ -172,6 +185,7 @@ static int rts5209_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) } static const struct pcr_ops rts5209_pcr_ops = { + .fetch_vendor_settings = rts5209_fetch_vendor_settings, .extra_init_hw = rts5209_extra_init_hw, .optimize_phy = rts5209_optimize_phy, .turn_on_led = rts5209_turn_on_led, @@ -242,7 +256,11 @@ void rts5209_init_params(struct rtsx_pcr *pcr) pcr->num_slots = 2; pcr->ops = &rts5209_pcr_ops; - rts5209_init_vendor_cfg(pcr); + pcr->flags = 0; + pcr->card_drive_sel = RTS5209_CARD_DRIVE_DEFAULT; + pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B; + pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D; + pcr->aspm_en = ASPM_L1_EN; pcr->ic_version = rts5209_get_ic_version(pcr); pcr->sd_pull_ctl_enable_tbl = rts5209_sd_pull_ctl_enable_tbl; diff --git a/drivers/mfd/rts5227.c b/drivers/mfd/rts5227.c index fc831dcb1480..c3181d71fedd 100644 --- a/drivers/mfd/rts5227.c +++ b/drivers/mfd/rts5227.c @@ -29,6 +29,60 @@ #include "rtsx_pcr.h" +static void rts5227_fill_driving(struct rtsx_pcr *pcr, u8 voltage) +{ + u8 driving_3v3[4][3] = { + {0x13, 0x13, 0x13}, + {0x96, 0x96, 0x96}, + {0x7F, 0x7F, 0x7F}, + {0x96, 0x96, 0x96}, + }; + u8 driving_1v8[4][3] = { + {0x99, 0x99, 0x99}, + {0xAA, 0xAA, 0xAA}, + {0xFE, 0xFE, 0xFE}, + {0xB3, 0xB3, 0xB3}, + }; + u8 (*driving)[3], drive_sel; + + if (voltage == OUTPUT_3V3) { + driving = driving_3v3; + drive_sel = pcr->sd30_drive_sel_3v3; + } else { + driving = driving_1v8; + drive_sel = pcr->sd30_drive_sel_1v8; + } + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL, + 0xFF, driving[drive_sel][0]); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL, + 0xFF, driving[drive_sel][1]); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL, + 0xFF, driving[drive_sel][2]); +} + +static void rts5227_fetch_vendor_settings(struct rtsx_pcr *pcr) +{ + u32 reg; + + rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg); + + if (!rtsx_vendor_setting_valid(reg)) + return; + + pcr->aspm_en = rtsx_reg_to_aspm(reg); + pcr->sd30_drive_sel_1v8 = rtsx_reg_to_sd30_drive_sel_1v8(reg); + pcr->card_drive_sel &= 0x3F; + pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg); + + rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, ®); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg); + pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg); + if (rtsx_reg_check_reverse_socket(reg)) + pcr->flags |= PCR_REVERSE_SOCKET; +} + static int rts5227_extra_init_hw(struct rtsx_pcr *pcr) { u16 cap; @@ -48,17 +102,15 @@ static int rts5227_extra_init_hw(struct rtsx_pcr *pcr) rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LTR_CTL, 0xFF, 0xA3); /* Configure OBFF */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OBFF_CFG, 0x03, 0x03); - /* Configure force_clock_req - * Maybe We should define 0xFF03 as some name - */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, 0xFF03, 0x08, 0x08); - /* Correct driving */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - SD30_CLK_DRIVE_SEL, 0xFF, 0x96); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - SD30_CMD_DRIVE_SEL, 0xFF, 0x96); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - SD30_DAT_DRIVE_SEL, 0xFF, 0x96); + /* Configure driving */ + rts5227_fill_driving(pcr, OUTPUT_3V3); + /* Configure force_clock_req */ + if (pcr->flags & PCR_REVERSE_SOCKET) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + AUTOLOAD_CFG_BASE + 3, 0xB8, 0xB8); + else + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + AUTOLOAD_CFG_BASE + 3, 0xB8, 0x88); return rtsx_pci_send_cmd(pcr, 100); } @@ -131,13 +183,11 @@ static int rts5227_card_power_off(struct rtsx_pcr *pcr, int card) static int rts5227_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) { int err; - u8 drive_sel; if (voltage == OUTPUT_3V3) { err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24); if (err < 0) return err; - drive_sel = 0x96; } else if (voltage == OUTPUT_1V8) { err = rtsx_pci_write_phy_register(pcr, 0x11, 0x3C02); if (err < 0) @@ -145,23 +195,18 @@ static int rts5227_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C80 | 0x24); if (err < 0) return err; - drive_sel = 0xB3; } else { return -EINVAL; } /* set pad drive */ rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL, - 0xFF, drive_sel); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL, - 0xFF, drive_sel); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL, - 0xFF, drive_sel); + rts5227_fill_driving(pcr, voltage); return rtsx_pci_send_cmd(pcr, 100); } static const struct pcr_ops rts5227_pcr_ops = { + .fetch_vendor_settings = rts5227_fetch_vendor_settings, .extra_init_hw = rts5227_extra_init_hw, .optimize_phy = rts5227_optimize_phy, .turn_on_led = rts5227_turn_on_led, @@ -227,6 +272,12 @@ void rts5227_init_params(struct rtsx_pcr *pcr) pcr->num_slots = 2; pcr->ops = &rts5227_pcr_ops; + pcr->flags = 0; + pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT; + pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B; + pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B; + pcr->aspm_en = ASPM_L1_EN; + pcr->sd_pull_ctl_enable_tbl = rts5227_sd_pull_ctl_enable_tbl; pcr->sd_pull_ctl_disable_tbl = rts5227_sd_pull_ctl_disable_tbl; pcr->ms_pull_ctl_enable_tbl = rts5227_ms_pull_ctl_enable_tbl; diff --git a/drivers/mfd/rts5229.c b/drivers/mfd/rts5229.c index 58af4dbe3586..7a1ad6dd2917 100644 --- a/drivers/mfd/rts5229.c +++ b/drivers/mfd/rts5229.c @@ -34,6 +34,28 @@ static u8 rts5229_get_ic_version(struct rtsx_pcr *pcr) return val & 0x0F; } +static void rts5229_fetch_vendor_settings(struct rtsx_pcr *pcr) +{ + u32 reg; + + rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg); + + if (!rtsx_vendor_setting_valid(reg)) + return; + + pcr->aspm_en = rtsx_reg_to_aspm(reg); + pcr->sd30_drive_sel_1v8 = + map_sd_drive(rtsx_reg_to_sd30_drive_sel_1v8(reg)); + pcr->card_drive_sel &= 0x3F; + pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg); + + rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, ®); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg); + pcr->sd30_drive_sel_3v3 = + map_sd_drive(rtsx_reg_to_sd30_drive_sel_3v3(reg)); +} + static int rts5229_extra_init_hw(struct rtsx_pcr *pcr) { rtsx_pci_init_cmd(pcr); @@ -45,6 +67,9 @@ static int rts5229_extra_init_hw(struct rtsx_pcr *pcr) rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01); /* LED shine disabled, set initial shine cycle period */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02); + /* Configure driving */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL, + 0xFF, pcr->sd30_drive_sel_3v3); return rtsx_pci_send_cmd(pcr, 100); } @@ -110,7 +135,7 @@ static int rts5229_card_power_off(struct rtsx_pcr *pcr, int card) SD_POWER_MASK | PMOS_STRG_MASK, SD_POWER_OFF | PMOS_STRG_400mA); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, - LDO3318_PWR_MASK, 0X00); + LDO3318_PWR_MASK, 0x00); return rtsx_pci_send_cmd(pcr, 100); } @@ -120,7 +145,7 @@ static int rts5229_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) if (voltage == OUTPUT_3V3) { err = rtsx_pci_write_register(pcr, - SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_D); + SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3); if (err < 0) return err; err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24); @@ -128,7 +153,7 @@ static int rts5229_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) return err; } else if (voltage == OUTPUT_1V8) { err = rtsx_pci_write_register(pcr, - SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B); + SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8); if (err < 0) return err; err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24); @@ -142,6 +167,7 @@ static int rts5229_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) } static const struct pcr_ops rts5229_pcr_ops = { + .fetch_vendor_settings = rts5229_fetch_vendor_settings, .extra_init_hw = rts5229_extra_init_hw, .optimize_phy = rts5229_optimize_phy, .turn_on_led = rts5229_turn_on_led, @@ -221,6 +247,12 @@ void rts5229_init_params(struct rtsx_pcr *pcr) pcr->num_slots = 2; pcr->ops = &rts5229_pcr_ops; + pcr->flags = 0; + pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT; + pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B; + pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D; + pcr->aspm_en = ASPM_L1_EN; + pcr->ic_version = rts5229_get_ic_version(pcr); if (pcr->ic_version == IC_VER_C) { pcr->sd_pull_ctl_enable_tbl = rts5229_sd_pull_ctl_enable_tbl2; diff --git a/drivers/mfd/rts5249.c b/drivers/mfd/rts5249.c index 15dc848bc081..d5db182f35db 100644 --- a/drivers/mfd/rts5249.c +++ b/drivers/mfd/rts5249.c @@ -34,6 +34,60 @@ static u8 rts5249_get_ic_version(struct rtsx_pcr *pcr) return val & 0x0F; } +static void rts5249_fill_driving(struct rtsx_pcr *pcr, u8 voltage) +{ + u8 driving_3v3[4][3] = { + {0x11, 0x11, 0x11}, + {0x55, 0x55, 0x5C}, + {0x99, 0x99, 0x92}, + {0x99, 0x99, 0x92}, + }; + u8 driving_1v8[4][3] = { + {0x3C, 0x3C, 0x3C}, + {0xB3, 0xB3, 0xB3}, + {0xFE, 0xFE, 0xFE}, + {0xC4, 0xC4, 0xC4}, + }; + u8 (*driving)[3], drive_sel; + + if (voltage == OUTPUT_3V3) { + driving = driving_3v3; + drive_sel = pcr->sd30_drive_sel_3v3; + } else { + driving = driving_1v8; + drive_sel = pcr->sd30_drive_sel_1v8; + } + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL, + 0xFF, driving[drive_sel][0]); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL, + 0xFF, driving[drive_sel][1]); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL, + 0xFF, driving[drive_sel][2]); +} + +static void rts5249_fetch_vendor_settings(struct rtsx_pcr *pcr) +{ + u32 reg; + + rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg); + + if (!rtsx_vendor_setting_valid(reg)) + return; + + pcr->aspm_en = rtsx_reg_to_aspm(reg); + pcr->sd30_drive_sel_1v8 = rtsx_reg_to_sd30_drive_sel_1v8(reg); + pcr->card_drive_sel &= 0x3F; + pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg); + + rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, ®); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg); + pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg); + if (rtsx_reg_check_reverse_socket(reg)) + pcr->flags |= PCR_REVERSE_SOCKET; +} + static int rts5249_extra_init_hw(struct rtsx_pcr *pcr) { rtsx_pci_init_cmd(pcr); @@ -45,13 +99,14 @@ static int rts5249_extra_init_hw(struct rtsx_pcr *pcr) rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01); /* LED shine disabled, set initial shine cycle period */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02); - /* Correct driving */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - SD30_CLK_DRIVE_SEL, 0xFF, 0x99); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - SD30_CMD_DRIVE_SEL, 0xFF, 0x99); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - SD30_DAT_DRIVE_SEL, 0xFF, 0x92); + /* Configure driving */ + rts5249_fill_driving(pcr, OUTPUT_3V3); + if (pcr->flags & PCR_REVERSE_SOCKET) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + AUTOLOAD_CFG_BASE + 3, 0xB0, 0xB0); + else + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + AUTOLOAD_CFG_BASE + 3, 0xB0, 0x80); return rtsx_pci_send_cmd(pcr, 100); } @@ -129,15 +184,11 @@ static int rts5249_card_power_off(struct rtsx_pcr *pcr, int card) static int rts5249_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) { int err; - u8 clk_drive, cmd_drive, dat_drive; if (voltage == OUTPUT_3V3) { err = rtsx_pci_write_phy_register(pcr, PHY_TUNE, 0x4FC0 | 0x24); if (err < 0) return err; - clk_drive = 0x99; - cmd_drive = 0x99; - dat_drive = 0x92; } else if (voltage == OUTPUT_1V8) { err = rtsx_pci_write_phy_register(pcr, PHY_BACR, 0x3C02); if (err < 0) @@ -145,25 +196,18 @@ static int rts5249_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) err = rtsx_pci_write_phy_register(pcr, PHY_TUNE, 0x4C40 | 0x24); if (err < 0) return err; - clk_drive = 0xb3; - cmd_drive = 0xb3; - dat_drive = 0xb3; } else { return -EINVAL; } /* set pad drive */ rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL, - 0xFF, clk_drive); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL, - 0xFF, cmd_drive); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL, - 0xFF, dat_drive); + rts5249_fill_driving(pcr, voltage); return rtsx_pci_send_cmd(pcr, 100); } static const struct pcr_ops rts5249_pcr_ops = { + .fetch_vendor_settings = rts5249_fetch_vendor_settings, .extra_init_hw = rts5249_extra_init_hw, .optimize_phy = rts5249_optimize_phy, .turn_on_led = rts5249_turn_on_led, @@ -233,6 +277,12 @@ void rts5249_init_params(struct rtsx_pcr *pcr) pcr->num_slots = 2; pcr->ops = &rts5249_pcr_ops; + pcr->flags = 0; + pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT; + pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_C; + pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B; + pcr->aspm_en = ASPM_L1_EN; + pcr->ic_version = rts5249_get_ic_version(pcr); pcr->sd_pull_ctl_enable_tbl = rts5249_sd_pull_ctl_enable_tbl; pcr->sd_pull_ctl_disable_tbl = rts5249_sd_pull_ctl_disable_tbl; diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c index dd186c4103c1..e06d6b0d55f6 100644 --- a/drivers/mfd/rtsx_pcr.c +++ b/drivers/mfd/rtsx_pcr.c @@ -73,6 +73,9 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr) pcr->state = PDEV_STAT_RUN; if (pcr->ops->enable_auto_blink) pcr->ops->enable_auto_blink(pcr); + + if (pcr->aspm_en) + rtsx_pci_write_config_byte(pcr, LCTLR, 0); } mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200)); @@ -717,7 +720,7 @@ int rtsx_pci_card_exclusive_check(struct rtsx_pcr *pcr, int card) [RTSX_MS_CARD] = MS_EXIST }; - if (!pcr->ms_pmos) { + if (!(pcr->flags & PCR_MS_PMOS)) { /* When using single PMOS, accessing card is not permitted * if the existing card is not the designated one. */ @@ -918,6 +921,9 @@ static void rtsx_pci_idle_work(struct work_struct *work) if (pcr->ops->turn_off_led) pcr->ops->turn_off_led(pcr); + if (pcr->aspm_en) + rtsx_pci_write_config_byte(pcr, LCTLR, pcr->aspm_en); + mutex_unlock(&pcr->pcr_mutex); } @@ -956,8 +962,8 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr) /* Reset delink mode */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CHANGE_LINK_STATE, 0x0A, 0); /* Card driving select */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL, - 0x07, DRIVER_TYPE_D); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DRIVE_SEL, + 0xFF, pcr->card_drive_sel); /* Enable SSC Clock */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, 0xFF, SSC_8X_EN | SSC_SEL_4M); @@ -989,6 +995,8 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr) if (err < 0) return err; + rtsx_pci_write_config_byte(pcr, LCTLR, 0); + /* Enable clk_request_n to enable clock power management */ rtsx_pci_write_config_byte(pcr, 0x81, 1); /* Enter L1 when host tx idle */ @@ -1053,6 +1061,18 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr) if (!pcr->slots) return -ENOMEM; + if (pcr->ops->fetch_vendor_settings) + pcr->ops->fetch_vendor_settings(pcr); + + dev_dbg(&(pcr->pci->dev), "pcr->aspm_en = 0x%x\n", pcr->aspm_en); + dev_dbg(&(pcr->pci->dev), "pcr->sd30_drive_sel_1v8 = 0x%x\n", + pcr->sd30_drive_sel_1v8); + dev_dbg(&(pcr->pci->dev), "pcr->sd30_drive_sel_3v3 = 0x%x\n", + pcr->sd30_drive_sel_3v3); + dev_dbg(&(pcr->pci->dev), "pcr->card_drive_sel = 0x%x\n", + pcr->card_drive_sel); + dev_dbg(&(pcr->pci->dev), "pcr->flags = 0x%x\n", pcr->flags); + pcr->state = PDEV_STAT_IDLE; err = rtsx_pci_init_hw(pcr); if (err < 0) { diff --git a/drivers/mfd/rtsx_pcr.h b/drivers/mfd/rtsx_pcr.h index c0cac7e8972f..7a1b87a250a5 100644 --- a/drivers/mfd/rtsx_pcr.h +++ b/drivers/mfd/rtsx_pcr.h @@ -35,4 +35,33 @@ void rts5227_init_params(struct rtsx_pcr *pcr); void rts5249_init_params(struct rtsx_pcr *pcr); void rtl8411b_init_params(struct rtsx_pcr *pcr); +static inline u8 map_sd_drive(int idx) +{ + u8 sd_drive[4] = { + 0x01, /* Type D */ + 0x02, /* Type C */ + 0x05, /* Type A */ + 0x03 /* Type B */ + }; + + return sd_drive[idx]; +} + +#define rtsx_vendor_setting_valid(reg) (!((reg) & 0x1000000)) +#define rts5209_vendor_setting1_valid(reg) (!((reg) & 0x80)) +#define rts5209_vendor_setting2_valid(reg) ((reg) & 0x80) + +#define rtsx_reg_to_aspm(reg) (((reg) >> 28) & 0x03) +#define rtsx_reg_to_sd30_drive_sel_1v8(reg) (((reg) >> 26) & 0x03) +#define rtsx_reg_to_sd30_drive_sel_3v3(reg) (((reg) >> 5) & 0x03) +#define rtsx_reg_to_card_drive_sel(reg) ((((reg) >> 25) & 0x01) << 6) +#define rtsx_reg_check_reverse_socket(reg) ((reg) & 0x4000) +#define rts5209_reg_to_aspm(reg) (((reg) >> 5) & 0x03) +#define rts5209_reg_check_ms_pmos(reg) (!((reg) & 0x08)) +#define rts5209_reg_to_sd30_drive_sel_1v8(reg) (((reg) >> 3) & 0x07) +#define rts5209_reg_to_sd30_drive_sel_3v3(reg) ((reg) & 0x07) +#define rts5209_reg_to_card_drive_sel(reg) ((reg) >> 8) +#define rtl8411_reg_to_sd30_drive_sel_3v3(reg) (((reg) >> 5) & 0x07) +#define rtl8411b_reg_to_sd30_drive_sel_3v3(reg) ((reg) & 0x03) + #endif diff --git a/include/linux/mfd/rtsx_pci.h b/include/linux/mfd/rtsx_pci.h index 7a9f7089435d..9cba73703704 100644 --- a/include/linux/mfd/rtsx_pci.h +++ b/include/linux/mfd/rtsx_pci.h @@ -184,11 +184,26 @@ #define CARD_SHARE_BAROSSA_SD 0x01 #define CARD_SHARE_BAROSSA_MS 0x02 +/* CARD_DRIVE_SEL */ +#define MS_DRIVE_8mA (0x01 << 6) +#define MMC_DRIVE_8mA (0x01 << 4) +#define XD_DRIVE_8mA (0x01 << 2) +#define GPIO_DRIVE_8mA 0x01 +#define RTS5209_CARD_DRIVE_DEFAULT (MS_DRIVE_8mA | MMC_DRIVE_8mA |\ + XD_DRIVE_8mA | GPIO_DRIVE_8mA) +#define RTL8411_CARD_DRIVE_DEFAULT (MS_DRIVE_8mA | MMC_DRIVE_8mA |\ + XD_DRIVE_8mA) +#define RTSX_CARD_DRIVE_DEFAULT (MS_DRIVE_8mA | GPIO_DRIVE_8mA) + /* SD30_DRIVE_SEL */ #define DRIVER_TYPE_A 0x05 #define DRIVER_TYPE_B 0x03 #define DRIVER_TYPE_C 0x02 #define DRIVER_TYPE_D 0x01 +#define CFG_DRIVER_TYPE_A 0x02 +#define CFG_DRIVER_TYPE_B 0x03 +#define CFG_DRIVER_TYPE_C 0x01 +#define CFG_DRIVER_TYPE_D 0x00 /* FPDCTL */ #define SSC_POWER_DOWN 0x01 @@ -684,6 +699,8 @@ #define DUMMY_REG_RESET_0 0xFE90 +#define AUTOLOAD_CFG_BASE 0xFF00 + /* Memory mapping */ #define SRAM_BASE 0xE600 #define RBUF_BASE 0xF400 @@ -726,6 +743,11 @@ #define PHY_FLD4 0x1E #define PHY_DUM_REG 0x1F +#define LCTLR 0x80 +#define PCR_SETTING_REG1 0x724 +#define PCR_SETTING_REG2 0x814 +#define PCR_SETTING_REG3 0x747 + #define rtsx_pci_init_cmd(pcr) ((pcr)->ci = 0) struct rtsx_pcr; @@ -747,6 +769,7 @@ struct pcr_ops { u8 voltage); unsigned int (*cd_deglitch)(struct rtsx_pcr *pcr); int (*conv_clk_and_div_n)(int clk, int dir); + void (*fetch_vendor_settings)(struct rtsx_pcr *pcr); }; enum PDEV_STAT {PDEV_STAT_IDLE, PDEV_STAT_RUN}; @@ -788,7 +811,6 @@ struct rtsx_pcr { struct completion *finish_me; unsigned int cur_clock; - bool ms_pmos; bool remove_pci; bool msi_en; @@ -806,6 +828,16 @@ struct rtsx_pcr { #define IC_VER_D 3 u8 ic_version; + u8 sd30_drive_sel_1v8; + u8 sd30_drive_sel_3v3; + u8 card_drive_sel; +#define ASPM_L1_EN 0x02 + u8 aspm_en; + +#define PCR_MS_PMOS (1 << 0) +#define PCR_REVERSE_SOCKET (1 << 1) + u32 flags; + const u32 *sd_pull_ctl_enable_tbl; const u32 *sd_pull_ctl_disable_tbl; const u32 *ms_pull_ctl_enable_tbl; -- cgit v1.2.3 From 5947c167d145f32d4475d647a87e2af2699efe45 Mon Sep 17 00:00:00 2001 From: Wei WANG Date: Tue, 20 Aug 2013 14:18:52 +0800 Subject: mfd: rtsx: Add shutdown callback in rtsx_pci_driver Some actions to clear power state should be handled in .shutdown callback in rtsx_pci_driver. This patch adopts the following measures to catch this goal: 1. Add a function rtsx_pci_power_off to abstract the common ops in .shutdown and .suspend 2. Add pcr->ops->force_power_down to fulfill the individual action for each reader model Signed-off-by: Wei WANG Signed-off-by: Samuel Ortiz --- drivers/mfd/rtl8411.c | 7 +++++++ drivers/mfd/rts5209.c | 6 ++++++ drivers/mfd/rts5227.c | 11 +++++++++++ drivers/mfd/rts5229.c | 6 ++++++ drivers/mfd/rts5249.c | 11 +++++++++++ drivers/mfd/rtsx_pcr.c | 43 +++++++++++++++++++++++++++++++++---------- include/linux/mfd/rtsx_pci.h | 13 +++++++++++-- 7 files changed, 85 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/rtl8411.c b/drivers/mfd/rtl8411.c index 5a68c9bdeddf..56cc248392b5 100644 --- a/drivers/mfd/rtl8411.c +++ b/drivers/mfd/rtl8411.c @@ -86,6 +86,11 @@ static void rtl8411b_fetch_vendor_settings(struct rtsx_pcr *pcr) map_sd_drive(rtl8411b_reg_to_sd30_drive_sel_3v3(reg)); } +static void rtl8411_force_power_down(struct rtsx_pcr *pcr) +{ + rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07); +} + static int rtl8411_extra_init_hw(struct rtsx_pcr *pcr) { rtsx_pci_init_cmd(pcr); @@ -285,6 +290,7 @@ static const struct pcr_ops rtl8411_pcr_ops = { .switch_output_voltage = rtl8411_switch_output_voltage, .cd_deglitch = rtl8411_cd_deglitch, .conv_clk_and_div_n = rtl8411_conv_clk_and_div_n, + .force_power_down = rtl8411_force_power_down, }; static const struct pcr_ops rtl8411b_pcr_ops = { @@ -300,6 +306,7 @@ static const struct pcr_ops rtl8411b_pcr_ops = { .switch_output_voltage = rtl8411_switch_output_voltage, .cd_deglitch = rtl8411_cd_deglitch, .conv_clk_and_div_n = rtl8411_conv_clk_and_div_n, + .force_power_down = rtl8411_force_power_down, }; /* SD Pull Control Enable: diff --git a/drivers/mfd/rts5209.c b/drivers/mfd/rts5209.c index 2170449bd7e5..c67935efd4f5 100644 --- a/drivers/mfd/rts5209.c +++ b/drivers/mfd/rts5209.c @@ -59,6 +59,11 @@ static void rts5209_fetch_vendor_settings(struct rtsx_pcr *pcr) } } +static void rts5209_force_power_down(struct rtsx_pcr *pcr) +{ + rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07); +} + static int rts5209_extra_init_hw(struct rtsx_pcr *pcr) { rtsx_pci_init_cmd(pcr); @@ -197,6 +202,7 @@ static const struct pcr_ops rts5209_pcr_ops = { .switch_output_voltage = rts5209_switch_output_voltage, .cd_deglitch = NULL, .conv_clk_and_div_n = NULL, + .force_power_down = rts5209_force_power_down, }; /* SD Pull Control Enable: diff --git a/drivers/mfd/rts5227.c b/drivers/mfd/rts5227.c index c3181d71fedd..42ebf5c050c1 100644 --- a/drivers/mfd/rts5227.c +++ b/drivers/mfd/rts5227.c @@ -83,6 +83,16 @@ static void rts5227_fetch_vendor_settings(struct rtsx_pcr *pcr) pcr->flags |= PCR_REVERSE_SOCKET; } +static void rts5227_force_power_down(struct rtsx_pcr *pcr) +{ + /* Set relink_time to 0 */ + rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, 0xFF, 0); + rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, 0xFF, 0); + rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3, 0x01, 0); + + rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03); +} + static int rts5227_extra_init_hw(struct rtsx_pcr *pcr) { u16 cap; @@ -218,6 +228,7 @@ static const struct pcr_ops rts5227_pcr_ops = { .switch_output_voltage = rts5227_switch_output_voltage, .cd_deglitch = NULL, .conv_clk_and_div_n = NULL, + .force_power_down = rts5227_force_power_down, }; /* SD Pull Control Enable: diff --git a/drivers/mfd/rts5229.c b/drivers/mfd/rts5229.c index 7a1ad6dd2917..a0b695af8561 100644 --- a/drivers/mfd/rts5229.c +++ b/drivers/mfd/rts5229.c @@ -56,6 +56,11 @@ static void rts5229_fetch_vendor_settings(struct rtsx_pcr *pcr) map_sd_drive(rtsx_reg_to_sd30_drive_sel_3v3(reg)); } +static void rts5229_force_power_down(struct rtsx_pcr *pcr) +{ + rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03); +} + static int rts5229_extra_init_hw(struct rtsx_pcr *pcr) { rtsx_pci_init_cmd(pcr); @@ -179,6 +184,7 @@ static const struct pcr_ops rts5229_pcr_ops = { .switch_output_voltage = rts5229_switch_output_voltage, .cd_deglitch = NULL, .conv_clk_and_div_n = NULL, + .force_power_down = rts5229_force_power_down, }; /* SD Pull Control Enable: diff --git a/drivers/mfd/rts5249.c b/drivers/mfd/rts5249.c index d5db182f35db..79ff212c3e7b 100644 --- a/drivers/mfd/rts5249.c +++ b/drivers/mfd/rts5249.c @@ -88,6 +88,16 @@ static void rts5249_fetch_vendor_settings(struct rtsx_pcr *pcr) pcr->flags |= PCR_REVERSE_SOCKET; } +static void rts5249_force_power_down(struct rtsx_pcr *pcr) +{ + /* Set relink_time to 0 */ + rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, 0xFF, 0); + rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, 0xFF, 0); + rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3, 0x01, 0); + + rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03); +} + static int rts5249_extra_init_hw(struct rtsx_pcr *pcr) { rtsx_pci_init_cmd(pcr); @@ -217,6 +227,7 @@ static const struct pcr_ops rts5249_pcr_ops = { .card_power_on = rts5249_card_power_on, .card_power_off = rts5249_card_power_off, .switch_output_voltage = rts5249_switch_output_voltage, + .force_power_down = rts5249_force_power_down, }; /* SD Pull Control Enable: diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c index e06d6b0d55f6..97526f1acf96 100644 --- a/drivers/mfd/rtsx_pcr.c +++ b/drivers/mfd/rtsx_pcr.c @@ -927,6 +927,21 @@ static void rtsx_pci_idle_work(struct work_struct *work) mutex_unlock(&pcr->pcr_mutex); } +static void rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state) +{ + if (pcr->ops->turn_off_led) + pcr->ops->turn_off_led(pcr); + + rtsx_pci_writel(pcr, RTSX_BIER, 0); + pcr->bier = 0; + + rtsx_pci_write_register(pcr, PETXCFG, 0x08, 0x08); + rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, pm_state); + + if (pcr->ops->force_power_down) + pcr->ops->force_power_down(pcr); +} + static int rtsx_pci_init_hw(struct rtsx_pcr *pcr) { int err; @@ -1255,7 +1270,6 @@ static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state) { struct pcr_handle *handle; struct rtsx_pcr *pcr; - int ret = 0; dev_dbg(&(pcidev->dev), "--> %s\n", __func__); @@ -1267,14 +1281,7 @@ static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state) mutex_lock(&pcr->pcr_mutex); - if (pcr->ops->turn_off_led) - pcr->ops->turn_off_led(pcr); - - rtsx_pci_writel(pcr, RTSX_BIER, 0); - pcr->bier = 0; - - rtsx_pci_write_register(pcr, PETXCFG, 0x08, 0x08); - rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x02); + rtsx_pci_power_off(pcr, HOST_ENTER_S3); pci_save_state(pcidev); pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0); @@ -1282,7 +1289,7 @@ static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state) pci_set_power_state(pcidev, pci_choose_state(pcidev, state)); mutex_unlock(&pcr->pcr_mutex); - return ret; + return 0; } static int rtsx_pci_resume(struct pci_dev *pcidev) @@ -1320,10 +1327,25 @@ out: return ret; } +static void rtsx_pci_shutdown(struct pci_dev *pcidev) +{ + struct pcr_handle *handle; + struct rtsx_pcr *pcr; + + dev_dbg(&(pcidev->dev), "--> %s\n", __func__); + + handle = pci_get_drvdata(pcidev); + pcr = handle->pcr; + rtsx_pci_power_off(pcr, HOST_ENTER_S1); + + pci_disable_device(pcidev); +} + #else /* CONFIG_PM */ #define rtsx_pci_suspend NULL #define rtsx_pci_resume NULL +#define rtsx_pci_shutdown NULL #endif /* CONFIG_PM */ @@ -1334,6 +1356,7 @@ static struct pci_driver rtsx_pci_driver = { .remove = rtsx_pci_remove, .suspend = rtsx_pci_suspend, .resume = rtsx_pci_resume, + .shutdown = rtsx_pci_shutdown, }; module_pci_driver(rtsx_pci_driver); diff --git a/include/linux/mfd/rtsx_pci.h b/include/linux/mfd/rtsx_pci.h index 9cba73703704..11ab786fdc83 100644 --- a/include/linux/mfd/rtsx_pci.h +++ b/include/linux/mfd/rtsx_pci.h @@ -25,8 +25,7 @@ #include #include - -#include "rtsx_common.h" +#include #define MAX_RW_REG_CNT 1024 @@ -536,6 +535,10 @@ #define SAMPLE_VAR_CLK0 (0x01 << 4) #define SAMPLE_VAR_CLK1 (0x02 << 4) +/* HOST_SLEEP_STATE */ +#define HOST_ENTER_S1 1 +#define HOST_ENTER_S3 2 + #define MS_CFG 0xFD40 #define MS_TPC 0xFD41 #define MS_TRANS_CFG 0xFD42 @@ -701,6 +704,11 @@ #define AUTOLOAD_CFG_BASE 0xFF00 +#define PM_CTRL1 0xFF44 +#define PM_CTRL2 0xFF45 +#define PM_CTRL3 0xFF46 +#define PM_CTRL4 0xFF47 + /* Memory mapping */ #define SRAM_BASE 0xE600 #define RBUF_BASE 0xF400 @@ -770,6 +778,7 @@ struct pcr_ops { unsigned int (*cd_deglitch)(struct rtsx_pcr *pcr); int (*conv_clk_and_div_n)(int clk, int dir); void (*fetch_vendor_settings)(struct rtsx_pcr *pcr); + void (*force_power_down)(struct rtsx_pcr *pcr); }; enum PDEV_STAT {PDEV_STAT_IDLE, PDEV_STAT_RUN}; -- cgit v1.2.3 From 7140812c4a3676e834bc2ed587be441afba04e18 Mon Sep 17 00:00:00 2001 From: Wei WANG Date: Tue, 20 Aug 2013 14:18:53 +0800 Subject: mfd: rtsx: Move some actions from rtsx_pci_init_hw to individual extra_init_hw These actions are individual for each reader model, so should be put in extra_init_hw instead of rtsx_pci_init_hw. Signed-off-by: Wei WANG Signed-off-by: Samuel Ortiz --- drivers/mfd/rts5209.c | 4 ++++ drivers/mfd/rts5227.c | 2 ++ drivers/mfd/rts5229.c | 4 ++++ drivers/mfd/rts5249.c | 2 ++ drivers/mfd/rtsx_pcr.c | 4 ---- 5 files changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/rts5209.c b/drivers/mfd/rts5209.c index c67935efd4f5..03a15f779ebb 100644 --- a/drivers/mfd/rts5209.c +++ b/drivers/mfd/rts5209.c @@ -70,6 +70,10 @@ static int rts5209_extra_init_hw(struct rtsx_pcr *pcr) /* Turn off LED */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO, 0xFF, 0x03); + /* Reset ASPM state to default value */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0); + /* Force CLKREQ# PIN to drive 0 to request clock */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08); /* Configure GPIO as output */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO_DIR, 0xFF, 0x03); /* Configure driving */ diff --git a/drivers/mfd/rts5227.c b/drivers/mfd/rts5227.c index 42ebf5c050c1..724ce4c54523 100644 --- a/drivers/mfd/rts5227.c +++ b/drivers/mfd/rts5227.c @@ -101,6 +101,8 @@ static int rts5227_extra_init_hw(struct rtsx_pcr *pcr) /* Configure GPIO as output */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02); + /* Reset ASPM state to default value */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0); /* Switch LDO3318 source from DV33 to card_3v3 */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01); diff --git a/drivers/mfd/rts5229.c b/drivers/mfd/rts5229.c index a0b695af8561..e8261d7436a8 100644 --- a/drivers/mfd/rts5229.c +++ b/drivers/mfd/rts5229.c @@ -67,6 +67,10 @@ static int rts5229_extra_init_hw(struct rtsx_pcr *pcr) /* Configure GPIO as output */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02); + /* Reset ASPM state to default value */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0); + /* Force CLKREQ# PIN to drive 0 to request clock */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08); /* Switch LDO3318 source from DV33 to card_3v3 */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01); diff --git a/drivers/mfd/rts5249.c b/drivers/mfd/rts5249.c index 79ff212c3e7b..c5e54d7cf528 100644 --- a/drivers/mfd/rts5249.c +++ b/drivers/mfd/rts5249.c @@ -104,6 +104,8 @@ static int rts5249_extra_init_hw(struct rtsx_pcr *pcr) /* Configure GPIO as output */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02); + /* Reset ASPM state to default value */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0); /* Switch LDO3318 source from DV33 to card_3v3 */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01); diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c index 97526f1acf96..ffd393c06d34 100644 --- a/drivers/mfd/rtsx_pcr.c +++ b/drivers/mfd/rtsx_pcr.c @@ -972,8 +972,6 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr) rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, HOST_SLEEP_STATE, 0x03, 0x00); /* Disable card clock */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, 0x1E, 0); - /* Reset ASPM state to default value */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0); /* Reset delink mode */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CHANGE_LINK_STATE, 0x0A, 0); /* Card driving select */ @@ -1003,8 +1001,6 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr) * 0: ELBI interrupt flag[31:22] & [7:0] only can be write clear */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, NFTS_TX_CTRL, 0x02, 0); - /* Force CLKREQ# PIN to drive 0 to request clock */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08); err = rtsx_pci_send_cmd(pcr, 100); if (err < 0) -- cgit v1.2.3 From 0ccc0065c90284f283314e52a96e76ae8a8dce0a Mon Sep 17 00:00:00 2001 From: Wei WANG Date: Tue, 20 Aug 2013 14:18:54 +0800 Subject: mfd: rtsx: Clear hardware PFM mode in rtl8411b Clear hw_pfm_en to disable hardware PFM mode, to fix a bug that in some situation registers in 0xFDxx domain can't be accessed. Signed-off-by: Wei WANG Signed-off-by: Samuel Ortiz --- drivers/mfd/rtl8411.c | 2 ++ include/linux/mfd/rtsx_pci.h | 1 + 2 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/rtl8411.c b/drivers/mfd/rtl8411.c index 56cc248392b5..d183fa002338 100644 --- a/drivers/mfd/rtl8411.c +++ b/drivers/mfd/rtl8411.c @@ -114,6 +114,8 @@ static int rtl8411b_extra_init_hw(struct rtsx_pcr *pcr) 0xFF, pcr->sd30_drive_sel_3v3); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CD_PAD_CTL, CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, FUNC_FORCE_CTL, + 0x06, 0x00); return rtsx_pci_send_cmd(pcr, 100); } diff --git a/include/linux/mfd/rtsx_pci.h b/include/linux/mfd/rtsx_pci.h index 11ab786fdc83..9a16276bc080 100644 --- a/include/linux/mfd/rtsx_pci.h +++ b/include/linux/mfd/rtsx_pci.h @@ -687,6 +687,7 @@ #define PME_FORCE_CTL 0xFE56 #define ASPM_FORCE_CTL 0xFE57 #define PM_CLK_FORCE_CTL 0xFE58 +#define FUNC_FORCE_CTL 0xFE59 #define PERST_GLITCH_WIDTH 0xFE5C #define CHANGE_LINK_STATE 0xFE5B #define RESET_LOAD_REG 0xFE5E -- cgit v1.2.3 From eb891c65c9c87e55f728d95bcc514dea337aed12 Mon Sep 17 00:00:00 2001 From: Wei WANG Date: Tue, 20 Aug 2013 14:18:55 +0800 Subject: mfd: rtsx: Configure to enter a deeper power-saving mode in S3 Set a bit to enable rts5227 and rts5249 to enter a deeper internal power-saving mode in S3, and recover it after resuming. Signed-off-by: Wei WANG Signed-off-by: Samuel Ortiz --- drivers/mfd/rtl8411.c | 2 +- drivers/mfd/rts5209.c | 2 +- drivers/mfd/rts5227.c | 6 +++++- drivers/mfd/rts5229.c | 2 +- drivers/mfd/rts5249.c | 6 +++++- drivers/mfd/rtsx_pcr.c | 2 +- include/linux/mfd/rtsx_pci.h | 2 +- 7 files changed, 15 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/rtl8411.c b/drivers/mfd/rtl8411.c index d183fa002338..37367fb1c11b 100644 --- a/drivers/mfd/rtl8411.c +++ b/drivers/mfd/rtl8411.c @@ -86,7 +86,7 @@ static void rtl8411b_fetch_vendor_settings(struct rtsx_pcr *pcr) map_sd_drive(rtl8411b_reg_to_sd30_drive_sel_3v3(reg)); } -static void rtl8411_force_power_down(struct rtsx_pcr *pcr) +static void rtl8411_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) { rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07); } diff --git a/drivers/mfd/rts5209.c b/drivers/mfd/rts5209.c index 03a15f779ebb..ef6a59fe37a4 100644 --- a/drivers/mfd/rts5209.c +++ b/drivers/mfd/rts5209.c @@ -59,7 +59,7 @@ static void rts5209_fetch_vendor_settings(struct rtsx_pcr *pcr) } } -static void rts5209_force_power_down(struct rtsx_pcr *pcr) +static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) { rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07); } diff --git a/drivers/mfd/rts5227.c b/drivers/mfd/rts5227.c index 724ce4c54523..c72abd6b9c81 100644 --- a/drivers/mfd/rts5227.c +++ b/drivers/mfd/rts5227.c @@ -83,13 +83,16 @@ static void rts5227_fetch_vendor_settings(struct rtsx_pcr *pcr) pcr->flags |= PCR_REVERSE_SOCKET; } -static void rts5227_force_power_down(struct rtsx_pcr *pcr) +static void rts5227_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) { /* Set relink_time to 0 */ rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, 0xFF, 0); rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, 0xFF, 0); rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3, 0x01, 0); + if (pm_state == HOST_ENTER_S3) + rtsx_pci_write_register(pcr, PM_CTRL3, 0x10, 0x10); + rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03); } @@ -123,6 +126,7 @@ static int rts5227_extra_init_hw(struct rtsx_pcr *pcr) else rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, AUTOLOAD_CFG_BASE + 3, 0xB8, 0x88); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PM_CTRL3, 0x10, 0x00); return rtsx_pci_send_cmd(pcr, 100); } diff --git a/drivers/mfd/rts5229.c b/drivers/mfd/rts5229.c index e8261d7436a8..afb0f24bac71 100644 --- a/drivers/mfd/rts5229.c +++ b/drivers/mfd/rts5229.c @@ -56,7 +56,7 @@ static void rts5229_fetch_vendor_settings(struct rtsx_pcr *pcr) map_sd_drive(rtsx_reg_to_sd30_drive_sel_3v3(reg)); } -static void rts5229_force_power_down(struct rtsx_pcr *pcr) +static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) { rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03); } diff --git a/drivers/mfd/rts5249.c b/drivers/mfd/rts5249.c index c5e54d7cf528..384b30b432bd 100644 --- a/drivers/mfd/rts5249.c +++ b/drivers/mfd/rts5249.c @@ -88,13 +88,16 @@ static void rts5249_fetch_vendor_settings(struct rtsx_pcr *pcr) pcr->flags |= PCR_REVERSE_SOCKET; } -static void rts5249_force_power_down(struct rtsx_pcr *pcr) +static void rts5249_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) { /* Set relink_time to 0 */ rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, 0xFF, 0); rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, 0xFF, 0); rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3, 0x01, 0); + if (pm_state == HOST_ENTER_S3) + rtsx_pci_write_register(pcr, PM_CTRL3, 0x10, 0x10); + rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03); } @@ -119,6 +122,7 @@ static int rts5249_extra_init_hw(struct rtsx_pcr *pcr) else rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, AUTOLOAD_CFG_BASE + 3, 0xB0, 0x80); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PM_CTRL3, 0x10, 0x00); return rtsx_pci_send_cmd(pcr, 100); } diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c index ffd393c06d34..29932a019fdf 100644 --- a/drivers/mfd/rtsx_pcr.c +++ b/drivers/mfd/rtsx_pcr.c @@ -939,7 +939,7 @@ static void rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state) rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, pm_state); if (pcr->ops->force_power_down) - pcr->ops->force_power_down(pcr); + pcr->ops->force_power_down(pcr, pm_state); } static int rtsx_pci_init_hw(struct rtsx_pcr *pcr) diff --git a/include/linux/mfd/rtsx_pci.h b/include/linux/mfd/rtsx_pci.h index 9a16276bc080..dd0bd5806adc 100644 --- a/include/linux/mfd/rtsx_pci.h +++ b/include/linux/mfd/rtsx_pci.h @@ -779,7 +779,7 @@ struct pcr_ops { unsigned int (*cd_deglitch)(struct rtsx_pcr *pcr); int (*conv_clk_and_div_n)(int clk, int dir); void (*fetch_vendor_settings)(struct rtsx_pcr *pcr); - void (*force_power_down)(struct rtsx_pcr *pcr); + void (*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state); }; enum PDEV_STAT {PDEV_STAT_IDLE, PDEV_STAT_RUN}; -- cgit v1.2.3 From 09fd86780bb4603df1886e17127f5beb97f70ffb Mon Sep 17 00:00:00 2001 From: Wei WANG Date: Tue, 20 Aug 2013 14:18:56 +0800 Subject: mfd: rtsx: Copyright modifications Update copyright date, remove author address and add Roger Tseng. Signed-off-by: Wei WANG Signed-off-by: Samuel Ortiz --- drivers/mfd/rtl8411.c | 4 ++-- drivers/mfd/rts5209.c | 3 +-- drivers/mfd/rts5227.c | 5 +---- drivers/mfd/rts5229.c | 3 +-- drivers/mfd/rts5249.c | 1 - drivers/mfd/rtsx_pcr.c | 3 +-- drivers/mfd/rtsx_pcr.h | 3 +-- include/linux/mfd/rtsx_common.h | 3 +-- include/linux/mfd/rtsx_pci.h | 3 +-- 9 files changed, 9 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/rtl8411.c b/drivers/mfd/rtl8411.c index 37367fb1c11b..e4c1833154ea 100644 --- a/drivers/mfd/rtl8411.c +++ b/drivers/mfd/rtl8411.c @@ -1,6 +1,6 @@ /* Driver for Realtek PCI-Express card reader * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * * 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 @@ -17,7 +17,7 @@ * * Author: * Wei WANG - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China + * Roger Tseng */ #include diff --git a/drivers/mfd/rts5209.c b/drivers/mfd/rts5209.c index ef6a59fe37a4..4026e1fcb0a6 100644 --- a/drivers/mfd/rts5209.c +++ b/drivers/mfd/rts5209.c @@ -1,6 +1,6 @@ /* Driver for Realtek PCI-Express card reader * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * * 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 @@ -17,7 +17,6 @@ * * Author: * Wei WANG - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China */ #include diff --git a/drivers/mfd/rts5227.c b/drivers/mfd/rts5227.c index c72abd6b9c81..d7cae82720a4 100644 --- a/drivers/mfd/rts5227.c +++ b/drivers/mfd/rts5227.c @@ -1,6 +1,6 @@ /* Driver for Realtek PCI-Express card reader * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * * 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 @@ -17,10 +17,7 @@ * * Author: * Wei WANG - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China - * * Roger Tseng - * No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan */ #include diff --git a/drivers/mfd/rts5229.c b/drivers/mfd/rts5229.c index afb0f24bac71..620e7fa9e0df 100644 --- a/drivers/mfd/rts5229.c +++ b/drivers/mfd/rts5229.c @@ -1,6 +1,6 @@ /* Driver for Realtek PCI-Express card reader * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * * 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 @@ -17,7 +17,6 @@ * * Author: * Wei WANG - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China */ #include diff --git a/drivers/mfd/rts5249.c b/drivers/mfd/rts5249.c index 384b30b432bd..ea90f8fb92ae 100644 --- a/drivers/mfd/rts5249.c +++ b/drivers/mfd/rts5249.c @@ -17,7 +17,6 @@ * * Author: * Wei WANG - * No. 128, West Shenhu Road, Suzhou Industry Park, Suzhou, China */ #include diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c index 29932a019fdf..e6ae7720f9e1 100644 --- a/drivers/mfd/rtsx_pcr.c +++ b/drivers/mfd/rtsx_pcr.c @@ -1,6 +1,6 @@ /* Driver for Realtek PCI-Express card reader * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * * 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 @@ -17,7 +17,6 @@ * * Author: * Wei WANG - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China */ #include diff --git a/drivers/mfd/rtsx_pcr.h b/drivers/mfd/rtsx_pcr.h index 7a1b87a250a5..947e79b05ceb 100644 --- a/drivers/mfd/rtsx_pcr.h +++ b/drivers/mfd/rtsx_pcr.h @@ -1,6 +1,6 @@ /* Driver for Realtek PCI-Express card reader * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * * 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 @@ -17,7 +17,6 @@ * * Author: * Wei WANG - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China */ #ifndef __RTSX_PCR_H diff --git a/include/linux/mfd/rtsx_common.h b/include/linux/mfd/rtsx_common.h index 2b13970596f5..443176ee1ab0 100644 --- a/include/linux/mfd/rtsx_common.h +++ b/include/linux/mfd/rtsx_common.h @@ -1,6 +1,6 @@ /* Driver for Realtek driver-based card reader * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * * 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 @@ -17,7 +17,6 @@ * * Author: * Wei WANG - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China */ #ifndef __RTSX_COMMON_H diff --git a/include/linux/mfd/rtsx_pci.h b/include/linux/mfd/rtsx_pci.h index dd0bd5806adc..daefca1bafb3 100644 --- a/include/linux/mfd/rtsx_pci.h +++ b/include/linux/mfd/rtsx_pci.h @@ -1,6 +1,6 @@ /* Driver for Realtek PCI-Express card reader * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * * 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 @@ -17,7 +17,6 @@ * * Author: * Wei WANG - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China */ #ifndef __RTSX_PCI_H -- cgit v1.2.3 From 8a105ca202b1a1061a24f1e980206cd2808e2f8b Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 20 Aug 2013 16:05:29 +0900 Subject: mfd: pcf50633-adc: Use devm_*() functions Use devm_*() functions to make cleanup paths simpler. Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/pcf50633-adc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c index 18b53cb72fea..b8941a556d71 100644 --- a/drivers/mfd/pcf50633-adc.c +++ b/drivers/mfd/pcf50633-adc.c @@ -203,7 +203,7 @@ static int pcf50633_adc_probe(struct platform_device *pdev) { struct pcf50633_adc *adc; - adc = kzalloc(sizeof(*adc), GFP_KERNEL); + adc = devm_kzalloc(&pdev->dev, sizeof(*adc), GFP_KERNEL); if (!adc) return -ENOMEM; @@ -236,7 +236,6 @@ static int pcf50633_adc_remove(struct platform_device *pdev) kfree(adc->queue[i]); mutex_unlock(&adc->queue_mutex); - kfree(adc); return 0; } -- cgit v1.2.3 From 84d72f9cc21d6e41c620dd34b8248734cd02d995 Mon Sep 17 00:00:00 2001 From: Wei WANG Date: Wed, 21 Aug 2013 09:46:25 +0800 Subject: mfd: mmc: rtsx: Change default tx phase The default phase can meet most cards' requirement, but it is not the optimal one. In some extreme situation, the rx phase point produced by the following tuning process will drift quite a distance. Before tuning UHS card, this patch will set a more proper initial tx phase point, which is calculated from statistic data, and can achieve a much better tx signal quality. Signed-off-by: Wei WANG Acked-by: Lee Jones Acked-by: Chris Ball Signed-off-by: Samuel Ortiz --- drivers/mfd/rtl8411.c | 4 +++ drivers/mfd/rts5209.c | 2 ++ drivers/mfd/rts5227.c | 2 ++ drivers/mfd/rts5229.c | 2 ++ drivers/mfd/rts5249.c | 2 ++ drivers/mmc/host/rtsx_pci_sdmmc.c | 58 ++++++++++++++++++++++++++++----------- include/linux/mfd/rtsx_pci.h | 15 ++++++++++ 7 files changed, 69 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/rtl8411.c b/drivers/mfd/rtl8411.c index e4c1833154ea..52801351864d 100644 --- a/drivers/mfd/rtl8411.c +++ b/drivers/mfd/rtl8411.c @@ -452,6 +452,8 @@ void rtl8411_init_params(struct rtsx_pcr *pcr) pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B; pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D; pcr->aspm_en = ASPM_L1_EN; + pcr->tx_initial_phase = SET_CLOCK_PHASE(23, 7, 14); + pcr->rx_initial_phase = SET_CLOCK_PHASE(4, 3, 10); pcr->ic_version = rtl8411_get_ic_version(pcr); pcr->sd_pull_ctl_enable_tbl = rtl8411_sd_pull_ctl_enable_tbl; @@ -471,6 +473,8 @@ void rtl8411b_init_params(struct rtsx_pcr *pcr) pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B; pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D; pcr->aspm_en = ASPM_L1_EN; + pcr->tx_initial_phase = SET_CLOCK_PHASE(23, 7, 14); + pcr->rx_initial_phase = SET_CLOCK_PHASE(4, 3, 10); pcr->ic_version = rtl8411_get_ic_version(pcr); diff --git a/drivers/mfd/rts5209.c b/drivers/mfd/rts5209.c index 4026e1fcb0a6..cb04174a8924 100644 --- a/drivers/mfd/rts5209.c +++ b/drivers/mfd/rts5209.c @@ -270,6 +270,8 @@ void rts5209_init_params(struct rtsx_pcr *pcr) pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B; pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D; pcr->aspm_en = ASPM_L1_EN; + pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 16); + pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5); pcr->ic_version = rts5209_get_ic_version(pcr); pcr->sd_pull_ctl_enable_tbl = rts5209_sd_pull_ctl_enable_tbl; diff --git a/drivers/mfd/rts5227.c b/drivers/mfd/rts5227.c index d7cae82720a4..c001151378b2 100644 --- a/drivers/mfd/rts5227.c +++ b/drivers/mfd/rts5227.c @@ -291,6 +291,8 @@ void rts5227_init_params(struct rtsx_pcr *pcr) pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B; pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B; pcr->aspm_en = ASPM_L1_EN; + pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 15); + pcr->rx_initial_phase = SET_CLOCK_PHASE(30, 7, 7); pcr->sd_pull_ctl_enable_tbl = rts5227_sd_pull_ctl_enable_tbl; pcr->sd_pull_ctl_disable_tbl = rts5227_sd_pull_ctl_disable_tbl; diff --git a/drivers/mfd/rts5229.c b/drivers/mfd/rts5229.c index 620e7fa9e0df..6353f5df087a 100644 --- a/drivers/mfd/rts5229.c +++ b/drivers/mfd/rts5229.c @@ -261,6 +261,8 @@ void rts5229_init_params(struct rtsx_pcr *pcr) pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B; pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D; pcr->aspm_en = ASPM_L1_EN; + pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 15); + pcr->rx_initial_phase = SET_CLOCK_PHASE(30, 6, 6); pcr->ic_version = rts5229_get_ic_version(pcr); if (pcr->ic_version == IC_VER_C) { diff --git a/drivers/mfd/rts5249.c b/drivers/mfd/rts5249.c index ea90f8fb92ae..3b835f593e35 100644 --- a/drivers/mfd/rts5249.c +++ b/drivers/mfd/rts5249.c @@ -298,6 +298,8 @@ void rts5249_init_params(struct rtsx_pcr *pcr) pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_C; pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B; pcr->aspm_en = ASPM_L1_EN; + pcr->tx_initial_phase = SET_CLOCK_PHASE(1, 29, 16); + pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5); pcr->ic_version = rts5249_get_ic_version(pcr); pcr->sd_pull_ctl_enable_tbl = rts5249_sd_pull_ctl_enable_tbl; diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index 82a35b91cdbc..fcb368ef4323 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -56,7 +56,6 @@ struct realtek_pci_sdmmc { bool double_clk; bool eject; bool initial_mode; - bool ddr_mode; int power_state; #define SDMMC_POWER_ON 1 #define SDMMC_POWER_OFF 0 @@ -475,18 +474,24 @@ static void sd_normal_rw(struct realtek_pci_sdmmc *host, kfree(buf); } -static int sd_change_phase(struct realtek_pci_sdmmc *host, u8 sample_point) +static int sd_change_phase(struct realtek_pci_sdmmc *host, + u8 sample_point, bool rx) { struct rtsx_pcr *pcr = host->pcr; int err; - dev_dbg(sdmmc_dev(host), "%s: sample_point = %d\n", - __func__, sample_point); + dev_dbg(sdmmc_dev(host), "%s(%s): sample_point = %d\n", + __func__, rx ? "RX" : "TX", sample_point); rtsx_pci_init_cmd(pcr); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CHANGE_CLK, CHANGE_CLK); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPRX_CTL, 0x1F, sample_point); + if (rx) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + SD_VPRX_CTL, 0x1F, sample_point); + else + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + SD_VPTX_CTL, 0x1F, sample_point); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, PHASE_NOT_RESET); @@ -602,7 +607,7 @@ static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host, int err; u8 cmd[5] = {0}; - err = sd_change_phase(host, sample_point); + err = sd_change_phase(host, sample_point, true); if (err < 0) return err; @@ -664,7 +669,7 @@ static int sd_tuning_rx(struct realtek_pci_sdmmc *host, u8 opcode) if (final_phase == 0xFF) return -EINVAL; - err = sd_change_phase(host, final_phase); + err = sd_change_phase(host, final_phase, true); if (err < 0) return err; } else { @@ -833,14 +838,11 @@ static int sd_set_power_mode(struct realtek_pci_sdmmc *host, return err; } -static int sd_set_timing(struct realtek_pci_sdmmc *host, - unsigned char timing, bool *ddr_mode) +static int sd_set_timing(struct realtek_pci_sdmmc *host, unsigned char timing) { struct rtsx_pcr *pcr = host->pcr; int err = 0; - *ddr_mode = false; - rtsx_pci_init_cmd(pcr); switch (timing) { @@ -857,8 +859,6 @@ static int sd_set_timing(struct realtek_pci_sdmmc *host, break; case MMC_TIMING_UHS_DDR50: - *ddr_mode = true; - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, 0x0C | SD_ASYNC_FIFO_NOT_RST, SD_DDR_MODE | SD_ASYNC_FIFO_NOT_RST); @@ -926,7 +926,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) sd_set_bus_width(host, ios->bus_width); sd_set_power_mode(host, ios->power_mode); - sd_set_timing(host, ios->timing, &host->ddr_mode); + sd_set_timing(host, ios->timing); host->vpclk = false; host->double_clk = true; @@ -1148,9 +1148,35 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode) rtsx_pci_start_run(pcr); - if (!host->ddr_mode) - err = sd_tuning_rx(host, MMC_SEND_TUNING_BLOCK); + /* Set initial TX phase */ + switch (mmc->ios.timing) { + case MMC_TIMING_UHS_SDR104: + err = sd_change_phase(host, SDR104_TX_PHASE(pcr), false); + break; + + case MMC_TIMING_UHS_SDR50: + err = sd_change_phase(host, SDR50_TX_PHASE(pcr), false); + break; + + case MMC_TIMING_UHS_DDR50: + err = sd_change_phase(host, DDR50_TX_PHASE(pcr), false); + break; + + default: + err = 0; + } + if (err) + goto out; + + /* Tuning RX phase */ + if ((mmc->ios.timing == MMC_TIMING_UHS_SDR104) || + (mmc->ios.timing == MMC_TIMING_UHS_SDR50)) + err = sd_tuning_rx(host, opcode); + else if (mmc->ios.timing == MMC_TIMING_UHS_DDR50) + err = sd_change_phase(host, DDR50_RX_PHASE(pcr), true); + +out: mutex_unlock(&pcr->pcr_mutex); return err; diff --git a/include/linux/mfd/rtsx_pci.h b/include/linux/mfd/rtsx_pci.h index daefca1bafb3..d1382dfbeff0 100644 --- a/include/linux/mfd/rtsx_pci.h +++ b/include/linux/mfd/rtsx_pci.h @@ -847,6 +847,9 @@ struct rtsx_pcr { #define PCR_REVERSE_SOCKET (1 << 1) u32 flags; + u32 tx_initial_phase; + u32 rx_initial_phase; + const u32 *sd_pull_ctl_enable_tbl; const u32 *sd_pull_ctl_disable_tbl; const u32 *ms_pull_ctl_enable_tbl; @@ -863,6 +866,18 @@ struct rtsx_pcr { #define PCI_VID(pcr) ((pcr)->pci->vendor) #define PCI_PID(pcr) ((pcr)->pci->device) +#define SDR104_PHASE(val) ((val) & 0xFF) +#define SDR50_PHASE(val) (((val) >> 8) & 0xFF) +#define DDR50_PHASE(val) (((val) >> 16) & 0xFF) +#define SDR104_TX_PHASE(pcr) SDR104_PHASE((pcr)->tx_initial_phase) +#define SDR50_TX_PHASE(pcr) SDR50_PHASE((pcr)->tx_initial_phase) +#define DDR50_TX_PHASE(pcr) DDR50_PHASE((pcr)->tx_initial_phase) +#define SDR104_RX_PHASE(pcr) SDR104_PHASE((pcr)->rx_initial_phase) +#define SDR50_RX_PHASE(pcr) SDR50_PHASE((pcr)->rx_initial_phase) +#define DDR50_RX_PHASE(pcr) DDR50_PHASE((pcr)->rx_initial_phase) +#define SET_CLOCK_PHASE(sdr104, sdr50, ddr50) \ + (((ddr50) << 16) | ((sdr50) << 8) | (sdr104)) + void rtsx_pci_start_run(struct rtsx_pcr *pcr); int rtsx_pci_write_register(struct rtsx_pcr *pcr, u16 addr, u8 mask, u8 data); int rtsx_pci_read_register(struct rtsx_pcr *pcr, u16 addr, u8 *data); -- cgit v1.2.3 From 1b8055b4904fe8fc77f9d96a2407178b0ff512b6 Mon Sep 17 00:00:00 2001 From: Wei WANG Date: Wed, 21 Aug 2013 09:46:26 +0800 Subject: mmc: rtsx: Clear SD_CLK toggle enable bit if switching voltage fail If switching voltage fails, SD_CLK toggle enable bit should been cleared so that SD host can control SD clock automatically. Signed-off-by: Wei WANG Acked-by: Chris Ball Signed-off-by: Samuel Ortiz --- drivers/mmc/host/rtsx_pci_sdmmc.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index fcb368ef4323..0fefe4e84f4a 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -227,6 +227,7 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, int stat_idx = 0; u8 rsp_type; int rsp_len = 5; + bool clock_toggled = false; dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n", __func__, cmd_idx, arg); @@ -270,6 +271,8 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, 0xFF, SD_CLK_TOGGLE_EN); if (err < 0) goto out; + + clock_toggled = true; } rtsx_pci_init_cmd(pcr); @@ -350,6 +353,10 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, out: cmd->error = err; + + if (err && clock_toggled) + rtsx_pci_write_register(pcr, SD_BUS_STAT, + SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); } static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq) @@ -1121,11 +1128,11 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) goto out; } +out: /* Stop toggle SD clock in idle */ err = rtsx_pci_write_register(pcr, SD_BUS_STAT, SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); -out: mutex_unlock(&pcr->pcr_mutex); return err; -- cgit v1.2.3 From 62282180645a94f8686680bca464afd418511510 Mon Sep 17 00:00:00 2001 From: Wei WANG Date: Wed, 21 Aug 2013 09:46:27 +0800 Subject: mmc: memstick: rtsx: Modify copyright comments Update copyright date, and remove author address. Signed-off-by: Wei WANG Acked-by: Chris Ball Signed-off-by: Samuel Ortiz --- drivers/memstick/host/rtsx_pci_ms.c | 3 +-- drivers/mmc/host/rtsx_pci_sdmmc.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/memstick/host/rtsx_pci_ms.c b/drivers/memstick/host/rtsx_pci_ms.c index 64a779c58a74..cf8bd727dfc7 100644 --- a/drivers/memstick/host/rtsx_pci_ms.c +++ b/drivers/memstick/host/rtsx_pci_ms.c @@ -1,6 +1,6 @@ /* Realtek PCI-Express Memstick Card Interface driver * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * * 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 @@ -17,7 +17,6 @@ * * Author: * Wei WANG - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China */ #include diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index 0fefe4e84f4a..375a880e0c5f 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -1,6 +1,6 @@ /* Realtek PCI-Express SD/MMC Card Interface driver * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * * 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 @@ -17,7 +17,6 @@ * * Author: * Wei WANG - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China */ #include -- cgit v1.2.3 From 6a017660768f8aca6ebf513cfb0c7ac241547deb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 31 Aug 2013 14:08:55 +0100 Subject: mfd: davinci_voicecodec: Remove unused read and write functions These functions are not referenced anywhere, nor prototyped, so just remove them. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/davinci_voicecodec.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c index fb64398506e9..a292d71c397c 100644 --- a/drivers/mfd/davinci_voicecodec.c +++ b/drivers/mfd/davinci_voicecodec.c @@ -32,17 +32,6 @@ #include -u32 davinci_vc_read(struct davinci_vc *davinci_vc, int reg) -{ - return __raw_readl(davinci_vc->base + reg); -} - -void davinci_vc_write(struct davinci_vc *davinci_vc, - int reg, u32 val) -{ - __raw_writel(val, davinci_vc->base + reg); -} - static int __init davinci_vc_probe(struct platform_device *pdev) { struct davinci_vc *davinci_vc; -- cgit v1.2.3 From 921a2c870faa0a88c34e5c8c2afbd898fe8d325d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 31 Aug 2013 14:08:56 +0100 Subject: mfd: davinci_voicecodec: Provide a regmap for register I/O This will be used to support refactoring of the ASoC CODEC driver to use a regmap. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/davinci_voicecodec.c | 14 ++++++++++++++ include/linux/mfd/davinci_voicecodec.h | 3 +++ 2 files changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c index a292d71c397c..013ba8159dcd 100644 --- a/drivers/mfd/davinci_voicecodec.c +++ b/drivers/mfd/davinci_voicecodec.c @@ -27,11 +27,17 @@ #include #include #include +#include #include #include +static struct regmap_config davinci_vc_regmap = { + .reg_bits = 32, + .val_bits = 32, +}; + static int __init davinci_vc_probe(struct platform_device *pdev) { struct davinci_vc *davinci_vc; @@ -63,6 +69,14 @@ static int __init davinci_vc_probe(struct platform_device *pdev) goto fail; } + davinci_vc->regmap = devm_regmap_init_mmio(&pdev->dev, + davinci_vc->base, + &davinci_vc_regmap); + if (IS_ERR(davinci_vc->regmap)) { + ret = PTR_ERR(davinci_vc->regmap); + goto fail; + } + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!res) { dev_err(&pdev->dev, "no DMA resource\n"); diff --git a/include/linux/mfd/davinci_voicecodec.h b/include/linux/mfd/davinci_voicecodec.h index 13a1ee95a233..5166935ce66d 100644 --- a/include/linux/mfd/davinci_voicecodec.h +++ b/include/linux/mfd/davinci_voicecodec.h @@ -30,6 +30,8 @@ #include +struct regmap; + /* * Register values. */ @@ -113,6 +115,7 @@ struct davinci_vc { /* Memory resources */ void __iomem *base; + struct regmap *regmap; /* MFD cells */ struct mfd_cell cells[DAVINCI_VC_CELLS]; -- cgit v1.2.3 From c6f39257c952bc7da974bf93255936ff2ece2c34 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 31 Aug 2013 17:48:19 +0100 Subject: mfd: twl6040: Use regmap for register cache Rather then open coding a cache of the vibra control registers use the regmap cache code. Also cache the interrupt mask register, providing a small performance improvement for the interrupt code. Signed-off-by: Mark Brown Acked-by: Peter Ujfalusi Signed-off-by: Samuel Ortiz --- drivers/mfd/twl6040.c | 43 ++++++++++++++++++++++++++++++------------- include/linux/mfd/twl6040.h | 1 - 2 files changed, 30 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index 492ee2cd3400..c7df66a208d4 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -63,15 +63,9 @@ int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg) int ret; unsigned int val; - /* Vibra control registers from cache */ - if (unlikely(reg == TWL6040_REG_VIBCTLL || - reg == TWL6040_REG_VIBCTLR)) { - val = twl6040->vibra_ctrl_cache[VIBRACTRL_MEMBER(reg)]; - } else { - ret = regmap_read(twl6040->regmap, reg, &val); - if (ret < 0) - return ret; - } + ret = regmap_read(twl6040->regmap, reg, &val); + if (ret < 0) + return ret; return val; } @@ -82,9 +76,6 @@ int twl6040_reg_write(struct twl6040 *twl6040, unsigned int reg, u8 val) int ret; ret = regmap_write(twl6040->regmap, reg, val); - /* Cache the vibra control registers */ - if (reg == TWL6040_REG_VIBCTLL || reg == TWL6040_REG_VIBCTLR) - twl6040->vibra_ctrl_cache[VIBRACTRL_MEMBER(reg)] = val; return ret; } @@ -461,9 +452,20 @@ EXPORT_SYMBOL(twl6040_get_sysclk); /* Get the combined status of the vibra control register */ int twl6040_get_vibralr_status(struct twl6040 *twl6040) { + unsigned int reg; + int ret; u8 status; - status = twl6040->vibra_ctrl_cache[0] | twl6040->vibra_ctrl_cache[1]; + ret = regmap_read(twl6040->regmap, TWL6040_REG_VIBCTLL, ®); + if (ret != 0) + return ret; + status = reg; + + ret = regmap_read(twl6040->regmap, TWL6040_REG_VIBCTLR, ®); + if (ret != 0) + return ret; + status |= reg; + status &= (TWL6040_VIBENA | TWL6040_VIBSEL); return status; @@ -490,12 +492,27 @@ static bool twl6040_readable_reg(struct device *dev, unsigned int reg) return true; } +static bool twl6040_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TWL6040_REG_VIBCTLL: + case TWL6040_REG_VIBCTLR: + case TWL6040_REG_INTMR: + return false; + default: + return true; + } +} + static struct regmap_config twl6040_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = TWL6040_REG_STATUS, /* 0x2e */ .readable_reg = twl6040_readable_reg, + .volatile_reg = twl6040_volatile_reg, + + .cache_type = REGCACHE_RBTREE, }; static const struct regmap_irq twl6040_irqs[] = { diff --git a/include/linux/mfd/twl6040.h b/include/linux/mfd/twl6040.h index 7e7fbce7a308..2b7d26573431 100644 --- a/include/linux/mfd/twl6040.h +++ b/include/linux/mfd/twl6040.h @@ -229,7 +229,6 @@ struct twl6040 { int audpwron; int power_count; int rev; - u8 vibra_ctrl_cache[2]; /* PLL configuration */ int pll; -- cgit v1.2.3 From b432fc25b5b0311a58772fefe8d07e143600e908 Mon Sep 17 00:00:00 2001 From: Chao Xie Date: Sun, 18 Aug 2013 21:27:54 -0400 Subject: mfd: 88pm800: Fix potential NULL pdata dereference User pass platform data to device, and platform data may be NULL. Add the check for pdata. Signed-off-by: Chao Xie Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm800.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c index cd9e17471232..a65447d65605 100644 --- a/drivers/mfd/88pm800.c +++ b/drivers/mfd/88pm800.c @@ -333,9 +333,11 @@ static int device_rtc_init(struct pm80x_chip *chip, { int ret; - rtc_devs[0].platform_data = pdata->rtc; - rtc_devs[0].pdata_size = - pdata->rtc ? sizeof(struct pm80x_rtc_pdata) : 0; + if (pdata) { + rtc_devs[0].platform_data = pdata->rtc; + rtc_devs[0].pdata_size = + pdata->rtc ? sizeof(struct pm80x_rtc_pdata) : 0; + } ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0], ARRAY_SIZE(rtc_devs), NULL, 0, NULL); if (ret) { @@ -578,7 +580,7 @@ static int pm800_probe(struct i2c_client *client, goto err_device_init; } - if (pdata->plat_config) + if (pdata && pdata->plat_config) pdata->plat_config(chip, pdata); return 0; -- cgit v1.2.3 From 2b274fe522e9d5ac7397e07e3516bb10e3c2ee92 Mon Sep 17 00:00:00 2001 From: Chao Xie Date: Sun, 18 Aug 2013 21:27:55 -0400 Subject: mfd: 88pm805: Fix potential NULL pdata dereference User pass platform data to device, and platform data may be NULL. Add the check for pdata. Signed-off-by: Chao Xie Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm805.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm805.c b/drivers/mfd/88pm805.c index 0686cdb06b3e..8a5b6ffb5afb 100644 --- a/drivers/mfd/88pm805.c +++ b/drivers/mfd/88pm805.c @@ -243,7 +243,7 @@ static int pm805_probe(struct i2c_client *client, goto err_805_init; } - if (pdata->plat_config) + if (pdata && pdata->plat_config) pdata->plat_config(chip, pdata); err_805_init: -- cgit v1.2.3 From 7844b989b39cb1fdf21b74cd9b69fd0953b9f28d Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 23 Aug 2013 16:42:58 +0530 Subject: mfd: omap-usb-host: Staticize usbhs_driver_name usbhs_driver_name is used only in this file. Make it static. Signed-off-by: Sachin Kamat Signed-off-by: Lee Jones --- drivers/mfd/omap-usb-host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index d2b8e7189907..29ee54d68512 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -114,7 +114,7 @@ struct usbhs_hcd_omap { }; /*-------------------------------------------------------------------------*/ -const char usbhs_driver_name[] = USBHS_DRIVER_NAME; +static const char usbhs_driver_name[] = USBHS_DRIVER_NAME; static u64 usbhs_dmamask = DMA_BIT_MASK(32); /*-------------------------------------------------------------------------*/ -- cgit v1.2.3 From ffb011602d263ca57c05125c3b9ef476673e88f7 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 23 Aug 2013 17:05:19 +0530 Subject: mfd: db8500-prcmu: Use ANSI function declaration Silences the following warning: drivers/mfd/db8500-prcmu.c:2322:25: warning: non-ANSI function declaration of function 'prcmu_ac_sleep_req' Acked-by: Linus Walleij Signed-off-by: Sachin Kamat Signed-off-by: Lee Jones --- drivers/mfd/db8500-prcmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 3c157faee645..961036e51212 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -2319,7 +2319,7 @@ unlock_and_return: /** * prcmu_ac_sleep_req - called when ARM no longer needs to talk to modem */ -void prcmu_ac_sleep_req() +void prcmu_ac_sleep_req(void) { u32 val; -- cgit v1.2.3 From 6746f2321c93f570386345c47c3aa262d17787c2 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 23 Aug 2013 17:05:20 +0530 Subject: mfd: db8500-prcmu: Staticize clk_mgt clk_mgt is used only in this file. Make it static. Acked-by: Linus Walleij Signed-off-by: Sachin Kamat Signed-off-by: Lee Jones --- drivers/mfd/db8500-prcmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 961036e51212..f7460383d4be 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -465,7 +465,7 @@ static DEFINE_SPINLOCK(clk_mgt_lock); #define CLK_MGT_ENTRY(_name, _branch, _clk38div)[PRCMU_##_name] = \ { (PRCM_##_name##_MGT), 0 , _branch, _clk38div} -struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = { +static struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = { CLK_MGT_ENTRY(SGACLK, PLL_DIV, false), CLK_MGT_ENTRY(UARTCLK, PLL_FIX, true), CLK_MGT_ENTRY(MSP02CLK, PLL_FIX, true), -- cgit v1.2.3 From 8455eaee41e78e9996c25c888cda9c6b597228b7 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 23 Aug 2013 17:37:42 +0530 Subject: mfd: ab8500-debugfs: Staticize local variables Local variables referenced only in this file are made static. Acked-by: Linus Walleij Signed-off-by: Sachin Kamat Signed-off-by: Lee Jones --- drivers/mfd/ab8500-debugfs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index 7d1f1b08fc4b..a0afa64b471b 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -159,7 +159,7 @@ static struct hwreg_cfg hwreg_cfg = { static struct ab8500_prcmu_ranges *debug_ranges; -struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = { +static struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = { [0x0] = { .num_ranges = 0, .range = NULL, @@ -488,7 +488,7 @@ struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = { }, }; -struct ab8500_prcmu_ranges ab8505_debug_ranges[AB8500_NUM_BANKS] = { +static struct ab8500_prcmu_ranges ab8505_debug_ranges[AB8500_NUM_BANKS] = { [0x0] = { .num_ranges = 0, .range = NULL, @@ -847,7 +847,7 @@ struct ab8500_prcmu_ranges ab8505_debug_ranges[AB8500_NUM_BANKS] = { }, }; -struct ab8500_prcmu_ranges ab8540_debug_ranges[AB8500_NUM_BANKS] = { +static struct ab8500_prcmu_ranges ab8540_debug_ranges[AB8500_NUM_BANKS] = { [AB8500_M_FSM_RANK] = { .num_ranges = 1, .range = (struct ab8500_reg_range[]) { @@ -1377,7 +1377,7 @@ void ab8500_dump_all_banks(struct device *dev) /* Space for 500 registers. */ #define DUMP_MAX_REGS 700 -struct ab8500_register_dump +static struct ab8500_register_dump { u8 bank; u8 reg; -- cgit v1.2.3 From 4eaf415762672e4becc30e637028de9d3aae07bf Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 23 Aug 2013 15:41:03 +0530 Subject: mfd: timberdale: Staticize local variables Local variables referenced only in this file are made static. Acked-by: Linus Walleij Signed-off-by: Sachin Kamat Signed-off-by: Lee Jones --- drivers/mfd/timberdale.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c index 0c1fcbc23d04..4c9c149f2be8 100644 --- a/drivers/mfd/timberdale.c +++ b/drivers/mfd/timberdale.c @@ -115,11 +115,11 @@ static const struct resource timberdale_ocores_resources[] = { }, }; -const struct max7301_platform_data timberdale_max7301_platform_data = { +static const struct max7301_platform_data timberdale_max7301_platform_data = { .base = 200 }; -const struct mc33880_platform_data timberdale_mc33880_platform_data = { +static const struct mc33880_platform_data timberdale_mc33880_platform_data = { .base = 100 }; -- cgit v1.2.3 From 624362676c1860874737dbd4db5fcee05d585722 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 23 Aug 2013 15:41:04 +0530 Subject: mfd: timberdale: Remove redundant break break after goto is unreachable. Delete it. Signed-off-by: Sachin Kamat Signed-off-by: Lee Jones --- drivers/mfd/timberdale.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c index 4c9c149f2be8..57dd89ddb683 100644 --- a/drivers/mfd/timberdale.c +++ b/drivers/mfd/timberdale.c @@ -781,7 +781,6 @@ static int timb_probe(struct pci_dev *dev, priv->fw.major, priv->fw.minor, ip_setup); err = -ENODEV; goto err_mfd; - break; } if (err) { -- cgit v1.2.3 From 0afb00e38bb220d198fd7778902d82e944e821a4 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 23 Aug 2013 15:41:05 +0530 Subject: mfd: timberdale: Use module_pci_driver module_pci_driver removes some boilerplate and makes the code simple. Signed-off-by: Sachin Kamat Signed-off-by: Lee Jones --- drivers/mfd/timberdale.c | 29 +---------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c index 57dd89ddb683..a6755ec7bd6a 100644 --- a/drivers/mfd/timberdale.c +++ b/drivers/mfd/timberdale.c @@ -868,34 +868,7 @@ static struct pci_driver timberdale_pci_driver = { .remove = timb_remove, }; -static int __init timberdale_init(void) -{ - int err; - - err = pci_register_driver(&timberdale_pci_driver); - if (err < 0) { - printk(KERN_ERR - "Failed to register PCI driver for %s device.\n", - timberdale_pci_driver.name); - return -ENODEV; - } - - printk(KERN_INFO "Driver for %s has been successfully registered.\n", - timberdale_pci_driver.name); - - return 0; -} - -static void __exit timberdale_exit(void) -{ - pci_unregister_driver(&timberdale_pci_driver); - - printk(KERN_INFO "Driver for %s has been successfully unregistered.\n", - timberdale_pci_driver.name); -} - -module_init(timberdale_init); -module_exit(timberdale_exit); +module_pci_driver(timberdale_pci_driver); MODULE_AUTHOR("Mocean Laboratories "); MODULE_VERSION(DRV_VERSION); -- cgit v1.2.3 From f840e23bcf16068eeffe8991ac38b58b82160e43 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 19 Jul 2013 08:44:50 +0100 Subject: mfd: ab8500-debugfs: Apply a check for -ENOMEM after allocating memory for sysfs The AB8500 debugfs driver allocates memory for a new sysfs entry, but fails to apply the proper post-allocation checks. If the device were to run out of memory, the allocation would return NULL. Without the correct checks the driver will continue to populate NULL->[show|store|...], which would obviously cause a pointer dereference Oops. Signed-off-by: Lee Jones --- drivers/mfd/ab8500-debugfs.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index a0afa64b471b..fe8189c4385a 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -2800,6 +2800,9 @@ static ssize_t ab8500_subscribe_write(struct file *file, */ dev_attr[irq_index] = kmalloc(sizeof(struct device_attribute), GFP_KERNEL); + if (!dev_attr[irq_index]) + return -ENOMEM; + event_name[irq_index] = kmalloc(count, GFP_KERNEL); sprintf(event_name[irq_index], "%lu", user_val); dev_attr[irq_index]->show = show_irq; -- cgit v1.2.3 From d551c4c43ccac3ef272e10ac23a64eaac16c23fd Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 19 Jul 2013 08:53:24 +0100 Subject: mfd: ab8500-debugfs: Apply a check for -ENOMEM after allocating memory for event name The AB8500 debugfs driver allocates memory to contain the name of a new sysfs entry, but fails to apply the proper post-allocation checks. If the device were to run out of memory, the allocation would return NULL. Without the correct checks the driver will continue to populate address NULL with the specified device name which would obviously cause a pointer dereference Oops. Signed-off-by: Lee Jones --- drivers/mfd/ab8500-debugfs.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index fe8189c4385a..e33e385af0a2 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -2804,6 +2804,9 @@ static ssize_t ab8500_subscribe_write(struct file *file, return -ENOMEM; event_name[irq_index] = kmalloc(count, GFP_KERNEL); + if (!event_name[irq_index]) + return -ENOMEM; + sprintf(event_name[irq_index], "%lu", user_val); dev_attr[irq_index]->show = show_irq; dev_attr[irq_index]->store = NULL; -- cgit v1.2.3 From 02a0bf6e351de6bcda4ddeeb2af34197a4e6d591 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 19 Jul 2013 14:19:58 +0100 Subject: mfd: ucb1x00-core: Rewrite ucb1x00_add_dev() Error handling is on-its-head in this function. After invoking a function we should examine the return code and return the error value if there was one. Instead, this function checks for success and goes onto provide functionality if success was received. Not so bad in a simple function like this, but in a more complex one this could end up drowning in curly brackets. Signed-off-by: Lee Jones --- drivers/mfd/ucb1x00-core.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index b7cf98f75e7c..d5966e6b5a7d 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c @@ -393,22 +393,24 @@ static struct irq_chip ucb1x00_irqchip = { static int ucb1x00_add_dev(struct ucb1x00 *ucb, struct ucb1x00_driver *drv) { struct ucb1x00_dev *dev; - int ret = -ENOMEM; + int ret; dev = kmalloc(sizeof(struct ucb1x00_dev), GFP_KERNEL); - if (dev) { - dev->ucb = ucb; - dev->drv = drv; - - ret = drv->add(dev); - - if (ret == 0) { - list_add_tail(&dev->dev_node, &ucb->devs); - list_add_tail(&dev->drv_node, &drv->devs); - } else { - kfree(dev); - } + if (!dev) + return -ENOMEM; + + dev->ucb = ucb; + dev->drv = drv; + + ret = drv->add(dev); + if (ret) { + kfree(dev); + return ret; } + + list_add_tail(&dev->dev_node, &ucb->devs); + list_add_tail(&dev->drv_node, &drv->devs); + return ret; } -- cgit v1.2.3