From fea52b8910f6f5438790dbd2de45003ce08d01a5 Mon Sep 17 00:00:00 2001 From: Roger Tseng Date: Fri, 11 Apr 2014 14:53:20 +0800 Subject: mfd: rtsx_usb: Fix possible race condition Fix two possible race condition generated by misuse of del_timer in rtsx_usb_bulk_transfer_sglist() and uninitialized timers before mfd_add_devices in rtsx_usb_probe(). Signed-off-by: Roger Tseng Signed-off-by: Lee Jones --- drivers/mfd/rtsx_usb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/rtsx_usb.c b/drivers/mfd/rtsx_usb.c index b53b9d4..0ca7973 100644 --- a/drivers/mfd/rtsx_usb.c +++ b/drivers/mfd/rtsx_usb.c @@ -67,7 +67,7 @@ static int rtsx_usb_bulk_transfer_sglist(struct rtsx_ucr *ucr, ucr->sg_timer.expires = jiffies + msecs_to_jiffies(timeout); add_timer(&ucr->sg_timer); usb_sg_wait(&ucr->current_sg); - del_timer(&ucr->sg_timer); + del_timer_sync(&ucr->sg_timer); if (act_len) *act_len = ucr->current_sg.bytes; @@ -644,14 +644,14 @@ static int rtsx_usb_probe(struct usb_interface *intf, if (ret) goto out_init_fail; + /* initialize USB SG transfer timer */ + setup_timer(&ucr->sg_timer, rtsx_usb_sg_timed_out, (unsigned long) ucr); + ret = mfd_add_devices(&intf->dev, usb_dev->devnum, rtsx_usb_cells, ARRAY_SIZE(rtsx_usb_cells), NULL, 0, NULL); if (ret) goto out_init_fail; - /* initialize USB SG transfer timer */ - init_timer(&ucr->sg_timer); - setup_timer(&ucr->sg_timer, rtsx_usb_sg_timed_out, (unsigned long) ucr); #ifdef CONFIG_PM intf->needs_remote_wakeup = 1; usb_enable_autosuspend(usb_dev); -- cgit v1.1 From 5f0334205239bb5ae22ca89ad2af378062836498 Mon Sep 17 00:00:00 2001 From: Roger Tseng Date: Fri, 11 Apr 2014 14:53:21 +0800 Subject: mfd: rtsx_usb: Add comment in rtsx_usb_suspend Explain why there is no need to have a symmetric LED turn-on in resume handler while calling rtsx_usb_turn_off_led() in suspend handler. Signed-off-by: Roger Tseng Signed-off-by: Lee Jones --- drivers/mfd/rtsx_usb.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/rtsx_usb.c b/drivers/mfd/rtsx_usb.c index 0ca7973..141ea52 100644 --- a/drivers/mfd/rtsx_usb.c +++ b/drivers/mfd/rtsx_usb.c @@ -687,9 +687,15 @@ static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message) dev_dbg(&intf->dev, "%s called with pm message 0x%04u\n", __func__, message.event); + /* + * Call to make sure LED is off during suspend to save more power. + * It is NOT a permanent state and could be turned on anytime later. + * Thus no need to call turn_on when resunming. + */ mutex_lock(&ucr->dev_mutex); rtsx_usb_turn_off_led(ucr); mutex_unlock(&ucr->dev_mutex); + return 0; } -- cgit v1.1 From b69d2ad6748e2cd3a6b93fca074adc31f56e4436 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 8 May 2014 23:16:37 +0200 Subject: mfd: stmpe: mask off unused blocks properly The STMPE driver would just read/modify/write the system control register on the STMPE1601, meaning it would not properly mask off the PWM block, which remained active if it was on at boot time. This makes sure the blocks are always masked off if they were active on boot, saving some power. Also rename the inconsistenty named STMPE1601 define for the PWM block activation. Signed-off-by: Linus Walleij --- drivers/mfd/stmpe.c | 9 +++++++++ drivers/mfd/stmpe.h | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 4a91f67..9fa2dd6 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -605,9 +605,18 @@ static int stmpe1601_enable(struct stmpe *stmpe, unsigned int blocks, if (blocks & STMPE_BLOCK_GPIO) mask |= STMPE1601_SYS_CTRL_ENABLE_GPIO; + else + mask &= ~STMPE1601_SYS_CTRL_ENABLE_GPIO; if (blocks & STMPE_BLOCK_KEYPAD) mask |= STMPE1601_SYS_CTRL_ENABLE_KPC; + else + mask &= ~STMPE1601_SYS_CTRL_ENABLE_KPC; + + if (blocks & STMPE_BLOCK_PWM) + mask |= STMPE1601_SYS_CTRL_ENABLE_SPWM; + else + mask &= ~STMPE1601_SYS_CTRL_ENABLE_SPWM; return __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL, mask, enable ? mask : 0); diff --git a/drivers/mfd/stmpe.h b/drivers/mfd/stmpe.h index 6639f1b..9e4d21d 100644 --- a/drivers/mfd/stmpe.h +++ b/drivers/mfd/stmpe.h @@ -192,7 +192,7 @@ int stmpe_remove(struct stmpe *stmpe); #define STMPE1601_SYS_CTRL_ENABLE_GPIO (1 << 3) #define STMPE1601_SYS_CTRL_ENABLE_KPC (1 << 1) -#define STMPE1601_SYSCON_ENABLE_SPWM (1 << 0) +#define STMPE1601_SYS_CTRL_ENABLE_SPWM (1 << 0) /* The 1601/2403 share the same masks */ #define STMPE1601_AUTOSLEEP_TIMEOUT_MASK (0x7) -- cgit v1.1 From 5a826feedc331a2d5ced2afd832199a70b3af891 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 23 Apr 2014 23:35:58 +0200 Subject: mfd: stmpe: Probe properly from the Device Tree The current STMPE I2C probing code does not really match the compatible strings - it matches node names happening to give the right device name. Instead, let's introduce some real compatible matching, more complex, more accurate. Make the driver depend on OF since all platforms using it are DT-only. Signed-off-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 1 + drivers/mfd/stmpe-i2c.c | 30 +++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 3383412..29be025 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -675,6 +675,7 @@ config MFD_DB8500_PRCMU config MFD_STMPE bool "STMicroelectronics STMPE" depends on (I2C=y || SPI_MASTER=y) + depends on OF select MFD_CORE help Support for the STMPE family of I/O Expanders from diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c index 0da02e1..a45f9c0 100644 --- a/drivers/mfd/stmpe-i2c.c +++ b/drivers/mfd/stmpe-i2c.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "stmpe.h" static int i2c_reg_read(struct stmpe *stmpe, u8 reg) @@ -52,15 +53,41 @@ static struct stmpe_client_info i2c_ci = { .write_block = i2c_block_write, }; +static const struct of_device_id stmpe_of_match[] = { + { .compatible = "st,stmpe610", .data = (void *)STMPE610, }, + { .compatible = "st,stmpe801", .data = (void *)STMPE801, }, + { .compatible = "st,stmpe811", .data = (void *)STMPE811, }, + { .compatible = "st,stmpe1601", .data = (void *)STMPE1601, }, + { .compatible = "st,stmpe1801", .data = (void *)STMPE1801, }, + { .compatible = "st,stmpe2401", .data = (void *)STMPE2401, }, + { .compatible = "st,stmpe2403", .data = (void *)STMPE2403, }, + {}, +}; +MODULE_DEVICE_TABLE(of, stmpe_of_match); + static int stmpe_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { + int partnum; + const struct of_device_id *of_id; + i2c_ci.data = (void *)id; i2c_ci.irq = i2c->irq; i2c_ci.client = i2c; i2c_ci.dev = &i2c->dev; - return stmpe_probe(&i2c_ci, id->driver_data); + of_id = of_match_device(stmpe_of_match, &i2c->dev); + if (!of_id) { + /* + * This happens when the I2C ID matches the node name + * but no real compatible string has been given. + */ + dev_info(&i2c->dev, "matching on node name, compatible is preferred\n"); + partnum = id->driver_data; + } else + partnum = (int)of_id->data; + + return stmpe_probe(&i2c_ci, partnum); } static int stmpe_i2c_remove(struct i2c_client *i2c) @@ -89,6 +116,7 @@ static struct i2c_driver stmpe_i2c_driver = { #ifdef CONFIG_PM .pm = &stmpe_dev_pm_ops, #endif + .of_match_table = stmpe_of_match, }, .probe = stmpe_i2c_probe, .remove = stmpe_i2c_remove, -- cgit v1.1 From 9c9e321455fb806108f9dbb1872bacfd42c6002b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 8 May 2014 23:16:35 +0200 Subject: mfd: stmpe: add optional regulators The STMPE has VCC and VIO supply lines, and sometimes (as on Ux500) this comes from a software-controlled regulator. Make it possible to supply the STMPE with power from these regulators. Signed-off-by: Linus Walleij --- drivers/mfd/stmpe.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 9fa2dd6..294731b 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "stmpe.h" static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks) @@ -1186,6 +1187,18 @@ int stmpe_probe(struct stmpe_client_info *ci, int partnum) stmpe->variant = stmpe_variant_info[partnum]; stmpe->regs = stmpe->variant->regs; stmpe->num_gpios = stmpe->variant->num_gpios; + stmpe->vcc = devm_regulator_get_optional(ci->dev, "vcc"); + if (!IS_ERR(stmpe->vcc)) { + ret = regulator_enable(stmpe->vcc); + if (ret) + dev_warn(ci->dev, "failed to enable VCC supply\n"); + } + stmpe->vio = devm_regulator_get_optional(ci->dev, "vio"); + if (!IS_ERR(stmpe->vio)) { + ret = regulator_enable(stmpe->vio); + if (ret) + dev_warn(ci->dev, "failed to enable VIO supply\n"); + } dev_set_drvdata(stmpe->dev, stmpe); if (ci->init) @@ -1252,6 +1265,11 @@ int stmpe_probe(struct stmpe_client_info *ci, int partnum) int stmpe_remove(struct stmpe *stmpe) { + if (!IS_ERR(stmpe->vio)) + regulator_disable(stmpe->vio); + if (!IS_ERR(stmpe->vcc)) + regulator_disable(stmpe->vcc); + mfd_remove_devices(stmpe->dev); return 0; -- cgit v1.1 From 9e9dc7d9597bd6881b3e7ae6ae3d710319605c47 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 8 May 2014 23:16:34 +0200 Subject: mfd: stmpe: root out static GPIO and IRQ assignments The only platform using the STMPE expander now boots from device tree using all-dynamic GPIO and IRQ number assignments, so remove the mechanism to pass this from the device tree entirely. Signed-off-by: Linus Walleij --- drivers/mfd/stmpe.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 294731b..3b6bfa7 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -996,9 +996,6 @@ static int stmpe_irq_init(struct stmpe *stmpe, struct device_node *np) int base = 0; int num_irqs = stmpe->variant->num_irqs; - if (!np) - base = stmpe->irq_base; - stmpe->domain = irq_domain_add_simple(np, num_irqs, base, &stmpe_irq_ops, stmpe); if (!stmpe->domain) { @@ -1077,7 +1074,7 @@ static int stmpe_chip_init(struct stmpe *stmpe) static int stmpe_add_device(struct stmpe *stmpe, const struct mfd_cell *cell) { return mfd_add_devices(stmpe->dev, stmpe->pdata->id, cell, 1, - NULL, stmpe->irq_base, stmpe->domain); + NULL, 0, stmpe->domain); } static int stmpe_devices_init(struct stmpe *stmpe) @@ -1181,7 +1178,6 @@ int stmpe_probe(struct stmpe_client_info *ci, int partnum) stmpe->dev = ci->dev; stmpe->client = ci->client; stmpe->pdata = pdata; - stmpe->irq_base = pdata->irq_base; stmpe->ci = ci; stmpe->partnum = partnum; stmpe->variant = stmpe_variant_info[partnum]; -- cgit v1.1 From 2b29ff7e0a609ff57938774ff62baede7b80a405 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 31 Mar 2014 21:32:37 +0800 Subject: mfd: bcm590xx: Add missing remove function Add missing mfd_remove_devices() call in remove function. Signed-off-by: Axel Lin Signed-off-by: Lee Jones --- drivers/mfd/bcm590xx.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/bcm590xx.c b/drivers/mfd/bcm590xx.c index e9a33c7..5adb2e3 100644 --- a/drivers/mfd/bcm590xx.c +++ b/drivers/mfd/bcm590xx.c @@ -64,6 +64,12 @@ static int bcm590xx_i2c_probe(struct i2c_client *i2c, return ret; } +static int bcm590xx_i2c_remove(struct i2c_client *i2c) +{ + mfd_remove_devices(&i2c->dev); + return 0; +} + static const struct of_device_id bcm590xx_of_match[] = { { .compatible = "brcm,bcm59056" }, { } @@ -83,6 +89,7 @@ static struct i2c_driver bcm590xx_i2c_driver = { .of_match_table = of_match_ptr(bcm590xx_of_match), }, .probe = bcm590xx_i2c_probe, + .remove = bcm590xx_i2c_remove, .id_table = bcm590xx_i2c_id, }; module_i2c_driver(bcm590xx_i2c_driver); -- cgit v1.1 From ed612a349c967dd235d83959f9a0878777a5ae18 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 31 Mar 2014 21:31:16 +0800 Subject: mfd: bcm590xx: Fix modalias prefix This is a i2c driver, so uses i2c prefix in modalias. Signed-off-by: Axel Lin Signed-off-by: Lee Jones --- drivers/mfd/bcm590xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/bcm590xx.c b/drivers/mfd/bcm590xx.c index 5adb2e3..be4d0ac 100644 --- a/drivers/mfd/bcm590xx.c +++ b/drivers/mfd/bcm590xx.c @@ -97,4 +97,4 @@ module_i2c_driver(bcm590xx_i2c_driver); MODULE_AUTHOR("Matt Porter "); MODULE_DESCRIPTION("BCM590xx multi-function driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:bcm590xx"); +MODULE_ALIAS("i2c:bcm590xx"); -- cgit v1.1 From 58a9e5b98360e8dcf9c958c0552fb35279e3933f Mon Sep 17 00:00:00 2001 From: Michael Brunner Date: Tue, 8 Apr 2014 08:21:06 +0200 Subject: mfd: Add sysfs attributes for Kontron PLD firmware revision This patch adds attributes to the Kontron PLD driver to allow applications to retrieve firmware information. Additionally the format has been changed to conform with the representation in other Kontron software. Signed-off-by: Michael Brunner Reviewed-by: Guenter Roeck Signed-off-by: Lee Jones --- drivers/mfd/kempld-core.c | 127 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 106 insertions(+), 21 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c index 0769260..25c5ca6 100644 --- a/drivers/mfd/kempld-core.c +++ b/drivers/mfd/kempld-core.c @@ -288,9 +288,38 @@ EXPORT_SYMBOL_GPL(kempld_release_mutex); */ static int kempld_get_info(struct kempld_device_data *pld) { + int ret; struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); + char major, minor; + + ret = pdata->get_info(pld); + if (ret) + return ret; + + /* The Kontron PLD firmware version string has the following format: + * Pwxy.zzzz + * P: Fixed + * w: PLD number - 1 hex digit + * x: Major version - 1 alphanumerical digit (0-9A-V) + * y: Minor version - 1 alphanumerical digit (0-9A-V) + * zzzz: Build number - 4 zero padded hex digits */ - return pdata->get_info(pld); + if (pld->info.major < 10) + major = pld->info.major + '0'; + else + major = (pld->info.major - 10) + 'A'; + if (pld->info.minor < 10) + minor = pld->info.minor + '0'; + else + minor = (pld->info.minor - 10) + 'A'; + + ret = scnprintf(pld->info.version, sizeof(pld->info.version), + "P%X%c%c.%04X", pld->info.number, major, minor, + pld->info.buildnr); + if (ret < 0) + return ret; + + return 0; } /* @@ -307,9 +336,71 @@ static int kempld_register_cells(struct kempld_device_data *pld) return pdata->register_cells(pld); } +static const char *kempld_get_type_string(struct kempld_device_data *pld) +{ + const char *version_type; + + switch (pld->info.type) { + case 0: + version_type = "release"; + break; + case 1: + version_type = "debug"; + break; + case 2: + version_type = "custom"; + break; + default: + version_type = "unspecified"; + break; + } + + return version_type; +} + +static ssize_t kempld_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kempld_device_data *pld = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%s\n", pld->info.version); +} + +static ssize_t kempld_specification_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kempld_device_data *pld = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%d.%d\n", pld->info.spec_major, + pld->info.spec_minor); +} + +static ssize_t kempld_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct kempld_device_data *pld = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%s\n", kempld_get_type_string(pld)); +} + +static DEVICE_ATTR(pld_version, S_IRUGO, kempld_version_show, NULL); +static DEVICE_ATTR(pld_specification, S_IRUGO, kempld_specification_show, + NULL); +static DEVICE_ATTR(pld_type, S_IRUGO, kempld_type_show, NULL); + +static struct attribute *pld_attributes[] = { + &dev_attr_pld_version.attr, + &dev_attr_pld_specification.attr, + &dev_attr_pld_type.attr, + NULL +}; + +static const struct attribute_group pld_attr_group = { + .attrs = pld_attributes, +}; + static int kempld_detect_device(struct kempld_device_data *pld) { - char *version_type; u8 index_reg; int ret; @@ -335,27 +426,19 @@ static int kempld_detect_device(struct kempld_device_data *pld) if (ret) return ret; - switch (pld->info.type) { - case 0: - version_type = "release"; - break; - case 1: - version_type = "debug"; - break; - case 2: - version_type = "custom"; - break; - default: - version_type = "unspecified"; - } + dev_info(pld->dev, "Found Kontron PLD - %s (%s), spec %d.%d\n", + pld->info.version, kempld_get_type_string(pld), + pld->info.spec_major, pld->info.spec_minor); + + ret = sysfs_create_group(&pld->dev->kobj, &pld_attr_group); + if (ret) + return ret; - dev_info(pld->dev, "Found Kontron PLD %d\n", pld->info.number); - dev_info(pld->dev, "%s version %d.%d build %d, specification %d.%d\n", - version_type, pld->info.major, pld->info.minor, - pld->info.buildnr, pld->info.spec_major, - pld->info.spec_minor); + ret = kempld_register_cells(pld); + if (ret) + sysfs_remove_group(&pld->dev->kobj, &pld_attr_group); - return kempld_register_cells(pld); + return ret; } static int kempld_probe(struct platform_device *pdev) @@ -399,6 +482,8 @@ static int kempld_remove(struct platform_device *pdev) struct kempld_device_data *pld = platform_get_drvdata(pdev); struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); + sysfs_remove_group(&pld->dev->kobj, &pld_attr_group); + mfd_remove_devices(&pdev->dev); pdata->release_hardware_mutex(pld); -- cgit v1.1 From 7abafa0a66414e385d122bcbc655a1d55ecbaecf Mon Sep 17 00:00:00 2001 From: Jay Aurabind Date: Wed, 21 May 2014 22:49:54 +0530 Subject: mfd: abx500-core: Fix compiler warning larger stack frame MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On systems with CONFIG_FRAME_WARN=1024, compiler warns the allocation of an object of struct device on stack. Make the allocation dynamically to fix the warning. Also change the caller's return type to int so as to account for error handling. drivers/mfd/abx500-core.c: In function ‘abx500_dump_all_banks’: drivers/mfd/abx500-core.c:167:1: warning: the frame size of 1032 bytes is larger than 1024 bytes [-Wframe-larger-than=] Signed-off-by: Aurabindo J Signed-off-by: Lee Jones --- drivers/mfd/abx500-core.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/abx500-core.c b/drivers/mfd/abx500-core.c index f3a15aa..d6d0ec4 100644 --- a/drivers/mfd/abx500-core.c +++ b/drivers/mfd/abx500-core.c @@ -151,19 +151,23 @@ int abx500_startup_irq_enabled(struct device *dev, unsigned int irq) } EXPORT_SYMBOL(abx500_startup_irq_enabled); -void abx500_dump_all_banks(void) +int abx500_dump_all_banks(void) { struct abx500_ops *ops; - struct device dummy_child = {NULL}; + struct device *dummy_child; struct abx500_device_entry *dev_entry; + dummy_child = kzalloc(sizeof(struct device), GFP_KERNEL); + if (!dummy_child) + return -ENOMEM; list_for_each_entry(dev_entry, &abx500_list, list) { - dummy_child.parent = dev_entry->dev; + dummy_child->parent = dev_entry->dev; ops = &dev_entry->ops; if ((ops != NULL) && (ops->dump_all_banks != NULL)) - ops->dump_all_banks(&dummy_child); + ops->dump_all_banks(dummy_child); } + kfree(dummy_child); } EXPORT_SYMBOL(abx500_dump_all_banks); -- cgit v1.1 From 48ca9a52c58c088c7492185ef33d0675d6382b5a Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 15 Apr 2014 19:56:14 -0300 Subject: mfd: mc13xxx-core: Initialize the lock prior to using it After request_threaded_irq() is called there is a chance that an interrupt may occur before the 'mc13xxx->lock' is initialized, which will trigger a kernel oops. In order to prevent that, move the initialization of 'mc13xxx->lock' prior to requesting the interrupts. Suggested-by: Russell King Signed-off-by: Fabio Estevam Acked-by: Russell King Signed-off-by: Lee Jones --- drivers/mfd/mc13xxx-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 0c6c21c5..ddabc81 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -660,13 +660,13 @@ int mc13xxx_common_init(struct device *dev) if (ret) return ret; + mutex_init(&mc13xxx->lock); + ret = request_threaded_irq(mc13xxx->irq, NULL, mc13xxx_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_HIGH, "mc13xxx", mc13xxx); if (ret) return ret; - mutex_init(&mc13xxx->lock); - if (mc13xxx_probe_flags_dt(mc13xxx) < 0 && pdata) mc13xxx->flags = pdata->flags; -- cgit v1.1 From fce7fbfcd1b836935d92512476a3b7d508a64b7b Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 17 Apr 2014 13:14:15 +0100 Subject: mfd: wm5110: Add missing isolation control register The isolation control register is required when DCVDD is externally supplied add this in as a readable register. Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/wm5110-tables.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 1942b6f..58bc2be 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -549,6 +549,7 @@ static const struct reg_default wm5110_reg_default[] = { { 0x000002A8, 0x1422 }, /* R680 - Mic Detect Level 3 */ { 0x000002A9, 0x300A }, /* R681 - Mic Detect Level 4 */ { 0x000002C3, 0x0000 }, /* R707 - Mic noise mix control 1 */ + { 0x000002CB, 0x0000 }, /* R715 - Isolation control */ { 0x000002D3, 0x0000 }, /* R723 - Jack detect analogue */ { 0x00000300, 0x0000 }, /* R768 - Input Enables */ { 0x00000308, 0x0000 }, /* R776 - Input Rate */ @@ -1580,6 +1581,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_MIC_DETECT_LEVEL_3: case ARIZONA_MIC_DETECT_LEVEL_4: case ARIZONA_MIC_NOISE_MIX_CONTROL_1: + case ARIZONA_ISOLATION_CONTROL: case ARIZONA_JACK_DETECT_ANALOGUE: case ARIZONA_INPUT_ENABLES: case ARIZONA_INPUT_ENABLES_STATUS: -- cgit v1.1 From 62cf2cdb99c7e870ab857bdd617e728790f8c43c Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 5 Apr 2014 08:49:34 -0700 Subject: mfd: lpc_ich: Enable GPIO for Panther Point Panther Point PCH GPIO configuration is similar to V5 PCHs. Signed-off-by: Guenter Roeck Signed-off-by: Lee Jones --- drivers/mfd/lpc_ich.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 3f10ea3..7d8482f 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -488,6 +488,7 @@ static struct lpc_ich_info lpc_chipset_info[] = { [LPC_PPT] = { .name = "Panther Point", .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, }, [LPC_LPT] = { .name = "Lynx Point", -- cgit v1.1 From a865a589144da6dbf26750b7193a9748da159305 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Thu, 17 Apr 2014 12:32:17 -0700 Subject: mfd: cros_ec: cleanup: cros_ec.c is GPL licensed, like all the others. This module has always been GPL licensed. It was just missing the explicit declaration to avoid tainting the kernel. Signed-off-by: Bill Richardson Signed-off-by: Doug Anderson Signed-off-by: Lee Jones --- drivers/mfd/cros_ec.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index 783fe2e..fae69b1 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -184,3 +184,6 @@ int cros_ec_resume(struct cros_ec_device *ec_dev) EXPORT_SYMBOL(cros_ec_resume); #endif + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ChromeOS EC core driver"); -- cgit v1.1 From e349c910e2398cbff59d7c58851503191a8e9157 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 14 Apr 2014 09:40:45 +0200 Subject: mfd/rtc: s5m: Do not allocate RTC I2C dummy and regmap for unsupported chipsets The rtc-s5m driver does not support all of S2M and S5M chipsets supported by main MFD sec-core driver. For such chipsets unsupported by rtc-s5m, the MFD sec-core driver initialized regmap with default config. This config in such cases wouldn't work at all. The main MFD sec-core driver shouldn't initialize regmap for child drivers which is not used by them and even not valid. Move the allocation of RTC I2C dummy device and initialization of RTC regmap from main MFD sec-core driver to the rtc-s5m driver. The rtc-s5m driver will use proper regmap config for supported devices. Signed-off-by: Krzysztof Kozlowski Acked-by: Alessandro Zummo Signed-off-by: Lee Jones --- drivers/mfd/sec-core.c | 53 +------------------------------------------------- 1 file changed, 1 insertion(+), 52 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 1cf2752..d4682c6 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -196,20 +195,6 @@ static const struct regmap_config s5m8767_regmap_config = { .cache_type = REGCACHE_FLAT, }; -static const struct regmap_config s5m_rtc_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = SEC_RTC_REG_MAX, -}; - -static const struct regmap_config s2mps14_rtc_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - - .max_register = S2MPS_RTC_REG_MAX, -}; - #ifdef CONFIG_OF /* * Only the common platform data elements for s5m8767 are parsed here from the @@ -264,7 +249,7 @@ static int sec_pmic_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev); - const struct regmap_config *regmap, *regmap_rtc; + const struct regmap_config *regmap; struct sec_pmic_dev *sec_pmic; int ret; @@ -298,39 +283,21 @@ static int sec_pmic_probe(struct i2c_client *i2c, switch (sec_pmic->device_type) { case S2MPA01: regmap = &s2mpa01_regmap_config; - /* - * The rtc-s5m driver does not support S2MPA01 and there - * is no mfd_cell for S2MPA01 RTC device. - * However we must pass something to devm_regmap_init_i2c() - * so use S5M-like regmap config even though it wouldn't work. - */ - regmap_rtc = &s5m_rtc_regmap_config; break; case S2MPS11X: regmap = &s2mps11_regmap_config; - /* - * The rtc-s5m driver does not support S2MPS11 and there - * is no mfd_cell for S2MPS11 RTC device. - * However we must pass something to devm_regmap_init_i2c() - * so use S5M-like regmap config even though it wouldn't work. - */ - regmap_rtc = &s5m_rtc_regmap_config; break; case S2MPS14X: regmap = &s2mps14_regmap_config; - regmap_rtc = &s2mps14_rtc_regmap_config; break; case S5M8763X: regmap = &s5m8763_regmap_config; - regmap_rtc = &s5m_rtc_regmap_config; break; case S5M8767X: regmap = &s5m8767_regmap_config; - regmap_rtc = &s5m_rtc_regmap_config; break; default: regmap = &sec_regmap_config; - regmap_rtc = &s5m_rtc_regmap_config; break; } @@ -342,21 +309,6 @@ static int sec_pmic_probe(struct i2c_client *i2c, return ret; } - sec_pmic->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR); - if (!sec_pmic->rtc) { - dev_err(&i2c->dev, "Failed to allocate I2C for RTC\n"); - return -ENODEV; - } - i2c_set_clientdata(sec_pmic->rtc, sec_pmic); - - sec_pmic->regmap_rtc = devm_regmap_init_i2c(sec_pmic->rtc, regmap_rtc); - if (IS_ERR(sec_pmic->regmap_rtc)) { - ret = PTR_ERR(sec_pmic->regmap_rtc); - dev_err(&i2c->dev, "Failed to allocate RTC register map: %d\n", - ret); - goto err_regmap_rtc; - } - if (pdata && pdata->cfg_pmic_irq) pdata->cfg_pmic_irq(); @@ -403,8 +355,6 @@ static int sec_pmic_probe(struct i2c_client *i2c, err_mfd: sec_irq_exit(sec_pmic); -err_regmap_rtc: - i2c_unregister_device(sec_pmic->rtc); return ret; } @@ -414,7 +364,6 @@ static int sec_pmic_remove(struct i2c_client *i2c) mfd_remove_devices(sec_pmic->dev); sec_irq_exit(sec_pmic); - i2c_unregister_device(sec_pmic->rtc); return 0; } -- cgit v1.1 From 1ec93b9b176b3c4e065c326ccf40458fcc01e6c0 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 25 Apr 2014 09:24:21 +0800 Subject: mfd: rdc321x: Fix off-by-one for ngpio setting The valid gpio is GPIO0 ~ GPIO58, so ngpio should be 59. This patch also renames RDC321X_MAX_GPIO to RDC321X_NUM_GPIO because it actually means the number of available GPIOs. Signed-off-by: Axel Lin Acked-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/rdc321x-southbridge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/rdc321x-southbridge.c b/drivers/mfd/rdc321x-southbridge.c index c795697..6575585 100644 --- a/drivers/mfd/rdc321x-southbridge.c +++ b/drivers/mfd/rdc321x-southbridge.c @@ -38,7 +38,7 @@ static struct resource rdc321x_wdt_resource[] = { }; static struct rdc321x_gpio_pdata rdc321x_gpio_pdata = { - .max_gpios = RDC321X_MAX_GPIO, + .max_gpios = RDC321X_NUM_GPIO, }; static struct resource rdc321x_gpio_resources[] = { -- cgit v1.1 From d137be00ee017bc40e6027cb66d667a2e0b450fd Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 24 Apr 2014 18:27:25 +0100 Subject: mfd: core: Don't use devres functions before device is added The supply aliases for the MFD devices were being added using devres but the device hasn't been added at this point and as such we can't use devres. The MFD already has a function that removes devices this patch uses the non-devres versions of the supply alias functions and adds an unregister in mfd_remove_devices_fn. Reported-by: Carlo Caione Reported-by: Mark Brown Signed-off-by: Charles Keepax Reviewed-by: Mark Brown Signed-off-by: Lee Jones --- drivers/mfd/mfd-core.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 2676492..892d343 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -102,7 +102,7 @@ static int mfd_add_device(struct device *parent, int id, pdev->dev.dma_mask = parent->dma_mask; pdev->dev.dma_parms = parent->dma_parms; - ret = devm_regulator_bulk_register_supply_alias( + ret = regulator_bulk_register_supply_alias( &pdev->dev, cell->parent_supplies, parent, cell->parent_supplies, cell->num_parent_supplies); @@ -182,9 +182,9 @@ static int mfd_add_device(struct device *parent, int id, return 0; fail_alias: - devm_regulator_bulk_unregister_supply_alias(&pdev->dev, - cell->parent_supplies, - cell->num_parent_supplies); + regulator_bulk_unregister_supply_alias(&pdev->dev, + cell->parent_supplies, + cell->num_parent_supplies); fail_res: kfree(res); fail_device: @@ -238,6 +238,9 @@ static int mfd_remove_devices_fn(struct device *dev, void *c) pdev = to_platform_device(dev); cell = mfd_get_cell(pdev); + regulator_bulk_unregister_supply_alias(dev, cell->parent_supplies, + cell->num_parent_supplies); + /* find the base address of usage_count pointers (for freeing) */ if (!*usage_count || (cell->usage_count < *usage_count)) *usage_count = cell->usage_count; -- cgit v1.1 From 02d02728ea8bb33dee221d7dcfeb3022d7635927 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 1 Apr 2014 16:45:01 +0300 Subject: mfd: twl6040: Clear the interrupt ID register before requesting IRQ If for some reason the boot loader enabled the audpwron GPIO we will have pending IRQs to be handled. This seams to break twl6040 for some reason leading to non working i2c communication (i2c timeouts). Clearing the INTID register after we requested the audpwron GPIO (and set it to low) will ensure that the chip will operate normally in this case as well. Signed-off-by: Peter Ujfalusi Signed-off-by: Lee Jones --- drivers/mfd/twl6040.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index 6e88f25..03dbff3 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -679,6 +679,9 @@ static int twl6040_probe(struct i2c_client *client, GPIOF_OUT_INIT_LOW, "audpwron"); if (ret) goto gpio_err; + + /* Clear any pending interrupt */ + twl6040_reg_read(twl6040, TWL6040_REG_INTID); } ret = regmap_add_irq_chip(twl6040->regmap, twl6040->irq, IRQF_ONESHOT, -- cgit v1.1 From 11e38e11afcdd598d0978746924a001e3e7cb723 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 1 Apr 2014 16:44:59 +0300 Subject: mfd: twl6040: Select i2c fast mode as default with regmap patch All boards using twl6040 configures the i2c bus to 400KHz. While twl6040's defaults to normal mode (100KHz). So far twl6040 has no problem with i2c communication in this configuration it is safer to select fast i2c mode. Signed-off-by: Peter Ujfalusi Signed-off-by: Lee Jones --- drivers/mfd/twl6040.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index 03dbff3..cb37bb8 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -87,8 +87,13 @@ static struct reg_default twl6040_defaults[] = { }; static struct reg_default twl6040_patch[] = { - /* Select I2C bus access to dual access registers */ - { TWL6040_REG_ACCCTL, 0x09 }, + /* + * Select I2C bus access to dual access registers + * Interrupt register is cleared on read + * Select fast mode for i2c (400KHz) + */ + { TWL6040_REG_ACCCTL, + TWL6040_I2CSEL | TWL6040_INTCLRMODE | TWL6040_I2CMODE(1) }, }; -- cgit v1.1 From 68bab8662f49b9e158f1d32f11becd4e48c04079 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 3 Apr 2014 13:54:41 +0300 Subject: mfd: twl6040: Optional clk32k clock handling In certain boards the source for the clk32k clock can be gated. In these boards the clk32k clock can be provided to the driver and it is going to be enabled/disabled when it is needed. If the clk32k clock is not provided the driver will assume that it is always running. Signed-off-by: Peter Ujfalusi Signed-off-by: Lee Jones --- drivers/mfd/twl6040.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index cb37bb8..574774d 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -291,6 +291,8 @@ int twl6040_power(struct twl6040 *twl6040, int on) if (twl6040->power_count++) goto out; + clk_prepare_enable(twl6040->clk32k); + /* Allow writes to the chip */ regcache_cache_only(twl6040->regmap, false); @@ -346,6 +348,8 @@ int twl6040_power(struct twl6040 *twl6040, int on) twl6040->sysclk = 0; twl6040->mclk = 0; + + clk_disable_unprepare(twl6040->clk32k); } out: @@ -644,6 +648,12 @@ static int twl6040_probe(struct i2c_client *client, i2c_set_clientdata(client, twl6040); + twl6040->clk32k = devm_clk_get(&client->dev, "clk32k"); + if (IS_ERR(twl6040->clk32k)) { + dev_info(&client->dev, "clk32k is not handled\n"); + twl6040->clk32k = NULL; + } + twl6040->supplies[0].supply = "vio"; twl6040->supplies[1].supply = "v2v1"; ret = devm_regulator_bulk_get(&client->dev, TWL6040_NUM_SUPPLIES, -- cgit v1.1 From 006cea3aeced7f3d67fe2849da7724683853d87d Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 1 Apr 2014 16:45:00 +0300 Subject: mfd: twl6040: Move register patching earlier in probe Make sure that we patch the ACCCTL register as the first thing when the driver loads, thus configuring I2C fast mode and i2c access for dual access registers. Signed-off-by: Peter Ujfalusi Signed-off-by: Lee Jones --- drivers/mfd/twl6040.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index 574774d..12b314e 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -675,6 +675,9 @@ static int twl6040_probe(struct i2c_client *client, mutex_init(&twl6040->mutex); init_completion(&twl6040->ready); + regmap_register_patch(twl6040->regmap, twl6040_patch, + ARRAY_SIZE(twl6040_patch)); + twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV); if (twl6040->rev < 0) { dev_err(&client->dev, "Failed to read revision register: %d\n", @@ -725,10 +728,6 @@ static int twl6040_probe(struct i2c_client *client, goto readyirq_err; } - /* dual-access registers controlled by I2C only */ - regmap_register_patch(twl6040->regmap, twl6040_patch, - ARRAY_SIZE(twl6040_patch)); - /* * The main functionality of twl6040 to provide audio on OMAP4+ systems. * We can add the ASoC codec child whenever this driver has been loaded. -- cgit v1.1 From 9549b5ff001a8904372370d10be9a2f05e10eca5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 23 Apr 2014 16:13:05 +0200 Subject: mfd: sec-core: Remove duplicated device type from sec_pmic_dev The device type was stored in sec_pmic_dev state container twice: - unsigned long type (initialized from of_device_id or i2c_device_id) - int device_type (initialized as above or from board files when there is no DTS) The 'type' field was never used outside of probe so it can be safely removed. Change also the device_type in sec_pmic_dev and sec_platform_data to unsigned long to avoid any casts. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/sec-core.c | 5 +++-- drivers/mfd/sec-irq.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index d4682c6..09fd256 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -251,6 +251,7 @@ static int sec_pmic_probe(struct i2c_client *i2c, struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev); const struct regmap_config *regmap; struct sec_pmic_dev *sec_pmic; + unsigned long device_type; int ret; sec_pmic = devm_kzalloc(&i2c->dev, sizeof(struct sec_pmic_dev), @@ -262,7 +263,7 @@ static int sec_pmic_probe(struct i2c_client *i2c, sec_pmic->dev = &i2c->dev; sec_pmic->i2c = i2c; sec_pmic->irq = i2c->irq; - sec_pmic->type = sec_i2c_get_driver_data(i2c, id); + device_type = sec_i2c_get_driver_data(i2c, id); if (sec_pmic->dev->of_node) { pdata = sec_pmic_i2c_parse_dt_pdata(sec_pmic->dev); @@ -270,7 +271,7 @@ static int sec_pmic_probe(struct i2c_client *i2c, ret = PTR_ERR(pdata); return ret; } - pdata->device_type = sec_pmic->type; + pdata->device_type = device_type; } if (pdata) { sec_pmic->device_type = pdata->device_type; diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c index 64e7913..654e2c1 100644 --- a/drivers/mfd/sec-irq.c +++ b/drivers/mfd/sec-irq.c @@ -385,7 +385,7 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic) &sec_pmic->irq_data); break; default: - dev_err(sec_pmic->dev, "Unknown device type %d\n", + dev_err(sec_pmic->dev, "Unknown device type %lu\n", sec_pmic->device_type); return -EINVAL; } -- cgit v1.1 From 360d15d6ef6f6e69baac6672147f16e2ac8b4c81 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 22 Apr 2014 16:00:25 +0200 Subject: mfd: sec-core: Fix IRQ handling after resume if this is not a wakeup source During suspend the IRQ should be disabled even if this is not a wakeup source. This is a proper way of fixing the IRQ handling issue during resume (IRQ handler fails because I2C bus did not resume yet). When device is suspended and sec-core interrupt is signaled the irq chip will try to handle it regardless of wakeup source. Device could be woken up by different IRQ but still the IRQ handler will try to read the registers over I2C bus and fail because I2C bus won't be ready yet. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/sec-core.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 09fd256..01beae8 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -374,19 +374,18 @@ static int sec_pmic_suspend(struct device *dev) struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); - if (device_may_wakeup(dev)) { + if (device_may_wakeup(dev)) enable_irq_wake(sec_pmic->irq); - /* - * PMIC IRQ must be disabled during suspend for RTC alarm - * to work properly. - * When device is woken up from suspend by RTC Alarm, an - * interrupt occurs before resuming I2C bus controller. - * The interrupt is handled by regmap_irq_thread which tries - * to read RTC registers. This read fails (I2C is still - * suspended) and RTC Alarm interrupt is disabled. - */ - disable_irq(sec_pmic->irq); - } + /* + * PMIC IRQ must be disabled during suspend for RTC alarm + * to work properly. + * When device is woken up from suspend, an + * interrupt occurs before resuming I2C bus controller. + * The interrupt is handled by regmap_irq_thread which tries + * to read RTC registers. This read fails (I2C is still + * suspended) and RTC Alarm interrupt is disabled. + */ + disable_irq(sec_pmic->irq); return 0; } @@ -396,10 +395,9 @@ static int sec_pmic_resume(struct device *dev) struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); struct sec_pmic_dev *sec_pmic = i2c_get_clientdata(i2c); - if (device_may_wakeup(dev)) { + if (device_may_wakeup(dev)) disable_irq_wake(sec_pmic->irq); - enable_irq(sec_pmic->irq); - } + enable_irq(sec_pmic->irq); return 0; } -- cgit v1.1 From c4f725b52cde3b82d66d54201bc97fcd539bffc8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 22 Apr 2014 15:59:22 +0200 Subject: mfd: max14577: Fix IRQ handling after resume if this is not a wakeup source During suspend the IRQ should be disabled even if this is not a wakeup source. This is a proper way of fixing the IRQ handling issue during resume (IRQ handler fails because I2C bus did not resume yet). When device is suspended and max14577 interrupt is signaled the irq chip will try to handle it regardless of wakeup source. Device could be woken up by different IRQ but still the IRQ handler will try to read the registers over I2C bus and fail because I2C bus won't be ready yet: max14577 2-0025: Failed to read IRQ status: -5 Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/max14577.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c index 484d372..caaf50c 100644 --- a/drivers/mfd/max14577.c +++ b/drivers/mfd/max14577.c @@ -414,20 +414,18 @@ static int max14577_suspend(struct device *dev) struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); struct max14577 *max14577 = i2c_get_clientdata(i2c); - if (device_may_wakeup(dev)) { + if (device_may_wakeup(dev)) enable_irq_wake(max14577->irq); - /* - * MUIC IRQ must be disabled during suspend if this is - * a wake up source because it will be handled before - * resuming I2C. - * - * When device is woken up from suspend (e.g. by ADC change), - * an interrupt occurs before resuming I2C bus controller. - * Interrupt handler tries to read registers but this read - * will fail because I2C is still suspended. - */ - disable_irq(max14577->irq); - } + /* + * MUIC IRQ must be disabled during suspend because if it happens + * while suspended it will be handled before resuming I2C. + * + * When device is woken up from suspend (e.g. by ADC change), + * an interrupt occurs before resuming I2C bus controller. + * Interrupt handler tries to read registers but this read + * will fail because I2C is still suspended. + */ + disable_irq(max14577->irq); return 0; } @@ -437,10 +435,9 @@ static int max14577_resume(struct device *dev) struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); struct max14577 *max14577 = i2c_get_clientdata(i2c); - if (device_may_wakeup(dev)) { + if (device_may_wakeup(dev)) disable_irq_wake(max14577->irq); - enable_irq(max14577->irq); - } + enable_irq(max14577->irq); return 0; } -- cgit v1.1 From 3e87933a68dce6a27bf1006964f8c850e13140b5 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 8 Apr 2014 17:14:15 -0700 Subject: mfd: pm8921: Remove pm8xxx API now that sub-devices use regmap The pm8xxx read/write wrappers are no longer necessary now that all the sub-device drivers are using the regmap API. Remove it. Signed-off-by: Stephen Boyd Signed-off-by: Lee Jones --- drivers/mfd/pm8921-core.c | 123 +--------------------------------------------- 1 file changed, 2 insertions(+), 121 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c index b97a971..9595138 100644 --- a/drivers/mfd/pm8921-core.c +++ b/drivers/mfd/pm8921-core.c @@ -26,7 +26,6 @@ #include #include #include -#include #define SSBI_REG_ADDR_IRQ_BASE 0x1BB @@ -57,7 +56,6 @@ #define PM8921_NR_IRQS 256 struct pm_irq_chip { - struct device *dev; struct regmap *regmap; spinlock_t pm_irq_lock; struct irq_domain *irqdomain; @@ -67,11 +65,6 @@ struct pm_irq_chip { u8 config[0]; }; -struct pm8921 { - struct device *dev; - struct pm_irq_chip *irq_chip; -}; - static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp, unsigned int *ip) { @@ -255,55 +248,6 @@ static struct irq_chip pm8xxx_irq_chip = { .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, }; -/** - * pm8xxx_get_irq_stat - get the status of the irq line - * @chip: pointer to identify a pmic irq controller - * @irq: the irq number - * - * The pm8xxx gpio and mpp rely on the interrupt block to read - * the values on their pins. This function is to facilitate reading - * the status of a gpio or an mpp line. The caller has to convert the - * gpio number to irq number. - * - * RETURNS: - * an int indicating the value read on that line - */ -static int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq) -{ - int pmirq, rc; - unsigned int block, bits, bit; - unsigned long flags; - struct irq_data *irq_data = irq_get_irq_data(irq); - - pmirq = irq_data->hwirq; - - block = pmirq / 8; - bit = pmirq % 8; - - spin_lock_irqsave(&chip->pm_irq_lock, flags); - - rc = regmap_write(chip->regmap, SSBI_REG_ADDR_IRQ_BLK_SEL, block); - if (rc) { - pr_err("Failed Selecting block irq=%d pmirq=%d blk=%d rc=%d\n", - irq, pmirq, block, rc); - goto bail_out; - } - - rc = regmap_read(chip->regmap, SSBI_REG_ADDR_IRQ_RT_STATUS, &bits); - if (rc) { - pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n", - irq, pmirq, block, rc); - goto bail_out; - } - - rc = (bits & (1 << bit)) ? 1 : 0; - -bail_out: - spin_unlock_irqrestore(&chip->pm_irq_lock, flags); - - return rc; -} - static int pm8xxx_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hwirq) { @@ -324,56 +268,6 @@ static const struct irq_domain_ops pm8xxx_irq_domain_ops = { .map = pm8xxx_irq_domain_map, }; -static int pm8921_readb(const struct device *dev, u16 addr, u8 *val) -{ - const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); - const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data; - - return ssbi_read(pmic->dev->parent, addr, val, 1); -} - -static int pm8921_writeb(const struct device *dev, u16 addr, u8 val) -{ - const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); - const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data; - - return ssbi_write(pmic->dev->parent, addr, &val, 1); -} - -static int pm8921_read_buf(const struct device *dev, u16 addr, u8 *buf, - int cnt) -{ - const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); - const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data; - - return ssbi_read(pmic->dev->parent, addr, buf, cnt); -} - -static int pm8921_write_buf(const struct device *dev, u16 addr, u8 *buf, - int cnt) -{ - const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); - const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data; - - return ssbi_write(pmic->dev->parent, addr, buf, cnt); -} - -static int pm8921_read_irq_stat(const struct device *dev, int irq) -{ - const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); - const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data; - - return pm8xxx_get_irq_stat(pmic->irq_chip, irq); -} - -static struct pm8xxx_drvdata pm8921_drvdata = { - .pmic_readb = pm8921_readb, - .pmic_writeb = pm8921_writeb, - .pmic_read_buf = pm8921_read_buf, - .pmic_write_buf = pm8921_write_buf, - .pmic_read_irq_stat = pm8921_read_irq_stat, -}; - static const struct regmap_config ssbi_regmap_config = { .reg_bits = 16, .val_bits = 8, @@ -392,7 +286,6 @@ MODULE_DEVICE_TABLE(of, pm8921_id_table); static int pm8921_probe(struct platform_device *pdev) { - struct pm8921 *pmic; struct regmap *regmap; int irq, rc; unsigned int val; @@ -404,12 +297,6 @@ static int pm8921_probe(struct platform_device *pdev) if (irq < 0) return irq; - pmic = devm_kzalloc(&pdev->dev, sizeof(struct pm8921), GFP_KERNEL); - if (!pmic) { - pr_err("Cannot alloc pm8921 struct\n"); - return -ENOMEM; - } - regmap = devm_regmap_init(&pdev->dev, NULL, pdev->dev.parent, &ssbi_regmap_config); if (IS_ERR(regmap)) @@ -434,18 +321,13 @@ static int pm8921_probe(struct platform_device *pdev) pr_info("PMIC revision 2: %02X\n", val); rev |= val << BITS_PER_BYTE; - pmic->dev = &pdev->dev; - pm8921_drvdata.pm_chip_data = pmic; - platform_set_drvdata(pdev, &pm8921_drvdata); - chip = devm_kzalloc(&pdev->dev, sizeof(*chip) + sizeof(chip->config[0]) * nirqs, GFP_KERNEL); if (!chip) return -ENOMEM; - pmic->irq_chip = chip; - chip->dev = &pdev->dev; + platform_set_drvdata(pdev, chip); chip->regmap = regmap; chip->num_irqs = nirqs; chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8); @@ -481,8 +363,7 @@ static int pm8921_remove_child(struct device *dev, void *unused) static int pm8921_remove(struct platform_device *pdev) { int irq = platform_get_irq(pdev, 0); - struct pm8921 *pmic = pm8921_drvdata.pm_chip_data; - struct pm_irq_chip *chip = pmic->irq_chip; + struct pm_irq_chip *chip = platform_get_drvdata(pdev); device_for_each_child(&pdev->dev, NULL, pm8921_remove_child); irq_set_chained_handler(irq, NULL); -- cgit v1.1 From 45330bb434214c83841171eb4c591da74367a589 Mon Sep 17 00:00:00 2001 From: Pankaj Dubey Date: Wed, 30 Apr 2014 11:14:26 +0900 Subject: mfd: syscon: Allow property as NULL in syscon_regmap_lookup_by_phandle If we pass syscon device node itself as first parameter to this function there is no need to parse and find syscon device node. So by allowing "property" parameter as NULL allow syscon_regmap_lookup_by_phandle to consider passed argument "np" itself as a syscon device node "syscon_np". This will help us in avoiding addition of "syscon" property in a device node which points back to same device node in device tree. Signed-off-by: Pankaj Dubey Signed-off-by: Lee Jones --- drivers/mfd/syscon.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index dbea55d..b30f941 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -94,7 +94,11 @@ struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np, struct device_node *syscon_np; struct regmap *regmap; - syscon_np = of_parse_phandle(np, property, 0); + if (property) + syscon_np = of_parse_phandle(np, property, 0); + else + syscon_np = np; + if (!syscon_np) return ERR_PTR(-ENODEV); -- cgit v1.1 From cfb61a419630a810033f2777aba724ab6b1272b3 Mon Sep 17 00:00:00 2001 From: Carlo Caione Date: Thu, 1 May 2014 14:29:27 +0200 Subject: mfd: AXP20x: Add mfd driver for AXP20x PMIC This patch introduces the preliminary support for PMICs X-Powers AXP202 and AXP209. The AXP209 and AXP202 are the PMUs (Power Management Unit) used by A10, A13 and A20 SoCs and developed by X-Powers, a sister company of Allwinner. The core enables support for two subsystems: - PEK (Power Enable Key) - Regulators Signed-off-by: Carlo Caione Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 12 +++ drivers/mfd/Makefile | 1 + drivers/mfd/axp20x.c | 258 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 271 insertions(+) create mode 100644 drivers/mfd/axp20x.c (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index e166d71..c681741 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -67,6 +67,18 @@ config MFD_BCM590XX help Support for the BCM590xx PMUs from Broadcom +config MFD_AXP20X + bool "X-Powers AXP20X" + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ + depends on I2C=y + help + If you say Y here you get support for the X-Powers AXP202 and AXP209. + This driver include only the core APIs. You have to select individual + components like regulators or the PEK (Power Enable Key) under the + corresponding menus. + config MFD_CROS_EC tristate "ChromeOS Embedded Controller" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 2851275..1efecf2 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -102,6 +102,7 @@ obj-$(CONFIG_PMIC_DA9052) += da9052-irq.o 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_AXP20X) += axp20x.o obj-$(CONFIG_MFD_LP3943) += lp3943.o obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c new file mode 100644 index 0000000..dee6539 --- /dev/null +++ b/drivers/mfd/axp20x.c @@ -0,0 +1,258 @@ +/* + * axp20x.c - MFD core driver for the X-Powers AXP202 and AXP209 + * + * AXP20x comprises an adaptive USB-Compatible PWM charger, 2 BUCK DC-DC + * converters, 5 LDOs, multiple 12-bit ADCs of voltage, current and temperature + * as well as 4 configurable GPIOs. + * + * Author: Carlo Caione + * + * 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 +#include +#include + +#define AXP20X_OFF 0x80 + +static const struct regmap_range axp20x_writeable_ranges[] = { + regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE), + regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES), +}; + +static const struct regmap_range axp20x_volatile_ranges[] = { + regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE), +}; + +static const struct regmap_access_table axp20x_writeable_table = { + .yes_ranges = axp20x_writeable_ranges, + .n_yes_ranges = ARRAY_SIZE(axp20x_writeable_ranges), +}; + +static const struct regmap_access_table axp20x_volatile_table = { + .yes_ranges = axp20x_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges), +}; + +static struct resource axp20x_pek_resources[] = { + { + .name = "PEK_DBR", + .start = AXP20X_IRQ_PEK_RIS_EDGE, + .end = AXP20X_IRQ_PEK_RIS_EDGE, + .flags = IORESOURCE_IRQ, + }, { + .name = "PEK_DBF", + .start = AXP20X_IRQ_PEK_FAL_EDGE, + .end = AXP20X_IRQ_PEK_FAL_EDGE, + .flags = IORESOURCE_IRQ, + }, +}; + +static const struct regmap_config axp20x_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .wr_table = &axp20x_writeable_table, + .volatile_table = &axp20x_volatile_table, + .max_register = AXP20X_FG_RES, + .cache_type = REGCACHE_RBTREE, +}; + +#define AXP20X_IRQ(_irq, _off, _mask) \ + [AXP20X_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) } + +static const struct regmap_irq axp20x_regmap_irqs[] = { + AXP20X_IRQ(ACIN_OVER_V, 0, 7), + AXP20X_IRQ(ACIN_PLUGIN, 0, 6), + AXP20X_IRQ(ACIN_REMOVAL, 0, 5), + AXP20X_IRQ(VBUS_OVER_V, 0, 4), + AXP20X_IRQ(VBUS_PLUGIN, 0, 3), + AXP20X_IRQ(VBUS_REMOVAL, 0, 2), + AXP20X_IRQ(VBUS_V_LOW, 0, 1), + AXP20X_IRQ(BATT_PLUGIN, 1, 7), + AXP20X_IRQ(BATT_REMOVAL, 1, 6), + AXP20X_IRQ(BATT_ENT_ACT_MODE, 1, 5), + AXP20X_IRQ(BATT_EXIT_ACT_MODE, 1, 4), + AXP20X_IRQ(CHARG, 1, 3), + AXP20X_IRQ(CHARG_DONE, 1, 2), + AXP20X_IRQ(BATT_TEMP_HIGH, 1, 1), + AXP20X_IRQ(BATT_TEMP_LOW, 1, 0), + AXP20X_IRQ(DIE_TEMP_HIGH, 2, 7), + AXP20X_IRQ(CHARG_I_LOW, 2, 6), + AXP20X_IRQ(DCDC1_V_LONG, 2, 5), + AXP20X_IRQ(DCDC2_V_LONG, 2, 4), + AXP20X_IRQ(DCDC3_V_LONG, 2, 3), + AXP20X_IRQ(PEK_SHORT, 2, 1), + AXP20X_IRQ(PEK_LONG, 2, 0), + AXP20X_IRQ(N_OE_PWR_ON, 3, 7), + AXP20X_IRQ(N_OE_PWR_OFF, 3, 6), + AXP20X_IRQ(VBUS_VALID, 3, 5), + AXP20X_IRQ(VBUS_NOT_VALID, 3, 4), + AXP20X_IRQ(VBUS_SESS_VALID, 3, 3), + AXP20X_IRQ(VBUS_SESS_END, 3, 2), + AXP20X_IRQ(LOW_PWR_LVL1, 3, 1), + AXP20X_IRQ(LOW_PWR_LVL2, 3, 0), + AXP20X_IRQ(TIMER, 4, 7), + AXP20X_IRQ(PEK_RIS_EDGE, 4, 6), + AXP20X_IRQ(PEK_FAL_EDGE, 4, 5), + AXP20X_IRQ(GPIO3_INPUT, 4, 3), + AXP20X_IRQ(GPIO2_INPUT, 4, 2), + AXP20X_IRQ(GPIO1_INPUT, 4, 1), + AXP20X_IRQ(GPIO0_INPUT, 4, 0), +}; + +static const struct of_device_id axp20x_of_match[] = { + { .compatible = "x-powers,axp202", .data = (void *) AXP202_ID }, + { .compatible = "x-powers,axp209", .data = (void *) AXP209_ID }, + { }, +}; +MODULE_DEVICE_TABLE(of, axp20x_of_match); + +/* + * This is useless for OF-enabled devices, but it is needed by I2C subsystem + */ +static const struct i2c_device_id axp20x_i2c_id[] = { + { }, +}; +MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id); + +static const struct regmap_irq_chip axp20x_regmap_irq_chip = { + .name = "axp20x_irq_chip", + .status_base = AXP20X_IRQ1_STATE, + .ack_base = AXP20X_IRQ1_STATE, + .mask_base = AXP20X_IRQ1_EN, + .num_regs = 5, + .irqs = axp20x_regmap_irqs, + .num_irqs = ARRAY_SIZE(axp20x_regmap_irqs), + .mask_invert = true, + .init_ack_masked = true, +}; + +static const char * const axp20x_supplies[] = { + "acin", + "vin2", + "vin3", + "ldo24in", + "ldo3in", + "ldo5in", +}; + +static struct mfd_cell axp20x_cells[] = { + { + .name = "axp20x-pek", + .num_resources = ARRAY_SIZE(axp20x_pek_resources), + .resources = axp20x_pek_resources, + }, { + .name = "axp20x-regulator", + .parent_supplies = axp20x_supplies, + .num_parent_supplies = ARRAY_SIZE(axp20x_supplies), + }, +}; + +static struct axp20x_dev *axp20x_pm_power_off; +static void axp20x_power_off(void) +{ + regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL, + AXP20X_OFF); +} + +static int axp20x_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct axp20x_dev *axp20x; + const struct of_device_id *of_id; + int ret; + + axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL); + if (!axp20x) + return -ENOMEM; + + of_id = of_match_device(axp20x_of_match, &i2c->dev); + if (!of_id) { + dev_err(&i2c->dev, "Unable to setup AXP20X data\n"); + return -ENODEV; + } + axp20x->variant = (long) of_id->data; + + axp20x->i2c_client = i2c; + axp20x->dev = &i2c->dev; + dev_set_drvdata(axp20x->dev, axp20x); + + axp20x->regmap = devm_regmap_init_i2c(i2c, &axp20x_regmap_config); + if (IS_ERR(axp20x->regmap)) { + ret = PTR_ERR(axp20x->regmap); + dev_err(&i2c->dev, "regmap init failed: %d\n", ret); + return ret; + } + + ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq, + IRQF_ONESHOT | IRQF_SHARED, -1, + &axp20x_regmap_irq_chip, + &axp20x->regmap_irqc); + if (ret) { + dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret); + return ret; + } + + ret = mfd_add_devices(axp20x->dev, -1, axp20x_cells, + ARRAY_SIZE(axp20x_cells), NULL, 0, NULL); + + if (ret) { + dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret); + regmap_del_irq_chip(i2c->irq, axp20x->regmap_irqc); + return ret; + } + + if (!pm_power_off) { + axp20x_pm_power_off = axp20x; + pm_power_off = axp20x_power_off; + } + + dev_info(&i2c->dev, "AXP20X driver loaded\n"); + + return 0; +} + +static int axp20x_i2c_remove(struct i2c_client *i2c) +{ + struct axp20x_dev *axp20x = i2c_get_clientdata(i2c); + + if (axp20x == axp20x_pm_power_off) { + axp20x_pm_power_off = NULL; + pm_power_off = NULL; + } + + mfd_remove_devices(axp20x->dev); + regmap_del_irq_chip(axp20x->i2c_client->irq, axp20x->regmap_irqc); + + return 0; +} + +static struct i2c_driver axp20x_i2c_driver = { + .driver = { + .name = "axp20x", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(axp20x_of_match), + }, + .probe = axp20x_i2c_probe, + .remove = axp20x_i2c_remove, + .id_table = axp20x_i2c_id, +}; + +module_i2c_driver(axp20x_i2c_driver); + +MODULE_DESCRIPTION("PMIC MFD core driver for AXP20X"); +MODULE_AUTHOR("Carlo Caione "); +MODULE_LICENSE("GPL"); -- cgit v1.1 From ae6eee3c8bc38ef45f35e9ee492840ac3e5c103c Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 7 May 2014 17:24:05 +0900 Subject: mfd: sm501: Make of_device_id array const Make of_device_id array const, because all OF functions handle it as const. Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/sm501.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index e7dc441..81e6d09 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -1726,7 +1726,7 @@ static struct pci_driver sm501_pci_driver = { MODULE_ALIAS("platform:sm501"); -static struct of_device_id of_sm501_match_tbl[] = { +static const struct of_device_id of_sm501_match_tbl[] = { { .compatible = "smi,sm501", }, { /* end */ } }; -- cgit v1.1 From c0dfbfe2a7ca401aaadf00dbab4e597027125e11 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 7 May 2014 17:15:48 +0900 Subject: mfd: tps65910: Make of_device_id array const Make of_device_id array const, because all OF functions handle it as const. Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/tps65910.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 460a014..f9e42ea 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -379,7 +379,7 @@ err_sleep_init: } #ifdef CONFIG_OF -static struct of_device_id tps65910_of_match[] = { +static const struct of_device_id tps65910_of_match[] = { { .compatible = "ti,tps65910", .data = (void *)TPS65910}, { .compatible = "ti,tps65911", .data = (void *)TPS65911}, { }, -- cgit v1.1 From 153a4ff4d4880d483dfb601b95dabe4d3fe0ddc6 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 7 May 2014 17:22:28 +0900 Subject: mfd: tps6507x: Make of_device_id array const Make of_device_id array const, because all OF functions handle it as const. Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/tps6507x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/tps6507x.c b/drivers/mfd/tps6507x.c index 3b27482..a2e1990 100644 --- a/drivers/mfd/tps6507x.c +++ b/drivers/mfd/tps6507x.c @@ -119,7 +119,7 @@ static const struct i2c_device_id tps6507x_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, tps6507x_i2c_id); #ifdef CONFIG_OF -static struct of_device_id tps6507x_of_match[] = { +static const struct of_device_id tps6507x_of_match[] = { {.compatible = "ti,tps6507x", }, {}, }; -- cgit v1.1 From a58cc84cafa2376a2d5fcdb3d513327a2fb813c2 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 7 May 2014 17:23:15 +0900 Subject: mfd: tps6586x: Make of_device_id array const Make of_device_id array const, because all OF functions handle it as const. Signed-off-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/mfd/tps6586x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 835e554..8e1dbc4 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -444,7 +444,7 @@ static struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *clien return pdata; } -static struct of_device_id tps6586x_of_match[] = { +static const struct of_device_id tps6586x_of_match[] = { { .compatible = "ti,tps6586x", }, { }, }; -- cgit v1.1 From ac8320c471e187d7fdc90f807199ff77c116a668 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 6 May 2014 11:46:10 +0300 Subject: mfd: twl6040: Correct HPPLL configuration for 19.2 and 38.4 MHz mclk When the MCLK is 19.2 or 38.4 MHz the HPPLL need to be enabled and can be put in bypass mode. This will fix HPPLL use on boards with 19.2MHz mclk. Signed-off-by: Peter Ujfalusi Signed-off-by: Lee Jones --- drivers/mfd/twl6040.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index 12b314e..ae26d84 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -441,12 +441,9 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, TWL6040_HPLLENA; break; case 19200000: - /* - * PLL disabled - * (enable PLL if MCLK jitter quality - * doesn't meet specification) - */ - hppllctl |= TWL6040_MCLK_19200KHZ; + /* PLL enabled, bypass mode */ + hppllctl |= TWL6040_MCLK_19200KHZ | + TWL6040_HPLLBP | TWL6040_HPLLENA; break; case 26000000: /* PLL enabled, active mode */ @@ -454,9 +451,9 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, TWL6040_HPLLENA; break; case 38400000: - /* PLL enabled, active mode */ + /* PLL enabled, bypass mode */ hppllctl |= TWL6040_MCLK_38400KHZ | - TWL6040_HPLLENA; + TWL6040_HPLLBP | TWL6040_HPLLENA; break; default: dev_err(twl6040->dev, -- cgit v1.1 From a2ff8459f1f88283935e6bc3fb536820148c7d6a Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Thu, 1 May 2014 10:48:03 +0400 Subject: mfd: mc13xxx: Do not use platform data with devicetree This patch removes platform data usage for codec and touchscreen when driver is used with devicetree. This fixes possible "null pointer dereference" error if DTS uses "fsl,mc13xxx-uses-codec" or "fsl,mc13xxx-uses-touch" options. Signed-off-by: Alexander Shiyan Signed-off-by: Lee Jones --- drivers/mfd/mc13xxx-core.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index ddabc81..acf5dd7 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -673,21 +673,9 @@ int mc13xxx_common_init(struct device *dev) if (mc13xxx->flags & MC13XXX_USE_ADC) mc13xxx_add_subdevice(mc13xxx, "%s-adc"); - if (mc13xxx->flags & MC13XXX_USE_CODEC) { - if (pdata) - mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec", - pdata->codec, sizeof(*pdata->codec)); - else - mc13xxx_add_subdevice(mc13xxx, "%s-codec"); - } - if (mc13xxx->flags & MC13XXX_USE_RTC) mc13xxx_add_subdevice(mc13xxx, "%s-rtc"); - if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN) - mc13xxx_add_subdevice_pdata(mc13xxx, "%s-ts", - &pdata->touch, sizeof(pdata->touch)); - if (pdata) { mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator", &pdata->regulators, sizeof(pdata->regulators)); @@ -695,10 +683,20 @@ int mc13xxx_common_init(struct device *dev) pdata->leds, sizeof(*pdata->leds)); mc13xxx_add_subdevice_pdata(mc13xxx, "%s-pwrbutton", pdata->buttons, sizeof(*pdata->buttons)); + if (mc13xxx->flags & MC13XXX_USE_CODEC) + mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec", + pdata->codec, sizeof(*pdata->codec)); + if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN) + mc13xxx_add_subdevice_pdata(mc13xxx, "%s-ts", + &pdata->touch, sizeof(pdata->touch)); } else { mc13xxx_add_subdevice(mc13xxx, "%s-regulator"); mc13xxx_add_subdevice(mc13xxx, "%s-led"); mc13xxx_add_subdevice(mc13xxx, "%s-pwrbutton"); + if (mc13xxx->flags & MC13XXX_USE_CODEC) + mc13xxx_add_subdevice(mc13xxx, "%s-codec"); + if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN) + mc13xxx_add_subdevice(mc13xxx, "%s-ts"); } return 0; -- cgit v1.1 From b68ece3d8e7fa3ff0844b8dbafe287f776a6768a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 May 2014 12:58:51 +0200 Subject: mfd: max77686: Make of_device_id array const Array of struct of_device_id may be be const as expected by of_match_table field. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/max77686.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index e5fce76..ce869ac 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -47,7 +47,7 @@ static struct regmap_config max77686_regmap_config = { }; #ifdef CONFIG_OF -static struct of_device_id max77686_pmic_dt_match[] = { +static const struct of_device_id max77686_pmic_dt_match[] = { {.compatible = "maxim,max77686", .data = NULL}, {}, }; -- cgit v1.1 From f1eb2cb82e2ac000e55a40d96d20fd80b379c6c1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 May 2014 12:58:49 +0200 Subject: mfd: max8997: Make of_device_id array const Array of struct of_device_id may be be const as expected by both of_match_table field and of_match_node() call. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/max8997.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c index 8cf7a01..595364e 100644 --- a/drivers/mfd/max8997.c +++ b/drivers/mfd/max8997.c @@ -51,7 +51,7 @@ static const struct mfd_cell max8997_devs[] = { }; #ifdef CONFIG_OF -static struct of_device_id max8997_pmic_dt_match[] = { +static const struct of_device_id max8997_pmic_dt_match[] = { { .compatible = "maxim,max8997-pmic", .data = (void *)TYPE_MAX8997 }, {}, }; -- cgit v1.1 From bd6d35a62df9f04eeb5aa0860114add92eba208d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 May 2014 12:58:42 +0200 Subject: mfd: kempld-core: Make mfd_cell array const The kempld_devs (array of mfd_cells) can be safely made const. Signed-off-by: Krzysztof Kozlowski Acked-by: Kevin Strasser Signed-off-by: Lee Jones --- drivers/mfd/kempld-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c index 25c5ca6..f7ff018 100644 --- a/drivers/mfd/kempld-core.c +++ b/drivers/mfd/kempld-core.c @@ -86,7 +86,7 @@ enum kempld_cells { KEMPLD_UART, }; -static struct mfd_cell kempld_devs[] = { +static const struct mfd_cell kempld_devs[] = { [KEMPLD_I2C] = { .name = "kempld-i2c", }, -- cgit v1.1 From 5ce9a55bdfe204617dd850594682d0fb9a9a80ff Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 May 2014 12:58:52 +0200 Subject: mfd: max77693: Make of_device_id array const Array of struct of_device_id may be be const as expected by of_match_table field. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Chanwoo Choi Signed-off-by: Lee Jones --- drivers/mfd/max77693.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c index c5535f0..7e05428 100644 --- a/drivers/mfd/max77693.c +++ b/drivers/mfd/max77693.c @@ -243,7 +243,7 @@ static const struct dev_pm_ops max77693_pm = { }; #ifdef CONFIG_OF -static struct of_device_id max77693_dt_match[] = { +static const struct of_device_id max77693_dt_match[] = { { .compatible = "maxim,max77693" }, {}, }; -- cgit v1.1 From 488e90032064fa6fcd34d45400a9e45f58668bbc Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 May 2014 12:58:53 +0200 Subject: mfd: max8907: Make of_device_id array const Array of struct of_device_id may be be const as expected by of_match_table field. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/max8907.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/max8907.c b/drivers/mfd/max8907.c index 0774031..232749c 100644 --- a/drivers/mfd/max8907.c +++ b/drivers/mfd/max8907.c @@ -305,7 +305,7 @@ static int max8907_i2c_remove(struct i2c_client *i2c) } #ifdef CONFIG_OF -static struct of_device_id max8907_of_match[] = { +static const struct of_device_id max8907_of_match[] = { { .compatible = "maxim,max8907" }, { }, }; -- cgit v1.1 From 5785a97e3d977a68854be9702ba428dd4c1f7e74 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 May 2014 12:58:41 +0200 Subject: mfd: db8500-prcmu: Make mfd_cell array const mfd_add_devices() expects array of struct mfd_cell to be const. Signed-off-by: Krzysztof Kozlowski Acked-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/db8500-prcmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index b11fdd6..722c2ce 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -3112,7 +3112,7 @@ static int db8500_prcmu_register_ab8500(struct device *parent, { struct device_node *np; struct resource ab8500_resource; - struct mfd_cell ab8500_cell = { + const struct mfd_cell ab8500_cell = { .name = "ab8500-core", .of_compatible = "stericsson,ab8500", .id = AB8500_VERSION_AB8500, -- cgit v1.1 From e920574d7f2869c7be859a4e37da9305be98698e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 May 2014 12:58:48 +0200 Subject: mfd: max8998: Make of_device_id array const Array of struct of_device_id may be be const as expected by both of_match_table field and of_match_node() call. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/max8998.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index 592db06..a37cb74 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c @@ -132,7 +132,7 @@ int max8998_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask) EXPORT_SYMBOL(max8998_update_reg); #ifdef CONFIG_OF -static struct of_device_id max8998_dt_match[] = { +static const struct of_device_id max8998_dt_match[] = { { .compatible = "maxim,max8998", .data = (void *)TYPE_MAX8998 }, { .compatible = "national,lp3974", .data = (void *)TYPE_LP3974 }, { .compatible = "ti,lp3974", .data = (void *)TYPE_LP3974 }, -- cgit v1.1 From d1fb70e27b8617ec3280d4588b97ac581afa3ae4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 May 2014 12:58:45 +0200 Subject: mfd: wm8400-core: Make mfd_cell array const mfd_add_devices() expects array of struct mfd_cell to be const. Signed-off-by: Krzysztof Kozlowski Acked-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/wm8400-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index e5eae75..c6fb5d1 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c @@ -64,7 +64,7 @@ EXPORT_SYMBOL_GPL(wm8400_block_read); static int wm8400_register_codec(struct wm8400 *wm8400) { - struct mfd_cell cell = { + const struct mfd_cell cell = { .name = "wm8400-codec", .platform_data = wm8400, .pdata_size = sizeof(*wm8400), -- cgit v1.1 From df20b7c53430f7badbf8947a82cc7eef6de5c5f1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 May 2014 12:58:46 +0200 Subject: mfd: sec-core: Make of_device_id array const Array of struct of_device_id may be be const as expected by both of_match_table field and of_match_node() call. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/sec-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 01beae8..be06d0a 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -90,7 +90,7 @@ static const struct mfd_cell s2mpa01_devs[] = { }; #ifdef CONFIG_OF -static struct of_device_id sec_dt_match[] = { +static const struct of_device_id sec_dt_match[] = { { .compatible = "samsung,s5m8767-pmic", .data = (void *)S5M8767X, }, { -- cgit v1.1 From 8f7f62705efbcffa933897af267210cc216c1302 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 May 2014 12:58:39 +0200 Subject: mfd: max14577: Make of_device_id array const Array of struct of_device_id should be const as expected by both of_match_table field and of_match_device() call. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/max14577.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c index caaf50c..6c81590 100644 --- a/drivers/mfd/max14577.c +++ b/drivers/mfd/max14577.c @@ -57,7 +57,7 @@ static struct mfd_cell max77836_devs[] = { }, }; -static struct of_device_id max14577_dt_match[] = { +static const struct of_device_id max14577_dt_match[] = { { .compatible = "maxim,max14577", .data = (void *)MAXIM_DEVICE_TYPE_MAX14577, -- cgit v1.1 From 81cf4f2d988fbc199fcf4757147b39414188168e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 May 2014 12:58:43 +0200 Subject: mfd: lp3943: Make mfd_cell array const mfd_add_devices() expects array of struct mfd_cell to be const. Signed-off-by: Krzysztof Kozlowski Acked-by: Milo Kim Signed-off-by: Lee Jones --- drivers/mfd/lp3943.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/lp3943.c b/drivers/mfd/lp3943.c index e322268..335b930 100644 --- a/drivers/mfd/lp3943.c +++ b/drivers/mfd/lp3943.c @@ -62,7 +62,7 @@ static const struct lp3943_reg_cfg lp3943_mux_cfg[] = { { LP3943_REG_MUX3, 0xC0, 6 }, }; -static struct mfd_cell lp3943_devs[] = { +static const struct mfd_cell lp3943_devs[] = { { .name = "lp3943-pwm", .of_compatible = "ti,lp3943-pwm", -- cgit v1.1 From 92725493d276ee9789d1c05dd2970057fb7d7c22 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 May 2014 12:58:38 +0200 Subject: mfd: max14577: Make mfd_cell array const mfd_add_devices() expects array of struct mfd_cell to be const. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/max14577.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c index 6c81590..36de88d 100644 --- a/drivers/mfd/max14577.c +++ b/drivers/mfd/max14577.c @@ -26,7 +26,7 @@ #include #include -static struct mfd_cell max14577_devs[] = { +static const struct mfd_cell max14577_devs[] = { { .name = "max14577-muic", .of_compatible = "maxim,max14577-muic", @@ -38,7 +38,7 @@ static struct mfd_cell max14577_devs[] = { { .name = "max14577-charger", }, }; -static struct mfd_cell max77836_devs[] = { +static const struct mfd_cell max77836_devs[] = { { .name = "max77836-muic", .of_compatible = "maxim,max77836-muic", @@ -292,7 +292,7 @@ static int max14577_i2c_probe(struct i2c_client *i2c, struct device_node *np = i2c->dev.of_node; int ret = 0; const struct regmap_irq_chip *irq_chip; - struct mfd_cell *mfd_devs; + const struct mfd_cell *mfd_devs; unsigned int mfd_devs_size; int irq_flags; -- cgit v1.1 From 445603030cbda672ec86ad262312edc2be1cd811 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 May 2014 12:58:50 +0200 Subject: mfd: as3711: Make of_device_id array const Array of struct of_device_id may be be const as expected by of_match_table field. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/as3711.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/as3711.c b/drivers/mfd/as3711.c index ec684fc..d9706ed 100644 --- a/drivers/mfd/as3711.c +++ b/drivers/mfd/as3711.c @@ -114,7 +114,7 @@ static const struct regmap_config as3711_regmap_config = { }; #ifdef CONFIG_OF -static struct of_device_id as3711_of_match[] = { +static const struct of_device_id as3711_of_match[] = { {.compatible = "ams,as3711",}, {} }; -- cgit v1.1 From a7cfee818fd7c6852837d6447e2cecc4a52880ea Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 May 2014 12:58:47 +0200 Subject: mfd: omap-usb-host: Make of_device_id array const Array of struct of_device_id may be be const as expected by of_platform_populate() call. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/omap-usb-host.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 651e249..b48d80c 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -557,7 +557,7 @@ static int usbhs_omap_get_dt_pdata(struct device *dev, return 0; } -static struct of_device_id usbhs_child_match_table[] = { +static const struct of_device_id usbhs_child_match_table[] = { { .compatible = "ti,omap-ehci", }, { .compatible = "ti,omap-ohci", }, { } -- cgit v1.1 From 9031a939185b65f1d8eda2c8f7cd30472496dc9a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 May 2014 12:58:44 +0200 Subject: mfd: rtsx_usb: Make mfd_cell array const mfd_add_devices() expects array of struct mfd_cell to be const. Signed-off-by: Krzysztof Kozlowski Acked-by: Roger Tseng Signed-off-by: Lee Jones --- drivers/mfd/rtsx_usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/rtsx_usb.c b/drivers/mfd/rtsx_usb.c index 141ea52..6352bec 100644 --- a/drivers/mfd/rtsx_usb.c +++ b/drivers/mfd/rtsx_usb.c @@ -29,7 +29,7 @@ static int polling_pipe = 1; module_param(polling_pipe, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(polling_pipe, "polling pipe (0: ctl, 1: bulk)"); -static struct mfd_cell rtsx_usb_cells[] = { +static const struct mfd_cell rtsx_usb_cells[] = { [RTSX_USB_SD_CARD] = { .name = "rtsx_usb_sdmmc", .pdata_size = 0, -- cgit v1.1 From d58603cc304b717707e8f8ff05bf6aff9d9c82b5 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Fri, 9 May 2014 13:11:47 +0200 Subject: mfd: Add support for sun6i PRCM (Power/Reset/Clock Management) unit The PRCM (Power/Reset/Clock Management) block exposes several subdevices in different subsystems (clk, reset ...) Add basic support for the PRCM unit with clk (AR100, AHB0, and APB0 clks) and reset controller subdevices. Other subdevices might be added later (if needed). Signed-off-by: Boris BREZILLON Acked-by: Maxime Ripard Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 8 +++ drivers/mfd/Makefile | 1 + drivers/mfd/sun6i-prcm.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+) create mode 100644 drivers/mfd/sun6i-prcm.c (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index c681741..e56fb37 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -732,6 +732,14 @@ config MFD_STA2X11 select MFD_CORE select REGMAP_MMIO +config MFD_SUN6I_PRCM + bool "Allwinner A31 PRCM controller" + depends on ARCH_SUNXI + select MFD_CORE + help + Support for the PRCM (Power/Reset/Clock Management) unit available + in A31 SoC. + config MFD_SYSCON bool "System Controller Register R/W Based on Regmap" select REGMAP_MMIO diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 1efecf2..df7823c 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_MFD_STA2X11) += sta2x11-mfd.o obj-$(CONFIG_MFD_STMPE) += stmpe.o obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o obj-$(CONFIG_STMPE_SPI) += stmpe-spi.o +obj-$(CONFIG_MFD_SUN6I_PRCM) += sun6i-prcm.o obj-$(CONFIG_MFD_TC3589X) += tc3589x.o obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o diff --git a/drivers/mfd/sun6i-prcm.c b/drivers/mfd/sun6i-prcm.c new file mode 100644 index 0000000..718fc4d --- /dev/null +++ b/drivers/mfd/sun6i-prcm.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2014 Free Electrons + * + * License Terms: GNU General Public License v2 + * Author: Boris BREZILLON + * + * Allwinner PRCM (Power/Reset/Clock Management) driver + * + */ + +#include +#include +#include + +struct prcm_data { + int nsubdevs; + const struct mfd_cell *subdevs; +}; + +static const struct resource sun6i_a31_ar100_clk_res[] = { + { + .start = 0x0, + .end = 0x3, + .flags = IORESOURCE_MEM, + }, +}; + +static const struct resource sun6i_a31_apb0_clk_res[] = { + { + .start = 0xc, + .end = 0xf, + .flags = IORESOURCE_MEM, + }, +}; + +static const struct resource sun6i_a31_apb0_gates_clk_res[] = { + { + .start = 0x28, + .end = 0x2b, + .flags = IORESOURCE_MEM, + }, +}; + +static const struct resource sun6i_a31_apb0_rstc_res[] = { + { + .start = 0xb0, + .end = 0xb3, + .flags = IORESOURCE_MEM, + }, +}; + +static const struct mfd_cell sun6i_a31_prcm_subdevs[] = { + { + .name = "sun6i-a31-ar100-clk", + .of_compatible = "allwinner,sun6i-a31-ar100-clk", + .num_resources = ARRAY_SIZE(sun6i_a31_ar100_clk_res), + .resources = sun6i_a31_ar100_clk_res, + }, + { + .name = "sun6i-a31-apb0-clk", + .of_compatible = "allwinner,sun6i-a31-apb0-clk", + .num_resources = ARRAY_SIZE(sun6i_a31_apb0_clk_res), + .resources = sun6i_a31_apb0_clk_res, + }, + { + .name = "sun6i-a31-apb0-gates-clk", + .of_compatible = "allwinner,sun6i-a31-apb0-gates-clk", + .num_resources = ARRAY_SIZE(sun6i_a31_apb0_gates_clk_res), + .resources = sun6i_a31_apb0_gates_clk_res, + }, + { + .name = "sun6i-a31-apb0-clock-reset", + .of_compatible = "allwinner,sun6i-a31-clock-reset", + .num_resources = ARRAY_SIZE(sun6i_a31_apb0_rstc_res), + .resources = sun6i_a31_apb0_rstc_res, + }, +}; + +static const struct prcm_data sun6i_a31_prcm_data = { + .nsubdevs = ARRAY_SIZE(sun6i_a31_prcm_subdevs), + .subdevs = sun6i_a31_prcm_subdevs, +}; + +static const struct of_device_id sun6i_prcm_dt_ids[] = { + { + .compatible = "allwinner,sun6i-a31-prcm", + .data = &sun6i_a31_prcm_data, + }, + { /* sentinel */ }, +}; + +static int sun6i_prcm_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; + const struct prcm_data *data; + struct resource *res; + int ret; + + match = of_match_node(sun6i_prcm_dt_ids, np); + if (!match) + return -EINVAL; + + data = match->data; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "no prcm memory region provided\n"); + return -ENOENT; + } + + ret = mfd_add_devices(&pdev->dev, 0, data->subdevs, data->nsubdevs, + res, -1, NULL); + if (ret) { + dev_err(&pdev->dev, "failed to add subdevices\n"); + return ret; + } + + return 0; +} + +static struct platform_driver sun6i_prcm_driver = { + .driver = { + .name = "sun6i-prcm", + .owner = THIS_MODULE, + .of_match_table = sun6i_prcm_dt_ids, + }, + .probe = sun6i_prcm_probe, +}; +module_platform_driver(sun6i_prcm_driver); + +MODULE_AUTHOR("Boris BREZILLON "); +MODULE_DESCRIPTION("Allwinner sun6i PRCM driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.1 From dcc21cc09e3c22d0ede4e105afa8884eba293b58 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 3 Apr 2014 17:45:15 +0200 Subject: mfd: Add driver for Atmel Microcontroller on iPaq h3xxx This adds a driver for the Atmel Microcontroller found on the iPAQ h3xxx series. This device handles some keys, the touchscreen, and the battery monitoring. This is a port of a driver from handhelds.org 2.6.21 kernel, written by Alessandro Gardich based on Andrew Christians original HAL-driver. It has been heavily cleaned and converted to mfd-core by Dmitry Artamonow and rewritten again for the v3.x series kernels by Linus Walleij, bringing back some of the functionality lost from Andrew's original driver. Acked-by: Greg Kroah-Hartman Signed-off-by: Alessandro Gardich Signed-off-by: Dmitry Artamonow Signed-off-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 10 + drivers/mfd/Makefile | 1 + drivers/mfd/ipaq-micro.c | 482 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 493 insertions(+) create mode 100644 drivers/mfd/ipaq-micro.c (limited to 'drivers/mfd') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index e56fb37..60cef41 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -262,6 +262,16 @@ config MFD_INTEL_MSIC Passage) chip. This chip embeds audio, battery, GPIO, etc. devices used in Intel Medfield platforms. +config MFD_IPAQ_MICRO + bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support" + depends on SA1100_H3100 || SA1100_H3600 + select MFD_CORE + help + Select this to get support for the Microcontroller found in + the Compaq iPAQ handheld computers. This is an Atmel + AT90LS8535 microcontroller flashed with a special iPAQ + firmware using the custom protocol implemented in this driver. + config MFD_JANZ_CMODIO tristate "Janz CMOD-IO PCI MODULbus Carrier Board" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index df7823c..5dec445 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -168,3 +168,4 @@ obj-$(CONFIG_MFD_RETU) += retu-mfd.o obj-$(CONFIG_MFD_AS3711) += as3711.o obj-$(CONFIG_MFD_AS3722) += as3722.o obj-$(CONFIG_MFD_STW481X) += stw481x.o +obj-$(CONFIG_MFD_IPAQ_MICRO) += ipaq-micro.o diff --git a/drivers/mfd/ipaq-micro.c b/drivers/mfd/ipaq-micro.c new file mode 100644 index 0000000..1763d6d --- /dev/null +++ b/drivers/mfd/ipaq-micro.c @@ -0,0 +1,482 @@ +/* + * Compaq iPAQ h3xxx Atmel microcontroller companion support + * + * This is an Atmel AT90LS8535 with a special flashed-in firmware that + * implements the special protocol used by this driver. + * + * based on previous kernel 2.4 version by Andrew Christian + * Author : Alessandro Gardich + * Author : Dmitry Artamonow + * Author : Linus Walleij + * + * 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 +#include +#include +#include + +#include + +static void ipaq_micro_trigger_tx(struct ipaq_micro *micro) +{ + struct ipaq_micro_txdev *tx = µ->tx; + struct ipaq_micro_msg *msg = micro->msg; + int i, bp; + u8 checksum; + u32 val; + + bp = 0; + tx->buf[bp++] = CHAR_SOF; + + checksum = ((msg->id & 0x0f) << 4) | (msg->tx_len & 0x0f); + tx->buf[bp++] = checksum; + + for (i = 0; i < msg->tx_len; i++) { + tx->buf[bp++] = msg->tx_data[i]; + checksum += msg->tx_data[i]; + } + + tx->buf[bp++] = checksum; + tx->len = bp; + tx->index = 0; + print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_OFFSET, 16, 1, + tx->buf, tx->len, true); + + /* Enable interrupt */ + val = readl(micro->base + UTCR3); + val |= UTCR3_TIE; + writel(val, micro->base + UTCR3); +} + +int ipaq_micro_tx_msg(struct ipaq_micro *micro, struct ipaq_micro_msg *msg) +{ + unsigned long flags; + + dev_dbg(micro->dev, "TX msg: %02x, %d bytes\n", msg->id, msg->tx_len); + + spin_lock_irqsave(µ->lock, flags); + if (micro->msg) { + list_add_tail(&msg->node, µ->queue); + spin_unlock_irqrestore(µ->lock, flags); + return 0; + } + micro->msg = msg; + ipaq_micro_trigger_tx(micro); + spin_unlock_irqrestore(µ->lock, flags); + return 0; +} +EXPORT_SYMBOL(ipaq_micro_tx_msg); + +static void micro_rx_msg(struct ipaq_micro *micro, u8 id, int len, u8 *data) +{ + int i; + + dev_dbg(micro->dev, "RX msg: %02x, %d bytes\n", id, len); + + spin_lock(µ->lock); + switch (id) { + case MSG_VERSION: + case MSG_EEPROM_READ: + case MSG_EEPROM_WRITE: + case MSG_BACKLIGHT: + case MSG_NOTIFY_LED: + case MSG_THERMAL_SENSOR: + case MSG_BATTERY: + /* Handle synchronous messages */ + if (micro->msg && micro->msg->id == id) { + struct ipaq_micro_msg *msg = micro->msg; + + memcpy(msg->rx_data, data, len); + msg->rx_len = len; + complete(µ->msg->ack); + if (!list_empty(µ->queue)) { + micro->msg = list_entry(micro->queue.next, + struct ipaq_micro_msg, + node); + list_del_init(µ->msg->node); + ipaq_micro_trigger_tx(micro); + } else + micro->msg = NULL; + dev_dbg(micro->dev, "OK RX message 0x%02x\n", id); + } else { + dev_err(micro->dev, + "out of band RX message 0x%02x\n", id); + if(!micro->msg) + dev_info(micro->dev, "no message queued\n"); + else + dev_info(micro->dev, "expected message %02x\n", + micro->msg->id); + } + break; + case MSG_KEYBOARD: + if (micro->key) + micro->key(micro->key_data, len, data); + else + dev_dbg(micro->dev, "key message ignored, no handle \n"); + break; + case MSG_TOUCHSCREEN: + if (micro->ts) + micro->ts(micro->ts_data, len, data); + else + dev_dbg(micro->dev, "touchscreen message ignored, no handle \n"); + break; + default: + dev_err(micro->dev, + "unknown msg %d [%d] ", id, len); + for (i = 0; i < len; ++i) + pr_cont("0x%02x ", data[i]); + pr_cont("\n"); + } + spin_unlock(µ->lock); +} + +static void micro_process_char(struct ipaq_micro *micro, u8 ch) +{ + struct ipaq_micro_rxdev *rx = µ->rx; + + switch (rx->state) { + case STATE_SOF: /* Looking for SOF */ + if (ch == CHAR_SOF) + rx->state = STATE_ID; /* Next byte is the id and len */ + break; + case STATE_ID: /* Looking for id and len byte */ + rx->id = (ch & 0xf0) >> 4 ; + rx->len = (ch & 0x0f); + rx->index = 0; + rx->chksum = ch; + rx->state = (rx->len > 0) ? STATE_DATA : STATE_CHKSUM; + break; + case STATE_DATA: /* Looking for 'len' data bytes */ + rx->chksum += ch; + rx->buf[rx->index] = ch; + if (++rx->index == rx->len) + rx->state = STATE_CHKSUM; + break; + case STATE_CHKSUM: /* Looking for the checksum */ + if (ch == rx->chksum) + micro_rx_msg(micro, rx->id, rx->len, rx->buf); + rx->state = STATE_SOF; + break; + } +} + +static void micro_rx_chars(struct ipaq_micro *micro) +{ + u32 status, ch; + + while ((status = readl(micro->base + UTSR1)) & UTSR1_RNE) { + ch = readl(micro->base + UTDR); + if (status & UTSR1_PRE) + dev_err(micro->dev, "rx: parity error\n"); + else if (status & UTSR1_FRE) + dev_err(micro->dev, "rx: framing error\n"); + else if (status & UTSR1_ROR) + dev_err(micro->dev, "rx: overrun error\n"); + micro_process_char(micro, ch); + } +} + +static void ipaq_micro_get_version(struct ipaq_micro *micro) +{ + struct ipaq_micro_msg msg = { + .id = MSG_VERSION, + }; + + ipaq_micro_tx_msg_sync(micro, &msg); + if (msg.rx_len == 4) { + memcpy(micro->version, msg.rx_data, 4); + micro->version[4] = '\0'; + } else if (msg.rx_len == 9) { + memcpy(micro->version, msg.rx_data, 4); + micro->version[4] = '\0'; + /* Bytes 4-7 are "pack", byte 8 is "boot type" */ + } else { + dev_err(micro->dev, + "illegal version message %d bytes\n", msg.rx_len); + } +} + +static void ipaq_micro_eeprom_read(struct ipaq_micro *micro, + u8 address, u8 len, u8 *data) +{ + struct ipaq_micro_msg msg = { + .id = MSG_EEPROM_READ, + }; + u8 i; + + for (i = 0; i < len; i++) { + msg.tx_data[0] = address + i; + msg.tx_data[1] = 1; + msg.tx_len = 2; + ipaq_micro_tx_msg_sync(micro, &msg); + memcpy(data + (i * 2), msg.rx_data, 2); + } +} + +static char *ipaq_micro_str(u8 *wchar, u8 len) +{ + char retstr[256]; + u8 i; + + for (i = 0; i < len / 2; i++) + retstr[i] = wchar[i * 2]; + return kstrdup(retstr, GFP_KERNEL); +} + +static u16 ipaq_micro_to_u16(u8 *data) +{ + return data[1] << 8 | data[0]; +} + +static void ipaq_micro_eeprom_dump(struct ipaq_micro *micro) +{ + u8 dump[256]; + char *str; + + ipaq_micro_eeprom_read(micro, 0, 128, dump); + str = ipaq_micro_str(dump, 10); + if (str) { + dev_info(micro->dev, "HM version %s\n", str); + kfree(str); + } + str = ipaq_micro_str(dump+10, 40); + if (str) { + dev_info(micro->dev, "serial number: %s\n", str); + /* Feed the random pool with this */ + add_device_randomness(str, strlen(str)); + kfree(str); + } + str = ipaq_micro_str(dump+50, 20); + if (str) { + dev_info(micro->dev, "module ID: %s\n", str); + kfree(str); + } + str = ipaq_micro_str(dump+70, 10); + if (str) { + dev_info(micro->dev, "product revision: %s\n", str); + kfree(str); + } + dev_info(micro->dev, "product ID: %u\n", ipaq_micro_to_u16(dump+80)); + dev_info(micro->dev, "frame rate: %u fps\n", + ipaq_micro_to_u16(dump+82)); + dev_info(micro->dev, "page mode: %u\n", ipaq_micro_to_u16(dump+84)); + dev_info(micro->dev, "country ID: %u\n", ipaq_micro_to_u16(dump+86)); + dev_info(micro->dev, "color display: %s\n", + ipaq_micro_to_u16(dump+88) ? "yes" : "no"); + dev_info(micro->dev, "ROM size: %u MiB\n", ipaq_micro_to_u16(dump+90)); + dev_info(micro->dev, "RAM size: %u KiB\n", ipaq_micro_to_u16(dump+92)); + dev_info(micro->dev, "screen: %u x %u\n", + ipaq_micro_to_u16(dump+94), ipaq_micro_to_u16(dump+96)); + print_hex_dump(KERN_DEBUG, "eeprom: ", DUMP_PREFIX_OFFSET, 16, 1, + dump, 256, true); + +} + +static void micro_tx_chars(struct ipaq_micro *micro) +{ + struct ipaq_micro_txdev *tx = µ->tx; + u32 val; + + while ((tx->index < tx->len) && + (readl(micro->base + UTSR1) & UTSR1_TNF)) { + writel(tx->buf[tx->index], micro->base + UTDR); + tx->index++; + } + + /* Stop interrupts */ + val = readl(micro->base + UTCR3); + val &= ~UTCR3_TIE; + writel(val, micro->base + UTCR3); +} + +static void micro_reset_comm(struct ipaq_micro *micro) +{ + struct ipaq_micro_rxdev *rx = µ->rx; + u32 val; + + if (micro->msg) + complete(µ->msg->ack); + + /* Initialize Serial channel protocol frame */ + rx->state = STATE_SOF; /* Reset the state machine */ + + /* Set up interrupts */ + writel(0x01, micro->sdlc + 0x0); /* Select UART mode */ + + /* Clean up CR3 */ + writel(0x0, micro->base + UTCR3); + + /* Format: 8N1 */ + writel(UTCR0_8BitData | UTCR0_1StpBit, micro->base + UTCR0); + + /* Baud rate: 115200 */ + writel(0x0, micro->base + UTCR1); + writel(0x1, micro->base + UTCR2); + + /* Clear SR0 */ + writel(0xff, micro->base + UTSR0); + + /* Enable RX int, disable TX int */ + writel(UTCR3_TXE | UTCR3_RXE | UTCR3_RIE, micro->base + UTCR3); + val = readl(micro->base + UTCR3); + val &= ~UTCR3_TIE; + writel(val, micro->base + UTCR3); +} + +static irqreturn_t micro_serial_isr(int irq, void *dev_id) +{ + struct ipaq_micro *micro = dev_id; + struct ipaq_micro_txdev *tx = µ->tx; + u32 status; + + status = readl(micro->base + UTSR0); + do { + if (status & (UTSR0_RID | UTSR0_RFS)) { + if (status & UTSR0_RID) + /* Clear the Receiver IDLE bit */ + writel(UTSR0_RID, micro->base + UTSR0); + micro_rx_chars(micro); + } + + /* Clear break bits */ + if (status & (UTSR0_RBB | UTSR0_REB)) + writel(status & (UTSR0_RBB | UTSR0_REB), + micro->base + UTSR0); + + if (status & UTSR0_TFS) + micro_tx_chars(micro); + + status = readl(micro->base + UTSR0); + + } while (((tx->index < tx->len) && (status & UTSR0_TFS)) || + (status & (UTSR0_RFS | UTSR0_RID))); + + return IRQ_HANDLED; +} + +static struct mfd_cell micro_cells[] = { + { .name = "ipaq-micro-backlight", }, + { .name = "ipaq-micro-battery", }, + { .name = "ipaq-micro-keys", }, + { .name = "ipaq-micro-ts", }, + { .name = "ipaq-micro-leds", }, +}; + +static int micro_resume(struct device *dev) +{ + struct ipaq_micro *micro = dev_get_drvdata(dev); + + micro_reset_comm(micro); + mdelay(10); + + return 0; +} + +static int micro_probe(struct platform_device *pdev) +{ + struct ipaq_micro *micro; + struct resource *res; + int ret; + int irq; + + micro = devm_kzalloc(&pdev->dev, sizeof(*micro), GFP_KERNEL); + if (!micro) + return -ENOMEM; + + micro->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; + + micro->base = devm_request_and_ioremap(&pdev->dev, res); + if (!micro->base) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) + return -EINVAL; + + micro->sdlc = devm_request_and_ioremap(&pdev->dev, res); + if (!micro->sdlc) + return -ENOMEM; + + micro_reset_comm(micro); + + irq = platform_get_irq(pdev, 0); + if (!irq) + return -EINVAL; + ret = devm_request_irq(&pdev->dev, irq, micro_serial_isr, + IRQF_SHARED, "ipaq-micro", + micro); + if (ret) { + dev_err(&pdev->dev, "unable to grab serial port IRQ\n"); + return ret; + } else + dev_info(&pdev->dev, "grabbed serial port IRQ\n"); + + spin_lock_init(µ->lock); + INIT_LIST_HEAD(µ->queue); + platform_set_drvdata(pdev, micro); + + ret = mfd_add_devices(&pdev->dev, pdev->id, micro_cells, + ARRAY_SIZE(micro_cells), NULL, 0, NULL); + if (ret) { + dev_err(&pdev->dev, "error adding MFD cells"); + return ret; + } + + /* Check version */ + ipaq_micro_get_version(micro); + dev_info(&pdev->dev, "Atmel micro ASIC version %s\n", micro->version); + ipaq_micro_eeprom_dump(micro); + + return 0; +} + +static int micro_remove(struct platform_device *pdev) +{ + struct ipaq_micro *micro = platform_get_drvdata(pdev); + u32 val; + + mfd_remove_devices(&pdev->dev); + + val = readl(micro->base + UTCR3); + val &= ~(UTCR3_RXE | UTCR3_RIE); /* disable receive interrupt */ + val &= ~(UTCR3_TXE | UTCR3_TIE); /* disable transmit interrupt */ + writel(val, micro->base + UTCR3); + + return 0; +} + +static const struct dev_pm_ops micro_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(NULL, micro_resume) +}; + +static struct platform_driver micro_device_driver = { + .driver = { + .name = "ipaq-h3xxx-micro", + .pm = µ_dev_pm_ops, + }, + .probe = micro_probe, + .remove = micro_remove, + /* .shutdown = micro_suspend, // FIXME */ +}; +module_platform_driver(micro_device_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("driver for iPAQ Atmel micro core and backlight"); -- cgit v1.1 From 63c348cb2b9c41fad259e6471692927f95e61d27 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 14 May 2014 12:17:14 +0900 Subject: mfd: ipaq-micro: Use devm_ioremap_resource() Use devm_ioremap_resource() because devm_request_and_ioremap() is obsoleted by devm_ioremap_resource(). Signed-off-by: Jingoo Han Acked-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/ipaq-micro.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/ipaq-micro.c b/drivers/mfd/ipaq-micro.c index 1763d6d..5d08daf 100644 --- a/drivers/mfd/ipaq-micro.c +++ b/drivers/mfd/ipaq-micro.c @@ -403,17 +403,17 @@ static int micro_probe(struct platform_device *pdev) if (!res) return -EINVAL; - micro->base = devm_request_and_ioremap(&pdev->dev, res); - if (!micro->base) - return -ENOMEM; + micro->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(micro->base)) + return PTR_ERR(micro->base); res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!res) return -EINVAL; - micro->sdlc = devm_request_and_ioremap(&pdev->dev, res); - if (!micro->sdlc) - return -ENOMEM; + micro->sdlc = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(micro->sdlc)) + return PTR_ERR(micro->sdlc); micro_reset_comm(micro); -- cgit v1.1 From 165b1cb15591e1e7f7769b8e1c32a0aae7918fb4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 13 May 2014 12:58:40 +0200 Subject: mfd: ipaq-micro: Make mfd_cell array const mfd_add_devices() expects array of struct mfd_cell to be const. Signed-off-by: Krzysztof Kozlowski Acked-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/ipaq-micro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/ipaq-micro.c b/drivers/mfd/ipaq-micro.c index 5d08daf..7e50fe0 100644 --- a/drivers/mfd/ipaq-micro.c +++ b/drivers/mfd/ipaq-micro.c @@ -368,7 +368,7 @@ static irqreturn_t micro_serial_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static struct mfd_cell micro_cells[] = { +static const struct mfd_cell micro_cells[] = { { .name = "ipaq-micro-backlight", }, { .name = "ipaq-micro-battery", }, { .name = "ipaq-micro-keys", }, -- cgit v1.1 From 058c89019ff029ca0ac45d94397c4d979c93cf4a Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 19 May 2014 17:35:27 +0100 Subject: mfd: arizona: Add MICVDD to mapped regulators Currently, MICVDD only binds because it is both the regulator name and the consumer name and we will always match against the regulator name regardless of the consumer device. If the regulator was renamed using the init_data ASoC will no longer be able to locate the supply, as it will be looking on the CODEC device where as the MICVDD consumer is on the Arizona device. Add a mapping as we do for the other regulators. Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/arizona-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 07e6e27..cfc191a 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -583,6 +583,7 @@ static const char *wm5102_supplies[] = { "CPVDD", "SPKVDDL", "SPKVDDR", + "MICVDD", }; static const struct mfd_cell wm5102_devs[] = { -- cgit v1.1 From bcc36b40dbba0f9a48af5b19a2f61d972f131bfa Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 19 May 2014 17:35:28 +0100 Subject: mfd: wm8997: Add registers for high power mode Some output configurations can require a 50Mhz SYSCLK which requires DCVDD to be 1.8V. This patch adds the registers necessary for supporting this operational mode. Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/wm8997-tables.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/wm8997-tables.c b/drivers/mfd/wm8997-tables.c index 5aa8076..c9c6519 100644 --- a/drivers/mfd/wm8997-tables.c +++ b/drivers/mfd/wm8997-tables.c @@ -846,6 +846,7 @@ static bool wm8997_readable_register(struct device *dev, unsigned int reg) case ARIZONA_RATE_ESTIMATOR_3: case ARIZONA_RATE_ESTIMATOR_4: case ARIZONA_RATE_ESTIMATOR_5: + case ARIZONA_DYNAMIC_FREQUENCY_SCALING_1: case ARIZONA_FLL1_CONTROL_1: case ARIZONA_FLL1_CONTROL_2: case ARIZONA_FLL1_CONTROL_3: @@ -880,6 +881,7 @@ static bool wm8997_readable_register(struct device *dev, unsigned int reg) case ARIZONA_FLL2_GPIO_CLOCK: case ARIZONA_MIC_CHARGE_PUMP_1: case ARIZONA_LDO1_CONTROL_1: + case ARIZONA_LDO1_CONTROL_2: case ARIZONA_LDO2_CONTROL_1: case ARIZONA_MIC_BIAS_CTRL_1: case ARIZONA_MIC_BIAS_CTRL_2: -- cgit v1.1 From d1cb4cc9051110a0d4f6261e2e8e90398166a4c5 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 19 May 2014 17:35:29 +0100 Subject: mfd: arizona: Correct error message for addition of main IRQ chip Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/arizona-irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index 88758ab..17102f5 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -285,7 +285,7 @@ int arizona_irq_init(struct arizona *arizona) IRQF_ONESHOT, -1, irq, &arizona->irq_chip); if (ret != 0) { - dev_err(arizona->dev, "Failed to add AOD IRQs: %d\n", ret); + dev_err(arizona->dev, "Failed to add main IRQs: %d\n", ret); goto err_aod; } -- cgit v1.1 From 1fe368665b1499041919d78467147849989af7c9 Mon Sep 17 00:00:00 2001 From: David Hendricks Date: Wed, 30 Apr 2014 10:44:04 -0700 Subject: mfd: cros_ec: spi: Calculate delay between transfers correctly To avoid spamming the EC we calculate the time between the previous transfer and the current transfer and force a delay if the time delta is too small. However, a small miscalculation causes the delay period to be far too short. Most noticably this impacts commands with a long turnaround time such as EC firmware reads and writes. Signed-off-by: David Hendricks Signed-off-by: Doug Anderson Reviewed-by: Simon Glass Tested-by: Andrew Bresticker Tested-by: Stephen Warren Signed-off-by: Lee Jones --- drivers/mfd/cros_ec_spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c index 84af8d7..c185eb6 100644 --- a/drivers/mfd/cros_ec_spi.c +++ b/drivers/mfd/cros_ec_spi.c @@ -219,7 +219,7 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev, ktime_get_ts(&ts); delay = timespec_to_ns(&ts) - ec_spi->last_transfer_ns; if (delay < EC_SPI_RECOVERY_TIME_NS) - ndelay(delay); + ndelay(EC_SPI_RECOVERY_TIME_NS - delay); } /* Transmit phase - send our message */ -- cgit v1.1 From 362196e5d0832ce3c4e1df376c02cff812a2391b Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Wed, 30 Apr 2014 10:44:05 -0700 Subject: mfd: cros_ec: spi: Add mutex to cros_ec_spi The main transfer function for cros_ec_spi can be called by more than one client at a time. Make sure that those clients don't stomp on each other by locking the bus for the duration of the transfer function. Signed-off-by: Doug Anderson Reviewed-by: Simon Glass Tested-by: Andrew Bresticker Tested-by: Stephen Warren Signed-off-by: Lee Jones --- drivers/mfd/cros_ec_spi.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c index c185eb6..a2a605d 100644 --- a/drivers/mfd/cros_ec_spi.c +++ b/drivers/mfd/cros_ec_spi.c @@ -65,11 +65,13 @@ * if no record * @end_of_msg_delay: used to set the delay_usecs on the spi_transfer that * is sent when we want to turn off CS at the end of a transaction. + * @lock: mutex to ensure only one user of cros_ec_command_spi_xfer at a time */ struct cros_ec_spi { struct spi_device *spi; s64 last_transfer_ns; unsigned int end_of_msg_delay; + struct mutex lock; }; static void debug_packet(struct device *dev, const char *name, u8 *ptr, @@ -208,6 +210,13 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev, int ret = 0, final_ret; struct timespec ts; + /* + * We have the shared ec_dev buffer plus we do lots of separate spi_sync + * calls, so we need to make sure only one person is using this at a + * time. + */ + mutex_lock(&ec_spi->lock); + len = cros_ec_prepare_tx(ec_dev, ec_msg); dev_dbg(ec_dev->dev, "prepared, len=%d\n", len); @@ -260,7 +269,7 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev, ret = final_ret; if (ret < 0) { dev_err(ec_dev->dev, "spi transfer failed: %d\n", ret); - return ret; + goto exit; } /* check response error code */ @@ -269,14 +278,16 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev, dev_warn(ec_dev->dev, "command 0x%02x returned an error %d\n", ec_msg->cmd, ptr[0]); debug_packet(ec_dev->dev, "in_err", ptr, len); - return -EINVAL; + ret = -EINVAL; + goto exit; } len = ptr[1]; sum = ptr[0] + ptr[1]; if (len > ec_msg->in_len) { dev_err(ec_dev->dev, "packet too long (%d bytes, expected %d)", len, ec_msg->in_len); - return -ENOSPC; + ret = -ENOSPC; + goto exit; } /* copy response packet payload and compute checksum */ @@ -293,10 +304,14 @@ static int cros_ec_command_spi_xfer(struct cros_ec_device *ec_dev, dev_err(ec_dev->dev, "bad packet checksum, expected %02x, got %02x\n", sum, ptr[len + 2]); - return -EBADMSG; + ret = -EBADMSG; + goto exit; } - return 0; + ret = 0; +exit: + mutex_unlock(&ec_spi->lock); + return ret; } static void cros_ec_spi_dt_probe(struct cros_ec_spi *ec_spi, struct device *dev) @@ -327,6 +342,7 @@ static int cros_ec_spi_probe(struct spi_device *spi) if (ec_spi == NULL) return -ENOMEM; ec_spi->spi = spi; + mutex_init(&ec_spi->lock); ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL); if (!ec_dev) return -ENOMEM; -- cgit v1.1 From c9a81d67ce4c9cd9b73f8ec6dba827882555d47e Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Wed, 30 Apr 2014 10:44:06 -0700 Subject: mfd: cros_ec: spi: Make the cros_ec_spi timeout more reliable The cros_ec_spi transfer had two problems with its timeout code: 1. It looked at the timeout even in the case that it found valid data. 2. If the cros_ec_spi code got switched out for a while, it's possible it could get a timeout after a single loop. Let's be paranoid and make sure we do one last transfer after the timeout expires. Signed-off-by: Doug Anderson Reviewed-by: Simon Glass Tested-by: Andrew Bresticker Tested-by: Stephen Warren Signed-off-by: Lee Jones --- drivers/mfd/cros_ec_spi.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c index a2a605d..4f863c3 100644 --- a/drivers/mfd/cros_ec_spi.c +++ b/drivers/mfd/cros_ec_spi.c @@ -113,7 +113,9 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev, /* Receive data until we see the header byte */ deadline = jiffies + msecs_to_jiffies(EC_MSG_DEADLINE_MS); - do { + while (true) { + unsigned long start_jiffies = jiffies; + memset(&trans, 0, sizeof(trans)); trans.cs_change = 1; trans.rx_buf = ptr = ec_dev->din; @@ -134,12 +136,19 @@ static int cros_ec_spi_receive_response(struct cros_ec_device *ec_dev, break; } } + if (ptr != end) + break; - if (time_after(jiffies, deadline)) { + /* + * Use the time at the start of the loop as a timeout. This + * gives us one last shot at getting the transfer and is useful + * in case we got context switched out for a while. + */ + if (time_after(start_jiffies, deadline)) { dev_warn(ec_dev->dev, "EC failed to respond in time\n"); return -ETIMEDOUT; } - } while (ptr == end); + } /* * ptr now points to the header byte. Copy any valid data to the -- cgit v1.1 From 9c0b54a120348813de16be935d2e8a3e0e8e4a8b Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Wed, 30 Apr 2014 10:44:07 -0700 Subject: mfd: cros_ec: spi: Increase cros_ec_spi deadline from 5ms to 100ms We're adding i2c tunneling to the list of things that goes over cros_ec. i2c tunneling can be slooooooow, so increase our deadline to 100ms to account for that. Signed-off-by: Doug Anderson Reviewed-by: Simon Glass Tested-by: Andrew Bresticker Tested-by: Stephen Warren Signed-off-by: Lee Jones --- drivers/mfd/cros_ec_spi.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c index 4f863c3..0b8d328 100644 --- a/drivers/mfd/cros_ec_spi.c +++ b/drivers/mfd/cros_ec_spi.c @@ -39,14 +39,22 @@ #define EC_MSG_PREAMBLE_COUNT 32 /* - * We must get a response from the EC in 5ms. This is a very long - * time, but the flash write command can take 2-3ms. The EC command - * processing is currently not very fast (about 500us). We could - * look at speeding this up and making the flash write command a - * 'slow' command, requiring a GET_STATUS wait loop, like flash - * erase. - */ -#define EC_MSG_DEADLINE_MS 5 + * Allow for a long time for the EC to respond. We support i2c + * tunneling and support fairly long messages for the tunnel (249 + * bytes long at the moment). If we're talking to a 100 kHz device + * on the other end and need to transfer ~256 bytes, then we need: + * 10 us/bit * ~10 bits/byte * ~256 bytes = ~25ms + * + * We'll wait 4 times that to handle clock stretching and other + * paranoia. + * + * It's pretty unlikely that we'll really see a 249 byte tunnel in + * anything other than testing. If this was more common we might + * consider having slow commands like this require a GET_STATUS + * wait loop. The 'flash write' command would be another candidate + * for this, clocking in at 2-3ms. + */ +#define EC_MSG_DEADLINE_MS 100 /* * Time between raising the SPI chip select (for the end of a -- cgit v1.1 From 5271db29d7199fe0ffb303ca4bbbb1485bba28c3 Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Wed, 30 Apr 2014 10:44:08 -0700 Subject: mfd: cros_ec: Sync to the latest cros_ec_commands.h from EC sources This just updates include/linux/mfd/cros_ec_commands.h to match the latest EC version (which is the One True Source for such things). See [dianders: took today's ToT version from the Chromium OS EC; deleted references to cros_ec_dev and cros_ec_lpc since those aren't upstream yet] Signed-off-by: Bill Richardson Signed-off-by: Doug Anderson Reviewed-by: Simon Glass Tested-by: Andrew Bresticker Tested-by: Stephen Warren Signed-off-by: Lee Jones --- drivers/mfd/cros_ec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index fae69b1..8b6fb34 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -30,7 +30,7 @@ int cros_ec_prepare_tx(struct cros_ec_device *ec_dev, uint8_t *out; int csum, i; - BUG_ON(msg->out_len > EC_HOST_PARAM_SIZE); + BUG_ON(msg->out_len > EC_PROTO2_MAX_PARAM_SIZE); out = ec_dev->dout; out[0] = EC_CMD_VERSION0 + msg->version; out[1] = msg->cmd; -- cgit v1.1 From 9d230c9e4f4e67cb1c1cb9e0f6142da16b0f2796 Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Wed, 30 Apr 2014 10:44:09 -0700 Subject: i2c: ChromeOS EC tunnel driver On ARM Chromebooks we have a few devices that are accessed by both the AP (the main "Application Processor") and the EC (the Embedded Controller). These are: * The battery (sbs-battery). * The power management unit tps65090. On the original Samsung ARM Chromebook these devices were on an I2C bus that was shared between the AP and the EC and arbitrated using some extranal GPIOs (see i2c-arb-gpio-challenge). The original arbitration scheme worked well enough but had some downsides: * It was nonstandard (not using standard I2C multimaster) * It only worked if the EC-AP communication was I2C * It was relatively hard to debug problems (hard to tell if i2c issues were caused by the EC, the AP, or some device on the bus). On the HP Chromebook 11 the design was changed to: * The AP/EC comms were still i2c, but the battery/tps65090 were no longer on the bus used for AP/EC communication. The battery was exposed to the AP through a limited i2c tunnel and tps65090 was exposed to the AP through a custom Linux driver. On the Samsung ARM Chromebook 2 the scheme is changed yet again, now: * The AP/EC comms are now using SPI for faster speeds. * The EC's i2c bus is exposed to the AP through a full i2c tunnel. The upstream "tegra124-venice2" uses the same scheme as the Samsung ARM Chromebook 2, though it has a different set of components on the other side of the bus. This driver supports the scheme used by the Samsung ARM Chromebook 2. Future patches to this driver could add support for the battery tunnel on the HP Chromebook 11 (and perhaps could even be used to access tps65090 on the HP Chromebook 11 instead of using a special driver, but I haven't researched that enough). Signed-off-by: Vincent Palatin Signed-off-by: Simon Glass Signed-off-by: Doug Anderson Reviewed-by: Wolfram Sang Signed-off-by: Lee Jones --- drivers/mfd/cros_ec.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index 8b6fb34..38fe9bf 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -90,6 +90,11 @@ static const struct mfd_cell cros_devs[] = { .id = 1, .of_compatible = "google,cros-ec-keyb", }, + { + .name = "cros-ec-i2c-tunnel", + .id = 2, + .of_compatible = "google,cros-ec-i2c-tunnel", + }, }; int cros_ec_register(struct cros_ec_device *ec_dev) -- cgit v1.1 From fab8445c55abf35e055ef51a1b713899c0778b8a Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 20 May 2014 15:37:41 +0100 Subject: mfd: max14577: Cast to architecture agnostic data type drivers/mfd/max14577.c:334:25: warning: cast from pointer to integer of different size max14577->dev_type = (unsigned int)of_id->data; ^ Signed-off-by: Lee Jones --- drivers/mfd/max14577.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c index 36de88d..4a5e885 100644 --- a/drivers/mfd/max14577.c +++ b/drivers/mfd/max14577.c @@ -331,7 +331,8 @@ static int max14577_i2c_probe(struct i2c_client *i2c, of_id = of_match_device(max14577_dt_match, &i2c->dev); if (of_id) - max14577->dev_type = (unsigned int)of_id->data; + max14577->dev_type = + (enum maxim_device_type)of_id->data; } else { max14577->dev_type = id->driver_data; } -- cgit v1.1 From a9cd92acabcb8aca8431647005ed868b8c7644c9 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 20 May 2014 13:48:51 +0100 Subject: mfd: arizona: Correct addresses of always-on trigger registers Update the addresses and names to match current silicon. The WM8997 regmap tables have been adjusted to match the new names. Missing registers have been added to WM5110 default value table. Signed-off-by: Richard Fitzgerald Signed-off-by: Lee Jones --- drivers/mfd/wm5102-tables.c | 2 ++ drivers/mfd/wm5110-tables.c | 12 ++++++++---- drivers/mfd/wm8997-tables.c | 12 ++++++------ 3 files changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index 070f8cf..ada3286 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c @@ -1037,6 +1037,8 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg) case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_4: case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_5: case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_6: + case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_7: + case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_8: case ARIZONA_COMFORT_NOISE_GENERATOR: case ARIZONA_HAPTICS_CONTROL_1: case ARIZONA_HAPTICS_CONTROL_2: diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 58bc2be..41a7f6f 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -468,10 +468,12 @@ static const struct reg_default wm5110_reg_default[] = { { 0x00000062, 0x01FF }, /* R98 - Sample Rate Sequence Select 2 */ { 0x00000063, 0x01FF }, /* R99 - Sample Rate Sequence Select 3 */ { 0x00000064, 0x01FF }, /* R100 - Sample Rate Sequence Select 4 */ - { 0x00000068, 0x01FF }, /* R104 - Always On Triggers Sequence Select 1 */ - { 0x00000069, 0x01FF }, /* R105 - Always On Triggers Sequence Select 2 */ - { 0x0000006A, 0x01FF }, /* R106 - Always On Triggers Sequence Select 3 */ - { 0x0000006B, 0x01FF }, /* R107 - Always On Triggers Sequence Select 4 */ + { 0x00000066, 0x01FF }, /* R102 - Always On Triggers Sequence Select 1 */ + { 0x00000067, 0x01FF }, /* R103 - Always On Triggers Sequence Select 2 */ + { 0x00000068, 0x01FF }, /* R104 - Always On Triggers Sequence Select 3 */ + { 0x00000069, 0x01FF }, /* R105 - Always On Triggers Sequence Select 4 */ + { 0x0000006A, 0x01FF }, /* R106 - Always On Triggers Sequence Select 5 */ + { 0x0000006B, 0x01FF }, /* R107 - Always On Triggers Sequence Select 6 */ { 0x00000070, 0x0000 }, /* R112 - Comfort Noise Generator */ { 0x00000090, 0x0000 }, /* R144 - Haptics Control 1 */ { 0x00000091, 0x7FFF }, /* R145 - Haptics Control 2 */ @@ -1499,6 +1501,8 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_2: case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_3: case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_4: + case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_5: + case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_6: case ARIZONA_COMFORT_NOISE_GENERATOR: case ARIZONA_HAPTICS_CONTROL_1: case ARIZONA_HAPTICS_CONTROL_2: diff --git a/drivers/mfd/wm8997-tables.c b/drivers/mfd/wm8997-tables.c index c9c6519..c7a81da 100644 --- a/drivers/mfd/wm8997-tables.c +++ b/drivers/mfd/wm8997-tables.c @@ -174,10 +174,10 @@ static const struct reg_default wm8997_reg_default[] = { { 0x00000062, 0x01FF }, /* R98 - Sample Rate Sequence Select 2 */ { 0x00000063, 0x01FF }, /* R99 - Sample Rate Sequence Select 3 */ { 0x00000064, 0x01FF }, /* R100 - Sample Rate Sequence Select 4 */ - { 0x00000068, 0x01FF }, /* R104 - Always On Triggers Sequence Select 1 */ - { 0x00000069, 0x01FF }, /* R105 - Always On Triggers Sequence Select 2 */ - { 0x0000006A, 0x01FF }, /* R106 - Always On Triggers Sequence Select 3 */ - { 0x0000006B, 0x01FF }, /* R107 - Always On Triggers Sequence Select 4 */ + { 0x00000068, 0x01FF }, /* R104 - Always On Triggers Sequence Select 3 */ + { 0x00000069, 0x01FF }, /* R105 - Always On Triggers Sequence Select 4 */ + { 0x0000006A, 0x01FF }, /* R106 - Always On Triggers Sequence Select 5 */ + { 0x0000006B, 0x01FF }, /* R107 - Always On Triggers Sequence Select 6 */ { 0x00000070, 0x0000 }, /* R112 - Comfort Noise Generator */ { 0x00000090, 0x0000 }, /* R144 - Haptics Control 1 */ { 0x00000091, 0x7FFF }, /* R145 - Haptics Control 2 */ @@ -814,10 +814,10 @@ static bool wm8997_readable_register(struct device *dev, unsigned int reg) case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2: case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3: case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_4: - case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_1: - case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_2: case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_3: case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_4: + case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_5: + case ARIZONA_ALWAYS_ON_TRIGGERS_SEQUENCE_SELECT_6: case ARIZONA_COMFORT_NOISE_GENERATOR: case ARIZONA_HAPTICS_CONTROL_1: case ARIZONA_HAPTICS_CONTROL_2: -- cgit v1.1 From a22c514c6a8bf21663b2e0a5339cc461be2f01a2 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 22 May 2014 09:50:57 +0100 Subject: mfd: abx500-core: Remove unused function abx500_dump_all_banks() abx500_dump_all_banks() has no callers in the kernel, so it's probably safe to remove it. Cc: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/abx500-core.c | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/abx500-core.c b/drivers/mfd/abx500-core.c index d6d0ec4..fe41899 100644 --- a/drivers/mfd/abx500-core.c +++ b/drivers/mfd/abx500-core.c @@ -151,26 +151,6 @@ int abx500_startup_irq_enabled(struct device *dev, unsigned int irq) } EXPORT_SYMBOL(abx500_startup_irq_enabled); -int abx500_dump_all_banks(void) -{ - struct abx500_ops *ops; - struct device *dummy_child; - struct abx500_device_entry *dev_entry; - - dummy_child = kzalloc(sizeof(struct device), GFP_KERNEL); - if (!dummy_child) - return -ENOMEM; - list_for_each_entry(dev_entry, &abx500_list, list) { - dummy_child->parent = dev_entry->dev; - ops = &dev_entry->ops; - - if ((ops != NULL) && (ops->dump_all_banks != NULL)) - ops->dump_all_banks(dummy_child); - } - kfree(dummy_child); -} -EXPORT_SYMBOL(abx500_dump_all_banks); - MODULE_AUTHOR("Mattias Wallin "); MODULE_DESCRIPTION("ABX500 core driver"); MODULE_LICENSE("GPL"); -- cgit v1.1 From 23b02519aaefbc3ec5b8ff67ef71def6040e0a04 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Thu, 22 May 2014 22:55:31 +0200 Subject: mfd: db8500-prcmu: Remove check for CONFIG_DBX500_PRCMU_DEBUG A check for CONFIG_DBX500_PRCMU_DEBUG was added in v3.6. But there's no Kconfig symbol DBX500_PRCMU_DEBUG. So remove this check. Signed-off-by: Paul Bolle Signed-off-by: Lee Jones --- drivers/mfd/db8500-prcmu.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 722c2ce..193cf16 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -2300,9 +2300,6 @@ int prcmu_ac_wake_req(void) if (!wait_for_completion_timeout(&mb0_transfer.ac_wake_work, msecs_to_jiffies(5000))) { -#if defined(CONFIG_DBX500_PRCMU_DEBUG) - db8500_prcmu_debug_dump(__func__, true, true); -#endif pr_crit("prcmu: %s timed out (5 s) waiting for a reply.\n", __func__); ret = -EFAULT; -- cgit v1.1 From 8320513e8b4c815206b5cc60f92a71c9ca5c439e Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 23 May 2014 17:16:52 -0700 Subject: mfd: tps65218: Terminate of match table Failure to terminate this match table can lead to boot failures depending on where the compiler places the match table. Signed-off-by: Stephen Boyd Signed-off-by: Lee Jones --- drivers/mfd/tps65218.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/mfd') diff --git a/drivers/mfd/tps65218.c b/drivers/mfd/tps65218.c index a74bfb5..0d256cb 100644 --- a/drivers/mfd/tps65218.c +++ b/drivers/mfd/tps65218.c @@ -197,6 +197,7 @@ static struct regmap_irq_chip tps65218_irq_chip = { static const struct of_device_id of_tps65218_match_table[] = { { .compatible = "ti,tps65218", }, + {} }; static int tps65218_probe(struct i2c_client *client, -- cgit v1.1 From 1d3c7f56614dcd29c7819368cac2a9388fb13b69 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Thu, 29 May 2014 17:13:22 +0530 Subject: mfd: menelaus: Use module_i2c_driver module_i2c_driver simplifies the code by eliminating boilerplate code. Signed-off-by: Sachin Kamat Signed-off-by: Lee Jones --- drivers/mfd/menelaus.c | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c index ad25bfa..5e2667a 100644 --- a/drivers/mfd/menelaus.c +++ b/drivers/mfd/menelaus.c @@ -1287,29 +1287,8 @@ static struct i2c_driver menelaus_i2c_driver = { .id_table = menelaus_id, }; -static int __init menelaus_init(void) -{ - int res; - - res = i2c_add_driver(&menelaus_i2c_driver); - if (res < 0) { - pr_err(DRIVER_NAME ": driver registration failed\n"); - return res; - } - - return 0; -} - -static void __exit menelaus_exit(void) -{ - i2c_del_driver(&menelaus_i2c_driver); - - /* FIXME: Shutdown menelaus parts that can be shut down */ -} +module_i2c_driver(menelaus_i2c_driver); MODULE_AUTHOR("Texas Instruments, Inc. (and others)"); MODULE_DESCRIPTION("I2C interface for Menelaus."); MODULE_LICENSE("GPL"); - -module_init(menelaus_init); -module_exit(menelaus_exit); -- cgit v1.1 From 89abd4df28c6f85645e32f37ffab6426f800e4a1 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Thu, 29 May 2014 17:11:26 +0100 Subject: mfd: wm5102: Correct default for LDO Control 2 register Update the default value to match the patch. Signed-off-by: Richard Fitzgerald Signed-off-by: Lee Jones --- drivers/mfd/wm5102-tables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mfd') diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index ada3286..c8a993b 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c @@ -333,7 +333,7 @@ static const struct reg_default wm5102_reg_default[] = { { 0x000001AA, 0x0004 }, /* R426 - FLL2 GPIO Clock */ { 0x00000200, 0x0006 }, /* R512 - Mic Charge Pump 1 */ { 0x00000210, 0x00D4 }, /* R528 - LDO1 Control 1 */ - { 0x00000212, 0x0001 }, /* R530 - LDO1 Control 2 */ + { 0x00000212, 0x0000 }, /* R530 - LDO1 Control 2 */ { 0x00000213, 0x0344 }, /* R531 - LDO2 Control 1 */ { 0x00000218, 0x01A6 }, /* R536 - Mic Bias Ctrl 1 */ { 0x00000219, 0x01A6 }, /* R537 - Mic Bias Ctrl 2 */ -- cgit v1.1