From 817bb7fbfb0a1ad5f9d475cef0752d4ec5fdeac2 Mon Sep 17 00:00:00 2001 From: AnilKumar Ch Date: Mon, 13 Aug 2012 20:36:05 +0530 Subject: mfd: Move tps65217 regulator plat data handling to regulator Regulator platform data handling was mistakenly added to MFD driver. So we will see build errors if we compile MFD drivers without CONFIG_REGULATOR. This patch moves regulator platform data handling from TPS65217 MFD driver to regulator driver. This makes MFD driver independent of REGULATOR framework so build error is fixed if CONFIG_REGULATOR is not set. drivers/built-in.o: In function `tps65217_probe': tps65217.c:(.devinit.text+0x13e37): undefined reference to `of_regulator_match' This patch also fix allocation size of tps65217 platform data. Current implementation allocates a struct tps65217_board for each regulator specified in the device tree. But the structure itself provides array of regulators so one instance of it is sufficient. Signed-off-by: AnilKumar Ch --- drivers/mfd/tps65217.c | 130 +++++++++++---------------------- drivers/regulator/tps65217-regulator.c | 124 +++++++++++++++++++++++++++---- 2 files changed, 152 insertions(+), 102 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index 61c097a98f5d..3bc274409b58 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -24,11 +24,18 @@ #include #include #include -#include +#include +#include #include #include +static struct mfd_cell tps65217s[] = { + { + .name = "tps65217-pmic", + }, +}; + /** * tps65217_reg_read: Read a single tps65217 register. * @@ -133,83 +140,48 @@ int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg, } EXPORT_SYMBOL_GPL(tps65217_clear_bits); -#ifdef CONFIG_OF -static struct of_regulator_match reg_matches[] = { - { .name = "dcdc1", .driver_data = (void *)TPS65217_DCDC_1 }, - { .name = "dcdc2", .driver_data = (void *)TPS65217_DCDC_2 }, - { .name = "dcdc3", .driver_data = (void *)TPS65217_DCDC_3 }, - { .name = "ldo1", .driver_data = (void *)TPS65217_LDO_1 }, - { .name = "ldo2", .driver_data = (void *)TPS65217_LDO_2 }, - { .name = "ldo3", .driver_data = (void *)TPS65217_LDO_3 }, - { .name = "ldo4", .driver_data = (void *)TPS65217_LDO_4 }, -}; - -static struct tps65217_board *tps65217_parse_dt(struct i2c_client *client) -{ - struct device_node *node = client->dev.of_node; - struct tps65217_board *pdata; - struct device_node *regs; - int count = ARRAY_SIZE(reg_matches); - int ret, i; - - regs = of_find_node_by_name(node, "regulators"); - if (!regs) - return NULL; - - ret = of_regulator_match(&client->dev, regs, reg_matches, count); - of_node_put(regs); - if ((ret < 0) || (ret > count)) - return NULL; - - count = ret; - pdata = devm_kzalloc(&client->dev, count * sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return NULL; - - for (i = 0; i < count; i++) { - if (!reg_matches[i].init_data || !reg_matches[i].of_node) - continue; - - pdata->tps65217_init_data[i] = reg_matches[i].init_data; - pdata->of_node[i] = reg_matches[i].of_node; - } - - return pdata; -} - -static struct of_device_id tps65217_of_match[] = { - { .compatible = "ti,tps65217", }, - { }, -}; -#else -static struct tps65217_board *tps65217_parse_dt(struct i2c_client *client) -{ - return NULL; -} -#endif - static struct regmap_config tps65217_regmap_config = { .reg_bits = 8, .val_bits = 8, }; +static const struct of_device_id tps65217_of_match[] = { + { .compatible = "ti,tps65217", .data = (void *)TPS65217 }, + { /* sentinel */ }, +}; + static int __devinit tps65217_probe(struct i2c_client *client, const struct i2c_device_id *ids) { struct tps65217 *tps; - struct regulator_init_data *reg_data; - struct tps65217_board *pdata = client->dev.platform_data; - int i, ret; unsigned int version; + unsigned int chip_id = ids->driver_data; + const struct of_device_id *match; + int ret; - if (!pdata && client->dev.of_node) - pdata = tps65217_parse_dt(client); + if (client->dev.of_node) { + match = of_match_device(tps65217_of_match, &client->dev); + if (!match) { + dev_err(&client->dev, + "Failed to find matching dt id\n"); + return -EINVAL; + } + chip_id = (unsigned int)match->data; + } + + if (!chip_id) { + dev_err(&client->dev, "id is null.\n"); + return -ENODEV; + } tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); if (!tps) return -ENOMEM; - tps->pdata = pdata; + i2c_set_clientdata(client, tps); + tps->dev = &client->dev; + tps->id = chip_id; + tps->regmap = devm_regmap_init_i2c(client, &tps65217_regmap_config); if (IS_ERR(tps->regmap)) { ret = PTR_ERR(tps->regmap); @@ -218,8 +190,12 @@ static int __devinit tps65217_probe(struct i2c_client *client, return ret; } - i2c_set_clientdata(client, tps); - tps->dev = &client->dev; + ret = mfd_add_devices(tps->dev, -1, tps65217s, + ARRAY_SIZE(tps65217s), NULL, 0); + if (ret < 0) { + dev_err(tps->dev, "mfd_add_devices failed: %d\n", ret); + return ret; + } ret = tps65217_reg_read(tps, TPS65217_REG_CHIPID, &version); if (ret < 0) { @@ -232,41 +208,21 @@ static int __devinit tps65217_probe(struct i2c_client *client, (version & TPS65217_CHIPID_CHIP_MASK) >> 4, version & TPS65217_CHIPID_REV_MASK); - for (i = 0; i < TPS65217_NUM_REGULATOR; i++) { - struct platform_device *pdev; - - pdev = platform_device_alloc("tps65217-pmic", i); - if (!pdev) { - dev_err(tps->dev, "Cannot create regulator %d\n", i); - continue; - } - - pdev->dev.parent = tps->dev; - pdev->dev.of_node = pdata->of_node[i]; - reg_data = pdata->tps65217_init_data[i]; - platform_device_add_data(pdev, reg_data, sizeof(*reg_data)); - tps->regulator_pdev[i] = pdev; - - platform_device_add(pdev); - } - return 0; } static int __devexit tps65217_remove(struct i2c_client *client) { struct tps65217 *tps = i2c_get_clientdata(client); - int i; - for (i = 0; i < TPS65217_NUM_REGULATOR; i++) - platform_device_unregister(tps->regulator_pdev[i]); + mfd_remove_devices(tps->dev); return 0; } static const struct i2c_device_id tps65217_id_table[] = { - {"tps65217", 0xF0}, - {/* end of list */} + {"tps65217", TPS65217}, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(i2c, tps65217_id_table); diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index 6caa222af77a..ab00cab905b7 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -281,37 +282,130 @@ static const struct regulator_desc regulators[] = { NULL), }; +#ifdef CONFIG_OF +static struct of_regulator_match reg_matches[] = { + { .name = "dcdc1", .driver_data = (void *)TPS65217_DCDC_1 }, + { .name = "dcdc2", .driver_data = (void *)TPS65217_DCDC_2 }, + { .name = "dcdc3", .driver_data = (void *)TPS65217_DCDC_3 }, + { .name = "ldo1", .driver_data = (void *)TPS65217_LDO_1 }, + { .name = "ldo2", .driver_data = (void *)TPS65217_LDO_2 }, + { .name = "ldo3", .driver_data = (void *)TPS65217_LDO_3 }, + { .name = "ldo4", .driver_data = (void *)TPS65217_LDO_4 }, +}; + +static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev) +{ + struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); + struct device_node *node = tps->dev->of_node; + struct tps65217_board *pdata; + struct device_node *regs; + int i, count; + + regs = of_find_node_by_name(node, "regulators"); + if (!regs) + return NULL; + + count = of_regulator_match(pdev->dev.parent, regs, + reg_matches, TPS65217_NUM_REGULATOR); + of_node_put(regs); + if ((count < 0) || (count > TPS65217_NUM_REGULATOR)) + return NULL; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + for (i = 0; i < count; i++) { + if (!reg_matches[i].init_data || !reg_matches[i].of_node) + continue; + + pdata->tps65217_init_data[i] = reg_matches[i].init_data; + pdata->of_node[i] = reg_matches[i].of_node; + } + + return pdata; +} +#else +static struct tps65217_board *tps65217_parse_dt(struct platform_device *pdev) +{ + return NULL; +} +#endif + static int __devinit tps65217_regulator_probe(struct platform_device *pdev) { + struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); + struct tps65217_board *pdata = dev_get_platdata(tps->dev); + struct regulator_init_data *reg_data; struct regulator_dev *rdev; - struct tps65217 *tps; - struct tps_info *info = &tps65217_pmic_regs[pdev->id]; struct regulator_config config = { }; + int i, ret; - /* Already set by core driver */ - tps = dev_to_tps65217(pdev->dev.parent); - tps->info[pdev->id] = info; + if (tps->dev->of_node) + pdata = tps65217_parse_dt(pdev); - config.dev = &pdev->dev; - config.of_node = pdev->dev.of_node; - config.init_data = pdev->dev.platform_data; - config.driver_data = tps; + if (!pdata) { + dev_err(&pdev->dev, "Platform data not found\n"); + return -EINVAL; + } - rdev = regulator_register(®ulators[pdev->id], &config); - if (IS_ERR(rdev)) - return PTR_ERR(rdev); + if (tps65217_chip_id(tps) != TPS65217) { + dev_err(&pdev->dev, "Invalid tps chip version\n"); + return -ENODEV; + } - platform_set_drvdata(pdev, rdev); + platform_set_drvdata(pdev, tps); + for (i = 0; i < TPS65217_NUM_REGULATOR; i++) { + + reg_data = pdata->tps65217_init_data[i]; + + /* + * Regulator API handles empty constraints but not NULL + * constraints + */ + if (!reg_data) + continue; + + /* Register the regulators */ + tps->info[i] = &tps65217_pmic_regs[i]; + + config.dev = tps->dev; + config.init_data = reg_data; + config.driver_data = tps; + config.regmap = tps->regmap; + if (tps->dev->of_node) + config.of_node = pdata->of_node[i]; + + rdev = regulator_register(®ulators[i], &config); + if (IS_ERR(rdev)) { + dev_err(tps->dev, "failed to register %s regulator\n", + pdev->name); + ret = PTR_ERR(rdev); + goto err_unregister_regulator; + } + + /* Save regulator for cleanup */ + tps->rdev[i] = rdev; + } return 0; + +err_unregister_regulator: + while (--i >= 0) + regulator_unregister(tps->rdev[i]); + + return ret; } static int __devexit tps65217_regulator_remove(struct platform_device *pdev) { - struct regulator_dev *rdev = platform_get_drvdata(pdev); + struct tps65217 *tps = platform_get_drvdata(pdev); + unsigned int i; + + for (i = 0; i < TPS65217_NUM_REGULATOR; i++) + regulator_unregister(tps->rdev[i]); platform_set_drvdata(pdev, NULL); - regulator_unregister(rdev); return 0; } -- cgit v1.2.2 From 092369efbd6ef6b4a215741ce9f65446bf45beff Mon Sep 17 00:00:00 2001 From: Feng Tang Date: Thu, 16 Aug 2012 15:50:10 +0800 Subject: mfd: lpc_ich: Fix a 3.5 kernel regression for iTCO_wdt driver There are many reports (including 2 of my machines) that iTCO_wdt watchdog driver fails to be initialized in 3.5 kernel with error message like: [ 5.265175] ACPI Warning: 0x00001060-0x0000107f SystemIO conflicts with Region \_SB_.PCI0.LPCB.TCOI 1 (20120320/utaddress-251) [ 5.265192] ACPI: If an ACPI driver is available for this device, you should use it instead of the native driver [ 5.265206] lpc_ich: Resource conflict(s) found affecting iTCO_wdt The root cause the iTCO_wdt driver in 3.4 probes the HW IO resource from LPC's PCI config space, while in 3.5 kernel it relies on lpc_ich driver for the probe, which adds a new acpi_check_resource_conflict() check, and give up the probe if there is any conflict with ACPI. Fix it by removing all the checks for iTCO_wdt to keep the same behavior as 3.4 kernel. https://bugzilla.kernel.org/show_bug.cgi?id=44991 Actually the same check could be removed for the gpio-ich in lpc_ich.c, but I'm not sure if it will cause problems. Signed-off-by: Feng Tang Cc: Aaron Sierra Cc: Wim Van Sebroeck Cc: Len Brown Cc: Bob Moore Signed-off-by: Samuel Ortiz --- drivers/mfd/lpc_ich.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 027cc8f86132..a05fdfc2ebcf 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -765,7 +765,6 @@ static int __devinit lpc_ich_init_wdt(struct pci_dev *dev, u32 base_addr_cfg; u32 base_addr; int ret; - bool acpi_conflict = false; struct resource *res; /* Setup power management base register */ @@ -780,20 +779,11 @@ static int __devinit lpc_ich_init_wdt(struct pci_dev *dev, res = wdt_io_res(ICH_RES_IO_TCO); res->start = base_addr + ACPIBASE_TCO_OFF; res->end = base_addr + ACPIBASE_TCO_END; - ret = acpi_check_resource_conflict(res); - if (ret) { - acpi_conflict = true; - goto wdt_done; - } res = wdt_io_res(ICH_RES_IO_SMI); res->start = base_addr + ACPIBASE_SMI_OFF; res->end = base_addr + ACPIBASE_SMI_END; - ret = acpi_check_resource_conflict(res); - if (ret) { - acpi_conflict = true; - goto wdt_done; - } + lpc_ich_enable_acpi_space(dev); /* @@ -813,11 +803,6 @@ static int __devinit lpc_ich_init_wdt(struct pci_dev *dev, res = wdt_mem_res(ICH_RES_MEM_GCS); res->start = base_addr + ACPIBASE_GCS_OFF; res->end = base_addr + ACPIBASE_GCS_END; - ret = acpi_check_resource_conflict(res); - if (ret) { - acpi_conflict = true; - goto wdt_done; - } } lpc_ich_finalize_cell(&lpc_ich_cells[LPC_WDT], id); @@ -825,9 +810,6 @@ static int __devinit lpc_ich_init_wdt(struct pci_dev *dev, 1, NULL, 0); wdt_done: - if (acpi_conflict) - pr_warn("Resource conflict(s) found affecting %s\n", - lpc_ich_cells[LPC_WDT].name); return ret; } -- cgit v1.2.2 From bee6e1fa617b1fb7f6f91033428410e05f5ab0ed Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 7 Aug 2012 19:42:43 +0100 Subject: mfd: max8925: Move _IO resources out of ioport_ioresource The removal of mach/io.h from most ARM platforms also set the range of valid IO ports to be empty for most platforms when previously any 32 bit integer had been valid. This makes it impossible to add IO resources as the added range is smaller than that of the root resource for IO ports. Since we're not really using IO memory at all fix this by defining our own root resource outside the normal tree and make that the parent of all IO resources. This also ensures we won't conflict with read IO ports if we ever run on a platform which happens to use them. Signed-off-by: Mark Brown Acked-by: Haojian Zhuang Tested-by: Haojian Zhuang Cc: stable@vger.kernel.org (v3.4+) Signed-off-by: Samuel Ortiz --- drivers/mfd/max8925-core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index 825a7f06d9ba..6aa3a22ea435 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -18,12 +18,19 @@ #include #include +static struct resource io_parent = { + .start = 0, + .end = 0xffffffff, + .flags = IORESOURCE_IO, +}; + static struct resource backlight_resources[] = { { .name = "max8925-backlight", .start = MAX8925_WLED_MODE_CNTL, .end = MAX8925_WLED_CNTL, .flags = IORESOURCE_IO, + .parent = &io_parent, }, }; @@ -42,6 +49,7 @@ static struct resource touch_resources[] = { .start = MAX8925_TSC_IRQ, .end = MAX8925_ADC_RES_END, .flags = IORESOURCE_IO, + .parent = &io_parent, }, }; @@ -60,6 +68,7 @@ static struct resource power_supply_resources[] = { .start = MAX8925_CHG_IRQ1, .end = MAX8925_CHG_IRQ1_MASK, .flags = IORESOURCE_IO, + .parent = &io_parent, }, }; @@ -118,6 +127,7 @@ static struct mfd_cell onkey_devs[] = { .start = MAX8925_##_start, \ .end = MAX8925_##_end, \ .flags = IORESOURCE_IO, \ + .parent = &io_parent, \ } static struct resource regulator_resources[] = { -- cgit v1.2.2 From c10c2aab634a3c61c46b98875988b2f53040bc9c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 7 Aug 2012 19:42:44 +0100 Subject: mfd: 88pm860x: Move _IO resources out of ioport_ioresource The removal of mach/io.h from most ARM platforms also set the range of valid IO ports to be empty for most platforms when previously any 32 bit integer had been valid. This makes it impossible to add IO resources as the added range is smaller than that of the root resource for IO ports. Since we're not really using IO memory at all fix this by defining our own root resource outside the normal tree and make that the parent of all IO resources. This also ensures we won't conflict with read IO ports if we ever run on a platform which happens to use them. Signed-off-by: Mark Brown Acked-by: Arnd Bergmann Acked-by: Haojian Zhuang Tested-by: Haojian Zhuang Cc: stable@vger.kernel.org (v3.4+) Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-core.c | 92 +++++++++++++++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index d09918cf1b15..220c79afe0bf 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -21,40 +21,73 @@ #define INT_STATUS_NUM 3 +static struct resource io_parent = { + .start = 0, + .end = 0xffffffff, + .flags = IORESOURCE_IO, +}; + static struct resource bk_resources[] __devinitdata = { - {PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,}, - {PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,}, - {PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,}, + {PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO, + &io_parent,}, + {PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO, + &io_parent,}, + {PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO, + &io_parent,}, }; static struct resource led_resources[] __devinitdata = { - {PM8606_LED1_RED, PM8606_LED1_RED, "led0-red", IORESOURCE_IO,}, - {PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,}, - {PM8606_LED1_BLUE, PM8606_LED1_BLUE, "led0-blue", IORESOURCE_IO,}, - {PM8606_LED2_RED, PM8606_LED2_RED, "led1-red", IORESOURCE_IO,}, - {PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_IO,}, - {PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_IO,}, + {PM8606_LED1_RED, PM8606_LED1_RED, "led0-red", IORESOURCE_IO, + &io_parent,}, + {PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO, + &io_parent,}, + {PM8606_LED1_BLUE, PM8606_LED1_BLUE, "led0-blue", IORESOURCE_IO, + &io_parent,}, + {PM8606_LED2_RED, PM8606_LED2_RED, "led1-red", IORESOURCE_IO, + &io_parent,}, + {PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_IO, + &io_parent,}, + {PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_IO, + &io_parent,}, }; static struct resource regulator_resources[] __devinitdata = { - {PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO,}, - {PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO,}, - {PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO,}, - {PM8607_ID_LDO1, PM8607_ID_LDO1, "ldo-01", IORESOURCE_IO,}, - {PM8607_ID_LDO2, PM8607_ID_LDO2, "ldo-02", IORESOURCE_IO,}, - {PM8607_ID_LDO3, PM8607_ID_LDO3, "ldo-03", IORESOURCE_IO,}, - {PM8607_ID_LDO4, PM8607_ID_LDO4, "ldo-04", IORESOURCE_IO,}, - {PM8607_ID_LDO5, PM8607_ID_LDO5, "ldo-05", IORESOURCE_IO,}, - {PM8607_ID_LDO6, PM8607_ID_LDO6, "ldo-06", IORESOURCE_IO,}, - {PM8607_ID_LDO7, PM8607_ID_LDO7, "ldo-07", IORESOURCE_IO,}, - {PM8607_ID_LDO8, PM8607_ID_LDO8, "ldo-08", IORESOURCE_IO,}, - {PM8607_ID_LDO9, PM8607_ID_LDO9, "ldo-09", IORESOURCE_IO,}, - {PM8607_ID_LDO10, PM8607_ID_LDO10, "ldo-10", IORESOURCE_IO,}, - {PM8607_ID_LDO11, PM8607_ID_LDO11, "ldo-11", IORESOURCE_IO,}, - {PM8607_ID_LDO12, PM8607_ID_LDO12, "ldo-12", IORESOURCE_IO,}, - {PM8607_ID_LDO13, PM8607_ID_LDO13, "ldo-13", IORESOURCE_IO,}, - {PM8607_ID_LDO14, PM8607_ID_LDO14, "ldo-14", IORESOURCE_IO,}, - {PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,}, + {PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO, + &io_parent,}, + {PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO, + &io_parent,}, + {PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO, + &io_parent,}, + {PM8607_ID_LDO1, PM8607_ID_LDO1, "ldo-01", IORESOURCE_IO, + &io_parent,}, + {PM8607_ID_LDO2, PM8607_ID_LDO2, "ldo-02", IORESOURCE_IO, + &io_parent,}, + {PM8607_ID_LDO3, PM8607_ID_LDO3, "ldo-03", IORESOURCE_IO, + &io_parent,}, + {PM8607_ID_LDO4, PM8607_ID_LDO4, "ldo-04", IORESOURCE_IO, + &io_parent,}, + {PM8607_ID_LDO5, PM8607_ID_LDO5, "ldo-05", IORESOURCE_IO, + &io_parent,}, + {PM8607_ID_LDO6, PM8607_ID_LDO6, "ldo-06", IORESOURCE_IO, + &io_parent,}, + {PM8607_ID_LDO7, PM8607_ID_LDO7, "ldo-07", IORESOURCE_IO, + &io_parent,}, + {PM8607_ID_LDO8, PM8607_ID_LDO8, "ldo-08", IORESOURCE_IO, + &io_parent,}, + {PM8607_ID_LDO9, PM8607_ID_LDO9, "ldo-09", IORESOURCE_IO, + &io_parent,}, + {PM8607_ID_LDO10, PM8607_ID_LDO10, "ldo-10", IORESOURCE_IO, + &io_parent,}, + {PM8607_ID_LDO11, PM8607_ID_LDO11, "ldo-11", IORESOURCE_IO, + &io_parent,}, + {PM8607_ID_LDO12, PM8607_ID_LDO12, "ldo-12", IORESOURCE_IO, + &io_parent,}, + {PM8607_ID_LDO13, PM8607_ID_LDO13, "ldo-13", IORESOURCE_IO, + &io_parent,}, + {PM8607_ID_LDO14, PM8607_ID_LDO14, "ldo-14", IORESOURCE_IO, + &io_parent,}, + {PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO, + &io_parent,}, }; static struct resource touch_resources[] __devinitdata = { @@ -91,11 +124,12 @@ static struct resource charger_resources[] __devinitdata = { }; static struct resource preg_resources[] __devinitdata = { - {PM8606_ID_PREG, PM8606_ID_PREG, "preg", IORESOURCE_IO,}, + {PM8606_ID_PREG, PM8606_ID_PREG, "preg", IORESOURCE_IO, + &io_parent,}, }; static struct resource rtc_resources[] __devinitdata = { - {PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,}, + {PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ, &io_parent,}, }; static struct mfd_cell bk_devs[] = { -- cgit v1.2.2 From 5656098e198e793f7b43a11c301b5025c6e51c9a Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 7 Aug 2012 19:42:47 +0100 Subject: mfd: wm831x: Convert to IORESOURCE_REG This was originally written by Russell King who unfortunately found himself unable to take the patch futher. Signed-off-by: Mark Brown Acked-by: Arnd Bergmann Acked-by: Haojian Zhuang Tested-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-core.c | 66 ++++++++++++---------------------------- drivers/regulator/wm831x-dcdc.c | 12 ++++---- drivers/regulator/wm831x-isink.c | 4 +-- drivers/regulator/wm831x-ldo.c | 12 ++++---- 4 files changed, 34 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 946698fd2dc6..2e5d58eb2ec1 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -614,18 +614,11 @@ int wm831x_set_bits(struct wm831x *wm831x, unsigned short reg, } EXPORT_SYMBOL_GPL(wm831x_set_bits); -static struct resource wm831x_io_parent = { - .start = 0, - .end = 0xffffffff, - .flags = IORESOURCE_IO, -}; - static struct resource wm831x_dcdc1_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_DC1_CONTROL_1, .end = WM831X_DC1_DVS_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -644,10 +637,9 @@ static struct resource wm831x_dcdc1_resources[] = { static struct resource wm831x_dcdc2_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_DC2_CONTROL_1, .end = WM831X_DC2_DVS_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -665,10 +657,9 @@ static struct resource wm831x_dcdc2_resources[] = { static struct resource wm831x_dcdc3_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_DC3_CONTROL_1, .end = WM831X_DC3_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -680,10 +671,9 @@ static struct resource wm831x_dcdc3_resources[] = { static struct resource wm831x_dcdc4_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_DC4_CONTROL, .end = WM831X_DC4_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -695,10 +685,9 @@ static struct resource wm831x_dcdc4_resources[] = { static struct resource wm8320_dcdc4_buck_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_DC4_CONTROL, .end = WM832X_DC4_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -718,10 +707,9 @@ static struct resource wm831x_gpio_resources[] = { static struct resource wm831x_isink1_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_CURRENT_SINK_1, .end = WM831X_CURRENT_SINK_1, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .start = WM831X_IRQ_CS1, @@ -732,10 +720,9 @@ static struct resource wm831x_isink1_resources[] = { static struct resource wm831x_isink2_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_CURRENT_SINK_2, .end = WM831X_CURRENT_SINK_2, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .start = WM831X_IRQ_CS2, @@ -746,10 +733,9 @@ static struct resource wm831x_isink2_resources[] = { static struct resource wm831x_ldo1_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO1_CONTROL, .end = WM831X_LDO1_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -761,10 +747,9 @@ static struct resource wm831x_ldo1_resources[] = { static struct resource wm831x_ldo2_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO2_CONTROL, .end = WM831X_LDO2_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -776,10 +761,9 @@ static struct resource wm831x_ldo2_resources[] = { static struct resource wm831x_ldo3_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO3_CONTROL, .end = WM831X_LDO3_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -791,10 +775,9 @@ static struct resource wm831x_ldo3_resources[] = { static struct resource wm831x_ldo4_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO4_CONTROL, .end = WM831X_LDO4_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -806,10 +789,9 @@ static struct resource wm831x_ldo4_resources[] = { static struct resource wm831x_ldo5_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO5_CONTROL, .end = WM831X_LDO5_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -821,10 +803,9 @@ static struct resource wm831x_ldo5_resources[] = { static struct resource wm831x_ldo6_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO6_CONTROL, .end = WM831X_LDO6_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -836,10 +817,9 @@ static struct resource wm831x_ldo6_resources[] = { static struct resource wm831x_ldo7_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO7_CONTROL, .end = WM831X_LDO7_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -851,10 +831,9 @@ static struct resource wm831x_ldo7_resources[] = { static struct resource wm831x_ldo8_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO8_CONTROL, .end = WM831X_LDO8_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -866,10 +845,9 @@ static struct resource wm831x_ldo8_resources[] = { static struct resource wm831x_ldo9_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO9_CONTROL, .end = WM831X_LDO9_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -881,10 +859,9 @@ static struct resource wm831x_ldo9_resources[] = { static struct resource wm831x_ldo10_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO10_CONTROL, .end = WM831X_LDO10_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, { .name = "UV", @@ -896,10 +873,9 @@ static struct resource wm831x_ldo10_resources[] = { static struct resource wm831x_ldo11_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_LDO11_ON_CONTROL, .end = WM831X_LDO11_SLEEP_CONTROL, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, }; @@ -998,19 +974,17 @@ static struct resource wm831x_rtc_resources[] = { static struct resource wm831x_status1_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_STATUS_LED_1, .end = WM831X_STATUS_LED_1, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, }; static struct resource wm831x_status2_resources[] = { { - .parent = &wm831x_io_parent, .start = WM831X_STATUS_LED_2, .end = WM831X_STATUS_LED_2, - .flags = IORESOURCE_IO, + .flags = IORESOURCE_REG, }, }; diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 7413885be01b..64111f4935a4 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -476,9 +476,9 @@ static __devinit int wm831x_buckv_probe(struct platform_device *pdev) dcdc->wm831x = wm831x; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource\n"); + dev_err(&pdev->dev, "No REG resource\n"); ret = -EINVAL; goto err; } @@ -651,9 +651,9 @@ static __devinit int wm831x_buckp_probe(struct platform_device *pdev) dcdc->wm831x = wm831x; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource\n"); + dev_err(&pdev->dev, "No REG resource\n"); ret = -EINVAL; goto err; } @@ -795,9 +795,9 @@ static __devinit int wm831x_boostp_probe(struct platform_device *pdev) dcdc->wm831x = wm831x; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource\n"); + dev_err(&pdev->dev, "No REG resource\n"); ret = -EINVAL; goto err; } diff --git a/drivers/regulator/wm831x-isink.c b/drivers/regulator/wm831x-isink.c index 0d207c297714..2646a1902b33 100644 --- a/drivers/regulator/wm831x-isink.c +++ b/drivers/regulator/wm831x-isink.c @@ -172,9 +172,9 @@ static __devinit int wm831x_isink_probe(struct platform_device *pdev) isink->wm831x = wm831x; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource\n"); + dev_err(&pdev->dev, "No REG resource\n"); ret = -EINVAL; goto err; } diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index 5cb70ca1e98d..da73daf2eb7c 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -269,9 +269,9 @@ static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev) ldo->wm831x = wm831x; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource\n"); + dev_err(&pdev->dev, "No REG resource\n"); ret = -EINVAL; goto err; } @@ -520,9 +520,9 @@ static __devinit int wm831x_aldo_probe(struct platform_device *pdev) ldo->wm831x = wm831x; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource\n"); + dev_err(&pdev->dev, "No REG resource\n"); ret = -EINVAL; goto err; } @@ -675,9 +675,9 @@ static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev) ldo->wm831x = wm831x; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource\n"); + dev_err(&pdev->dev, "No REG resource\n"); ret = -EINVAL; goto err; } -- cgit v1.2.2 From 023670295ab6b65f5a84b8f214377c04c683809d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 7 Aug 2012 19:42:48 +0100 Subject: mfd: 88pm860x: Convert to IORESOURCE_REG Signed-off-by: Mark Brown Acked-by: Arnd Bergmann Acked-by: Haojian Zhuang Tested-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/leds/leds-88pm860x.c | 2 +- drivers/mfd/88pm860x-core.c | 92 +++++++++++------------------------ drivers/regulator/88pm8607.c | 2 +- drivers/video/backlight/88pm860x_bl.c | 2 +- 4 files changed, 32 insertions(+), 66 deletions(-) (limited to 'drivers') diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c index 61897cfeeda6..ea2615b25082 100644 --- a/drivers/leds/leds-88pm860x.c +++ b/drivers/leds/leds-88pm860x.c @@ -197,7 +197,7 @@ static int pm860x_led_probe(struct platform_device *pdev) struct resource *res; int ret; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { dev_err(&pdev->dev, "No I/O resource!\n"); return -EINVAL; diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 220c79afe0bf..75864383573d 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -21,73 +21,40 @@ #define INT_STATUS_NUM 3 -static struct resource io_parent = { - .start = 0, - .end = 0xffffffff, - .flags = IORESOURCE_IO, -}; - static struct resource bk_resources[] __devinitdata = { - {PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO, - &io_parent,}, - {PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO, - &io_parent,}, - {PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO, - &io_parent,}, + {PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_REG,}, + {PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_REG,}, + {PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_REG,}, }; static struct resource led_resources[] __devinitdata = { - {PM8606_LED1_RED, PM8606_LED1_RED, "led0-red", IORESOURCE_IO, - &io_parent,}, - {PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO, - &io_parent,}, - {PM8606_LED1_BLUE, PM8606_LED1_BLUE, "led0-blue", IORESOURCE_IO, - &io_parent,}, - {PM8606_LED2_RED, PM8606_LED2_RED, "led1-red", IORESOURCE_IO, - &io_parent,}, - {PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_IO, - &io_parent,}, - {PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_IO, - &io_parent,}, + {PM8606_LED1_RED, PM8606_LED1_RED, "led0-red", IORESOURCE_REG,}, + {PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_REG,}, + {PM8606_LED1_BLUE, PM8606_LED1_BLUE, "led0-blue", IORESOURCE_REG,}, + {PM8606_LED2_RED, PM8606_LED2_RED, "led1-red", IORESOURCE_REG,}, + {PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_REG,}, + {PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_REG,}, }; static struct resource regulator_resources[] __devinitdata = { - {PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO, - &io_parent,}, - {PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO, - &io_parent,}, - {PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO, - &io_parent,}, - {PM8607_ID_LDO1, PM8607_ID_LDO1, "ldo-01", IORESOURCE_IO, - &io_parent,}, - {PM8607_ID_LDO2, PM8607_ID_LDO2, "ldo-02", IORESOURCE_IO, - &io_parent,}, - {PM8607_ID_LDO3, PM8607_ID_LDO3, "ldo-03", IORESOURCE_IO, - &io_parent,}, - {PM8607_ID_LDO4, PM8607_ID_LDO4, "ldo-04", IORESOURCE_IO, - &io_parent,}, - {PM8607_ID_LDO5, PM8607_ID_LDO5, "ldo-05", IORESOURCE_IO, - &io_parent,}, - {PM8607_ID_LDO6, PM8607_ID_LDO6, "ldo-06", IORESOURCE_IO, - &io_parent,}, - {PM8607_ID_LDO7, PM8607_ID_LDO7, "ldo-07", IORESOURCE_IO, - &io_parent,}, - {PM8607_ID_LDO8, PM8607_ID_LDO8, "ldo-08", IORESOURCE_IO, - &io_parent,}, - {PM8607_ID_LDO9, PM8607_ID_LDO9, "ldo-09", IORESOURCE_IO, - &io_parent,}, - {PM8607_ID_LDO10, PM8607_ID_LDO10, "ldo-10", IORESOURCE_IO, - &io_parent,}, - {PM8607_ID_LDO11, PM8607_ID_LDO11, "ldo-11", IORESOURCE_IO, - &io_parent,}, - {PM8607_ID_LDO12, PM8607_ID_LDO12, "ldo-12", IORESOURCE_IO, - &io_parent,}, - {PM8607_ID_LDO13, PM8607_ID_LDO13, "ldo-13", IORESOURCE_IO, - &io_parent,}, - {PM8607_ID_LDO14, PM8607_ID_LDO14, "ldo-14", IORESOURCE_IO, - &io_parent,}, - {PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO, - &io_parent,}, + {PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_REG,}, + {PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_REG,}, + {PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_REG,}, + {PM8607_ID_LDO1, PM8607_ID_LDO1, "ldo-01", IORESOURCE_REG,}, + {PM8607_ID_LDO2, PM8607_ID_LDO2, "ldo-02", IORESOURCE_REG,}, + {PM8607_ID_LDO3, PM8607_ID_LDO3, "ldo-03", IORESOURCE_REG,}, + {PM8607_ID_LDO4, PM8607_ID_LDO4, "ldo-04", IORESOURCE_REG,}, + {PM8607_ID_LDO5, PM8607_ID_LDO5, "ldo-05", IORESOURCE_REG,}, + {PM8607_ID_LDO6, PM8607_ID_LDO6, "ldo-06", IORESOURCE_REG,}, + {PM8607_ID_LDO7, PM8607_ID_LDO7, "ldo-07", IORESOURCE_REG,}, + {PM8607_ID_LDO8, PM8607_ID_LDO8, "ldo-08", IORESOURCE_REG,}, + {PM8607_ID_LDO9, PM8607_ID_LDO9, "ldo-09", IORESOURCE_REG,}, + {PM8607_ID_LDO10, PM8607_ID_LDO10, "ldo-10", IORESOURCE_REG,}, + {PM8607_ID_LDO11, PM8607_ID_LDO11, "ldo-11", IORESOURCE_REG,}, + {PM8607_ID_LDO12, PM8607_ID_LDO12, "ldo-12", IORESOURCE_REG,}, + {PM8607_ID_LDO13, PM8607_ID_LDO13, "ldo-13", IORESOURCE_REG,}, + {PM8607_ID_LDO14, PM8607_ID_LDO14, "ldo-14", IORESOURCE_REG,}, + {PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_REG,}, }; static struct resource touch_resources[] __devinitdata = { @@ -124,12 +91,11 @@ static struct resource charger_resources[] __devinitdata = { }; static struct resource preg_resources[] __devinitdata = { - {PM8606_ID_PREG, PM8606_ID_PREG, "preg", IORESOURCE_IO, - &io_parent,}, + {PM8606_ID_PREG, PM8606_ID_PREG, "preg", IORESOURCE_REG,}, }; static struct resource rtc_resources[] __devinitdata = { - {PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ, &io_parent,}, + {PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,}, }; static struct mfd_cell bk_devs[] = { diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index c3482b954cb7..0b76372aee72 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -320,7 +320,7 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) struct resource *res; int i; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { dev_err(&pdev->dev, "No I/O resource!\n"); return -EINVAL; diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index f75da8758adc..d65472e9b30d 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -201,7 +201,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev) char name[MFD_NAME_SIZE]; int ret; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { dev_err(&pdev->dev, "No I/O resource!\n"); return -EINVAL; -- cgit v1.2.2 From 015625a20f630c798a8c5fdf5d472be091b8ac7d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 7 Aug 2012 19:42:49 +0100 Subject: mfd: max8925: Convert to IORESOURCE_REG Signed-off-by: Mark Brown Acked-by: Arnd Bergmann Acked-by: Haojian Zhuang Tested-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/mfd/max8925-core.c | 18 ++++-------------- drivers/video/backlight/max8925_bl.c | 2 +- 2 files changed, 5 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index 6aa3a22ea435..08a57231c25b 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -18,19 +18,12 @@ #include #include -static struct resource io_parent = { - .start = 0, - .end = 0xffffffff, - .flags = IORESOURCE_IO, -}; - static struct resource backlight_resources[] = { { .name = "max8925-backlight", .start = MAX8925_WLED_MODE_CNTL, .end = MAX8925_WLED_CNTL, - .flags = IORESOURCE_IO, - .parent = &io_parent, + .flags = IORESOURCE_REG, }, }; @@ -48,8 +41,7 @@ static struct resource touch_resources[] = { .name = "max8925-tsc", .start = MAX8925_TSC_IRQ, .end = MAX8925_ADC_RES_END, - .flags = IORESOURCE_IO, - .parent = &io_parent, + .flags = IORESOURCE_REG, }, }; @@ -67,8 +59,7 @@ static struct resource power_supply_resources[] = { .name = "max8925-power", .start = MAX8925_CHG_IRQ1, .end = MAX8925_CHG_IRQ1_MASK, - .flags = IORESOURCE_IO, - .parent = &io_parent, + .flags = IORESOURCE_REG, }, }; @@ -126,8 +117,7 @@ static struct mfd_cell onkey_devs[] = { { \ .start = MAX8925_##_start, \ .end = MAX8925_##_end, \ - .flags = IORESOURCE_IO, \ - .parent = &io_parent, \ + .flags = IORESOURCE_REG, \ } static struct resource regulator_resources[] = { diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index e833ac72e063..996dadfa09ff 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -112,7 +112,7 @@ static int __devinit max8925_backlight_probe(struct platform_device *pdev) unsigned char value; int ret; - res = platform_get_resource(pdev, IORESOURCE_IO, 0); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { dev_err(&pdev->dev, "No I/O resource!\n"); return -EINVAL; -- cgit v1.2.2 From a6ccdcd98c39ac13508570dbd943a1cf1b569f55 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Wed, 8 Aug 2012 23:17:26 +0800 Subject: mfd: 88pm860x: Use REG resource for backlight Now resource of 88pm860x backlight is changed from IORESOURCE_IO to IORESOURCE_REG. In original driver, the resource is using self-defined IORESOURCE_IO. So change the resource to register offset to match the definition of IORESOURCE_REG. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-core.c | 78 ++++++++++++----------- drivers/video/backlight/88pm860x_bl.c | 114 ++++++++++++++-------------------- 2 files changed, 89 insertions(+), 103 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 75864383573d..b72628e8d6ee 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -21,10 +21,20 @@ #define INT_STATUS_NUM 3 -static struct resource bk_resources[] __devinitdata = { - {PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_REG,}, - {PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_REG,}, - {PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_REG,}, +static struct resource bk0_resources[] __devinitdata = { + {2, 2, "duty cycle", IORESOURCE_REG, }, + {3, 3, "always on", IORESOURCE_REG, }, + {3, 3, "current", IORESOURCE_REG, }, +}; +static struct resource bk1_resources[] __devinitdata = { + {4, 4, "duty cycle", IORESOURCE_REG, }, + {5, 5, "always on", IORESOURCE_REG, }, + {5, 5, "current", IORESOURCE_REG, }, +}; +static struct resource bk2_resources[] __devinitdata = { + {6, 6, "duty cycle", IORESOURCE_REG, }, + {7, 7, "always on", IORESOURCE_REG, }, + {5, 5, "current", IORESOURCE_REG, }, }; static struct resource led_resources[] __devinitdata = { @@ -99,9 +109,22 @@ static struct resource rtc_resources[] __devinitdata = { }; static struct mfd_cell bk_devs[] = { - {"88pm860x-backlight", 0,}, - {"88pm860x-backlight", 1,}, - {"88pm860x-backlight", 2,}, + { + .name = "88pm860x-backlight", + .id = 0, + .num_resources = ARRAY_SIZE(bk0_resources), + .resources = bk0_resources, + }, { + .name = "88pm860x-backlight", + .id = 1, + .num_resources = ARRAY_SIZE(bk1_resources), + .resources = bk1_resources, + }, { + .name = "88pm860x-backlight", + .id = 2, + .num_resources = ARRAY_SIZE(bk2_resources), + .resources = bk2_resources, + }, }; static struct mfd_cell led_devs[] = { @@ -615,36 +638,21 @@ static void __devinit device_osc_init(struct i2c_client *i2c) static void __devinit device_bk_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { - int ret; - int i, j, id; - - if ((pdata == NULL) || (pdata->backlight == NULL)) - return; - - if (pdata->num_backlights > ARRAY_SIZE(bk_devs)) - pdata->num_backlights = ARRAY_SIZE(bk_devs); - - for (i = 0; i < pdata->num_backlights; i++) { - bk_devs[i].platform_data = &pdata->backlight[i]; - bk_devs[i].pdata_size = sizeof(struct pm860x_backlight_pdata); - - for (j = 0; j < ARRAY_SIZE(bk_devs); j++) { - id = bk_resources[j].start; - if (pdata->backlight[i].flags != id) - continue; - - bk_devs[i].num_resources = 1; - bk_devs[i].resources = &bk_resources[j]; - ret = mfd_add_devices(chip->dev, 0, - &bk_devs[i], 1, - &bk_resources[j], 0); - if (ret < 0) { - dev_err(chip->dev, "Failed to add " - "backlight subdev\n"); - return; - } + int ret, i; + + if (pdata && pdata->backlight) { + if (pdata->num_backlights > ARRAY_SIZE(bk_devs)) + pdata->num_backlights = ARRAY_SIZE(bk_devs); + for (i = 0; i < pdata->num_backlights; i++) { + bk_devs[i].platform_data = &pdata->backlight[i]; + bk_devs[i].pdata_size = + sizeof(struct pm860x_backlight_pdata); } } + ret = mfd_add_devices(chip->dev, 0, bk_devs, + ARRAY_SIZE(bk_devs), NULL, 0); + if (ret < 0) + dev_err(chip->dev, "Failed to add backlight subdev\n"); } static void __devinit device_led_init(struct pm860x_chip *chip, diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index d65472e9b30d..965161cacefa 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -31,57 +31,26 @@ struct pm860x_backlight_data { int port; int pwm; int iset; + int reg_duty_cycle; + int reg_always_on; + int reg_current; }; -static inline int wled_a(int port) -{ - int ret; - - ret = ((port - PM8606_BACKLIGHT1) << 1) + 2; - return ret; -} - -static inline int wled_b(int port) -{ - int ret; - - ret = ((port - PM8606_BACKLIGHT1) << 1) + 3; - return ret; -} - -/* WLED2 & WLED3 share the same IDC */ -static inline int wled_idc(int port) -{ - int ret; - - switch (port) { - case PM8606_BACKLIGHT1: - case PM8606_BACKLIGHT2: - ret = ((port - PM8606_BACKLIGHT1) << 1) + 3; - break; - case PM8606_BACKLIGHT3: - default: - ret = ((port - PM8606_BACKLIGHT2) << 1) + 3; - break; - } - return ret; -} - static int backlight_power_set(struct pm860x_chip *chip, int port, int on) { int ret = -EINVAL; switch (port) { - case PM8606_BACKLIGHT1: + case 0: ret = on ? pm8606_osc_enable(chip, WLED1_DUTY) : pm8606_osc_disable(chip, WLED1_DUTY); break; - case PM8606_BACKLIGHT2: + case 1: ret = on ? pm8606_osc_enable(chip, WLED2_DUTY) : pm8606_osc_disable(chip, WLED2_DUTY); break; - case PM8606_BACKLIGHT3: + case 2: ret = on ? pm8606_osc_enable(chip, WLED3_DUTY) : pm8606_osc_disable(chip, WLED3_DUTY); break; @@ -104,13 +73,13 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness) if (brightness) backlight_power_set(chip, data->port, 1); - ret = pm860x_reg_write(data->i2c, wled_a(data->port), value); + ret = pm860x_reg_write(data->i2c, data->reg_duty_cycle, value); if (ret < 0) goto out; if ((data->current_brightness == 0) && brightness) { if (data->iset) { - ret = pm860x_set_bits(data->i2c, wled_idc(data->port), + ret = pm860x_set_bits(data->i2c, data->reg_current, CURRENT_BITMASK, data->iset); if (ret < 0) goto out; @@ -123,17 +92,17 @@ static int pm860x_backlight_set(struct backlight_device *bl, int brightness) } if (brightness == MAX_BRIGHTNESS) { /* set WLED_ON bit as 100% */ - ret = pm860x_set_bits(data->i2c, wled_b(data->port), + ret = pm860x_set_bits(data->i2c, data->reg_always_on, PM8606_WLED_ON, PM8606_WLED_ON); } } else { if (brightness == MAX_BRIGHTNESS) { /* set WLED_ON bit as 100% */ - ret = pm860x_set_bits(data->i2c, wled_b(data->port), + ret = pm860x_set_bits(data->i2c, data->reg_always_on, PM8606_WLED_ON, PM8606_WLED_ON); } else { /* clear WLED_ON bit since it's not 100% */ - ret = pm860x_set_bits(data->i2c, wled_b(data->port), + ret = pm860x_set_bits(data->i2c, data->reg_always_on, PM8606_WLED_ON, 0); } } @@ -174,7 +143,7 @@ static int pm860x_backlight_get_brightness(struct backlight_device *bl) struct pm860x_chip *chip = data->chip; int ret; - ret = pm860x_reg_read(data->i2c, wled_a(data->port)); + ret = pm860x_reg_read(data->i2c, data->reg_duty_cycle); if (ret < 0) goto out; data->current_brightness = ret; @@ -193,43 +162,50 @@ static const struct backlight_ops pm860x_backlight_ops = { static int pm860x_backlight_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct pm860x_backlight_pdata *pdata = NULL; + struct pm860x_backlight_pdata *pdata = pdev->dev.platform_data; struct pm860x_backlight_data *data; struct backlight_device *bl; struct resource *res; struct backlight_properties props; char name[MFD_NAME_SIZE]; - int ret; - - res = platform_get_resource(pdev, IORESOURCE_REG, 0); - if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource!\n"); - return -EINVAL; - } - - pdata = pdev->dev.platform_data; - if (pdata == NULL) { - dev_err(&pdev->dev, "platform data isn't assigned to " - "backlight\n"); - return -EINVAL; - } + int ret = 0; data = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_backlight_data), GFP_KERNEL); if (data == NULL) return -ENOMEM; - strncpy(name, res->name, MFD_NAME_SIZE); + res = platform_get_resource_byname(pdev, IORESOURCE_REG, "duty cycle"); + if (!res) { + dev_err(&pdev->dev, "No REG resource for duty cycle\n"); + ret = -ENXIO; + goto out; + } + data->reg_duty_cycle = res->start; + res = platform_get_resource_byname(pdev, IORESOURCE_REG, "always on"); + if (!res) { + dev_err(&pdev->dev, "No REG resorce for always on\n"); + ret = -ENXIO; + goto out; + } + data->reg_always_on = res->start; + res = platform_get_resource_byname(pdev, IORESOURCE_REG, "current"); + if (!res) { + dev_err(&pdev->dev, "No REG resource for current\n"); + ret = -ENXIO; + goto out; + } + data->reg_current = res->start; + + memset(name, 0, MFD_NAME_SIZE); + sprintf(name, "backlight-%d", pdev->id); + data->port = pdev->id; data->chip = chip; data->i2c = (chip->id == CHIP_PM8606) ? chip->client \ : chip->companion; data->current_brightness = MAX_BRIGHTNESS; - data->pwm = pdata->pwm; - data->iset = pdata->iset; - data->port = pdata->flags; - if (data->port < 0) { - dev_err(&pdev->dev, "wrong platform data is assigned"); - kfree(data); - return -EINVAL; + if (pdata) { + data->pwm = pdata->pwm; + data->iset = pdata->iset; } memset(&props, 0, sizeof(struct backlight_properties)); @@ -248,12 +224,14 @@ static int pm860x_backlight_probe(struct platform_device *pdev) /* read current backlight */ ret = pm860x_backlight_get_brightness(bl); if (ret < 0) - goto out; + goto out_brt; backlight_update_status(bl); return 0; -out: +out_brt: backlight_device_unregister(bl); +out: + devm_kfree(&pdev->dev, data); return ret; } -- cgit v1.2.2 From 894fc8f2c295373e6c73943d8bc2023cc49b9bb0 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Wed, 8 Aug 2012 23:17:27 +0800 Subject: mfd: 88pm860x: Use REG in leds resource Since the resources of 88pm860x leds are changed from IORESOURCE_IO to IORESOURCE_REG that is register offset, change the original self-defined IORESOURCE_IO to register offset. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/leds/leds-88pm860x.c | 176 +++++++++++++++++-------------------------- drivers/mfd/88pm860x-core.c | 114 ++++++++++++++++++---------- 2 files changed, 143 insertions(+), 147 deletions(-) (limited to 'drivers') diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c index ea2615b25082..70232b1756f9 100644 --- a/drivers/leds/leds-88pm860x.c +++ b/drivers/leds/leds-88pm860x.c @@ -20,18 +20,12 @@ #include #include -#define LED_PWM_SHIFT (3) #define LED_PWM_MASK (0x1F) #define LED_CURRENT_MASK (0x07 << 5) -#define LED_BLINK_ON_MASK (0x07) #define LED_BLINK_MASK (0x7F) -#define LED_BLINK_ON(x) ((x & 0x7) * 66 + 66) -#define LED_BLINK_ON_MIN LED_BLINK_ON(0) -#define LED_BLINK_ON_MAX LED_BLINK_ON(0x7) #define LED_ON_CONTINUOUS (0x0F << 3) -#define LED_TO_ON(x) ((x - 66) / 66) #define LED1_BLINK_EN (1 << 1) #define LED2_BLINK_EN (1 << 2) @@ -49,85 +43,25 @@ struct pm860x_led { unsigned char brightness; unsigned char current_brightness; - int blink_data; - int blink_time; - int blink_on; - int blink_off; + int reg_control; + int reg_blink; + int blink_mask; }; -/* return offset of color register */ -static inline int __led_off(int port) -{ - int ret = -EINVAL; - - switch (port) { - case PM8606_LED1_RED: - case PM8606_LED1_GREEN: - case PM8606_LED1_BLUE: - ret = port - PM8606_LED1_RED + PM8606_RGB1B; - break; - case PM8606_LED2_RED: - case PM8606_LED2_GREEN: - case PM8606_LED2_BLUE: - ret = port - PM8606_LED2_RED + PM8606_RGB2B; - break; - } - return ret; -} - -/* return offset of blink register */ -static inline int __blink_off(int port) -{ - int ret = -EINVAL; - - switch (port) { - case PM8606_LED1_RED: - case PM8606_LED1_GREEN: - case PM8606_LED1_BLUE: - ret = PM8606_RGB1A; - break; - case PM8606_LED2_RED: - case PM8606_LED2_GREEN: - case PM8606_LED2_BLUE: - ret = PM8606_RGB2A; - break; - } - return ret; -} - -static inline int __blink_ctl_mask(int port) -{ - int ret = -EINVAL; - - switch (port) { - case PM8606_LED1_RED: - case PM8606_LED1_GREEN: - case PM8606_LED1_BLUE: - ret = LED1_BLINK_EN; - break; - case PM8606_LED2_RED: - case PM8606_LED2_GREEN: - case PM8606_LED2_BLUE: - ret = LED2_BLINK_EN; - break; - } - return ret; -} - static int led_power_set(struct pm860x_chip *chip, int port, int on) { int ret = -EINVAL; switch (port) { - case PM8606_LED1_RED: - case PM8606_LED1_GREEN: - case PM8606_LED1_BLUE: + case 0: + case 1: + case 2: ret = on ? pm8606_osc_enable(chip, RGB1_ENABLE) : pm8606_osc_disable(chip, RGB1_ENABLE); break; - case PM8606_LED2_RED: - case PM8606_LED2_GREEN: - case PM8606_LED2_BLUE: + case 3: + case 4: + case 5: ret = on ? pm8606_osc_enable(chip, RGB2_ENABLE) : pm8606_osc_disable(chip, RGB2_ENABLE); break; @@ -141,7 +75,7 @@ static void pm860x_led_work(struct work_struct *work) struct pm860x_led *led; struct pm860x_chip *chip; unsigned char buf[3]; - int mask, ret; + int ret; led = container_of(work, struct pm860x_led, work); chip = led->chip; @@ -149,34 +83,34 @@ static void pm860x_led_work(struct work_struct *work) if ((led->current_brightness == 0) && led->brightness) { led_power_set(chip, led->port, 1); if (led->iset) { - pm860x_set_bits(led->i2c, __led_off(led->port), + pm860x_set_bits(led->i2c, led->reg_control, LED_CURRENT_MASK, led->iset); } - pm860x_set_bits(led->i2c, __blink_off(led->port), + pm860x_set_bits(led->i2c, led->reg_blink, LED_BLINK_MASK, LED_ON_CONTINUOUS); - mask = __blink_ctl_mask(led->port); - pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, mask); + pm860x_set_bits(led->i2c, PM8606_WLED3B, led->blink_mask, + led->blink_mask); } - pm860x_set_bits(led->i2c, __led_off(led->port), LED_PWM_MASK, + pm860x_set_bits(led->i2c, led->reg_control, LED_PWM_MASK, led->brightness); if (led->brightness == 0) { - pm860x_bulk_read(led->i2c, __led_off(led->port), 3, buf); + pm860x_bulk_read(led->i2c, led->reg_control, 3, buf); ret = buf[0] & LED_PWM_MASK; ret |= buf[1] & LED_PWM_MASK; ret |= buf[2] & LED_PWM_MASK; if (ret == 0) { /* unset current since no led is lighting */ - pm860x_set_bits(led->i2c, __led_off(led->port), + pm860x_set_bits(led->i2c, led->reg_control, LED_CURRENT_MASK, 0); - mask = __blink_ctl_mask(led->port); - pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0); + pm860x_set_bits(led->i2c, PM8606_WLED3B, + led->blink_mask, 0); led_power_set(chip, led->port, 0); } } led->current_brightness = led->brightness; dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n", - __led_off(led->port), led->brightness); + led->reg_control, led->brightness); mutex_unlock(&led->lock); } @@ -192,36 +126,61 @@ static void pm860x_led_set(struct led_classdev *cdev, static int pm860x_led_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct pm860x_led_pdata *pdata; + struct pm860x_led_pdata *pdata = pdev->dev.platform_data; struct pm860x_led *data; struct resource *res; - int ret; - - res = platform_get_resource(pdev, IORESOURCE_REG, 0); - if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource!\n"); - return -EINVAL; - } - - pdata = pdev->dev.platform_data; - if (pdata == NULL) { - dev_err(&pdev->dev, "No platform data!\n"); - return -EINVAL; - } + int ret = 0; data = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_led), GFP_KERNEL); if (data == NULL) return -ENOMEM; - strncpy(data->name, res->name, MFD_NAME_SIZE - 1); + res = platform_get_resource_byname(pdev, IORESOURCE_REG, "control"); + if (!res) { + dev_err(&pdev->dev, "No REG resource for control\n"); + ret = -ENXIO; + goto out; + } + data->reg_control = res->start; + res = platform_get_resource_byname(pdev, IORESOURCE_REG, "blink"); + if (!res) { + dev_err(&pdev->dev, "No REG resource for blink\n"); + ret = -ENXIO; + goto out; + } + data->reg_blink = res->start; + memset(data->name, 0, MFD_NAME_SIZE); + switch (pdev->id) { + case 0: + data->blink_mask = LED1_BLINK_EN; + sprintf(data->name, "led0-red"); + break; + case 1: + data->blink_mask = LED1_BLINK_EN; + sprintf(data->name, "led0-green"); + break; + case 2: + data->blink_mask = LED1_BLINK_EN; + sprintf(data->name, "led0-blue"); + break; + case 3: + data->blink_mask = LED2_BLINK_EN; + sprintf(data->name, "led1-red"); + break; + case 4: + data->blink_mask = LED2_BLINK_EN; + sprintf(data->name, "led1-green"); + break; + case 5: + data->blink_mask = LED2_BLINK_EN; + sprintf(data->name, "led1-blue"); + break; + } dev_set_drvdata(&pdev->dev, data); data->chip = chip; data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion; - data->iset = pdata->iset; - data->port = pdata->flags; - if (data->port < 0) { - dev_err(&pdev->dev, "check device failed\n"); - return -EINVAL; - } + data->port = pdev->id; + if (pdata && pdata->iset) + data->iset = pdata->iset; data->current_brightness = 0; data->cdev.name = data->name; @@ -236,6 +195,9 @@ static int pm860x_led_probe(struct platform_device *pdev) } pm860x_led_set(&data->cdev, 0); return 0; +out: + devm_kfree(&pdev->dev, data); + return ret; } static int pm860x_led_remove(struct platform_device *pdev) diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index b72628e8d6ee..e364b22f957d 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -37,13 +37,35 @@ static struct resource bk2_resources[] __devinitdata = { {5, 5, "current", IORESOURCE_REG, }, }; -static struct resource led_resources[] __devinitdata = { - {PM8606_LED1_RED, PM8606_LED1_RED, "led0-red", IORESOURCE_REG,}, - {PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_REG,}, - {PM8606_LED1_BLUE, PM8606_LED1_BLUE, "led0-blue", IORESOURCE_REG,}, - {PM8606_LED2_RED, PM8606_LED2_RED, "led1-red", IORESOURCE_REG,}, - {PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_REG,}, - {PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_REG,}, +static struct resource led0_resources[] __devinitdata = { + /* RGB1 Red LED */ + {0xd, 0xd, "control", IORESOURCE_REG, }, + {0xc, 0xc, "blink", IORESOURCE_REG, }, +}; +static struct resource led1_resources[] __devinitdata = { + /* RGB1 Green LED */ + {0xe, 0xe, "control", IORESOURCE_REG, }, + {0xc, 0xc, "blink", IORESOURCE_REG, }, +}; +static struct resource led2_resources[] __devinitdata = { + /* RGB1 Blue LED */ + {0xf, 0xf, "control", IORESOURCE_REG, }, + {0xc, 0xc, "blink", IORESOURCE_REG, }, +}; +static struct resource led3_resources[] __devinitdata = { + /* RGB2 Red LED */ + {0x9, 0x9, "control", IORESOURCE_REG, }, + {0x8, 0x8, "blink", IORESOURCE_REG, }, +}; +static struct resource led4_resources[] __devinitdata = { + /* RGB2 Green LED */ + {0xa, 0xa, "control", IORESOURCE_REG, }, + {0x8, 0x8, "blink", IORESOURCE_REG, }, +}; +static struct resource led5_resources[] __devinitdata = { + /* RGB2 Blue LED */ + {0xb, 0xb, "control", IORESOURCE_REG, }, + {0x8, 0x8, "blink", IORESOURCE_REG, }, }; static struct resource regulator_resources[] __devinitdata = { @@ -128,12 +150,37 @@ static struct mfd_cell bk_devs[] = { }; static struct mfd_cell led_devs[] = { - {"88pm860x-led", 0,}, - {"88pm860x-led", 1,}, - {"88pm860x-led", 2,}, - {"88pm860x-led", 3,}, - {"88pm860x-led", 4,}, - {"88pm860x-led", 5,}, + { + .name = "88pm860x-led", + .id = 0, + .num_resources = ARRAY_SIZE(led0_resources), + .resources = led0_resources, + }, { + .name = "88pm860x-led", + .id = 1, + .num_resources = ARRAY_SIZE(led1_resources), + .resources = led1_resources, + }, { + .name = "88pm860x-led", + .id = 2, + .num_resources = ARRAY_SIZE(led2_resources), + .resources = led2_resources, + }, { + .name = "88pm860x-led", + .id = 3, + .num_resources = ARRAY_SIZE(led3_resources), + .resources = led3_resources, + }, { + .name = "88pm860x-led", + .id = 4, + .num_resources = ARRAY_SIZE(led4_resources), + .resources = led4_resources, + }, { + .name = "88pm860x-led", + .id = 5, + .num_resources = ARRAY_SIZE(led5_resources), + .resources = led5_resources, + }, }; static struct mfd_cell regulator_devs[] = { @@ -658,36 +705,23 @@ static void __devinit device_bk_init(struct pm860x_chip *chip, static void __devinit device_led_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { - int ret; - int i, j, id; - - if ((pdata == NULL) || (pdata->led == NULL)) - return; + int ret, i; - if (pdata->num_leds > ARRAY_SIZE(led_devs)) - pdata->num_leds = ARRAY_SIZE(led_devs); - - for (i = 0; i < pdata->num_leds; i++) { - led_devs[i].platform_data = &pdata->led[i]; - led_devs[i].pdata_size = sizeof(struct pm860x_led_pdata); - - for (j = 0; j < ARRAY_SIZE(led_devs); j++) { - id = led_resources[j].start; - if (pdata->led[i].flags != id) - continue; - - led_devs[i].num_resources = 1; - led_devs[i].resources = &led_resources[j], - ret = mfd_add_devices(chip->dev, 0, - &led_devs[i], 1, - &led_resources[j], 0); - if (ret < 0) { - dev_err(chip->dev, "Failed to add " - "led subdev\n"); - return; - } + if (pdata && pdata->led) { + if (pdata->num_leds > ARRAY_SIZE(led_devs)) + pdata->num_leds = ARRAY_SIZE(led_devs); + for (i = 0; i < pdata->num_leds; i++) { + led_devs[i].platform_data = &pdata->led[i]; + led_devs[i].pdata_size = + sizeof(struct pm860x_led_pdata); } } + ret = mfd_add_devices(chip->dev, 0, led_devs, + ARRAY_SIZE(led_devs), NULL, 0); + if (ret < 0) { + dev_err(chip->dev, "Failed to add led subdev\n"); + return; + } } static void __devinit device_regulator_init(struct pm860x_chip *chip, -- cgit v1.2.2 From a70abacb06b884131ec181551a71ef325490f374 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Wed, 8 Aug 2012 23:17:28 +0800 Subject: mfd: 88pm860x: Use REG resource in regulator Since IORESOURCE_IO is changed to IORESOURCE_REG in 88pm860x driver, update self-defined IORESOURCE_IO resource to register offset that is IORESOURCE_REG in regulator driver. And split regulator platform data array into scattered platform data. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-core.c | 265 ++++++++++++++++++++++++++++++++----------- drivers/regulator/88pm8607.c | 5 +- 2 files changed, 201 insertions(+), 69 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index e364b22f957d..fca15be6c0d1 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -68,25 +68,53 @@ static struct resource led5_resources[] __devinitdata = { {0x8, 0x8, "blink", IORESOURCE_REG, }, }; -static struct resource regulator_resources[] __devinitdata = { - {PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_REG,}, - {PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_REG,}, - {PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_REG,}, - {PM8607_ID_LDO1, PM8607_ID_LDO1, "ldo-01", IORESOURCE_REG,}, - {PM8607_ID_LDO2, PM8607_ID_LDO2, "ldo-02", IORESOURCE_REG,}, - {PM8607_ID_LDO3, PM8607_ID_LDO3, "ldo-03", IORESOURCE_REG,}, - {PM8607_ID_LDO4, PM8607_ID_LDO4, "ldo-04", IORESOURCE_REG,}, - {PM8607_ID_LDO5, PM8607_ID_LDO5, "ldo-05", IORESOURCE_REG,}, - {PM8607_ID_LDO6, PM8607_ID_LDO6, "ldo-06", IORESOURCE_REG,}, - {PM8607_ID_LDO7, PM8607_ID_LDO7, "ldo-07", IORESOURCE_REG,}, - {PM8607_ID_LDO8, PM8607_ID_LDO8, "ldo-08", IORESOURCE_REG,}, - {PM8607_ID_LDO9, PM8607_ID_LDO9, "ldo-09", IORESOURCE_REG,}, - {PM8607_ID_LDO10, PM8607_ID_LDO10, "ldo-10", IORESOURCE_REG,}, - {PM8607_ID_LDO11, PM8607_ID_LDO11, "ldo-11", IORESOURCE_REG,}, - {PM8607_ID_LDO12, PM8607_ID_LDO12, "ldo-12", IORESOURCE_REG,}, - {PM8607_ID_LDO13, PM8607_ID_LDO13, "ldo-13", IORESOURCE_REG,}, - {PM8607_ID_LDO14, PM8607_ID_LDO14, "ldo-14", IORESOURCE_REG,}, - {PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_REG,}, +static struct resource buck1_resources[] __devinitdata = { + {0x24, 0x24, "buck set", IORESOURCE_REG, }, +}; +static struct resource buck2_resources[] __devinitdata = { + {0x25, 0x25, "buck set", IORESOURCE_REG, }, +}; +static struct resource buck3_resources[] __devinitdata = { + {0x26, 0x26, "buck set", IORESOURCE_REG, }, +}; +static struct resource ldo1_resources[] __devinitdata = { + {0x10, 0x10, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo2_resources[] __devinitdata = { + {0x11, 0x11, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo3_resources[] __devinitdata = { + {0x12, 0x12, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo4_resources[] __devinitdata = { + {0x13, 0x13, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo5_resources[] __devinitdata = { + {0x14, 0x14, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo6_resources[] __devinitdata = { + {0x15, 0x15, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo7_resources[] __devinitdata = { + {0x16, 0x16, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo8_resources[] __devinitdata = { + {0x17, 0x17, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo9_resources[] __devinitdata = { + {0x18, 0x18, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo10_resources[] __devinitdata = { + {0x19, 0x19, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo12_resources[] __devinitdata = { + {0x1a, 0x1a, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo_vibrator_resources[] __devinitdata = { + {0x28, 0x28, "ldo set", IORESOURCE_REG, }, +}; +static struct resource ldo14_resources[] __devinitdata = { + {0x1b, 0x1b, "ldo set", IORESOURCE_REG, }, }; static struct resource touch_resources[] __devinitdata = { @@ -183,25 +211,88 @@ static struct mfd_cell led_devs[] = { }, }; -static struct mfd_cell regulator_devs[] = { - {"88pm860x-regulator", 0,}, - {"88pm860x-regulator", 1,}, - {"88pm860x-regulator", 2,}, - {"88pm860x-regulator", 3,}, - {"88pm860x-regulator", 4,}, - {"88pm860x-regulator", 5,}, - {"88pm860x-regulator", 6,}, - {"88pm860x-regulator", 7,}, - {"88pm860x-regulator", 8,}, - {"88pm860x-regulator", 9,}, - {"88pm860x-regulator", 10,}, - {"88pm860x-regulator", 11,}, - {"88pm860x-regulator", 12,}, - {"88pm860x-regulator", 13,}, - {"88pm860x-regulator", 14,}, - {"88pm860x-regulator", 15,}, - {"88pm860x-regulator", 16,}, - {"88pm860x-regulator", 17,}, +static struct mfd_cell reg_devs[] = { + { + .name = "88pm860x-regulator", + .id = 0, + .num_resources = ARRAY_SIZE(buck1_resources), + .resources = buck1_resources, + }, { + .name = "88pm860x-regulator", + .id = 1, + .num_resources = ARRAY_SIZE(buck2_resources), + .resources = buck2_resources, + }, { + .name = "88pm860x-regulator", + .id = 2, + .num_resources = ARRAY_SIZE(buck3_resources), + .resources = buck3_resources, + }, { + .name = "88pm860x-regulator", + .id = 3, + .num_resources = ARRAY_SIZE(ldo1_resources), + .resources = ldo1_resources, + }, { + .name = "88pm860x-regulator", + .id = 4, + .num_resources = ARRAY_SIZE(ldo2_resources), + .resources = ldo2_resources, + }, { + .name = "88pm860x-regulator", + .id = 5, + .num_resources = ARRAY_SIZE(ldo3_resources), + .resources = ldo3_resources, + }, { + .name = "88pm860x-regulator", + .id = 6, + .num_resources = ARRAY_SIZE(ldo4_resources), + .resources = ldo4_resources, + }, { + .name = "88pm860x-regulator", + .id = 7, + .num_resources = ARRAY_SIZE(ldo5_resources), + .resources = ldo5_resources, + }, { + .name = "88pm860x-regulator", + .id = 8, + .num_resources = ARRAY_SIZE(ldo6_resources), + .resources = ldo6_resources, + }, { + .name = "88pm860x-regulator", + .id = 9, + .num_resources = ARRAY_SIZE(ldo7_resources), + .resources = ldo7_resources, + }, { + .name = "88pm860x-regulator", + .id = 10, + .num_resources = ARRAY_SIZE(ldo8_resources), + .resources = ldo8_resources, + }, { + .name = "88pm860x-regulator", + .id = 11, + .num_resources = ARRAY_SIZE(ldo9_resources), + .resources = ldo9_resources, + }, { + .name = "88pm860x-regulator", + .id = 12, + .num_resources = ARRAY_SIZE(ldo10_resources), + .resources = ldo10_resources, + }, { + .name = "88pm860x-regulator", + .id = 13, + .num_resources = ARRAY_SIZE(ldo12_resources), + .resources = ldo12_resources, + }, { + .name = "88pm860x-regulator", + .id = 14, + .num_resources = ARRAY_SIZE(ldo_vibrator_resources), + .resources = ldo_vibrator_resources, + }, { + .name = "88pm860x-regulator", + .id = 15, + .num_resources = ARRAY_SIZE(ldo14_resources), + .resources = ldo14_resources, + }, }; static struct mfd_cell touch_devs[] = { @@ -727,38 +818,80 @@ static void __devinit device_led_init(struct pm860x_chip *chip, static void __devinit device_regulator_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { - struct regulator_init_data *initdata; int ret; - int i, seq; - if ((pdata == NULL) || (pdata->regulator == NULL)) + if (pdata == NULL) + return; + if (pdata->buck1) { + reg_devs[0].platform_data = pdata->buck1; + reg_devs[0].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->buck2) { + reg_devs[1].platform_data = pdata->buck2; + reg_devs[1].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->buck3) { + reg_devs[2].platform_data = pdata->buck3; + reg_devs[2].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo1) { + reg_devs[3].platform_data = pdata->ldo1; + reg_devs[3].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo2) { + reg_devs[4].platform_data = pdata->ldo2; + reg_devs[4].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo3) { + reg_devs[5].platform_data = pdata->ldo3; + reg_devs[5].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo4) { + reg_devs[6].platform_data = pdata->ldo4; + reg_devs[6].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo5) { + reg_devs[7].platform_data = pdata->ldo5; + reg_devs[7].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo6) { + reg_devs[8].platform_data = pdata->ldo6; + reg_devs[8].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo7) { + reg_devs[9].platform_data = pdata->ldo7; + reg_devs[9].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo8) { + reg_devs[10].platform_data = pdata->ldo8; + reg_devs[10].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo9) { + reg_devs[11].platform_data = pdata->ldo9; + reg_devs[11].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo10) { + reg_devs[12].platform_data = pdata->ldo10; + reg_devs[12].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo12) { + reg_devs[13].platform_data = pdata->ldo12; + reg_devs[13].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo_vibrator) { + reg_devs[14].platform_data = pdata->ldo_vibrator; + reg_devs[14].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo14) { + reg_devs[15].platform_data = pdata->ldo14; + reg_devs[15].pdata_size = sizeof(struct regulator_init_data); + } + ret = mfd_add_devices(chip->dev, 0, reg_devs, + ARRAY_SIZE(reg_devs), NULL, 0); + if (ret < 0) { + dev_err(chip->dev, "Failed to add regulator subdev\n"); return; - - if (pdata->num_regulators > ARRAY_SIZE(regulator_devs)) - pdata->num_regulators = ARRAY_SIZE(regulator_devs); - - for (i = 0, seq = -1; i < pdata->num_regulators; i++) { - initdata = &pdata->regulator[i]; - seq = *(unsigned int *)initdata->driver_data; - if ((seq < 0) || (seq > PM8607_ID_RG_MAX)) { - dev_err(chip->dev, "Wrong ID(%d) on regulator(%s)\n", - seq, initdata->constraints.name); - goto out; - } - regulator_devs[i].platform_data = &pdata->regulator[i]; - regulator_devs[i].pdata_size = sizeof(struct regulator_init_data); - regulator_devs[i].num_resources = 1; - regulator_devs[i].resources = ®ulator_resources[seq]; - - ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[i], 1, - ®ulator_resources[seq], 0); - if (ret < 0) { - dev_err(chip->dev, "Failed to add regulator subdev\n"); - goto out; - } } -out: - return; } static void __devinit device_rtc_init(struct pm860x_chip *chip, diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index 0b76372aee72..843c89a15472 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -322,12 +322,12 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_REG, 0); if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource!\n"); + dev_err(&pdev->dev, "No REG resource!\n"); return -EINVAL; } for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) { info = &pm8607_regulator_info[i]; - if (info->desc.id == res->start) + if (info->desc.vsel_reg == res->start) break; } if (i == ARRAY_SIZE(pm8607_regulator_info)) { @@ -351,7 +351,6 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) else config.regmap = chip->regmap_companion; - /* replace driver_data with info */ info->regulator = regulator_register(&info->desc, &config); if (IS_ERR(info->regulator)) { dev_err(&pdev->dev, "failed to register regulator %s\n", -- cgit v1.2.2 From 92d801390c1d0659fd52008336ae9daebdfd7509 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 7 Aug 2012 19:57:53 +0100 Subject: mfd: arizona: Disable control interface error reporting for early devices Early revisions of the initial Arizona-based devices can generate spurious control interface errors in certain circumstances. Avoid causing confusion by disabling the control interface error reporting on these devices. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/arizona-irq.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index 98ac345f468e..64940c6da93c 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -156,18 +156,35 @@ int arizona_irq_init(struct arizona *arizona) int flags = IRQF_ONESHOT; int ret, i; const struct regmap_irq_chip *aod, *irq; + bool ctrlif_error = true; switch (arizona->type) { #ifdef CONFIG_MFD_WM5102 case WM5102: aod = &wm5102_aod; irq = &wm5102_irq; + + switch (arizona->rev) { + case 0: + ctrlif_error = false; + break; + default: + break; + } break; #endif #ifdef CONFIG_MFD_WM5110 case WM5110: aod = &wm5110_aod; irq = &wm5110_irq; + + switch (arizona->rev) { + case 0: + ctrlif_error = false; + break; + default: + break; + } break; #endif default: @@ -226,13 +243,17 @@ int arizona_irq_init(struct arizona *arizona) } /* Handle control interface errors in the core */ - i = arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR); - ret = request_threaded_irq(i, NULL, arizona_ctrlif_err, IRQF_ONESHOT, - "Control interface error", arizona); - if (ret != 0) { - dev_err(arizona->dev, "Failed to request boot done %d: %d\n", - arizona->irq, ret); - goto err_ctrlif; + if (ctrlif_error) { + i = arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR); + ret = request_threaded_irq(i, NULL, arizona_ctrlif_err, + IRQF_ONESHOT, + "Control interface error", arizona); + if (ret != 0) { + dev_err(arizona->dev, + "Failed to request CTRLIF_ERR %d: %d\n", + arizona->irq, ret); + goto err_ctrlif; + } } ret = request_threaded_irq(arizona->irq, NULL, arizona_irq_thread, -- cgit v1.2.2 From 55692af5eb587f7592d6c2713e1e0eeaab0f6c31 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 11 Sep 2012 15:16:36 +0800 Subject: mfd: core: Push irqdomain mapping out into devices Currently the MFD core supports remapping MFD cell interrupts using an irqdomain but only if the MFD is being instantiated using device tree and only if the device tree bindings use the pattern of registering IPs in the device tree with compatible properties. This will be actively harmful for drivers which support non-DT platforms and use this pattern for their DT bindings as it will mean that the core will silently change remapping behaviour and it is also limiting for drivers which don't do DT with this particular pattern. There is also a potential fragility if there are interrupts not associated with MFD cells and all the cells are omitted from the device tree for some reason. Instead change the code to take an IRQ domain as an optional argument, allowing drivers to take the decision about the parent domain for their interrupts. The one current user of this feature is ab8500-core, it has the domain lookup pushed out into the driver. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm800.c | 5 +++-- drivers/mfd/88pm805.c | 3 ++- drivers/mfd/88pm860x-core.c | 21 +++++++++++---------- drivers/mfd/aat2870-core.c | 2 +- drivers/mfd/ab3100-core.c | 2 +- drivers/mfd/ab8500-core.c | 10 +++++----- drivers/mfd/arizona-core.c | 6 +++--- drivers/mfd/asic3.c | 6 +++--- drivers/mfd/cs5535-mfd.c | 2 +- drivers/mfd/da9052-core.c | 2 +- drivers/mfd/davinci_voicecodec.c | 2 +- drivers/mfd/db8500-prcmu.c | 2 +- drivers/mfd/htc-pasic3.c | 5 +++-- drivers/mfd/intel_msic.c | 4 ++-- drivers/mfd/janz-cmodio.c | 2 +- drivers/mfd/jz4740-adc.c | 3 ++- drivers/mfd/lm3533-core.c | 7 ++++--- drivers/mfd/lpc_ich.c | 4 ++-- drivers/mfd/lpc_sch.c | 6 ++++-- drivers/mfd/max77686.c | 2 +- drivers/mfd/max77693.c | 2 +- drivers/mfd/max8925-core.c | 12 ++++++------ drivers/mfd/max8997.c | 2 +- drivers/mfd/max8998.c | 8 ++++---- drivers/mfd/mc13xxx-core.c | 2 +- drivers/mfd/mfd-core.c | 12 ++++++------ drivers/mfd/palmas.c | 3 ++- drivers/mfd/rc5t583.c | 2 +- drivers/mfd/rdc321x-southbridge.c | 3 ++- drivers/mfd/sec-core.c | 8 ++++---- drivers/mfd/sta2x11-mfd.c | 4 ++-- drivers/mfd/stmpe.c | 2 +- drivers/mfd/t7l66xb.c | 2 +- drivers/mfd/tc3589x.c | 8 ++++---- drivers/mfd/tc6387xb.c | 2 +- drivers/mfd/tc6393xb.c | 4 ++-- drivers/mfd/ti-ssp.c | 2 +- drivers/mfd/timberdale.c | 12 ++++++------ drivers/mfd/tps6105x.c | 2 +- drivers/mfd/tps6507x.c | 2 +- drivers/mfd/tps65090.c | 2 +- drivers/mfd/tps65217.c | 2 +- drivers/mfd/tps6586x.c | 3 ++- drivers/mfd/tps65910.c | 2 +- drivers/mfd/tps65912-core.c | 2 +- drivers/mfd/twl4030-audio.c | 2 +- drivers/mfd/twl6040-core.c | 2 +- drivers/mfd/vx855.c | 2 +- drivers/mfd/wl1273-core.c | 2 +- drivers/mfd/wm831x-core.c | 16 ++++++++-------- drivers/mfd/wm8400-core.c | 2 +- drivers/mfd/wm8994-core.c | 4 ++-- drivers/staging/nvec/nvec.c | 2 +- 53 files changed, 122 insertions(+), 111 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c index b67a3018b136..ce229ea933d1 100644 --- a/drivers/mfd/88pm800.c +++ b/drivers/mfd/88pm800.c @@ -470,7 +470,8 @@ static int __devinit device_800_init(struct pm80x_chip *chip, ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0], - ARRAY_SIZE(onkey_devs), &onkey_resources[0], 0); + ARRAY_SIZE(onkey_devs), &onkey_resources[0], 0, + NULL); if (ret < 0) { dev_err(chip->dev, "Failed to add onkey subdev\n"); goto out_dev; @@ -481,7 +482,7 @@ static int __devinit device_800_init(struct pm80x_chip *chip, rtc_devs[0].platform_data = pdata->rtc; rtc_devs[0].pdata_size = sizeof(struct pm80x_rtc_pdata); ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0], - ARRAY_SIZE(rtc_devs), NULL, 0); + ARRAY_SIZE(rtc_devs), NULL, 0, NULL); if (ret < 0) { dev_err(chip->dev, "Failed to add rtc subdev\n"); goto out_dev; diff --git a/drivers/mfd/88pm805.c b/drivers/mfd/88pm805.c index 6146583589f6..c20a31136f04 100644 --- a/drivers/mfd/88pm805.c +++ b/drivers/mfd/88pm805.c @@ -216,7 +216,8 @@ static int __devinit device_805_init(struct pm80x_chip *chip) } ret = mfd_add_devices(chip->dev, 0, &codec_devs[0], - ARRAY_SIZE(codec_devs), &codec_resources[0], 0); + ARRAY_SIZE(codec_devs), &codec_resources[0], 0, + NULL); if (ret < 0) { dev_err(chip->dev, "Failed to add codec subdev\n"); goto out_codec; diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index fca15be6c0d1..4927f4efcf9d 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -788,7 +788,7 @@ static void __devinit device_bk_init(struct pm860x_chip *chip, } } ret = mfd_add_devices(chip->dev, 0, bk_devs, - ARRAY_SIZE(bk_devs), NULL, 0); + ARRAY_SIZE(bk_devs), NULL, 0, NULL); if (ret < 0) dev_err(chip->dev, "Failed to add backlight subdev\n"); } @@ -808,7 +808,7 @@ static void __devinit device_led_init(struct pm860x_chip *chip, } } ret = mfd_add_devices(chip->dev, 0, led_devs, - ARRAY_SIZE(led_devs), NULL, 0); + ARRAY_SIZE(led_devs), NULL, 0, NULL); if (ret < 0) { dev_err(chip->dev, "Failed to add led subdev\n"); return; @@ -887,7 +887,7 @@ static void __devinit device_regulator_init(struct pm860x_chip *chip, reg_devs[15].pdata_size = sizeof(struct regulator_init_data); } ret = mfd_add_devices(chip->dev, 0, reg_devs, - ARRAY_SIZE(reg_devs), NULL, 0); + ARRAY_SIZE(reg_devs), NULL, 0, NULL); if (ret < 0) { dev_err(chip->dev, "Failed to add regulator subdev\n"); return; @@ -908,7 +908,7 @@ static void __devinit device_rtc_init(struct pm860x_chip *chip, rtc_devs[0].resources = &rtc_resources[0]; ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0], ARRAY_SIZE(rtc_devs), &rtc_resources[0], - chip->irq_base); + chip->irq_base, NULL); if (ret < 0) dev_err(chip->dev, "Failed to add rtc subdev\n"); } @@ -927,7 +927,7 @@ static void __devinit device_touch_init(struct pm860x_chip *chip, touch_devs[0].resources = &touch_resources[0]; ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], ARRAY_SIZE(touch_devs), &touch_resources[0], - chip->irq_base); + chip->irq_base, NULL); if (ret < 0) dev_err(chip->dev, "Failed to add touch subdev\n"); } @@ -945,7 +945,7 @@ static void __devinit device_power_init(struct pm860x_chip *chip, power_devs[0].num_resources = ARRAY_SIZE(battery_resources); power_devs[0].resources = &battery_resources[0], ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1, - &battery_resources[0], chip->irq_base); + &battery_resources[0], chip->irq_base, NULL); if (ret < 0) dev_err(chip->dev, "Failed to add battery subdev\n"); @@ -954,7 +954,7 @@ static void __devinit device_power_init(struct pm860x_chip *chip, power_devs[1].num_resources = ARRAY_SIZE(charger_resources); power_devs[1].resources = &charger_resources[0], ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1, - &charger_resources[0], chip->irq_base); + &charger_resources[0], chip->irq_base, NULL); if (ret < 0) dev_err(chip->dev, "Failed to add charger subdev\n"); @@ -963,7 +963,7 @@ static void __devinit device_power_init(struct pm860x_chip *chip, power_devs[2].num_resources = ARRAY_SIZE(preg_resources); power_devs[2].resources = &preg_resources[0], ret = mfd_add_devices(chip->dev, 0, &power_devs[2], 1, - &preg_resources[0], chip->irq_base); + &preg_resources[0], chip->irq_base, NULL); if (ret < 0) dev_err(chip->dev, "Failed to add preg subdev\n"); } @@ -977,7 +977,7 @@ static void __devinit device_onkey_init(struct pm860x_chip *chip, onkey_devs[0].resources = &onkey_resources[0], ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0], ARRAY_SIZE(onkey_devs), &onkey_resources[0], - chip->irq_base); + chip->irq_base, NULL); if (ret < 0) dev_err(chip->dev, "Failed to add onkey subdev\n"); } @@ -990,7 +990,8 @@ static void __devinit device_codec_init(struct pm860x_chip *chip, codec_devs[0].num_resources = ARRAY_SIZE(codec_resources); codec_devs[0].resources = &codec_resources[0], ret = mfd_add_devices(chip->dev, 0, &codec_devs[0], - ARRAY_SIZE(codec_devs), &codec_resources[0], 0); + ARRAY_SIZE(codec_devs), &codec_resources[0], 0, + NULL); if (ret < 0) dev_err(chip->dev, "Failed to add codec subdev\n"); } diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c index 44a3fdbadef4..f1beb4971f87 100644 --- a/drivers/mfd/aat2870-core.c +++ b/drivers/mfd/aat2870-core.c @@ -424,7 +424,7 @@ static int aat2870_i2c_probe(struct i2c_client *client, } ret = mfd_add_devices(aat2870->dev, 0, aat2870_devs, - ARRAY_SIZE(aat2870_devs), NULL, 0); + ARRAY_SIZE(aat2870_devs), NULL, 0, NULL); if (ret != 0) { dev_err(aat2870->dev, "Failed to add subdev: %d\n", ret); goto out_disable; diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 78fca2902c8d..01781ae5d0d7 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -946,7 +946,7 @@ static int __devinit ab3100_probe(struct i2c_client *client, } err = mfd_add_devices(&client->dev, 0, ab3100_devs, - ARRAY_SIZE(ab3100_devs), NULL, 0); + ARRAY_SIZE(ab3100_devs), NULL, 0, NULL); ab3100_setup_debugfs(ab3100); diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 626b4ecaf647..47adf800024e 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -1418,25 +1418,25 @@ static int __devinit ab8500_probe(struct platform_device *pdev) ret = mfd_add_devices(ab8500->dev, 0, abx500_common_devs, ARRAY_SIZE(abx500_common_devs), NULL, - ab8500->irq_base); + ab8500->irq_base, ab8500->domain); if (ret) goto out_freeirq; if (is_ab9540(ab8500)) ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, ARRAY_SIZE(ab9540_devs), NULL, - ab8500->irq_base); + ab8500->irq_base, ab8500->domain); else ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs, ARRAY_SIZE(ab8500_devs), NULL, - ab8500->irq_base); + ab8500->irq_base, ab8500->domain); if (ret) goto out_freeirq; if (is_ab9540(ab8500) || is_ab8505(ab8500)) ret = mfd_add_devices(ab8500->dev, 0, ab9540_ab8505_devs, ARRAY_SIZE(ab9540_ab8505_devs), NULL, - ab8500->irq_base); + ab8500->irq_base, ab8500->domain); if (ret) goto out_freeirq; @@ -1444,7 +1444,7 @@ static int __devinit ab8500_probe(struct platform_device *pdev) /* Add battery management devices */ ret = mfd_add_devices(ab8500->dev, 0, ab8500_bm_devs, ARRAY_SIZE(ab8500_bm_devs), NULL, - ab8500->irq_base); + ab8500->irq_base, ab8500->domain); if (ret) dev_err(ab8500->dev, "error adding bm devices\n"); } diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index c7983e862549..1b48f2094806 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -316,7 +316,7 @@ int __devinit arizona_dev_init(struct arizona *arizona) } ret = mfd_add_devices(arizona->dev, -1, early_devs, - ARRAY_SIZE(early_devs), NULL, 0); + ARRAY_SIZE(early_devs), NULL, 0, NULL); if (ret != 0) { dev_err(dev, "Failed to add early children: %d\n", ret); return ret; @@ -516,11 +516,11 @@ int __devinit arizona_dev_init(struct arizona *arizona) switch (arizona->type) { case WM5102: ret = mfd_add_devices(arizona->dev, -1, wm5102_devs, - ARRAY_SIZE(wm5102_devs), NULL, 0); + ARRAY_SIZE(wm5102_devs), NULL, 0, NULL); break; case WM5110: ret = mfd_add_devices(arizona->dev, -1, wm5110_devs, - ARRAY_SIZE(wm5102_devs), NULL, 0); + ARRAY_SIZE(wm5102_devs), NULL, 0, NULL); break; } diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 683e18a23329..62f0883a7630 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -913,14 +913,14 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, if (pdata->clock_rate) { ds1wm_pdata.clock_rate = pdata->clock_rate; ret = mfd_add_devices(&pdev->dev, pdev->id, - &asic3_cell_ds1wm, 1, mem, asic->irq_base); + &asic3_cell_ds1wm, 1, mem, asic->irq_base, NULL); if (ret < 0) goto out; } if (mem_sdio && (irq >= 0)) { ret = mfd_add_devices(&pdev->dev, pdev->id, - &asic3_cell_mmc, 1, mem_sdio, irq); + &asic3_cell_mmc, 1, mem_sdio, irq, NULL); if (ret < 0) goto out; } @@ -934,7 +934,7 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, asic3_cell_leds[i].pdata_size = sizeof(pdata->leds[i]); } ret = mfd_add_devices(&pdev->dev, 0, - asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0); + asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0, NULL); } out: diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c index 3419e726de47..2b282133c725 100644 --- a/drivers/mfd/cs5535-mfd.c +++ b/drivers/mfd/cs5535-mfd.c @@ -149,7 +149,7 @@ static int __devinit cs5535_mfd_probe(struct pci_dev *pdev, } err = mfd_add_devices(&pdev->dev, -1, cs5535_mfd_cells, - ARRAY_SIZE(cs5535_mfd_cells), NULL, 0); + ARRAY_SIZE(cs5535_mfd_cells), NULL, 0, NULL); if (err) { dev_err(&pdev->dev, "MFD add devices failed: %d\n", err); goto err_disable; diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c index 2544910e1fd6..a0a62b24621b 100644 --- a/drivers/mfd/da9052-core.c +++ b/drivers/mfd/da9052-core.c @@ -803,7 +803,7 @@ int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id) dev_err(da9052->dev, "DA9052 ADC IRQ failed ret=%d\n", ret); ret = mfd_add_devices(da9052->dev, -1, da9052_subdev_info, - ARRAY_SIZE(da9052_subdev_info), NULL, 0); + ARRAY_SIZE(da9052_subdev_info), NULL, 0, NULL); if (ret) goto err; diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c index 4e2af2cb2d26..45e83a68641b 100644 --- a/drivers/mfd/davinci_voicecodec.c +++ b/drivers/mfd/davinci_voicecodec.c @@ -129,7 +129,7 @@ static int __init davinci_vc_probe(struct platform_device *pdev) cell->pdata_size = sizeof(*davinci_vc); ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells, - DAVINCI_VC_CELLS, NULL, 0); + DAVINCI_VC_CELLS, NULL, 0, NULL); if (ret != 0) { dev_err(&pdev->dev, "fail to register client devices\n"); goto fail4; diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 7040a0081130..0e63cdd9b52a 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -3010,7 +3010,7 @@ static int __devinit db8500_prcmu_probe(struct platform_device *pdev) prcmu_config_esram0_deep_sleep(ESRAM0_DEEP_SLEEP_STATE_RET); err = mfd_add_devices(&pdev->dev, 0, db8500_prcmu_devs, - ARRAY_SIZE(db8500_prcmu_devs), NULL, 0); + ARRAY_SIZE(db8500_prcmu_devs), NULL, 0, NULL); if (err) { pr_err("prcmu: Failed to add subdevices\n"); return err; diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c index 04c7093d6499..9e5453d21a68 100644 --- a/drivers/mfd/htc-pasic3.c +++ b/drivers/mfd/htc-pasic3.c @@ -168,7 +168,7 @@ static int __init pasic3_probe(struct platform_device *pdev) /* the first 5 PASIC3 registers control the DS1WM */ ds1wm_resources[0].end = (5 << asic->bus_shift) - 1; ret = mfd_add_devices(&pdev->dev, pdev->id, - &ds1wm_cell, 1, r, irq); + &ds1wm_cell, 1, r, irq, NULL); if (ret < 0) dev_warn(dev, "failed to register DS1WM\n"); } @@ -176,7 +176,8 @@ static int __init pasic3_probe(struct platform_device *pdev) if (pdata && pdata->led_pdata) { led_cell.platform_data = pdata->led_pdata; led_cell.pdata_size = sizeof(struct pasic3_leds_machinfo); - ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r, 0); + ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r, + 0, NULL); if (ret < 0) dev_warn(dev, "failed to register LED device\n"); } diff --git a/drivers/mfd/intel_msic.c b/drivers/mfd/intel_msic.c index 59df5584cb58..266bdc5bd96d 100644 --- a/drivers/mfd/intel_msic.c +++ b/drivers/mfd/intel_msic.c @@ -344,13 +344,13 @@ static int __devinit intel_msic_init_devices(struct intel_msic *msic) continue; ret = mfd_add_devices(&pdev->dev, -1, &msic_devs[i], 1, NULL, - pdata->irq[i]); + pdata->irq[i], NULL); if (ret) goto fail; } ret = mfd_add_devices(&pdev->dev, 0, msic_other_devs, - ARRAY_SIZE(msic_other_devs), NULL, 0); + ARRAY_SIZE(msic_other_devs), NULL, 0, NULL); if (ret) goto fail; diff --git a/drivers/mfd/janz-cmodio.c b/drivers/mfd/janz-cmodio.c index 2ea99989551a..965c4801df8a 100644 --- a/drivers/mfd/janz-cmodio.c +++ b/drivers/mfd/janz-cmodio.c @@ -147,7 +147,7 @@ static int __devinit cmodio_probe_submodules(struct cmodio_device *priv) } return mfd_add_devices(&pdev->dev, 0, priv->cells, - num_probed, NULL, pdev->irq); + num_probed, NULL, pdev->irq, NULL); } /* diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index 87662a17dec6..c6b6d7dda517 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c @@ -287,7 +287,8 @@ static int __devinit jz4740_adc_probe(struct platform_device *pdev) writeb(0xff, adc->base + JZ_REG_ADC_CTRL); ret = mfd_add_devices(&pdev->dev, 0, jz4740_adc_cells, - ARRAY_SIZE(jz4740_adc_cells), mem_base, irq_base); + ARRAY_SIZE(jz4740_adc_cells), mem_base, + irq_base, NULL); if (ret < 0) goto err_clk_put; diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c index 0b2879b87fd9..24212f45b201 100644 --- a/drivers/mfd/lm3533-core.c +++ b/drivers/mfd/lm3533-core.c @@ -393,7 +393,8 @@ static int __devinit lm3533_device_als_init(struct lm3533 *lm3533) lm3533_als_devs[0].platform_data = pdata->als; lm3533_als_devs[0].pdata_size = sizeof(*pdata->als); - ret = mfd_add_devices(lm3533->dev, 0, lm3533_als_devs, 1, NULL, 0); + ret = mfd_add_devices(lm3533->dev, 0, lm3533_als_devs, 1, NULL, + 0, NULL); if (ret) { dev_err(lm3533->dev, "failed to add ALS device\n"); return ret; @@ -422,7 +423,7 @@ static int __devinit lm3533_device_bl_init(struct lm3533 *lm3533) } ret = mfd_add_devices(lm3533->dev, 0, lm3533_bl_devs, - pdata->num_backlights, NULL, 0); + pdata->num_backlights, NULL, 0, NULL); if (ret) { dev_err(lm3533->dev, "failed to add backlight devices\n"); return ret; @@ -451,7 +452,7 @@ static int __devinit lm3533_device_led_init(struct lm3533 *lm3533) } ret = mfd_add_devices(lm3533->dev, 0, lm3533_led_devs, - pdata->num_leds, NULL, 0); + pdata->num_leds, NULL, 0, NULL); if (ret) { dev_err(lm3533->dev, "failed to add LED devices\n"); return ret; diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index a05fdfc2ebcf..092ad4b44b6d 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -750,7 +750,7 @@ gpe0_done: lpc_ich_finalize_cell(&lpc_ich_cells[LPC_GPIO], id); ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_GPIO], - 1, NULL, 0); + 1, NULL, 0, NULL); gpio_done: if (acpi_conflict) @@ -807,7 +807,7 @@ static int __devinit lpc_ich_init_wdt(struct pci_dev *dev, lpc_ich_finalize_cell(&lpc_ich_cells[LPC_WDT], id); ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_WDT], - 1, NULL, 0); + 1, NULL, 0, NULL); wdt_done: return ret; diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c index 9f20abc5e393..f6b9c5c96b24 100644 --- a/drivers/mfd/lpc_sch.c +++ b/drivers/mfd/lpc_sch.c @@ -127,7 +127,8 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev, lpc_sch_cells[i].id = id->device; ret = mfd_add_devices(&dev->dev, 0, - lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, 0); + lpc_sch_cells, ARRAY_SIZE(lpc_sch_cells), NULL, + 0, NULL); if (ret) goto out_dev; @@ -153,7 +154,8 @@ static int __devinit lpc_sch_probe(struct pci_dev *dev, tunnelcreek_cells[i].id = id->device; ret = mfd_add_devices(&dev->dev, 0, tunnelcreek_cells, - ARRAY_SIZE(tunnelcreek_cells), NULL, 0); + ARRAY_SIZE(tunnelcreek_cells), NULL, + 0, NULL); } return ret; diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index c03e12b51924..d9e24c849a00 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -126,7 +126,7 @@ static int max77686_i2c_probe(struct i2c_client *i2c, max77686_irq_init(max77686); ret = mfd_add_devices(max77686->dev, -1, max77686_devs, - ARRAY_SIZE(max77686_devs), NULL, 0); + ARRAY_SIZE(max77686_devs), NULL, 0, NULL); if (ret < 0) goto err_mfd; diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c index a1811cb50ec7..4fdd03d28539 100644 --- a/drivers/mfd/max77693.c +++ b/drivers/mfd/max77693.c @@ -159,7 +159,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c, pm_runtime_set_active(max77693->dev); ret = mfd_add_devices(max77693->dev, -1, max77693_devs, - ARRAY_SIZE(max77693_devs), NULL, 0); + ARRAY_SIZE(max77693_devs), NULL, 0, NULL); if (ret < 0) goto err_mfd; diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index 08a57231c25b..f2ff31f3a2f0 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -598,7 +598,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip, ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0], ARRAY_SIZE(rtc_devs), - &rtc_resources[0], chip->irq_base); + &rtc_resources[0], chip->irq_base, NULL); if (ret < 0) { dev_err(chip->dev, "Failed to add rtc subdev\n"); goto out; @@ -606,7 +606,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip, ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0], ARRAY_SIZE(onkey_devs), - &onkey_resources[0], 0); + &onkey_resources[0], 0, NULL); if (ret < 0) { dev_err(chip->dev, "Failed to add onkey subdev\n"); goto out_dev; @@ -615,7 +615,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip, if (pdata) { ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0], ARRAY_SIZE(regulator_devs), - ®ulator_resources[0], 0); + ®ulator_resources[0], 0, NULL); if (ret < 0) { dev_err(chip->dev, "Failed to add regulator subdev\n"); goto out_dev; @@ -625,7 +625,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip, if (pdata && pdata->backlight) { ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0], ARRAY_SIZE(backlight_devs), - &backlight_resources[0], 0); + &backlight_resources[0], 0, NULL); if (ret < 0) { dev_err(chip->dev, "Failed to add backlight subdev\n"); goto out_dev; @@ -635,7 +635,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip, if (pdata && pdata->power) { ret = mfd_add_devices(chip->dev, 0, &power_devs[0], ARRAY_SIZE(power_devs), - &power_supply_resources[0], 0); + &power_supply_resources[0], 0, NULL); if (ret < 0) { dev_err(chip->dev, "Failed to add power supply " "subdev\n"); @@ -646,7 +646,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip, if (pdata && pdata->touch) { ret = mfd_add_devices(chip->dev, 0, &touch_devs[0], ARRAY_SIZE(touch_devs), - &touch_resources[0], 0); + &touch_resources[0], 0, NULL); if (ret < 0) { dev_err(chip->dev, "Failed to add touch subdev\n"); goto out_dev; diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c index 10b629c245b6..f123517065ec 100644 --- a/drivers/mfd/max8997.c +++ b/drivers/mfd/max8997.c @@ -160,7 +160,7 @@ static int max8997_i2c_probe(struct i2c_client *i2c, mfd_add_devices(max8997->dev, -1, max8997_devs, ARRAY_SIZE(max8997_devs), - NULL, 0); + NULL, 0, NULL); /* * TODO: enable others (flash, muic, rtc, battery, ...) and diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index 6ef56d28c056..d7218cc90945 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c @@ -161,13 +161,13 @@ static int max8998_i2c_probe(struct i2c_client *i2c, switch (id->driver_data) { case TYPE_LP3974: ret = mfd_add_devices(max8998->dev, -1, - lp3974_devs, ARRAY_SIZE(lp3974_devs), - NULL, 0); + lp3974_devs, ARRAY_SIZE(lp3974_devs), + NULL, 0, NULL); break; case TYPE_MAX8998: ret = mfd_add_devices(max8998->dev, -1, - max8998_devs, ARRAY_SIZE(max8998_devs), - NULL, 0); + max8998_devs, ARRAY_SIZE(max8998_devs), + NULL, 0, NULL); break; default: ret = -EINVAL; diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index b801dc72f041..1ec79b54bd2f 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -612,7 +612,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, if (!cell.name) return -ENOMEM; - return mfd_add_devices(mc13xxx->dev, -1, &cell, 1, NULL, 0); + return mfd_add_devices(mc13xxx->dev, -1, &cell, 1, NULL, 0, NULL); } static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format) diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 0c3a01cde2f7..f8b77711ad2d 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -74,12 +74,11 @@ static int mfd_platform_add_cell(struct platform_device *pdev, static int mfd_add_device(struct device *parent, int id, const struct mfd_cell *cell, struct resource *mem_base, - int irq_base) + int irq_base, struct irq_domain *domain) { struct resource *res; struct platform_device *pdev; struct device_node *np = NULL; - struct irq_domain *domain = NULL; int ret = -ENOMEM; int r; @@ -97,7 +96,6 @@ static int mfd_add_device(struct device *parent, int id, for_each_child_of_node(parent->of_node, np) { if (of_device_is_compatible(np, cell->of_compatible)) { pdev->dev.of_node = np; - domain = irq_find_host(parent->of_node); break; } } @@ -177,7 +175,7 @@ fail_alloc: int mfd_add_devices(struct device *parent, int id, struct mfd_cell *cells, int n_devs, struct resource *mem_base, - int irq_base) + int irq_base, struct irq_domain *domain) { int i; int ret = 0; @@ -191,7 +189,8 @@ int mfd_add_devices(struct device *parent, int id, for (i = 0; i < n_devs; i++) { atomic_set(&cnts[i], 0); cells[i].usage_count = &cnts[i]; - ret = mfd_add_device(parent, id, cells + i, mem_base, irq_base); + ret = mfd_add_device(parent, id, cells + i, mem_base, + irq_base, domain); if (ret) break; } @@ -247,7 +246,8 @@ int mfd_clone_cell(const char *cell, const char **clones, size_t n_clones) for (i = 0; i < n_clones; i++) { cell_entry.name = clones[i]; /* don't give up if a single call fails; just report error */ - if (mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0)) + if (mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0, + NULL)) dev_err(dev, "failed to create platform device '%s'\n", clones[i]); } diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index c4a69f193a1d..a345f9bb7b47 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c @@ -453,7 +453,8 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c, ret = mfd_add_devices(palmas->dev, -1, children, ARRAY_SIZE(palmas_children), - NULL, regmap_irq_chip_get_base(palmas->irq_data)); + NULL, regmap_irq_chip_get_base(palmas->irq_data), + NULL); kfree(children); if (ret < 0) diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c index cdc1df7fa0e9..3a8fa88567b1 100644 --- a/drivers/mfd/rc5t583.c +++ b/drivers/mfd/rc5t583.c @@ -289,7 +289,7 @@ static int __devinit rc5t583_i2c_probe(struct i2c_client *i2c, } ret = mfd_add_devices(rc5t583->dev, -1, rc5t583_subdevs, - ARRAY_SIZE(rc5t583_subdevs), NULL, 0); + ARRAY_SIZE(rc5t583_subdevs), NULL, 0, NULL); if (ret) { dev_err(&i2c->dev, "add mfd devices failed: %d\n", ret); goto err_add_devs; diff --git a/drivers/mfd/rdc321x-southbridge.c b/drivers/mfd/rdc321x-southbridge.c index 685d61e431ad..0f70dce61160 100644 --- a/drivers/mfd/rdc321x-southbridge.c +++ b/drivers/mfd/rdc321x-southbridge.c @@ -87,7 +87,8 @@ static int __devinit rdc321x_sb_probe(struct pci_dev *pdev, rdc321x_wdt_pdata.sb_pdev = pdev; return mfd_add_devices(&pdev->dev, -1, - rdc321x_sb_cells, ARRAY_SIZE(rdc321x_sb_cells), NULL, 0); + rdc321x_sb_cells, ARRAY_SIZE(rdc321x_sb_cells), + NULL, 0, NULL); } static void __devexit rdc321x_sb_remove(struct pci_dev *pdev) diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 2988efde11eb..49d361a618d0 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -141,19 +141,19 @@ static int sec_pmic_probe(struct i2c_client *i2c, switch (sec_pmic->device_type) { case S5M8751X: ret = mfd_add_devices(sec_pmic->dev, -1, s5m8751_devs, - ARRAY_SIZE(s5m8751_devs), NULL, 0); + ARRAY_SIZE(s5m8751_devs), NULL, 0, NULL); break; case S5M8763X: ret = mfd_add_devices(sec_pmic->dev, -1, s5m8763_devs, - ARRAY_SIZE(s5m8763_devs), NULL, 0); + ARRAY_SIZE(s5m8763_devs), NULL, 0, NULL); break; case S5M8767X: ret = mfd_add_devices(sec_pmic->dev, -1, s5m8767_devs, - ARRAY_SIZE(s5m8767_devs), NULL, 0); + ARRAY_SIZE(s5m8767_devs), NULL, 0, NULL); break; case S2MPS11X: ret = mfd_add_devices(sec_pmic->dev, -1, s2mps11_devs, - ARRAY_SIZE(s2mps11_devs), NULL, 0); + ARRAY_SIZE(s2mps11_devs), NULL, 0, NULL); break; default: /* If this happens the probe function is problem */ diff --git a/drivers/mfd/sta2x11-mfd.c b/drivers/mfd/sta2x11-mfd.c index d31fed07aefb..d35da6820bea 100644 --- a/drivers/mfd/sta2x11-mfd.c +++ b/drivers/mfd/sta2x11-mfd.c @@ -407,7 +407,7 @@ static int __devinit sta2x11_mfd_probe(struct pci_dev *pdev, sta2x11_mfd_bar0, ARRAY_SIZE(sta2x11_mfd_bar0), &pdev->resource[0], - 0); + 0, NULL); if (err) { dev_err(&pdev->dev, "mfd_add_devices[0] failed: %d\n", err); goto err_disable; @@ -417,7 +417,7 @@ static int __devinit sta2x11_mfd_probe(struct pci_dev *pdev, sta2x11_mfd_bar1, ARRAY_SIZE(sta2x11_mfd_bar1), &pdev->resource[1], - 0); + 0, NULL); if (err) { dev_err(&pdev->dev, "mfd_add_devices[1] failed: %d\n", err); goto err_disable; diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 2dd8d49cb30b..c94f521f392c 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -962,7 +962,7 @@ static int __devinit stmpe_add_device(struct stmpe *stmpe, struct mfd_cell *cell, int irq) { return mfd_add_devices(stmpe->dev, stmpe->pdata->id, cell, 1, - NULL, stmpe->irq_base + irq); + NULL, stmpe->irq_base + irq, NULL); } static int __devinit stmpe_devices_init(struct stmpe *stmpe) diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index 2d9e8799e733..b32940ec9034 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -388,7 +388,7 @@ static int t7l66xb_probe(struct platform_device *dev) ret = mfd_add_devices(&dev->dev, dev->id, t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells), - iomem, t7l66xb->irq_base); + iomem, t7l66xb->irq_base, NULL); if (!ret) return 0; diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index 048bf0532a09..b56ba6b43294 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c @@ -262,8 +262,8 @@ static int __devinit tc3589x_device_init(struct tc3589x *tc3589x) if (blocks & TC3589x_BLOCK_GPIO) { ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio, - ARRAY_SIZE(tc3589x_dev_gpio), NULL, - tc3589x->irq_base); + ARRAY_SIZE(tc3589x_dev_gpio), NULL, + tc3589x->irq_base, NULL); if (ret) { dev_err(tc3589x->dev, "failed to add gpio child\n"); return ret; @@ -273,8 +273,8 @@ static int __devinit tc3589x_device_init(struct tc3589x *tc3589x) if (blocks & TC3589x_BLOCK_KEYPAD) { ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad, - ARRAY_SIZE(tc3589x_dev_keypad), NULL, - tc3589x->irq_base); + ARRAY_SIZE(tc3589x_dev_keypad), NULL, + tc3589x->irq_base, NULL); if (ret) { dev_err(tc3589x->dev, "failed to keypad child\n"); return ret; diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c index d20a284ad4ba..413c891102f8 100644 --- a/drivers/mfd/tc6387xb.c +++ b/drivers/mfd/tc6387xb.c @@ -192,7 +192,7 @@ static int __devinit tc6387xb_probe(struct platform_device *dev) printk(KERN_INFO "Toshiba tc6387xb initialised\n"); ret = mfd_add_devices(&dev->dev, dev->id, tc6387xb_cells, - ARRAY_SIZE(tc6387xb_cells), iomem, irq); + ARRAY_SIZE(tc6387xb_cells), iomem, irq, NULL); if (!ret) return 0; diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 9612264f0e6d..dcab026fcbb2 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -700,8 +700,8 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) tc6393xb_cells[TC6393XB_CELL_FB].pdata_size = sizeof(*tcpd->fb_data); ret = mfd_add_devices(&dev->dev, dev->id, - tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), - iomem, tcpd->irq_base); + tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), + iomem, tcpd->irq_base, NULL); if (!ret) return 0; diff --git a/drivers/mfd/ti-ssp.c b/drivers/mfd/ti-ssp.c index 4fb0e6c8e8fe..7c3675a74f93 100644 --- a/drivers/mfd/ti-ssp.c +++ b/drivers/mfd/ti-ssp.c @@ -412,7 +412,7 @@ static int __devinit ti_ssp_probe(struct platform_device *pdev) cells[id].data_size = data->pdata_size; } - error = mfd_add_devices(dev, 0, cells, 2, NULL, 0); + error = mfd_add_devices(dev, 0, cells, 2, NULL, 0, NULL); if (error < 0) { dev_err(dev, "cannot add mfd cells\n"); goto error_enable; diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c index a447f4ec11fb..cccc626c83c8 100644 --- a/drivers/mfd/timberdale.c +++ b/drivers/mfd/timberdale.c @@ -757,25 +757,25 @@ static int __devinit timb_probe(struct pci_dev *dev, err = mfd_add_devices(&dev->dev, -1, timberdale_cells_bar0_cfg0, ARRAY_SIZE(timberdale_cells_bar0_cfg0), - &dev->resource[0], msix_entries[0].vector); + &dev->resource[0], msix_entries[0].vector, NULL); break; case TIMB_HW_VER1: err = mfd_add_devices(&dev->dev, -1, timberdale_cells_bar0_cfg1, ARRAY_SIZE(timberdale_cells_bar0_cfg1), - &dev->resource[0], msix_entries[0].vector); + &dev->resource[0], msix_entries[0].vector, NULL); break; case TIMB_HW_VER2: err = mfd_add_devices(&dev->dev, -1, timberdale_cells_bar0_cfg2, ARRAY_SIZE(timberdale_cells_bar0_cfg2), - &dev->resource[0], msix_entries[0].vector); + &dev->resource[0], msix_entries[0].vector, NULL); break; case TIMB_HW_VER3: err = mfd_add_devices(&dev->dev, -1, timberdale_cells_bar0_cfg3, ARRAY_SIZE(timberdale_cells_bar0_cfg3), - &dev->resource[0], msix_entries[0].vector); + &dev->resource[0], msix_entries[0].vector, NULL); break; default: dev_err(&dev->dev, "Uknown IP setup: %d.%d.%d\n", @@ -792,7 +792,7 @@ static int __devinit timb_probe(struct pci_dev *dev, err = mfd_add_devices(&dev->dev, 0, timberdale_cells_bar1, ARRAY_SIZE(timberdale_cells_bar1), - &dev->resource[1], msix_entries[0].vector); + &dev->resource[1], msix_entries[0].vector, NULL); if (err) { dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err); goto err_mfd2; @@ -803,7 +803,7 @@ static int __devinit timb_probe(struct pci_dev *dev, ((priv->fw.config & TIMB_HW_VER_MASK) == TIMB_HW_VER3)) { err = mfd_add_devices(&dev->dev, 1, timberdale_cells_bar2, ARRAY_SIZE(timberdale_cells_bar2), - &dev->resource[2], msix_entries[0].vector); + &dev->resource[2], msix_entries[0].vector, NULL); if (err) { dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err); goto err_mfd2; diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c index a293b978e27c..14051bdc714b 100644 --- a/drivers/mfd/tps6105x.c +++ b/drivers/mfd/tps6105x.c @@ -188,7 +188,7 @@ static int __devinit tps6105x_probe(struct i2c_client *client, } ret = mfd_add_devices(&client->dev, 0, tps6105x_cells, - ARRAY_SIZE(tps6105x_cells), NULL, 0); + ARRAY_SIZE(tps6105x_cells), NULL, 0, NULL); if (ret) goto fail; diff --git a/drivers/mfd/tps6507x.c b/drivers/mfd/tps6507x.c index 33ba7723c967..1b203499c744 100644 --- a/drivers/mfd/tps6507x.c +++ b/drivers/mfd/tps6507x.c @@ -100,7 +100,7 @@ static int tps6507x_i2c_probe(struct i2c_client *i2c, ret = mfd_add_devices(tps6507x->dev, -1, tps6507x_devs, ARRAY_SIZE(tps6507x_devs), - NULL, 0); + NULL, 0, NULL); if (ret < 0) goto err; diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c index 80e24f4b47bf..50fd87c87a1c 100644 --- a/drivers/mfd/tps65090.c +++ b/drivers/mfd/tps65090.c @@ -292,7 +292,7 @@ static int __devinit tps65090_i2c_probe(struct i2c_client *client, } ret = mfd_add_devices(tps65090->dev, -1, tps65090s, - ARRAY_SIZE(tps65090s), NULL, 0); + ARRAY_SIZE(tps65090s), NULL, 0, NULL); if (ret) { dev_err(&client->dev, "add mfd devices failed with err: %d\n", ret); diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index 3bc274409b58..a95e9421b735 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -191,7 +191,7 @@ static int __devinit tps65217_probe(struct i2c_client *client, } ret = mfd_add_devices(tps->dev, -1, tps65217s, - ARRAY_SIZE(tps65217s), NULL, 0); + ARRAY_SIZE(tps65217s), NULL, 0, NULL); if (ret < 0) { dev_err(tps->dev, "mfd_add_devices failed: %d\n", ret); return ret; diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 353c34812120..5f58370ccf55 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -493,7 +493,8 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client, } ret = mfd_add_devices(tps6586x->dev, -1, - tps6586x_cell, ARRAY_SIZE(tps6586x_cell), NULL, 0); + tps6586x_cell, ARRAY_SIZE(tps6586x_cell), + NULL, 0, NULL); if (ret < 0) { dev_err(&client->dev, "mfd_add_devices failed: %d\n", ret); goto err_mfd_add; diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 1c563792c777..d3ce4d569deb 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -254,7 +254,7 @@ static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, ret = mfd_add_devices(tps65910->dev, -1, tps65910s, ARRAY_SIZE(tps65910s), - NULL, 0); + NULL, 0, NULL); if (ret < 0) { dev_err(&i2c->dev, "mfd_add_devices failed: %d\n", ret); return ret; diff --git a/drivers/mfd/tps65912-core.c b/drivers/mfd/tps65912-core.c index 74fd8cb5f372..4658b5bdcd84 100644 --- a/drivers/mfd/tps65912-core.c +++ b/drivers/mfd/tps65912-core.c @@ -146,7 +146,7 @@ int tps65912_device_init(struct tps65912 *tps65912) ret = mfd_add_devices(tps65912->dev, -1, tps65912s, ARRAY_SIZE(tps65912s), - NULL, 0); + NULL, 0, NULL); if (ret < 0) goto err; diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index 838ce4eb444e..77c9acb14583 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -223,7 +223,7 @@ static int __devinit twl4030_audio_probe(struct platform_device *pdev) if (childs) ret = mfd_add_devices(&pdev->dev, pdev->id, audio->cells, - childs, NULL, 0); + childs, NULL, 0, NULL); else { dev_err(&pdev->dev, "No platform data found for childs\n"); ret = -ENODEV; diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c index b0fad0ffca56..3dca5c195a20 100644 --- a/drivers/mfd/twl6040-core.c +++ b/drivers/mfd/twl6040-core.c @@ -632,7 +632,7 @@ static int __devinit twl6040_probe(struct i2c_client *client, } ret = mfd_add_devices(&client->dev, -1, twl6040->cells, children, - NULL, 0); + NULL, 0, NULL); if (ret) goto mfd_err; diff --git a/drivers/mfd/vx855.c b/drivers/mfd/vx855.c index 872aff21e4be..b9a636d44c7f 100644 --- a/drivers/mfd/vx855.c +++ b/drivers/mfd/vx855.c @@ -102,7 +102,7 @@ static __devinit int vx855_probe(struct pci_dev *pdev, vx855_gpio_resources[1].end = vx855_gpio_resources[1].start + 3; ret = mfd_add_devices(&pdev->dev, -1, vx855_cells, ARRAY_SIZE(vx855_cells), - NULL, 0); + NULL, 0, NULL); /* we always return -ENODEV here in order to enable other * drivers like old, not-yet-platform_device ported i2c-viapro */ diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c index f39b756df561..86e0e4309fc2 100644 --- a/drivers/mfd/wl1273-core.c +++ b/drivers/mfd/wl1273-core.c @@ -241,7 +241,7 @@ static int __devinit wl1273_core_probe(struct i2c_client *client, __func__, children); r = mfd_add_devices(&client->dev, -1, core->cells, - children, NULL, 0); + children, NULL, 0, NULL); if (r) goto err; diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 2e5d58eb2ec1..521340a708d3 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -1787,27 +1787,27 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) case WM8310: ret = mfd_add_devices(wm831x->dev, wm831x_num, wm8310_devs, ARRAY_SIZE(wm8310_devs), - NULL, 0); + NULL, 0, NULL); break; case WM8311: ret = mfd_add_devices(wm831x->dev, wm831x_num, wm8311_devs, ARRAY_SIZE(wm8311_devs), - NULL, 0); + NULL, 0, NULL); if (!pdata || !pdata->disable_touch) mfd_add_devices(wm831x->dev, wm831x_num, touch_devs, ARRAY_SIZE(touch_devs), - NULL, 0); + NULL, 0, NULL); break; case WM8312: ret = mfd_add_devices(wm831x->dev, wm831x_num, wm8312_devs, ARRAY_SIZE(wm8312_devs), - NULL, 0); + NULL, 0, NULL); if (!pdata || !pdata->disable_touch) mfd_add_devices(wm831x->dev, wm831x_num, touch_devs, ARRAY_SIZE(touch_devs), - NULL, 0); + NULL, 0, NULL); break; case WM8320: @@ -1816,7 +1816,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) case WM8326: ret = mfd_add_devices(wm831x->dev, wm831x_num, wm8320_devs, ARRAY_SIZE(wm8320_devs), - NULL, 0); + NULL, 0, NULL); break; default: @@ -1841,7 +1841,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) if (ret & WM831X_XTAL_ENA) { ret = mfd_add_devices(wm831x->dev, wm831x_num, rtc_devs, ARRAY_SIZE(rtc_devs), - NULL, 0); + NULL, 0, NULL); if (ret != 0) { dev_err(wm831x->dev, "Failed to add RTC: %d\n", ret); goto err_irq; @@ -1854,7 +1854,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) /* Treat errors as non-critical */ ret = mfd_add_devices(wm831x->dev, wm831x_num, backlight_devs, ARRAY_SIZE(backlight_devs), NULL, - 0); + 0, NULL); if (ret < 0) dev_err(wm831x->dev, "Failed to add backlight: %d\n", ret); diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index 4b7d378551d5..639ca359242f 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c @@ -70,7 +70,7 @@ static int wm8400_register_codec(struct wm8400 *wm8400) .pdata_size = sizeof(*wm8400), }; - return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0); + return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0, NULL); } /* diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index eec74aa55fdf..2febf88cfce8 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -414,7 +414,7 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq) ret = mfd_add_devices(wm8994->dev, -1, wm8994_regulator_devs, ARRAY_SIZE(wm8994_regulator_devs), - NULL, 0); + NULL, 0, NULL); if (ret != 0) { dev_err(wm8994->dev, "Failed to add children: %d\n", ret); goto err; @@ -648,7 +648,7 @@ static __devinit int wm8994_device_init(struct wm8994 *wm8994, int irq) ret = mfd_add_devices(wm8994->dev, -1, wm8994_devs, ARRAY_SIZE(wm8994_devs), - NULL, 0); + NULL, 0, NULL); if (ret != 0) { dev_err(wm8994->dev, "Failed to add children: %d\n", ret); goto err_irq; diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index 695ea35f75b0..d0a7e408efe9 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -837,7 +837,7 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev) } ret = mfd_add_devices(nvec->dev, -1, nvec_devices, - ARRAY_SIZE(nvec_devices), base, 0); + ARRAY_SIZE(nvec_devices), base, 0, NULL); if (ret) dev_err(nvec->dev, "error adding subdevices\n"); -- cgit v1.2.2 From 3080de4ef62f0cc1910b227d33d3533f3c4a4a5d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 21 Aug 2012 20:02:03 +0100 Subject: mfd: arizona: Suppress needless calls to the primary IRQ We can read back if the primary IRQ is asserted from the register map, meaning that we can suppress polling of the interrupt status registers when only the AoD IRQ domain is asserting. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/arizona-irq.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index 64940c6da93c..a062153f54e7 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -94,6 +94,7 @@ static irqreturn_t arizona_ctrlif_err(int irq, void *data) static irqreturn_t arizona_irq_thread(int irq, void *data) { struct arizona *arizona = data; + unsigned int val; int i, ret; ret = pm_runtime_get_sync(arizona->dev); @@ -102,9 +103,20 @@ static irqreturn_t arizona_irq_thread(int irq, void *data) return IRQ_NONE; } - /* Check both domains */ - for (i = 0; i < 2; i++) - handle_nested_irq(irq_find_mapping(arizona->virq, i)); + /* Always handle the AoD domain */ + handle_nested_irq(irq_find_mapping(arizona->virq, 0)); + + /* + * Check if one of the main interrupts is asserted and only + * check that domain if it is. + */ + ret = regmap_read(arizona->regmap, ARIZONA_IRQ_PIN_STATUS, &val); + if (ret == 0 && val & ARIZONA_IRQ1_STS) { + handle_nested_irq(irq_find_mapping(arizona->virq, 1)); + } else if (ret != 0) { + dev_err(arizona->dev, "Failed to read main IRQ status: %d\n", + ret); + } pm_runtime_mark_last_busy(arizona->dev); pm_runtime_put_autosuspend(arizona->dev); -- cgit v1.2.2 From 1de74cfd69077c06507f444d7192aefc17784ab5 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 23 Aug 2012 15:47:52 +0100 Subject: mfd: wm8994: Implement support for WM1811 devices with higher cust_ids Higher cust_ids have had the device revision field reset so need different handling of GPIO6. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8994-regmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/wm8994-regmap.c b/drivers/mfd/wm8994-regmap.c index 52e9e2944940..2fbce9c5950b 100644 --- a/drivers/mfd/wm8994-regmap.c +++ b/drivers/mfd/wm8994-regmap.c @@ -1136,7 +1136,7 @@ static bool wm1811_volatile_register(struct device *dev, unsigned int reg) switch (reg) { case WM8994_GPIO_6: - if (wm8994->revision > 1) + if (wm8994->cust_id > 1 || wm8994->revision > 1) return true; else return false; -- cgit v1.2.2 From 9282a7b9f058ec9e086ecdb53464b151ecf323fe Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 23 Aug 2012 16:10:29 +0100 Subject: mfd: wm8994: Update WM1811 register patches for latest evaluation Further evaluation of the device has yielded some improvements to the device configuration. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8994-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 2febf88cfce8..3d6d9beb18d4 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -390,7 +390,7 @@ static const __devinitdata struct reg_default wm8958_reva_patch[] = { static const __devinitdata struct reg_default wm1811_reva_patch[] = { { 0x102, 0x3 }, - { 0x56, 0x7 }, + { 0x56, 0xc07 }, { 0x5d, 0x7e }, { 0x5e, 0x0 }, { 0x102, 0x0 }, -- cgit v1.2.2 From cdabc1c88a12e9fc2a49f2a54ce9be470398d8a9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 8 Sep 2012 09:00:59 +0800 Subject: mfd: arizona: Remove unused variable Left over as bitrot from previous changes. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/arizona-irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index a062153f54e7..f7886c8269bc 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -95,7 +95,7 @@ static irqreturn_t arizona_irq_thread(int irq, void *data) { struct arizona *arizona = data; unsigned int val; - int i, ret; + int ret; ret = pm_runtime_get_sync(arizona->dev); if (ret < 0) { -- cgit v1.2.2 From 4f600ada70beeb1dfe08e11e871bf31015aa0a3d Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 23 Jul 2012 17:34:15 +0200 Subject: gpio: gpio-ich: Share ownership of GPIO groups The ICH chips have their GPIO pins organized in 2 or 3 independent groups of 32 GPIO pins. It can happen that the ACPI BIOS wants to make use of pins in one group, preventing the OS to access these. This does not prevent the OS from accessing the other group(s). This is the case for example on my Asus Z8NA-D6 board. The ACPI BIOS wants to control GPIO 18 (group 1), while I (the OS) need to control GPIO 52 and 53 (group 2) for SMBus multiplexing. So instead of checking for ACPI resource conflict on the whole I/O range, check on a per-group basis, and consider it a success if at least one of the groups is available for the OS to use. Signed-off-by: Jean Delvare Cc: Peter Tyser Cc: Aaron Sierra Cc: Grant Likely Acked-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/gpio/gpio-ich.c | 79 ++++++++++++++++++++++++++++++++++++++++++------- drivers/mfd/lpc_ich.c | 29 ++++++++++++++++-- 2 files changed, 96 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index b7c06517403d..d4d617966696 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -49,6 +49,10 @@ static const u8 ichx_regs[3][3] = { {0x0c, 0x38, 0x48}, /* LVL[1-3] offsets */ }; +static const u8 ichx_reglen[3] = { + 0x30, 0x10, 0x10, +}; + #define ICHX_WRITE(val, reg, base_res) outl(val, (reg) + (base_res)->start) #define ICHX_READ(reg, base_res) inl((reg) + (base_res)->start) @@ -75,6 +79,7 @@ static struct { struct resource *pm_base; /* Power Mangagment IO base */ struct ichx_desc *desc; /* Pointer to chipset-specific description */ u32 orig_gpio_ctrl; /* Orig CTRL value, used to restore on exit */ + u8 use_gpio; /* Which GPIO groups are usable */ } ichx_priv; static int modparam_gpiobase = -1; /* dynamic */ @@ -123,8 +128,16 @@ static int ichx_read_bit(int reg, unsigned nr) return data & (1 << bit) ? 1 : 0; } +static int ichx_gpio_check_available(struct gpio_chip *gpio, unsigned nr) +{ + return (ichx_priv.use_gpio & (1 << (nr / 32))) ? 0 : -ENXIO; +} + static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) { + if (!ichx_gpio_check_available(gpio, nr)) + return -ENXIO; + /* * Try setting pin as an input and verify it worked since many pins * are output-only. @@ -138,6 +151,9 @@ static int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned nr) static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, int val) { + if (!ichx_gpio_check_available(gpio, nr)) + return -ENXIO; + /* Set GPIO output value. */ ichx_write_bit(GPIO_LVL, nr, val, 0); @@ -153,6 +169,9 @@ static int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned nr, static int ichx_gpio_get(struct gpio_chip *chip, unsigned nr) { + if (!ichx_gpio_check_available(chip, nr)) + return -ENXIO; + return ichx_read_bit(GPIO_LVL, nr); } @@ -161,6 +180,9 @@ static int ich6_gpio_get(struct gpio_chip *chip, unsigned nr) unsigned long flags; u32 data; + if (!ichx_gpio_check_available(chip, nr)) + return -ENXIO; + /* * GPI 0 - 15 need to be read from the power management registers on * a ICH6/3100 bridge. @@ -291,6 +313,46 @@ static struct ichx_desc intel5_desc = { .ngpio = 76, }; +static int __devinit ichx_gpio_request_regions(struct resource *res_base, + const char *name, u8 use_gpio) +{ + int i; + + if (!res_base || !res_base->start || !res_base->end) + return -ENODEV; + + for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) { + if (!(use_gpio & (1 << i))) + continue; + if (!request_region(res_base->start + ichx_regs[0][i], + ichx_reglen[i], name)) + goto request_err; + } + return 0; + +request_err: + /* Clean up: release already requested regions, if any */ + for (i--; i >= 0; i--) { + if (!(use_gpio & (1 << i))) + continue; + release_region(res_base->start + ichx_regs[0][i], + ichx_reglen[i]); + } + return -EBUSY; +} + +static void ichx_gpio_release_regions(struct resource *res_base, u8 use_gpio) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ichx_regs[0]); i++) { + if (!(use_gpio & (1 << i))) + continue; + release_region(res_base->start + ichx_regs[0][i], + ichx_reglen[i]); + } +} + static int __devinit ichx_gpio_probe(struct platform_device *pdev) { struct resource *res_base, *res_pm; @@ -329,12 +391,11 @@ static int __devinit ichx_gpio_probe(struct platform_device *pdev) } res_base = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPIO); - if (!res_base || !res_base->start || !res_base->end) - return -ENODEV; - - if (!request_region(res_base->start, resource_size(res_base), - pdev->name)) - return -EBUSY; + ichx_priv.use_gpio = ich_info->use_gpio; + err = ichx_gpio_request_regions(res_base, pdev->name, + ichx_priv.use_gpio); + if (err) + return err; ichx_priv.gpio_base = res_base; @@ -374,8 +435,7 @@ init: return 0; add_err: - release_region(ichx_priv.gpio_base->start, - resource_size(ichx_priv.gpio_base)); + ichx_gpio_release_regions(ichx_priv.gpio_base, ichx_priv.use_gpio); if (ichx_priv.pm_base) release_region(ichx_priv.pm_base->start, resource_size(ichx_priv.pm_base)); @@ -393,8 +453,7 @@ static int __devexit ichx_gpio_remove(struct platform_device *pdev) return err; } - release_region(ichx_priv.gpio_base->start, - resource_size(ichx_priv.gpio_base)); + ichx_gpio_release_regions(ichx_priv.gpio_base, ichx_priv.use_gpio); if (ichx_priv.pm_base) release_region(ichx_priv.pm_base->start, resource_size(ichx_priv.pm_base)); diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 092ad4b44b6d..d142622a3fb0 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -683,6 +683,30 @@ static void __devinit lpc_ich_finalize_cell(struct mfd_cell *cell, cell->pdata_size = sizeof(struct lpc_ich_info); } +/* + * We don't check for resource conflict globally. There are 2 or 3 independent + * GPIO groups and it's enough to have access to one of these to instantiate + * the device. + */ +static int __devinit lpc_ich_check_conflict_gpio(struct resource *res) +{ + int ret; + u8 use_gpio = 0; + + if (resource_size(res) >= 0x50 && + !acpi_check_region(res->start + 0x40, 0x10, "LPC ICH GPIO3")) + use_gpio |= 1 << 2; + + if (!acpi_check_region(res->start + 0x30, 0x10, "LPC ICH GPIO2")) + use_gpio |= 1 << 1; + + ret = acpi_check_region(res->start + 0x00, 0x30, "LPC ICH GPIO1"); + if (!ret) + use_gpio |= 1 << 0; + + return use_gpio ? use_gpio : ret; +} + static int __devinit lpc_ich_init_gpio(struct pci_dev *dev, const struct pci_device_id *id) { @@ -740,12 +764,13 @@ gpe0_done: break; } - ret = acpi_check_resource_conflict(res); - if (ret) { + ret = lpc_ich_check_conflict_gpio(res); + if (ret < 0) { /* this isn't necessarily fatal for the GPIO */ acpi_conflict = true; goto gpio_done; } + lpc_chipset_info[id->driver_data].use_gpio = ret; lpc_ich_enable_gpio_space(dev); lpc_ich_finalize_cell(&lpc_ich_cells[LPC_GPIO], id); -- cgit v1.2.2 From 80633f05b0dbf5819ef28f626f2f0b7c885d1f88 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 20 Aug 2012 11:53:36 +0100 Subject: mfd: ab8500: Make ab8500_irq_get_virq() static MFD core now takes care of HWIRQ <-> VIRQ mapping, so the helper ab8500_irq_get_virq() is no longer used by ab8500 subordinate devices to obtain a Linux wide Virtual IRQ. The AB8500 IRQ controller still uses it internally though, so we'll just hide it from the rest of the world by making it static instead. Signed-off-by: Lee Jones Reviewed-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 47adf800024e..dd91951c68f0 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -472,6 +472,22 @@ static irqreturn_t ab8500_hierarchical_irq(int irq, void *dev) return IRQ_HANDLED; } +/** + * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ + * + * @ab8500: ab8500_irq controller to operate on. + * @irq: index of the interrupt requested in the chip IRQs + * + * Useful for drivers to request their own IRQs. + */ +static int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq) +{ + if (!ab8500) + return -EINVAL; + + return irq_create_mapping(ab8500->domain, irq); +} + static irqreturn_t ab8500_irq(int irq, void *dev) { struct ab8500 *ab8500 = dev; @@ -511,23 +527,6 @@ static irqreturn_t ab8500_irq(int irq, void *dev) return IRQ_HANDLED; } -/** - * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ - * - * @ab8500: ab8500_irq controller to operate on. - * @irq: index of the interrupt requested in the chip IRQs - * - * Useful for drivers to request their own IRQs. - */ -int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq) -{ - if (!ab8500) - return -EINVAL; - - return irq_create_mapping(ab8500->domain, irq); -} -EXPORT_SYMBOL_GPL(ab8500_irq_get_virq); - static int ab8500_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq) { -- cgit v1.2.2 From 004c15a68076f5bdc343bed92efed81087cecbfb Mon Sep 17 00:00:00 2001 From: Bill Huang Date: Sun, 19 Aug 2012 18:07:55 -0700 Subject: mfd: dt: tps6586x: Add power off control Add DT property "ti,system-power-controller" telling whether or not this pmic is in charge of controlling the system power, so the power off routine can be hooked up to system call "pm_power_off". Based on the work by: Dan Willemsen Signed-off-by: Bill Huang Tested-by: Stephen Warren Signed-off-by: Samuel Ortiz --- drivers/mfd/tps6586x.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 5f58370ccf55..95ef40754dd7 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -29,6 +29,10 @@ #include #include +#define TPS6586X_SUPPLYENE 0x14 +#define EXITSLREQ_BIT BIT(1) +#define SLEEP_MODE_BIT BIT(3) + /* interrupt control registers */ #define TPS6586X_INT_ACK1 0xb5 #define TPS6586X_INT_ACK2 0xb6 @@ -409,6 +413,7 @@ static struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *clien pdata->subdevs = devs; pdata->gpio_base = -1; pdata->irq_base = -1; + pdata->pm_off = of_property_read_bool(np, "ti,system-power-controller"); return pdata; } @@ -441,6 +446,15 @@ static const struct regmap_config tps6586x_regmap_config = { .cache_type = REGCACHE_RBTREE, }; +static struct device *tps6586x_dev; +static void tps6586x_power_off(void) +{ + if (tps6586x_clr_bits(tps6586x_dev, TPS6586X_SUPPLYENE, EXITSLREQ_BIT)) + return; + + tps6586x_set_bits(tps6586x_dev, TPS6586X_SUPPLYENE, SLEEP_MODE_BIT); +} + static int __devinit tps6586x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -506,6 +520,11 @@ static int __devinit tps6586x_i2c_probe(struct i2c_client *client, goto err_add_devs; } + if (pdata->pm_off && !pm_power_off) { + tps6586x_dev = &client->dev; + pm_power_off = tps6586x_power_off; + } + return 0; err_add_devs: -- cgit v1.2.2 From b079fa72069ba7f754ba8bdf737335abdb971b67 Mon Sep 17 00:00:00 2001 From: Bill Huang Date: Sun, 19 Aug 2012 18:07:56 -0700 Subject: mfd: dt: tps65910: Add power off control Add DT property "ti,system-power-controller" telling whether or not this pmic is in charge of controlling the system power, so the power off routine can be hooked up to system call "pm_power_off". Based on the work by: Dan Willemsen Signed-off-by: Bill Huang Tested-by: Stephen Warren Signed-off-by: Samuel Ortiz --- drivers/mfd/tps65910.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index d3ce4d569deb..ca902943cfa9 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -198,6 +198,8 @@ static struct tps65910_board *tps65910_parse_dt(struct i2c_client *client, board_info->irq = client->irq; board_info->irq_base = -1; + board_info->pm_off = of_property_read_bool(np, + "ti,system-power-controller"); return board_info; } @@ -210,6 +212,21 @@ struct tps65910_board *tps65910_parse_dt(struct i2c_client *client, } #endif +static struct i2c_client *tps65910_i2c_client; +static void tps65910_power_off(void) +{ + struct tps65910 *tps65910; + + tps65910 = dev_get_drvdata(&tps65910_i2c_client->dev); + + if (tps65910_reg_set_bits(tps65910, TPS65910_DEVCTRL, + DEVCTRL_PWR_OFF_MASK) < 0) + return; + + tps65910_reg_clear_bits(tps65910, TPS65910_DEVCTRL, + DEVCTRL_DEV_ON_MASK); +} + static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -267,6 +284,11 @@ static __devinit int tps65910_i2c_probe(struct i2c_client *i2c, tps65910_ck32k_init(tps65910, pmic_plat_data); tps65910_sleepinit(tps65910, pmic_plat_data); + if (pmic_plat_data->pm_off && !pm_power_off) { + tps65910_i2c_client = i2c; + pm_power_off = tps65910_power_off; + } + return ret; } -- cgit v1.2.2 From 50b381b72bf080dc10d20f5d33486488bf737bbc Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Tue, 11 Sep 2012 22:09:55 +0800 Subject: mfd: 88pm860x: Fix section mismatch warning WARNING: drivers/built-in.o(.data+0x1e3c8): Section mismatch in reference from the variable bk_devs to the variable .devinit.data:bk0_resources The variable bk_devs references the variable __devinitdata bk0_resources If the reference is valid then annotate the variable with __init* or __refdata (see linux/init.h) or name the variable: *driver, *_template, *_timer, *_sht, *_ops, *_probe, *_probe_one, *_console So add __devinitdata on bk_devs, led_devs & reg_devs. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 4927f4efcf9d..0c01d7403251 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -158,7 +158,7 @@ static struct resource rtc_resources[] __devinitdata = { {PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,}, }; -static struct mfd_cell bk_devs[] = { +static struct mfd_cell bk_devs[] __devinitdata = { { .name = "88pm860x-backlight", .id = 0, @@ -177,7 +177,7 @@ static struct mfd_cell bk_devs[] = { }, }; -static struct mfd_cell led_devs[] = { +static struct mfd_cell led_devs[] __devinitdata = { { .name = "88pm860x-led", .id = 0, @@ -211,7 +211,7 @@ static struct mfd_cell led_devs[] = { }, }; -static struct mfd_cell reg_devs[] = { +static struct mfd_cell reg_devs[] __devinitdata = { { .name = "88pm860x-regulator", .id = 0, -- cgit v1.2.2 From 0fd0013cda05a3bbdaf861c9fdfe8496230da672 Mon Sep 17 00:00:00 2001 From: Marcus Cooper Date: Fri, 10 Aug 2012 10:32:35 +0200 Subject: mfd: ab3100: Split ab3100 headers out of abx500.h The U8500 has its own set of separate header, so the abx500 becomes completely abstract. Do the same split for the AB3100 legacy ASIC. Signed-off-by: Marcus Cooper Signed-off-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab3100-core.c | 1 + drivers/regulator/ab3100.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 01781ae5d0d7..2b3dde571a50 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -21,6 +21,7 @@ #include #include #include +#include #include /* These are the only registers inside AB3100 used in this main file */ diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index 182b553059c9..b6cde9c16c8f 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c @@ -15,6 +15,7 @@ #include #include #include +#include #include /* LDO registers and some handy masking definitions for AB3100 */ -- cgit v1.2.2 From f84e9954f7352293e223b0b5f3b13c09e7cba098 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 21 Aug 2012 15:15:52 +0900 Subject: mfd: MAX77693: Fix interrupt handling bug This patch fix bug related to interrupt handling for MAX77693 devices. - Unmask interrupt masking bit for charger/flash/muic to revolve that interrupt isn't happened when external connector is attached. - Fix wrong regmap instance when muic interrupt is happened. This patch were discussed and confirm discussion about this patch on below url: http://lkml.org/lkml/2012/7/16/118 Signed-off-by: Chanwoo Choi Signed-off-by: Myungjoo Ham Signed-off-by: Kyungmin Park Acked-by: Greg Kroah-Hartman Signed-off-by: Samuel Ortiz --- drivers/mfd/max77693-irq.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/max77693-irq.c b/drivers/mfd/max77693-irq.c index 2b403569e0a6..1029d018c739 100644 --- a/drivers/mfd/max77693-irq.c +++ b/drivers/mfd/max77693-irq.c @@ -137,6 +137,9 @@ static void max77693_irq_mask(struct irq_data *data) const struct max77693_irq_data *irq_data = irq_to_max77693_irq(max77693, data->irq); + if (irq_data->group >= MAX77693_IRQ_GROUP_NR) + return; + if (irq_data->group >= MUIC_INT1 && irq_data->group <= MUIC_INT3) max77693->irq_masks_cur[irq_data->group] &= ~irq_data->mask; else @@ -149,6 +152,9 @@ static void max77693_irq_unmask(struct irq_data *data) const struct max77693_irq_data *irq_data = irq_to_max77693_irq(max77693, data->irq); + if (irq_data->group >= MAX77693_IRQ_GROUP_NR) + return; + if (irq_data->group >= MUIC_INT1 && irq_data->group <= MUIC_INT3) max77693->irq_masks_cur[irq_data->group] |= irq_data->mask; else @@ -200,7 +206,7 @@ static irqreturn_t max77693_irq_thread(int irq, void *data) if (irq_src & MAX77693_IRQSRC_MUIC) /* MUIC INT1 ~ INT3 */ - max77693_bulk_read(max77693->regmap, MAX77693_MUIC_REG_INT1, + max77693_bulk_read(max77693->regmap_muic, MAX77693_MUIC_REG_INT1, MAX77693_NUM_IRQ_MUIC_REGS, &irq_reg[MUIC_INT1]); /* Apply masking */ @@ -255,7 +261,8 @@ int max77693_irq_init(struct max77693_dev *max77693) { struct irq_domain *domain; int i; - int ret; + int ret = 0; + u8 intsrc_mask; mutex_init(&max77693->irqlock); @@ -287,19 +294,38 @@ int max77693_irq_init(struct max77693_dev *max77693) &max77693_irq_domain_ops, max77693); if (!domain) { dev_err(max77693->dev, "could not create irq domain\n"); - return -ENODEV; + ret = -ENODEV; + goto err_irq; } max77693->irq_domain = domain; + /* Unmask max77693 interrupt */ + ret = max77693_read_reg(max77693->regmap, + MAX77693_PMIC_REG_INTSRC_MASK, &intsrc_mask); + if (ret < 0) { + dev_err(max77693->dev, "fail to read PMIC register\n"); + goto err_irq; + } + + intsrc_mask &= ~(MAX77693_IRQSRC_CHG); + intsrc_mask &= ~(MAX77693_IRQSRC_FLASH); + intsrc_mask &= ~(MAX77693_IRQSRC_MUIC); + ret = max77693_write_reg(max77693->regmap, + MAX77693_PMIC_REG_INTSRC_MASK, intsrc_mask); + if (ret < 0) { + dev_err(max77693->dev, "fail to write PMIC register\n"); + goto err_irq; + } + ret = request_threaded_irq(max77693->irq, NULL, max77693_irq_thread, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "max77693-irq", max77693); - if (ret) dev_err(max77693->dev, "Failed to request IRQ %d: %d\n", max77693->irq, ret); - return 0; +err_irq: + return ret; } void max77693_irq_exit(struct max77693_dev *max77693) -- cgit v1.2.2 From 887780b85a8dde06224f33681ecc4fac73b92a36 Mon Sep 17 00:00:00 2001 From: Chanwoo Choi Date: Tue, 21 Aug 2012 15:16:23 +0900 Subject: mfd: MAX77693: Fix NULL pointer error when initializing irqs This patch initialize register map of MUIC device because mfd driver of Maxim MAX77693 use regmap-muic instance of MUIC device when irqs of Maxim MAX77693 is initialized before call max77693-muic probe() function. Signed-off-by: Chanwoo Choi Signed-off-by: Myungjoo Ham Signed-off-by: Kyungmin Park Reported-by: Sylwester Nawrocki Acked-by: Greg Kroah-Hartman Signed-off-by: Samuel Ortiz --- drivers/extcon/extcon-max77693.c | 19 ++++++++++++------- drivers/mfd/max77693.c | 14 ++++++++++++++ 2 files changed, 26 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index 920a609b2c35..38f9e52f358b 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -669,13 +669,18 @@ static int __devinit max77693_muic_probe(struct platform_device *pdev) } info->dev = &pdev->dev; info->max77693 = max77693; - info->max77693->regmap_muic = regmap_init_i2c(info->max77693->muic, - &max77693_muic_regmap_config); - if (IS_ERR(info->max77693->regmap_muic)) { - ret = PTR_ERR(info->max77693->regmap_muic); - dev_err(max77693->dev, - "failed to allocate register map: %d\n", ret); - goto err_regmap; + if (info->max77693->regmap_muic) + dev_dbg(&pdev->dev, "allocate register map\n"); + else { + info->max77693->regmap_muic = devm_regmap_init_i2c( + info->max77693->muic, + &max77693_muic_regmap_config); + if (IS_ERR(info->max77693->regmap_muic)) { + ret = PTR_ERR(info->max77693->regmap_muic); + dev_err(max77693->dev, + "failed to allocate register map: %d\n", ret); + goto err_regmap; + } } platform_set_drvdata(pdev, info); mutex_init(&info->mutex); diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c index 4fdd03d28539..cc5155e20494 100644 --- a/drivers/mfd/max77693.c +++ b/drivers/mfd/max77693.c @@ -152,6 +152,20 @@ static int max77693_i2c_probe(struct i2c_client *i2c, max77693->haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC); i2c_set_clientdata(max77693->haptic, max77693); + /* + * Initialize register map for MUIC device because use regmap-muic + * instance of MUIC device when irq of max77693 is initialized + * before call max77693-muic probe() function. + */ + max77693->regmap_muic = devm_regmap_init_i2c(max77693->muic, + &max77693_regmap_config); + if (IS_ERR(max77693->regmap_muic)) { + ret = PTR_ERR(max77693->regmap_muic); + dev_err(max77693->dev, + "failed to allocate register map: %d\n", ret); + goto err_regmap; + } + ret = max77693_irq_init(max77693); if (ret < 0) goto err_irq; -- cgit v1.2.2 From 7fb9c1a4851562e9f9b522ff929c0742797f301a Mon Sep 17 00:00:00 2001 From: James Ralston Date: Thu, 9 Aug 2012 09:46:13 -0700 Subject: mfd: lpc_ich: Add Device IDs for Intel Lynx Point-LP PCH This patch adds the Watchdog Timer Device IDs for the Intel Lynx Point-LP PCH. The Device IDs are defined in drivers/mfd/lpc_ich.c Signed-off-by: James Ralston Acked-by: Wim Van Sebroeck Signed-off-by: Samuel Ortiz --- drivers/mfd/lpc_ich.c | 14 ++++++++++++++ drivers/watchdog/iTCO_wdt.c | 1 + 2 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index d142622a3fb0..a22544fe5319 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -49,6 +49,7 @@ * document number TBD : DH89xxCC * document number TBD : Panther Point * document number TBD : Lynx Point + * document number TBD : Lynx Point-LP */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -192,6 +193,7 @@ enum lpc_chipsets { LPC_DH89XXCC, /* DH89xxCC */ LPC_PPT, /* Panther Point */ LPC_LPT, /* Lynx Point */ + LPC_LPT_LP, /* Lynx Point-LP */ }; struct lpc_ich_info lpc_chipset_info[] __devinitdata = { @@ -468,6 +470,10 @@ struct lpc_ich_info lpc_chipset_info[] __devinitdata = { .name = "Lynx Point", .iTCO_version = 2, }, + [LPC_LPT_LP] = { + .name = "Lynx Point_LP", + .iTCO_version = 2, + }, }; /* @@ -641,6 +647,14 @@ static DEFINE_PCI_DEVICE_TABLE(lpc_ich_ids) = { { PCI_VDEVICE(INTEL, 0x8c5d), LPC_LPT}, { PCI_VDEVICE(INTEL, 0x8c5e), LPC_LPT}, { PCI_VDEVICE(INTEL, 0x8c5f), LPC_LPT}, + { PCI_VDEVICE(INTEL, 0x9c40), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c41), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c42), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c43), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c44), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c45), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c46), LPC_LPT_LP}, + { PCI_VDEVICE(INTEL, 0x9c47), LPC_LPT_LP}, { 0, }, /* End of list */ }; MODULE_DEVICE_TABLE(pci, lpc_ich_ids); diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index ceed39f26011..545d387de411 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -37,6 +37,7 @@ * document number TBD : DH89xxCC * document number TBD : Panther Point * document number TBD : Lynx Point + * document number TBD : Lynx Point-LP */ /* -- cgit v1.2.2 From a91d2f8d6e4c0fd3d6e1a2b5609eb93b114effb6 Mon Sep 17 00:00:00 2001 From: Gyungoh Yoo Date: Wed, 15 Aug 2012 10:28:46 -0600 Subject: mfd: Add MAX8907 core driver The MAX8907 is an I2C-based power-management IC containing voltage regulators, a reset controller, a real-time clock, and a touch-screen controller. The original driver was written by: * Gyungoh Yoo Various fixes and enhancements by: * Jin Park * Tom Cherry * Prashant Gaikwad * Dan Willemsen * Laxman Dewangan During upstreaming, I (swarren): * Converted to regmap. * Converted to regmap-irq. * Allowed probing from device tree. * Renamed from max8907c->max8907, since the driver covers at least the C and B revisions. * General cleanup. Signed-off-by: Gyungoh Yoo Signed-off-by: Stephen Warren Reviewed-by: Mark Brown #v3 Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 12 ++ drivers/mfd/Makefile | 1 + drivers/mfd/max8907.c | 331 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 344 insertions(+) create mode 100644 drivers/mfd/max8907.c (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d1facef28a60..856ec00ab787 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -476,6 +476,18 @@ config MFD_MAX77693 additional drivers must be enabled in order to use the functionality of the device. +config MFD_MAX8907 + tristate "Maxim Semiconductor MAX8907 PMIC Support" + select MFD_CORE + depends on I2C=y && GENERIC_HARDIRQS + select REGMAP_I2C + select REGMAP_IRQ + help + Say yes here to support for Maxim Semiconductor MAX8907. This is + a Power Management IC. This driver provides common support for + accessing the device; additional drivers must be enabled in order + to use the functionality of the device. + config MFD_MAX8925 bool "Maxim Semiconductor MAX8925 PMIC Support" depends on I2C=y && GENERIC_HARDIRQS diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 79dd22d1dc3d..2a4108d98442 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -92,6 +92,7 @@ obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.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 max8925-objs := max8925-core.o max8925-i2c.o obj-$(CONFIG_MFD_MAX8925) += max8925.o obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o diff --git a/drivers/mfd/max8907.c b/drivers/mfd/max8907.c new file mode 100644 index 000000000000..6497c98e030d --- /dev/null +++ b/drivers/mfd/max8907.c @@ -0,0 +1,331 @@ +/* + * max8907.c - mfd driver for MAX8907 + * + * Copyright (C) 2010 Gyungoh Yoo + * Copyright (C) 2010-2012, NVIDIA CORPORATION. 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 version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct mfd_cell max8907_cells[] = { + { .name = "max8907-regulator", }, + { .name = "max8907-rtc", }, +}; + +static bool max8907_gen_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX8907_REG_ON_OFF_IRQ1: + case MAX8907_REG_ON_OFF_STAT: + case MAX8907_REG_ON_OFF_IRQ2: + case MAX8907_REG_CHG_IRQ1: + case MAX8907_REG_CHG_IRQ2: + case MAX8907_REG_CHG_STAT: + return true; + default: + return false; + } +} + +static bool max8907_gen_is_precious_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX8907_REG_ON_OFF_IRQ1: + case MAX8907_REG_ON_OFF_IRQ2: + case MAX8907_REG_CHG_IRQ1: + case MAX8907_REG_CHG_IRQ2: + return true; + default: + return false; + } +} + +static bool max8907_gen_is_writeable_reg(struct device *dev, unsigned int reg) +{ + return !max8907_gen_is_volatile_reg(dev, reg); +} + +static const struct regmap_config max8907_regmap_gen_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_reg = max8907_gen_is_volatile_reg, + .precious_reg = max8907_gen_is_precious_reg, + .writeable_reg = max8907_gen_is_writeable_reg, + .max_register = MAX8907_REG_LDO20VOUT, + .cache_type = REGCACHE_RBTREE, +}; + +static bool max8907_rtc_is_volatile_reg(struct device *dev, unsigned int reg) +{ + if (reg <= MAX8907_REG_RTC_YEAR2) + return true; + + switch (reg) { + case MAX8907_REG_RTC_STATUS: + case MAX8907_REG_RTC_IRQ: + return true; + default: + return false; + } +} + +static bool max8907_rtc_is_precious_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX8907_REG_RTC_IRQ: + return true; + default: + return false; + } +} + +static bool max8907_rtc_is_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX8907_REG_RTC_STATUS: + case MAX8907_REG_RTC_IRQ: + return false; + default: + return true; + } +} + +static const struct regmap_config max8907_regmap_rtc_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_reg = max8907_rtc_is_volatile_reg, + .precious_reg = max8907_rtc_is_precious_reg, + .writeable_reg = max8907_rtc_is_writeable_reg, + .max_register = MAX8907_REG_MPL_CNTL, + .cache_type = REGCACHE_RBTREE, +}; + +static const struct regmap_irq max8907_chg_irqs[] = { + { .reg_offset = 0, .mask = 1 << 0, }, + { .reg_offset = 0, .mask = 1 << 1, }, + { .reg_offset = 0, .mask = 1 << 2, }, + { .reg_offset = 1, .mask = 1 << 0, }, + { .reg_offset = 1, .mask = 1 << 1, }, + { .reg_offset = 1, .mask = 1 << 2, }, + { .reg_offset = 1, .mask = 1 << 3, }, + { .reg_offset = 1, .mask = 1 << 4, }, + { .reg_offset = 1, .mask = 1 << 5, }, + { .reg_offset = 1, .mask = 1 << 6, }, + { .reg_offset = 1, .mask = 1 << 7, }, +}; + +static const struct regmap_irq_chip max8907_chg_irq_chip = { + .name = "max8907 chg", + .status_base = MAX8907_REG_CHG_IRQ1, + .mask_base = MAX8907_REG_CHG_IRQ1_MASK, + .wake_base = MAX8907_REG_CHG_IRQ1_MASK, + .irq_reg_stride = MAX8907_REG_CHG_IRQ2 - MAX8907_REG_CHG_IRQ1, + .num_regs = 2, + .irqs = max8907_chg_irqs, + .num_irqs = ARRAY_SIZE(max8907_chg_irqs), +}; + +static const struct regmap_irq max8907_on_off_irqs[] = { + { .reg_offset = 0, .mask = 1 << 0, }, + { .reg_offset = 0, .mask = 1 << 1, }, + { .reg_offset = 0, .mask = 1 << 2, }, + { .reg_offset = 0, .mask = 1 << 3, }, + { .reg_offset = 0, .mask = 1 << 4, }, + { .reg_offset = 0, .mask = 1 << 5, }, + { .reg_offset = 0, .mask = 1 << 6, }, + { .reg_offset = 0, .mask = 1 << 7, }, + { .reg_offset = 1, .mask = 1 << 0, }, + { .reg_offset = 1, .mask = 1 << 1, }, +}; + +static const struct regmap_irq_chip max8907_on_off_irq_chip = { + .name = "max8907 on_off", + .status_base = MAX8907_REG_ON_OFF_IRQ1, + .mask_base = MAX8907_REG_ON_OFF_IRQ1_MASK, + .irq_reg_stride = MAX8907_REG_ON_OFF_IRQ2 - MAX8907_REG_ON_OFF_IRQ1, + .num_regs = 2, + .irqs = max8907_on_off_irqs, + .num_irqs = ARRAY_SIZE(max8907_on_off_irqs), +}; + +static const struct regmap_irq max8907_rtc_irqs[] = { + { .reg_offset = 0, .mask = 1 << 2, }, + { .reg_offset = 0, .mask = 1 << 3, }, +}; + +static const struct regmap_irq_chip max8907_rtc_irq_chip = { + .name = "max8907 rtc", + .status_base = MAX8907_REG_RTC_IRQ, + .mask_base = MAX8907_REG_RTC_IRQ_MASK, + .num_regs = 1, + .irqs = max8907_rtc_irqs, + .num_irqs = ARRAY_SIZE(max8907_rtc_irqs), +}; + +static __devinit int max8907_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct max8907 *max8907; + int ret; + + max8907 = devm_kzalloc(&i2c->dev, sizeof(struct max8907), GFP_KERNEL); + if (!max8907) { + ret = -ENOMEM; + goto err_alloc_drvdata; + } + + max8907->dev = &i2c->dev; + dev_set_drvdata(max8907->dev, max8907); + + max8907->i2c_gen = i2c; + i2c_set_clientdata(i2c, max8907); + max8907->regmap_gen = devm_regmap_init_i2c(i2c, + &max8907_regmap_gen_config); + if (IS_ERR(max8907->regmap_gen)) { + ret = PTR_ERR(max8907->regmap_gen); + dev_err(&i2c->dev, "gen regmap init failed: %d\n", ret); + goto err_regmap_gen; + } + + max8907->i2c_rtc = i2c_new_dummy(i2c->adapter, MAX8907_RTC_I2C_ADDR); + if (!max8907->i2c_rtc) { + ret = -ENOMEM; + goto err_dummy_rtc; + } + i2c_set_clientdata(max8907->i2c_rtc, max8907); + max8907->regmap_rtc = devm_regmap_init_i2c(max8907->i2c_rtc, + &max8907_regmap_rtc_config); + if (IS_ERR(max8907->regmap_rtc)) { + ret = PTR_ERR(max8907->regmap_rtc); + dev_err(&i2c->dev, "rtc regmap init failed: %d\n", ret); + goto err_regmap_rtc; + } + + irq_set_status_flags(max8907->i2c_gen->irq, IRQ_NOAUTOEN); + + ret = regmap_add_irq_chip(max8907->regmap_gen, max8907->i2c_gen->irq, + IRQF_ONESHOT | IRQF_SHARED, -1, + &max8907_chg_irq_chip, + &max8907->irqc_chg); + if (ret != 0) { + dev_err(&i2c->dev, "failed to add chg irq chip: %d\n", ret); + goto err_irqc_chg; + } + ret = regmap_add_irq_chip(max8907->regmap_gen, max8907->i2c_gen->irq, + IRQF_ONESHOT | IRQF_SHARED, -1, + &max8907_on_off_irq_chip, + &max8907->irqc_on_off); + if (ret != 0) { + dev_err(&i2c->dev, "failed to add on off irq chip: %d\n", ret); + goto err_irqc_on_off; + } + ret = regmap_add_irq_chip(max8907->regmap_rtc, max8907->i2c_gen->irq, + IRQF_ONESHOT | IRQF_SHARED, -1, + &max8907_rtc_irq_chip, + &max8907->irqc_rtc); + if (ret != 0) { + dev_err(&i2c->dev, "failed to add rtc irq chip: %d\n", ret); + goto err_irqc_rtc; + } + + enable_irq(max8907->i2c_gen->irq); + + ret = mfd_add_devices(max8907->dev, -1, max8907_cells, + ARRAY_SIZE(max8907_cells), NULL, 0, NULL); + if (ret != 0) { + dev_err(&i2c->dev, "failed to add MFD devices %d\n", ret); + goto err_add_devices; + } + + return 0; + +err_add_devices: + regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_rtc); +err_irqc_rtc: + regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_on_off); +err_irqc_on_off: + regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_chg); +err_irqc_chg: +err_regmap_rtc: + i2c_unregister_device(max8907->i2c_rtc); +err_dummy_rtc: +err_regmap_gen: +err_alloc_drvdata: + return ret; +} + +static __devexit int max8907_i2c_remove(struct i2c_client *i2c) +{ + struct max8907 *max8907 = i2c_get_clientdata(i2c); + + mfd_remove_devices(max8907->dev); + + regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_rtc); + regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_on_off); + regmap_del_irq_chip(max8907->i2c_gen->irq, max8907->irqc_chg); + + i2c_unregister_device(max8907->i2c_rtc); + + return 0; +} + +#ifdef CONFIG_OF +static struct of_device_id max8907_of_match[] = { + { .compatible = "maxim,max8907" }, + { }, +}; +MODULE_DEVICE_TABLE(of, max8907_of_match); +#endif + +static const struct i2c_device_id max8907_i2c_id[] = { + {"max8907", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, max8907_i2c_id); + +static struct i2c_driver max8907_i2c_driver = { + .driver = { + .name = "max8907", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(max8907_of_match), + }, + .probe = max8907_i2c_probe, + .remove = max8907_i2c_remove, + .id_table = max8907_i2c_id, +}; + +static int __init max8907_i2c_init(void) +{ + int ret = -ENODEV; + + ret = i2c_add_driver(&max8907_i2c_driver); + if (ret != 0) + pr_err("Failed to register I2C driver: %d\n", ret); + + return ret; +} +subsys_initcall(max8907_i2c_init); + +static void __exit max8907_i2c_exit(void) +{ + i2c_del_driver(&max8907_i2c_driver); +} +module_exit(max8907_i2c_exit); + +MODULE_DESCRIPTION("MAX8907 multi-function core driver"); +MODULE_AUTHOR("Gyungoh Yoo "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.2 From 8d2493781ad910019e9dc63dbf99f6dd2a8a2083 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 4 Aug 2012 14:00:31 +0200 Subject: mfd: palmas: Drop kfree of devm_kzalloc's data Using kfree to free data allocated with devm_kzalloc causes double frees. The semantic patch that fixes this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression x; @@ x = devm_kzalloc(...) ... ?-kfree(x); // Signed-off-by: Julia Lawall Signed-off-by: Samuel Ortiz --- drivers/mfd/palmas.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index a345f9bb7b47..e7a7415b8c2b 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c @@ -464,7 +464,6 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c, err: mfd_remove_devices(palmas->dev); - kfree(palmas); return ret; } -- cgit v1.2.2 From 15e27b1088245a2de3b7d09d39cd209212eb16af Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 7 Sep 2012 12:14:56 +0100 Subject: mfd: Provide the tc3589x with its own IRQ domain In preparation for Device Tree enablement all IRQ controllers should control their own IRQ domain. This patch provides just that. Signed-off-by: Lee Jones Acked-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/tc3589x.c | 73 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index b56ba6b43294..2df44acaf907 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -168,8 +169,9 @@ again: while (status) { int bit = __ffs(status); + int virq = irq_create_mapping(tc3589x->domain, bit); - handle_nested_irq(tc3589x->irq_base + bit); + handle_nested_irq(virq); status &= ~(1 << bit); } @@ -186,38 +188,60 @@ again: return IRQ_HANDLED; } -static int tc3589x_irq_init(struct tc3589x *tc3589x) +static int tc3589x_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hwirq) { - int base = tc3589x->irq_base; - int irq; + struct tc3589x *tc3589x = d->host_data; - for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) { - irq_set_chip_data(irq, tc3589x); - irq_set_chip_and_handler(irq, &dummy_irq_chip, - handle_edge_irq); - irq_set_nested_thread(irq, 1); + irq_set_chip_data(virq, tc3589x); + irq_set_chip_and_handler(virq, &dummy_irq_chip, + handle_edge_irq); + irq_set_nested_thread(virq, 1); #ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); + set_irq_flags(virq, IRQF_VALID); #else - irq_set_noprobe(irq); + irq_set_noprobe(virq); #endif - } return 0; } -static void tc3589x_irq_remove(struct tc3589x *tc3589x) +static void tc3589x_irq_unmap(struct irq_domain *d, unsigned int virq) { - int base = tc3589x->irq_base; - int irq; - - for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) { #ifdef CONFIG_ARM - set_irq_flags(irq, 0); + set_irq_flags(virq, 0); #endif - irq_set_chip_and_handler(irq, NULL, NULL); - irq_set_chip_data(irq, NULL); + irq_set_chip_and_handler(virq, NULL, NULL); + irq_set_chip_data(virq, NULL); +} + +static struct irq_domain_ops tc3589x_irq_ops = { + .map = tc3589x_irq_map, + .unmap = tc3589x_irq_unmap, + .xlate = irq_domain_xlate_twocell, +}; + +static int tc3589x_irq_init(struct tc3589x *tc3589x) +{ + int base = tc3589x->irq_base; + + if (base) { + tc3589x->domain = irq_domain_add_legacy( + NULL, TC3589x_NR_INTERNAL_IRQS, base, + 0, &tc3589x_irq_ops, tc3589x); } + else { + tc3589x->domain = irq_domain_add_linear( + NULL, TC3589x_NR_INTERNAL_IRQS, + &tc3589x_irq_ops, tc3589x); + } + + if (!tc3589x->domain) { + dev_err(tc3589x->dev, "Failed to create irqdomain\n"); + return -ENOSYS; + } + + return 0; } static int tc3589x_chip_init(struct tc3589x *tc3589x) @@ -263,7 +287,7 @@ static int __devinit tc3589x_device_init(struct tc3589x *tc3589x) if (blocks & TC3589x_BLOCK_GPIO) { ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio, ARRAY_SIZE(tc3589x_dev_gpio), NULL, - tc3589x->irq_base, NULL); + tc3589x->irq_base, tc3589x->domain); if (ret) { dev_err(tc3589x->dev, "failed to add gpio child\n"); return ret; @@ -274,7 +298,7 @@ static int __devinit tc3589x_device_init(struct tc3589x *tc3589x) if (blocks & TC3589x_BLOCK_KEYPAD) { ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad, ARRAY_SIZE(tc3589x_dev_keypad), NULL, - tc3589x->irq_base, NULL); + tc3589x->irq_base, tc3589x->domain); if (ret) { dev_err(tc3589x->dev, "failed to keypad child\n"); return ret; @@ -323,7 +347,7 @@ static int __devinit tc3589x_probe(struct i2c_client *i2c, "tc3589x", tc3589x); if (ret) { dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret); - goto out_removeirq; + goto out_free; } ret = tc3589x_device_init(tc3589x); @@ -336,8 +360,6 @@ static int __devinit tc3589x_probe(struct i2c_client *i2c, out_freeirq: free_irq(tc3589x->i2c->irq, tc3589x); -out_removeirq: - tc3589x_irq_remove(tc3589x); out_free: kfree(tc3589x); return ret; @@ -350,7 +372,6 @@ static int __devexit tc3589x_remove(struct i2c_client *client) mfd_remove_devices(tc3589x->dev); free_irq(tc3589x->i2c->irq, tc3589x); - tc3589x_irq_remove(tc3589x); kfree(tc3589x); -- cgit v1.2.2 From a435ae1d51e2f18414f2a87219fdbe068231e692 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 7 Sep 2012 12:14:57 +0100 Subject: mfd: Enable the tc3589x for Device Tree Here we provide a means to probe and extract vital information from Device Tree when booting with it enabled. Without this patch sub-devices wouldn't be able to reference the tc3589x from Device Tree. Signed-off-by: Lee Jones Acked-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/tc3589x.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index 2df44acaf907..8f4c853ca116 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -146,6 +147,7 @@ static struct mfd_cell tc3589x_dev_gpio[] = { .name = "tc3589x-gpio", .num_resources = ARRAY_SIZE(gpio_resources), .resources = &gpio_resources[0], + .of_compatible = "tc3589x-gpio", }, }; @@ -154,6 +156,7 @@ static struct mfd_cell tc3589x_dev_keypad[] = { .name = "tc3589x-keypad", .num_resources = ARRAY_SIZE(keypad_resources), .resources = &keypad_resources[0], + .of_compatible = "tc3589x-keypad", }, }; @@ -221,7 +224,7 @@ static struct irq_domain_ops tc3589x_irq_ops = { .xlate = irq_domain_xlate_twocell, }; -static int tc3589x_irq_init(struct tc3589x *tc3589x) +static int tc3589x_irq_init(struct tc3589x *tc3589x, struct device_node *np) { int base = tc3589x->irq_base; @@ -232,7 +235,7 @@ static int tc3589x_irq_init(struct tc3589x *tc3589x) } else { tc3589x->domain = irq_domain_add_linear( - NULL, TC3589x_NR_INTERNAL_IRQS, + np, TC3589x_NR_INTERNAL_IRQS, &tc3589x_irq_ops, tc3589x); } @@ -309,13 +312,47 @@ static int __devinit tc3589x_device_init(struct tc3589x *tc3589x) return ret; } +static int tc3589x_of_probe(struct device_node *np, + struct tc3589x_platform_data *pdata) +{ + struct device_node *child; + + for_each_child_of_node(np, child) { + if (!strcmp(child->name, "tc3589x_gpio")) { + pdata->block |= TC3589x_BLOCK_GPIO; + } + if (!strcmp(child->name, "tc3589x_keypad")) { + pdata->block |= TC3589x_BLOCK_KEYPAD; + } + } + + return 0; +} + static int __devinit tc3589x_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct tc3589x_platform_data *pdata = i2c->dev.platform_data; + struct device_node *np = i2c->dev.of_node; struct tc3589x *tc3589x; int ret; + if (!pdata) { + if (np) { + pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + ret = tc3589x_of_probe(np, pdata); + if (ret) + return ret; + } + else { + dev_err(&i2c->dev, "No platform data or DT found\n"); + return -EINVAL; + } + } + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK)) return -EIO; @@ -338,7 +375,7 @@ static int __devinit tc3589x_probe(struct i2c_client *i2c, if (ret) goto out_free; - ret = tc3589x_irq_init(tc3589x); + ret = tc3589x_irq_init(tc3589x, np); if (ret) goto out_free; -- cgit v1.2.2 From 87d687301f380729ec320619f100f3ba39f3693d Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Wed, 5 Sep 2012 10:57:13 +0800 Subject: mfd: Add syscon driver based on regmap Add regmap based syscon driver. This is usually used for access misc bits in registers which does not belong to a specific module, for example, IMX IOMUXC GPR and ANATOP. With this driver, client can use generic regmap API to access registers which are registered into syscon. Reviewed-by: Mark Brown Acked-by: Stephen Warren Signed-off-by: Dong Aisheng Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 8 +++ drivers/mfd/Makefile | 1 + drivers/mfd/syscon.c | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 drivers/mfd/syscon.c (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 856ec00ab787..909d84b1f5c1 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1004,6 +1004,14 @@ config MFD_ANATOP MFD controller. This controller embeds regulator and thermal devices for Freescale i.MX platforms. +config MFD_SYSCON + bool "System Controller Register R/W Based on Regmap" + depends on OF + select REGMAP_MMIO + help + Select this option to enable accessing system control registers + via regmap. + config MFD_PALMAS bool "Support for the TI Palmas series chips" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 2a4108d98442..07b66aff30b4 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -132,4 +132,5 @@ obj-$(CONFIG_MFD_PALMAS) += palmas.o obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o +obj-$(CONFIG_MFD_SYSCON) += syscon.o obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c new file mode 100644 index 000000000000..65fe609026cc --- /dev/null +++ b/drivers/mfd/syscon.c @@ -0,0 +1,176 @@ +/* + * System Control Driver + * + * Copyright (C) 2012 Freescale Semiconductor, Inc. + * Copyright (C) 2012 Linaro Ltd. + * + * Author: Dong Aisheng + * + * 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 + +static struct platform_driver syscon_driver; + +struct syscon { + struct device *dev; + void __iomem *base; + struct regmap *regmap; +}; + +static int syscon_match(struct device *dev, void *data) +{ + struct syscon *syscon = dev_get_drvdata(dev); + struct device_node *dn = data; + + return (syscon->dev->of_node == dn) ? 1 : 0; +} + +struct regmap *syscon_node_to_regmap(struct device_node *np) +{ + struct syscon *syscon; + struct device *dev; + + dev = driver_find_device(&syscon_driver.driver, NULL, np, + syscon_match); + if (!dev) + return ERR_PTR(-EPROBE_DEFER); + + syscon = dev_get_drvdata(dev); + + return syscon->regmap; +} +EXPORT_SYMBOL_GPL(syscon_node_to_regmap); + +struct regmap *syscon_regmap_lookup_by_compatible(const char *s) +{ + struct device_node *syscon_np; + struct regmap *regmap; + + syscon_np = of_find_compatible_node(NULL, NULL, s); + if (!syscon_np) + return ERR_PTR(-ENODEV); + + regmap = syscon_node_to_regmap(syscon_np); + of_node_put(syscon_np); + + return regmap; +} +EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible); + +struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, + const char *property) +{ + struct device_node *syscon_np; + struct regmap *regmap; + + syscon_np = of_parse_phandle(np, property, 0); + if (!syscon_np) + return ERR_PTR(-ENODEV); + + regmap = syscon_node_to_regmap(syscon_np); + of_node_put(syscon_np); + + return regmap; +} +EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle); + +static const struct of_device_id of_syscon_match[] = { + { .compatible = "syscon", }, + { }, +}; + +static struct regmap_config syscon_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static int __devinit syscon_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct syscon *syscon; + struct resource res; + int ret; + + if (!np) + return -ENOENT; + + syscon = devm_kzalloc(dev, sizeof(struct syscon), + GFP_KERNEL); + if (!syscon) + return -ENOMEM; + + syscon->base = of_iomap(np, 0); + if (!syscon->base) + return -EADDRNOTAVAIL; + + ret = of_address_to_resource(np, 0, &res); + if (ret) + return ret; + + syscon_regmap_config.max_register = res.end - res.start - 3; + syscon->regmap = devm_regmap_init_mmio(dev, syscon->base, + &syscon_regmap_config); + if (IS_ERR(syscon->regmap)) { + dev_err(dev, "regmap init failed\n"); + return PTR_ERR(syscon->regmap); + } + + syscon->dev = dev; + platform_set_drvdata(pdev, syscon); + + dev_info(dev, "syscon regmap start 0x%x end 0x%x registered\n", + res.start, res.end); + + return 0; +} + +static int __devexit syscon_remove(struct platform_device *pdev) +{ + struct syscon *syscon; + + syscon = platform_get_drvdata(pdev); + iounmap(syscon->base); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver syscon_driver = { + .driver = { + .name = "syscon", + .owner = THIS_MODULE, + .of_match_table = of_syscon_match, + }, + .probe = syscon_probe, + .remove = __devexit_p(syscon_remove), +}; + +static int __init syscon_init(void) +{ + return platform_driver_register(&syscon_driver); +} +postcore_initcall(syscon_init); + +static void __exit syscon_exit(void) +{ + platform_driver_unregister(&syscon_driver); +} +module_exit(syscon_exit); + +MODULE_AUTHOR("Dong Aisheng "); +MODULE_DESCRIPTION("System Control driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.2 From baa64151aecccedbafae1bbc0c167c8b2a711752 Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Wed, 5 Sep 2012 10:57:15 +0800 Subject: regulator: anatop-regulator: Convert to use syscon to access anatop register Using syscon to access anatop register. Acked-by: Mark Brown Acked-by: Stephen Warren Signed-off-by: Dong Aisheng Signed-off-by: Samuel Ortiz --- drivers/regulator/Kconfig | 2 +- drivers/regulator/anatop-regulator.c | 31 +++++++++++++++++++++---------- 2 files changed, 22 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 4e932cc695e9..2ae1d97fac1e 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -112,7 +112,7 @@ config REGULATOR_DA9052 config REGULATOR_ANATOP tristate "Freescale i.MX on-chip ANATOP LDO regulators" - depends on MFD_ANATOP + depends on MFD_SYSCON help Say y here to support Freescale i.MX on-chip ANATOP LDOs regulators. It is recommended that this option be diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index e9c2085f9dfb..596535dd917a 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -21,19 +21,20 @@ #include #include #include +#include #include #include #include #include #include -#include +#include #include #include struct anatop_regulator { const char *name; u32 control_reg; - struct anatop *mfd; + struct regmap *anatop; int vol_bit_shift; int vol_bit_width; int min_bit_val; @@ -43,7 +44,8 @@ struct anatop_regulator { struct regulator_init_data *initdata; }; -static int anatop_set_voltage_sel(struct regulator_dev *reg, unsigned selector) +static int anatop_regmap_set_voltage_sel(struct regulator_dev *reg, + unsigned selector) { struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); u32 val, mask; @@ -56,12 +58,13 @@ static int anatop_set_voltage_sel(struct regulator_dev *reg, unsigned selector) mask = ((1 << anatop_reg->vol_bit_width) - 1) << anatop_reg->vol_bit_shift; val <<= anatop_reg->vol_bit_shift; - anatop_write_reg(anatop_reg->mfd, anatop_reg->control_reg, val, mask); + regmap_update_bits(anatop_reg->anatop, anatop_reg->control_reg, + mask, val); return 0; } -static int anatop_get_voltage_sel(struct regulator_dev *reg) +static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg) { struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); u32 val; @@ -69,7 +72,7 @@ static int anatop_get_voltage_sel(struct regulator_dev *reg) if (!anatop_reg->control_reg) return -ENOTSUPP; - val = anatop_read_reg(anatop_reg->mfd, anatop_reg->control_reg); + regmap_read(anatop_reg->anatop, anatop_reg->control_reg, &val); val = (val & ((1 << anatop_reg->vol_bit_width) - 1)) >> anatop_reg->vol_bit_shift; @@ -77,8 +80,8 @@ static int anatop_get_voltage_sel(struct regulator_dev *reg) } static struct regulator_ops anatop_rops = { - .set_voltage_sel = anatop_set_voltage_sel, - .get_voltage_sel = anatop_get_voltage_sel, + .set_voltage_sel = anatop_regmap_set_voltage_sel, + .get_voltage_sel = anatop_regmap_get_voltage_sel, .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, }; @@ -87,11 +90,11 @@ static int __devinit anatop_regulator_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; + struct device_node *anatop_np; struct regulator_desc *rdesc; struct regulator_dev *rdev; struct anatop_regulator *sreg; struct regulator_init_data *initdata; - struct anatop *anatopmfd = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = { }; int ret = 0; @@ -108,7 +111,15 @@ static int __devinit anatop_regulator_probe(struct platform_device *pdev) rdesc->ops = &anatop_rops; rdesc->type = REGULATOR_VOLTAGE; rdesc->owner = THIS_MODULE; - sreg->mfd = anatopmfd; + + anatop_np = of_get_parent(np); + if (!anatop_np) + return -ENODEV; + sreg->anatop = syscon_node_to_regmap(anatop_np); + of_node_put(anatop_np); + if (IS_ERR(sreg->anatop)) + return PTR_ERR(sreg->anatop); + ret = of_property_read_u32(np, "anatop-reg-offset", &sreg->control_reg); if (ret) { -- cgit v1.2.2 From 4adcefd3f908f02a5266cb37d82dc34615edbd3b Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Wed, 5 Sep 2012 10:57:16 +0800 Subject: mfd: anatop-mfd: remove anatop driver The anatop registers are accessed via syscon now, no one will use mfd anatop driver anymore, remove it. Acked-by: Stephen Warren Signed-off-by: Dong Aisheng Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 8 --- drivers/mfd/Makefile | 1 - drivers/mfd/anatop-mfd.c | 124 ----------------------------------------------- 3 files changed, 133 deletions(-) delete mode 100644 drivers/mfd/anatop-mfd.c (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 909d84b1f5c1..b0d7d9b5b7d4 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -996,14 +996,6 @@ config MFD_STA2X11 depends on STA2X11 select MFD_CORE -config MFD_ANATOP - bool "Support for Freescale i.MX on-chip ANATOP controller" - depends on SOC_IMX6Q - help - Select this option to enable Freescale i.MX on-chip ANATOP - MFD controller. This controller embeds regulator and - thermal devices for Freescale i.MX platforms. - config MFD_SYSCON bool "System Controller Register R/W Based on Regmap" depends on OF diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 07b66aff30b4..b88cdb876e15 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -131,6 +131,5 @@ obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o obj-$(CONFIG_MFD_PALMAS) += palmas.o obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o -obj-$(CONFIG_MFD_ANATOP) += anatop-mfd.o obj-$(CONFIG_MFD_SYSCON) += syscon.o obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o diff --git a/drivers/mfd/anatop-mfd.c b/drivers/mfd/anatop-mfd.c deleted file mode 100644 index 5576e07576de..000000000000 --- a/drivers/mfd/anatop-mfd.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Anatop MFD driver - * - * Copyright (C) 2012 Ying-Chun Liu (PaulLiu) - * Copyright (C) 2012 Linaro - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -u32 anatop_read_reg(struct anatop *adata, u32 addr) -{ - return readl(adata->ioreg + addr); -} -EXPORT_SYMBOL_GPL(anatop_read_reg); - -void anatop_write_reg(struct anatop *adata, u32 addr, u32 data, u32 mask) -{ - u32 val; - - data &= mask; - - spin_lock(&adata->reglock); - val = readl(adata->ioreg + addr); - val &= ~mask; - val |= data; - writel(val, adata->ioreg + addr); - spin_unlock(&adata->reglock); -} -EXPORT_SYMBOL_GPL(anatop_write_reg); - -static const struct of_device_id of_anatop_match[] = { - { .compatible = "fsl,imx6q-anatop", }, - { }, -}; - -static int __devinit of_anatop_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; - void *ioreg; - struct anatop *drvdata; - - ioreg = of_iomap(np, 0); - if (!ioreg) - return -EADDRNOTAVAIL; - drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; - drvdata->ioreg = ioreg; - spin_lock_init(&drvdata->reglock); - platform_set_drvdata(pdev, drvdata); - of_platform_populate(np, NULL, NULL, dev); - - return 0; -} - -static int __devexit of_anatop_remove(struct platform_device *pdev) -{ - struct anatop *drvdata; - drvdata = platform_get_drvdata(pdev); - iounmap(drvdata->ioreg); - - return 0; -} - -static struct platform_driver anatop_of_driver = { - .driver = { - .name = "anatop-mfd", - .owner = THIS_MODULE, - .of_match_table = of_anatop_match, - }, - .probe = of_anatop_probe, - .remove = of_anatop_remove, -}; - -static int __init anatop_init(void) -{ - return platform_driver_register(&anatop_of_driver); -} -postcore_initcall(anatop_init); - -static void __exit anatop_exit(void) -{ - platform_driver_unregister(&anatop_of_driver); -} -module_exit(anatop_exit); - -MODULE_AUTHOR("Ying-Chun Liu (PaulLiu) "); -MODULE_DESCRIPTION("ANATOP MFD driver"); -MODULE_LICENSE("GPL v2"); -- cgit v1.2.2 From 0a37fc56888c37049f60aab398fddceafd33fe72 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 9 Aug 2012 16:53:54 +0100 Subject: mfd: Use the AB8500's IRQ domain to convert hwirq to virq Before the AB8500 had its own IRQ domain, the IRQ handler would take the fired local IRQ (hwirq) and add it to the irq_base to convert it to an IRQ number which Linux would understand (virq). However, the IRQ base is not always used anymore since we can make use of Linear domains. It's better to use the AB8500 hwirq -> virq mapping helper function to convert them instead. That's what we do here. Signed-off-by: Lee Jones Acked-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index dd91951c68f0..a3aceffb60fe 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -517,8 +517,9 @@ static irqreturn_t ab8500_irq(int irq, void *dev) do { int bit = __ffs(value); int line = i * 8 + bit; + int virq = ab8500_irq_get_virq(ab8500, line); - handle_nested_irq(ab8500->irq_base + line); + handle_nested_irq(virq); value &= ~(1 << bit); } while (value); -- cgit v1.2.2 From 41569a16e4e12910e14ce98edea9ef30bd89299b Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 10 Sep 2012 13:46:19 +0300 Subject: mfd: twl4030-audio: Clean up MODULE_* and platform_driver part Place the MODULE_* lines in the same block and add MODULE_DESCRIPTION. Rearange the platform_driver structure at the same time. Signed-off-by: Peter Ujfalusi Signed-off-by: Samuel Ortiz --- drivers/mfd/twl4030-audio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index 77c9acb14583..e330dfcc74e5 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -250,18 +250,18 @@ static int __devexit twl4030_audio_remove(struct platform_device *pdev) return 0; } -MODULE_ALIAS("platform:twl4030-audio"); - static struct platform_driver twl4030_audio_driver = { - .probe = twl4030_audio_probe, - .remove = __devexit_p(twl4030_audio_remove), .driver = { .owner = THIS_MODULE, .name = "twl4030-audio", }, + .probe = twl4030_audio_probe, + .remove = __devexit_p(twl4030_audio_remove), }; module_platform_driver(twl4030_audio_driver); MODULE_AUTHOR("Peter Ujfalusi "); +MODULE_DESCRIPTION("TWL4030 audio block MFD driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:twl4030-audio"); -- cgit v1.2.2 From 39c1421db694ee2594bbb2196b1b5a3085e3c656 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 10 Sep 2012 13:46:20 +0300 Subject: mfd: twl4030-audio: Convert to use devm_kzalloc To clean up the module probe and remove functions. Signed-off-by: Peter Ujfalusi Signed-off-by: Samuel Ortiz --- drivers/mfd/twl4030-audio.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index e330dfcc74e5..2ab8a1a96b91 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -188,7 +188,8 @@ static int __devinit twl4030_audio_probe(struct platform_device *pdev) twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, val, TWL4030_REG_APLL_CTL); - audio = kzalloc(sizeof(struct twl4030_audio), GFP_KERNEL); + audio = devm_kzalloc(&pdev->dev, sizeof(struct twl4030_audio), + GFP_KERNEL); if (!audio) return -ENOMEM; @@ -229,22 +230,18 @@ static int __devinit twl4030_audio_probe(struct platform_device *pdev) ret = -ENODEV; } - if (!ret) - return 0; + if (ret) { + platform_set_drvdata(pdev, NULL); + twl4030_audio_dev = NULL; + } - platform_set_drvdata(pdev, NULL); - kfree(audio); - twl4030_audio_dev = NULL; return ret; } static int __devexit twl4030_audio_remove(struct platform_device *pdev) { - struct twl4030_audio *audio = platform_get_drvdata(pdev); - mfd_remove_devices(&pdev->dev); platform_set_drvdata(pdev, NULL); - kfree(audio); twl4030_audio_dev = NULL; return 0; -- cgit v1.2.2 From cdf4b67099ee8e038178a9e7d83c1aa16618c1ca Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 10 Sep 2012 13:46:21 +0300 Subject: mfd: twl4030-audio: Rearange and clean-up the probe function To facilitate the device tree support the probe function need to be rearanged. Small cleanup in the APLL frequency selection part as well. Signed-off-by: Peter Ujfalusi Signed-off-by: Samuel Ortiz --- drivers/mfd/twl4030-audio.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index 2ab8a1a96b91..42e69ae63c44 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -169,35 +169,30 @@ static int __devinit twl4030_audio_probe(struct platform_device *pdev) return -EINVAL; } + audio = devm_kzalloc(&pdev->dev, sizeof(struct twl4030_audio), + GFP_KERNEL); + if (!audio) + return -ENOMEM; + + mutex_init(&audio->mutex); + audio->audio_mclk = pdata->audio_mclk; + /* Configure APLL_INFREQ and disable APLL if enabled */ - val = 0; - switch (pdata->audio_mclk) { + switch (audio->audio_mclk) { case 19200000: - val |= TWL4030_APLL_INFREQ_19200KHZ; + val = TWL4030_APLL_INFREQ_19200KHZ; break; case 26000000: - val |= TWL4030_APLL_INFREQ_26000KHZ; + val = TWL4030_APLL_INFREQ_26000KHZ; break; case 38400000: - val |= TWL4030_APLL_INFREQ_38400KHZ; + val = TWL4030_APLL_INFREQ_38400KHZ; break; default: dev_err(&pdev->dev, "Invalid audio_mclk\n"); return -EINVAL; } - twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, - val, TWL4030_REG_APLL_CTL); - - audio = devm_kzalloc(&pdev->dev, sizeof(struct twl4030_audio), - GFP_KERNEL); - if (!audio) - return -ENOMEM; - - platform_set_drvdata(pdev, audio); - - twl4030_audio_dev = pdev; - mutex_init(&audio->mutex); - audio->audio_mclk = pdata->audio_mclk; + twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, val, TWL4030_REG_APLL_CTL); /* Codec power */ audio->resource[TWL4030_AUDIO_RES_POWER].reg = TWL4030_REG_CODEC_MODE; @@ -222,6 +217,9 @@ static int __devinit twl4030_audio_probe(struct platform_device *pdev) childs++; } + platform_set_drvdata(pdev, audio); + twl4030_audio_dev = pdev; + if (childs) ret = mfd_add_devices(&pdev->dev, pdev->id, audio->cells, childs, NULL, 0, NULL); -- cgit v1.2.2 From 2275c544cb824b469a386e411cbcaa01a19d4f55 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 10 Sep 2012 13:46:22 +0300 Subject: mfd: twl-core: Add API to query the HFCLK rate CFG_BOOT register's HFCLK_FREQ field hold information about the used HFCLK frequency. Add possibility for users to get the configured rate based on this register. This register was configured during boot, without it the chip would not operate correctly, so we can trust on this information. Signed-off-by: Peter Ujfalusi Signed-off-by: Samuel Ortiz --- drivers/mfd/twl-core.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 1c32afed28aa..f162b68e78a8 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -552,6 +552,38 @@ int twl_get_version(void) } EXPORT_SYMBOL_GPL(twl_get_version); +/** + * twl_get_hfclk_rate - API to get TWL external HFCLK clock rate. + * + * Api to get the TWL HFCLK rate based on BOOT_CFG register. + */ +int twl_get_hfclk_rate(void) +{ + u8 ctrl; + int rate; + + twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &ctrl, R_CFG_BOOT); + + switch (ctrl & 0x3) { + case HFCLK_FREQ_19p2_MHZ: + rate = 19200000; + break; + case HFCLK_FREQ_26_MHZ: + rate = 26000000; + break; + case HFCLK_FREQ_38p4_MHZ: + rate = 38400000; + break; + default: + pr_err("TWL4030: HFCLK is not configured\n"); + rate = -EINVAL; + break; + } + + return rate; +} +EXPORT_SYMBOL_GPL(twl_get_hfclk_rate); + static struct device * add_numbered_child(unsigned chip, const char *name, int num, void *pdata, unsigned pdata_len, -- cgit v1.2.2 From c531241dcc010e4457e0eb9401aaeae0a56bf5c6 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 10 Sep 2012 13:46:23 +0300 Subject: mfd: twl4030-audio: Get audio MCLK via twl-core API instead of pdata twl-core has API to get the boot time configured HFCLK rate which has the same rate as the audio MCLK. Signed-off-by: Peter Ujfalusi Signed-off-by: Samuel Ortiz --- drivers/mfd/twl4030-audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index 42e69ae63c44..31605fa02ca1 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -175,7 +175,7 @@ static int __devinit twl4030_audio_probe(struct platform_device *pdev) return -ENOMEM; mutex_init(&audio->mutex); - audio->audio_mclk = pdata->audio_mclk; + audio->audio_mclk = twl_get_hfclk_rate(); /* Configure APLL_INFREQ and disable APLL if enabled */ switch (audio->audio_mclk) { -- cgit v1.2.2 From 019a7e6b7b312b17cd74b45d09d4ec17486c4088 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 10 Sep 2012 13:46:25 +0300 Subject: mfd: twl4030-audio: Add DT support Support for loading the twl4030 audio module via devicetree. Sub devices for codec and vibra will be created as mfd devices once the core MFD driver is loaded when the kernel is booted with a DT blob. Signed-off-by: Peter Ujfalusi Signed-off-by: Samuel Ortiz --- drivers/mfd/twl4030-audio.c | 54 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index 31605fa02ca1..5c11acf9e0fd 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include #include @@ -156,15 +158,42 @@ unsigned int twl4030_audio_get_mclk(void) } EXPORT_SYMBOL_GPL(twl4030_audio_get_mclk); +static bool twl4030_audio_has_codec(struct twl4030_audio_data *pdata, + struct device_node *node) +{ + if (pdata && pdata->codec) + return true; + + if (of_find_node_by_name(node, "codec")) + return true; + + return false; +} + +static bool twl4030_audio_has_vibra(struct twl4030_audio_data *pdata, + struct device_node *node) +{ + int vibra; + + if (pdata && pdata->vibra) + return true; + + if (!of_property_read_u32(node, "ti,enable-vibra", &vibra) && vibra) + return true; + + return false; +} + static int __devinit twl4030_audio_probe(struct platform_device *pdev) { struct twl4030_audio *audio; struct twl4030_audio_data *pdata = pdev->dev.platform_data; + struct device_node *node = pdev->dev.of_node; struct mfd_cell *cell = NULL; int ret, childs = 0; u8 val; - if (!pdata) { + if (!pdata && !node) { dev_err(&pdev->dev, "Platform data is missing\n"); return -EINVAL; } @@ -202,18 +231,22 @@ static int __devinit twl4030_audio_probe(struct platform_device *pdev) audio->resource[TWL4030_AUDIO_RES_APLL].reg = TWL4030_REG_APLL_CTL; audio->resource[TWL4030_AUDIO_RES_APLL].mask = TWL4030_APLL_EN; - if (pdata->codec) { + if (twl4030_audio_has_codec(pdata, node)) { cell = &audio->cells[childs]; cell->name = "twl4030-codec"; - cell->platform_data = pdata->codec; - cell->pdata_size = sizeof(*pdata->codec); + if (pdata) { + cell->platform_data = pdata->codec; + cell->pdata_size = sizeof(*pdata->codec); + } childs++; } - if (pdata->vibra) { + if (twl4030_audio_has_vibra(pdata, node)) { cell = &audio->cells[childs]; cell->name = "twl4030-vibra"; - cell->platform_data = pdata->vibra; - cell->pdata_size = sizeof(*pdata->vibra); + if (pdata) { + cell->platform_data = pdata->vibra; + cell->pdata_size = sizeof(*pdata->vibra); + } childs++; } @@ -245,10 +278,17 @@ static int __devexit twl4030_audio_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id twl4030_audio_of_match[] = { + {.compatible = "ti,twl4030-audio", }, + { }, +}; +MODULE_DEVICE_TABLE(of, twl4030_audio_of_match); + static struct platform_driver twl4030_audio_driver = { .driver = { .owner = THIS_MODULE, .name = "twl4030-audio", + .of_match_table = twl4030_audio_of_match, }, .probe = twl4030_audio_probe, .remove = __devexit_p(twl4030_audio_remove), -- cgit v1.2.2 From 64b9e4d803b154a78a2e76bd466bb32ad6f383de Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Mon, 10 Sep 2012 13:46:26 +0300 Subject: input: twl4030-vibra: Support for DT booted kernel Add support when the kernel has been booted with DT blob. In this case the pdata is NULL, we need to reach up to the core node and check if the codec part has been enabled to determine if we need to coexist with the codec or not. Signed-off-by: Peter Ujfalusi Acked-by: Dmitry Torokhov Signed-off-by: Samuel Ortiz --- drivers/input/misc/twl4030-vibra.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c index fc0ed9b43424..2194a3c7236a 100644 --- a/drivers/input/misc/twl4030-vibra.c +++ b/drivers/input/misc/twl4030-vibra.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -194,13 +195,26 @@ static int twl4030_vibra_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops, twl4030_vibra_suspend, twl4030_vibra_resume); +static bool twl4030_vibra_check_coexist(struct twl4030_vibra_data *pdata, + struct device_node *node) +{ + if (pdata && pdata->coexist) + return true; + + if (of_find_node_by_name(node, "codec")) + return true; + + return false; +} + static int __devinit twl4030_vibra_probe(struct platform_device *pdev) { struct twl4030_vibra_data *pdata = pdev->dev.platform_data; + struct device_node *twl4030_core_node = pdev->dev.parent->of_node; struct vibra_info *info; int ret; - if (!pdata) { + if (!pdata && !twl4030_core_node) { dev_dbg(&pdev->dev, "platform_data not available\n"); return -EINVAL; } @@ -210,7 +224,7 @@ static int __devinit twl4030_vibra_probe(struct platform_device *pdev) return -ENOMEM; info->dev = &pdev->dev; - info->coexist = pdata->coexist; + info->coexist = twl4030_vibra_check_coexist(pdata, twl4030_core_node); INIT_WORK(&info->play_work, vibra_play_work); info->input_dev = input_allocate_device(); -- cgit v1.2.2 From f78959cfa335196ba36d8c4651078f14dc07f2a8 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 18 Sep 2012 10:29:50 +0200 Subject: mfd: twl: Replace twl_has_*() macros by IS_ENABLED() Instead of reinventing macros for the same purpose, use the standard macros. Signed-off-by: Thierry Reding Acked-by: Peter Ujfalusi Signed-off-by: Samuel Ortiz --- drivers/mfd/twl-core.c | 117 +++++++++++-------------------------------------- 1 file changed, 25 insertions(+), 92 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index f162b68e78a8..e208d88d2180 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -63,70 +63,6 @@ #define DRIVER_NAME "twl" -#if defined(CONFIG_KEYBOARD_TWL4030) || defined(CONFIG_KEYBOARD_TWL4030_MODULE) -#define twl_has_keypad() true -#else -#define twl_has_keypad() false -#endif - -#if defined(CONFIG_GPIO_TWL4030) || defined(CONFIG_GPIO_TWL4030_MODULE) -#define twl_has_gpio() true -#else -#define twl_has_gpio() false -#endif - -#if defined(CONFIG_REGULATOR_TWL4030) \ - || defined(CONFIG_REGULATOR_TWL4030_MODULE) -#define twl_has_regulator() true -#else -#define twl_has_regulator() false -#endif - -#if defined(CONFIG_TWL4030_MADC) || defined(CONFIG_TWL4030_MADC_MODULE) -#define twl_has_madc() true -#else -#define twl_has_madc() false -#endif - -#ifdef CONFIG_TWL4030_POWER -#define twl_has_power() true -#else -#define twl_has_power() false -#endif - -#if defined(CONFIG_RTC_DRV_TWL4030) || defined(CONFIG_RTC_DRV_TWL4030_MODULE) -#define twl_has_rtc() true -#else -#define twl_has_rtc() false -#endif - -#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE) ||\ - defined(CONFIG_TWL6030_USB) || defined(CONFIG_TWL6030_USB_MODULE) -#define twl_has_usb() true -#else -#define twl_has_usb() false -#endif - -#if defined(CONFIG_TWL4030_WATCHDOG) || \ - defined(CONFIG_TWL4030_WATCHDOG_MODULE) -#define twl_has_watchdog() true -#else -#define twl_has_watchdog() false -#endif - -#if defined(CONFIG_MFD_TWL4030_AUDIO) || \ - defined(CONFIG_MFD_TWL4030_AUDIO_MODULE) -#define twl_has_codec() true -#else -#define twl_has_codec() false -#endif - -#if defined(CONFIG_CHARGER_TWL4030) || defined(CONFIG_CHARGER_TWL4030_MODULE) -#define twl_has_bci() true -#else -#define twl_has_bci() false -#endif - /* Triton Core internal information (BEGIN) */ /* Last - for index max*/ @@ -134,13 +70,6 @@ #define TWL_NUM_SLAVES 4 -#if defined(CONFIG_INPUT_TWL4030_PWRBUTTON) \ - || defined(CONFIG_INPUT_TWL4030_PWRBUTTON_MODULE) -#define twl_has_pwrbutton() true -#else -#define twl_has_pwrbutton() false -#endif - #define SUB_CHIP_ID0 0 #define SUB_CHIP_ID1 1 #define SUB_CHIP_ID2 2 @@ -701,7 +630,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, struct device *child; unsigned sub_chip_id; - if (twl_has_gpio() && pdata->gpio) { + if (IS_ENABLED(CONFIG_GPIO_TWL4030) && pdata->gpio) { child = add_child(SUB_CHIP_ID1, "twl4030_gpio", pdata->gpio, sizeof(*pdata->gpio), false, irq_base + GPIO_INTR_OFFSET, 0); @@ -709,7 +638,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); } - if (twl_has_keypad() && pdata->keypad) { + if (IS_ENABLED(CONFIG_KEYBOARD_TWL4030) && pdata->keypad) { child = add_child(SUB_CHIP_ID2, "twl4030_keypad", pdata->keypad, sizeof(*pdata->keypad), true, irq_base + KEYPAD_INTR_OFFSET, 0); @@ -717,7 +646,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); } - if (twl_has_madc() && pdata->madc) { + if (IS_ENABLED(CONFIG_TWL4030_MADC) && pdata->madc) { child = add_child(2, "twl4030_madc", pdata->madc, sizeof(*pdata->madc), true, irq_base + MADC_INTR_OFFSET, 0); @@ -725,7 +654,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); } - if (twl_has_rtc()) { + if (IS_ENABLED(CONFIG_RTC_DRV_TWL4030)) { /* * REVISIT platform_data here currently might expose the * "msecure" line ... but for now we just expect board @@ -741,7 +670,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); } - if (twl_has_usb() && pdata->usb && twl_class_is_4030()) { + if (IS_ENABLED(CONFIG_TWL4030_USB) && pdata->usb && + twl_class_is_4030()) { static struct regulator_consumer_supply usb1v5 = { .supply = "usb1v5", @@ -755,7 +685,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, }; /* First add the regulators so that they can be used by transceiver */ - if (twl_has_regulator()) { + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030)) { /* this is a template that gets copied */ struct regulator_init_data usb_fixed = { .constraints.valid_modes_mask = @@ -797,18 +727,19 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); /* we need to connect regulators to this transceiver */ - if (twl_has_regulator() && child) { + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && child) { usb1v5.dev_name = dev_name(child); usb1v8.dev_name = dev_name(child); usb3v1[0].dev_name = dev_name(child); } } - if (twl_has_usb() && pdata->usb && twl_class_is_6030()) { + if (IS_ENABLED(CONFIG_TWL6030_USB) && pdata->usb && + twl_class_is_6030()) { static struct regulator_consumer_supply usb3v3; int regulator; - if (twl_has_regulator()) { + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030)) { /* this is a template that gets copied */ struct regulator_init_data usb_fixed = { .constraints.valid_modes_mask = @@ -845,9 +776,10 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, if (IS_ERR(child)) return PTR_ERR(child); /* we need to connect regulators to this transceiver */ - if (twl_has_regulator() && child) + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && child) usb3v3.dev_name = dev_name(child); - } else if (twl_has_regulator() && twl_class_is_6030()) { + } else if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && + twl_class_is_6030()) { if (features & TWL6025_SUBCLASS) child = add_regulator(TWL6025_REG_LDOUSB, pdata->ldousb, features); @@ -859,20 +791,21 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); } - if (twl_has_watchdog() && twl_class_is_4030()) { + if (IS_ENABLED(CONFIG_TWL4030_WATCHDOG) && twl_class_is_4030()) { child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0); if (IS_ERR(child)) return PTR_ERR(child); } - if (twl_has_pwrbutton() && twl_class_is_4030()) { + if (IS_ENABLED(CONFIG_INPUT_TWL4030_PWRBUTTON) && twl_class_is_4030()) { child = add_child(1, "twl4030_pwrbutton", NULL, 0, true, irq_base + 8 + 0, 0); if (IS_ERR(child)) return PTR_ERR(child); } - if (twl_has_codec() && pdata->audio && twl_class_is_4030()) { + if (IS_ENABLED(CONFIG_MFD_TWL4030_AUDIO) && pdata->audio && + twl_class_is_4030()) { sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid; child = add_child(sub_chip_id, "twl4030-audio", pdata->audio, sizeof(*pdata->audio), @@ -882,7 +815,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, } /* twl4030 regulators */ - if (twl_has_regulator() && twl_class_is_4030()) { + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_4030()) { child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1, features); if (IS_ERR(child)) @@ -937,7 +870,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, } /* maybe add LDOs that are omitted on cost-reduced parts */ - if (twl_has_regulator() && !(features & TPS_SUBSET) + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && !(features & TPS_SUBSET) && twl_class_is_4030()) { child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2, features); @@ -971,7 +904,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, } /* twl6030 regulators */ - if (twl_has_regulator() && twl_class_is_6030() && + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030() && !(features & TWL6025_SUBCLASS)) { child = add_regulator(TWL6030_REG_VDD1, pdata->vdd1, features); @@ -1045,7 +978,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, } /* 6030 and 6025 share this regulator */ - if (twl_has_regulator() && twl_class_is_6030()) { + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030()) { child = add_regulator(TWL6030_REG_VANA, pdata->vana, features); if (IS_ERR(child)) @@ -1053,7 +986,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, } /* twl6025 regulators */ - if (twl_has_regulator() && twl_class_is_6030() && + if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_6030() && (features & TWL6025_SUBCLASS)) { child = add_regulator(TWL6025_REG_LDO5, pdata->ldo5, features); @@ -1112,7 +1045,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, } - if (twl_has_bci() && pdata->bci && + if (IS_ENABLED(CONFIG_CHARGER_TWL4030) && pdata->bci && !(features & (TPS_SUBSET | TWL5031))) { child = add_child(3, "twl4030_bci", pdata->bci, sizeof(*pdata->bci), false, @@ -1324,7 +1257,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) } /* load power event scripts */ - if (twl_has_power() && pdata->power) + if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata->power) twl4030_power_init(pdata->power); /* Maybe init the T2 Interrupt subsystem */ -- cgit v1.2.2 From 48a364b758f861b21747a5148f26aedc504edb7f Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 18 Sep 2012 10:29:51 +0200 Subject: pwm: Move TWL6030 PWM driver to PWM framework This commit moves the driver to drivers/pwm and converts it to the new PWM framework. In order for this to work properly, register the PWM as child of the multi-function TWL6030 device. Signed-off-by: Thierry Reding Acked-by: Peter Ujfalusi Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 10 --- drivers/mfd/Makefile | 1 - drivers/mfd/twl-core.c | 7 ++ drivers/mfd/twl6030-pwm.c | 165 ----------------------------------------- drivers/pwm/Kconfig | 9 +++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-twl6030.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 201 insertions(+), 176 deletions(-) delete mode 100644 drivers/mfd/twl6030-pwm.c create mode 100644 drivers/pwm/pwm-twl6030.c (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b0d7d9b5b7d4..2143fd283a74 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -298,16 +298,6 @@ config MFD_TWL4030_AUDIO select MFD_CORE default n -config TWL6030_PWM - tristate "TWL6030 PWM (Pulse Width Modulator) Support" - depends on TWL4030_CORE - select HAVE_PWM - depends on !PWM - default n - help - Say yes here if you want support for TWL6030 PWM. - This is used to control charging LED brightness. - config TWL6040_CORE bool "Support for TWL6040 audio codec" depends on I2C=y && GENERIC_HARDIRQS diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index b88cdb876e15..95dfa14ad174 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -63,7 +63,6 @@ obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o -obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o obj-$(CONFIG_TWL6040_CORE) += twl6040-core.o twl6040-irq.o obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index e208d88d2180..3d700129cf3e 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -670,6 +670,13 @@ add_children(struct twl4030_platform_data *pdata, unsigned irq_base, return PTR_ERR(child); } + if (IS_ENABLED(CONFIG_PWM_TWL6030) && twl_class_is_6030()) { + child = add_child(TWL6030_MODULE_ID1, "twl6030-pwm", NULL, 0, + false, 0, 0); + if (IS_ERR(child)) + return PTR_ERR(child); + } + if (IS_ENABLED(CONFIG_TWL4030_USB) && pdata->usb && twl_class_is_4030()) { diff --git a/drivers/mfd/twl6030-pwm.c b/drivers/mfd/twl6030-pwm.c deleted file mode 100644 index e8fee147678d..000000000000 --- a/drivers/mfd/twl6030-pwm.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * twl6030_pwm.c - * Driver for PHOENIX (TWL6030) Pulse Width Modulator - * - * Copyright (C) 2010 Texas Instruments - * Author: Hemanth V - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - */ - -#include -#include -#include -#include - -#define LED_PWM_CTRL1 0xF4 -#define LED_PWM_CTRL2 0xF5 - -/* Max value for CTRL1 register */ -#define PWM_CTRL1_MAX 255 - -/* Pull down disable */ -#define PWM_CTRL2_DIS_PD (1 << 6) - -/* Current control 2.5 milli Amps */ -#define PWM_CTRL2_CURR_02 (2 << 4) - -/* LED supply source */ -#define PWM_CTRL2_SRC_VAC (1 << 2) - -/* LED modes */ -#define PWM_CTRL2_MODE_HW (0 << 0) -#define PWM_CTRL2_MODE_SW (1 << 0) -#define PWM_CTRL2_MODE_DIS (2 << 0) - -#define PWM_CTRL2_MODE_MASK 0x3 - -struct pwm_device { - const char *label; - unsigned int pwm_id; -}; - -int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) -{ - u8 duty_cycle; - int ret; - - if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) - return -EINVAL; - - duty_cycle = (duty_ns * PWM_CTRL1_MAX) / period_ns; - - ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, duty_cycle, LED_PWM_CTRL1); - - if (ret < 0) { - pr_err("%s: Failed to configure PWM, Error %d\n", - pwm->label, ret); - return ret; - } - return 0; -} -EXPORT_SYMBOL(pwm_config); - -int pwm_enable(struct pwm_device *pwm) -{ - u8 val; - int ret; - - ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); - if (ret < 0) { - pr_err("%s: Failed to enable PWM, Error %d\n", pwm->label, ret); - return ret; - } - - /* Change mode to software control */ - val &= ~PWM_CTRL2_MODE_MASK; - val |= PWM_CTRL2_MODE_SW; - - ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); - if (ret < 0) { - pr_err("%s: Failed to enable PWM, Error %d\n", pwm->label, ret); - return ret; - } - - twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); - return 0; -} -EXPORT_SYMBOL(pwm_enable); - -void pwm_disable(struct pwm_device *pwm) -{ - u8 val; - int ret; - - ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); - if (ret < 0) { - pr_err("%s: Failed to disable PWM, Error %d\n", - pwm->label, ret); - return; - } - - val &= ~PWM_CTRL2_MODE_MASK; - val |= PWM_CTRL2_MODE_HW; - - ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); - if (ret < 0) { - pr_err("%s: Failed to disable PWM, Error %d\n", - pwm->label, ret); - return; - } - return; -} -EXPORT_SYMBOL(pwm_disable); - -struct pwm_device *pwm_request(int pwm_id, const char *label) -{ - u8 val; - int ret; - struct pwm_device *pwm; - - pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL); - if (pwm == NULL) { - pr_err("%s: failed to allocate memory\n", label); - return NULL; - } - - pwm->label = label; - pwm->pwm_id = pwm_id; - - /* Configure PWM */ - val = PWM_CTRL2_DIS_PD | PWM_CTRL2_CURR_02 | PWM_CTRL2_SRC_VAC | - PWM_CTRL2_MODE_HW; - - ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); - - if (ret < 0) { - pr_err("%s: Failed to configure PWM, Error %d\n", - pwm->label, ret); - - kfree(pwm); - return NULL; - } - - return pwm; -} -EXPORT_SYMBOL(pwm_request); - -void pwm_free(struct pwm_device *pwm) -{ - pwm_disable(pwm); - kfree(pwm); -} -EXPORT_SYMBOL(pwm_free); - -MODULE_LICENSE("GPL"); diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 8fc3808d7a3e..c7500dcdc65e 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -96,6 +96,15 @@ config PWM_TIEHRPWM To compile this driver as a module, choose M here: the module will be called pwm-tiehrpwm. +config PWM_TWL6030 + tristate "TWL6030 PWM support" + depends on TWL4030_CORE + help + Generic PWM framework driver for TWL6030. + + To compile this driver as a module, choose M here: the module + will be called pwm-twl6030. + config PWM_VT8500 tristate "vt8500 pwm support" depends on ARCH_VT8500 diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index e4b2c898964d..78f123dca30d 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -8,4 +8,5 @@ obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o +obj-$(CONFIG_PWM_TWL6030) += pwm-twl6030.o obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o diff --git a/drivers/pwm/pwm-twl6030.c b/drivers/pwm/pwm-twl6030.c new file mode 100644 index 000000000000..8e6387864ca2 --- /dev/null +++ b/drivers/pwm/pwm-twl6030.c @@ -0,0 +1,184 @@ +/* + * twl6030_pwm.c + * Driver for PHOENIX (TWL6030) Pulse Width Modulator + * + * Copyright (C) 2010 Texas Instruments + * Author: Hemanth V + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include +#include +#include +#include + +#define LED_PWM_CTRL1 0xF4 +#define LED_PWM_CTRL2 0xF5 + +/* Max value for CTRL1 register */ +#define PWM_CTRL1_MAX 255 + +/* Pull down disable */ +#define PWM_CTRL2_DIS_PD (1 << 6) + +/* Current control 2.5 milli Amps */ +#define PWM_CTRL2_CURR_02 (2 << 4) + +/* LED supply source */ +#define PWM_CTRL2_SRC_VAC (1 << 2) + +/* LED modes */ +#define PWM_CTRL2_MODE_HW (0 << 0) +#define PWM_CTRL2_MODE_SW (1 << 0) +#define PWM_CTRL2_MODE_DIS (2 << 0) + +#define PWM_CTRL2_MODE_MASK 0x3 + +struct twl6030_pwm_chip { + struct pwm_chip chip; +}; + +static int twl6030_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) +{ + int ret; + u8 val; + + /* Configure PWM */ + val = PWM_CTRL2_DIS_PD | PWM_CTRL2_CURR_02 | PWM_CTRL2_SRC_VAC | + PWM_CTRL2_MODE_HW; + + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to configure PWM, Error %d\n", + pwm->label, ret); + return ret; + } + + return 0; +} + +static int twl6030_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + u8 duty_cycle = (duty_ns * PWM_CTRL1_MAX) / period_ns; + int ret; + + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, duty_cycle, LED_PWM_CTRL1); + if (ret < 0) { + pr_err("%s: Failed to configure PWM, Error %d\n", + pwm->label, ret); + return ret; + } + + return 0; +} + +static int twl6030_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + int ret; + u8 val; + + ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n", + pwm->label, ret); + return ret; + } + + /* Change mode to software control */ + val &= ~PWM_CTRL2_MODE_MASK; + val |= PWM_CTRL2_MODE_SW; + + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to enable PWM, Error %d\n", + pwm->label, ret); + return ret; + } + + twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); + return 0; +} + +static void twl6030_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + int ret; + u8 val; + + ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n", + pwm->label, ret); + return; + } + + val &= ~PWM_CTRL2_MODE_MASK; + val |= PWM_CTRL2_MODE_HW; + + ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2); + if (ret < 0) { + dev_err(chip->dev, "%s: Failed to disable PWM, Error %d\n", + pwm->label, ret); + } +} + +static const struct pwm_ops twl6030_pwm_ops = { + .request = twl6030_pwm_request, + .config = twl6030_pwm_config, + .enable = twl6030_pwm_enable, + .disable = twl6030_pwm_disable, +}; + +static int twl6030_pwm_probe(struct platform_device *pdev) +{ + struct twl6030_pwm_chip *twl6030; + int ret; + + twl6030 = devm_kzalloc(&pdev->dev, sizeof(*twl6030), GFP_KERNEL); + if (!twl6030) + return -ENOMEM; + + twl6030->chip.dev = &pdev->dev; + twl6030->chip.ops = &twl6030_pwm_ops; + twl6030->chip.base = -1; + twl6030->chip.npwm = 1; + + ret = pwmchip_add(&twl6030->chip); + if (ret < 0) + return ret; + + platform_set_drvdata(pdev, twl6030); + + return 0; +} + +static int twl6030_pwm_remove(struct platform_device *pdev) +{ + struct twl6030_pwm_chip *twl6030 = platform_get_drvdata(pdev); + + return pwmchip_remove(&twl6030->chip); +} + +static struct platform_driver twl6030_pwm_driver = { + .driver = { + .name = "twl6030-pwm", + }, + .probe = twl6030_pwm_probe, + .remove = __devexit_p(twl6030_pwm_remove), +}; +module_platform_driver(twl6030_pwm_driver); + +MODULE_ALIAS("platform:twl6030-pwm"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 9582fdcb6fcf1b596a83b161a2ea886272d2a62f Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 18 Sep 2012 16:51:19 -0600 Subject: mfd: max8907: Add power off control Add DT property "maxim,system-power-controller" to indicate whether the PMIC is in charge of controlling the system power. If this is set, the driver will provide the pm_power_off() function. Signed-off-by: Stephen Warren Signed-off-by: Samuel Ortiz --- drivers/mfd/max8907.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/max8907.c b/drivers/mfd/max8907.c index 6497c98e030d..2303641dd052 100644 --- a/drivers/mfd/max8907.c +++ b/drivers/mfd/max8907.c @@ -176,11 +176,26 @@ static const struct regmap_irq_chip max8907_rtc_irq_chip = { .num_irqs = ARRAY_SIZE(max8907_rtc_irqs), }; +struct max8907 *max8907_pm_off; +static void max8907_power_off(void) +{ + regmap_update_bits(max8907_pm_off->regmap_gen, MAX8907_REG_RESET_CNFG, + MAX8907_MASK_POWER_OFF, MAX8907_MASK_POWER_OFF); +} + static __devinit int max8907_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct max8907 *max8907; int ret; + struct max8907_platform_data *pdata = dev_get_platdata(&i2c->dev); + bool pm_off = false; + + if (pdata) + pm_off = pdata->pm_off; + else if (i2c->dev.of_node) + pm_off = of_property_read_bool(i2c->dev.of_node, + "maxim,system-power-controller"); max8907 = devm_kzalloc(&i2c->dev, sizeof(struct max8907), GFP_KERNEL); if (!max8907) { @@ -251,6 +266,11 @@ static __devinit int max8907_i2c_probe(struct i2c_client *i2c, goto err_add_devices; } + if (pm_off && !pm_power_off) { + max8907_pm_off = max8907; + pm_power_off = max8907_power_off; + } + return 0; err_add_devices: -- cgit v1.2.2 From 5016498408de41bc4da5c79055c5698768916ec8 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Wed, 19 Sep 2012 09:30:51 +0800 Subject: mfd: Use IRQF_ONESHOT for 88pm860x Generated by: scripts/coccinelle/misc/irqf_oneshot.cocci Make sure threaded IRQs without a primary handler are always request with IRQF_ONESHOT. Signed-off-by: Fengguang Wu Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 0c01d7403251..ad966c413087 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -659,7 +659,7 @@ static int __devinit device_irq_init(struct pm860x_chip *chip, #endif } - ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq, flags, + ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq, flags | IRQF_ONESHOT, "88pm860x", chip); if (ret) { dev_err(chip->dev, "Failed to request IRQ: %d\n", ret); -- cgit v1.2.2 From 09e09069f2564af7c2b1beac46e6e439d4ab61cf Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Wed, 19 Sep 2012 09:32:38 +0800 Subject: mfd: Use IRQF_ONESHOT for twl6040 Generated by: scripts/coccinelle/misc/irqf_oneshot.cocci Make sure threaded IRQs without a primary handler are always request with IRQF_ONESHOT. Signed-off-by: Fengguang Wu Acked-by: Peter Ujfalusi Signed-off-by: Samuel Ortiz --- drivers/mfd/twl6040-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c index 3dca5c195a20..348e1de8e7c1 100644 --- a/drivers/mfd/twl6040-core.c +++ b/drivers/mfd/twl6040-core.c @@ -584,7 +584,7 @@ static int __devinit twl6040_probe(struct i2c_client *client, goto irq_init_err; ret = request_threaded_irq(twl6040->irq_base + TWL6040_IRQ_READY, - NULL, twl6040_naudint_handler, 0, + NULL, twl6040_naudint_handler, IRQF_ONESHOT, "twl6040_irq_ready", twl6040); if (ret) { dev_err(twl6040->dev, "READY IRQ request failed: %d\n", -- cgit v1.2.2 From 619a1e31f2b190814fcb088c8f2281461fafd396 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Wed, 19 Sep 2012 09:41:13 +0800 Subject: mfd: Use IRQF_ONESHOT for max8925 Generated by: scripts/coccinelle/misc/irqf_oneshot.cocci Make sure threaded IRQs without a primary handler are always request with IRQF_ONESHOT. Signed-off-by: Fengguang Wu Signed-off-by: Samuel Ortiz --- drivers/mfd/max8925-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index f2ff31f3a2f0..e25a24269d51 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -547,7 +547,7 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq, goto tsc_irq; } - ret = request_threaded_irq(irq, NULL, max8925_irq, flags, + ret = request_threaded_irq(irq, NULL, max8925_irq, flags | IRQF_ONESHOT, "max8925", chip); if (ret) { dev_err(chip->dev, "Failed to request core IRQ: %d\n", ret); @@ -565,7 +565,7 @@ tsc_irq: chip->tsc_irq = pdata->tsc_irq; ret = request_threaded_irq(chip->tsc_irq, NULL, max8925_tsc_irq, - flags, "max8925-tsc", chip); + flags | IRQF_ONESHOT, "max8925-tsc", chip); if (ret) { dev_err(chip->dev, "Failed to request TSC IRQ: %d\n", ret); chip->tsc_irq = 0; -- cgit v1.2.2 From 5cbe786a6e32e80149f7b29def50b2bf563f6628 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 16 Aug 2012 15:13:14 +0300 Subject: mfd: twl6040: Add twl6040-gpio child Add needed platform data structure and code to be able to load the GPO child of twl6040. Update the devicetree binding documentation at the same time. Signed-off-by: Sergio Aguirre Signed-off-by: Peter Ujfalusi Signed-off-by: Samuel Ortiz --- drivers/mfd/twl6040-core.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c index 348e1de8e7c1..3f2a1cf02fc0 100644 --- a/drivers/mfd/twl6040-core.c +++ b/drivers/mfd/twl6040-core.c @@ -631,6 +631,21 @@ static int __devinit twl6040_probe(struct i2c_client *client, 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++; + } + ret = mfd_add_devices(&client->dev, -1, twl6040->cells, children, NULL, 0, NULL); if (ret) -- cgit v1.2.2 From 70ffd691ffd45e6753eee5b5636df2ff7d2c04c8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 16 Aug 2012 15:13:15 +0300 Subject: gpio: Add basic support for TWL6040 GPOs TWL6040 provides GPO lines to be used for controlling external devices.The number of lines different between versions: twl6040 have 3 GPO while TWL6041 have 1. Signed-off-by: Sergio Aguirre Signed-off-by: Peter Ujfalusi Acked-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/gpio/Kconfig | 7 +++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-twl6040.c | 137 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 drivers/gpio/gpio-twl6040.c (limited to 'drivers') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index b16c8a72a2e2..f74633e0495a 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -402,6 +402,13 @@ config GPIO_TWL4030 Say yes here to access the GPIO signals of various multi-function power management chips from Texas Instruments. +config GPIO_TWL6040 + tristate "TWL6040 GPO" + depends on TWL6040_CORE + help + Say yes here to access the GPO signals of twl6040 + audio chip from Texas Instruments. + config GPIO_WM831X tristate "WM831x GPIOs" depends on MFD_WM831X diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 153caceeb053..f857b463af0f 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_GPIO_TPS6586X) += gpio-tps6586x.o obj-$(CONFIG_GPIO_TPS65910) += gpio-tps65910.o obj-$(CONFIG_GPIO_TPS65912) += gpio-tps65912.o obj-$(CONFIG_GPIO_TWL4030) += gpio-twl4030.o +obj-$(CONFIG_GPIO_TWL6040) += gpio-twl6040.o obj-$(CONFIG_GPIO_UCB1400) += gpio-ucb1400.o obj-$(CONFIG_GPIO_VR41XX) += gpio-vr41xx.o obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o diff --git a/drivers/gpio/gpio-twl6040.c b/drivers/gpio/gpio-twl6040.c new file mode 100644 index 000000000000..dd58e8b25043 --- /dev/null +++ b/drivers/gpio/gpio-twl6040.c @@ -0,0 +1,137 @@ +/* + * Access to GPOs on TWL6040 chip + * + * Copyright (C) 2012 Texas Instruments, Inc. + * + * Authors: + * Sergio Aguirre + * Peter Ujfalusi + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +static struct gpio_chip twl6040gpo_chip; + +static int twl6040gpo_get(struct gpio_chip *chip, unsigned offset) +{ + struct twl6040 *twl6040 = dev_get_drvdata(chip->dev->parent); + int ret = 0; + + ret = twl6040_reg_read(twl6040, TWL6040_REG_GPOCTL); + if (ret < 0) + return ret; + + return (ret >> offset) & 1; +} + +static int twl6040gpo_direction_out(struct gpio_chip *chip, unsigned offset, + int value) +{ + /* This only drives GPOs, and can't change direction */ + return 0; +} + +static void twl6040gpo_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct twl6040 *twl6040 = dev_get_drvdata(chip->dev->parent); + int ret; + u8 gpoctl; + + ret = twl6040_reg_read(twl6040, TWL6040_REG_GPOCTL); + if (ret < 0) + return; + + if (value) + gpoctl = ret | (1 << offset); + else + gpoctl = ret & ~(1 << offset); + + twl6040_reg_write(twl6040, TWL6040_REG_GPOCTL, gpoctl); +} + +static struct gpio_chip twl6040gpo_chip = { + .label = "twl6040", + .owner = THIS_MODULE, + .get = twl6040gpo_get, + .direction_output = twl6040gpo_direction_out, + .set = twl6040gpo_set, + .can_sleep = 1, +}; + +/*----------------------------------------------------------------------*/ + +static int __devinit gpo_twl6040_probe(struct platform_device *pdev) +{ + struct twl6040_gpo_data *pdata = pdev->dev.platform_data; + struct device *twl6040_core_dev = pdev->dev.parent; + struct twl6040 *twl6040 = dev_get_drvdata(twl6040_core_dev); + int ret; + + if (pdata) + twl6040gpo_chip.base = pdata->gpio_base; + else + twl6040gpo_chip.base = -1; + + if (twl6040_get_revid(twl6040) < TWL6041_REV_ES2_0) + twl6040gpo_chip.ngpio = 3; /* twl6040 have 3 GPO */ + else + twl6040gpo_chip.ngpio = 1; /* twl6041 have 1 GPO */ + + twl6040gpo_chip.dev = &pdev->dev; +#ifdef CONFIG_OF_GPIO + twl6040gpo_chip.of_node = twl6040_core_dev->of_node; +#endif + + ret = gpiochip_add(&twl6040gpo_chip); + if (ret < 0) { + dev_err(&pdev->dev, "could not register gpiochip, %d\n", ret); + twl6040gpo_chip.ngpio = 0; + } + + return ret; +} + +static int __devexit gpo_twl6040_remove(struct platform_device *pdev) +{ + return gpiochip_remove(&twl6040gpo_chip); +} + +/* Note: this hardware lives inside an I2C-based multi-function device. */ +MODULE_ALIAS("platform:twl6040-gpo"); + +static struct platform_driver gpo_twl6040_driver = { + .driver = { + .name = "twl6040-gpo", + .owner = THIS_MODULE, + }, + .probe = gpo_twl6040_probe, + .remove = gpo_twl6040_remove, +}; + +module_platform_driver(gpo_twl6040_driver); + +MODULE_AUTHOR("Texas Instruments, Inc."); +MODULE_DESCRIPTION("GPO interface for TWL6040"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 63b501e22aa9b22cdfe206a5670aaae646d93021 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 17 Sep 2012 12:19:04 +0800 Subject: mfd: max8925: Use register offset as REG in backlight Remove the register offset definition. All these register offset are transfered as IORESOURCE_REG resources. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/mfd/max8925-core.c | 31 +++++++------- drivers/video/backlight/max8925_bl.c | 79 +++++++++++++++++++----------------- 2 files changed, 55 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index e25a24269d51..934be40cd542 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -18,20 +18,16 @@ #include #include -static struct resource backlight_resources[] = { - { - .name = "max8925-backlight", - .start = MAX8925_WLED_MODE_CNTL, - .end = MAX8925_WLED_CNTL, - .flags = IORESOURCE_REG, - }, +static struct resource bk_resources[] __devinitdata = { + { 0x84, 0x84, "mode control", IORESOURCE_REG, }, + { 0x85, 0x85, "control", IORESOURCE_REG, }, }; -static struct mfd_cell backlight_devs[] = { +static struct mfd_cell bk_devs[] __devinitdata = { { .name = "max8925-backlight", - .num_resources = 1, - .resources = &backlight_resources[0], + .num_resources = ARRAY_SIZE(bk_resources), + .resources = &bk_resources[0], .id = -1, }, }; @@ -623,13 +619,14 @@ int __devinit max8925_device_init(struct max8925_chip *chip, } if (pdata && pdata->backlight) { - ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0], - ARRAY_SIZE(backlight_devs), - &backlight_resources[0], 0, NULL); - if (ret < 0) { - dev_err(chip->dev, "Failed to add backlight subdev\n"); - goto out_dev; - } + bk_devs[0].platform_data = &pdata->backlight; + bk_devs[0].pdata_size = sizeof(struct max8925_backlight_pdata); + } + ret = mfd_add_devices(chip->dev, 0, bk_devs, ARRAY_SIZE(bk_devs), + NULL, 0, NULL); + if (ret < 0) { + dev_err(chip->dev, "Failed to add backlight subdev\n"); + goto out_dev; } if (pdata && pdata->power) { diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index 996dadfa09ff..f72ba54f364e 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -27,7 +27,9 @@ struct max8925_backlight_data { struct max8925_chip *chip; - int current_brightness; + int current_brightness; + int reg_mode_cntl; + int reg_cntl; }; static int max8925_backlight_set(struct backlight_device *bl, int brightness) @@ -42,16 +44,16 @@ static int max8925_backlight_set(struct backlight_device *bl, int brightness) else value = brightness; - ret = max8925_reg_write(chip->i2c, MAX8925_WLED_CNTL, value); + ret = max8925_reg_write(chip->i2c, data->reg_cntl, value); if (ret < 0) goto out; if (!data->current_brightness && brightness) /* enable WLED output */ - ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 1, 1); + ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 1, 1); else if (!brightness) /* disable WLED output */ - ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 1, 0); + ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 1, 0); if (ret < 0) goto out; dev_dbg(chip->dev, "set brightness %d\n", value); @@ -85,7 +87,7 @@ static int max8925_backlight_get_brightness(struct backlight_device *bl) struct max8925_chip *chip = data->chip; int ret; - ret = max8925_reg_read(chip->i2c, MAX8925_WLED_CNTL); + ret = max8925_reg_read(chip->i2c, data->reg_cntl); if (ret < 0) return -EINVAL; data->current_brightness = ret; @@ -102,69 +104,70 @@ static const struct backlight_ops max8925_backlight_ops = { static int __devinit max8925_backlight_probe(struct platform_device *pdev) { struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct max8925_platform_data *max8925_pdata; - struct max8925_backlight_pdata *pdata = NULL; + struct max8925_backlight_pdata *pdata = pdev->dev.platform_data; struct max8925_backlight_data *data; struct backlight_device *bl; struct backlight_properties props; struct resource *res; - char name[MAX8925_NAME_SIZE]; unsigned char value; - int ret; - - res = platform_get_resource(pdev, IORESOURCE_REG, 0); - if (res == NULL) { - dev_err(&pdev->dev, "No I/O resource!\n"); - return -EINVAL; - } - - if (pdev->dev.parent->platform_data) { - max8925_pdata = pdev->dev.parent->platform_data; - pdata = max8925_pdata->backlight; - } - - if (!pdata) { - dev_err(&pdev->dev, "platform data isn't assigned to " - "backlight\n"); - return -EINVAL; - } + int ret = 0; data = devm_kzalloc(&pdev->dev, sizeof(struct max8925_backlight_data), GFP_KERNEL); if (data == NULL) return -ENOMEM; - strncpy(name, res->name, MAX8925_NAME_SIZE); + + res = platform_get_resource(pdev, IORESOURCE_REG, 0); + if (!res) { + dev_err(&pdev->dev, "No REG resource for mode control!\n"); + ret = -ENXIO; + goto out; + } + data->reg_mode_cntl = res->start; + res = platform_get_resource(pdev, IORESOURCE_REG, 1); + if (!res) { + dev_err(&pdev->dev, "No REG resource for control!\n"); + ret = -ENXIO; + goto out; + } + data->reg_cntl = res->start; + data->chip = chip; data->current_brightness = 0; memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_RAW; props.max_brightness = MAX_BRIGHTNESS; - bl = backlight_device_register(name, &pdev->dev, data, + bl = backlight_device_register("max8925-backlight", &pdev->dev, data, &max8925_backlight_ops, &props); if (IS_ERR(bl)) { dev_err(&pdev->dev, "failed to register backlight\n"); - return PTR_ERR(bl); + ret = PTR_ERR(bl); + goto out; } bl->props.brightness = MAX_BRIGHTNESS; platform_set_drvdata(pdev, bl); value = 0; - if (pdata->lxw_scl) - value |= (1 << 7); - if (pdata->lxw_freq) - value |= (LWX_FREQ(pdata->lxw_freq) << 4); - if (pdata->dual_string) - value |= (1 << 1); - ret = max8925_set_bits(chip->i2c, MAX8925_WLED_MODE_CNTL, 0xfe, value); + if (pdata) { + if (pdata->lxw_scl) + value |= (1 << 7); + if (pdata->lxw_freq) + value |= (LWX_FREQ(pdata->lxw_freq) << 4); + if (pdata->dual_string) + value |= (1 << 1); + } + ret = max8925_set_bits(chip->i2c, data->reg_mode_cntl, 0xfe, value); if (ret < 0) - goto out; + goto out_brt; backlight_update_status(bl); return 0; -out: +out_brt: backlight_device_unregister(bl); +out: + devm_kfree(&pdev->dev, data); return ret; } -- cgit v1.2.2 From 51acdb61185e9c7579366712a415fc929929d3bb Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 17 Sep 2012 12:19:05 +0800 Subject: mfd: max8925: Remove array in regulator platform data Remove array in parent's platform data. Use struct regulator_init_data as regulator device's platform data directly. So a lot of pdata are added into parent's platform data. And voltage out register offset is used as IORESOURCE_REG to distinguish different regualtor devices. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/mfd/max8925-core.c | 388 +++++++++++++++++++++++++++------- drivers/regulator/max8925-regulator.c | 35 ++- 2 files changed, 333 insertions(+), 90 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index 934be40cd542..9f54c04912f2 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -109,71 +110,215 @@ static struct mfd_cell onkey_devs[] = { }, }; -#define MAX8925_REG_RESOURCE(_start, _end) \ -{ \ - .start = MAX8925_##_start, \ - .end = MAX8925_##_end, \ - .flags = IORESOURCE_REG, \ -} +static struct resource sd1_resources[] __devinitdata = { + {0x06, 0x06, "sdv", IORESOURCE_REG, }, +}; -static struct resource regulator_resources[] = { - MAX8925_REG_RESOURCE(SDCTL1, SDCTL1), - MAX8925_REG_RESOURCE(SDCTL2, SDCTL2), - MAX8925_REG_RESOURCE(SDCTL3, SDCTL3), - MAX8925_REG_RESOURCE(LDOCTL1, LDOCTL1), - MAX8925_REG_RESOURCE(LDOCTL2, LDOCTL2), - MAX8925_REG_RESOURCE(LDOCTL3, LDOCTL3), - MAX8925_REG_RESOURCE(LDOCTL4, LDOCTL4), - MAX8925_REG_RESOURCE(LDOCTL5, LDOCTL5), - MAX8925_REG_RESOURCE(LDOCTL6, LDOCTL6), - MAX8925_REG_RESOURCE(LDOCTL7, LDOCTL7), - MAX8925_REG_RESOURCE(LDOCTL8, LDOCTL8), - MAX8925_REG_RESOURCE(LDOCTL9, LDOCTL9), - MAX8925_REG_RESOURCE(LDOCTL10, LDOCTL10), - MAX8925_REG_RESOURCE(LDOCTL11, LDOCTL11), - MAX8925_REG_RESOURCE(LDOCTL12, LDOCTL12), - MAX8925_REG_RESOURCE(LDOCTL13, LDOCTL13), - MAX8925_REG_RESOURCE(LDOCTL14, LDOCTL14), - MAX8925_REG_RESOURCE(LDOCTL15, LDOCTL15), - MAX8925_REG_RESOURCE(LDOCTL16, LDOCTL16), - MAX8925_REG_RESOURCE(LDOCTL17, LDOCTL17), - MAX8925_REG_RESOURCE(LDOCTL18, LDOCTL18), - MAX8925_REG_RESOURCE(LDOCTL19, LDOCTL19), - MAX8925_REG_RESOURCE(LDOCTL20, LDOCTL20), -}; - -#define MAX8925_REG_DEVS(_id) \ -{ \ - .name = "max8925-regulator", \ - .num_resources = 1, \ - .resources = ®ulator_resources[MAX8925_ID_##_id], \ - .id = MAX8925_ID_##_id, \ -} +static struct resource sd2_resources[] __devinitdata = { + {0x09, 0x09, "sdv", IORESOURCE_REG, }, +}; + +static struct resource sd3_resources[] __devinitdata = { + {0x0c, 0x0c, "sdv", IORESOURCE_REG, }, +}; + +static struct resource ldo1_resources[] __devinitdata = { + {0x1a, 0x1a, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo2_resources[] __devinitdata = { + {0x1e, 0x1e, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo3_resources[] __devinitdata = { + {0x22, 0x22, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo4_resources[] __devinitdata = { + {0x26, 0x26, "ldov", IORESOURCE_REG, }, +}; -static struct mfd_cell regulator_devs[] = { - MAX8925_REG_DEVS(SD1), - MAX8925_REG_DEVS(SD2), - MAX8925_REG_DEVS(SD3), - MAX8925_REG_DEVS(LDO1), - MAX8925_REG_DEVS(LDO2), - MAX8925_REG_DEVS(LDO3), - MAX8925_REG_DEVS(LDO4), - MAX8925_REG_DEVS(LDO5), - MAX8925_REG_DEVS(LDO6), - MAX8925_REG_DEVS(LDO7), - MAX8925_REG_DEVS(LDO8), - MAX8925_REG_DEVS(LDO9), - MAX8925_REG_DEVS(LDO10), - MAX8925_REG_DEVS(LDO11), - MAX8925_REG_DEVS(LDO12), - MAX8925_REG_DEVS(LDO13), - MAX8925_REG_DEVS(LDO14), - MAX8925_REG_DEVS(LDO15), - MAX8925_REG_DEVS(LDO16), - MAX8925_REG_DEVS(LDO17), - MAX8925_REG_DEVS(LDO18), - MAX8925_REG_DEVS(LDO19), - MAX8925_REG_DEVS(LDO20), +static struct resource ldo5_resources[] __devinitdata = { + {0x2a, 0x2a, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo6_resources[] __devinitdata = { + {0x2e, 0x2e, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo7_resources[] __devinitdata = { + {0x32, 0x32, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo8_resources[] __devinitdata = { + {0x36, 0x36, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo9_resources[] __devinitdata = { + {0x3a, 0x3a, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo10_resources[] __devinitdata = { + {0x3e, 0x3e, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo11_resources[] __devinitdata = { + {0x42, 0x42, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo12_resources[] __devinitdata = { + {0x46, 0x46, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo13_resources[] __devinitdata = { + {0x4a, 0x4a, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo14_resources[] __devinitdata = { + {0x4e, 0x4e, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo15_resources[] __devinitdata = { + {0x52, 0x52, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo16_resources[] __devinitdata = { + {0x12, 0x12, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo17_resources[] __devinitdata = { + {0x16, 0x16, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo18_resources[] __devinitdata = { + {0x74, 0x74, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo19_resources[] __devinitdata = { + {0x5e, 0x5e, "ldov", IORESOURCE_REG, }, +}; + +static struct resource ldo20_resources[] __devinitdata = { + {0x9e, 0x9e, "ldov", IORESOURCE_REG, }, +}; + +static struct mfd_cell reg_devs[] __devinitdata = { + { + .name = "max8925-regulator", + .id = 0, + .num_resources = ARRAY_SIZE(sd1_resources), + .resources = sd1_resources, + }, { + .name = "max8925-regulator", + .id = 1, + .num_resources = ARRAY_SIZE(sd2_resources), + .resources = sd2_resources, + }, { + .name = "max8925-regulator", + .id = 2, + .num_resources = ARRAY_SIZE(sd3_resources), + .resources = sd3_resources, + }, { + .name = "max8925-regulator", + .id = 3, + .num_resources = ARRAY_SIZE(ldo1_resources), + .resources = ldo1_resources, + }, { + .name = "max8925-regulator", + .id = 4, + .num_resources = ARRAY_SIZE(ldo2_resources), + .resources = ldo2_resources, + }, { + .name = "max8925-regulator", + .id = 5, + .num_resources = ARRAY_SIZE(ldo3_resources), + .resources = ldo3_resources, + }, { + .name = "max8925-regulator", + .id = 6, + .num_resources = ARRAY_SIZE(ldo4_resources), + .resources = ldo4_resources, + }, { + .name = "max8925-regulator", + .id = 7, + .num_resources = ARRAY_SIZE(ldo5_resources), + .resources = ldo5_resources, + }, { + .name = "max8925-regulator", + .id = 8, + .num_resources = ARRAY_SIZE(ldo6_resources), + .resources = ldo6_resources, + }, { + .name = "max8925-regulator", + .id = 9, + .num_resources = ARRAY_SIZE(ldo7_resources), + .resources = ldo7_resources, + }, { + .name = "max8925-regulator", + .id = 10, + .num_resources = ARRAY_SIZE(ldo8_resources), + .resources = ldo8_resources, + }, { + .name = "max8925-regulator", + .id = 11, + .num_resources = ARRAY_SIZE(ldo9_resources), + .resources = ldo9_resources, + }, { + .name = "max8925-regulator", + .id = 12, + .num_resources = ARRAY_SIZE(ldo10_resources), + .resources = ldo10_resources, + }, { + .name = "max8925-regulator", + .id = 13, + .num_resources = ARRAY_SIZE(ldo11_resources), + .resources = ldo11_resources, + }, { + .name = "max8925-regulator", + .id = 14, + .num_resources = ARRAY_SIZE(ldo12_resources), + .resources = ldo12_resources, + }, { + .name = "max8925-regulator", + .id = 15, + .num_resources = ARRAY_SIZE(ldo13_resources), + .resources = ldo13_resources, + }, { + .name = "max8925-regulator", + .id = 16, + .num_resources = ARRAY_SIZE(ldo14_resources), + .resources = ldo14_resources, + }, { + .name = "max8925-regulator", + .id = 17, + .num_resources = ARRAY_SIZE(ldo15_resources), + .resources = ldo15_resources, + }, { + .name = "max8925-regulator", + .id = 18, + .num_resources = ARRAY_SIZE(ldo16_resources), + .resources = ldo16_resources, + }, { + .name = "max8925-regulator", + .id = 19, + .num_resources = ARRAY_SIZE(ldo17_resources), + .resources = ldo17_resources, + }, { + .name = "max8925-regulator", + .id = 20, + .num_resources = ARRAY_SIZE(ldo18_resources), + .resources = ldo18_resources, + }, { + .name = "max8925-regulator", + .id = 21, + .num_resources = ARRAY_SIZE(ldo19_resources), + .resources = ldo19_resources, + }, { + .name = "max8925-regulator", + .id = 22, + .num_resources = ARRAY_SIZE(ldo20_resources), + .resources = ldo20_resources, + }, }; enum { @@ -569,6 +714,113 @@ tsc_irq: return 0; } +static void __devinit init_regulator(struct max8925_chip *chip, + struct max8925_platform_data *pdata) +{ + int ret; + + if (!pdata) + return; + if (pdata->sd1) { + reg_devs[0].platform_data = pdata->sd1; + reg_devs[0].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->sd2) { + reg_devs[1].platform_data = pdata->sd2; + reg_devs[1].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->sd3) { + reg_devs[2].platform_data = pdata->sd3; + reg_devs[2].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo1) { + reg_devs[3].platform_data = pdata->ldo1; + reg_devs[3].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo2) { + reg_devs[4].platform_data = pdata->ldo2; + reg_devs[4].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo3) { + reg_devs[5].platform_data = pdata->ldo3; + reg_devs[5].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo4) { + reg_devs[6].platform_data = pdata->ldo4; + reg_devs[6].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo5) { + reg_devs[7].platform_data = pdata->ldo5; + reg_devs[7].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo6) { + reg_devs[8].platform_data = pdata->ldo6; + reg_devs[8].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo7) { + reg_devs[9].platform_data = pdata->ldo7; + reg_devs[9].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo8) { + reg_devs[10].platform_data = pdata->ldo8; + reg_devs[10].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo9) { + reg_devs[11].platform_data = pdata->ldo9; + reg_devs[11].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo10) { + reg_devs[12].platform_data = pdata->ldo10; + reg_devs[12].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo11) { + reg_devs[13].platform_data = pdata->ldo11; + reg_devs[13].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo12) { + reg_devs[14].platform_data = pdata->ldo12; + reg_devs[14].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo13) { + reg_devs[15].platform_data = pdata->ldo13; + reg_devs[15].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo14) { + reg_devs[16].platform_data = pdata->ldo14; + reg_devs[16].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo15) { + reg_devs[17].platform_data = pdata->ldo15; + reg_devs[17].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo16) { + reg_devs[18].platform_data = pdata->ldo16; + reg_devs[18].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo17) { + reg_devs[19].platform_data = pdata->ldo17; + reg_devs[19].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo18) { + reg_devs[20].platform_data = pdata->ldo18; + reg_devs[20].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo19) { + reg_devs[21].platform_data = pdata->ldo19; + reg_devs[21].pdata_size = sizeof(struct regulator_init_data); + } + if (pdata->ldo20) { + reg_devs[22].platform_data = pdata->ldo20; + reg_devs[22].pdata_size = sizeof(struct regulator_init_data); + } + ret = mfd_add_devices(chip->dev, 0, reg_devs, ARRAY_SIZE(reg_devs), + NULL, 0, NULL); + if (ret < 0) { + dev_err(chip->dev, "Failed to add regulator subdev\n"); + return; + } +} + int __devinit max8925_device_init(struct max8925_chip *chip, struct max8925_platform_data *pdata) { @@ -608,15 +860,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip, goto out_dev; } - if (pdata) { - ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0], - ARRAY_SIZE(regulator_devs), - ®ulator_resources[0], 0, NULL); - if (ret < 0) { - dev_err(chip->dev, "Failed to add regulator subdev\n"); - goto out_dev; - } - } + init_regulator(chip, pdata); if (pdata && pdata->backlight) { bk_devs[0].platform_data = &pdata->backlight; diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index 43dc97ec3932..9bb0be37495f 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -214,37 +214,36 @@ static struct max8925_regulator_info max8925_regulator_info[] = { MAX8925_LDO(20, 750, 3900, 50), }; -static struct max8925_regulator_info * __devinit find_regulator_info(int id) -{ - struct max8925_regulator_info *ri; - int i; - - for (i = 0; i < ARRAY_SIZE(max8925_regulator_info); i++) { - ri = &max8925_regulator_info[i]; - if (ri->desc.id == id) - return ri; - } - return NULL; -} - static int __devinit max8925_regulator_probe(struct platform_device *pdev) { struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct max8925_platform_data *pdata = chip->dev->platform_data; + struct regulator_init_data *pdata = pdev->dev.platform_data; struct regulator_config config = { }; struct max8925_regulator_info *ri; + struct resource *res; struct regulator_dev *rdev; + int i; - ri = find_regulator_info(pdev->id); - if (ri == NULL) { - dev_err(&pdev->dev, "invalid regulator ID specified\n"); + res = platform_get_resource(pdev, IORESOURCE_REG, 0); + if (!res) { + dev_err(&pdev->dev, "No REG resource!\n"); + return -EINVAL; + } + for (i = 0; i < ARRAY_SIZE(max8925_regulator_info); i++) { + ri = &max8925_regulator_info[i]; + if (ri->vol_reg == res->start) + break; + } + if (i == ARRAY_SIZE(max8925_regulator_info)) { + dev_err(&pdev->dev, "Failed to find regulator %llu\n", + (unsigned long long)res->start); return -EINVAL; } ri->i2c = chip->i2c; ri->chip = chip; config.dev = &pdev->dev; - config.init_data = pdata->regulator[pdev->id]; + config.init_data = pdata; config.driver_data = ri; rdev = regulator_register(&ri->desc, &config); -- cgit v1.2.2 From e7a7810ae08bfca5cb2cad8a8d55c16f299cc3fe Mon Sep 17 00:00:00 2001 From: "Jett.Zhou" Date: Mon, 17 Sep 2012 12:19:06 +0800 Subject: regulator: 88pm860x: Add pre-regulator support for 88pm860x regulator Pre-regulator of 88pm8606 is mainly for support charging based on vbus, it needs to be enabled for charging battery, and will be disabled in some exception condition like over-temp. Add the pre-regulator support for 88pm860x regulator driver. Signed-off-by: Jett.Zhou Acked-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/regulator/88pm8607.c | 66 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'drivers') diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index 843c89a15472..d34bd8c5ad08 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -23,6 +23,7 @@ struct pm8607_regulator_info { struct pm860x_chip *chip; struct regulator_dev *regulator; struct i2c_client *i2c; + struct i2c_client *i2c_8606; unsigned int *vol_table; unsigned int *vol_suspend; @@ -242,6 +243,35 @@ static int pm8607_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) return ret; } +static int pm8606_preg_enable(struct regulator_dev *rdev) +{ + struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); + + return pm860x_set_bits(info->i2c, rdev->desc->enable_reg, + 1 << rdev->desc->enable_mask, 0); +} + +static int pm8606_preg_disable(struct regulator_dev *rdev) +{ + struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); + + return pm860x_set_bits(info->i2c, rdev->desc->enable_reg, + 1 << rdev->desc->enable_mask, + 1 << rdev->desc->enable_mask); +} + +static int pm8606_preg_is_enabled(struct regulator_dev *rdev) +{ + struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); + int ret; + + ret = pm860x_reg_read(info->i2c, rdev->desc->enable_reg); + if (ret < 0) + return ret; + + return !((unsigned char)ret & (1 << rdev->desc->enable_mask)); +} + static struct regulator_ops pm8607_regulator_ops = { .list_voltage = pm8607_list_voltage, .set_voltage_sel = pm8607_set_voltage_sel, @@ -251,6 +281,25 @@ static struct regulator_ops pm8607_regulator_ops = { .is_enabled = regulator_is_enabled_regmap, }; +static struct regulator_ops pm8606_preg_ops = { + .enable = pm8606_preg_enable, + .disable = pm8606_preg_disable, + .is_enabled = pm8606_preg_is_enabled, +}; + +#define PM8606_PREG(ereg, ebit) \ +{ \ + .desc = { \ + .name = "PREG", \ + .ops = &pm8606_preg_ops, \ + .type = REGULATOR_CURRENT, \ + .id = PM8606_ID_PREG, \ + .owner = THIS_MODULE, \ + .enable_reg = PM8606_##ereg, \ + .enable_mask = (ebit), \ + }, \ +} + #define PM8607_DVC(vreg, ureg, ubit, ereg, ebit) \ { \ .desc = { \ @@ -309,6 +358,8 @@ static struct pm8607_regulator_info pm8607_regulator_info[] = { PM8607_LDO(12, LDO12, 0, SUPPLIES_EN12, 5), PM8607_LDO(13, VIBRATOR_SET, 1, VIBRATOR_SET, 0), PM8607_LDO(14, LDO14, 0, SUPPLIES_EN12, 6), + + PM8606_PREG(PREREGULATORB, 5), }; static int __devinit pm8607_regulator_probe(struct platform_device *pdev) @@ -336,6 +387,8 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) return -EINVAL; } info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; + info->i2c_8606 = (chip->id == CHIP_PM8607) ? chip->companion : + chip->client; info->chip = chip; /* check DVC ramp slope double */ @@ -371,6 +424,18 @@ static int __devexit pm8607_regulator_remove(struct platform_device *pdev) return 0; } +static struct platform_device_id pm8607_regulator_driver_ids[] = { + { + .name = "88pm860x-regulator", + .driver_data = 0, + }, { + .name = "88pm860x-preg", + .driver_data = 0, + }, + { }, +}; +MODULE_DEVICE_TABLE(platform, pm8607_regulator_driver_ids); + static struct platform_driver pm8607_regulator_driver = { .driver = { .name = "88pm860x-regulator", @@ -378,6 +443,7 @@ static struct platform_driver pm8607_regulator_driver = { }, .probe = pm8607_regulator_probe, .remove = __devexit_p(pm8607_regulator_remove), + .id_table = pm8607_regulator_driver_ids, }; static int __init pm8607_regulator_init(void) -- cgit v1.2.2 From ff13e9e256d49a478b34da3dc380af41e0b9175f Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 17 Sep 2012 12:19:07 +0800 Subject: mfd: 88pm860x: Avoid to check resource for preg regulator Since PREG regulator is the only one regulator in 88PM8606, and other regulators are in 88PM8607. Checking resource as identifying regulator is not a good way. We can use NULL resource to indentify PREG regulator. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-core.c | 8 +------- drivers/regulator/88pm8607.c | 32 +++++++++++++++++++------------- 2 files changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index ad966c413087..8bf7622300f4 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -150,10 +150,6 @@ static struct resource charger_resources[] __devinitdata = { {PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage", IORESOURCE_IRQ,}, }; -static struct resource preg_resources[] __devinitdata = { - {PM8606_ID_PREG, PM8606_ID_PREG, "preg", IORESOURCE_REG,}, -}; - static struct resource rtc_resources[] __devinitdata = { {PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,}, }; @@ -960,10 +956,8 @@ static void __devinit device_power_init(struct pm860x_chip *chip, power_devs[2].platform_data = &preg_init_data; power_devs[2].pdata_size = sizeof(struct regulator_init_data); - power_devs[2].num_resources = ARRAY_SIZE(preg_resources); - power_devs[2].resources = &preg_resources[0], ret = mfd_add_devices(chip->dev, 0, &power_devs[2], 1, - &preg_resources[0], chip->irq_base, NULL); + NULL, chip->irq_base, NULL); if (ret < 0) dev_err(chip->dev, "Failed to add preg subdev\n"); } diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index d34bd8c5ad08..f96fbe38ff6f 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -358,7 +358,9 @@ static struct pm8607_regulator_info pm8607_regulator_info[] = { PM8607_LDO(12, LDO12, 0, SUPPLIES_EN12, 5), PM8607_LDO(13, VIBRATOR_SET, 1, VIBRATOR_SET, 0), PM8607_LDO(14, LDO14, 0, SUPPLIES_EN12, 6), +}; +static struct pm8607_regulator_info pm8606_regulator_info[] = { PM8606_PREG(PREREGULATORB, 5), }; @@ -372,19 +374,23 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) int i; res = platform_get_resource(pdev, IORESOURCE_REG, 0); - if (res == NULL) { - dev_err(&pdev->dev, "No REG resource!\n"); - return -EINVAL; - } - for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) { - info = &pm8607_regulator_info[i]; - if (info->desc.vsel_reg == res->start) - break; - } - if (i == ARRAY_SIZE(pm8607_regulator_info)) { - dev_err(&pdev->dev, "Failed to find regulator %llu\n", - (unsigned long long)res->start); - return -EINVAL; + if (res) { + /* There're resources in 88PM8607 regulator driver */ + for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) { + info = &pm8607_regulator_info[i]; + if (info->desc.vsel_reg == res->start) + break; + } + if (i == ARRAY_SIZE(pm8607_regulator_info)) { + dev_err(&pdev->dev, "Failed to find regulator %llu\n", + (unsigned long long)res->start); + return -EINVAL; + } + } else { + /* There's no resource in 88PM8606 PREG regulator driver */ + info = &pm8606_regulator_info[0]; + /* i is used to check regulator ID */ + i = -1; } info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; info->i2c_8606 = (chip->id == CHIP_PM8607) ? chip->companion : -- cgit v1.2.2 From f2f218cdc3ef4fd46f4fcc8880d69207a1740181 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 17 Sep 2012 12:19:08 +0800 Subject: mfd: 88pm860x: Move initilization code Move probe() and other functions from 88pm860x-i2c.c to 88pm860x-core.c. Since it could benefit to handle DT information. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-core.c | 162 +++++++++++++++++++++++++++++++++++++++++++- drivers/mfd/88pm860x-i2c.c | 160 ------------------------------------------- 2 files changed, 159 insertions(+), 163 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 8bf7622300f4..72bf290bd020 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -11,10 +11,13 @@ #include #include +#include #include #include #include #include +#include +#include #include #include #include @@ -1064,8 +1067,8 @@ static void __devinit device_8606_init(struct pm860x_chip *chip, device_led_init(chip, pdata); } -int __devinit pm860x_device_init(struct pm860x_chip *chip, - struct pm860x_platform_data *pdata) +static int __devinit pm860x_device_init(struct pm860x_chip *chip, + struct pm860x_platform_data *pdata) { chip->core_irq = 0; @@ -1092,12 +1095,165 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip, return 0; } -void __devexit pm860x_device_exit(struct pm860x_chip *chip) +static void __devexit pm860x_device_exit(struct pm860x_chip *chip) { device_irq_exit(chip); mfd_remove_devices(chip->dev); } +static const struct i2c_device_id pm860x_id_table[] = { + { "88PM860x", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, pm860x_id_table); + +static int verify_addr(struct i2c_client *i2c) +{ + unsigned short addr_8607[] = {0x30, 0x34}; + unsigned short addr_8606[] = {0x10, 0x11}; + int size, i; + + if (i2c == NULL) + return 0; + size = ARRAY_SIZE(addr_8606); + for (i = 0; i < size; i++) { + if (i2c->addr == *(addr_8606 + i)) + return CHIP_PM8606; + } + size = ARRAY_SIZE(addr_8607); + for (i = 0; i < size; i++) { + if (i2c->addr == *(addr_8607 + i)) + return CHIP_PM8607; + } + return 0; +} + +static struct regmap_config pm860x_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int __devinit pm860x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pm860x_platform_data *pdata = client->dev.platform_data; + struct pm860x_chip *chip; + int ret; + + if (!pdata) { + pr_info("No platform data in %s!\n", __func__); + return -EINVAL; + } + + chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + + chip->id = verify_addr(client); + chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config); + if (IS_ERR(chip->regmap)) { + ret = PTR_ERR(chip->regmap); + dev_err(&client->dev, "Failed to allocate register map: %d\n", + ret); + kfree(chip); + return ret; + } + chip->client = client; + i2c_set_clientdata(client, chip); + chip->dev = &client->dev; + dev_set_drvdata(chip->dev, chip); + + /* + * Both client and companion client shares same platform driver. + * Driver distinguishes them by pdata->companion_addr. + * pdata->companion_addr is only assigned if companion chip exists. + * At the same time, the companion_addr shouldn't equal to client + * address. + */ + if (pdata->companion_addr && (pdata->companion_addr != client->addr)) { + chip->companion_addr = pdata->companion_addr; + chip->companion = i2c_new_dummy(chip->client->adapter, + chip->companion_addr); + chip->regmap_companion = regmap_init_i2c(chip->companion, + &pm860x_regmap_config); + if (IS_ERR(chip->regmap_companion)) { + ret = PTR_ERR(chip->regmap_companion); + dev_err(&chip->companion->dev, + "Failed to allocate register map: %d\n", ret); + return ret; + } + i2c_set_clientdata(chip->companion, chip); + } + + pm860x_device_init(chip, pdata); + return 0; +} + +static int __devexit pm860x_remove(struct i2c_client *client) +{ + struct pm860x_chip *chip = i2c_get_clientdata(client); + + pm860x_device_exit(chip); + if (chip->companion) { + regmap_exit(chip->regmap_companion); + i2c_unregister_device(chip->companion); + } + regmap_exit(chip->regmap); + kfree(chip); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int pm860x_suspend(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct pm860x_chip *chip = i2c_get_clientdata(client); + + if (device_may_wakeup(dev) && chip->wakeup_flag) + enable_irq_wake(chip->core_irq); + return 0; +} + +static int pm860x_resume(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct pm860x_chip *chip = i2c_get_clientdata(client); + + if (device_may_wakeup(dev) && chip->wakeup_flag) + disable_irq_wake(chip->core_irq); + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume); + +static struct i2c_driver pm860x_driver = { + .driver = { + .name = "88PM860x", + .owner = THIS_MODULE, + .pm = &pm860x_pm_ops, + }, + .probe = pm860x_probe, + .remove = __devexit_p(pm860x_remove), + .id_table = pm860x_id_table, +}; + +static int __init pm860x_i2c_init(void) +{ + int ret; + ret = i2c_add_driver(&pm860x_driver); + if (ret != 0) + pr_err("Failed to register 88PM860x I2C driver: %d\n", ret); + return ret; +} +subsys_initcall(pm860x_i2c_init); + +static void __exit pm860x_i2c_exit(void) +{ + i2c_del_driver(&pm860x_driver); +} +module_exit(pm860x_i2c_exit); + MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x"); MODULE_AUTHOR("Haojian Zhuang "); MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c index b2cfdc458561..cd53a823c0c5 100644 --- a/drivers/mfd/88pm860x-i2c.c +++ b/drivers/mfd/88pm860x-i2c.c @@ -10,12 +10,9 @@ */ #include #include -#include #include -#include #include #include -#include int pm860x_reg_read(struct i2c_client *i2c, int reg) { @@ -231,160 +228,3 @@ out: return ret; } EXPORT_SYMBOL(pm860x_page_set_bits); - -static const struct i2c_device_id pm860x_id_table[] = { - { "88PM860x", 0 }, - {} -}; -MODULE_DEVICE_TABLE(i2c, pm860x_id_table); - -static int verify_addr(struct i2c_client *i2c) -{ - unsigned short addr_8607[] = {0x30, 0x34}; - unsigned short addr_8606[] = {0x10, 0x11}; - int size, i; - - if (i2c == NULL) - return 0; - size = ARRAY_SIZE(addr_8606); - for (i = 0; i < size; i++) { - if (i2c->addr == *(addr_8606 + i)) - return CHIP_PM8606; - } - size = ARRAY_SIZE(addr_8607); - for (i = 0; i < size; i++) { - if (i2c->addr == *(addr_8607 + i)) - return CHIP_PM8607; - } - return 0; -} - -static struct regmap_config pm860x_regmap_config = { - .reg_bits = 8, - .val_bits = 8, -}; - -static int __devinit pm860x_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct pm860x_platform_data *pdata = client->dev.platform_data; - struct pm860x_chip *chip; - int ret; - - if (!pdata) { - pr_info("No platform data in %s!\n", __func__); - return -EINVAL; - } - - chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; - - chip->id = verify_addr(client); - chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config); - if (IS_ERR(chip->regmap)) { - ret = PTR_ERR(chip->regmap); - dev_err(&client->dev, "Failed to allocate register map: %d\n", - ret); - kfree(chip); - return ret; - } - chip->client = client; - i2c_set_clientdata(client, chip); - chip->dev = &client->dev; - dev_set_drvdata(chip->dev, chip); - - /* - * Both client and companion client shares same platform driver. - * Driver distinguishes them by pdata->companion_addr. - * pdata->companion_addr is only assigned if companion chip exists. - * At the same time, the companion_addr shouldn't equal to client - * address. - */ - if (pdata->companion_addr && (pdata->companion_addr != client->addr)) { - chip->companion_addr = pdata->companion_addr; - chip->companion = i2c_new_dummy(chip->client->adapter, - chip->companion_addr); - chip->regmap_companion = regmap_init_i2c(chip->companion, - &pm860x_regmap_config); - if (IS_ERR(chip->regmap_companion)) { - ret = PTR_ERR(chip->regmap_companion); - dev_err(&chip->companion->dev, - "Failed to allocate register map: %d\n", ret); - return ret; - } - i2c_set_clientdata(chip->companion, chip); - } - - pm860x_device_init(chip, pdata); - return 0; -} - -static int __devexit pm860x_remove(struct i2c_client *client) -{ - struct pm860x_chip *chip = i2c_get_clientdata(client); - - pm860x_device_exit(chip); - if (chip->companion) { - regmap_exit(chip->regmap_companion); - i2c_unregister_device(chip->companion); - } - regmap_exit(chip->regmap); - kfree(chip); - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int pm860x_suspend(struct device *dev) -{ - struct i2c_client *client = container_of(dev, struct i2c_client, dev); - struct pm860x_chip *chip = i2c_get_clientdata(client); - - if (device_may_wakeup(dev) && chip->wakeup_flag) - enable_irq_wake(chip->core_irq); - return 0; -} - -static int pm860x_resume(struct device *dev) -{ - struct i2c_client *client = container_of(dev, struct i2c_client, dev); - struct pm860x_chip *chip = i2c_get_clientdata(client); - - if (device_may_wakeup(dev) && chip->wakeup_flag) - disable_irq_wake(chip->core_irq); - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume); - -static struct i2c_driver pm860x_driver = { - .driver = { - .name = "88PM860x", - .owner = THIS_MODULE, - .pm = &pm860x_pm_ops, - }, - .probe = pm860x_probe, - .remove = __devexit_p(pm860x_remove), - .id_table = pm860x_id_table, -}; - -static int __init pm860x_i2c_init(void) -{ - int ret; - ret = i2c_add_driver(&pm860x_driver); - if (ret != 0) - pr_err("Failed to register 88PM860x I2C driver: %d\n", ret); - return ret; -} -subsys_initcall(pm860x_i2c_init); - -static void __exit pm860x_i2c_exit(void) -{ - i2c_del_driver(&pm860x_driver); -} -module_exit(pm860x_i2c_exit); - -MODULE_DESCRIPTION("I2C Driver for Marvell 88PM860x"); -MODULE_AUTHOR("Haojian Zhuang "); -MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 99de1cc5a77122e59640668b202280ecdb0f3c2e Mon Sep 17 00:00:00 2001 From: Venu Byravarasu Date: Mon, 17 Sep 2012 11:00:47 +0530 Subject: mfd: tps65090: Remove redundant check Remove redundant check in is_volatile_reg(). Signed-off-by: Venu Byravarasu Signed-off-by: Samuel Ortiz --- drivers/mfd/tps65090.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c index 50fd87c87a1c..074ae32b0d2a 100644 --- a/drivers/mfd/tps65090.c +++ b/drivers/mfd/tps65090.c @@ -236,7 +236,7 @@ static int __devinit tps65090_irq_init(struct tps65090 *tps65090, int irq, static bool is_volatile_reg(struct device *dev, unsigned int reg) { - if ((reg == TPS65090_INT_STS) || (reg == TPS65090_INT_STS)) + if (reg == TPS65090_INT_STS) return true; else return false; -- cgit v1.2.2 From 16fa3dc75c22f9769d418f19c45e11b118aab2eb Mon Sep 17 00:00:00 2001 From: Keshava Munegowda Date: Mon, 16 Jul 2012 19:01:08 +0530 Subject: mfd: omap-usb-tll: HOST TLL platform driver The platform driver for the TLL component of the OMAP USB host controller is implemented. Depending on the TLL hardware revision , the TLL channels are configured. The USB HS core driver uses this driver through exported APIs from the TLL platform driver. usb_tll_enable and usb_tll_disble are the exported APIs of the USB TLL platform driver. Signed-off-by: Keshava Munegowda Reviewed-by: Partha Basak Acked-by: Felipe Balbi Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 2 +- drivers/mfd/Makefile | 2 +- drivers/mfd/omap-usb-tll.c | 471 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 473 insertions(+), 2 deletions(-) create mode 100644 drivers/mfd/omap-usb-tll.c (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 2143fd283a74..b9282cafa978 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -897,7 +897,7 @@ config MFD_WL1273_CORE audio codec. config MFD_OMAP_USB_HOST - bool "Support OMAP USBHS core driver" + bool "Support OMAP USBHS core and TLL driver" depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3 default y help diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 95dfa14ad174..d16bc0220e1f 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -120,7 +120,7 @@ obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o obj-$(CONFIG_MFD_VX855) += vx855.o obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o -obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o +obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c new file mode 100644 index 000000000000..4b7757b84301 --- /dev/null +++ b/drivers/mfd/omap-usb-tll.c @@ -0,0 +1,471 @@ +/** + * omap-usb-tll.c - The USB TLL driver for OMAP EHCI & OHCI + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * Author: Keshava Munegowda + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define USBTLL_DRIVER_NAME "usbhs_tll" + +/* TLL Register Set */ +#define OMAP_USBTLL_REVISION (0x00) +#define OMAP_USBTLL_SYSCONFIG (0x10) +#define OMAP_USBTLL_SYSCONFIG_CACTIVITY (1 << 8) +#define OMAP_USBTLL_SYSCONFIG_SIDLEMODE (1 << 3) +#define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP (1 << 2) +#define OMAP_USBTLL_SYSCONFIG_SOFTRESET (1 << 1) +#define OMAP_USBTLL_SYSCONFIG_AUTOIDLE (1 << 0) + +#define OMAP_USBTLL_SYSSTATUS (0x14) +#define OMAP_USBTLL_SYSSTATUS_RESETDONE (1 << 0) + +#define OMAP_USBTLL_IRQSTATUS (0x18) +#define OMAP_USBTLL_IRQENABLE (0x1C) + +#define OMAP_TLL_SHARED_CONF (0x30) +#define OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN (1 << 6) +#define OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN (1 << 5) +#define OMAP_TLL_SHARED_CONF_USB_DIVRATION (1 << 2) +#define OMAP_TLL_SHARED_CONF_FCLK_REQ (1 << 1) +#define OMAP_TLL_SHARED_CONF_FCLK_IS_ON (1 << 0) + +#define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num) +#define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT 24 +#define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11) +#define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10) +#define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9) +#define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8) +#define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS (1 << 1) +#define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0) + +#define OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0 0x0 +#define OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM 0x1 +#define OMAP_TLL_FSLSMODE_3PIN_PHY 0x2 +#define OMAP_TLL_FSLSMODE_4PIN_PHY 0x3 +#define OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0 0x4 +#define OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM 0x5 +#define OMAP_TLL_FSLSMODE_3PIN_TLL 0x6 +#define OMAP_TLL_FSLSMODE_4PIN_TLL 0x7 +#define OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0 0xA +#define OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM 0xB + +#define OMAP_TLL_ULPI_FUNCTION_CTRL(num) (0x804 + 0x100 * num) +#define OMAP_TLL_ULPI_INTERFACE_CTRL(num) (0x807 + 0x100 * num) +#define OMAP_TLL_ULPI_OTG_CTRL(num) (0x80A + 0x100 * num) +#define OMAP_TLL_ULPI_INT_EN_RISE(num) (0x80D + 0x100 * num) +#define OMAP_TLL_ULPI_INT_EN_FALL(num) (0x810 + 0x100 * num) +#define OMAP_TLL_ULPI_INT_STATUS(num) (0x813 + 0x100 * num) +#define OMAP_TLL_ULPI_INT_LATCH(num) (0x814 + 0x100 * num) +#define OMAP_TLL_ULPI_DEBUG(num) (0x815 + 0x100 * num) +#define OMAP_TLL_ULPI_SCRATCH_REGISTER(num) (0x816 + 0x100 * num) + +#define OMAP_REV2_TLL_CHANNEL_COUNT 2 +#define OMAP_TLL_CHANNEL_COUNT 3 +#define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 0) +#define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 1) +#define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 2) + +/* Values of USBTLL_REVISION - Note: these are not given in the TRM */ +#define OMAP_USBTLL_REV1 0x00000015 /* OMAP3 */ +#define OMAP_USBTLL_REV2 0x00000018 /* OMAP 3630 */ +#define OMAP_USBTLL_REV3 0x00000004 /* OMAP4 */ + +#define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL) + +struct usbtll_omap { + struct clk *usbtll_p1_fck; + struct clk *usbtll_p2_fck; + struct usbtll_omap_platform_data platdata; + /* secure the register updates */ + spinlock_t lock; +}; + +/*-------------------------------------------------------------------------*/ + +const char usbtll_driver_name[] = USBTLL_DRIVER_NAME; +struct platform_device *tll_pdev; + +/*-------------------------------------------------------------------------*/ + +static inline void usbtll_write(void __iomem *base, u32 reg, u32 val) +{ + __raw_writel(val, base + reg); +} + +static inline u32 usbtll_read(void __iomem *base, u32 reg) +{ + return __raw_readl(base + reg); +} + +static inline void usbtll_writeb(void __iomem *base, u8 reg, u8 val) +{ + __raw_writeb(val, base + reg); +} + +static inline u8 usbtll_readb(void __iomem *base, u8 reg) +{ + return __raw_readb(base + reg); +} + +/*-------------------------------------------------------------------------*/ + +static bool is_ohci_port(enum usbhs_omap_port_mode pmode) +{ + switch (pmode) { + case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: + case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: + case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: + case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: + case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: + case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: + case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: + case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: + case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: + case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: + return true; + + default: + return false; + } +} + +/* + * convert the port-mode enum to a value we can use in the FSLSMODE + * field of USBTLL_CHANNEL_CONF + */ +static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode) +{ + switch (mode) { + case OMAP_USBHS_PORT_MODE_UNUSED: + case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: + return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; + + case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: + return OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM; + + case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: + return OMAP_TLL_FSLSMODE_3PIN_PHY; + + case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: + return OMAP_TLL_FSLSMODE_4PIN_PHY; + + case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: + return OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0; + + case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: + return OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM; + + case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: + return OMAP_TLL_FSLSMODE_3PIN_TLL; + + case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: + return OMAP_TLL_FSLSMODE_4PIN_TLL; + + case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: + return OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0; + + case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: + return OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM; + default: + pr_warn("Invalid port mode, using default\n"); + return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; + } +} + +/** + * usbtll_omap_probe - initialize TI-based HCDs + * + * Allocates basic resources for this USB host controller. + */ +static int __devinit usbtll_omap_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct usbtll_omap_platform_data *pdata = dev->platform_data; + void __iomem *base; + struct resource *res; + struct usbtll_omap *tll; + unsigned reg; + unsigned long flags; + int ret = 0; + int i, ver, count; + + dev_dbg(dev, "starting TI HSUSB TLL Controller\n"); + + tll = kzalloc(sizeof(struct usbtll_omap), GFP_KERNEL); + if (!tll) { + dev_err(dev, "Memory allocation failed\n"); + ret = -ENOMEM; + goto end; + } + + spin_lock_init(&tll->lock); + + for (i = 0; i < OMAP3_HS_USB_PORTS; i++) + tll->platdata.port_mode[i] = pdata->port_mode[i]; + + tll->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk"); + if (IS_ERR(tll->usbtll_p1_fck)) { + ret = PTR_ERR(tll->usbtll_p1_fck); + dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret); + goto err_tll; + } + + tll->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk"); + if (IS_ERR(tll->usbtll_p2_fck)) { + ret = PTR_ERR(tll->usbtll_p2_fck); + dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret); + goto err_usbtll_p1_fck; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "usb tll get resource failed\n"); + ret = -ENODEV; + goto err_usbtll_p2_fck; + } + + base = ioremap(res->start, resource_size(res)); + if (!base) { + dev_err(dev, "TLL ioremap failed\n"); + ret = -ENOMEM; + goto err_usbtll_p2_fck; + } + + platform_set_drvdata(pdev, tll); + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + + spin_lock_irqsave(&tll->lock, flags); + + ver = usbtll_read(base, OMAP_USBTLL_REVISION); + switch (ver) { + case OMAP_USBTLL_REV1: + case OMAP_USBTLL_REV2: + count = OMAP_TLL_CHANNEL_COUNT; + break; + case OMAP_USBTLL_REV3: + count = OMAP_REV2_TLL_CHANNEL_COUNT; + break; + default: + dev_err(dev, "TLL version failed\n"); + ret = -ENODEV; + goto err_ioremap; + } + + if (is_ehci_tll_mode(pdata->port_mode[0]) || + is_ehci_tll_mode(pdata->port_mode[1]) || + is_ehci_tll_mode(pdata->port_mode[2]) || + is_ohci_port(pdata->port_mode[0]) || + is_ohci_port(pdata->port_mode[1]) || + is_ohci_port(pdata->port_mode[2])) { + + /* Program Common TLL register */ + reg = usbtll_read(base, OMAP_TLL_SHARED_CONF); + reg |= (OMAP_TLL_SHARED_CONF_FCLK_IS_ON + | OMAP_TLL_SHARED_CONF_USB_DIVRATION); + reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN; + reg &= ~OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN; + + usbtll_write(base, OMAP_TLL_SHARED_CONF, reg); + + /* Enable channels now */ + for (i = 0; i < count; i++) { + reg = usbtll_read(base, OMAP_TLL_CHANNEL_CONF(i)); + + if (is_ohci_port(pdata->port_mode[i])) { + reg |= ohci_omap3_fslsmode(pdata->port_mode[i]) + << OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT; + reg |= OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS; + } else if (pdata->port_mode[i] == + OMAP_EHCI_PORT_MODE_TLL) { + /* + * Disable AutoIdle, BitStuffing + * and use SDR Mode + */ + reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE + | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF + | OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE); + } else { + continue; + } + reg |= OMAP_TLL_CHANNEL_CONF_CHANEN; + usbtll_write(base, OMAP_TLL_CHANNEL_CONF(i), reg); + + usbtll_writeb(base, + OMAP_TLL_ULPI_SCRATCH_REGISTER(i), + 0xbe); + } + } + +err_ioremap: + spin_unlock_irqrestore(&tll->lock, flags); + iounmap(base); + pm_runtime_put_sync(dev); + tll_pdev = pdev; + if (!ret) + goto end; + pm_runtime_disable(dev); + +err_usbtll_p2_fck: + clk_put(tll->usbtll_p2_fck); + +err_usbtll_p1_fck: + clk_put(tll->usbtll_p1_fck); + +err_tll: + kfree(tll); + +end: + return ret; +} + +/** + * usbtll_omap_remove - shutdown processing for UHH & TLL HCDs + * @pdev: USB Host Controller being removed + * + * Reverses the effect of usbtll_omap_probe(). + */ +static int __devexit usbtll_omap_remove(struct platform_device *pdev) +{ + struct usbtll_omap *tll = platform_get_drvdata(pdev); + + clk_put(tll->usbtll_p2_fck); + clk_put(tll->usbtll_p1_fck); + pm_runtime_disable(&pdev->dev); + kfree(tll); + return 0; +} + +static int usbtll_runtime_resume(struct device *dev) +{ + struct usbtll_omap *tll = dev_get_drvdata(dev); + struct usbtll_omap_platform_data *pdata = &tll->platdata; + unsigned long flags; + + dev_dbg(dev, "usbtll_runtime_resume\n"); + + if (!pdata) { + dev_dbg(dev, "missing platform_data\n"); + return -ENODEV; + } + + spin_lock_irqsave(&tll->lock, flags); + + if (is_ehci_tll_mode(pdata->port_mode[0])) + clk_enable(tll->usbtll_p1_fck); + + if (is_ehci_tll_mode(pdata->port_mode[1])) + clk_enable(tll->usbtll_p2_fck); + + spin_unlock_irqrestore(&tll->lock, flags); + + return 0; +} + +static int usbtll_runtime_suspend(struct device *dev) +{ + struct usbtll_omap *tll = dev_get_drvdata(dev); + struct usbtll_omap_platform_data *pdata = &tll->platdata; + unsigned long flags; + + dev_dbg(dev, "usbtll_runtime_suspend\n"); + + if (!pdata) { + dev_dbg(dev, "missing platform_data\n"); + return -ENODEV; + } + + spin_lock_irqsave(&tll->lock, flags); + + if (is_ehci_tll_mode(pdata->port_mode[0])) + clk_disable(tll->usbtll_p1_fck); + + if (is_ehci_tll_mode(pdata->port_mode[1])) + clk_disable(tll->usbtll_p2_fck); + + spin_unlock_irqrestore(&tll->lock, flags); + + return 0; +} + +static const struct dev_pm_ops usbtllomap_dev_pm_ops = { + SET_RUNTIME_PM_OPS(usbtll_runtime_suspend, + usbtll_runtime_resume, + NULL) +}; + +static struct platform_driver usbtll_omap_driver = { + .driver = { + .name = (char *)usbtll_driver_name, + .owner = THIS_MODULE, + .pm = &usbtllomap_dev_pm_ops, + }, + .probe = usbtll_omap_probe, + .remove = __devexit_p(usbtll_omap_remove), +}; + +int omap_tll_enable(void) +{ + if (!tll_pdev) { + pr_err("missing omap usbhs tll platform_data\n"); + return -ENODEV; + } + return pm_runtime_get_sync(&tll_pdev->dev); +} +EXPORT_SYMBOL_GPL(omap_tll_enable); + +int omap_tll_disable(void) +{ + if (!tll_pdev) { + pr_err("missing omap usbhs tll platform_data\n"); + return -ENODEV; + } + return pm_runtime_put_sync(&tll_pdev->dev); +} +EXPORT_SYMBOL_GPL(omap_tll_disable); + +MODULE_AUTHOR("Keshava Munegowda "); +MODULE_ALIAS("platform:" USBHS_DRIVER_NAME); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("usb tll driver for TI OMAP EHCI and OHCI controllers"); + +static int __init omap_usbtll_drvinit(void) +{ + return platform_driver_register(&usbtll_omap_driver); +} + +/* + * init before usbhs core driver; + * The usbtll driver should be initialized before + * the usbhs core driver probe function is called. + */ +fs_initcall(omap_usbtll_drvinit); + +static void __exit omap_usbtll_drvexit(void) +{ + platform_driver_unregister(&usbtll_omap_driver); +} +module_exit(omap_usbtll_drvexit); -- cgit v1.2.2 From 4dc2cceb5a85e8792517ea9b7ba334eaae75a10d Mon Sep 17 00:00:00 2001 From: Keshava Munegowda Date: Mon, 16 Jul 2012 19:01:09 +0530 Subject: mfd: omap-usb-host: Invoke the TLL driver from USB HS core driver The usbhs driver invokes the enable/disable APIs of the usb tll driver in the runtime resume/suspend callbacks of the runtime get sync and put sync of the usbhs driver. Signed-off-by: Keshava Munegowda Reviewed-by: Partha Basak Acked-by: Felipe Balbi Signed-off-by: Samuel Ortiz --- drivers/mfd/omap-usb-host.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 41088ecbb2a9..8a256dfe6ddf 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -436,6 +435,7 @@ static int usbhs_runtime_resume(struct device *dev) return -ENODEV; } + omap_tll_enable(); spin_lock_irqsave(&omap->lock, flags); if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck)) @@ -487,6 +487,7 @@ static int usbhs_runtime_suspend(struct device *dev) clk_disable(omap->ehci_logic_fck); spin_unlock_irqrestore(&omap->lock, flags); + omap_tll_disable(); return 0; } @@ -910,8 +911,10 @@ static int __init omap_usbhs_drvinit(void) * init before ehci and ohci drivers; * The usbhs core driver should be initialized much before * the omap ehci and ohci probe functions are called. + * This usbhs core driver should be initialized after + * usb tll driver */ -fs_initcall(omap_usbhs_drvinit); +fs_initcall_sync(omap_usbhs_drvinit); static void __exit omap_usbhs_drvexit(void) { -- cgit v1.2.2 From 760189b362a5e00ea60477995a1d0a5826a333be Mon Sep 17 00:00:00 2001 From: Keshava Munegowda Date: Mon, 16 Jul 2012 19:01:10 +0530 Subject: mfd: omap-usb-host: Remove TLL specific code from USB HS core driver The TLL specific code such as channels clocks enable/disable, initialization functions are removed from the USBHS core driver. The hwmod of the usb tll is retrieved and omap device build is performed to created the platform device for the usb tll component. Signed-off-by: Keshava Munegowda Reviewed-by: Partha Basak Acked-by: Felipe Balbi Signed-off-by: Samuel Ortiz --- drivers/mfd/omap-usb-host.c | 231 ++------------------------------------------ 1 file changed, 10 insertions(+), 221 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 8a256dfe6ddf..23cec57c02ba 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -35,63 +35,6 @@ /* OMAP USBHOST Register addresses */ -/* TLL Register Set */ -#define OMAP_USBTLL_REVISION (0x00) -#define OMAP_USBTLL_SYSCONFIG (0x10) -#define OMAP_USBTLL_SYSCONFIG_CACTIVITY (1 << 8) -#define OMAP_USBTLL_SYSCONFIG_SIDLEMODE (1 << 3) -#define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP (1 << 2) -#define OMAP_USBTLL_SYSCONFIG_SOFTRESET (1 << 1) -#define OMAP_USBTLL_SYSCONFIG_AUTOIDLE (1 << 0) - -#define OMAP_USBTLL_SYSSTATUS (0x14) -#define OMAP_USBTLL_SYSSTATUS_RESETDONE (1 << 0) - -#define OMAP_USBTLL_IRQSTATUS (0x18) -#define OMAP_USBTLL_IRQENABLE (0x1C) - -#define OMAP_TLL_SHARED_CONF (0x30) -#define OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN (1 << 6) -#define OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN (1 << 5) -#define OMAP_TLL_SHARED_CONF_USB_DIVRATION (1 << 2) -#define OMAP_TLL_SHARED_CONF_FCLK_REQ (1 << 1) -#define OMAP_TLL_SHARED_CONF_FCLK_IS_ON (1 << 0) - -#define OMAP_TLL_CHANNEL_CONF(num) (0x040 + 0x004 * num) -#define OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT 24 -#define OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF (1 << 11) -#define OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE (1 << 10) -#define OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE (1 << 9) -#define OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE (1 << 8) -#define OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS (1 << 1) -#define OMAP_TLL_CHANNEL_CONF_CHANEN (1 << 0) - -#define OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0 0x0 -#define OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM 0x1 -#define OMAP_TLL_FSLSMODE_3PIN_PHY 0x2 -#define OMAP_TLL_FSLSMODE_4PIN_PHY 0x3 -#define OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0 0x4 -#define OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM 0x5 -#define OMAP_TLL_FSLSMODE_3PIN_TLL 0x6 -#define OMAP_TLL_FSLSMODE_4PIN_TLL 0x7 -#define OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0 0xA -#define OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM 0xB - -#define OMAP_TLL_ULPI_FUNCTION_CTRL(num) (0x804 + 0x100 * num) -#define OMAP_TLL_ULPI_INTERFACE_CTRL(num) (0x807 + 0x100 * num) -#define OMAP_TLL_ULPI_OTG_CTRL(num) (0x80A + 0x100 * num) -#define OMAP_TLL_ULPI_INT_EN_RISE(num) (0x80D + 0x100 * num) -#define OMAP_TLL_ULPI_INT_EN_FALL(num) (0x810 + 0x100 * num) -#define OMAP_TLL_ULPI_INT_STATUS(num) (0x813 + 0x100 * num) -#define OMAP_TLL_ULPI_INT_LATCH(num) (0x814 + 0x100 * num) -#define OMAP_TLL_ULPI_DEBUG(num) (0x815 + 0x100 * num) -#define OMAP_TLL_ULPI_SCRATCH_REGISTER(num) (0x816 + 0x100 * num) - -#define OMAP_TLL_CHANNEL_COUNT 3 -#define OMAP_TLL_CHANNEL_1_EN_MASK (1 << 0) -#define OMAP_TLL_CHANNEL_2_EN_MASK (1 << 1) -#define OMAP_TLL_CHANNEL_3_EN_MASK (1 << 2) - /* UHH Register Set */ #define OMAP_UHH_REVISION (0x00) #define OMAP_UHH_SYSCONFIG (0x10) @@ -131,8 +74,6 @@ #define OMAP4_P2_MODE_TLL (1 << 18) #define OMAP4_P2_MODE_HSIC (3 << 18) -#define OMAP_REV2_TLL_CHANNEL_COUNT 2 - #define OMAP_UHH_DEBUG_CSR (0x44) /* Values of UHH_REVISION - Note: these are not given in the TRM */ @@ -152,15 +93,12 @@ struct usbhs_hcd_omap { struct clk *xclk60mhsp2_ck; struct clk *utmi_p1_fck; struct clk *usbhost_p1_fck; - struct clk *usbtll_p1_fck; struct clk *utmi_p2_fck; struct clk *usbhost_p2_fck; - struct clk *usbtll_p2_fck; struct clk *init_60m_fclk; struct clk *ehci_logic_fck; void __iomem *uhh_base; - void __iomem *tll_base; struct usbhs_omap_platform_data platdata; @@ -335,93 +273,6 @@ static bool is_ohci_port(enum usbhs_omap_port_mode pmode) } } -/* - * convert the port-mode enum to a value we can use in the FSLSMODE - * field of USBTLL_CHANNEL_CONF - */ -static unsigned ohci_omap3_fslsmode(enum usbhs_omap_port_mode mode) -{ - switch (mode) { - case OMAP_USBHS_PORT_MODE_UNUSED: - case OMAP_OHCI_PORT_MODE_PHY_6PIN_DATSE0: - return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; - - case OMAP_OHCI_PORT_MODE_PHY_6PIN_DPDM: - return OMAP_TLL_FSLSMODE_6PIN_PHY_DP_DM; - - case OMAP_OHCI_PORT_MODE_PHY_3PIN_DATSE0: - return OMAP_TLL_FSLSMODE_3PIN_PHY; - - case OMAP_OHCI_PORT_MODE_PHY_4PIN_DPDM: - return OMAP_TLL_FSLSMODE_4PIN_PHY; - - case OMAP_OHCI_PORT_MODE_TLL_6PIN_DATSE0: - return OMAP_TLL_FSLSMODE_6PIN_TLL_DAT_SE0; - - case OMAP_OHCI_PORT_MODE_TLL_6PIN_DPDM: - return OMAP_TLL_FSLSMODE_6PIN_TLL_DP_DM; - - case OMAP_OHCI_PORT_MODE_TLL_3PIN_DATSE0: - return OMAP_TLL_FSLSMODE_3PIN_TLL; - - case OMAP_OHCI_PORT_MODE_TLL_4PIN_DPDM: - return OMAP_TLL_FSLSMODE_4PIN_TLL; - - case OMAP_OHCI_PORT_MODE_TLL_2PIN_DATSE0: - return OMAP_TLL_FSLSMODE_2PIN_TLL_DAT_SE0; - - case OMAP_OHCI_PORT_MODE_TLL_2PIN_DPDM: - return OMAP_TLL_FSLSMODE_2PIN_DAT_DP_DM; - default: - pr_warning("Invalid port mode, using default\n"); - return OMAP_TLL_FSLSMODE_6PIN_PHY_DAT_SE0; - } -} - -static void usbhs_omap_tll_init(struct device *dev, u8 tll_channel_count) -{ - struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); - struct usbhs_omap_platform_data *pdata = dev->platform_data; - unsigned reg; - int i; - - /* Program Common TLL register */ - reg = usbhs_read(omap->tll_base, OMAP_TLL_SHARED_CONF); - reg |= (OMAP_TLL_SHARED_CONF_FCLK_IS_ON - | OMAP_TLL_SHARED_CONF_USB_DIVRATION); - reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN; - reg &= ~OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN; - - usbhs_write(omap->tll_base, OMAP_TLL_SHARED_CONF, reg); - - /* Enable channels now */ - for (i = 0; i < tll_channel_count; i++) { - reg = usbhs_read(omap->tll_base, - OMAP_TLL_CHANNEL_CONF(i)); - - if (is_ohci_port(pdata->port_mode[i])) { - reg |= ohci_omap3_fslsmode(pdata->port_mode[i]) - << OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT; - reg |= OMAP_TLL_CHANNEL_CONF_CHANMODE_FSLS; - } else if (pdata->port_mode[i] == OMAP_EHCI_PORT_MODE_TLL) { - - /* Disable AutoIdle, BitStuffing and use SDR Mode */ - reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE - | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF - | OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE); - - } else - continue; - - reg |= OMAP_TLL_CHANNEL_CONF_CHANEN; - usbhs_write(omap->tll_base, - OMAP_TLL_CHANNEL_CONF(i), reg); - - usbhs_writeb(omap->tll_base, - OMAP_TLL_ULPI_SCRATCH_REGISTER(i), 0xbe); - } -} - static int usbhs_runtime_resume(struct device *dev) { struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); @@ -441,14 +292,11 @@ static int usbhs_runtime_resume(struct device *dev) if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck)) clk_enable(omap->ehci_logic_fck); - if (is_ehci_tll_mode(pdata->port_mode[0])) { + if (is_ehci_tll_mode(pdata->port_mode[0])) clk_enable(omap->usbhost_p1_fck); - clk_enable(omap->usbtll_p1_fck); - } - if (is_ehci_tll_mode(pdata->port_mode[1])) { + if (is_ehci_tll_mode(pdata->port_mode[1])) clk_enable(omap->usbhost_p2_fck); - clk_enable(omap->usbtll_p2_fck); - } + clk_enable(omap->utmi_p1_fck); clk_enable(omap->utmi_p2_fck); @@ -472,14 +320,11 @@ static int usbhs_runtime_suspend(struct device *dev) spin_lock_irqsave(&omap->lock, flags); - if (is_ehci_tll_mode(pdata->port_mode[0])) { + if (is_ehci_tll_mode(pdata->port_mode[0])) clk_disable(omap->usbhost_p1_fck); - clk_disable(omap->usbtll_p1_fck); - } - if (is_ehci_tll_mode(pdata->port_mode[1])) { + if (is_ehci_tll_mode(pdata->port_mode[1])) clk_disable(omap->usbhost_p2_fck); - clk_disable(omap->usbtll_p2_fck); - } + clk_disable(omap->utmi_p2_fck); clk_disable(omap->utmi_p1_fck); @@ -501,8 +346,6 @@ static void omap_usbhs_init(struct device *dev) dev_dbg(dev, "starting TI HSUSB Controller\n"); - pm_runtime_get_sync(dev); - if (pdata->ehci_data->phy_reset) { if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) gpio_request_one(pdata->ehci_data->reset_gpio_port[0], @@ -516,6 +359,7 @@ static void omap_usbhs_init(struct device *dev) udelay(10); } + pm_runtime_get_sync(dev); spin_lock_irqsave(&omap->lock, flags); omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); @@ -581,22 +425,9 @@ static void omap_usbhs_init(struct device *dev) usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg); - if (is_ehci_tll_mode(pdata->port_mode[0]) || - is_ehci_tll_mode(pdata->port_mode[1]) || - is_ehci_tll_mode(pdata->port_mode[2]) || - (is_ohci_port(pdata->port_mode[0])) || - (is_ohci_port(pdata->port_mode[1])) || - (is_ohci_port(pdata->port_mode[2]))) { - - /* Enable UTMI mode for required TLL channels */ - if (is_omap_usbhs_rev2(omap)) - usbhs_omap_tll_init(dev, OMAP_REV2_TLL_CHANNEL_COUNT); - else - usbhs_omap_tll_init(dev, OMAP_TLL_CHANNEL_COUNT); - } - spin_unlock_irqrestore(&omap->lock, flags); + pm_runtime_put_sync(dev); if (pdata->ehci_data->phy_reset) { /* Hold the PHY in RESET for enough time till * PHY is settled and ready @@ -611,8 +442,6 @@ static void omap_usbhs_init(struct device *dev) gpio_set_value_cansleep (pdata->ehci_data->reset_gpio_port[1], 1); } - - pm_runtime_put_sync(dev); } static void omap_usbhs_deinit(struct device *dev) @@ -715,32 +544,18 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev) goto err_xclk60mhsp2_ck; } - omap->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk"); - if (IS_ERR(omap->usbtll_p1_fck)) { - ret = PTR_ERR(omap->usbtll_p1_fck); - dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret); - goto err_usbhost_p1_fck; - } - omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk"); if (IS_ERR(omap->usbhost_p2_fck)) { ret = PTR_ERR(omap->usbhost_p2_fck); dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret); - goto err_usbtll_p1_fck; - } - - omap->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk"); - if (IS_ERR(omap->usbtll_p2_fck)) { - ret = PTR_ERR(omap->usbtll_p2_fck); - dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret); - goto err_usbhost_p2_fck; + goto err_usbhost_p1_fck; } omap->init_60m_fclk = clk_get(dev, "init_60m_fclk"); if (IS_ERR(omap->init_60m_fclk)) { ret = PTR_ERR(omap->init_60m_fclk); dev_err(dev, "init_60m_fclk failed error:%d\n", ret); - goto err_usbtll_p2_fck; + goto err_usbhost_p2_fck; } if (is_ehci_phy_mode(pdata->port_mode[0])) { @@ -786,20 +601,6 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev) goto err_init_60m_fclk; } - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tll"); - if (!res) { - dev_err(dev, "UHH EHCI get resource failed\n"); - ret = -ENODEV; - goto err_tll; - } - - omap->tll_base = ioremap(res->start, resource_size(res)); - if (!omap->tll_base) { - dev_err(dev, "TLL ioremap failed\n"); - ret = -ENOMEM; - goto err_tll; - } - platform_set_drvdata(pdev, omap); omap_usbhs_init(dev); @@ -813,23 +614,14 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev) err_alloc: omap_usbhs_deinit(&pdev->dev); - iounmap(omap->tll_base); - -err_tll: iounmap(omap->uhh_base); err_init_60m_fclk: clk_put(omap->init_60m_fclk); -err_usbtll_p2_fck: - clk_put(omap->usbtll_p2_fck); - err_usbhost_p2_fck: clk_put(omap->usbhost_p2_fck); -err_usbtll_p1_fck: - clk_put(omap->usbtll_p1_fck); - err_usbhost_p1_fck: clk_put(omap->usbhost_p1_fck); @@ -865,12 +657,9 @@ static int __devexit usbhs_omap_remove(struct platform_device *pdev) struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); omap_usbhs_deinit(&pdev->dev); - iounmap(omap->tll_base); iounmap(omap->uhh_base); clk_put(omap->init_60m_fclk); - clk_put(omap->usbtll_p2_fck); clk_put(omap->usbhost_p2_fck); - clk_put(omap->usbtll_p1_fck); clk_put(omap->usbhost_p1_fck); clk_put(omap->xclk60mhsp2_ck); clk_put(omap->utmi_p2_fck); -- cgit v1.2.2 From 489422224b74c33e0efec940ad17fc02dcfe0e1f Mon Sep 17 00:00:00 2001 From: Shubhrajyoti D Date: Mon, 17 Sep 2012 21:14:58 +0530 Subject: mfd: Convert struct i2c_msg initialization to C99 format Convert the struct i2c_msg initialization to C99 format. This makes maintaining and editing the code simpler. Also helps once other fields like transferred are added in future. Thanks to Julia Lawall for automating the conversion Signed-off-by: Shubhrajyoti D Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-i2c.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c index cd53a823c0c5..ff8f803ce833 100644 --- a/drivers/mfd/88pm860x-i2c.c +++ b/drivers/mfd/88pm860x-i2c.c @@ -88,8 +88,18 @@ static int read_device(struct i2c_client *i2c, int reg, unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX + 3]; unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX + 2]; struct i2c_adapter *adap = i2c->adapter; - struct i2c_msg msg[2] = {{i2c->addr, 0, 1, msgbuf0}, - {i2c->addr, I2C_M_RD, 0, msgbuf1}, + struct i2c_msg msg[2] = { + { + .addr = i2c->addr, + .flags = 0, + .len = 1, + .buf = msgbuf0 + }, + { .addr = i2c->addr, + .flags = I2C_M_RD, + .len = 0, + .buf = msgbuf1 + }, }; int num = 1, ret = 0; -- cgit v1.2.2 From 0cb166e0538b2b2fe746bfa3c82ef6fece9b8888 Mon Sep 17 00:00:00 2001 From: Andreas Pretzsch Date: Mon, 17 Sep 2012 18:17:21 +0200 Subject: mfd: Use devm_* APIs for mc13xxx: remove leftover kfree commit e7c706b1e5ccf28eaaf76c7a4613e80b0ca52863 migrated the allocation of struct mc13xxx to devm_* functions, but left a kfree(mc13xxx) in the mc13xxx_common_init error path. Remove it to prevent memory corruption. Signed-off-by: Andreas Pretzsch Reviewed-by: Axel Lin Signed-off-by: Samuel Ortiz --- drivers/mfd/mc13xxx-core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 1ec79b54bd2f..1aba0238f426 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -676,7 +676,6 @@ int mc13xxx_common_init(struct mc13xxx *mc13xxx, err_mask: err_revision: mc13xxx_unlock(mc13xxx); - kfree(mc13xxx); return ret; } -- cgit v1.2.2 From 81a21cddaf14bd1144c2d173add7cbdeb95a07ca Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 27 Jul 2012 13:38:51 +0100 Subject: mfd: ab8500-core: Apply the AB8500 CODEC's compatible string to its MFD cell Provide a compatible string for the AB8500 CODEC to aid in configuration property look-up from its associated Device Tree node. Signed-off-by: Lee Jones Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index a3aceffb60fe..1667c77b5cde 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -1076,6 +1076,7 @@ static struct mfd_cell __devinitdata ab8500_devs[] = { }, { .name = "ab8500-codec", + .of_compatible = "stericsson,ab8500-codec", }, }; -- cgit v1.2.2 From 3f78decc321d48724809406b498708d2ab4b93d2 Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Tue, 28 Aug 2012 13:47:35 +0200 Subject: mfd: palmas: Improve the error exit path Improve the error exit path so that we correctly de-allocate resources that have been allocated upto the point where error occurs. Signed-off-by: Graeme Gregory Signed-off-by: Samuel Ortiz --- drivers/mfd/palmas.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index e7a7415b8c2b..5831dfdb3f4c 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c @@ -377,11 +377,11 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c, reg = pdata->pad1; ret = regmap_write(palmas->regmap[slave], addr, reg); if (ret) - goto err; + goto err_irq; } else { ret = regmap_read(palmas->regmap[slave], addr, ®); if (ret) - goto err; + goto err_irq; } if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD1_GPIO_0)) @@ -412,11 +412,11 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c, reg = pdata->pad2; ret = regmap_write(palmas->regmap[slave], addr, reg); if (ret) - goto err; + goto err_irq; } else { ret = regmap_read(palmas->regmap[slave], addr, ®); if (ret) - goto err; + goto err_irq; } if (!(reg & PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_4)) @@ -439,13 +439,13 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c, ret = regmap_write(palmas->regmap[slave], addr, reg); if (ret) - goto err; + goto err_irq; children = kmemdup(palmas_children, sizeof(palmas_children), GFP_KERNEL); if (!children) { ret = -ENOMEM; - goto err; + goto err_irq; } children[PALMAS_PMIC_ID].platform_data = pdata->pmic_pdata; @@ -458,12 +458,15 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c, kfree(children); if (ret < 0) - goto err; + goto err_devices; return ret; -err: +err_devices: mfd_remove_devices(palmas->dev); +err_irq: + regmap_del_irq_chip(palmas->irq, palmas->irq_data); +err: return ret; } -- cgit v1.2.2 From 8664fade0d235eeed2f2cfdeb10d3f243ec01e4f Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Tue, 28 Aug 2012 13:47:36 +0200 Subject: mfd: palmas: Switch to linear domain in all cases Swith the palmas to linear domain in all cases so in future DT and non DT cases will work the same. With this patch children no longer need IRQ resources as it's easier for them to use regmap_get_virq. So we can remove the resources definitions. Signed-off-by: Graeme Gregory Signed-off-by: Samuel Ortiz --- drivers/mfd/palmas.c | 64 +--------------------------------------------------- 1 file changed, 1 insertion(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index 5831dfdb3f4c..942d1d3813a5 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c @@ -24,60 +24,6 @@ #include #include -static const struct resource gpadc_resource[] = { - { - .name = "EOC_SW", - .start = PALMAS_GPADC_EOC_SW_IRQ, - .end = PALMAS_GPADC_EOC_SW_IRQ, - .flags = IORESOURCE_IRQ, - } -}; - -static const struct resource usb_resource[] = { - { - .name = "ID", - .start = PALMAS_ID_OTG_IRQ, - .end = PALMAS_ID_OTG_IRQ, - .flags = IORESOURCE_IRQ, - }, - { - .name = "ID_WAKEUP", - .start = PALMAS_ID_IRQ, - .end = PALMAS_ID_IRQ, - .flags = IORESOURCE_IRQ, - }, - { - .name = "VBUS", - .start = PALMAS_VBUS_OTG_IRQ, - .end = PALMAS_VBUS_OTG_IRQ, - .flags = IORESOURCE_IRQ, - }, - { - .name = "VBUS_WAKEUP", - .start = PALMAS_VBUS_IRQ, - .end = PALMAS_VBUS_IRQ, - .flags = IORESOURCE_IRQ, - }, -}; - -static const struct resource rtc_resource[] = { - { - .name = "RTC_ALARM", - .start = PALMAS_RTC_ALARM_IRQ, - .end = PALMAS_RTC_ALARM_IRQ, - .flags = IORESOURCE_IRQ, - }, -}; - -static const struct resource pwron_resource[] = { - { - .name = "PWRON_BUTTON", - .start = PALMAS_PWRON_IRQ, - .end = PALMAS_PWRON_IRQ, - .flags = IORESOURCE_IRQ, - }, -}; - enum palmas_ids { PALMAS_PMIC_ID, PALMAS_GPIO_ID, @@ -111,20 +57,14 @@ static const struct mfd_cell palmas_children[] = { }, { .name = "palmas-rtc", - .num_resources = ARRAY_SIZE(rtc_resource), - .resources = rtc_resource, .id = PALMAS_RTC_ID, }, { .name = "palmas-pwrbutton", - .num_resources = ARRAY_SIZE(pwron_resource), - .resources = pwron_resource, .id = PALMAS_PWRBUTTON_ID, }, { .name = "palmas-gpadc", - .num_resources = ARRAY_SIZE(gpadc_resource), - .resources = gpadc_resource, .id = PALMAS_GPADC_ID, }, { @@ -141,8 +81,6 @@ static const struct mfd_cell palmas_children[] = { }, { .name = "palmas-usb", - .num_resources = ARRAY_SIZE(usb_resource), - .resources = usb_resource, .id = PALMAS_USB_ID, } }; @@ -364,7 +302,7 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c, regmap_write(palmas->regmap[slave], addr, reg); ret = regmap_add_irq_chip(palmas->regmap[slave], palmas->irq, - IRQF_ONESHOT | IRQF_TRIGGER_LOW, -1, &palmas_irq_chip, + IRQF_ONESHOT | IRQF_TRIGGER_LOW, 0, &palmas_irq_chip, &palmas->irq_data); if (ret < 0) goto err; -- cgit v1.2.2 From 190ef1a6e1e493340281d10a9dbda2eac205884c Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Tue, 28 Aug 2012 13:47:37 +0200 Subject: mfd: palmas: Add pdata/data for rest of children Add the platform data and data structures for children that shall be added by a future set of commits. Signed-off-by: Graeme Gregory Signed-off-by: Samuel Ortiz --- drivers/mfd/palmas.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index 942d1d3813a5..7c1a1942d334 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c @@ -389,6 +389,19 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c, children[PALMAS_PMIC_ID].platform_data = pdata->pmic_pdata; children[PALMAS_PMIC_ID].pdata_size = sizeof(*pdata->pmic_pdata); + children[PALMAS_GPADC_ID].platform_data = pdata->gpadc_pdata; + children[PALMAS_GPADC_ID].pdata_size = sizeof(*pdata->gpadc_pdata); + + children[PALMAS_RESOURCE_ID].platform_data = pdata->resource_pdata; + children[PALMAS_RESOURCE_ID].pdata_size = + sizeof(*pdata->resource_pdata); + + children[PALMAS_USB_ID].platform_data = pdata->usb_pdata; + children[PALMAS_USB_ID].pdata_size = sizeof(*pdata->usb_pdata); + + children[PALMAS_CLK_ID].platform_data = pdata->clk_pdata; + children[PALMAS_CLK_ID].pdata_size = sizeof(*pdata->clk_pdata); + ret = mfd_add_devices(palmas->dev, -1, children, ARRAY_SIZE(palmas_children), NULL, regmap_irq_chip_get_base(palmas->irq_data), -- cgit v1.2.2 From 9c14ac33450eaa3347d0d202c2a4116578976a63 Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Tue, 28 Aug 2012 13:47:38 +0200 Subject: mfd: palmas: Add device tree handling to mfd Add device tree handling to the palmas MFD. This takes the values that can be set from platform data from the device tree nodes instead. Signed-off-by: Graeme Gregory Signed-off-by: Samuel Ortiz --- drivers/mfd/palmas.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index 7c1a1942d334..4f8d6e6b19aa 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c @@ -23,6 +23,7 @@ #include #include #include +#include enum palmas_ids { PALMAS_PMIC_ID, @@ -246,17 +247,56 @@ static struct regmap_irq_chip palmas_irq_chip = { PALMAS_INT1_MASK), }; +static void __devinit palmas_dt_to_pdata(struct device_node *node, + struct palmas_platform_data *pdata) +{ + int ret; + u32 prop; + + ret = of_property_read_u32(node, "ti,mux_pad1", &prop); + if (!ret) { + pdata->mux_from_pdata = 1; + pdata->pad1 = prop; + } + + ret = of_property_read_u32(node, "ti,mux_pad2", &prop); + if (!ret) { + pdata->mux_from_pdata = 1; + pdata->pad2 = prop; + } + + /* The default for this register is all masked */ + ret = of_property_read_u32(node, "ti,power_ctrl", &prop); + if (!ret) + pdata->power_ctrl = prop; + else + pdata->power_ctrl = PALMAS_POWER_CTRL_NSLEEP_MASK | + PALMAS_POWER_CTRL_ENABLE1_MASK | + PALMAS_POWER_CTRL_ENABLE2_MASK; +} + static int __devinit palmas_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct palmas *palmas; struct palmas_platform_data *pdata; + struct device_node *node = i2c->dev.of_node; int ret = 0, i; unsigned int reg, addr; int slave; struct mfd_cell *children; pdata = dev_get_platdata(&i2c->dev); + + if (node && !pdata) { + pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL); + + if (!pdata) + return -ENOMEM; + + palmas_dt_to_pdata(node, pdata); + } + if (!pdata) return -EINVAL; @@ -379,6 +419,18 @@ static int __devinit palmas_i2c_probe(struct i2c_client *i2c, if (ret) goto err_irq; + /* + * If we are probing with DT do this the DT way and return here + * otherwise continue and add devices using mfd helpers. + */ + if (node) { + ret = of_platform_populate(node, NULL, NULL, &i2c->dev); + if (ret < 0) + goto err_irq; + else + return ret; + } + children = kmemdup(palmas_children, sizeof(palmas_children), GFP_KERNEL); if (!children) { -- cgit v1.2.2 From a361cd9f2e9f2110e03ebeb6c4fb000a9a1adf2d Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Tue, 28 Aug 2012 13:47:40 +0200 Subject: regulator: palmas: Add DT support Add DT support to palmas regulator. This involved a little change to the platform data structure. Regulator information can now come from platform data or DT. Signed-off-by: Graeme Gregory Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Samuel Ortiz --- drivers/regulator/palmas-regulator.c | 127 ++++++++++++++++++++++++++++++++--- 1 file changed, 119 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index 17d19fbbc490..a8294e5bcf36 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -22,6 +22,9 @@ #include #include #include +#include +#include +#include struct regs_info { char *name; @@ -603,10 +606,103 @@ static int palmas_ldo_init(struct palmas *palmas, int id, return 0; } +static struct of_regulator_match palmas_matches[] = { + { .name = "smps12", }, + { .name = "smps123", }, + { .name = "smps3", }, + { .name = "smps45", }, + { .name = "smps457", }, + { .name = "smps6", }, + { .name = "smps7", }, + { .name = "smps8", }, + { .name = "smps9", }, + { .name = "smps10", }, + { .name = "ldo1", }, + { .name = "ldo2", }, + { .name = "ldo3", }, + { .name = "ldo4", }, + { .name = "ldo5", }, + { .name = "ldo6", }, + { .name = "ldo7", }, + { .name = "ldo8", }, + { .name = "ldo9", }, + { .name = "ldoln", }, + { .name = "ldousb", }, +}; + +static void __devinit palmas_dt_to_pdata(struct device *dev, + struct device_node *node, + struct palmas_pmic_platform_data *pdata) +{ + struct device_node *regulators; + u32 prop; + int idx, ret; + + regulators = of_find_node_by_name(node, "regulators"); + if (!regulators) { + dev_info(dev, "regulator node not found\n"); + return; + } + + ret = of_regulator_match(dev, regulators, palmas_matches, + PALMAS_NUM_REGS); + if (ret < 0) { + dev_err(dev, "Error parsing regulator init data: %d\n", ret); + return; + } + + for (idx = 0; idx < PALMAS_NUM_REGS; idx++) { + if (!palmas_matches[idx].init_data || + !palmas_matches[idx].of_node) + continue; + + pdata->reg_data[idx] = palmas_matches[idx].init_data; + + pdata->reg_init[idx] = devm_kzalloc(dev, + sizeof(struct palmas_reg_init), GFP_KERNEL); + + ret = of_property_read_u32(palmas_matches[idx].of_node, + "ti,warm_reset", &prop); + if (!ret) + pdata->reg_init[idx]->warm_reset = prop; + + ret = of_property_read_u32(palmas_matches[idx].of_node, + "ti,roof_floor", &prop); + if (!ret) + pdata->reg_init[idx]->roof_floor = prop; + + ret = of_property_read_u32(palmas_matches[idx].of_node, + "ti,mode_sleep", &prop); + if (!ret) + pdata->reg_init[idx]->mode_sleep = prop; + + ret = of_property_read_u32(palmas_matches[idx].of_node, + "ti,warm_reset", &prop); + if (!ret) + pdata->reg_init[idx]->warm_reset = prop; + + ret = of_property_read_u32(palmas_matches[idx].of_node, + "ti,tstep", &prop); + if (!ret) + pdata->reg_init[idx]->tstep = prop; + + ret = of_property_read_u32(palmas_matches[idx].of_node, + "ti,vsel", &prop); + if (!ret) + pdata->reg_init[idx]->vsel = prop; + } + + ret = of_property_read_u32(node, "ti,ldo6_vibrator", &prop); + if (!ret) + pdata->ldo6_vibrator = prop; +} + + static __devinit int palmas_probe(struct platform_device *pdev) { struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); struct palmas_pmic_platform_data *pdata = pdev->dev.platform_data; + struct device_node *node = pdev->dev.of_node; struct regulator_dev *rdev; struct regulator_config config = { }; struct palmas_pmic *pmic; @@ -614,10 +710,14 @@ static __devinit int palmas_probe(struct platform_device *pdev) int id = 0, ret; unsigned int addr, reg; - if (!pdata) - return -EINVAL; - if (!pdata->reg_data) - return -EINVAL; + if (node && !pdata) { + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + + if (!pdata) + return -ENOMEM; + + palmas_dt_to_pdata(&pdev->dev, node, pdata); + } pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); if (!pmic) @@ -694,7 +794,7 @@ static __devinit int palmas_probe(struct platform_device *pdev) pmic->desc[id].owner = THIS_MODULE; /* Initialise sleep/init values from platform data */ - if (pdata && pdata->reg_init) { + if (pdata) { reg_init = pdata->reg_init[id]; if (reg_init) { ret = palmas_smps_init(palmas, id, reg_init); @@ -718,11 +818,13 @@ static __devinit int palmas_probe(struct platform_device *pdev) pmic->range[id] = 1; } - if (pdata && pdata->reg_data) + if (pdata) config.init_data = pdata->reg_data[id]; else config.init_data = NULL; + config.of_node = palmas_matches[id].of_node; + rdev = regulator_register(&pmic->desc[id], &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, @@ -756,11 +858,13 @@ static __devinit int palmas_probe(struct platform_device *pdev) palmas_regs_info[id].ctrl_addr); pmic->desc[id].enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE; - if (pdata && pdata->reg_data) + if (pdata) config.init_data = pdata->reg_data[id]; else config.init_data = NULL; + config.of_node = palmas_matches[id].of_node; + rdev = regulator_register(&pmic->desc[id], &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, @@ -774,7 +878,7 @@ static __devinit int palmas_probe(struct platform_device *pdev) pmic->rdev[id] = rdev; /* Initialise sleep/init values from platform data */ - if (pdata->reg_init) { + if (pdata) { reg_init = pdata->reg_init[id]; if (reg_init) { ret = palmas_ldo_init(palmas, id, reg_init); @@ -802,9 +906,15 @@ static int __devexit palmas_remove(struct platform_device *pdev) return 0; } +static struct of_device_id __devinitdata of_palmas_match_tbl[] = { + { .compatible = "ti,palmas-pmic", }, + { /* end */ } +}; + static struct platform_driver palmas_driver = { .driver = { .name = "palmas-pmic", + .of_match_table = of_palmas_match_tbl, .owner = THIS_MODULE, }, .probe = palmas_probe, @@ -827,3 +937,4 @@ MODULE_AUTHOR("Graeme Gregory "); MODULE_DESCRIPTION("Palmas voltage regulator driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:palmas-pmic"); +MODULE_DEVICE_TABLE(of, of_palmas_match_tbl); -- cgit v1.2.2 From 0dd96360e21ec7963aeba253261db87a32e728c6 Mon Sep 17 00:00:00 2001 From: Venu Byravarasu Date: Thu, 23 Aug 2012 12:21:16 +0530 Subject: mfd: rc5t583: Fix warning messages Two variables named master_int and sleepseq_val, were just declared without initialization. Pointers to these variables were passed to mfd read function. After that these variables were used for some of the logical operations. Though logically there is nothing wrong, compiler is complaining that the variables may be used uninitialized. Hence fixing these warning messages by initializing them. Signed-off-by: Venu Byravarasu Signed-off-by: Samuel Ortiz --- drivers/mfd/rc5t583-irq.c | 2 +- drivers/mfd/rc5t583.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/rc5t583-irq.c b/drivers/mfd/rc5t583-irq.c index fa6f80fad5f1..fe00cdd6f83d 100644 --- a/drivers/mfd/rc5t583-irq.c +++ b/drivers/mfd/rc5t583-irq.c @@ -255,7 +255,7 @@ static irqreturn_t rc5t583_irq(int irq, void *data) { struct rc5t583 *rc5t583 = data; uint8_t int_sts[RC5T583_MAX_INTERRUPT_MASK_REGS]; - uint8_t master_int; + uint8_t master_int = 0; int i; int ret; unsigned int rtc_int_sts = 0; diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c index 3a8fa88567b1..d6b50728ea32 100644 --- a/drivers/mfd/rc5t583.c +++ b/drivers/mfd/rc5t583.c @@ -85,7 +85,7 @@ static int __rc5t583_set_ext_pwrreq1_control(struct device *dev, int id, int ext_pwr, int slots) { int ret; - uint8_t sleepseq_val; + uint8_t sleepseq_val = 0; unsigned int en_bit; unsigned int slot_bit; -- cgit v1.2.2 From 804971ec3793d30f40c1a74775dd3fe89deb461a Mon Sep 17 00:00:00 2001 From: Michel Jaouen Date: Fri, 31 Aug 2012 14:21:30 +0200 Subject: mfd: dbx500: Provide a more accurate smp_twd clock The local timer clock is based on ARM subsystem clock. This patch obtains a more exact value of that clock by reading PRCMU registers. Using this increases the accuracy of the local timer events. Signed-off-by: Ulf Hansson Signed-off-by: Rickard Andersson Signed-off-by: Michel Jaouen Acked-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/db8500-prcmu.c | 41 +++++++++++++++++++++++++++++++++++++++++ drivers/mfd/dbx500-prcmu-regs.h | 4 +++- 2 files changed, 44 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 0e63cdd9b52a..6fb11b76071e 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -418,6 +418,9 @@ static struct { static atomic_t ac_wake_req_state = ATOMIC_INIT(0); +/* Functions definition */ +static void compute_armss_rate(void); + /* Spinlocks */ static DEFINE_SPINLOCK(prcmu_lock); static DEFINE_SPINLOCK(clkout_lock); @@ -1013,6 +1016,7 @@ int db8500_prcmu_set_arm_opp(u8 opp) (mb1_transfer.ack.arm_opp != opp)) r = -EIO; + compute_armss_rate(); mutex_unlock(&mb1_transfer.lock); return r; @@ -1612,6 +1616,7 @@ static unsigned long pll_rate(void __iomem *reg, unsigned long src_rate, if ((branch == PLL_FIX) || ((branch == PLL_DIV) && (val & PRCM_PLL_FREQ_DIV2EN) && ((reg == PRCM_PLLSOC0_FREQ) || + (reg == PRCM_PLLARM_FREQ) || (reg == PRCM_PLLDDR_FREQ)))) div *= 2; @@ -1661,6 +1666,39 @@ static unsigned long clock_rate(u8 clock) else return 0; } +static unsigned long latest_armss_rate; +static unsigned long armss_rate(void) +{ + return latest_armss_rate; +} + +static void compute_armss_rate(void) +{ + u32 r; + unsigned long rate; + + r = readl(PRCM_ARM_CHGCLKREQ); + + if (r & PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ) { + /* External ARMCLKFIX clock */ + + rate = pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_FIX); + + /* Check PRCM_ARM_CHGCLKREQ divider */ + if (!(r & PRCM_ARM_CHGCLKREQ_PRCM_ARM_DIVSEL)) + rate /= 2; + + /* Check PRCM_ARMCLKFIX_MGT divider */ + r = readl(PRCM_ARMCLKFIX_MGT); + r &= PRCM_CLK_MGT_CLKPLLDIV_MASK; + rate /= r; + + } else {/* ARM PLL */ + rate = pll_rate(PRCM_PLLARM_FREQ, ROOT_CLOCK_RATE, PLL_DIV); + } + + latest_armss_rate = rate; +} static unsigned long dsiclk_rate(u8 n) { @@ -1707,6 +1745,8 @@ unsigned long prcmu_clock_rate(u8 clock) return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, PLL_RAW); else if (clock == PRCMU_PLLSOC1) return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, PLL_RAW); + else if (clock == PRCMU_ARMSS) + return armss_rate(); else if (clock == PRCMU_PLLDDR) return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_RAW); else if (clock == PRCMU_PLLDSI) @@ -2693,6 +2733,7 @@ void __init db8500_prcmu_early_init(void) handle_simple_irq); set_irq_flags(irq, IRQF_VALID); } + compute_armss_rate(); } static void __init init_prcm_registers(void) diff --git a/drivers/mfd/dbx500-prcmu-regs.h b/drivers/mfd/dbx500-prcmu-regs.h index 23108a6e3167..79c76ebdba52 100644 --- a/drivers/mfd/dbx500-prcmu-regs.h +++ b/drivers/mfd/dbx500-prcmu-regs.h @@ -61,7 +61,8 @@ #define PRCM_PLLARM_LOCKP_PRCM_PLLARM_LOCKP3 0x2 #define PRCM_ARM_CHGCLKREQ (_PRCMU_BASE + 0x114) -#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ 0x1 +#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ BIT(0) +#define PRCM_ARM_CHGCLKREQ_PRCM_ARM_DIVSEL BIT(16) #define PRCM_PLLARM_ENABLE (_PRCMU_BASE + 0x98) #define PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE 0x1 @@ -140,6 +141,7 @@ /* PRCMU clock/PLL/reset registers */ #define PRCM_PLLSOC0_FREQ (_PRCMU_BASE + 0x080) #define PRCM_PLLSOC1_FREQ (_PRCMU_BASE + 0x084) +#define PRCM_PLLARM_FREQ (_PRCMU_BASE + 0x088) #define PRCM_PLLDDR_FREQ (_PRCMU_BASE + 0x08C) #define PRCM_PLL_FREQ_D_SHIFT 0 #define PRCM_PLL_FREQ_D_MASK BITS(0, 7) -- cgit v1.2.2 From eea6b7cc53aaecf868e1643058159807c744e04e Mon Sep 17 00:00:00 2001 From: Milo Kim Date: Wed, 19 Sep 2012 18:53:33 +0200 Subject: mfd: Add lp8788 mfd driver TI LP8788 PMU provides regulators, battery charger, ADC, RTC, backlight driver and current sinks. This MFD patch supports the I2C communication using the regmap, the interrupt handling using the linear IRQ domain and configurable platform data structures for each driver module. (Driver Architecture) < mfd devices > LP8788 HW .......... mfd .......... regulator drivers I2C power supply driver IRQs iio adc driver rtc driver backlight driver current sink drivers o regulators : LDOs and BUCKs o power supply : Battery charger o iio adc : Battery voltage/temperature o rtc : RTC and alarm o backlight o current sink : LED and vibrator All MFD device modules are registered by LP8788 MFD core driver. For sharing information such like the virtual IRQ number, MFD core driver uses the resource structure. Then each module can retrieve the specific IRQ number and detect it in the IRQ thread. Configurable platform data is handled in each driver module. Signed-off-by: Milo(Woogyom) Kim Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 10 ++ drivers/mfd/Makefile | 2 + drivers/mfd/lp8788-irq.c | 198 ++++++++++++++++++++++++++++++++++++++ drivers/mfd/lp8788.c | 245 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 455 insertions(+) create mode 100644 drivers/mfd/lp8788-irq.c create mode 100644 drivers/mfd/lp8788.c (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b9282cafa978..84d6ea2d74f4 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -440,6 +440,16 @@ config PMIC_ADP5520 individual components like LCD backlight, LEDs, GPIOs and Kepad under the corresponding menus. +config MFD_LP8788 + bool "Texas Instruments LP8788 Power Management Unit Driver" + depends on I2C=y + select MFD_CORE + select REGMAP_I2C + select IRQ_DOMAIN + help + TI LP8788 PMU supports regulators, battery charger, RTC, + ADC, backlight driver and current sinks. + config MFD_MAX77686 bool "Maxim Semiconductor MAX77686 PMIC Support" depends on I2C=y && GENERIC_HARDIRQS diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index d16bc0220e1f..083acf97af26 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -89,6 +89,8 @@ obj-$(CONFIG_PMIC_DA9052) += da9052-core.o obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o +obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.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/lp8788-irq.c b/drivers/mfd/lp8788-irq.c new file mode 100644 index 000000000000..c84ded5f8ece --- /dev/null +++ b/drivers/mfd/lp8788-irq.c @@ -0,0 +1,198 @@ +/* + * TI LP8788 MFD - interrupt handler + * + * Copyright 2012 Texas Instruments + * + * Author: Milo(Woogyom) Kim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* register address */ +#define LP8788_INT_1 0x00 +#define LP8788_INTEN_1 0x03 + +#define BASE_INTEN_ADDR LP8788_INTEN_1 +#define SIZE_REG 8 +#define NUM_REGS 3 + +/* + * struct lp8788_irq_data + * @lp : used for accessing to lp8788 registers + * @irq_lock : mutex for enabling/disabling the interrupt + * @domain : IRQ domain for handling nested interrupt + * @enabled : status of enabled interrupt + */ +struct lp8788_irq_data { + struct lp8788 *lp; + struct mutex irq_lock; + struct irq_domain *domain; + int enabled[LP8788_INT_MAX]; +}; + +static inline u8 _irq_to_addr(enum lp8788_int_id id) +{ + return id / SIZE_REG; +} + +static inline u8 _irq_to_enable_addr(enum lp8788_int_id id) +{ + return _irq_to_addr(id) + BASE_INTEN_ADDR; +} + +static inline u8 _irq_to_mask(enum lp8788_int_id id) +{ + return 1 << (id % SIZE_REG); +} + +static inline u8 _irq_to_val(enum lp8788_int_id id, int enable) +{ + return enable << (id % SIZE_REG); +} + +static void lp8788_irq_enable(struct irq_data *data) +{ + struct lp8788_irq_data *irqd = irq_data_get_irq_chip_data(data); + irqd->enabled[data->hwirq] = 1; +} + +static void lp8788_irq_disable(struct irq_data *data) +{ + struct lp8788_irq_data *irqd = irq_data_get_irq_chip_data(data); + irqd->enabled[data->hwirq] = 0; +} + +static void lp8788_irq_bus_lock(struct irq_data *data) +{ + struct lp8788_irq_data *irqd = irq_data_get_irq_chip_data(data); + + mutex_lock(&irqd->irq_lock); +} + +static void lp8788_irq_bus_sync_unlock(struct irq_data *data) +{ + struct lp8788_irq_data *irqd = irq_data_get_irq_chip_data(data); + enum lp8788_int_id irq = data->hwirq; + u8 addr, mask, val; + + addr = _irq_to_enable_addr(irq); + mask = _irq_to_mask(irq); + val = _irq_to_val(irq, irqd->enabled[irq]); + + lp8788_update_bits(irqd->lp, addr, mask, val); + + mutex_unlock(&irqd->irq_lock); +} + +static struct irq_chip lp8788_irq_chip = { + .name = "lp8788", + .irq_enable = lp8788_irq_enable, + .irq_disable = lp8788_irq_disable, + .irq_bus_lock = lp8788_irq_bus_lock, + .irq_bus_sync_unlock = lp8788_irq_bus_sync_unlock, +}; + +static irqreturn_t lp8788_irq_handler(int irq, void *ptr) +{ + struct lp8788_irq_data *irqd = ptr; + struct lp8788 *lp = irqd->lp; + u8 status[NUM_REGS], addr, mask; + bool handled; + int i; + + if (lp8788_read_multi_bytes(lp, LP8788_INT_1, status, NUM_REGS)) + return IRQ_NONE; + + for (i = 0 ; i < LP8788_INT_MAX ; i++) { + addr = _irq_to_addr(i); + mask = _irq_to_mask(i); + + /* reporting only if the irq is enabled */ + if (status[addr] & mask) { + handle_nested_irq(irq_find_mapping(irqd->domain, i)); + handled = true; + } + } + + return handled ? IRQ_HANDLED : IRQ_NONE; +} + +static int lp8788_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hwirq) +{ + struct lp8788_irq_data *irqd = d->host_data; + struct irq_chip *chip = &lp8788_irq_chip; + + irq_set_chip_data(virq, irqd); + irq_set_chip_and_handler(virq, chip, handle_edge_irq); + irq_set_nested_thread(virq, 1); + +#ifdef CONFIG_ARM + set_irq_flags(virq, IRQF_VALID); +#else + irq_set_noprobe(virq); +#endif + + return 0; +} + +static struct irq_domain_ops lp8788_domain_ops = { + .map = lp8788_irq_map, +}; + +int lp8788_irq_init(struct lp8788 *lp, int irq) +{ + struct lp8788_irq_data *irqd; + int ret; + + if (irq <= 0) { + dev_warn(lp->dev, "invalid irq number: %d\n", irq); + return 0; + } + + irqd = devm_kzalloc(lp->dev, sizeof(*irqd), GFP_KERNEL); + if (!irqd) + return -ENOMEM; + + irqd->lp = lp; + irqd->domain = irq_domain_add_linear(lp->dev->of_node, LP8788_INT_MAX, + &lp8788_domain_ops, irqd); + if (!irqd->domain) { + dev_err(lp->dev, "failed to add irq domain err\n"); + return -EINVAL; + } + + lp->irqdm = irqd->domain; + mutex_init(&irqd->irq_lock); + + ret = request_threaded_irq(irq, NULL, lp8788_irq_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "lp8788-irq", irqd); + if (ret) { + dev_err(lp->dev, "failed to create a thread for IRQ_N\n"); + return ret; + } + + lp->irq = irq; + + return 0; +} + +void lp8788_irq_exit(struct lp8788 *lp) +{ + if (lp->irq) + free_irq(lp->irq, lp->irqdm); +} diff --git a/drivers/mfd/lp8788.c b/drivers/mfd/lp8788.c new file mode 100644 index 000000000000..3e94a699833c --- /dev/null +++ b/drivers/mfd/lp8788.c @@ -0,0 +1,245 @@ +/* + * TI LP8788 MFD - core interface + * + * Copyright 2012 Texas Instruments + * + * Author: Milo(Woogyom) Kim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include + +#define MAX_LP8788_REGISTERS 0xA2 + +#define MFD_DEV_SIMPLE(_name) \ +{ \ + .name = LP8788_DEV_##_name, \ +} + +#define MFD_DEV_WITH_ID(_name, _id) \ +{ \ + .name = LP8788_DEV_##_name, \ + .id = _id, \ +} + +#define MFD_DEV_WITH_RESOURCE(_name, _resource, num_resource) \ +{ \ + .name = LP8788_DEV_##_name, \ + .resources = _resource, \ + .num_resources = num_resource, \ +} + +static struct resource chg_irqs[] = { + /* Charger Interrupts */ + { + .start = LP8788_INT_CHG_INPUT_STATE, + .end = LP8788_INT_PRECHG_TIMEOUT, + .name = LP8788_CHG_IRQ, + .flags = IORESOURCE_IRQ, + }, + /* Power Routing Switch Interrupts */ + { + .start = LP8788_INT_ENTER_SYS_SUPPORT, + .end = LP8788_INT_EXIT_SYS_SUPPORT, + .name = LP8788_PRSW_IRQ, + .flags = IORESOURCE_IRQ, + }, + /* Battery Interrupts */ + { + .start = LP8788_INT_BATT_LOW, + .end = LP8788_INT_NO_BATT, + .name = LP8788_BATT_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource rtc_irqs[] = { + { + .start = LP8788_INT_RTC_ALARM1, + .end = LP8788_INT_RTC_ALARM2, + .name = LP8788_ALM_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct mfd_cell lp8788_devs[] = { + /* 4 bucks */ + MFD_DEV_WITH_ID(BUCK, 1), + MFD_DEV_WITH_ID(BUCK, 2), + MFD_DEV_WITH_ID(BUCK, 3), + MFD_DEV_WITH_ID(BUCK, 4), + + /* 12 digital ldos */ + MFD_DEV_WITH_ID(DLDO, 1), + MFD_DEV_WITH_ID(DLDO, 2), + MFD_DEV_WITH_ID(DLDO, 3), + MFD_DEV_WITH_ID(DLDO, 4), + MFD_DEV_WITH_ID(DLDO, 5), + MFD_DEV_WITH_ID(DLDO, 6), + MFD_DEV_WITH_ID(DLDO, 7), + MFD_DEV_WITH_ID(DLDO, 8), + MFD_DEV_WITH_ID(DLDO, 9), + MFD_DEV_WITH_ID(DLDO, 10), + MFD_DEV_WITH_ID(DLDO, 11), + MFD_DEV_WITH_ID(DLDO, 12), + + /* 10 analog ldos */ + MFD_DEV_WITH_ID(ALDO, 1), + MFD_DEV_WITH_ID(ALDO, 2), + MFD_DEV_WITH_ID(ALDO, 3), + MFD_DEV_WITH_ID(ALDO, 4), + MFD_DEV_WITH_ID(ALDO, 5), + MFD_DEV_WITH_ID(ALDO, 6), + MFD_DEV_WITH_ID(ALDO, 7), + MFD_DEV_WITH_ID(ALDO, 8), + MFD_DEV_WITH_ID(ALDO, 9), + MFD_DEV_WITH_ID(ALDO, 10), + + /* ADC */ + MFD_DEV_SIMPLE(ADC), + + /* battery charger */ + MFD_DEV_WITH_RESOURCE(CHARGER, chg_irqs, ARRAY_SIZE(chg_irqs)), + + /* rtc */ + MFD_DEV_WITH_RESOURCE(RTC, rtc_irqs, ARRAY_SIZE(rtc_irqs)), + + /* backlight */ + MFD_DEV_SIMPLE(BACKLIGHT), + + /* current sink for vibrator */ + MFD_DEV_SIMPLE(VIBRATOR), + + /* current sink for keypad LED */ + MFD_DEV_SIMPLE(KEYLED), +}; + +int lp8788_read_byte(struct lp8788 *lp, u8 reg, u8 *data) +{ + int ret; + unsigned int val; + + ret = regmap_read(lp->regmap, reg, &val); + if (ret < 0) { + dev_err(lp->dev, "failed to read 0x%.2x\n", reg); + return ret; + } + + *data = (u8)val; + return 0; +} +EXPORT_SYMBOL_GPL(lp8788_read_byte); + +int lp8788_read_multi_bytes(struct lp8788 *lp, u8 reg, u8 *data, size_t count) +{ + return regmap_bulk_read(lp->regmap, reg, data, count); +} +EXPORT_SYMBOL_GPL(lp8788_read_multi_bytes); + +int lp8788_write_byte(struct lp8788 *lp, u8 reg, u8 data) +{ + return regmap_write(lp->regmap, reg, data); +} +EXPORT_SYMBOL_GPL(lp8788_write_byte); + +int lp8788_update_bits(struct lp8788 *lp, u8 reg, u8 mask, u8 data) +{ + return regmap_update_bits(lp->regmap, reg, mask, data); +} +EXPORT_SYMBOL_GPL(lp8788_update_bits); + +static int lp8788_platform_init(struct lp8788 *lp) +{ + struct lp8788_platform_data *pdata = lp->pdata; + + return (pdata && pdata->init_func) ? pdata->init_func(lp) : 0; +} + +static const struct regmap_config lp8788_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MAX_LP8788_REGISTERS, +}; + +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; + int ret; + + lp = devm_kzalloc(&cl->dev, sizeof(struct lp8788), GFP_KERNEL); + if (!lp) + return -ENOMEM; + + lp->regmap = devm_regmap_init_i2c(cl, &lp8788_regmap_config); + if (IS_ERR(lp->regmap)) { + ret = PTR_ERR(lp->regmap); + dev_err(&cl->dev, "regmap init i2c err: %d\n", ret); + return ret; + } + + lp->pdata = pdata; + lp->dev = &cl->dev; + i2c_set_clientdata(cl, lp); + + ret = lp8788_platform_init(lp); + if (ret) + return ret; + + ret = lp8788_irq_init(lp, cl->irq); + if (ret) + return ret; + + return mfd_add_devices(lp->dev, -1, lp8788_devs, + ARRAY_SIZE(lp8788_devs), NULL, 0, NULL); +} + +static int __devexit lp8788_remove(struct i2c_client *cl) +{ + struct lp8788 *lp = i2c_get_clientdata(cl); + + mfd_remove_devices(lp->dev); + lp8788_irq_exit(lp); + return 0; +} + +static const struct i2c_device_id lp8788_ids[] = { + {"lp8788", 0}, + { } +}; +MODULE_DEVICE_TABLE(i2c, lp8788_ids); + +static struct i2c_driver lp8788_driver = { + .driver = { + .name = "lp8788", + .owner = THIS_MODULE, + }, + .probe = lp8788_probe, + .remove = __devexit_p(lp8788_remove), + .id_table = lp8788_ids, +}; + +static int __init lp8788_init(void) +{ + return i2c_add_driver(&lp8788_driver); +} +subsys_initcall(lp8788_init); + +static void __exit lp8788_exit(void) +{ + i2c_del_driver(&lp8788_driver); +} +module_exit(lp8788_exit); + +MODULE_DESCRIPTION("TI LP8788 MFD Driver"); +MODULE_AUTHOR("Milo Kim"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From 0f471916d4d03503cf6fb696f7c8baf12fec30b9 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Thu, 20 Sep 2012 16:10:46 +0200 Subject: mfd: Fix max8907 sparse warning This fixes: drivers/mfd/max8907.c:179:16: sparse: symbol 'max8907_pm_off' was not declared. Should it be static? Signed-off-by: Fengguang Wu Signed-off-by: Samuel Ortiz --- drivers/mfd/max8907.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/max8907.c b/drivers/mfd/max8907.c index 2303641dd052..17f2593d82b8 100644 --- a/drivers/mfd/max8907.c +++ b/drivers/mfd/max8907.c @@ -176,7 +176,7 @@ static const struct regmap_irq_chip max8907_rtc_irq_chip = { .num_irqs = ARRAY_SIZE(max8907_rtc_irqs), }; -struct max8907 *max8907_pm_off; +static struct max8907 *max8907_pm_off; static void max8907_power_off(void) { regmap_update_bits(max8907_pm_off->regmap_gen, MAX8907_REG_RESET_CNFG, -- cgit v1.2.2 From f3f1f0a1eac6fd1529d552b8e2a0e1ac07293c62 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 24 Sep 2012 09:11:46 +0100 Subject: mfd: Provide the PRCMU with its own IRQ domain The PRCMU has its own USB, Thermal, GPIO, Modem, HSI and RTC drivers, amongst other things. This patch allows those subordinate devices to use it as an interrupt controller as and when they are DT enabled. Signed-off-by: Lee Jones Acked-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/db8500-prcmu.c | 47 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 6fb11b76071e..bac4876d090f 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -270,6 +270,8 @@ static struct { struct prcmu_fw_version version; } fw_info; +static struct irq_domain *db8500_irq_domain; + /* * This vector maps irq numbers to the bits in the bit field used in * communication with the PRCMU firmware. @@ -2623,7 +2625,7 @@ static void prcmu_irq_mask(struct irq_data *d) spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags); - mb0_transfer.req.dbb_irqs &= ~prcmu_irq_bit[d->irq - IRQ_PRCMU_BASE]; + mb0_transfer.req.dbb_irqs &= ~prcmu_irq_bit[d->hwirq]; spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags); @@ -2637,7 +2639,7 @@ static void prcmu_irq_unmask(struct irq_data *d) spin_lock_irqsave(&mb0_transfer.dbb_irqs_lock, flags); - mb0_transfer.req.dbb_irqs |= prcmu_irq_bit[d->irq - IRQ_PRCMU_BASE]; + mb0_transfer.req.dbb_irqs |= prcmu_irq_bit[d->hwirq]; spin_unlock_irqrestore(&mb0_transfer.dbb_irqs_lock, flags); @@ -2677,9 +2679,37 @@ static char *fw_project_name(u8 project) } } +static int db8500_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler(virq, &prcmu_irq_chip, + handle_simple_irq); + set_irq_flags(virq, IRQF_VALID); + + return 0; +} + +static struct irq_domain_ops db8500_irq_ops = { + .map = db8500_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +static int db8500_irq_init(struct device_node *np) +{ + db8500_irq_domain = irq_domain_add_legacy( + np, NUM_PRCMU_WAKEUPS, IRQ_PRCMU_BASE, + 0, &db8500_irq_ops, NULL); + + if (!db8500_irq_domain) { + pr_err("Failed to create irqdomain\n"); + return -ENOSYS; + } + + return 0; +} + void __init db8500_prcmu_early_init(void) { - unsigned int i; if (cpu_is_u8500v2()) { void *tcpm_base = ioremap_nocache(U8500_PRCMU_TCPM_BASE, SZ_4K); @@ -2724,15 +2754,6 @@ void __init db8500_prcmu_early_init(void) INIT_WORK(&mb0_transfer.mask_work, prcmu_mask_work); - /* Initalize irqs. */ - for (i = 0; i < NUM_PRCMU_WAKEUPS; i++) { - unsigned int irq; - - irq = IRQ_PRCMU_BASE + i; - irq_set_chip_and_handler(irq, &prcmu_irq_chip, - handle_simple_irq); - set_irq_flags(irq, IRQF_VALID); - } compute_armss_rate(); } @@ -3040,6 +3061,8 @@ static int __devinit db8500_prcmu_probe(struct platform_device *pdev) goto no_irq_return; } + db8500_irq_init(np); + for (i = 0; i < ARRAY_SIZE(db8500_prcmu_devs); i++) { if (!strcmp(db8500_prcmu_devs[i].name, "ab8500-core")) { db8500_prcmu_devs[i].platform_data = ab8500_platdata; -- cgit v1.2.2 From b6290ffe1f4ed4d8521fd7e46738d42ddd9f1935 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Mon, 24 Sep 2012 22:25:34 +0200 Subject: mfd: Add backlight as subdevice to the tps65217 mfd: Add backlight as subdevice to the tps65217 Signed-off-by: Matthias Kaehlcke Signed-off-by: Samuel Ortiz --- drivers/mfd/tps65217.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index a95e9421b735..3fb32e655254 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -34,6 +34,9 @@ static struct mfd_cell tps65217s[] = { { .name = "tps65217-pmic", }, + { + .name = "tps65217-bl", + }, }; /** -- cgit v1.2.2 From eebfdc17cc6c9f184a713d84b84e7602236360c6 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Mon, 24 Sep 2012 22:25:28 +0200 Subject: backlight: Add TPS65217 WLED driver The TPS65217 chip contains a boost converter and current sinks which can be used to drive LEDs for use as backlights. Expose this functionality via the backlight API. Tested on an AM335x based custom board with a single WLED string, using different values for ISEL and FDIM (though it would be hard to tell the difference except for the value in WLEDCTRL1). Both instantiation through the device tree and by passing platform data have been tested. Testing has been done with an Androidized 3.2 kernel from the rowboat project. Koen Kooi reported the driver to be working on a Beaglebone board with LCD3 cape Signed-off-by: Matthias Kaehlcke Signed-off-by: Samuel Ortiz --- drivers/video/backlight/Kconfig | 7 + drivers/video/backlight/Makefile | 1 + drivers/video/backlight/tps65217_bl.c | 352 ++++++++++++++++++++++++++++++++++ 3 files changed, 360 insertions(+) create mode 100644 drivers/video/backlight/tps65217_bl.c (limited to 'drivers') diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index cf282763a8dc..63cee2e9d622 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -373,6 +373,13 @@ config BACKLIGHT_PANDORA If you have a Pandora console, say Y to enable the backlight driver. +config BACKLIGHT_TPS65217 + tristate "TPS65217 Backlight" + depends on BACKLIGHT_CLASS_DEVICE && MFD_TPS65217 + help + If you have a Texas Instruments TPS65217 say Y to enable the + backlight driver. + endif # BACKLIGHT_CLASS_DEVICE endif # BACKLIGHT_LCD_SUPPORT diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index a2ac9cfbaf6b..00223a62ec12 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -43,3 +43,4 @@ obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o obj-$(CONFIG_BACKLIGHT_AAT2870) += aat2870_bl.o obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o +obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c new file mode 100644 index 000000000000..6ac2ef5da32c --- /dev/null +++ b/drivers/video/backlight/tps65217_bl.c @@ -0,0 +1,352 @@ +/* + * tps65217_bl.c + * + * TPS65217 backlight driver + * + * Copyright (C) 2012 Matthias Kaehlcke + * Author: Matthias Kaehlcke + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct tps65217_bl { + struct tps65217 *tps; + struct device *dev; + struct backlight_device *bl; + bool is_enabled; +}; + +static int tps65217_bl_enable(struct tps65217_bl *tps65217_bl) +{ + int rc; + + rc = tps65217_set_bits(tps65217_bl->tps, TPS65217_REG_WLEDCTRL1, + TPS65217_WLEDCTRL1_ISINK_ENABLE, + TPS65217_WLEDCTRL1_ISINK_ENABLE, TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to enable backlight: %d\n", rc); + return rc; + } + + tps65217_bl->is_enabled = true; + + dev_dbg(tps65217_bl->dev, "backlight enabled\n"); + + return 0; +} + +static int tps65217_bl_disable(struct tps65217_bl *tps65217_bl) +{ + int rc; + + rc = tps65217_clear_bits(tps65217_bl->tps, + TPS65217_REG_WLEDCTRL1, + TPS65217_WLEDCTRL1_ISINK_ENABLE, + TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to disable backlight: %d\n", rc); + return rc; + } + + tps65217_bl->is_enabled = false; + + dev_dbg(tps65217_bl->dev, "backlight disabled\n"); + + return 0; +} + +static int tps65217_bl_update_status(struct backlight_device *bl) +{ + struct tps65217_bl *tps65217_bl = bl_get_data(bl); + int rc; + int brightness = bl->props.brightness; + + if (bl->props.state & BL_CORE_SUSPENDED) + brightness = 0; + + if ((bl->props.power != FB_BLANK_UNBLANK) || + (bl->props.fb_blank != FB_BLANK_UNBLANK)) + /* framebuffer in low power mode or blanking active */ + brightness = 0; + + if (brightness > 0) { + rc = tps65217_reg_write(tps65217_bl->tps, + TPS65217_REG_WLEDCTRL2, + brightness - 1, + TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to set brightness level: %d\n", rc); + return rc; + } + + dev_dbg(tps65217_bl->dev, "brightness set to %d\n", brightness); + + if (!tps65217_bl->is_enabled) + rc = tps65217_bl_enable(tps65217_bl); + } else { + rc = tps65217_bl_disable(tps65217_bl); + } + + return rc; +} + +static int tps65217_bl_get_brightness(struct backlight_device *bl) +{ + return bl->props.brightness; +} + +static const struct backlight_ops tps65217_bl_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = tps65217_bl_update_status, + .get_brightness = tps65217_bl_get_brightness +}; + +static int tps65217_bl_hw_init(struct tps65217_bl *tps65217_bl, + struct tps65217_bl_pdata *pdata) +{ + int rc; + + rc = tps65217_bl_disable(tps65217_bl); + if (rc) + return rc; + + switch (pdata->isel) { + case TPS65217_BL_ISET1: + /* select ISET_1 current level */ + rc = tps65217_clear_bits(tps65217_bl->tps, + TPS65217_REG_WLEDCTRL1, + TPS65217_WLEDCTRL1_ISEL, + TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to select ISET1 current level: %d)\n", + rc); + return rc; + } + + dev_dbg(tps65217_bl->dev, "selected ISET1 current level\n"); + + break; + + case TPS65217_BL_ISET2: + /* select ISET2 current level */ + rc = tps65217_set_bits(tps65217_bl->tps, TPS65217_REG_WLEDCTRL1, + TPS65217_WLEDCTRL1_ISEL, + TPS65217_WLEDCTRL1_ISEL, TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to select ISET2 current level: %d\n", + rc); + return rc; + } + + dev_dbg(tps65217_bl->dev, "selected ISET2 current level\n"); + + break; + + default: + dev_err(tps65217_bl->dev, + "invalid value for current level: %d\n", pdata->isel); + return -EINVAL; + } + + /* set PWM frequency */ + rc = tps65217_set_bits(tps65217_bl->tps, + TPS65217_REG_WLEDCTRL1, + TPS65217_WLEDCTRL1_FDIM_MASK, + pdata->fdim, + TPS65217_PROTECT_NONE); + if (rc) { + dev_err(tps65217_bl->dev, + "failed to select PWM dimming frequency: %d\n", + rc); + return rc; + } + + return 0; +} + +#ifdef CONFIG_OF +static struct tps65217_bl_pdata * +tps65217_bl_parse_dt(struct platform_device *pdev) +{ + struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); + struct device_node *node = of_node_get(tps->dev->of_node); + struct tps65217_bl_pdata *pdata, *err; + u32 val; + + node = of_find_node_by_name(node, "backlight"); + if (!node) + return ERR_PTR(-ENODEV); + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, "failed to allocate platform data\n"); + err = ERR_PTR(-ENOMEM); + goto err; + } + + pdata->isel = TPS65217_BL_ISET1; + if (!of_property_read_u32(node, "isel", &val)) { + if (val < TPS65217_BL_ISET1 || + val > TPS65217_BL_ISET2) { + dev_err(&pdev->dev, + "invalid 'isel' value in the device tree\n"); + err = ERR_PTR(-EINVAL); + goto err; + } + + pdata->isel = val; + } + + pdata->fdim = TPS65217_BL_FDIM_200HZ; + if (!of_property_read_u32(node, "fdim", &val)) { + switch (val) { + case 100: + pdata->fdim = TPS65217_BL_FDIM_100HZ; + break; + + case 200: + pdata->fdim = TPS65217_BL_FDIM_200HZ; + break; + + case 500: + pdata->fdim = TPS65217_BL_FDIM_500HZ; + break; + + case 1000: + pdata->fdim = TPS65217_BL_FDIM_1000HZ; + break; + + default: + dev_err(&pdev->dev, + "invalid 'fdim' value in the device tree\n"); + err = ERR_PTR(-EINVAL); + goto err; + } + } + + of_node_put(node); + + return pdata; + +err: + of_node_put(node); + + return err; +} +#else +static struct tps65217_bl_pdata * +tps65217_bl_parse_dt(struct platform_device *pdev) +{ + return NULL; +} +#endif + +static int tps65217_bl_probe(struct platform_device *pdev) +{ + int rc; + struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); + struct tps65217_bl *tps65217_bl; + struct tps65217_bl_pdata *pdata; + struct backlight_properties bl_props; + + if (tps->dev->of_node) { + pdata = tps65217_bl_parse_dt(pdev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + } else { + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "no platform data provided\n"); + return -EINVAL; + } + + pdata = pdev->dev.platform_data; + } + + tps65217_bl = devm_kzalloc(&pdev->dev, sizeof(*tps65217_bl), + GFP_KERNEL); + if (tps65217_bl == NULL) { + dev_err(&pdev->dev, "allocation of struct tps65217_bl failed\n"); + return -ENOMEM; + } + + tps65217_bl->tps = tps; + tps65217_bl->dev = &pdev->dev; + tps65217_bl->is_enabled = false; + + rc = tps65217_bl_hw_init(tps65217_bl, pdata); + if (rc) + return rc; + + memset(&bl_props, 0, sizeof(struct backlight_properties)); + bl_props.type = BACKLIGHT_RAW; + bl_props.max_brightness = 100; + + tps65217_bl->bl = backlight_device_register(pdev->name, + tps65217_bl->dev, tps65217_bl, + &tps65217_bl_ops, &bl_props); + if (IS_ERR(tps65217_bl->bl)) { + dev_err(tps65217_bl->dev, + "registration of backlight device failed: %d\n", rc); + return PTR_ERR(tps65217_bl->bl); + } + + tps65217_bl->bl->props.brightness = 0; + + return 0; +} + +static int tps65217_bl_remove(struct platform_device *pdev) +{ + struct tps65217_bl *tps65217_bl = platform_get_drvdata(pdev); + + backlight_device_unregister(tps65217_bl->bl); + + return 0; +} + +static struct platform_driver tps65217_bl_driver = { + .probe = tps65217_bl_probe, + .remove = tps65217_bl_remove, + .driver = { + .owner = THIS_MODULE, + .name = "tps65217-bl", + }, +}; + +static int __init tps65217_bl_init(void) +{ + return platform_driver_register(&tps65217_bl_driver); +} + +static void __exit tps65217_bl_exit(void) +{ + platform_driver_unregister(&tps65217_bl_driver); +} + +module_init(tps65217_bl_init); +module_exit(tps65217_bl_exit); + +MODULE_DESCRIPTION("TPS65217 Backlight driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Matthias Kaehlcke "); -- cgit v1.2.2 From 46ae368bfc526a53ce9e516e3af051b2d7a7c24d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 26 Sep 2012 18:00:28 +0100 Subject: mfd: wm5110: Disable control interface error report for WM5110 rev B It can misreport. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/arizona-irq.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index f7886c8269bc..ef0f2d001df2 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -192,6 +192,7 @@ int arizona_irq_init(struct arizona *arizona) switch (arizona->rev) { case 0: + case 1: ctrlif_error = false; break; default: -- cgit v1.2.2 From da58deec69777c22ece2ef871054c0d3d04e3e63 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 26 Sep 2012 18:00:29 +0100 Subject: mfd: wm5110: Add register patches for revision B Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm5110-tables.c | 96 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index bd8782c8896b..adda6b10b90d 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -133,15 +133,109 @@ static const struct reg_default wm5110_reva_patch[] = { { 0x209, 0x002A }, }; +static const struct reg_default wm5110_revb_patch[] = { + { 0x80, 0x3 }, + { 0x36e, 0x0210 }, + { 0x370, 0x0210 }, + { 0x372, 0x0210 }, + { 0x374, 0x0210 }, + { 0x376, 0x0210 }, + { 0x378, 0x0210 }, + { 0x36d, 0x0028 }, + { 0x36f, 0x0028 }, + { 0x371, 0x0028 }, + { 0x373, 0x0028 }, + { 0x375, 0x0028 }, + { 0x377, 0x0028 }, + { 0x280, 0x2002 }, + { 0x44, 0x20 }, + { 0x45, 0x40 }, + { 0x46, 0x60 }, + { 0x47, 0x80 }, + { 0x48, 0xa0 }, + { 0x51, 0x13 }, + { 0x52, 0x33 }, + { 0x53, 0x53 }, + { 0x54, 0x73 }, + { 0x55, 0x93 }, + { 0x56, 0xb3 }, + { 0xc30, 0x3e3e }, + { 0xc31, 0x3e }, + { 0xc32, 0x3e3e }, + { 0xc33, 0x3e3e }, + { 0xc34, 0x3e3e }, + { 0xc35, 0x3e3e }, + { 0xc36, 0x3e3e }, + { 0xc37, 0x3e3e }, + { 0xc38, 0x3e3e }, + { 0xc39, 0x3e3e }, + { 0xc3a, 0x3e3e }, + { 0xc3b, 0x3e3e }, + { 0xc3c, 0x3e }, + { 0x201, 0x18a5 }, + { 0x202, 0x4100 }, + { 0x460, 0x0c40 }, + { 0x461, 0x8000 }, + { 0x462, 0x0c41 }, + { 0x463, 0x4820 }, + { 0x464, 0x0c41 }, + { 0x465, 0x4040 }, + { 0x466, 0x0841 }, + { 0x467, 0x3940 }, + { 0x468, 0x0841 }, + { 0x469, 0x2030 }, + { 0x46a, 0x0842 }, + { 0x46b, 0x1990 }, + { 0x46c, 0x08c2 }, + { 0x46d, 0x1450 }, + { 0x46e, 0x08c6 }, + { 0x46f, 0x1020 }, + { 0x470, 0x08c6 }, + { 0x471, 0x0cd0 }, + { 0x472, 0x08c6 }, + { 0x473, 0x0a30 }, + { 0x474, 0x0442 }, + { 0x475, 0x0660 }, + { 0x476, 0x0446 }, + { 0x477, 0x0510 }, + { 0x478, 0x04c6 }, + { 0x479, 0x0400 }, + { 0x47a, 0x04ce }, + { 0x47b, 0x0330 }, + { 0x47c, 0x05df }, + { 0x47d, 0x0001 }, + { 0x47e, 0x07ff }, + { 0x2db, 0x0a00 }, + { 0x2dd, 0x0023 }, + { 0x2df, 0x0102 }, + { 0x2ef, 0x924 }, + { 0x2f0, 0x924 }, + { 0x2f1, 0x924 }, + { 0x2f2, 0x924 }, + { 0x2f3, 0x924 }, + { 0x2f4, 0x924 }, + { 0x2eb, 0x60 }, + { 0x2ec, 0x60 }, + { 0x2ed, 0x60 }, + { 0x4f2, 0x33e }, + { 0x458, 0x0000 }, + { 0x15a, 0x0003 }, + { 0x80, 0x0 }, +}; + /* We use a function so we can use ARRAY_SIZE() */ int wm5110_patch(struct arizona *arizona) { switch (arizona->rev) { case 0: - case 1: return regmap_register_patch(arizona->regmap, wm5110_reva_patch, ARRAY_SIZE(wm5110_reva_patch)); + case 1: + return regmap_register_patch(arizona->regmap, + wm5110_revb_patch, + ARRAY_SIZE(wm5110_revb_patch)); + default: return 0; } -- cgit v1.2.2 From 5863eabb2a317ef499d340aa7201233a4fc9211e Mon Sep 17 00:00:00 2001 From: Venu Byravarasu Date: Fri, 21 Sep 2012 16:25:36 +0530 Subject: mfd: tps65910: Add alarm interrupt of TPS65910 RTC to mfd device list Add RTC alarm interrupt details to TPS65910 MFD device list, to support RTC alarm events. Signed-off-by: Venu Byravarasu Signed-off-by: Samuel Ortiz --- drivers/mfd/tps65910.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index ca902943cfa9..0d79ce2b5014 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -24,6 +24,14 @@ #include #include +static struct resource rtc_resources[] = { + { + .start = TPS65910_IRQ_RTC_ALARM, + .end = TPS65910_IRQ_RTC_ALARM, + .flags = IORESOURCE_IRQ, + } +}; + static struct mfd_cell tps65910s[] = { { .name = "tps65910-gpio", @@ -33,6 +41,8 @@ static struct mfd_cell tps65910s[] = { }, { .name = "tps65910-rtc", + .num_resources = ARRAY_SIZE(rtc_resources), + .resources = &rtc_resources[0], }, { .name = "tps65910-power", -- cgit v1.2.2 From 2896434cf272acace1b7093d5e4ba8022ed11ac8 Mon Sep 17 00:00:00 2001 From: Ashish Jangam Date: Fri, 14 Sep 2012 18:54:50 +0530 Subject: mfd: DA9055 core driver This is the DA9055 MFD core driver that instantiate all the dependent component drivers and provides them the device access via I2C. This patch is functionally tested on Samsung SMDK6410. Signed-off-by: David Dajun Chen Signed-off-by: Ashish Jangam Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 17 ++ drivers/mfd/Makefile | 3 + drivers/mfd/da9055-core.c | 423 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/mfd/da9055-i2c.c | 93 ++++++++++ 4 files changed, 536 insertions(+) create mode 100644 drivers/mfd/da9055-core.c create mode 100644 drivers/mfd/da9055-i2c.c (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 84d6ea2d74f4..6bfa2a1ec9df 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -430,6 +430,23 @@ config MFD_DA9052_I2C for accessing the device, additional drivers must be enabled in order to use the functionality of the device. +config MFD_DA9055 + bool "Dialog Semiconductor DA9055 PMIC Support" + select REGMAP_I2C + select REGMAP_IRQ + select PMIC_DA9055 + select MFD_CORE + depends on I2C=y + help + Say yes here for support of Dialog Semiconductor DA9055. This is + a Power Management IC. This driver provides common support for + accessing the device as well as the I2C interface to the chip itself. + Additional drivers must be enabled in order to use the functionality + of the device. + + This driver can be built as a module. If built as a module it will be + called "da9055" + config PMIC_ADP5520 bool "Analog Devices ADP5520/01 MFD PMIC Core Support" depends on I2C=y diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 083acf97af26..33c0e49f7e60 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -91,6 +91,9 @@ obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o +da9055-objs := da9055-core.o da9055-i2c.o +obj-$(CONFIG_MFD_DA9055) += da9055.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/da9055-core.c b/drivers/mfd/da9055-core.c new file mode 100644 index 000000000000..ff6c77f392bd --- /dev/null +++ b/drivers/mfd/da9055-core.c @@ -0,0 +1,423 @@ +/* + * Device access for Dialog DA9055 PMICs. + * + * Copyright(c) 2012 Dialog Semiconductor Ltd. + * + * Author: David Dajun Chen + * + * 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 + +#define DA9055_IRQ_NONKEY_MASK 0x01 +#define DA9055_IRQ_ALM_MASK 0x02 +#define DA9055_IRQ_TICK_MASK 0x04 +#define DA9055_IRQ_ADC_MASK 0x08 +#define DA9055_IRQ_BUCK_ILIM_MASK 0x08 + +static bool da9055_register_readable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case DA9055_REG_STATUS_A: + case DA9055_REG_STATUS_B: + case DA9055_REG_EVENT_A: + case DA9055_REG_EVENT_B: + case DA9055_REG_EVENT_C: + case DA9055_REG_IRQ_MASK_A: + case DA9055_REG_IRQ_MASK_B: + case DA9055_REG_IRQ_MASK_C: + + case DA9055_REG_CONTROL_A: + case DA9055_REG_CONTROL_B: + case DA9055_REG_CONTROL_C: + case DA9055_REG_CONTROL_D: + case DA9055_REG_CONTROL_E: + + case DA9055_REG_ADC_MAN: + case DA9055_REG_ADC_CONT: + case DA9055_REG_VSYS_MON: + case DA9055_REG_ADC_RES_L: + case DA9055_REG_ADC_RES_H: + case DA9055_REG_VSYS_RES: + case DA9055_REG_ADCIN1_RES: + case DA9055_REG_ADCIN2_RES: + case DA9055_REG_ADCIN3_RES: + + case DA9055_REG_COUNT_S: + case DA9055_REG_COUNT_MI: + case DA9055_REG_COUNT_H: + case DA9055_REG_COUNT_D: + case DA9055_REG_COUNT_MO: + case DA9055_REG_COUNT_Y: + case DA9055_REG_ALARM_H: + case DA9055_REG_ALARM_D: + case DA9055_REG_ALARM_MI: + case DA9055_REG_ALARM_MO: + case DA9055_REG_ALARM_Y: + + case DA9055_REG_GPIO0_1: + case DA9055_REG_GPIO2: + case DA9055_REG_GPIO_MODE0_2: + + case DA9055_REG_BCORE_CONT: + case DA9055_REG_BMEM_CONT: + case DA9055_REG_LDO1_CONT: + case DA9055_REG_LDO2_CONT: + case DA9055_REG_LDO3_CONT: + case DA9055_REG_LDO4_CONT: + case DA9055_REG_LDO5_CONT: + case DA9055_REG_LDO6_CONT: + case DA9055_REG_BUCK_LIM: + case DA9055_REG_BCORE_MODE: + case DA9055_REG_VBCORE_A: + case DA9055_REG_VBMEM_A: + case DA9055_REG_VLDO1_A: + case DA9055_REG_VLDO2_A: + case DA9055_REG_VLDO3_A: + case DA9055_REG_VLDO4_A: + case DA9055_REG_VLDO5_A: + case DA9055_REG_VLDO6_A: + case DA9055_REG_VBCORE_B: + case DA9055_REG_VBMEM_B: + case DA9055_REG_VLDO1_B: + case DA9055_REG_VLDO2_B: + case DA9055_REG_VLDO3_B: + case DA9055_REG_VLDO4_B: + case DA9055_REG_VLDO5_B: + case DA9055_REG_VLDO6_B: + return true; + default: + return false; + } +} + +static bool da9055_register_writeable(struct device *dev, unsigned int reg) +{ + switch (reg) { + case DA9055_REG_STATUS_A: + case DA9055_REG_STATUS_B: + case DA9055_REG_EVENT_A: + case DA9055_REG_EVENT_B: + case DA9055_REG_EVENT_C: + case DA9055_REG_IRQ_MASK_A: + case DA9055_REG_IRQ_MASK_B: + case DA9055_REG_IRQ_MASK_C: + + case DA9055_REG_CONTROL_A: + case DA9055_REG_CONTROL_B: + case DA9055_REG_CONTROL_C: + case DA9055_REG_CONTROL_D: + case DA9055_REG_CONTROL_E: + + case DA9055_REG_ADC_MAN: + case DA9055_REG_ADC_CONT: + case DA9055_REG_VSYS_MON: + case DA9055_REG_ADC_RES_L: + case DA9055_REG_ADC_RES_H: + case DA9055_REG_VSYS_RES: + case DA9055_REG_ADCIN1_RES: + case DA9055_REG_ADCIN2_RES: + case DA9055_REG_ADCIN3_RES: + + case DA9055_REG_COUNT_S: + case DA9055_REG_COUNT_MI: + case DA9055_REG_COUNT_H: + case DA9055_REG_COUNT_D: + case DA9055_REG_COUNT_MO: + case DA9055_REG_COUNT_Y: + case DA9055_REG_ALARM_H: + case DA9055_REG_ALARM_D: + case DA9055_REG_ALARM_MI: + case DA9055_REG_ALARM_MO: + case DA9055_REG_ALARM_Y: + + case DA9055_REG_GPIO0_1: + case DA9055_REG_GPIO2: + case DA9055_REG_GPIO_MODE0_2: + + case DA9055_REG_BCORE_CONT: + case DA9055_REG_BMEM_CONT: + case DA9055_REG_LDO1_CONT: + case DA9055_REG_LDO2_CONT: + case DA9055_REG_LDO3_CONT: + case DA9055_REG_LDO4_CONT: + case DA9055_REG_LDO5_CONT: + case DA9055_REG_LDO6_CONT: + case DA9055_REG_BUCK_LIM: + case DA9055_REG_BCORE_MODE: + case DA9055_REG_VBCORE_A: + case DA9055_REG_VBMEM_A: + case DA9055_REG_VLDO1_A: + case DA9055_REG_VLDO2_A: + case DA9055_REG_VLDO3_A: + case DA9055_REG_VLDO4_A: + case DA9055_REG_VLDO5_A: + case DA9055_REG_VLDO6_A: + case DA9055_REG_VBCORE_B: + case DA9055_REG_VBMEM_B: + case DA9055_REG_VLDO1_B: + case DA9055_REG_VLDO2_B: + case DA9055_REG_VLDO3_B: + case DA9055_REG_VLDO4_B: + case DA9055_REG_VLDO5_B: + case DA9055_REG_VLDO6_B: + return true; + default: + return false; + } +} + +static bool da9055_register_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case DA9055_REG_STATUS_A: + case DA9055_REG_STATUS_B: + case DA9055_REG_EVENT_A: + case DA9055_REG_EVENT_B: + case DA9055_REG_EVENT_C: + + case DA9055_REG_CONTROL_A: + case DA9055_REG_CONTROL_E: + + case DA9055_REG_ADC_MAN: + case DA9055_REG_ADC_RES_L: + case DA9055_REG_ADC_RES_H: + case DA9055_REG_VSYS_RES: + case DA9055_REG_ADCIN1_RES: + case DA9055_REG_ADCIN2_RES: + case DA9055_REG_ADCIN3_RES: + + case DA9055_REG_COUNT_S: + case DA9055_REG_COUNT_MI: + case DA9055_REG_COUNT_H: + case DA9055_REG_COUNT_D: + case DA9055_REG_COUNT_MO: + case DA9055_REG_COUNT_Y: + case DA9055_REG_ALARM_MI: + + case DA9055_REG_BCORE_CONT: + case DA9055_REG_BMEM_CONT: + case DA9055_REG_LDO1_CONT: + case DA9055_REG_LDO2_CONT: + case DA9055_REG_LDO3_CONT: + case DA9055_REG_LDO4_CONT: + case DA9055_REG_LDO5_CONT: + case DA9055_REG_LDO6_CONT: + return true; + default: + return false; + } +} + +static struct regmap_irq da9055_irqs[] = { + [DA9055_IRQ_NONKEY] = { + .reg_offset = 0, + .mask = DA9055_IRQ_NONKEY_MASK, + }, + [DA9055_IRQ_ALARM] = { + .reg_offset = 0, + .mask = DA9055_IRQ_ALM_MASK, + }, + [DA9055_IRQ_TICK] = { + .reg_offset = 0, + .mask = DA9055_IRQ_TICK_MASK, + }, + [DA9055_IRQ_HWMON] = { + .reg_offset = 0, + .mask = DA9055_IRQ_ADC_MASK, + }, + [DA9055_IRQ_REGULATOR] = { + .reg_offset = 1, + .mask = DA9055_IRQ_BUCK_ILIM_MASK, + }, +}; + +struct regmap_config da9055_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .cache_type = REGCACHE_RBTREE, + + .max_register = DA9055_MAX_REGISTER_CNT, + .readable_reg = da9055_register_readable, + .writeable_reg = da9055_register_writeable, + .volatile_reg = da9055_register_volatile, +}; +EXPORT_SYMBOL_GPL(da9055_regmap_config); + +static struct resource da9055_onkey_resource = { + .name = "ONKEY", + .start = DA9055_IRQ_NONKEY, + .end = DA9055_IRQ_NONKEY, + .flags = IORESOURCE_IRQ, +}; + +static struct resource da9055_rtc_resource[] = { + { + .name = "ALM", + .start = DA9055_IRQ_ALARM, + .end = DA9055_IRQ_ALARM, + .flags = IORESOURCE_IRQ, + }, + { + .name = "TICK", + .start = DA9055_IRQ_TICK, + .end = DA9055_IRQ_TICK, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource da9055_hwmon_resource = { + .name = "HWMON", + .start = DA9055_IRQ_HWMON, + .end = DA9055_IRQ_HWMON, + .flags = IORESOURCE_IRQ, +}; + +static struct resource da9055_ld05_6_resource = { + .name = "REGULATOR", + .start = DA9055_IRQ_REGULATOR, + .end = DA9055_IRQ_REGULATOR, + .flags = IORESOURCE_IRQ, +}; + +static struct mfd_cell da9055_devs[] = { + { + .of_compatible = "dialog,da9055-gpio", + .name = "da9055-gpio", + }, + { + .of_compatible = "dialog,da9055-regulator", + .name = "da9055-regulator", + .id = 1, + }, + { + .of_compatible = "dialog,da9055-regulator", + .name = "da9055-regulator", + .id = 2, + }, + { + .of_compatible = "dialog,da9055-regulator", + .name = "da9055-regulator", + .id = 3, + }, + { + .of_compatible = "dialog,da9055-regulator", + .name = "da9055-regulator", + .id = 4, + }, + { + .of_compatible = "dialog,da9055-regulator", + .name = "da9055-regulator", + .id = 5, + }, + { + .of_compatible = "dialog,da9055-regulator", + .name = "da9055-regulator", + .id = 6, + }, + { + .of_compatible = "dialog,da9055-regulator", + .name = "da9055-regulator", + .id = 7, + .resources = &da9055_ld05_6_resource, + .num_resources = 1, + }, + { + .of_compatible = "dialog,da9055-regulator", + .name = "da9055-regulator", + .resources = &da9055_ld05_6_resource, + .num_resources = 1, + .id = 8, + }, + { + .of_compatible = "dialog,da9055-onkey", + .name = "da9055-onkey", + .resources = &da9055_onkey_resource, + .num_resources = 1, + }, + { + .of_compatible = "dialog,da9055-rtc", + .name = "da9055-rtc", + .resources = da9055_rtc_resource, + .num_resources = ARRAY_SIZE(da9055_rtc_resource), + }, + { + .of_compatible = "dialog,da9055-hwmon", + .name = "da9055-hwmon", + .resources = &da9055_hwmon_resource, + .num_resources = 1, + }, + { + .of_compatible = "dialog,da9055-watchdog", + .name = "da9055-watchdog", + }, +}; + +static struct regmap_irq_chip da9055_regmap_irq_chip = { + .name = "da9055_irq", + .status_base = DA9055_REG_EVENT_A, + .mask_base = DA9055_REG_IRQ_MASK_A, + .ack_base = DA9055_REG_EVENT_A, + .num_regs = 3, + .irqs = da9055_irqs, + .num_irqs = ARRAY_SIZE(da9055_irqs), +}; + +int __devinit da9055_device_init(struct da9055 *da9055) +{ + struct da9055_pdata *pdata = da9055->dev->platform_data; + int ret; + + if (pdata && pdata->init != NULL) + pdata->init(da9055); + + if (!pdata || !pdata->irq_base) + da9055->irq_base = -1; + else + da9055->irq_base = pdata->irq_base; + + ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + da9055->irq_base, &da9055_regmap_irq_chip, + &da9055->irq_data); + if (ret < 0) + return ret; + + da9055->irq_base = regmap_irq_chip_get_base(da9055->irq_data); + + ret = mfd_add_devices(da9055->dev, -1, + da9055_devs, ARRAY_SIZE(da9055_devs), + NULL, da9055->irq_base, NULL); + if (ret) + goto err; + + return 0; + +err: + mfd_remove_devices(da9055->dev); + return ret; +} + +void __devexit da9055_device_exit(struct da9055 *da9055) +{ + regmap_del_irq_chip(da9055->chip_irq, da9055->irq_data); + mfd_remove_devices(da9055->dev); +} + +MODULE_DESCRIPTION("Core support for the DA9055 PMIC"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Dajun Chen "); diff --git a/drivers/mfd/da9055-i2c.c b/drivers/mfd/da9055-i2c.c new file mode 100644 index 000000000000..88f6dca53bac --- /dev/null +++ b/drivers/mfd/da9055-i2c.c @@ -0,0 +1,93 @@ + /* I2C access for DA9055 PMICs. + * + * Copyright(c) 2012 Dialog Semiconductor Ltd. + * + * Author: David Dajun Chen + * + * 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 + +static int __devinit da9055_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct da9055 *da9055; + int ret; + + da9055 = devm_kzalloc(&i2c->dev, sizeof(struct da9055), GFP_KERNEL); + if (!da9055) + return -ENOMEM; + + da9055->regmap = devm_regmap_init_i2c(i2c, &da9055_regmap_config); + if (IS_ERR(da9055->regmap)) { + ret = PTR_ERR(da9055->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + da9055->dev = &i2c->dev; + da9055->chip_irq = i2c->irq; + + i2c_set_clientdata(i2c, da9055); + + return da9055_device_init(da9055); +} + +static int __devexit da9055_i2c_remove(struct i2c_client *i2c) +{ + struct da9055 *da9055 = i2c_get_clientdata(i2c); + + da9055_device_exit(da9055); + + return 0; +} + +static struct i2c_device_id da9055_i2c_id[] = { + {"da9055-pmic", 0}, + { } +}; + +static struct i2c_driver da9055_i2c_driver = { + .probe = da9055_i2c_probe, + .remove = __devexit_p(da9055_i2c_remove), + .id_table = da9055_i2c_id, + .driver = { + .name = "da9055", + .owner = THIS_MODULE, + }, +}; + +static int __init da9055_i2c_init(void) +{ + int ret; + + ret = i2c_add_driver(&da9055_i2c_driver); + if (ret != 0) { + pr_err("DA9055 I2C registration failed %d\n", ret); + return ret; + } + + return 0; +} +subsys_initcall(da9055_i2c_init); + +static void __exit da9055_i2c_exit(void) +{ + i2c_del_driver(&da9055_i2c_driver); +} +module_exit(da9055_i2c_exit); + +MODULE_AUTHOR("David Dajun Chen "); +MODULE_DESCRIPTION("I2C driver for Dialog DA9055 PMIC"); +MODULE_LICENSE("GPL"); -- cgit v1.2.2 From c6bed9deb6047179a6c58ace847f8b2129085e37 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 30 Sep 2012 18:28:26 +0800 Subject: backlight: tps65217_bl: Add missing platform_set_drvdata in tps65217_bl_probe Otherwise, we got NULL derefernce while calling backlight_device_unregister() in tps65217_bl_remove(). Also convert to use module_platform_driver. Signed-off-by: Axel Lin Signed-off-by: Samuel Ortiz --- drivers/video/backlight/tps65217_bl.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c index 6ac2ef5da32c..70881633b45a 100644 --- a/drivers/video/backlight/tps65217_bl.c +++ b/drivers/video/backlight/tps65217_bl.c @@ -312,6 +312,7 @@ static int tps65217_bl_probe(struct platform_device *pdev) } tps65217_bl->bl->props.brightness = 0; + platform_set_drvdata(pdev, tps65217_bl); return 0; } @@ -334,18 +335,7 @@ static struct platform_driver tps65217_bl_driver = { }, }; -static int __init tps65217_bl_init(void) -{ - return platform_driver_register(&tps65217_bl_driver); -} - -static void __exit tps65217_bl_exit(void) -{ - platform_driver_unregister(&tps65217_bl_driver); -} - -module_init(tps65217_bl_init); -module_exit(tps65217_bl_exit); +module_platform_driver(tps65217_bl_driver); MODULE_DESCRIPTION("TPS65217 Backlight driver"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.2 From 8284328cd98b9ac9eebf646e6fcb9047bc12bf55 Mon Sep 17 00:00:00 2001 From: Sourav Poddar Date: Mon, 1 Oct 2012 16:31:22 +0530 Subject: mfd: smsc: Add support for smsc gpio io/keypad driver smsc ece1099 is a keyboard scan or gpio expansion device. The patch create keypad and gpio expander child for this multi function smsc driver. Cc: Benoit Cousson Cc: Felipe Balbi Cc: Santosh Shilimkar Signed-off-by: Sourav Poddar Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 12 +++++ drivers/mfd/Makefile | 1 + drivers/mfd/smsc-ece1099.c | 113 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 drivers/mfd/smsc-ece1099.c (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 6bfa2a1ec9df..ae511b738441 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -375,6 +375,18 @@ config MFD_T7L66XB help Support for Toshiba Mobile IO Controller T7L66XB +config MFD_SMSC + bool "Support for the SMSC ECE1099 series chips" + depends on I2C=y + select MFD_CORE + select REGMAP_I2C + help + If you say yes here you get support for the + ece1099 chips from SMSC. + + To compile this driver as a module, choose M here: the + module will be called smsc. + config MFD_TC6387XB bool "Support Toshiba TC6387XB" depends on ARM && HAVE_CLK diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 33c0e49f7e60..d8ccb630ddb0 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -76,6 +76,7 @@ obj-$(CONFIG_EZX_PCAP) += ezx-pcap.o obj-$(CONFIG_MCP) += mcp-core.o obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o +obj-$(CONFIG_MFD_SMSC) += smsc-ece1099.o obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o ifeq ($(CONFIG_SA1100_ASSABET),y) diff --git a/drivers/mfd/smsc-ece1099.c b/drivers/mfd/smsc-ece1099.c new file mode 100644 index 000000000000..24ae3d8421c5 --- /dev/null +++ b/drivers/mfd/smsc-ece1099.c @@ -0,0 +1,113 @@ +/* + * TI SMSC MFD Driver + * + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com + * + * Author: Sourav Poddar + * + * 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; GPL v2. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct regmap_config smsc_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = SMSC_VEN_ID_H, + .cache_type = REGCACHE_RBTREE, +}; + +static int smsc_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct smsc *smsc; + int devid, rev, venid_l, venid_h; + int ret = 0; + + smsc = devm_kzalloc(&i2c->dev, sizeof(struct smsc), + GFP_KERNEL); + if (!smsc) { + dev_err(&i2c->dev, "smsc mfd driver memory allocation failed\n"); + return -ENOMEM; + } + + smsc->regmap = devm_regmap_init_i2c(i2c, &smsc_regmap_config); + if (IS_ERR(smsc->regmap)) { + ret = PTR_ERR(smsc->regmap); + goto err; + } + + i2c_set_clientdata(i2c, smsc); + smsc->dev = &i2c->dev; + +#ifdef CONFIG_OF + of_property_read_u32(i2c->dev.of_node, "clock", &smsc->clk); +#endif + + regmap_read(smsc->regmap, SMSC_DEV_ID, &devid); + regmap_read(smsc->regmap, SMSC_DEV_REV, &rev); + regmap_read(smsc->regmap, SMSC_VEN_ID_L, &venid_l); + regmap_read(smsc->regmap, SMSC_VEN_ID_H, &venid_h); + + dev_info(&i2c->dev, "SMSCxxx devid: %02x rev: %02x venid: %02x\n", + devid, rev, (venid_h << 8) | venid_l); + + ret = regmap_write(smsc->regmap, SMSC_CLK_CTRL, smsc->clk); + if (ret) + goto err; + +#ifdef CONFIG_OF + if (i2c->dev.of_node) + ret = of_platform_populate(i2c->dev.of_node, + NULL, NULL, &i2c->dev); +#endif + +err: + return ret; +} + +static int smsc_i2c_remove(struct i2c_client *i2c) +{ + struct smsc *smsc = i2c_get_clientdata(i2c); + + mfd_remove_devices(smsc->dev); + + return 0; +} + +static const struct i2c_device_id smsc_i2c_id[] = { + { "smscece1099", 0}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, smsc_i2c_id); + +static struct i2c_driver smsc_i2c_driver = { + .driver = { + .name = "smsc", + .owner = THIS_MODULE, + }, + .probe = smsc_i2c_probe, + .remove = smsc_i2c_remove, + .id_table = smsc_i2c_id, +}; + +module_i2c_driver(smsc_i2c_driver); + +MODULE_AUTHOR("Sourav Poddar "); +MODULE_DESCRIPTION("SMSC chip multi-function driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.2 From 837c8293ba24d08cd7438d82ad9bb8d2fb0f8a5b Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Tue, 2 Oct 2012 10:23:20 +0800 Subject: mfd: 88pm860x: Use irqdomain Use irqdomain and allocating interrupts. It's necessary for supporting DT mode. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-core.c | 65 ++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 72bf290bd020..5b56fe8250b4 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -520,15 +521,12 @@ static void pm860x_irq_sync_unlock(struct irq_data *data) static void pm860x_irq_enable(struct irq_data *data) { - struct pm860x_chip *chip = irq_data_get_irq_chip_data(data); - pm860x_irqs[data->irq - chip->irq_base].enable - = pm860x_irqs[data->irq - chip->irq_base].offs; + pm860x_irqs[data->hwirq].enable = pm860x_irqs[data->hwirq].offs; } static void pm860x_irq_disable(struct irq_data *data) { - struct pm860x_chip *chip = irq_data_get_irq_chip_data(data); - pm860x_irqs[data->irq - chip->irq_base].enable = 0; + pm860x_irqs[data->hwirq].enable = 0; } static struct irq_chip pm860x_irq_chip = { @@ -539,6 +537,25 @@ static struct irq_chip pm860x_irq_chip = { .irq_disable = pm860x_irq_disable, }; +static int pm860x_irq_domain_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) +{ + irq_set_chip_data(virq, d->host_data); + irq_set_chip_and_handler(virq, &pm860x_irq_chip, handle_edge_irq); + irq_set_nested_thread(virq, 1); +#ifdef CONFIG_ARM + set_irq_flags(virq, IRQF_VALID); +#else + irq_set_noprobe(virq); +#endif + return 0; +} + +static struct irq_domain_ops pm860x_irq_domain_ops = { + .map = pm860x_irq_domain_map, + .xlate = irq_domain_xlate_onetwocell, +}; + static int __devinit device_gpadc_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { @@ -593,13 +610,9 @@ static int __devinit device_irq_init(struct pm860x_chip *chip, : chip->companion; unsigned char status_buf[INT_STATUS_NUM]; unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; - int i, data, mask, ret = -EINVAL; - int __irq; - - if (!pdata || !pdata->irq_base) { - dev_warn(chip->dev, "No interrupt support on IRQ base\n"); - return -EINVAL; - } + int data, mask, ret = -EINVAL; + int nr_irqs, irq_base = -1; + struct device_node *node = i2c->dev.of_node; mask = PM8607_B0_MISC1_INV_INT | PM8607_B0_MISC1_INT_CLEAR | PM8607_B0_MISC1_INT_MASK; @@ -639,25 +652,23 @@ static int __devinit device_irq_init(struct pm860x_chip *chip, goto out; mutex_init(&chip->irq_lock); - chip->irq_base = pdata->irq_base; + + if (pdata && pdata->irq_base) + irq_base = pdata->irq_base; + nr_irqs = ARRAY_SIZE(pm860x_irqs); + chip->irq_base = irq_alloc_descs(irq_base, 0, nr_irqs, 0); + if (chip->irq_base < 0) { + dev_err(&i2c->dev, "Failed to allocate interrupts, ret:%d\n", + chip->irq_base); + ret = -EBUSY; + goto out; + } + irq_domain_add_legacy(node, nr_irqs, chip->irq_base, 0, + &pm860x_irq_domain_ops, chip); chip->core_irq = i2c->irq; if (!chip->core_irq) goto out; - /* register IRQ by genirq */ - for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) { - __irq = i + chip->irq_base; - irq_set_chip_data(__irq, chip); - irq_set_chip_and_handler(__irq, &pm860x_irq_chip, - handle_edge_irq); - irq_set_nested_thread(__irq, 1); -#ifdef CONFIG_ARM - set_irq_flags(__irq, IRQF_VALID); -#else - irq_set_noprobe(__irq); -#endif - } - ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq, flags | IRQF_ONESHOT, "88pm860x", chip); if (ret) { -- cgit v1.2.2 From 2e57d56747e601b3e0ff6697e524025d0504d161 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Fri, 21 Sep 2012 18:06:52 +0800 Subject: mfd: 88pm860x: Device tree support Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/input/touchscreen/88pm860x-ts.c | 46 ++++++++++++++++-------- drivers/leds/leds-88pm860x.c | 33 ++++++++++++++++-- drivers/mfd/88pm860x-core.c | 62 ++++++++++++++++++++++++++++----- drivers/regulator/88pm8607.c | 35 ++++++++++++++++++- drivers/rtc/rtc-88pm860x.c | 43 ++++++++++++++++++----- drivers/video/backlight/88pm860x_bl.c | 39 +++++++++++++++++++-- 6 files changed, 219 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c index 05f30b73c3c3..4f81e6eb74b6 100644 --- a/drivers/input/touchscreen/88pm860x-ts.c +++ b/drivers/input/touchscreen/88pm860x-ts.c @@ -10,6 +10,7 @@ */ #include #include +#include #include #include #include @@ -113,14 +114,31 @@ static void pm860x_touch_close(struct input_dev *dev) pm860x_set_bits(touch->i2c, MEAS_EN3, data, 0); } +#ifdef CONFIG_OF +static int __devinit pm860x_touch_dt_init(struct platform_device *pdev, + int *res_x) +{ + struct device_node *np = pdev->dev.parent->of_node; + if (!np) + return -ENODEV; + np = of_find_node_by_name(np, "touch"); + if (!np) { + dev_err(&pdev->dev, "Can't find touch node\n"); + return -EINVAL; + } + of_property_read_u32(np, "marvell,88pm860x-resistor-X", res_x); + return 0; +} +#else +#define pm860x_touch_dt_init(x, y) (-1) +#endif + static int __devinit pm860x_touch_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct pm860x_platform_data *pm860x_pdata = \ - pdev->dev.parent->platform_data; - struct pm860x_touch_pdata *pdata = NULL; + struct pm860x_touch_pdata *pdata = pdev->dev.platform_data; struct pm860x_touch *touch; - int irq, ret; + int irq, ret, res_x = 0; irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -128,15 +146,13 @@ static int __devinit pm860x_touch_probe(struct platform_device *pdev) return -EINVAL; } - if (!pm860x_pdata) { - dev_err(&pdev->dev, "platform data is missing\n"); - return -EINVAL; - } - - pdata = pm860x_pdata->touch; - if (!pdata) { - dev_err(&pdev->dev, "touchscreen data is missing\n"); - return -EINVAL; + if (pm860x_touch_dt_init(pdev, &res_x)) { + if (pdata) + res_x = pdata->res_x; + else { + dev_err(&pdev->dev, "failed to get platform data\n"); + return -EINVAL; + } } touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL); @@ -159,8 +175,8 @@ static int __devinit pm860x_touch_probe(struct platform_device *pdev) touch->idev->close = pm860x_touch_close; touch->chip = chip; touch->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; - touch->irq = irq + chip->irq_base; - touch->res_x = pdata->res_x; + touch->irq = irq; + touch->res_x = res_x; input_set_drvdata(touch->idev, touch); ret = request_threaded_irq(touch->irq, NULL, pm860x_touch_handler, diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c index 70232b1756f9..b7e8cc0957fc 100644 --- a/drivers/leds/leds-88pm860x.c +++ b/drivers/leds/leds-88pm860x.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -123,6 +124,33 @@ static void pm860x_led_set(struct led_classdev *cdev, schedule_work(&data->work); } +#ifdef CONFIG_OF +static int pm860x_led_dt_init(struct platform_device *pdev, + struct pm860x_led *data) +{ + struct device_node *nproot = pdev->dev.parent->of_node, *np; + int iset = 0; + if (!nproot) + return -ENODEV; + nproot = of_find_node_by_name(nproot, "leds"); + if (!nproot) { + dev_err(&pdev->dev, "failed to find leds node\n"); + return -ENODEV; + } + for_each_child_of_node(nproot, np) { + if (!of_node_cmp(np->name, data->name)) { + of_property_read_u32(np, "marvell,88pm860x-iset", + &iset); + data->iset = PM8606_LED_CURRENT(iset); + break; + } + } + return 0; +} +#else +#define pm860x_led_dt_init(x, y) (-1) +#endif + static int pm860x_led_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); @@ -179,8 +207,9 @@ static int pm860x_led_probe(struct platform_device *pdev) data->chip = chip; data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion; data->port = pdev->id; - if (pdata && pdata->iset) - data->iset = pdata->iset; + if (pm860x_led_dt_init(pdev, data)) + if (pdata) + data->iset = pdata->iset; data->current_brightness = 0; data->cdev.name = data->name; diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 5b56fe8250b4..fdaf6861ce95 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include #include @@ -1112,12 +1114,6 @@ static void __devexit pm860x_device_exit(struct pm860x_chip *chip) mfd_remove_devices(chip->dev); } -static const struct i2c_device_id pm860x_id_table[] = { - { "88PM860x", 0 }, - {} -}; -MODULE_DEVICE_TABLE(i2c, pm860x_id_table); - static int verify_addr(struct i2c_client *i2c) { unsigned short addr_8607[] = {0x30, 0x34}; @@ -1144,21 +1140,52 @@ static struct regmap_config pm860x_regmap_config = { .val_bits = 8, }; +static int __devinit pm860x_dt_init(struct device_node *np, + struct device *dev, + struct pm860x_platform_data *pdata) +{ + int ret; + + if (of_get_property(np, "marvell,88pm860x-irq-read-clr", NULL)) + pdata->irq_mode = 1; + ret = of_property_read_u32(np, "marvell,88pm860x-slave-addr", + &pdata->companion_addr); + if (ret) { + dev_err(dev, "Not found \"marvell,88pm860x-slave-addr\" " + "property\n"); + pdata->companion_addr = 0; + } + return 0; +} + static int __devinit pm860x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct pm860x_platform_data *pdata = client->dev.platform_data; + struct device_node *node = client->dev.of_node; struct pm860x_chip *chip; int ret; - if (!pdata) { + if (node && !pdata) { + /* parse DT to get platform data */ + pdata = devm_kzalloc(&client->dev, + sizeof(struct pm860x_platform_data), + GFP_KERNEL); + if (!pdata) + return -ENOMEM; + ret = pm860x_dt_init(node, &client->dev, pdata); + if (ret) + goto err; + } else if (!pdata) { pr_info("No platform data in %s!\n", __func__); return -EINVAL; } chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; + if (chip == NULL) { + ret = -ENOMEM; + goto err; + } chip->id = verify_addr(client); chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config); @@ -1198,6 +1225,10 @@ static int __devinit pm860x_probe(struct i2c_client *client, pm860x_device_init(chip, pdata); return 0; +err: + if (node) + devm_kfree(&client->dev, pdata); + return ret; } static int __devexit pm860x_remove(struct i2c_client *client) @@ -1238,11 +1269,24 @@ static int pm860x_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume); +static const struct i2c_device_id pm860x_id_table[] = { + { "88PM860x", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, pm860x_id_table); + +static const struct of_device_id pm860x_dt_ids[] = { + { .compatible = "marvell,88pm860x", }, + {}, +}; +MODULE_DEVICE_TABLE(of, pm860x_dt_ids); + static struct i2c_driver pm860x_driver = { .driver = { .name = "88PM860x", .owner = THIS_MODULE, .pm = &pm860x_pm_ops, + .of_match_table = of_match_ptr(pm860x_dt_ids), }, .probe = pm860x_probe, .remove = __devexit_p(pm860x_remove), diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index f96fbe38ff6f..1c5ab0172ea2 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include #include @@ -364,6 +366,34 @@ static struct pm8607_regulator_info pm8606_regulator_info[] = { PM8606_PREG(PREREGULATORB, 5), }; +#ifdef CONFIG_OF +static int pm8607_regulator_dt_init(struct platform_device *pdev, + struct pm8607_regulator_info *info, + struct regulator_config *config) +{ + struct device_node *nproot, *np; + nproot = pdev->dev.parent->of_node; + if (!nproot) + return -ENODEV; + nproot = of_find_node_by_name(nproot, "regulators"); + if (!nproot) { + dev_err(&pdev->dev, "failed to find regulators node\n"); + return -ENODEV; + } + for_each_child_of_node(nproot, np) { + if (!of_node_cmp(np->name, info->desc.name)) { + config->init_data = + of_get_regulator_init_data(&pdev->dev, np); + config->of_node = np; + break; + } + } + return 0; +} +#else +#define pm8607_regulator_dt_init(x, y, z) (-1) +#endif + static int __devinit pm8607_regulator_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); @@ -402,9 +432,12 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) info->slope_double = 1; config.dev = &pdev->dev; - config.init_data = pdata; config.driver_data = info; + if (pm8607_regulator_dt_init(pdev, info, &config)) + if (pdata) + config.init_data = pdata; + if (chip->id == CHIP_PM8607) config.regmap = chip->regmap; else diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index feddefc42109..de9e854b326a 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -284,6 +285,28 @@ out: } #endif +#ifdef CONFIG_OF +static int __devinit pm860x_rtc_dt_init(struct platform_device *pdev, + struct pm860x_rtc_info *info) +{ + struct device_node *np = pdev->dev.parent->of_node; + int ret; + if (!np) + return -ENODEV; + np = of_find_node_by_name(np, "rtc"); + if (!np) { + dev_err(&pdev->dev, "failed to find rtc node\n"); + return -ENODEV; + } + ret = of_property_read_u32(np, "marvell,88pm860x-vrtc", &info->vrtc); + if (ret) + info->vrtc = 0; + return 0; +} +#else +#define pm860x_rtc_dt_init(x, y) (-1) +#endif + static int __devinit pm860x_rtc_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); @@ -294,8 +317,6 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev) int ret; pdata = pdev->dev.platform_data; - if (pdata == NULL) - dev_warn(&pdev->dev, "No platform data!\n"); info = kzalloc(sizeof(struct pm860x_rtc_info), GFP_KERNEL); if (!info) @@ -345,9 +366,11 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev) } } rtc_tm_to_time(&tm, &ticks); - if (pdata && pdata->sync) { - pdata->sync(ticks); - info->sync = pdata->sync; + if (pm860x_rtc_dt_init(pdev, info)) { + if (pdata && pdata->sync) { + pdata->sync(ticks); + info->sync = pdata->sync; + } } info->rtc_dev = rtc_device_register("88pm860x-rtc", &pdev->dev, @@ -366,10 +389,12 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev) #ifdef VRTC_CALIBRATION /* <00> -- 2.7V, <01> -- 2.9V, <10> -- 3.1V, <11> -- 3.3V */ - if (pdata && pdata->vrtc) - info->vrtc = pdata->vrtc & 0x3; - else - info->vrtc = 1; + if (pm860x_rtc_dt_init(pdev, info)) { + if (pdata && pdata->vrtc) + info->vrtc = pdata->vrtc & 0x3; + else + info->vrtc = 1; + } pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, MEAS2_VRTC); /* calibrate VRTC */ diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index 965161cacefa..b7ec34c57f46 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -159,6 +160,36 @@ static const struct backlight_ops pm860x_backlight_ops = { .get_brightness = pm860x_backlight_get_brightness, }; +#ifdef CONFIG_OF +static int pm860x_backlight_dt_init(struct platform_device *pdev, + struct pm860x_backlight_data *data, + char *name) +{ + struct device_node *nproot = pdev->dev.parent->of_node, *np; + int iset = 0; + if (!nproot) + return -ENODEV; + nproot = of_find_node_by_name(nproot, "backlights"); + if (!nproot) { + dev_err(&pdev->dev, "failed to find backlights node\n"); + return -ENODEV; + } + for_each_child_of_node(nproot, np) { + if (!of_node_cmp(np->name, name)) { + of_property_read_u32(np, "marvell,88pm860x-iset", + &iset); + data->iset = PM8606_WLED_CURRENT(iset); + of_property_read_u32(np, "marvell,88pm860x-pwm", + &data->pwm); + break; + } + } + return 0; +} +#else +#define pm860x_backlight_dt_init(x, y, z) (-1) +#endif + static int pm860x_backlight_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); @@ -203,9 +234,11 @@ static int pm860x_backlight_probe(struct platform_device *pdev) data->i2c = (chip->id == CHIP_PM8606) ? chip->client \ : chip->companion; data->current_brightness = MAX_BRIGHTNESS; - if (pdata) { - data->pwm = pdata->pwm; - data->iset = pdata->iset; + if (pm860x_backlight_dt_init(pdev, data, name)) { + if (pdata) { + data->pwm = pdata->pwm; + data->iset = pdata->iset; + } } memset(&props, 0, sizeof(struct backlight_properties)); -- cgit v1.2.2 From fe1d38e80d1497a2b64685dd2e7a6018dc79b408 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Fri, 21 Sep 2012 18:06:53 +0800 Subject: mfd: 88pm860x: Move gpadc init into touch The initilization of GPADC is moved from core driver to touch driver with DT support. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/input/touchscreen/88pm860x-ts.c | 91 ++++++++++++++++++++++++++++++--- drivers/mfd/88pm860x-core.c | 51 ------------------ 2 files changed, 85 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c index 4f81e6eb74b6..326218dbd6e6 100644 --- a/drivers/input/touchscreen/88pm860x-ts.c +++ b/drivers/input/touchscreen/88pm860x-ts.c @@ -116,9 +116,13 @@ static void pm860x_touch_close(struct input_dev *dev) #ifdef CONFIG_OF static int __devinit pm860x_touch_dt_init(struct platform_device *pdev, + struct pm860x_chip *chip, int *res_x) { struct device_node *np = pdev->dev.parent->of_node; + struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ + : chip->companion; + int data, n, ret; if (!np) return -ENODEV; np = of_find_node_by_name(np, "touch"); @@ -126,11 +130,43 @@ static int __devinit pm860x_touch_dt_init(struct platform_device *pdev, dev_err(&pdev->dev, "Can't find touch node\n"); return -EINVAL; } + /* set GPADC MISC1 register */ + data = 0; + if (!of_property_read_u32(np, "marvell,88pm860x-gpadc-prebias", &n)) + data |= (n << 1) & PM8607_GPADC_PREBIAS_MASK; + if (!of_property_read_u32(np, "marvell,88pm860x-gpadc-slot-cycle", &n)) + data |= (n << 3) & PM8607_GPADC_SLOT_CYCLE_MASK; + if (!of_property_read_u32(np, "marvell,88pm860x-gpadc-off-scale", &n)) + data |= (n << 5) & PM8607_GPADC_OFF_SCALE_MASK; + if (!of_property_read_u32(np, "marvell,88pm860x-gpadc-sw-cal", &n)) + data |= (n << 7) & PM8607_GPADC_SW_CAL_MASK; + if (data) { + ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data); + if (ret < 0) + return -EINVAL; + } + /* set tsi prebias time */ + if (!of_property_read_u32(np, "marvell,88pm860x-tsi-prebias", &data)) { + ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data); + if (ret < 0) + return -EINVAL; + } + /* set prebias & prechg time of pen detect */ + data = 0; + if (!of_property_read_u32(np, "marvell,88pm860x-pen-prebias", &n)) + data |= n & PM8607_PD_PREBIAS_MASK; + if (!of_property_read_u32(np, "marvell,88pm860x-pen-prechg", &n)) + data |= n & PM8607_PD_PRECHG_MASK; + if (data) { + ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data); + if (ret < 0) + return -EINVAL; + } of_property_read_u32(np, "marvell,88pm860x-resistor-X", res_x); return 0; } #else -#define pm860x_touch_dt_init(x, y) (-1) +#define pm860x_touch_dt_init(x, y, z) (-1) #endif static int __devinit pm860x_touch_probe(struct platform_device *pdev) @@ -138,7 +174,9 @@ static int __devinit pm860x_touch_probe(struct platform_device *pdev) struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); struct pm860x_touch_pdata *pdata = pdev->dev.platform_data; struct pm860x_touch *touch; - int irq, ret, res_x = 0; + struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ + : chip->companion; + int irq, ret, res_x = 0, data = 0; irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -146,14 +184,55 @@ static int __devinit pm860x_touch_probe(struct platform_device *pdev) return -EINVAL; } - if (pm860x_touch_dt_init(pdev, &res_x)) { - if (pdata) + if (pm860x_touch_dt_init(pdev, chip, &res_x)) { + if (pdata) { + /* set GPADC MISC1 register */ + data = 0; + data |= (pdata->gpadc_prebias << 1) + & PM8607_GPADC_PREBIAS_MASK; + data |= (pdata->slot_cycle << 3) + & PM8607_GPADC_SLOT_CYCLE_MASK; + data |= (pdata->off_scale << 5) + & PM8607_GPADC_OFF_SCALE_MASK; + data |= (pdata->sw_cal << 7) + & PM8607_GPADC_SW_CAL_MASK; + if (data) { + ret = pm860x_reg_write(i2c, + PM8607_GPADC_MISC1, data); + if (ret < 0) + return -EINVAL; + } + /* set tsi prebias time */ + if (pdata->tsi_prebias) { + data = pdata->tsi_prebias; + ret = pm860x_reg_write(i2c, + PM8607_TSI_PREBIAS, data); + if (ret < 0) + return -EINVAL; + } + /* set prebias & prechg time of pen detect */ + data = 0; + data |= pdata->pen_prebias + & PM8607_PD_PREBIAS_MASK; + data |= (pdata->pen_prechg << 5) + & PM8607_PD_PRECHG_MASK; + if (data) { + ret = pm860x_reg_write(i2c, + PM8607_PD_PREBIAS, data); + if (ret < 0) + return -EINVAL; + } res_x = pdata->res_x; - else { + } else { dev_err(&pdev->dev, "failed to get platform data\n"); return -EINVAL; } } + /* enable GPADC */ + ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1, PM8607_GPADC_EN, + PM8607_GPADC_EN); + if (ret) + return ret; touch = kzalloc(sizeof(struct pm860x_touch), GFP_KERNEL); if (touch == NULL) @@ -174,7 +253,7 @@ static int __devinit pm860x_touch_probe(struct platform_device *pdev) touch->idev->open = pm860x_touch_open; touch->idev->close = pm860x_touch_close; touch->chip = chip; - touch->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; + touch->i2c = i2c; touch->irq = irq; touch->res_x = res_x; input_set_drvdata(touch->idev, touch); diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index fdaf6861ce95..59d117e9fa31 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -558,53 +558,6 @@ static struct irq_domain_ops pm860x_irq_domain_ops = { .xlate = irq_domain_xlate_onetwocell, }; -static int __devinit device_gpadc_init(struct pm860x_chip *chip, - struct pm860x_platform_data *pdata) -{ - struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \ - : chip->companion; - int data; - int ret; - - /* initialize GPADC without activating it */ - - if (!pdata || !pdata->touch) - return -EINVAL; - - /* set GPADC MISC1 register */ - data = 0; - data |= (pdata->touch->gpadc_prebias << 1) & PM8607_GPADC_PREBIAS_MASK; - data |= (pdata->touch->slot_cycle << 3) & PM8607_GPADC_SLOT_CYCLE_MASK; - data |= (pdata->touch->off_scale << 5) & PM8607_GPADC_OFF_SCALE_MASK; - data |= (pdata->touch->sw_cal << 7) & PM8607_GPADC_SW_CAL_MASK; - if (data) { - ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data); - if (ret < 0) - goto out; - } - /* set tsi prebias time */ - if (pdata->touch->tsi_prebias) { - data = pdata->touch->tsi_prebias; - ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data); - if (ret < 0) - goto out; - } - /* set prebias & prechg time of pen detect */ - data = 0; - data |= pdata->touch->pen_prebias & PM8607_PD_PREBIAS_MASK; - data |= (pdata->touch->pen_prechg << 5) & PM8607_PD_PRECHG_MASK; - if (data) { - ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data); - if (ret < 0) - goto out; - } - - ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1, - PM8607_GPADC_EN, PM8607_GPADC_EN); -out: - return ret; -} - static int __devinit device_irq_init(struct pm860x_chip *chip, struct pm860x_platform_data *pdata) { @@ -1053,10 +1006,6 @@ static void __devinit device_8607_init(struct pm860x_chip *chip, goto out; } - ret = device_gpadc_init(chip, pdata); - if (ret < 0) - goto out; - ret = device_irq_init(chip, pdata); if (ret < 0) goto out; -- cgit v1.2.2