diff options
Diffstat (limited to 'drivers/mfd')
45 files changed, 1016 insertions, 259 deletions
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 31ca55548ef9..eeb481d426b5 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -1150,17 +1150,17 @@ static int pm860x_probe(struct i2c_client *client, return -EINVAL; } - chip = kzalloc(sizeof(struct pm860x_chip), GFP_KERNEL); + chip = devm_kzalloc(&client->dev, + sizeof(struct pm860x_chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->id = verify_addr(client); - chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config); + chip->regmap = devm_regmap_init_i2c(client, &pm860x_regmap_config); if (IS_ERR(chip->regmap)) { ret = PTR_ERR(chip->regmap); dev_err(&client->dev, "Failed to allocate register map: %d\n", ret); - kfree(chip); return ret; } chip->client = client; @@ -1203,8 +1203,6 @@ static int pm860x_remove(struct i2c_client *client) regmap_exit(chip->regmap_companion); i2c_unregister_device(chip->companion); } - regmap_exit(chip->regmap); - kfree(chip); return 0; } diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d54e985748b7..c6eb930fb54d 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -53,7 +53,7 @@ config MFD_CROS_EC help If you say Y here you get support for the ChromeOS Embedded Controller (EC) providing keyboard, battery and power services. - You also ned to enable the driver for the bus you are using. The + You also need to enable the driver for the bus you are using. The protocol for talking to the EC is defined by the bus driver. config MFD_CROS_EC_I2C @@ -419,7 +419,8 @@ config MFD_PM8XXX config MFD_PM8921_CORE tristate "Qualcomm PM8921 PMIC chip" - depends on SSBI && BROKEN + depends on (ARCH_MSM || HEXAGON) + depends on BROKEN select MFD_CORE select MFD_PM8XXX help diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 718e94a2a9a7..31d0f97d6e50 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -140,7 +140,7 @@ obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o -obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o +obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o ssbi.o obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o obj-$(CONFIG_MFD_TPS65090) += tps65090.o diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c index dfdb0a2b6835..d4f594517521 100644 --- a/drivers/mfd/aat2870-core.c +++ b/drivers/mfd/aat2870-core.c @@ -312,8 +312,9 @@ static ssize_t aat2870_reg_write_file(struct file *file, while (*start == ' ') start++; - if (strict_strtoul(start, 16, &val)) - return -EINVAL; + ret = kstrtoul(start, 16, &val); + if (ret) + return ret; ret = aat2870->write(aat2870, (u8)addr, (u8)val); if (ret) diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index a9bb140bc86b..ddc669d19530 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -491,7 +491,7 @@ static ssize_t ab3100_get_set_reg(struct file *file, char buf[32]; ssize_t buf_size; int regp; - unsigned long user_reg; + u8 user_reg; int err; int i = 0; @@ -514,34 +514,29 @@ static ssize_t ab3100_get_set_reg(struct file *file, /* * Advance pointer to end of string then terminate * the register string. This is needed to satisfy - * the strict_strtoul() function. + * the kstrtou8() function. */ while ((i < buf_size) && (buf[i] != ' ')) i++; buf[i] = '\0'; - err = strict_strtoul(&buf[regp], 16, &user_reg); + err = kstrtou8(&buf[regp], 16, &user_reg); if (err) return err; - if (user_reg > 0xff) - return -EINVAL; /* Either we read or we write a register here */ if (!priv->mode) { /* Reading */ - u8 reg = (u8) user_reg; u8 regvalue; - ab3100_get_register_interruptible(ab3100, reg, ®value); + ab3100_get_register_interruptible(ab3100, user_reg, ®value); dev_info(ab3100->dev, "debug read AB3100 reg[0x%02x]: 0x%02x\n", - reg, regvalue); + user_reg, regvalue); } else { int valp; - unsigned long user_value; - u8 reg = (u8) user_reg; - u8 value; + u8 user_value; u8 regvalue; /* @@ -557,20 +552,17 @@ static ssize_t ab3100_get_set_reg(struct file *file, i++; buf[i] = '\0'; - err = strict_strtoul(&buf[valp], 16, &user_value); + err = kstrtou8(&buf[valp], 16, &user_value); if (err) return err; - if (user_reg > 0xff) - return -EINVAL; - value = (u8) user_value; - ab3100_set_register_interruptible(ab3100, reg, value); - ab3100_get_register_interruptible(ab3100, reg, ®value); + ab3100_set_register_interruptible(ab3100, user_reg, user_value); + ab3100_get_register_interruptible(ab3100, user_reg, ®value); dev_info(ab3100->dev, "debug write reg[0x%02x] with 0x%02x, " "after readback: 0x%02x\n", - reg, value, regvalue); + user_reg, user_value, regvalue); } return buf_size; } diff --git a/drivers/mfd/ab3100-otp.c b/drivers/mfd/ab3100-otp.c index d7ce016029fa..c9af16cc7310 100644 --- a/drivers/mfd/ab3100-otp.c +++ b/drivers/mfd/ab3100-otp.c @@ -187,7 +187,7 @@ static int __init ab3100_otp_probe(struct platform_device *pdev) int err = 0; int i; - otp = kzalloc(sizeof(struct ab3100_otp), GFP_KERNEL); + otp = devm_kzalloc(&pdev->dev, sizeof(struct ab3100_otp), GFP_KERNEL); if (!otp) { dev_err(&pdev->dev, "could not allocate AB3100 OTP device\n"); return -ENOMEM; @@ -199,7 +199,7 @@ static int __init ab3100_otp_probe(struct platform_device *pdev) err = ab3100_otp_read(otp); if (err) - goto err_otp_read; + return err; dev_info(&pdev->dev, "AB3100 OTP readout registered\n"); @@ -208,22 +208,19 @@ static int __init ab3100_otp_probe(struct platform_device *pdev) err = device_create_file(&pdev->dev, &ab3100_otp_attrs[i]); if (err) - goto err_create_file; + goto err; } /* debugfs entries */ err = ab3100_otp_init_debugfs(&pdev->dev, otp); if (err) - goto err_init_debugfs; + goto err; return 0; -err_init_debugfs: -err_create_file: +err: while (--i >= 0) device_remove_file(&pdev->dev, &ab3100_otp_attrs[i]); -err_otp_read: - kfree(otp); return err; } @@ -236,7 +233,6 @@ static int __exit ab3100_otp_remove(struct platform_device *pdev) device_remove_file(&pdev->dev, &ab3100_otp_attrs[i]); ab3100_otp_exit_debugfs(otp); - kfree(otp); return 0; } diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 258b367e3989..b6c2cdc76091 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -650,6 +650,21 @@ static struct resource ab8500_rtc_resources[] = { }, }; +static struct resource ab8540_rtc_resources[] = { + { + .name = "1S", + .start = AB8540_INT_RTC_1S, + .end = AB8540_INT_RTC_1S, + .flags = IORESOURCE_IRQ, + }, + { + .name = "ALARM", + .start = AB8500_INT_RTC_ALARM, + .end = AB8500_INT_RTC_ALARM, + .flags = IORESOURCE_IRQ, + }, +}; + static struct resource ab8500_poweronkey_db_resources[] = { { .name = "ONKEY_DBF", @@ -1051,6 +1066,10 @@ static struct mfd_cell ab8500_devs[] = { .of_compatible = "stericsson,ab8500-sysctrl", }, { + .name = "ab8500-ext-regulator", + .of_compatible = "stericsson,ab8500-ext-regulator", + }, + { .name = "ab8500-regulator", .of_compatible = "stericsson,ab8500-regulator", }, @@ -1099,10 +1118,6 @@ static struct mfd_cell ab8500_devs[] = { .id = 3, }, { - .name = "ab8500-leds", - .of_compatible = "stericsson,ab8500-leds", - }, - { .name = "ab8500-denc", .of_compatible = "stericsson,ab8500-denc", }, @@ -1124,6 +1139,7 @@ static struct mfd_cell ab8500_devs[] = { }, { .name = "ab8500-codec", + .of_compatible = "stericsson,ab8500-codec", }, }; @@ -1139,6 +1155,9 @@ static struct mfd_cell ab9540_devs[] = { .name = "ab8500-sysctrl", }, { + .name = "ab8500-ext-regulator", + }, + { .name = "ab8500-regulator", }, { @@ -1171,9 +1190,6 @@ static struct mfd_cell ab9540_devs[] = { .id = 1, }, { - .name = "ab8500-leds", - }, - { .name = "abx500-temp", .num_resources = ARRAY_SIZE(ab8500_temp_resources), .resources = ab8500_temp_resources, @@ -1242,9 +1258,6 @@ static struct mfd_cell ab8505_devs[] = { .id = 1, }, { - .name = "ab8500-leds", - }, - { .name = "pinctrl-ab8505", }, { @@ -1274,6 +1287,9 @@ static struct mfd_cell ab8540_devs[] = { .name = "ab8500-sysctrl", }, { + .name = "ab8500-ext-regulator", + }, + { .name = "ab8500-regulator", }, { @@ -1287,11 +1303,6 @@ static struct mfd_cell ab8540_devs[] = { .resources = ab8505_gpadc_resources, }, { - .name = "ab8500-rtc", - .num_resources = ARRAY_SIZE(ab8500_rtc_resources), - .resources = ab8500_rtc_resources, - }, - { .name = "ab8500-acc-det", .num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources), .resources = ab8500_av_acc_detect_resources, @@ -1306,9 +1317,6 @@ static struct mfd_cell ab8540_devs[] = { .id = 1, }, { - .name = "ab8500-leds", - }, - { .name = "abx500-temp", .num_resources = ARRAY_SIZE(ab8500_temp_resources), .resources = ab8500_temp_resources, @@ -1331,6 +1339,24 @@ static struct mfd_cell ab8540_devs[] = { }, }; +static struct mfd_cell ab8540_cut1_devs[] = { + { + .name = "ab8500-rtc", + .of_compatible = "stericsson,ab8500-rtc", + .num_resources = ARRAY_SIZE(ab8500_rtc_resources), + .resources = ab8500_rtc_resources, + }, +}; + +static struct mfd_cell ab8540_cut2_devs[] = { + { + .name = "ab8540-rtc", + .of_compatible = "stericsson,ab8540-rtc", + .num_resources = ARRAY_SIZE(ab8540_rtc_resources), + .resources = ab8540_rtc_resources, + }, +}; + static ssize_t show_chip_id(struct device *dev, struct device_attribute *attr, char *buf) { @@ -1734,11 +1760,22 @@ static int ab8500_probe(struct platform_device *pdev) ret = mfd_add_devices(ab8500->dev, 0, ab9540_devs, ARRAY_SIZE(ab9540_devs), NULL, ab8500->irq_base, ab8500->domain); - else if (is_ab8540(ab8500)) + else if (is_ab8540(ab8500)) { ret = mfd_add_devices(ab8500->dev, 0, ab8540_devs, ARRAY_SIZE(ab8540_devs), NULL, - ab8500->irq_base, ab8500->domain); - else if (is_ab8505(ab8500)) + ab8500->irq_base, NULL); + if (ret) + return ret; + + if (is_ab8540_1p2_or_earlier(ab8500)) + ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut1_devs, + ARRAY_SIZE(ab8540_cut1_devs), NULL, + ab8500->irq_base, NULL); + else /* ab8540 >= cut2 */ + ret = mfd_add_devices(ab8500->dev, 0, ab8540_cut2_devs, + ARRAY_SIZE(ab8540_cut2_devs), NULL, + ab8500->irq_base, NULL); + } else if (is_ab8505(ab8500)) ret = mfd_add_devices(ab8500->dev, 0, ab8505_devs, ARRAY_SIZE(ab8505_devs), NULL, ab8500->irq_base, ab8500->domain); diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index 37b7ce4c7c3b..7d1f1b08fc4b 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -2757,7 +2757,7 @@ static ssize_t show_irq(struct device *dev, unsigned int irq_index; int err; - err = strict_strtoul(attr->attr.name, 0, &name); + err = kstrtoul(attr->attr.name, 0, &name); if (err) return err; @@ -2937,7 +2937,6 @@ static struct dentry *ab8500_gpadc_dir; static int ab8500_debug_probe(struct platform_device *plf) { struct dentry *file; - int ret = -ENOMEM; struct ab8500 *ab8500; struct resource *res; debug_bank = AB8500_MISC; @@ -2946,24 +2945,26 @@ static int ab8500_debug_probe(struct platform_device *plf) ab8500 = dev_get_drvdata(plf->dev.parent); num_irqs = ab8500->mask_size; - irq_count = kzalloc(sizeof(*irq_count)*num_irqs, GFP_KERNEL); + irq_count = devm_kzalloc(&plf->dev, + sizeof(*irq_count)*num_irqs, GFP_KERNEL); if (!irq_count) return -ENOMEM; - dev_attr = kzalloc(sizeof(*dev_attr)*num_irqs,GFP_KERNEL); + dev_attr = devm_kzalloc(&plf->dev, + sizeof(*dev_attr)*num_irqs,GFP_KERNEL); if (!dev_attr) - goto out_freeirq_count; + return -ENOMEM; - event_name = kzalloc(sizeof(*event_name)*num_irqs, GFP_KERNEL); + event_name = devm_kzalloc(&plf->dev, + sizeof(*event_name)*num_irqs, GFP_KERNEL); if (!event_name) - goto out_freedev_attr; + return -ENOMEM; res = platform_get_resource_byname(plf, 0, "IRQ_AB8500"); if (!res) { dev_err(&plf->dev, "AB8500 irq not found, err %d\n", irq_first); - ret = -ENXIO; - goto out_freeevent_name; + return ENXIO; } irq_ab8500 = res->start; @@ -2971,16 +2972,14 @@ static int ab8500_debug_probe(struct platform_device *plf) if (irq_first < 0) { dev_err(&plf->dev, "First irq not found, err %d\n", irq_first); - ret = irq_first; - goto out_freeevent_name; + return irq_first; } irq_last = platform_get_irq_byname(plf, "IRQ_LAST"); if (irq_last < 0) { dev_err(&plf->dev, "Last irq not found, err %d\n", irq_last); - ret = irq_last; - goto out_freeevent_name; + return irq_last; } ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL); @@ -3189,22 +3188,13 @@ err: if (ab8500_dir) debugfs_remove_recursive(ab8500_dir); dev_err(&plf->dev, "failed to create debugfs entries.\n"); -out_freeevent_name: - kfree(event_name); -out_freedev_attr: - kfree(dev_attr); -out_freeirq_count: - kfree(irq_count); - return ret; + return -ENOMEM; } static int ab8500_debug_remove(struct platform_device *plf) { debugfs_remove_recursive(ab8500_dir); - kfree(event_name); - kfree(dev_attr); - kfree(irq_count); return 0; } diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index 13f7866de46e..f1d4565e6fb4 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c @@ -925,7 +925,7 @@ static int ab8500_gpadc_probe(struct platform_device *pdev) int ret = 0; struct ab8500_gpadc *gpadc; - gpadc = kzalloc(sizeof(struct ab8500_gpadc), GFP_KERNEL); + gpadc = devm_kzalloc(&pdev->dev, sizeof(struct ab8500_gpadc), GFP_KERNEL); if (!gpadc) { dev_err(&pdev->dev, "Error: No memory\n"); return -ENOMEM; @@ -1005,8 +1005,6 @@ fail_irq: free_irq(gpadc->irq_sw, gpadc); free_irq(gpadc->irq_hw, gpadc); fail: - kfree(gpadc); - gpadc = NULL; return ret; } @@ -1031,8 +1029,6 @@ static int ab8500_gpadc_remove(struct platform_device *pdev) pm_runtime_put_noidle(gpadc->dev); - kfree(gpadc); - gpadc = NULL; return 0; } diff --git a/drivers/mfd/abx500-core.c b/drivers/mfd/abx500-core.c index 3714acb61458..f3a15aa54d7b 100644 --- a/drivers/mfd/abx500-core.c +++ b/drivers/mfd/abx500-core.c @@ -36,7 +36,9 @@ int abx500_register_ops(struct device *dev, struct abx500_ops *ops) { struct abx500_device_entry *dev_entry; - dev_entry = kzalloc(sizeof(struct abx500_device_entry), GFP_KERNEL); + dev_entry = devm_kzalloc(dev, + sizeof(struct abx500_device_entry), + GFP_KERNEL); if (!dev_entry) { dev_err(dev, "register_ops kzalloc failed"); return -ENOMEM; @@ -54,12 +56,8 @@ void abx500_remove_ops(struct device *dev) struct abx500_device_entry *dev_entry, *tmp; list_for_each_entry_safe(dev_entry, tmp, &abx500_list, list) - { - if (dev_entry->dev == dev) { + if (dev_entry->dev == dev) list_del(&dev_entry->list); - kfree(dev_entry); - } - } } EXPORT_SYMBOL(abx500_remove_ops); diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c index 0d2eba023439..28346ad0b4a6 100644 --- a/drivers/mfd/adp5520.c +++ b/drivers/mfd/adp5520.c @@ -223,7 +223,7 @@ static int adp5520_probe(struct i2c_client *client, return -ENODEV; } - chip = kzalloc(sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; @@ -244,7 +244,7 @@ static int adp5520_probe(struct i2c_client *client, if (ret) { dev_err(&client->dev, "failed to request irq %d\n", chip->irq); - goto out_free_chip; + return ret; } } @@ -302,9 +302,6 @@ out_free_irq: if (chip->irq) free_irq(chip->irq, chip); -out_free_chip: - kfree(chip); - return ret; } @@ -317,7 +314,6 @@ static int adp5520_remove(struct i2c_client *client) adp5520_remove_subdevs(chip); adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0); - kfree(chip); return 0; } diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 6ab03043fd60..74b4481754fd 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -16,9 +16,13 @@ #include <linux/interrupt.h> #include <linux/mfd/core.h> #include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> +#include <linux/regulator/machine.h> #include <linux/slab.h> #include <linux/mfd/arizona/core.h> @@ -344,6 +348,17 @@ static int arizona_runtime_resume(struct device *dev) switch (arizona->type) { case WM5102: + if (arizona->external_dcvdd) { + ret = regmap_update_bits(arizona->regmap, + ARIZONA_ISOLATION_CONTROL, + ARIZONA_ISOLATE_DCVDD1, 0); + if (ret != 0) { + dev_err(arizona->dev, + "Failed to connect DCVDD: %d\n", ret); + goto err; + } + } + ret = wm5102_patch(arizona); if (ret != 0) { dev_err(arizona->dev, "Failed to apply patch: %d\n", @@ -365,6 +380,28 @@ static int arizona_runtime_resume(struct device *dev) goto err; } + if (arizona->external_dcvdd) { + ret = regmap_update_bits(arizona->regmap, + ARIZONA_ISOLATION_CONTROL, + ARIZONA_ISOLATE_DCVDD1, 0); + if (ret != 0) { + dev_err(arizona->dev, + "Failed to connect DCVDD: %d\n", ret); + goto err; + } + } + break; + } + + switch (arizona->type) { + case WM5102: + ret = wm5102_patch(arizona); + if (ret != 0) { + dev_err(arizona->dev, "Failed to apply patch: %d\n", + ret); + goto err; + } + default: break; } @@ -385,9 +422,22 @@ err: static int arizona_runtime_suspend(struct device *dev) { struct arizona *arizona = dev_get_drvdata(dev); + int ret; dev_dbg(arizona->dev, "Entering AoD mode\n"); + if (arizona->external_dcvdd) { + ret = regmap_update_bits(arizona->regmap, + ARIZONA_ISOLATION_CONTROL, + ARIZONA_ISOLATE_DCVDD1, + ARIZONA_ISOLATE_DCVDD1); + if (ret != 0) { + dev_err(arizona->dev, "Failed to isolate DCVDD: %d\n", + ret); + return ret; + } + } + regulator_disable(arizona->dcvdd); regcache_cache_only(arizona->regmap, true); regcache_mark_dirty(arizona->regmap); @@ -397,6 +447,26 @@ static int arizona_runtime_suspend(struct device *dev) #endif #ifdef CONFIG_PM_SLEEP +static int arizona_suspend(struct device *dev) +{ + struct arizona *arizona = dev_get_drvdata(dev); + + dev_dbg(arizona->dev, "Suspend, disabling IRQ\n"); + disable_irq(arizona->irq); + + return 0; +} + +static int arizona_suspend_late(struct device *dev) +{ + struct arizona *arizona = dev_get_drvdata(dev); + + dev_dbg(arizona->dev, "Late suspend, reenabling IRQ\n"); + enable_irq(arizona->irq); + + return 0; +} + static int arizona_resume_noirq(struct device *dev) { struct arizona *arizona = dev_get_drvdata(dev); @@ -422,13 +492,78 @@ const struct dev_pm_ops arizona_pm_ops = { SET_RUNTIME_PM_OPS(arizona_runtime_suspend, arizona_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(NULL, arizona_resume) + SET_SYSTEM_SLEEP_PM_OPS(arizona_suspend, arizona_resume) #ifdef CONFIG_PM_SLEEP + .suspend_late = arizona_suspend_late, .resume_noirq = arizona_resume_noirq, #endif }; EXPORT_SYMBOL_GPL(arizona_pm_ops); +#ifdef CONFIG_OF +int arizona_of_get_type(struct device *dev) +{ + const struct of_device_id *id = of_match_device(arizona_of_match, dev); + + if (id) + return (int)id->data; + else + return 0; +} +EXPORT_SYMBOL_GPL(arizona_of_get_type); + +static int arizona_of_get_core_pdata(struct arizona *arizona) +{ + int ret, i; + + arizona->pdata.reset = of_get_named_gpio(arizona->dev->of_node, + "wlf,reset", 0); + if (arizona->pdata.reset < 0) + arizona->pdata.reset = 0; + + arizona->pdata.ldoena = of_get_named_gpio(arizona->dev->of_node, + "wlf,ldoena", 0); + if (arizona->pdata.ldoena < 0) + arizona->pdata.ldoena = 0; + + ret = of_property_read_u32_array(arizona->dev->of_node, + "wlf,gpio-defaults", + arizona->pdata.gpio_defaults, + ARRAY_SIZE(arizona->pdata.gpio_defaults)); + if (ret >= 0) { + /* + * All values are literal except out of range values + * which are chip default, translate into platform + * data which uses 0 as chip default and out of range + * as zero. + */ + for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { + if (arizona->pdata.gpio_defaults[i] > 0xffff) + arizona->pdata.gpio_defaults[i] = 0; + if (arizona->pdata.gpio_defaults[i] == 0) + arizona->pdata.gpio_defaults[i] = 0x10000; + } + } else { + dev_err(arizona->dev, "Failed to parse GPIO defaults: %d\n", + ret); + } + + return 0; +} + +const struct of_device_id arizona_of_match[] = { + { .compatible = "wlf,wm5102", .data = (void *)WM5102 }, + { .compatible = "wlf,wm5110", .data = (void *)WM5110 }, + {}, +}; +EXPORT_SYMBOL_GPL(arizona_of_match); +#else +static inline int arizona_of_get_core_pdata(struct arizona *arizona) +{ + return 0; +} +#endif + static struct mfd_cell early_devs[] = { { .name = "arizona-ldo1" }, }; @@ -462,6 +597,8 @@ int arizona_dev_init(struct arizona *arizona) dev_set_drvdata(arizona->dev, arizona); mutex_init(&arizona->clk_lock); + arizona_of_get_core_pdata(arizona); + if (dev_get_platdata(arizona->dev)) memcpy(&arizona->pdata, dev_get_platdata(arizona->dev), sizeof(arizona->pdata)); @@ -536,51 +673,22 @@ int arizona_dev_init(struct arizona *arizona) regcache_cache_only(arizona->regmap, false); + /* Verify that this is a chip we know about */ ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); if (ret != 0) { dev_err(dev, "Failed to read ID register: %d\n", ret); goto err_reset; } - ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION, - &arizona->rev); - if (ret != 0) { - dev_err(dev, "Failed to read revision register: %d\n", ret); - goto err_reset; - } - arizona->rev &= ARIZONA_DEVICE_REVISION_MASK; - switch (reg) { -#ifdef CONFIG_MFD_WM5102 case 0x5102: - type_name = "WM5102"; - if (arizona->type != WM5102) { - dev_err(arizona->dev, "WM5102 registered as %d\n", - arizona->type); - arizona->type = WM5102; - } - apply_patch = wm5102_patch; - arizona->rev &= 0x7; - break; -#endif -#ifdef CONFIG_MFD_WM5110 case 0x5110: - type_name = "WM5110"; - if (arizona->type != WM5110) { - dev_err(arizona->dev, "WM5110 registered as %d\n", - arizona->type); - arizona->type = WM5110; - } - apply_patch = wm5110_patch; break; -#endif default: - dev_err(arizona->dev, "Unknown device ID %x\n", reg); + dev_err(arizona->dev, "Unknown device ID: %x\n", reg); goto err_reset; } - dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A'); - /* If we have a /RESET GPIO we'll already be reset */ if (!arizona->pdata.reset) { regcache_mark_dirty(arizona->regmap); @@ -600,6 +708,7 @@ int arizona_dev_init(struct arizona *arizona) } } + /* Ensure device startup is complete */ switch (arizona->type) { case WM5102: ret = regmap_read(arizona->regmap, 0x19, &val); @@ -620,6 +729,52 @@ int arizona_dev_init(struct arizona *arizona) break; } + /* Read the device ID information & do device specific stuff */ + ret = regmap_read(arizona->regmap, ARIZONA_SOFTWARE_RESET, ®); + if (ret != 0) { + dev_err(dev, "Failed to read ID register: %d\n", ret); + goto err_reset; + } + + ret = regmap_read(arizona->regmap, ARIZONA_DEVICE_REVISION, + &arizona->rev); + if (ret != 0) { + dev_err(dev, "Failed to read revision register: %d\n", ret); + goto err_reset; + } + arizona->rev &= ARIZONA_DEVICE_REVISION_MASK; + + switch (reg) { +#ifdef CONFIG_MFD_WM5102 + case 0x5102: + type_name = "WM5102"; + if (arizona->type != WM5102) { + dev_err(arizona->dev, "WM5102 registered as %d\n", + arizona->type); + arizona->type = WM5102; + } + apply_patch = wm5102_patch; + arizona->rev &= 0x7; + break; +#endif +#ifdef CONFIG_MFD_WM5110 + case 0x5110: + type_name = "WM5110"; + if (arizona->type != WM5110) { + dev_err(arizona->dev, "WM5110 registered as %d\n", + arizona->type); + arizona->type = WM5110; + } + apply_patch = wm5110_patch; + break; +#endif + default: + dev_err(arizona->dev, "Unknown device ID %x\n", reg); + goto err_reset; + } + + dev_info(dev, "%s revision %c\n", type_name, arizona->rev + 'A'); + if (apply_patch) { ret = apply_patch(arizona); if (ret != 0) { @@ -651,6 +806,14 @@ int arizona_dev_init(struct arizona *arizona) arizona->pdata.gpio_defaults[i]); } + /* + * LDO1 can only be used to supply DCVDD so if it has no + * consumers then DCVDD is supplied externally. + */ + if (arizona->pdata.ldo1 && + arizona->pdata.ldo1->num_consumer_supplies == 0) + arizona->external_dcvdd = true; + pm_runtime_set_autosuspend_delay(arizona->dev, 100); pm_runtime_use_autosuspend(arizona->dev); pm_runtime_enable(arizona->dev); @@ -697,7 +860,7 @@ int arizona_dev_init(struct arizona *arizona) if (arizona->pdata.micbias[i].discharge) val |= ARIZONA_MICB1_DISCH; - if (arizona->pdata.micbias[i].fast_start) + if (arizona->pdata.micbias[i].soft_start) val |= ARIZONA_MICB1_RATE; if (arizona->pdata.micbias[i].bypass) @@ -809,6 +972,11 @@ int arizona_dev_exit(struct arizona *arizona) arizona_free_irq(arizona, ARIZONA_IRQ_CLKGEN_ERR, arizona); pm_runtime_disable(arizona->dev); arizona_irq_exit(arizona); + if (arizona->pdata.reset) + gpio_set_value_cansleep(arizona->pdata.reset, 0); + regulator_disable(arizona->dcvdd); + regulator_bulk_disable(ARRAY_SIZE(arizona->core_supplies), + arizona->core_supplies); return 0; } EXPORT_SYMBOL_GPL(arizona_dev_exit); diff --git a/drivers/mfd/arizona-i2c.c b/drivers/mfd/arizona-i2c.c index 44a1bb969841..deb267ebf84e 100644 --- a/drivers/mfd/arizona-i2c.c +++ b/drivers/mfd/arizona-i2c.c @@ -27,9 +27,14 @@ static int arizona_i2c_probe(struct i2c_client *i2c, { struct arizona *arizona; const struct regmap_config *regmap_config; - int ret; + int ret, type; - switch (id->driver_data) { + if (i2c->dev.of_node) + type = arizona_of_get_type(&i2c->dev); + else + type = id->driver_data; + + switch (type) { #ifdef CONFIG_MFD_WM5102 case WM5102: regmap_config = &wm5102_i2c_regmap; @@ -84,6 +89,7 @@ static struct i2c_driver arizona_i2c_driver = { .name = "arizona", .owner = THIS_MODULE, .pm = &arizona_pm_ops, + .of_match_table = of_match_ptr(arizona_of_match), }, .probe = arizona_i2c_probe, .remove = arizona_i2c_remove, diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c index b57e642d2b4a..47be7b35b5c5 100644 --- a/drivers/mfd/arizona-spi.c +++ b/drivers/mfd/arizona-spi.c @@ -27,9 +27,14 @@ static int arizona_spi_probe(struct spi_device *spi) const struct spi_device_id *id = spi_get_device_id(spi); struct arizona *arizona; const struct regmap_config *regmap_config; - int ret; + int ret, type; - switch (id->driver_data) { + if (spi->dev.of_node) + type = arizona_of_get_type(&spi->dev); + else + type = id->driver_data; + + switch (type) { #ifdef CONFIG_MFD_WM5102 case WM5102: regmap_config = &wm5102_spi_regmap; @@ -84,6 +89,7 @@ static struct spi_driver arizona_spi_driver = { .name = "arizona", .owner = THIS_MODULE, .pm = &arizona_pm_ops, + .of_match_table = of_match_ptr(arizona_of_match), }, .probe = arizona_spi_probe, .remove = arizona_spi_remove, diff --git a/drivers/mfd/arizona.h b/drivers/mfd/arizona.h index 9798ae5da67b..db55d9854a55 100644 --- a/drivers/mfd/arizona.h +++ b/drivers/mfd/arizona.h @@ -13,6 +13,7 @@ #ifndef _WM5102_H #define _WM5102_H +#include <linux/of.h> #include <linux/regmap.h> #include <linux/pm.h> @@ -26,6 +27,8 @@ extern const struct regmap_config wm5110_spi_regmap; extern const struct dev_pm_ops arizona_pm_ops; +extern const struct of_device_id arizona_of_match[]; + extern const struct regmap_irq_chip wm5102_aod; extern const struct regmap_irq_chip wm5102_irq; @@ -37,4 +40,13 @@ int arizona_dev_exit(struct arizona *arizona); int arizona_irq_init(struct arizona *arizona); int arizona_irq_exit(struct arizona *arizona); +#ifdef CONFIG_OF +int arizona_of_get_type(struct device *dev); +#else +static inline int arizona_of_get_type(struct device *dev) +{ + return 0; +} +#endif + #endif diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 1b15986c01e1..9532f749412f 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -958,7 +958,8 @@ static int __init asic3_probe(struct platform_device *pdev) unsigned long clksel; int ret = 0; - asic = kzalloc(sizeof(struct asic3), GFP_KERNEL); + asic = devm_kzalloc(&pdev->dev, + sizeof(struct asic3), GFP_KERNEL); if (asic == NULL) { printk(KERN_ERR "kzalloc failed\n"); return -ENOMEM; @@ -970,16 +971,14 @@ static int __init asic3_probe(struct platform_device *pdev) mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { - ret = -ENOMEM; dev_err(asic->dev, "no MEM resource\n"); - goto out_free; + return -ENOMEM; } asic->mapping = ioremap(mem->start, resource_size(mem)); if (!asic->mapping) { - ret = -ENOMEM; dev_err(asic->dev, "Couldn't ioremap\n"); - goto out_free; + return -ENOMEM; } asic->irq_base = pdata->irq_base; @@ -1033,9 +1032,6 @@ static int __init asic3_probe(struct platform_device *pdev) out_unmap: iounmap(asic->mapping); - out_free: - kfree(asic); - return ret; } @@ -1058,8 +1054,6 @@ static int asic3_remove(struct platform_device *pdev) iounmap(asic->mapping); - kfree(asic); - return 0; } diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index 10cd14e35eb0..1f36885d674b 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -104,23 +104,19 @@ int cros_ec_register(struct cros_ec_device *ec_dev) ec_dev->command_sendrecv = cros_ec_command_sendrecv; if (ec_dev->din_size) { - ec_dev->din = kmalloc(ec_dev->din_size, GFP_KERNEL); - if (!ec_dev->din) { - err = -ENOMEM; - goto fail_din; - } + ec_dev->din = devm_kzalloc(dev, ec_dev->din_size, GFP_KERNEL); + if (!ec_dev->din) + return -ENOMEM; } if (ec_dev->dout_size) { - ec_dev->dout = kmalloc(ec_dev->dout_size, GFP_KERNEL); - if (!ec_dev->dout) { - err = -ENOMEM; - goto fail_dout; - } + ec_dev->dout = devm_kzalloc(dev, ec_dev->dout_size, GFP_KERNEL); + if (!ec_dev->dout) + return -ENOMEM; } if (!ec_dev->irq) { dev_dbg(dev, "no valid IRQ: %d\n", ec_dev->irq); - goto fail_irq; + return err; } err = request_threaded_irq(ec_dev->irq, NULL, ec_irq_thread, @@ -128,7 +124,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev) "chromeos-ec", ec_dev); if (err) { dev_err(dev, "request irq %d: error %d\n", ec_dev->irq, err); - goto fail_irq; + return err; } err = mfd_add_devices(dev, 0, cros_devs, @@ -145,11 +141,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev) fail_mfd: free_irq(ec_dev->irq, ec_dev); -fail_irq: - kfree(ec_dev->dout); -fail_dout: - kfree(ec_dev->din); -fail_din: + return err; } EXPORT_SYMBOL(cros_ec_register); @@ -158,8 +150,6 @@ int cros_ec_remove(struct cros_ec_device *ec_dev) { mfd_remove_devices(ec_dev->dev); free_irq(ec_dev->irq, ec_dev); - kfree(ec_dev->dout); - kfree(ec_dev->din); return 0; } diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c index c60ab0c3c4db..b6e297363946 100644 --- a/drivers/mfd/davinci_voicecodec.c +++ b/drivers/mfd/davinci_voicecodec.c @@ -50,7 +50,8 @@ static int __init davinci_vc_probe(struct platform_device *pdev) struct mfd_cell *cell = NULL; int ret; - davinci_vc = kzalloc(sizeof(struct davinci_vc), GFP_KERNEL); + davinci_vc = devm_kzalloc(&pdev->dev, + sizeof(struct davinci_vc), GFP_KERNEL); if (!davinci_vc) { dev_dbg(&pdev->dev, "could not allocate memory for private data\n"); @@ -61,8 +62,7 @@ static int __init davinci_vc_probe(struct platform_device *pdev) if (IS_ERR(davinci_vc->clk)) { dev_dbg(&pdev->dev, "could not get the clock for voice codec\n"); - ret = -ENODEV; - goto fail1; + return -ENODEV; } clk_enable(davinci_vc->clk); @@ -145,8 +145,6 @@ fail2: clk_disable(davinci_vc->clk); clk_put(davinci_vc->clk); davinci_vc->clk = NULL; -fail1: - kfree(davinci_vc); return ret; } @@ -164,8 +162,6 @@ static int davinci_vc_remove(struct platform_device *pdev) clk_put(davinci_vc->clk); davinci_vc->clk = NULL; - kfree(davinci_vc); - return 0; } diff --git a/drivers/mfd/dbx500-prcmu-regs.h b/drivers/mfd/dbx500-prcmu-regs.h index d14836ed2114..7cc32a8ff01c 100644 --- a/drivers/mfd/dbx500-prcmu-regs.h +++ b/drivers/mfd/dbx500-prcmu-regs.h @@ -16,8 +16,8 @@ #define BITS(_start, _end) ((BIT(_end) - BIT(_start)) + BIT(_end)) #define PRCM_ACLK_MGT (0x004) -#define PRCM_SVACLK_MGT (0x008) -#define PRCM_SIACLK_MGT (0x00C) +#define PRCM_SVAMMCSPCLK_MGT (0x008) +#define PRCM_SIAMMDSPCLK_MGT (0x00C) #define PRCM_SGACLK_MGT (0x014) #define PRCM_UARTCLK_MGT (0x018) #define PRCM_MSP02CLK_MGT (0x01C) diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c index bbaec0ccba8f..f2e0ad4b332e 100644 --- a/drivers/mfd/htc-egpio.c +++ b/drivers/mfd/htc-egpio.c @@ -270,7 +270,7 @@ static int __init egpio_probe(struct platform_device *pdev) int ret; /* Initialize ei data structure. */ - ei = kzalloc(sizeof(*ei), GFP_KERNEL); + ei = devm_kzalloc(&pdev->dev, sizeof(*ei), GFP_KERNEL); if (!ei) return -ENOMEM; @@ -306,7 +306,9 @@ static int __init egpio_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ei); ei->nchips = pdata->num_chips; - ei->chip = kzalloc(sizeof(struct egpio_chip) * ei->nchips, GFP_KERNEL); + ei->chip = devm_kzalloc(&pdev->dev, + sizeof(struct egpio_chip) * ei->nchips, + GFP_KERNEL); if (!ei->chip) { ret = -ENOMEM; goto fail; @@ -361,7 +363,6 @@ static int __init egpio_probe(struct platform_device *pdev) fail: printk(KERN_ERR "EGPIO failed to setup\n"); - kfree(ei); return ret; } @@ -380,8 +381,6 @@ static int __exit egpio_remove(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 0); } iounmap(ei->base_addr); - kfree(ei->chip); - kfree(ei); return 0; } diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c index 324187c0c124..c9dfce6ae0c2 100644 --- a/drivers/mfd/htc-i2cpld.c +++ b/drivers/mfd/htc-i2cpld.c @@ -514,8 +514,8 @@ static int htcpld_setup_chips(struct platform_device *pdev) /* Setup each chip's output GPIOs */ htcpld->nchips = pdata->num_chip; - htcpld->chip = kzalloc(sizeof(struct htcpld_chip) * htcpld->nchips, - GFP_KERNEL); + htcpld->chip = devm_kzalloc(dev, sizeof(struct htcpld_chip) * htcpld->nchips, + GFP_KERNEL); if (!htcpld->chip) { dev_warn(dev, "Unable to allocate memory for chips\n"); return -ENOMEM; @@ -580,12 +580,11 @@ static int htcpld_core_probe(struct platform_device *pdev) return -ENXIO; } - htcpld = kzalloc(sizeof(struct htcpld_data), GFP_KERNEL); + htcpld = devm_kzalloc(dev, sizeof(struct htcpld_data), GFP_KERNEL); if (!htcpld) return -ENOMEM; /* Find chained irq */ - ret = -EINVAL; res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res) { int flags; @@ -598,7 +597,7 @@ static int htcpld_core_probe(struct platform_device *pdev) flags, pdev->name, htcpld); if (ret) { dev_warn(dev, "Unable to setup chained irq handler: %d\n", ret); - goto fail; + return ret; } else device_init_wakeup(dev, 0); } @@ -609,7 +608,7 @@ static int htcpld_core_probe(struct platform_device *pdev) /* Setup the htcpld chips */ ret = htcpld_setup_chips(pdev); if (ret) - goto fail; + return ret; /* Request the GPIO(s) for the int reset and set them up */ if (pdata->int_reset_gpio_hi) { @@ -644,10 +643,6 @@ static int htcpld_core_probe(struct platform_device *pdev) dev_info(dev, "Initialized successfully\n"); return 0; - -fail: - kfree(htcpld); - return ret; } /* The I2C Driver -- used internally */ diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c index 0285fceb99a6..0a5e85fd8517 100644 --- a/drivers/mfd/htc-pasic3.c +++ b/drivers/mfd/htc-pasic3.c @@ -147,7 +147,7 @@ static int __init pasic3_probe(struct platform_device *pdev) if (!request_mem_region(r->start, resource_size(r), "pasic3")) return -EBUSY; - asic = kzalloc(sizeof(struct pasic3_data), GFP_KERNEL); + asic = devm_kzalloc(dev, sizeof(struct pasic3_data), GFP_KERNEL); if (!asic) return -ENOMEM; @@ -156,7 +156,6 @@ static int __init pasic3_probe(struct platform_device *pdev) asic->mapping = ioremap(r->start, resource_size(r)); if (!asic->mapping) { dev_err(dev, "couldn't ioremap PASIC3\n"); - kfree(asic); return -ENOMEM; } @@ -195,7 +194,6 @@ static int pasic3_remove(struct platform_device *pdev) iounmap(asic->mapping); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(r->start, resource_size(r)); - kfree(asic); return 0; } diff --git a/drivers/mfd/intel_msic.c b/drivers/mfd/intel_msic.c index d8d5137f9717..4f2462f0963e 100644 --- a/drivers/mfd/intel_msic.c +++ b/drivers/mfd/intel_msic.c @@ -438,7 +438,6 @@ static int intel_msic_remove(struct platform_device *pdev) struct intel_msic *msic = platform_get_drvdata(pdev); intel_msic_remove_devices(msic); - platform_set_drvdata(pdev, NULL); return 0; } diff --git a/drivers/mfd/janz-cmodio.c b/drivers/mfd/janz-cmodio.c index 45ece11cc27c..fcbb2e9dfd37 100644 --- a/drivers/mfd/janz-cmodio.c +++ b/drivers/mfd/janz-cmodio.c @@ -183,11 +183,10 @@ static int cmodio_pci_probe(struct pci_dev *dev, struct cmodio_device *priv; int ret; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); + priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) { dev_err(&dev->dev, "unable to allocate private data\n"); - ret = -ENOMEM; - goto out_return; + return -ENOMEM; } pci_set_drvdata(dev, priv); @@ -197,7 +196,7 @@ static int cmodio_pci_probe(struct pci_dev *dev, ret = pci_enable_device(dev); if (ret) { dev_err(&dev->dev, "unable to enable device\n"); - goto out_free_priv; + return ret; } pci_set_master(dev); @@ -248,9 +247,7 @@ out_pci_release_regions: pci_release_regions(dev); out_pci_disable_device: pci_disable_device(dev); -out_free_priv: - kfree(priv); -out_return: + return ret; } @@ -263,7 +260,6 @@ static void cmodio_pci_remove(struct pci_dev *dev) iounmap(priv->ctrl); pci_release_regions(dev); pci_disable_device(dev); - kfree(priv); } #define PCI_VENDOR_ID_JANZ 0x13c3 diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index e80587f1a792..3c0e8cf6916b 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c @@ -86,13 +86,13 @@ static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc) static inline void jz4740_adc_clk_enable(struct jz4740_adc *adc) { if (atomic_inc_return(&adc->clk_ref) == 1) - clk_enable(adc->clk); + clk_prepare_enable(adc->clk); } static inline void jz4740_adc_clk_disable(struct jz4740_adc *adc) { if (atomic_dec_return(&adc->clk_ref) == 0) - clk_disable(adc->clk); + clk_disable_unprepare(adc->clk); } static inline void jz4740_adc_set_enabled(struct jz4740_adc *adc, int engine, @@ -294,7 +294,6 @@ static int jz4740_adc_probe(struct platform_device *pdev) err_clk_put: clk_put(adc->clk); err_iounmap: - platform_set_drvdata(pdev, NULL); iounmap(adc->base); err_release_mem_region: release_mem_region(adc->mem->start, resource_size(adc->mem)); @@ -317,8 +316,6 @@ static int jz4740_adc_remove(struct platform_device *pdev) clk_put(adc->clk); - platform_set_drvdata(pdev, NULL); - return 0; } diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 9f12f91d6296..330cd44771be 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -51,6 +51,7 @@ * document number TBD : Lynx Point * document number TBD : Lynx Point-LP * document number TBD : Wellsburg + * document number TBD : Avoton SoC */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -207,6 +208,7 @@ enum lpc_chipsets { LPC_LPT, /* Lynx Point */ LPC_LPT_LP, /* Lynx Point-LP */ LPC_WBG, /* Wellsburg */ + LPC_AVN, /* Avoton SoC */ }; struct lpc_ich_info lpc_chipset_info[] = { @@ -491,6 +493,10 @@ struct lpc_ich_info lpc_chipset_info[] = { .name = "Wellsburg", .iTCO_version = 2, }, + [LPC_AVN] = { + .name = "Avoton SoC", + .iTCO_version = 1, + }, }; /* @@ -704,6 +710,10 @@ static DEFINE_PCI_DEVICE_TABLE(lpc_ich_ids) = { { PCI_VDEVICE(INTEL, 0x8d5d), LPC_WBG}, { PCI_VDEVICE(INTEL, 0x8d5e), LPC_WBG}, { PCI_VDEVICE(INTEL, 0x8d5f), LPC_WBG}, + { PCI_VDEVICE(INTEL, 0x1f38), LPC_AVN}, + { PCI_VDEVICE(INTEL, 0x1f39), LPC_AVN}, + { PCI_VDEVICE(INTEL, 0x1f3a), LPC_AVN}, + { PCI_VDEVICE(INTEL, 0x1f3b), LPC_AVN}, { 0, }, /* End of list */ }; MODULE_DEVICE_TABLE(pci, lpc_ich_ids); diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index 1cbb17609c8b..f27a21831583 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -37,6 +37,7 @@ static struct mfd_cell max77686_devs[] = { { .name = "max77686-pmic", }, { .name = "max77686-rtc", }, + { .name = "max77686-clk", }, }; static struct regmap_config max77686_regmap_config = { @@ -84,12 +85,12 @@ static int max77686_i2c_probe(struct i2c_client *i2c, pdata = max77686_i2c_parse_dt_pdata(&i2c->dev); if (!pdata) { - ret = -EIO; dev_err(&i2c->dev, "No platform data found.\n"); - goto err; + return -EIO; } - max77686 = kzalloc(sizeof(struct max77686_dev), GFP_KERNEL); + max77686 = devm_kzalloc(&i2c->dev, + sizeof(struct max77686_dev), GFP_KERNEL); if (max77686 == NULL) return -ENOMEM; @@ -107,7 +108,6 @@ static int max77686_i2c_probe(struct i2c_client *i2c, ret = PTR_ERR(max77686->regmap); dev_err(max77686->dev, "Failed to allocate register map: %d\n", ret); - kfree(max77686); return ret; } @@ -115,8 +115,7 @@ static int max77686_i2c_probe(struct i2c_client *i2c, MAX77686_REG_DEVICE_ID, &data) < 0) { dev_err(max77686->dev, "device not found on this channel (this is not an error)\n"); - ret = -ENODEV; - goto err; + return -ENODEV; } else dev_info(max77686->dev, "device found\n"); @@ -127,17 +126,11 @@ static int max77686_i2c_probe(struct i2c_client *i2c, ret = mfd_add_devices(max77686->dev, -1, max77686_devs, ARRAY_SIZE(max77686_devs), NULL, 0, NULL); + if (ret < 0) { + mfd_remove_devices(max77686->dev); + i2c_unregister_device(max77686->rtc); + } - if (ret < 0) - goto err_mfd; - - return ret; - -err_mfd: - mfd_remove_devices(max77686->dev); - i2c_unregister_device(max77686->rtc); -err: - kfree(max77686); return ret; } @@ -147,7 +140,6 @@ static int max77686_i2c_remove(struct i2c_client *i2c) mfd_remove_devices(max77686->dev); i2c_unregister_device(max77686->rtc); - kfree(max77686); return 0; } diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c index 92bbebd31598..8042b3205eaa 100644 --- a/drivers/mfd/max8925-i2c.c +++ b/drivers/mfd/max8925-i2c.c @@ -170,7 +170,8 @@ static int max8925_probe(struct i2c_client *client, return -EINVAL; } - chip = kzalloc(sizeof(struct max8925_chip), GFP_KERNEL); + chip = devm_kzalloc(&client->dev, + sizeof(struct max8925_chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->i2c = client; @@ -199,7 +200,6 @@ static int max8925_remove(struct i2c_client *client) max8925_device_exit(chip); i2c_unregister_device(chip->adc); i2c_unregister_device(chip->rtc); - kfree(chip); return 0; } diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c index f99d6299ec24..13198d937e36 100644 --- a/drivers/mfd/mcp-sa11x0.c +++ b/drivers/mfd/mcp-sa11x0.c @@ -225,8 +225,6 @@ static int mcp_sa11x0_probe(struct platform_device *dev) if (ret == 0) return 0; - platform_set_drvdata(dev, NULL); - err_ioremap: iounmap(m->base1); iounmap(m->base0); @@ -252,7 +250,6 @@ static int mcp_sa11x0_remove(struct platform_device *dev) mem0 = platform_get_resource(dev, IORESOURCE_MEM, 0); mem1 = platform_get_resource(dev, IORESOURCE_MEM, 1); - platform_set_drvdata(dev, NULL); mcp_host_del(mcp); iounmap(m->base1); iounmap(m->base0); diff --git a/drivers/mfd/rtl8411.c b/drivers/mfd/rtl8411.c index 2a2d31687b72..c436bf27e78d 100644 --- a/drivers/mfd/rtl8411.c +++ b/drivers/mfd/rtl8411.c @@ -35,12 +35,33 @@ static u8 rtl8411_get_ic_version(struct rtsx_pcr *pcr) return val & 0x0F; } +static int rtl8411b_is_qfn48(struct rtsx_pcr *pcr) +{ + u8 val = 0; + + rtsx_pci_read_register(pcr, RTL8411B_PACKAGE_MODE, &val); + + if (val & 0x2) + return 1; + else + return 0; +} + static int rtl8411_extra_init_hw(struct rtsx_pcr *pcr) { return rtsx_pci_write_register(pcr, CD_PAD_CTL, CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE); } +static int rtl8411b_extra_init_hw(struct rtsx_pcr *pcr) +{ + if (rtl8411b_is_qfn48(pcr)) + rtsx_pci_write_register(pcr, CARD_PULL_CTL3, 0xFF, 0xF5); + + return rtsx_pci_write_register(pcr, CD_PAD_CTL, + CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE); +} + static int rtl8411_turn_on_led(struct rtsx_pcr *pcr) { return rtsx_pci_write_register(pcr, CARD_GPIO, 0x01, 0x00); @@ -214,6 +235,20 @@ static const struct pcr_ops rtl8411_pcr_ops = { .conv_clk_and_div_n = rtl8411_conv_clk_and_div_n, }; +static const struct pcr_ops rtl8411b_pcr_ops = { + .extra_init_hw = rtl8411b_extra_init_hw, + .optimize_phy = NULL, + .turn_on_led = rtl8411_turn_on_led, + .turn_off_led = rtl8411_turn_off_led, + .enable_auto_blink = rtl8411_enable_auto_blink, + .disable_auto_blink = rtl8411_disable_auto_blink, + .card_power_on = rtl8411_card_power_on, + .card_power_off = rtl8411_card_power_off, + .switch_output_voltage = rtl8411_switch_output_voltage, + .cd_deglitch = rtl8411_cd_deglitch, + .conv_clk_and_div_n = rtl8411_conv_clk_and_div_n, +}; + /* SD Pull Control Enable: * SD_DAT[3:0] ==> pull up * SD_CD ==> pull up @@ -276,6 +311,74 @@ static const u32 rtl8411_ms_pull_ctl_disable_tbl[] = { 0, }; +static const u32 rtl8411b_qfn64_sd_pull_ctl_enable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL1, 0xAA), + RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0x09 | 0xD0), + RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50), + RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11), + 0, +}; + +static const u32 rtl8411b_qfn48_sd_pull_ctl_enable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0x69 | 0x90), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x08 | 0x11), + 0, +}; + +static const u32 rtl8411b_qfn64_sd_pull_ctl_disable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), + RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0), + RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50), + RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11), + 0, +}; + +static const u32 rtl8411b_qfn48_sd_pull_ctl_disable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11), + 0, +}; + +static const u32 rtl8411b_qfn64_ms_pull_ctl_enable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), + RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0), + RTSX_REG_PAIR(CARD_PULL_CTL4, 0x05 | 0x50), + RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11), + 0, +}; + +static const u32 rtl8411b_qfn48_ms_pull_ctl_enable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11), + 0, +}; + +static const u32 rtl8411b_qfn64_ms_pull_ctl_disable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL1, 0x65), + RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0x05 | 0xD0), + RTSX_REG_PAIR(CARD_PULL_CTL4, 0x09 | 0x50), + RTSX_REG_PAIR(CARD_PULL_CTL5, 0x05 | 0x50), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11), + 0, +}; + +static const u32 rtl8411b_qfn48_ms_pull_ctl_disable_tbl[] = { + RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55), + RTSX_REG_PAIR(CARD_PULL_CTL3, 0x65 | 0x90), + RTSX_REG_PAIR(CARD_PULL_CTL6, 0x04 | 0x11), + 0, +}; + void rtl8411_init_params(struct rtsx_pcr *pcr) { pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104; @@ -288,3 +391,32 @@ void rtl8411_init_params(struct rtsx_pcr *pcr) pcr->ms_pull_ctl_enable_tbl = rtl8411_ms_pull_ctl_enable_tbl; pcr->ms_pull_ctl_disable_tbl = rtl8411_ms_pull_ctl_disable_tbl; } + +void rtl8411b_init_params(struct rtsx_pcr *pcr) +{ + pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104; + pcr->num_slots = 2; + pcr->ops = &rtl8411b_pcr_ops; + + pcr->ic_version = rtl8411_get_ic_version(pcr); + + if (rtl8411b_is_qfn48(pcr)) { + pcr->sd_pull_ctl_enable_tbl = + rtl8411b_qfn48_sd_pull_ctl_enable_tbl; + pcr->sd_pull_ctl_disable_tbl = + rtl8411b_qfn48_sd_pull_ctl_disable_tbl; + pcr->ms_pull_ctl_enable_tbl = + rtl8411b_qfn48_ms_pull_ctl_enable_tbl; + pcr->ms_pull_ctl_disable_tbl = + rtl8411b_qfn48_ms_pull_ctl_disable_tbl; + } else { + pcr->sd_pull_ctl_enable_tbl = + rtl8411b_qfn64_sd_pull_ctl_enable_tbl; + pcr->sd_pull_ctl_disable_tbl = + rtl8411b_qfn64_sd_pull_ctl_disable_tbl; + pcr->ms_pull_ctl_enable_tbl = + rtl8411b_qfn64_ms_pull_ctl_enable_tbl; + pcr->ms_pull_ctl_disable_tbl = + rtl8411b_qfn64_ms_pull_ctl_disable_tbl; + } +} diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c index e968c01ca2ac..dd186c4103c1 100644 --- a/drivers/mfd/rtsx_pcr.c +++ b/drivers/mfd/rtsx_pcr.c @@ -57,6 +57,7 @@ static DEFINE_PCI_DEVICE_TABLE(rtsx_pci_ids) = { { PCI_DEVICE(0x10EC, 0x5289), PCI_CLASS_OTHERS << 16, 0xFF0000 }, { PCI_DEVICE(0x10EC, 0x5227), PCI_CLASS_OTHERS << 16, 0xFF0000 }, { PCI_DEVICE(0x10EC, 0x5249), PCI_CLASS_OTHERS << 16, 0xFF0000 }, + { PCI_DEVICE(0x10EC, 0x5287), PCI_CLASS_OTHERS << 16, 0xFF0000 }, { 0, } }; @@ -1038,6 +1039,10 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr) case 0x5249: rts5249_init_params(pcr); break; + + case 0x5287: + rtl8411b_init_params(pcr); + break; } dev_dbg(&(pcr->pci->dev), "PID: 0x%04x, IC version: 0x%02x\n", diff --git a/drivers/mfd/rtsx_pcr.h b/drivers/mfd/rtsx_pcr.h index 55fcfc25c4e4..c0cac7e8972f 100644 --- a/drivers/mfd/rtsx_pcr.h +++ b/drivers/mfd/rtsx_pcr.h @@ -33,5 +33,6 @@ void rts5229_init_params(struct rtsx_pcr *pcr); void rtl8411_init_params(struct rtsx_pcr *pcr); void rts5227_init_params(struct rtsx_pcr *pcr); void rts5249_init_params(struct rtsx_pcr *pcr); +void rtl8411b_init_params(struct rtsx_pcr *pcr); #endif diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 77ee26ef5941..cc896d1c1cdd 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -230,13 +230,12 @@ static int sec_pmic_probe(struct i2c_client *i2c, BUG(); } - if (ret < 0) + if (ret) goto err; return ret; err: - mfd_remove_devices(sec_pmic->dev); sec_irq_exit(sec_pmic); i2c_unregister_device(sec_pmic->rtc); return ret; diff --git a/drivers/mfd/ssbi.c b/drivers/mfd/ssbi.c new file mode 100644 index 000000000000..f32da0258a8e --- /dev/null +++ b/drivers/mfd/ssbi.c @@ -0,0 +1,379 @@ +/* Copyright (c) 2009-2013, The Linux Foundation. All rights reserved. + * Copyright (c) 2010, Google Inc. + * + * Original authors: Code Aurora Forum + * + * Author: Dima Zavin <dima@android.com> + * - Largely rewritten from original to not be an i2c driver. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/ssbi.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> + +/* SSBI 2.0 controller registers */ +#define SSBI2_CMD 0x0008 +#define SSBI2_RD 0x0010 +#define SSBI2_STATUS 0x0014 +#define SSBI2_MODE2 0x001C + +/* SSBI_CMD fields */ +#define SSBI_CMD_RDWRN (1 << 24) + +/* SSBI_STATUS fields */ +#define SSBI_STATUS_RD_READY (1 << 2) +#define SSBI_STATUS_READY (1 << 1) +#define SSBI_STATUS_MCHN_BUSY (1 << 0) + +/* SSBI_MODE2 fields */ +#define SSBI_MODE2_REG_ADDR_15_8_SHFT 0x04 +#define SSBI_MODE2_REG_ADDR_15_8_MASK (0x7f << SSBI_MODE2_REG_ADDR_15_8_SHFT) + +#define SET_SSBI_MODE2_REG_ADDR_15_8(MD, AD) \ + (((MD) & 0x0F) | ((((AD) >> 8) << SSBI_MODE2_REG_ADDR_15_8_SHFT) & \ + SSBI_MODE2_REG_ADDR_15_8_MASK)) + +/* SSBI PMIC Arbiter command registers */ +#define SSBI_PA_CMD 0x0000 +#define SSBI_PA_RD_STATUS 0x0004 + +/* SSBI_PA_CMD fields */ +#define SSBI_PA_CMD_RDWRN (1 << 24) +#define SSBI_PA_CMD_ADDR_MASK 0x7fff /* REG_ADDR_7_0, REG_ADDR_8_14*/ + +/* SSBI_PA_RD_STATUS fields */ +#define SSBI_PA_RD_STATUS_TRANS_DONE (1 << 27) +#define SSBI_PA_RD_STATUS_TRANS_DENIED (1 << 26) + +#define SSBI_TIMEOUT_US 100 + +struct ssbi { + struct device *slave; + void __iomem *base; + spinlock_t lock; + enum ssbi_controller_type controller_type; + int (*read)(struct ssbi *, u16 addr, u8 *buf, int len); + int (*write)(struct ssbi *, u16 addr, u8 *buf, int len); +}; + +#define to_ssbi(dev) platform_get_drvdata(to_platform_device(dev)) + +static inline u32 ssbi_readl(struct ssbi *ssbi, u32 reg) +{ + return readl(ssbi->base + reg); +} + +static inline void ssbi_writel(struct ssbi *ssbi, u32 val, u32 reg) +{ + writel(val, ssbi->base + reg); +} + +/* + * Via private exchange with one of the original authors, the hardware + * should generally finish a transaction in about 5us. The worst + * case, is when using the arbiter and both other CPUs have just + * started trying to use the SSBI bus will result in a time of about + * 20us. It should never take longer than this. + * + * As such, this wait merely spins, with a udelay. + */ +static int ssbi_wait_mask(struct ssbi *ssbi, u32 set_mask, u32 clr_mask) +{ + u32 timeout = SSBI_TIMEOUT_US; + u32 val; + + while (timeout--) { + val = ssbi_readl(ssbi, SSBI2_STATUS); + if (((val & set_mask) == set_mask) && ((val & clr_mask) == 0)) + return 0; + udelay(1); + } + + return -ETIMEDOUT; +} + +static int +ssbi_read_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len) +{ + u32 cmd = SSBI_CMD_RDWRN | ((addr & 0xff) << 16); + int ret = 0; + + if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) { + u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2); + mode2 = SET_SSBI_MODE2_REG_ADDR_15_8(mode2, addr); + ssbi_writel(ssbi, mode2, SSBI2_MODE2); + } + + while (len) { + ret = ssbi_wait_mask(ssbi, SSBI_STATUS_READY, 0); + if (ret) + goto err; + + ssbi_writel(ssbi, cmd, SSBI2_CMD); + ret = ssbi_wait_mask(ssbi, SSBI_STATUS_RD_READY, 0); + if (ret) + goto err; + *buf++ = ssbi_readl(ssbi, SSBI2_RD) & 0xff; + len--; + } + +err: + return ret; +} + +static int +ssbi_write_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len) +{ + int ret = 0; + + if (ssbi->controller_type == MSM_SBI_CTRL_SSBI2) { + u32 mode2 = ssbi_readl(ssbi, SSBI2_MODE2); + mode2 = SET_SSBI_MODE2_REG_ADDR_15_8(mode2, addr); + ssbi_writel(ssbi, mode2, SSBI2_MODE2); + } + + while (len) { + ret = ssbi_wait_mask(ssbi, SSBI_STATUS_READY, 0); + if (ret) + goto err; + + ssbi_writel(ssbi, ((addr & 0xff) << 16) | *buf, SSBI2_CMD); + ret = ssbi_wait_mask(ssbi, 0, SSBI_STATUS_MCHN_BUSY); + if (ret) + goto err; + buf++; + len--; + } + +err: + return ret; +} + +/* + * See ssbi_wait_mask for an explanation of the time and the + * busywait. + */ +static inline int +ssbi_pa_transfer(struct ssbi *ssbi, u32 cmd, u8 *data) +{ + u32 timeout = SSBI_TIMEOUT_US; + u32 rd_status = 0; + + ssbi_writel(ssbi, cmd, SSBI_PA_CMD); + + while (timeout--) { + rd_status = ssbi_readl(ssbi, SSBI_PA_RD_STATUS); + + if (rd_status & SSBI_PA_RD_STATUS_TRANS_DENIED) + return -EPERM; + + if (rd_status & SSBI_PA_RD_STATUS_TRANS_DONE) { + if (data) + *data = rd_status & 0xff; + return 0; + } + udelay(1); + } + + return -ETIMEDOUT; +} + +static int +ssbi_pa_read_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len) +{ + u32 cmd; + int ret = 0; + + cmd = SSBI_PA_CMD_RDWRN | (addr & SSBI_PA_CMD_ADDR_MASK) << 8; + + while (len) { + ret = ssbi_pa_transfer(ssbi, cmd, buf); + if (ret) + goto err; + buf++; + len--; + } + +err: + return ret; +} + +static int +ssbi_pa_write_bytes(struct ssbi *ssbi, u16 addr, u8 *buf, int len) +{ + u32 cmd; + int ret = 0; + + while (len) { + cmd = (addr & SSBI_PA_CMD_ADDR_MASK) << 8 | *buf; + ret = ssbi_pa_transfer(ssbi, cmd, NULL); + if (ret) + goto err; + buf++; + len--; + } + +err: + return ret; +} + +int ssbi_read(struct device *dev, u16 addr, u8 *buf, int len) +{ + struct ssbi *ssbi = to_ssbi(dev); + unsigned long flags; + int ret; + + spin_lock_irqsave(&ssbi->lock, flags); + ret = ssbi->read(ssbi, addr, buf, len); + spin_unlock_irqrestore(&ssbi->lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(ssbi_read); + +int ssbi_write(struct device *dev, u16 addr, u8 *buf, int len) +{ + struct ssbi *ssbi = to_ssbi(dev); + unsigned long flags; + int ret; + + spin_lock_irqsave(&ssbi->lock, flags); + ret = ssbi->write(ssbi, addr, buf, len); + spin_unlock_irqrestore(&ssbi->lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(ssbi_write); + +static int ssbi_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct resource *mem_res; + struct ssbi *ssbi; + int ret = 0; + const char *type; + + ssbi = kzalloc(sizeof(struct ssbi), GFP_KERNEL); + if (!ssbi) { + pr_err("can not allocate ssbi_data\n"); + return -ENOMEM; + } + + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem_res) { + pr_err("missing mem resource\n"); + ret = -EINVAL; + goto err_get_mem_res; + } + + ssbi->base = ioremap(mem_res->start, resource_size(mem_res)); + if (!ssbi->base) { + pr_err("ioremap of 0x%p failed\n", (void *)mem_res->start); + ret = -EINVAL; + goto err_ioremap; + } + platform_set_drvdata(pdev, ssbi); + + type = of_get_property(np, "qcom,controller-type", NULL); + if (type == NULL) { + pr_err("Missing qcom,controller-type property\n"); + ret = -EINVAL; + goto err_ssbi_controller; + } + dev_info(&pdev->dev, "SSBI controller type: '%s'\n", type); + if (strcmp(type, "ssbi") == 0) + ssbi->controller_type = MSM_SBI_CTRL_SSBI; + else if (strcmp(type, "ssbi2") == 0) + ssbi->controller_type = MSM_SBI_CTRL_SSBI2; + else if (strcmp(type, "pmic-arbiter") == 0) + ssbi->controller_type = MSM_SBI_CTRL_PMIC_ARBITER; + else { + pr_err("Unknown qcom,controller-type\n"); + ret = -EINVAL; + goto err_ssbi_controller; + } + + if (ssbi->controller_type == MSM_SBI_CTRL_PMIC_ARBITER) { + ssbi->read = ssbi_pa_read_bytes; + ssbi->write = ssbi_pa_write_bytes; + } else { + ssbi->read = ssbi_read_bytes; + ssbi->write = ssbi_write_bytes; + } + + spin_lock_init(&ssbi->lock); + + ret = of_platform_populate(np, NULL, NULL, &pdev->dev); + if (ret) + goto err_ssbi_controller; + + return 0; + +err_ssbi_controller: + platform_set_drvdata(pdev, NULL); + iounmap(ssbi->base); +err_ioremap: +err_get_mem_res: + kfree(ssbi); + return ret; +} + +static int ssbi_remove(struct platform_device *pdev) +{ + struct ssbi *ssbi = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + iounmap(ssbi->base); + kfree(ssbi); + return 0; +} + +static struct of_device_id ssbi_match_table[] = { + { .compatible = "qcom,ssbi" }, + {} +}; + +static struct platform_driver ssbi_driver = { + .probe = ssbi_probe, + .remove = ssbi_remove, + .driver = { + .name = "ssbi", + .owner = THIS_MODULE, + .of_match_table = ssbi_match_table, + }, +}; + +static int __init ssbi_init(void) +{ + return platform_driver_register(&ssbi_driver); +} +module_init(ssbi_init); + +static void __exit ssbi_exit(void) +{ + platform_driver_unregister(&ssbi_driver); +} +module_exit(ssbi_exit) + +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("1.0"); +MODULE_ALIAS("platform:ssbi"); +MODULE_AUTHOR("Dima Zavin <dima@android.com>"); diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index b32940ec9034..a21bff283a98 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -422,7 +422,6 @@ static int t7l66xb_remove(struct platform_device *dev) iounmap(t7l66xb->scr); release_resource(&t7l66xb->rscr); mfd_remove_devices(&dev->dev); - platform_set_drvdata(dev, NULL); kfree(t7l66xb); return ret; diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c index 366f7b906278..65c425a517c5 100644 --- a/drivers/mfd/tc6387xb.c +++ b/drivers/mfd/tc6387xb.c @@ -217,7 +217,6 @@ static int tc6387xb_remove(struct platform_device *dev) release_resource(&tc6387xb->rscr); clk_disable(tc6387xb->clk32k); clk_put(tc6387xb->clk32k); - platform_set_drvdata(dev, NULL); kfree(tc6387xb); return 0; diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 15e1463e5e13..a563dfa3cf87 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -756,7 +756,6 @@ static int tc6393xb_remove(struct platform_device *dev) clk_disable(tc6393xb->clk); iounmap(tc6393xb->scr); release_resource(&tc6393xb->rscr); - platform_set_drvdata(dev, NULL); clk_put(tc6393xb->clk); kfree(tc6393xb); diff --git a/drivers/mfd/tps65912-core.c b/drivers/mfd/tps65912-core.c index aeb8e40ab424..479886a4cf80 100644 --- a/drivers/mfd/tps65912-core.c +++ b/drivers/mfd/tps65912-core.c @@ -162,7 +162,6 @@ int tps65912_device_init(struct tps65912 *tps65912) err: kfree(init_data); mfd_remove_devices(tps65912->dev); - kfree(tps65912); return ret; } @@ -170,7 +169,6 @@ void tps65912_device_exit(struct tps65912 *tps65912) { mfd_remove_devices(tps65912->dev); tps65912_irq_exit(tps65912); - kfree(tps65912); } MODULE_AUTHOR("Margarita Olaya <magi@slimlogic.co.uk>"); diff --git a/drivers/mfd/tps65912-i2c.c b/drivers/mfd/tps65912-i2c.c index c041f2c3d2bd..6a6343ee95fe 100644 --- a/drivers/mfd/tps65912-i2c.c +++ b/drivers/mfd/tps65912-i2c.c @@ -77,7 +77,8 @@ static int tps65912_i2c_probe(struct i2c_client *i2c, { struct tps65912 *tps65912; - tps65912 = kzalloc(sizeof(struct tps65912), GFP_KERNEL); + tps65912 = devm_kzalloc(&i2c->dev, + sizeof(struct tps65912), GFP_KERNEL); if (tps65912 == NULL) return -ENOMEM; diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c index b45f460d299f..69a5178bf152 100644 --- a/drivers/mfd/tps65912-spi.c +++ b/drivers/mfd/tps65912-spi.c @@ -85,7 +85,8 @@ static int tps65912_spi_probe(struct spi_device *spi) { struct tps65912 *tps65912; - tps65912 = kzalloc(sizeof(struct tps65912), GFP_KERNEL); + tps65912 = devm_kzalloc(&spi->dev, + sizeof(struct tps65912), GFP_KERNEL); if (tps65912 == NULL) return -ENOMEM; diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 89ab4d970643..8d9bc10c5312 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -1305,17 +1305,7 @@ static struct i2c_driver twl_driver = { .remove = twl_remove, }; -static int __init twl_init(void) -{ - return i2c_add_driver(&twl_driver); -} -subsys_initcall(twl_init); - -static void __exit twl_exit(void) -{ - i2c_del_driver(&twl_driver); -} -module_exit(twl_exit); +module_i2c_driver(twl_driver); MODULE_AUTHOR("Texas Instruments, Inc."); MODULE_DESCRIPTION("I2C Core interface for TWL"); diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index d2ab222138c2..a31fba96ef43 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -261,10 +261,8 @@ static int twl4030_audio_probe(struct platform_device *pdev) ret = -ENODEV; } - if (ret) { - platform_set_drvdata(pdev, NULL); + if (ret) twl4030_audio_dev = NULL; - } return ret; } @@ -272,7 +270,6 @@ static int twl4030_audio_probe(struct platform_device *pdev) static int twl4030_audio_remove(struct platform_device *pdev) { mfd_remove_devices(&pdev->dev); - platform_set_drvdata(pdev, NULL); twl4030_audio_dev = NULL; return 0; diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index 42bd3ea5df3c..1ea54d4d003a 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c @@ -775,12 +775,10 @@ static int twl4030_madc_probe(struct platform_device *pdev) IRQF_TRIGGER_RISING, "twl4030_madc", madc); if (ret) { dev_dbg(&pdev->dev, "could not request irq\n"); - goto err_irq; + goto err_i2c; } twl4030_madc = madc; return 0; -err_irq: - platform_set_drvdata(pdev, NULL); err_i2c: twl4030_madc_set_current_generator(madc, 0, 0); err_current_generator: @@ -796,7 +794,6 @@ static int twl4030_madc_remove(struct platform_device *pdev) struct twl4030_madc_data *madc = platform_get_drvdata(pdev); free_irq(platform_get_irq(pdev, 0), madc); - platform_set_drvdata(pdev, NULL); twl4030_madc_set_current_generator(madc, 0, 0); twl4030_madc_set_power(madc, 0); kfree(madc); diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index c41599815299..2a7972349159 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -2273,18 +2273,22 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_DSP1_CLOCKING_1: case ARIZONA_DSP1_STATUS_1: case ARIZONA_DSP1_STATUS_2: + case ARIZONA_DSP1_STATUS_3: case ARIZONA_DSP2_CONTROL_1: case ARIZONA_DSP2_CLOCKING_1: case ARIZONA_DSP2_STATUS_1: case ARIZONA_DSP2_STATUS_2: + case ARIZONA_DSP2_STATUS_3: case ARIZONA_DSP3_CONTROL_1: case ARIZONA_DSP3_CLOCKING_1: case ARIZONA_DSP3_STATUS_1: case ARIZONA_DSP3_STATUS_2: + case ARIZONA_DSP3_STATUS_3: case ARIZONA_DSP4_CONTROL_1: case ARIZONA_DSP4_CLOCKING_1: case ARIZONA_DSP4_STATUS_1: case ARIZONA_DSP4_STATUS_2: + case ARIZONA_DSP4_STATUS_3: return true; default: return false; @@ -2334,12 +2338,16 @@ static bool wm5110_volatile_register(struct device *dev, unsigned int reg) case ARIZONA_DSP1_CLOCKING_1: case ARIZONA_DSP1_STATUS_1: case ARIZONA_DSP1_STATUS_2: + case ARIZONA_DSP1_STATUS_3: case ARIZONA_DSP2_STATUS_1: case ARIZONA_DSP2_STATUS_2: + case ARIZONA_DSP2_STATUS_3: case ARIZONA_DSP3_STATUS_1: case ARIZONA_DSP3_STATUS_2: + case ARIZONA_DSP3_STATUS_3: case ARIZONA_DSP4_STATUS_1: case ARIZONA_DSP4_STATUS_2: + case ARIZONA_DSP4_STATUS_3: return true; default: return false; diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c index a050e56a9bbd..d3a184a240f5 100644 --- a/drivers/mfd/wm8994-irq.c +++ b/drivers/mfd/wm8994-irq.c @@ -14,10 +14,12 @@ #include <linux/kernel.h> #include <linux/module.h> +#include <linux/gpio.h> #include <linux/i2c.h> #include <linux/irq.h> #include <linux/mfd/core.h> #include <linux/interrupt.h> +#include <linux/irqdomain.h> #include <linux/regmap.h> #include <linux/mfd/wm8994/core.h> @@ -138,6 +140,55 @@ static struct regmap_irq_chip wm8994_irq_chip = { .runtime_pm = true, }; +static void wm8994_edge_irq_enable(struct irq_data *data) +{ +} + +static void wm8994_edge_irq_disable(struct irq_data *data) +{ +} + +static struct irq_chip wm8994_edge_irq_chip = { + .name = "wm8994_edge", + .irq_disable = wm8994_edge_irq_disable, + .irq_enable = wm8994_edge_irq_enable, +}; + +static irqreturn_t wm8994_edge_irq(int irq, void *data) +{ + struct wm8994 *wm8994 = data; + + while (gpio_get_value_cansleep(wm8994->pdata.irq_gpio)) + handle_nested_irq(irq_create_mapping(wm8994->edge_irq, 0)); + + return IRQ_HANDLED; +} + +static int wm8994_edge_irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct wm8994 *wm8994 = h->host_data; + + irq_set_chip_data(virq, wm8994); + irq_set_chip_and_handler(virq, &wm8994_edge_irq_chip, handle_edge_irq); + irq_set_nested_thread(virq, 1); + + /* ARM needs us to explicitly flag the IRQ as valid + * and will set them noprobe when we do so. */ +#ifdef CONFIG_ARM + set_irq_flags(virq, IRQF_VALID); +#else + irq_set_noprobe(virq); +#endif + + return 0; +} + +static struct irq_domain_ops wm8994_edge_irq_ops = { + .map = wm8994_edge_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + int wm8994_irq_init(struct wm8994 *wm8994) { int ret; @@ -156,10 +207,51 @@ int wm8994_irq_init(struct wm8994 *wm8994) if (pdata->irq_flags) irqflags = pdata->irq_flags; - ret = regmap_add_irq_chip(wm8994->regmap, wm8994->irq, - irqflags, - wm8994->irq_base, &wm8994_irq_chip, - &wm8994->irq_data); + /* use a GPIO for edge triggered controllers */ + if (irqflags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { + if (gpio_to_irq(pdata->irq_gpio) != wm8994->irq) { + dev_warn(wm8994->dev, "IRQ %d is not GPIO %d (%d)\n", + wm8994->irq, pdata->irq_gpio, + gpio_to_irq(pdata->irq_gpio)); + wm8994->irq = gpio_to_irq(pdata->irq_gpio); + } + + ret = devm_gpio_request_one(wm8994->dev, pdata->irq_gpio, + GPIOF_IN, "WM8994 IRQ"); + + if (ret != 0) { + dev_err(wm8994->dev, "Failed to get IRQ GPIO: %d\n", + ret); + return ret; + } + + wm8994->edge_irq = irq_domain_add_linear(NULL, 1, + &wm8994_edge_irq_ops, + wm8994); + + ret = regmap_add_irq_chip(wm8994->regmap, + irq_create_mapping(wm8994->edge_irq, + 0), + IRQF_ONESHOT, + wm8994->irq_base, &wm8994_irq_chip, + &wm8994->irq_data); + if (ret != 0) { + dev_err(wm8994->dev, "Failed to get IRQ: %d\n", + ret); + return ret; + } + + ret = request_threaded_irq(wm8994->irq, + NULL, wm8994_edge_irq, + irqflags, + "WM8994 edge", wm8994); + } else { + ret = regmap_add_irq_chip(wm8994->regmap, wm8994->irq, + irqflags, + wm8994->irq_base, &wm8994_irq_chip, + &wm8994->irq_data); + } + if (ret != 0) { dev_err(wm8994->dev, "Failed to register IRQ chip: %d\n", ret); return ret; |