diff options
Diffstat (limited to 'drivers')
91 files changed, 1754 insertions, 642 deletions
diff --git a/drivers/memstick/host/rtsx_pci_ms.c b/drivers/memstick/host/rtsx_pci_ms.c index 64a779c58a74..cf8bd727dfc7 100644 --- a/drivers/memstick/host/rtsx_pci_ms.c +++ b/drivers/memstick/host/rtsx_pci_ms.c @@ -1,6 +1,6 @@ /* Realtek PCI-Express Memstick Card Interface driver * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -17,7 +17,6 @@ * * Author: * Wei WANG <wei_wang@realsil.com.cn> - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China */ #include <linux/module.h> diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c index 6c954835d61e..a65447d65605 100644 --- a/drivers/mfd/88pm800.c +++ b/drivers/mfd/88pm800.c @@ -333,9 +333,11 @@ static int device_rtc_init(struct pm80x_chip *chip, { int ret; - rtc_devs[0].platform_data = pdata->rtc; - rtc_devs[0].pdata_size = - pdata->rtc ? sizeof(struct pm80x_rtc_pdata) : 0; + if (pdata) { + rtc_devs[0].platform_data = pdata->rtc; + rtc_devs[0].pdata_size = + pdata->rtc ? sizeof(struct pm80x_rtc_pdata) : 0; + } ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0], ARRAY_SIZE(rtc_devs), NULL, 0, NULL); if (ret) { @@ -541,7 +543,7 @@ static int pm800_probe(struct i2c_client *client, { int ret = 0; struct pm80x_chip *chip; - struct pm80x_platform_data *pdata = client->dev.platform_data; + struct pm80x_platform_data *pdata = dev_get_platdata(&client->dev); struct pm80x_subchip *subchip; ret = pm80x_init(client); @@ -578,7 +580,7 @@ static int pm800_probe(struct i2c_client *client, goto err_device_init; } - if (pdata->plat_config) + if (pdata && pdata->plat_config) pdata->plat_config(chip, pdata); return 0; diff --git a/drivers/mfd/88pm805.c b/drivers/mfd/88pm805.c index 521602231c7b..8a5b6ffb5afb 100644 --- a/drivers/mfd/88pm805.c +++ b/drivers/mfd/88pm805.c @@ -227,7 +227,7 @@ static int pm805_probe(struct i2c_client *client, { int ret = 0; struct pm80x_chip *chip; - struct pm80x_platform_data *pdata = client->dev.platform_data; + struct pm80x_platform_data *pdata = dev_get_platdata(&client->dev); ret = pm80x_init(client); if (ret) { @@ -243,7 +243,7 @@ static int pm805_probe(struct i2c_client *client, goto err_805_init; } - if (pdata->plat_config) + if (pdata && pdata->plat_config) pdata->plat_config(chip, pdata); err_805_init: diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index eeb481d426b5..7ebe9ef1eba6 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -1130,7 +1130,7 @@ static int pm860x_dt_init(struct device_node *np, static int pm860x_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct pm860x_platform_data *pdata = client->dev.platform_data; + struct pm860x_platform_data *pdata = dev_get_platdata(&client->dev); struct device_node *node = client->dev.of_node; struct pm860x_chip *chip; int ret; diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index aecd6ddcbbbf..e0e46f50f95d 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -139,6 +139,18 @@ config MFD_DA9055 This driver can be built as a module. If built as a module it will be called "da9055" +config MFD_DA9063 + bool "Dialog Semiconductor DA9063 PMIC Support" + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ + depends on I2C=y && GENERIC_HARDIRQS + help + Say yes here for support for the Dialog Semiconductor DA9063 PMIC. + This includes the I2C driver and core APIs. + Additional drivers must be enabled in order to use the functionality + of the device. + config MFD_MC13783 tristate @@ -1070,7 +1082,7 @@ config MFD_WM5110 Support for Wolfson Microelectronics WM5110 low power audio SoC config MFD_WM8997 - bool "Support Wolfson Microelectronics WM8997" + bool "Wolfson Microelectronics WM8997" depends on MFD_ARIZONA help Support for Wolfson Microelectronics WM8997 low power audio SoC diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 3c90051ffa5a..15b905c6553c 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -107,6 +107,9 @@ obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o da9055-objs := da9055-core.o da9055-i2c.o obj-$(CONFIG_MFD_DA9055) += da9055.o +da9063-objs := da9063-core.o da9063-irq.o da9063-i2c.o +obj-$(CONFIG_MFD_DA9063) += da9063.o + obj-$(CONFIG_MFD_MAX77686) += max77686.o max77686-irq.o obj-$(CONFIG_MFD_MAX77693) += max77693.o max77693-irq.o obj-$(CONFIG_MFD_MAX8907) += max8907.o diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c index d4f594517521..6f68472e0ca6 100644 --- a/drivers/mfd/aat2870-core.c +++ b/drivers/mfd/aat2870-core.c @@ -363,7 +363,7 @@ static inline void aat2870_uninit_debugfs(struct aat2870_data *aat2870) static int aat2870_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct aat2870_platform_data *pdata = client->dev.platform_data; + struct aat2870_platform_data *pdata = dev_get_platdata(&client->dev); struct aat2870_data *aat2870; int i, j; int ret = 0; diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index ddc669d19530..b348ae520629 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -854,7 +854,7 @@ static int ab3100_probe(struct i2c_client *client, { struct ab3100 *ab3100; struct ab3100_platform_data *ab3100_plf_data = - client->dev.platform_data; + dev_get_platdata(&client->dev); int err; int i; diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index 7d1f1b08fc4b..e33e385af0a2 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -159,7 +159,7 @@ static struct hwreg_cfg hwreg_cfg = { static struct ab8500_prcmu_ranges *debug_ranges; -struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = { +static struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = { [0x0] = { .num_ranges = 0, .range = NULL, @@ -488,7 +488,7 @@ struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = { }, }; -struct ab8500_prcmu_ranges ab8505_debug_ranges[AB8500_NUM_BANKS] = { +static struct ab8500_prcmu_ranges ab8505_debug_ranges[AB8500_NUM_BANKS] = { [0x0] = { .num_ranges = 0, .range = NULL, @@ -847,7 +847,7 @@ struct ab8500_prcmu_ranges ab8505_debug_ranges[AB8500_NUM_BANKS] = { }, }; -struct ab8500_prcmu_ranges ab8540_debug_ranges[AB8500_NUM_BANKS] = { +static struct ab8500_prcmu_ranges ab8540_debug_ranges[AB8500_NUM_BANKS] = { [AB8500_M_FSM_RANK] = { .num_ranges = 1, .range = (struct ab8500_reg_range[]) { @@ -1377,7 +1377,7 @@ void ab8500_dump_all_banks(struct device *dev) /* Space for 500 registers. */ #define DUMP_MAX_REGS 700 -struct ab8500_register_dump +static struct ab8500_register_dump { u8 bank; u8 reg; @@ -2800,7 +2800,13 @@ static ssize_t ab8500_subscribe_write(struct file *file, */ dev_attr[irq_index] = kmalloc(sizeof(struct device_attribute), GFP_KERNEL); + if (!dev_attr[irq_index]) + return -ENOMEM; + event_name[irq_index] = kmalloc(count, GFP_KERNEL); + if (!event_name[irq_index]) + return -ENOMEM; + sprintf(event_name[irq_index], "%lu", user_val); dev_attr[irq_index]->show = show_irq; dev_attr[irq_index]->store = NULL; diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index 7623e9123828..36000f920981 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c @@ -867,6 +867,7 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc) gpadc->cal_data[ADC_INPUT_VBAT].offset); } +#ifdef CONFIG_PM_RUNTIME static int ab8500_gpadc_runtime_suspend(struct device *dev) { struct ab8500_gpadc *gpadc = dev_get_drvdata(dev); @@ -885,7 +886,9 @@ static int ab8500_gpadc_runtime_resume(struct device *dev) dev_err(dev, "Failed to enable vtvout LDO: %d\n", ret); return ret; } +#endif +#ifdef CONFIG_PM_SLEEP static int ab8500_gpadc_suspend(struct device *dev) { struct ab8500_gpadc *gpadc = dev_get_drvdata(dev); @@ -913,6 +916,7 @@ static int ab8500_gpadc_resume(struct device *dev) mutex_unlock(&gpadc->ab8500_gpadc_lock); return ret; } +#endif static int ab8500_gpadc_probe(struct platform_device *pdev) { diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c index 28346ad0b4a6..62501553d63c 100644 --- a/drivers/mfd/adp5520.c +++ b/drivers/mfd/adp5520.c @@ -207,7 +207,7 @@ static int adp5520_remove_subdevs(struct adp5520_chip *chip) static int adp5520_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct adp5520_platform_data *pdata = client->dev.platform_data; + struct adp5520_platform_data *pdata = dev_get_platdata(&client->dev); struct platform_device *pdev; struct adp5520_chip *chip; int ret; diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 89a115301a0c..5ac3aa48473b 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -438,9 +438,9 @@ static int arizona_runtime_suspend(struct device *dev) } } - regulator_disable(arizona->dcvdd); regcache_cache_only(arizona->regmap, true); regcache_mark_dirty(arizona->regmap); + regulator_disable(arizona->dcvdd); return 0; } diff --git a/drivers/mfd/as3711.c b/drivers/mfd/as3711.c index 01e414162702..abd3ab7c0908 100644 --- a/drivers/mfd/as3711.c +++ b/drivers/mfd/as3711.c @@ -129,7 +129,7 @@ static int as3711_i2c_probe(struct i2c_client *client, int ret; if (!client->dev.of_node) { - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); if (!pdata) dev_dbg(&client->dev, "Platform data not found\n"); } else { diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 9532f749412f..fa22154c84e4 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -952,7 +952,7 @@ static void asic3_mfd_remove(struct platform_device *pdev) /* Core */ static int __init asic3_probe(struct platform_device *pdev) { - struct asic3_platform_data *pdata = pdev->dev.platform_data; + struct asic3_platform_data *pdata = dev_get_platdata(&pdev->dev); struct asic3 *asic; struct resource *mem; unsigned long clksel; diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c index f1a316e0d6a6..e0a2e0ee603b 100644 --- a/drivers/mfd/da903x.c +++ b/drivers/mfd/da903x.c @@ -494,7 +494,7 @@ failed: static int da903x_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct da903x_platform_data *pdata = client->dev.platform_data; + struct da903x_platform_data *pdata = dev_get_platdata(&client->dev); struct da903x_chip *chip; unsigned int tmp; int ret; diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c index a3c9613f9166..ea28a33576e4 100644 --- a/drivers/mfd/da9052-core.c +++ b/drivers/mfd/da9052-core.c @@ -534,7 +534,7 @@ EXPORT_SYMBOL_GPL(da9052_regmap_config); int da9052_device_init(struct da9052 *da9052, u8 chip_id) { - struct da9052_pdata *pdata = da9052->dev->platform_data; + struct da9052_pdata *pdata = dev_get_platdata(da9052->dev); int ret; mutex_init(&da9052->auxadc_lock); diff --git a/drivers/mfd/da9055-core.c b/drivers/mfd/da9055-core.c index 49cb23d37469..d3670cd3c3c6 100644 --- a/drivers/mfd/da9055-core.c +++ b/drivers/mfd/da9055-core.c @@ -379,8 +379,9 @@ static struct regmap_irq_chip da9055_regmap_irq_chip = { int da9055_device_init(struct da9055 *da9055) { - struct da9055_pdata *pdata = da9055->dev->platform_data; + struct da9055_pdata *pdata = dev_get_platdata(da9055->dev); int ret; + uint8_t clear_events[3] = {0xFF, 0xFF, 0xFF}; if (pdata && pdata->init != NULL) pdata->init(da9055); @@ -390,6 +391,10 @@ int da9055_device_init(struct da9055 *da9055) else da9055->irq_base = pdata->irq_base; + ret = da9055_group_write(da9055, DA9055_REG_EVENT_A, 3, clear_events); + if (ret < 0) + return ret; + ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq, IRQF_TRIGGER_LOW | IRQF_ONESHOT, da9055->irq_base, &da9055_regmap_irq_chip, diff --git a/drivers/mfd/da9055-i2c.c b/drivers/mfd/da9055-i2c.c index 607387ffe8ca..13af7e50021e 100644 --- a/drivers/mfd/da9055-i2c.c +++ b/drivers/mfd/da9055-i2c.c @@ -54,7 +54,7 @@ static int da9055_i2c_remove(struct i2c_client *i2c) } static struct i2c_device_id da9055_i2c_id[] = { - {"da9055-pmic", 0}, + {"da9055", 0}, { } }; diff --git a/drivers/mfd/da9063-core.c b/drivers/mfd/da9063-core.c new file mode 100644 index 000000000000..c9cf8d988406 --- /dev/null +++ b/drivers/mfd/da9063-core.c @@ -0,0 +1,185 @@ +/* + * da9063-core.c: Device access for Dialog DA9063 modules + * + * Copyright 2012 Dialog Semiconductors Ltd. + * Copyright 2013 Philipp Zabel, Pengutronix + * + * Author: Krystian Garbaciak <krystian.garbaciak@diasemi.com>, + * Michal Hajduk <michal.hajduk@diasemi.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/mutex.h> +#include <linux/mfd/core.h> +#include <linux/regmap.h> + +#include <linux/mfd/da9063/core.h> +#include <linux/mfd/da9063/pdata.h> +#include <linux/mfd/da9063/registers.h> + +#include <linux/proc_fs.h> +#include <linux/kthread.h> +#include <linux/uaccess.h> + + +static struct resource da9063_regulators_resources[] = { + { + .name = "LDO_LIM", + .start = DA9063_IRQ_LDO_LIM, + .end = DA9063_IRQ_LDO_LIM, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource da9063_rtc_resources[] = { + { + .name = "ALARM", + .start = DA9063_IRQ_ALARM, + .end = DA9063_IRQ_ALARM, + .flags = IORESOURCE_IRQ, + }, + { + .name = "TICK", + .start = DA9063_IRQ_TICK, + .end = DA9063_IRQ_TICK, + .flags = IORESOURCE_IRQ, + } +}; + +static struct resource da9063_onkey_resources[] = { + { + .start = DA9063_IRQ_ONKEY, + .end = DA9063_IRQ_ONKEY, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource da9063_hwmon_resources[] = { + { + .start = DA9063_IRQ_ADC_RDY, + .end = DA9063_IRQ_ADC_RDY, + .flags = IORESOURCE_IRQ, + }, +}; + + +static struct mfd_cell da9063_devs[] = { + { + .name = DA9063_DRVNAME_REGULATORS, + .num_resources = ARRAY_SIZE(da9063_regulators_resources), + .resources = da9063_regulators_resources, + }, + { + .name = DA9063_DRVNAME_LEDS, + }, + { + .name = DA9063_DRVNAME_WATCHDOG, + }, + { + .name = DA9063_DRVNAME_HWMON, + .num_resources = ARRAY_SIZE(da9063_hwmon_resources), + .resources = da9063_hwmon_resources, + }, + { + .name = DA9063_DRVNAME_ONKEY, + .num_resources = ARRAY_SIZE(da9063_onkey_resources), + .resources = da9063_onkey_resources, + }, + { + .name = DA9063_DRVNAME_RTC, + .num_resources = ARRAY_SIZE(da9063_rtc_resources), + .resources = da9063_rtc_resources, + }, + { + .name = DA9063_DRVNAME_VIBRATION, + }, +}; + +int da9063_device_init(struct da9063 *da9063, unsigned int irq) +{ + struct da9063_pdata *pdata = da9063->dev->platform_data; + int model, revision; + int ret; + + if (pdata) { + da9063->flags = pdata->flags; + da9063->irq_base = pdata->irq_base; + } else { + da9063->flags = 0; + da9063->irq_base = 0; + } + da9063->chip_irq = irq; + + if (pdata && pdata->init != NULL) { + ret = pdata->init(da9063); + if (ret != 0) { + dev_err(da9063->dev, + "Platform initialization failed.\n"); + return ret; + } + } + + ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_ID, &model); + if (ret < 0) { + dev_err(da9063->dev, "Cannot read chip model id.\n"); + return -EIO; + } + if (model != PMIC_DA9063) { + dev_err(da9063->dev, "Invalid chip model id: 0x%02x\n", model); + return -ENODEV; + } + + ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_VARIANT, &revision); + if (ret < 0) { + dev_err(da9063->dev, "Cannot read chip revision id.\n"); + return -EIO; + } + revision >>= DA9063_CHIP_VARIANT_SHIFT; + if (revision != 3) { + dev_err(da9063->dev, "Unknown chip revision: %d\n", revision); + return -ENODEV; + } + + da9063->model = model; + da9063->revision = revision; + + dev_info(da9063->dev, + "Device detected (model-ID: 0x%02X rev-ID: 0x%02X)\n", + model, revision); + + ret = da9063_irq_init(da9063); + if (ret) { + dev_err(da9063->dev, "Cannot initialize interrupts.\n"); + return ret; + } + + ret = mfd_add_devices(da9063->dev, -1, da9063_devs, + ARRAY_SIZE(da9063_devs), NULL, da9063->irq_base, + NULL); + if (ret) + dev_err(da9063->dev, "Cannot add MFD cells\n"); + + return ret; +} + +void da9063_device_exit(struct da9063 *da9063) +{ + mfd_remove_devices(da9063->dev); + da9063_irq_exit(da9063); +} + +MODULE_DESCRIPTION("PMIC driver for Dialog DA9063"); +MODULE_AUTHOR("Krystian Garbaciak <krystian.garbaciak@diasemi.com>, Michal Hajduk <michal.hajduk@diasemi.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mfd/da9063-i2c.c b/drivers/mfd/da9063-i2c.c new file mode 100644 index 000000000000..8db5c805c64f --- /dev/null +++ b/drivers/mfd/da9063-i2c.c @@ -0,0 +1,182 @@ +/* da9063-i2c.c: Interrupt support for Dialog DA9063 + * + * Copyright 2012 Dialog Semiconductor Ltd. + * Copyright 2013 Philipp Zabel, Pengutronix + * + * Author: Krystian Garbaciak <krystian.garbaciak@diasemi.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/regmap.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/err.h> + +#include <linux/mfd/core.h> +#include <linux/mfd/da9063/core.h> +#include <linux/mfd/da9063/pdata.h> +#include <linux/mfd/da9063/registers.h> + +static const struct regmap_range da9063_readable_ranges[] = { + { + .range_min = DA9063_REG_PAGE_CON, + .range_max = DA9063_REG_SECOND_D, + }, { + .range_min = DA9063_REG_SEQ, + .range_max = DA9063_REG_ID_32_31, + }, { + .range_min = DA9063_REG_SEQ_A, + .range_max = DA9063_REG_AUTO3_LOW, + }, { + .range_min = DA9063_REG_T_OFFSET, + .range_max = DA9063_REG_GP_ID_19, + }, { + .range_min = DA9063_REG_CHIP_ID, + .range_max = DA9063_REG_CHIP_VARIANT, + }, +}; + +static const struct regmap_range da9063_writeable_ranges[] = { + { + .range_min = DA9063_REG_PAGE_CON, + .range_max = DA9063_REG_PAGE_CON, + }, { + .range_min = DA9063_REG_FAULT_LOG, + .range_max = DA9063_REG_VSYS_MON, + }, { + .range_min = DA9063_REG_COUNT_S, + .range_max = DA9063_REG_ALARM_Y, + }, { + .range_min = DA9063_REG_SEQ, + .range_max = DA9063_REG_ID_32_31, + }, { + .range_min = DA9063_REG_SEQ_A, + .range_max = DA9063_REG_AUTO3_LOW, + }, { + .range_min = DA9063_REG_CONFIG_I, + .range_max = DA9063_REG_MON_REG_4, + }, { + .range_min = DA9063_REG_GP_ID_0, + .range_max = DA9063_REG_GP_ID_19, + }, +}; + +static const struct regmap_range da9063_volatile_ranges[] = { + { + .range_min = DA9063_REG_STATUS_A, + .range_max = DA9063_REG_EVENT_D, + }, { + .range_min = DA9063_REG_CONTROL_F, + .range_max = DA9063_REG_CONTROL_F, + }, { + .range_min = DA9063_REG_ADC_MAN, + .range_max = DA9063_REG_ADC_MAN, + }, { + .range_min = DA9063_REG_ADC_RES_L, + .range_max = DA9063_REG_SECOND_D, + }, { + .range_min = DA9063_REG_MON_REG_5, + .range_max = DA9063_REG_MON_REG_6, + }, +}; + +static const struct regmap_access_table da9063_readable_table = { + .yes_ranges = da9063_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(da9063_readable_ranges), +}; + +static const struct regmap_access_table da9063_writeable_table = { + .yes_ranges = da9063_writeable_ranges, + .n_yes_ranges = ARRAY_SIZE(da9063_writeable_ranges), +}; + +static const struct regmap_access_table da9063_volatile_table = { + .yes_ranges = da9063_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(da9063_volatile_ranges), +}; + +static const struct regmap_range_cfg da9063_range_cfg[] = { + { + .range_min = DA9063_REG_PAGE_CON, + .range_max = DA9063_REG_CHIP_VARIANT, + .selector_reg = DA9063_REG_PAGE_CON, + .selector_mask = 1 << DA9063_I2C_PAGE_SEL_SHIFT, + .selector_shift = DA9063_I2C_PAGE_SEL_SHIFT, + .window_start = 0, + .window_len = 256, + } +}; + +static struct regmap_config da9063_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .ranges = da9063_range_cfg, + .num_ranges = ARRAY_SIZE(da9063_range_cfg), + .max_register = DA9063_REG_CHIP_VARIANT, + + .cache_type = REGCACHE_RBTREE, + + .rd_table = &da9063_readable_table, + .wr_table = &da9063_writeable_table, + .volatile_table = &da9063_volatile_table, +}; + +static int da9063_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct da9063 *da9063; + int ret; + + da9063 = devm_kzalloc(&i2c->dev, sizeof(struct da9063), GFP_KERNEL); + if (da9063 == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, da9063); + da9063->dev = &i2c->dev; + da9063->chip_irq = i2c->irq; + + da9063->regmap = devm_regmap_init_i2c(i2c, &da9063_regmap_config); + if (IS_ERR(da9063->regmap)) { + ret = PTR_ERR(da9063->regmap); + dev_err(da9063->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + return da9063_device_init(da9063, i2c->irq); +} + +static int da9063_i2c_remove(struct i2c_client *i2c) +{ + struct da9063 *da9063 = i2c_get_clientdata(i2c); + + da9063_device_exit(da9063); + + return 0; +} + +static const struct i2c_device_id da9063_i2c_id[] = { + {"da9063", PMIC_DA9063}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, da9063_i2c_id); + +static struct i2c_driver da9063_i2c_driver = { + .driver = { + .name = "da9063", + .owner = THIS_MODULE, + }, + .probe = da9063_i2c_probe, + .remove = da9063_i2c_remove, + .id_table = da9063_i2c_id, +}; + +module_i2c_driver(da9063_i2c_driver); diff --git a/drivers/mfd/da9063-irq.c b/drivers/mfd/da9063-irq.c new file mode 100644 index 000000000000..822922602ce9 --- /dev/null +++ b/drivers/mfd/da9063-irq.c @@ -0,0 +1,193 @@ +/* da9063-irq.c: Interrupts support for Dialog DA9063 + * + * Copyright 2012 Dialog Semiconductor Ltd. + * Copyright 2013 Philipp Zabel, Pengutronix + * + * Author: Michal Hajduk <michal.hajduk@diasemi.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/irq.h> +#include <linux/mfd/core.h> +#include <linux/interrupt.h> +#include <linux/regmap.h> +#include <linux/mfd/da9063/core.h> +#include <linux/mfd/da9063/pdata.h> + +#define DA9063_REG_EVENT_A_OFFSET 0 +#define DA9063_REG_EVENT_B_OFFSET 1 +#define DA9063_REG_EVENT_C_OFFSET 2 +#define DA9063_REG_EVENT_D_OFFSET 3 +#define EVENTS_BUF_LEN 4 + +static const u8 mask_events_buf[] = { [0 ... (EVENTS_BUF_LEN - 1)] = ~0 }; + +struct da9063_irq_data { + u16 reg; + u8 mask; +}; + +static struct regmap_irq da9063_irqs[] = { + /* DA9063 event A register */ + [DA9063_IRQ_ONKEY] = { + .reg_offset = DA9063_REG_EVENT_A_OFFSET, + .mask = DA9063_M_ONKEY, + }, + [DA9063_IRQ_ALARM] = { + .reg_offset = DA9063_REG_EVENT_A_OFFSET, + .mask = DA9063_M_ALARM, + }, + [DA9063_IRQ_TICK] = { + .reg_offset = DA9063_REG_EVENT_A_OFFSET, + .mask = DA9063_M_TICK, + }, + [DA9063_IRQ_ADC_RDY] = { + .reg_offset = DA9063_REG_EVENT_A_OFFSET, + .mask = DA9063_M_ADC_RDY, + }, + [DA9063_IRQ_SEQ_RDY] = { + .reg_offset = DA9063_REG_EVENT_A_OFFSET, + .mask = DA9063_M_SEQ_RDY, + }, + /* DA9063 event B register */ + [DA9063_IRQ_WAKE] = { + .reg_offset = DA9063_REG_EVENT_B_OFFSET, + .mask = DA9063_M_WAKE, + }, + [DA9063_IRQ_TEMP] = { + .reg_offset = DA9063_REG_EVENT_B_OFFSET, + .mask = DA9063_M_TEMP, + }, + [DA9063_IRQ_COMP_1V2] = { + .reg_offset = DA9063_REG_EVENT_B_OFFSET, + .mask = DA9063_M_COMP_1V2, + }, + [DA9063_IRQ_LDO_LIM] = { + .reg_offset = DA9063_REG_EVENT_B_OFFSET, + .mask = DA9063_M_LDO_LIM, + }, + [DA9063_IRQ_REG_UVOV] = { + .reg_offset = DA9063_REG_EVENT_B_OFFSET, + .mask = DA9063_M_UVOV, + }, + [DA9063_IRQ_VDD_MON] = { + .reg_offset = DA9063_REG_EVENT_B_OFFSET, + .mask = DA9063_M_VDD_MON, + }, + [DA9063_IRQ_WARN] = { + .reg_offset = DA9063_REG_EVENT_B_OFFSET, + .mask = DA9063_M_VDD_WARN, + }, + /* DA9063 event C register */ + [DA9063_IRQ_GPI0] = { + .reg_offset = DA9063_REG_EVENT_C_OFFSET, + .mask = DA9063_M_GPI0, + }, + [DA9063_IRQ_GPI1] = { + .reg_offset = DA9063_REG_EVENT_C_OFFSET, + .mask = DA9063_M_GPI1, + }, + [DA9063_IRQ_GPI2] = { + .reg_offset = DA9063_REG_EVENT_C_OFFSET, + .mask = DA9063_M_GPI2, + }, + [DA9063_IRQ_GPI3] = { + .reg_offset = DA9063_REG_EVENT_C_OFFSET, + .mask = DA9063_M_GPI3, + }, + [DA9063_IRQ_GPI4] = { + .reg_offset = DA9063_REG_EVENT_C_OFFSET, + .mask = DA9063_M_GPI4, + }, + [DA9063_IRQ_GPI5] = { + .reg_offset = DA9063_REG_EVENT_C_OFFSET, + .mask = DA9063_M_GPI5, + }, + [DA9063_IRQ_GPI6] = { + .reg_offset = DA9063_REG_EVENT_C_OFFSET, + .mask = DA9063_M_GPI6, + }, + [DA9063_IRQ_GPI7] = { + .reg_offset = DA9063_REG_EVENT_C_OFFSET, + .mask = DA9063_M_GPI7, + }, + /* DA9063 event D register */ + [DA9063_IRQ_GPI8] = { + .reg_offset = DA9063_REG_EVENT_D_OFFSET, + .mask = DA9063_M_GPI8, + }, + [DA9063_IRQ_GPI9] = { + .reg_offset = DA9063_REG_EVENT_D_OFFSET, + .mask = DA9063_M_GPI9, + }, + [DA9063_IRQ_GPI10] = { + .reg_offset = DA9063_REG_EVENT_D_OFFSET, + .mask = DA9063_M_GPI10, + }, + [DA9063_IRQ_GPI11] = { + .reg_offset = DA9063_REG_EVENT_D_OFFSET, + .mask = DA9063_M_GPI11, + }, + [DA9063_IRQ_GPI12] = { + .reg_offset = DA9063_REG_EVENT_D_OFFSET, + .mask = DA9063_M_GPI12, + }, + [DA9063_IRQ_GPI13] = { + .reg_offset = DA9063_REG_EVENT_D_OFFSET, + .mask = DA9063_M_GPI13, + }, + [DA9063_IRQ_GPI14] = { + .reg_offset = DA9063_REG_EVENT_D_OFFSET, + .mask = DA9063_M_GPI14, + }, + [DA9063_IRQ_GPI15] = { + .reg_offset = DA9063_REG_EVENT_D_OFFSET, + .mask = DA9063_M_GPI15, + }, +}; + +static struct regmap_irq_chip da9063_irq_chip = { + .name = "da9063-irq", + .irqs = da9063_irqs, + .num_irqs = DA9063_NUM_IRQ, + + .num_regs = 4, + .status_base = DA9063_REG_EVENT_A, + .mask_base = DA9063_REG_IRQ_MASK_A, + .ack_base = DA9063_REG_EVENT_A, + .init_ack_masked = true, +}; + +int da9063_irq_init(struct da9063 *da9063) +{ + int ret; + + if (!da9063->chip_irq) { + dev_err(da9063->dev, "No IRQ configured\n"); + return -EINVAL; + } + + ret = regmap_add_irq_chip(da9063->regmap, da9063->chip_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED, + da9063->irq_base, &da9063_irq_chip, + &da9063->regmap_irq); + if (ret) { + dev_err(da9063->dev, "Failed to reguest IRQ %d: %d\n", + da9063->chip_irq, ret); + return ret; + } + + return 0; +} + +void da9063_irq_exit(struct da9063 *da9063) +{ + regmap_del_irq_chip(da9063->chip_irq, da9063->regmap_irq); +} diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c index fb64398506e9..013ba8159dcd 100644 --- a/drivers/mfd/davinci_voicecodec.c +++ b/drivers/mfd/davinci_voicecodec.c @@ -27,21 +27,16 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/clk.h> +#include <linux/regmap.h> #include <sound/pcm.h> #include <linux/mfd/davinci_voicecodec.h> -u32 davinci_vc_read(struct davinci_vc *davinci_vc, int reg) -{ - return __raw_readl(davinci_vc->base + reg); -} - -void davinci_vc_write(struct davinci_vc *davinci_vc, - int reg, u32 val) -{ - __raw_writel(val, davinci_vc->base + reg); -} +static struct regmap_config davinci_vc_regmap = { + .reg_bits = 32, + .val_bits = 32, +}; static int __init davinci_vc_probe(struct platform_device *pdev) { @@ -74,6 +69,14 @@ static int __init davinci_vc_probe(struct platform_device *pdev) goto fail; } + davinci_vc->regmap = devm_regmap_init_mmio(&pdev->dev, + davinci_vc->base, + &davinci_vc_regmap); + if (IS_ERR(davinci_vc->regmap)) { + ret = PTR_ERR(davinci_vc->regmap); + goto fail; + } + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!res) { dev_err(&pdev->dev, "no DMA resource\n"); diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c index 0d68eb1a5ec5..53f371dcbb6e 100644 --- a/drivers/mfd/db8500-prcmu.c +++ b/drivers/mfd/db8500-prcmu.c @@ -465,7 +465,7 @@ static DEFINE_SPINLOCK(clk_mgt_lock); #define CLK_MGT_ENTRY(_name, _branch, _clk38div)[PRCMU_##_name] = \ { (PRCM_##_name##_MGT), 0 , _branch, _clk38div} -struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = { +static struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = { CLK_MGT_ENTRY(SGACLK, PLL_DIV, false), CLK_MGT_ENTRY(UARTCLK, PLL_FIX, true), CLK_MGT_ENTRY(MSP02CLK, PLL_FIX, true), @@ -2319,7 +2319,7 @@ unlock_and_return: /** * prcmu_ac_sleep_req - called when ARM no longer needs to talk to modem */ -void prcmu_ac_sleep_req() +void prcmu_ac_sleep_req(void) { u32 val; diff --git a/drivers/mfd/dm355evm_msp.c b/drivers/mfd/dm355evm_msp.c index 7710227d284e..7a55c0071fa8 100644 --- a/drivers/mfd/dm355evm_msp.c +++ b/drivers/mfd/dm355evm_msp.c @@ -315,8 +315,8 @@ static int add_children(struct i2c_client *client) } /* MMC/SD inputs -- right after the last config input */ - if (client->dev.platform_data) { - void (*mmcsd_setup)(unsigned) = client->dev.platform_data; + if (dev_get_platdata(&client->dev)) { + void (*mmcsd_setup)(unsigned) = dev_get_platdata(&client->dev); mmcsd_setup(dm355evm_msp_gpio.base + 8 + 5); } diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index 5502106ad515..7245b0c5b794 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c @@ -177,7 +177,7 @@ static void pcap_msr_work(struct work_struct *work) static void pcap_isr_work(struct work_struct *work) { struct pcap_chip *pcap = container_of(work, struct pcap_chip, isr_work); - struct pcap_platform_data *pdata = pcap->spi->dev.platform_data; + struct pcap_platform_data *pdata = dev_get_platdata(&pcap->spi->dev); u32 msr, isr, int_sel, service; int irq; @@ -394,7 +394,7 @@ static int pcap_add_subdev(struct pcap_chip *pcap, static int ezx_pcap_remove(struct spi_device *spi) { struct pcap_chip *pcap = spi_get_drvdata(spi); - struct pcap_platform_data *pdata = spi->dev.platform_data; + struct pcap_platform_data *pdata = dev_get_platdata(&spi->dev); int i, adc_irq; /* remove all registered subdevs */ @@ -420,7 +420,7 @@ static int ezx_pcap_remove(struct spi_device *spi) static int ezx_pcap_probe(struct spi_device *spi) { - struct pcap_platform_data *pdata = spi->dev.platform_data; + struct pcap_platform_data *pdata = dev_get_platdata(&spi->dev); struct pcap_chip *pcap; int i, adc_irq; int ret = -ENODEV; diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c index 26aca545084b..49f39feca784 100644 --- a/drivers/mfd/htc-egpio.c +++ b/drivers/mfd/htc-egpio.c @@ -261,7 +261,7 @@ static void egpio_write_cache(struct egpio_info *ei) static int __init egpio_probe(struct platform_device *pdev) { - struct htc_egpio_platform_data *pdata = pdev->dev.platform_data; + struct htc_egpio_platform_data *pdata = dev_get_platdata(&pdev->dev); struct resource *res; struct egpio_info *ei; struct gpio_chip *chip; diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c index c9dfce6ae0c2..d7b2a75aca3e 100644 --- a/drivers/mfd/htc-i2cpld.c +++ b/drivers/mfd/htc-i2cpld.c @@ -340,7 +340,7 @@ static int htcpld_setup_chip_irq( int ret = 0; /* Get the platform and driver data */ - pdata = dev->platform_data; + pdata = dev_get_platdata(dev); htcpld = platform_get_drvdata(pdev); chip = &htcpld->chip[chip_index]; plat_chip_data = &pdata->chip[chip_index]; @@ -375,7 +375,7 @@ static int htcpld_register_chip_i2c( struct i2c_board_info info; /* Get the platform and driver data */ - pdata = dev->platform_data; + pdata = dev_get_platdata(dev); htcpld = platform_get_drvdata(pdev); chip = &htcpld->chip[chip_index]; plat_chip_data = &pdata->chip[chip_index]; @@ -447,7 +447,7 @@ static int htcpld_register_chip_gpio( int ret = 0; /* Get the platform and driver data */ - pdata = dev->platform_data; + pdata = dev_get_platdata(dev); htcpld = platform_get_drvdata(pdev); chip = &htcpld->chip[chip_index]; plat_chip_data = &pdata->chip[chip_index]; @@ -509,7 +509,7 @@ static int htcpld_setup_chips(struct platform_device *pdev) int i; /* Get the platform and driver data */ - pdata = dev->platform_data; + pdata = dev_get_platdata(dev); htcpld = platform_get_drvdata(pdev); /* Setup each chip's output GPIOs */ @@ -574,7 +574,7 @@ static int htcpld_core_probe(struct platform_device *pdev) if (!dev) return -ENODEV; - pdata = dev->platform_data; + pdata = dev_get_platdata(dev); if (!pdata) { dev_warn(dev, "Platform data not found for htcpld core!\n"); return -ENXIO; diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c index 0a5e85fd8517..6bf92a507b95 100644 --- a/drivers/mfd/htc-pasic3.c +++ b/drivers/mfd/htc-pasic3.c @@ -126,7 +126,7 @@ static struct mfd_cell ds1wm_cell __initdata = { static int __init pasic3_probe(struct platform_device *pdev) { - struct pasic3_platform_data *pdata = pdev->dev.platform_data; + struct pasic3_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device *dev = &pdev->dev; struct pasic3_data *asic; struct resource *r; diff --git a/drivers/mfd/intel_msic.c b/drivers/mfd/intel_msic.c index 4f2462f0963e..9203d47cdbb1 100644 --- a/drivers/mfd/intel_msic.c +++ b/drivers/mfd/intel_msic.c @@ -310,7 +310,7 @@ EXPORT_SYMBOL_GPL(intel_msic_irq_read); static int intel_msic_init_devices(struct intel_msic *msic) { struct platform_device *pdev = msic->pdev; - struct intel_msic_platform_data *pdata = pdev->dev.platform_data; + struct intel_msic_platform_data *pdata = dev_get_platdata(&pdev->dev); int ret, i; if (pdata->gpio) { @@ -372,7 +372,7 @@ static void intel_msic_remove_devices(struct intel_msic *msic) static int intel_msic_probe(struct platform_device *pdev) { - struct intel_msic_platform_data *pdata = pdev->dev.platform_data; + struct intel_msic_platform_data *pdata = dev_get_platdata(&pdev->dev); struct intel_msic *msic; struct resource *res; u8 id0, id1; diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c index 686a4565acb6..d3e23278d299 100644 --- a/drivers/mfd/kempld-core.c +++ b/drivers/mfd/kempld-core.c @@ -258,7 +258,7 @@ EXPORT_SYMBOL_GPL(kempld_write32); */ void kempld_get_mutex(struct kempld_device_data *pld) { - struct kempld_platform_data *pdata = pld->dev->platform_data; + struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); mutex_lock(&pld->lock); pdata->get_hardware_mutex(pld); @@ -271,7 +271,7 @@ EXPORT_SYMBOL_GPL(kempld_get_mutex); */ void kempld_release_mutex(struct kempld_device_data *pld) { - struct kempld_platform_data *pdata = pld->dev->platform_data; + struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); pdata->release_hardware_mutex(pld); mutex_unlock(&pld->lock); @@ -288,7 +288,7 @@ EXPORT_SYMBOL_GPL(kempld_release_mutex); */ static int kempld_get_info(struct kempld_device_data *pld) { - struct kempld_platform_data *pdata = pld->dev->platform_data; + struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); return pdata->get_info(pld); } @@ -302,7 +302,7 @@ static int kempld_get_info(struct kempld_device_data *pld) */ static int kempld_register_cells(struct kempld_device_data *pld) { - struct kempld_platform_data *pdata = pld->dev->platform_data; + struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); return pdata->register_cells(pld); } @@ -357,7 +357,7 @@ static int kempld_detect_device(struct kempld_device_data *pld) static int kempld_probe(struct platform_device *pdev) { - struct kempld_platform_data *pdata = pdev->dev.platform_data; + struct kempld_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device *dev = &pdev->dev; struct kempld_device_data *pld; struct resource *ioport; @@ -394,7 +394,7 @@ static int kempld_probe(struct platform_device *pdev) static int kempld_remove(struct platform_device *pdev) { struct kempld_device_data *pld = platform_get_drvdata(pdev); - struct kempld_platform_data *pdata = pld->dev->platform_data; + struct kempld_platform_data *pdata = dev_get_platdata(pld->dev); mfd_remove_devices(&pdev->dev); pdata->release_hardware_mutex(pld); @@ -413,6 +413,15 @@ static struct platform_driver kempld_driver = { static struct dmi_system_id __initdata kempld_dmi_table[] = { { + .ident = "BHL6", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), + DMI_MATCH(DMI_BOARD_NAME, "COMe-bHL6"), + }, + .driver_data = (void *)&kempld_platform_data_generic, + .callback = kempld_create_platform_device, + }, + { .ident = "CCR2", .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), @@ -596,6 +605,15 @@ static struct dmi_system_id __initdata kempld_dmi_table[] = { .driver_data = (void *)&kempld_platform_data_generic, .callback = kempld_create_platform_device, }, + { + .ident = "UTH6", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), + DMI_MATCH(DMI_BOARD_NAME, "COMe-cTH6"), + }, + .driver_data = (void *)&kempld_platform_data_generic, + .callback = kempld_create_platform_device, + }, {} }; MODULE_DEVICE_TABLE(dmi, kempld_dmi_table); diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c index 4b7e6dac1de8..8c29f7b27324 100644 --- a/drivers/mfd/lm3533-core.c +++ b/drivers/mfd/lm3533-core.c @@ -384,7 +384,7 @@ static struct attribute_group lm3533_attribute_group = { static int lm3533_device_als_init(struct lm3533 *lm3533) { - struct lm3533_platform_data *pdata = lm3533->dev->platform_data; + struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev); int ret; if (!pdata->als) @@ -407,7 +407,7 @@ static int lm3533_device_als_init(struct lm3533 *lm3533) static int lm3533_device_bl_init(struct lm3533 *lm3533) { - struct lm3533_platform_data *pdata = lm3533->dev->platform_data; + struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev); int i; int ret; @@ -436,7 +436,7 @@ static int lm3533_device_bl_init(struct lm3533 *lm3533) static int lm3533_device_led_init(struct lm3533 *lm3533) { - struct lm3533_platform_data *pdata = lm3533->dev->platform_data; + struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev); int i; int ret; @@ -481,7 +481,7 @@ static int lm3533_device_setup(struct lm3533 *lm3533, static int lm3533_device_init(struct lm3533 *lm3533) { - struct lm3533_platform_data *pdata = lm3533->dev->platform_data; + struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev); int ret; dev_dbg(lm3533->dev, "%s\n", __func__); diff --git a/drivers/mfd/lp8788.c b/drivers/mfd/lp8788.c index c3d3c9b4d3ad..0f1221911018 100644 --- a/drivers/mfd/lp8788.c +++ b/drivers/mfd/lp8788.c @@ -173,7 +173,7 @@ static const struct regmap_config lp8788_regmap_config = { static int lp8788_probe(struct i2c_client *cl, const struct i2c_device_id *id) { struct lp8788 *lp; - struct lp8788_platform_data *pdata = cl->dev.platform_data; + struct lp8788_platform_data *pdata = dev_get_platdata(&cl->dev); int ret; lp = devm_kzalloc(&cl->dev, sizeof(struct lp8788), GFP_KERNEL); diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 24033324c17a..9483bc8472a5 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -213,7 +213,7 @@ enum lpc_chipsets { LPC_COLETO, /* Coleto Creek */ }; -struct lpc_ich_info lpc_chipset_info[] = { +static struct lpc_ich_info lpc_chipset_info[] = { [LPC_ICH] = { .name = "ICH", .iTCO_version = 1, diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index f27a21831583..522be67b2e68 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -77,7 +77,7 @@ static int max77686_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct max77686_dev *max77686 = NULL; - struct max77686_platform_data *pdata = i2c->dev.platform_data; + struct max77686_platform_data *pdata = dev_get_platdata(&i2c->dev); unsigned int data; int ret = 0; diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c index 9e60fed5ff82..c04723efc707 100644 --- a/drivers/mfd/max77693.c +++ b/drivers/mfd/max77693.c @@ -110,7 +110,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct max77693_dev *max77693; - struct max77693_platform_data *pdata = i2c->dev.platform_data; + struct max77693_platform_data *pdata = dev_get_platdata(&i2c->dev); u8 reg_data; int ret = 0; diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c index 8042b3205eaa..de7fb80a6052 100644 --- a/drivers/mfd/max8925-i2c.c +++ b/drivers/mfd/max8925-i2c.c @@ -151,7 +151,7 @@ static int max8925_dt_init(struct device_node *np, struct device *dev, static int max8925_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct max8925_platform_data *pdata = client->dev.platform_data; + struct max8925_platform_data *pdata = dev_get_platdata(&client->dev); static struct max8925_chip *chip; struct device_node *node = client->dev.of_node; diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c index 14714058f2d2..cee098c0dae3 100644 --- a/drivers/mfd/max8997.c +++ b/drivers/mfd/max8997.c @@ -51,7 +51,7 @@ static struct mfd_cell max8997_devs[] = { #ifdef CONFIG_OF static struct of_device_id max8997_pmic_dt_match[] = { - { .compatible = "maxim,max8997-pmic", .data = TYPE_MAX8997 }, + { .compatible = "maxim,max8997-pmic", .data = (void *)TYPE_MAX8997 }, {}, }; #endif @@ -188,10 +188,11 @@ static int max8997_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct max8997_dev *max8997; - struct max8997_platform_data *pdata = i2c->dev.platform_data; + struct max8997_platform_data *pdata = dev_get_platdata(&i2c->dev); int ret = 0; - max8997 = kzalloc(sizeof(struct max8997_dev), GFP_KERNEL); + max8997 = devm_kzalloc(&i2c->dev, sizeof(struct max8997_dev), + GFP_KERNEL); if (max8997 == NULL) return -ENOMEM; @@ -203,14 +204,12 @@ static int max8997_i2c_probe(struct i2c_client *i2c, if (max8997->dev->of_node) { pdata = max8997_i2c_parse_dt_pdata(max8997->dev); - if (IS_ERR(pdata)) { - ret = PTR_ERR(pdata); - goto err; - } + if (IS_ERR(pdata)) + return PTR_ERR(pdata); } if (!pdata) - goto err; + return ret; max8997->pdata = pdata; max8997->ono = pdata->ono; @@ -250,8 +249,6 @@ err_mfd: i2c_unregister_device(max8997->muic); i2c_unregister_device(max8997->haptic); i2c_unregister_device(max8997->rtc); -err: - kfree(max8997); return ret; } @@ -263,7 +260,6 @@ static int max8997_i2c_remove(struct i2c_client *i2c) i2c_unregister_device(max8997->muic); i2c_unregister_device(max8997->haptic); i2c_unregister_device(max8997->rtc); - kfree(max8997); return 0; } diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index 21af51a499f4..fe6332dcabee 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c @@ -184,11 +184,12 @@ static inline int max8998_i2c_get_driver_data(struct i2c_client *i2c, static int max8998_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct max8998_platform_data *pdata = i2c->dev.platform_data; + struct max8998_platform_data *pdata = dev_get_platdata(&i2c->dev); struct max8998_dev *max8998; int ret = 0; - max8998 = kzalloc(sizeof(struct max8998_dev), GFP_KERNEL); + max8998 = devm_kzalloc(&i2c->dev, sizeof(struct max8998_dev), + GFP_KERNEL); if (max8998 == NULL) return -ENOMEM; @@ -246,7 +247,6 @@ err: mfd_remove_devices(max8998->dev); max8998_irq_exit(max8998); i2c_unregister_device(max8998->rtc); - kfree(max8998); return ret; } @@ -257,7 +257,6 @@ static int max8998_i2c_remove(struct i2c_client *i2c) mfd_remove_devices(max8998->dev); max8998_irq_exit(max8998); i2c_unregister_device(max8998->rtc); - kfree(max8998); return 0; } diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c index 13198d937e36..41c31b3ac940 100644 --- a/drivers/mfd/mcp-sa11x0.c +++ b/drivers/mfd/mcp-sa11x0.c @@ -156,7 +156,7 @@ static struct mcp_ops mcp_sa11x0 = { static int mcp_sa11x0_probe(struct platform_device *dev) { - struct mcp_plat_data *data = dev->dev.platform_data; + struct mcp_plat_data *data = dev_get_platdata(&dev->dev); struct resource *mem0, *mem1; struct mcp_sa11x0 *m; struct mcp *mcp; diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c index 998ce8cb3065..ad25bfa3fb02 100644 --- a/drivers/mfd/menelaus.c +++ b/drivers/mfd/menelaus.c @@ -442,7 +442,7 @@ void menelaus_unregister_mmc_callback(void) menelaus_remove_irq_work(MENELAUS_MMC_S2D1_IRQ); the_menelaus->mmc_callback = NULL; - the_menelaus->mmc_callback_data = 0; + the_menelaus->mmc_callback_data = NULL; } EXPORT_SYMBOL(menelaus_unregister_mmc_callback); @@ -466,7 +466,7 @@ static int menelaus_set_voltage(const struct menelaus_vtg *vtg, int mV, struct i2c_client *c = the_menelaus->client; mutex_lock(&the_menelaus->lock); - if (vtg == 0) + if (!vtg) goto set_voltage; ret = menelaus_read_reg(vtg->vtg_reg); @@ -1189,7 +1189,7 @@ static int menelaus_probe(struct i2c_client *client, int rev = 0, val; int err = 0; struct menelaus_platform_data *menelaus_pdata = - client->dev.platform_data; + dev_get_platdata(&client->dev); if (the_menelaus) { dev_dbg(&client->dev, "only one %s for now\n", @@ -1197,7 +1197,7 @@ static int menelaus_probe(struct i2c_client *client, return -ENODEV; } - menelaus = kzalloc(sizeof *menelaus, GFP_KERNEL); + menelaus = devm_kzalloc(&client->dev, sizeof(*menelaus), GFP_KERNEL); if (!menelaus) return -ENOMEM; @@ -1210,8 +1210,7 @@ static int menelaus_probe(struct i2c_client *client, rev = menelaus_read_reg(MENELAUS_REV); if (rev < 0) { pr_err(DRIVER_NAME ": device not found"); - err = -ENODEV; - goto fail1; + return -ENODEV; } /* Ack and disable all Menelaus interrupts */ @@ -1231,7 +1230,7 @@ static int menelaus_probe(struct i2c_client *client, if (err) { dev_dbg(&client->dev, "can't get IRQ %d, err %d\n", client->irq, err); - goto fail1; + return err; } } @@ -1242,7 +1241,7 @@ static int menelaus_probe(struct i2c_client *client, val = menelaus_read_reg(MENELAUS_VCORE_CTRL1); if (val < 0) - goto fail2; + goto fail; if (val & (1 << 7)) menelaus->vcore_hw_mode = 1; else @@ -1251,17 +1250,15 @@ static int menelaus_probe(struct i2c_client *client, if (menelaus_pdata != NULL && menelaus_pdata->late_init != NULL) { err = menelaus_pdata->late_init(&client->dev); if (err < 0) - goto fail2; + goto fail; } menelaus_rtc_init(menelaus); return 0; -fail2: +fail: free_irq(client->irq, menelaus); flush_work(&menelaus->work); -fail1: - kfree(menelaus); return err; } @@ -1271,7 +1268,6 @@ static int __exit menelaus_remove(struct i2c_client *client) free_irq(client->irq, menelaus); flush_work(&menelaus->work); - kfree(menelaus); the_menelaus = NULL; return 0; } diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 7604f4e5df40..f421586f29fb 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -96,6 +96,8 @@ static int mfd_add_device(struct device *parent, int id, pdev->dev.parent = parent; pdev->dev.type = &mfd_dev_type; + pdev->dev.dma_mask = parent->dma_mask; + pdev->dev.dma_parms = parent->dma_parms; if (parent->of_node && cell->of_compatible) { for_each_child_of_node(parent->of_node, np) { diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 759fae3ca7fb..29ee54d68512 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -114,7 +114,7 @@ struct usbhs_hcd_omap { }; /*-------------------------------------------------------------------------*/ -const char usbhs_driver_name[] = USBHS_DRIVER_NAME; +static const char usbhs_driver_name[] = USBHS_DRIVER_NAME; static u64 usbhs_dmamask = DMA_BIT_MASK(32); /*-------------------------------------------------------------------------*/ @@ -232,7 +232,7 @@ err_end: static int omap_usbhs_alloc_children(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct usbhs_omap_platform_data *pdata = dev->platform_data; + struct usbhs_omap_platform_data *pdata = dev_get_platdata(dev); struct platform_device *ehci; struct platform_device *ohci; struct resource *res; @@ -571,7 +571,7 @@ static struct of_device_id usbhs_child_match_table[] = { static int usbhs_omap_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct usbhs_omap_platform_data *pdata = dev->platform_data; + struct usbhs_omap_platform_data *pdata = dev_get_platdata(dev); struct usbhs_hcd_omap *omap; struct resource *res; int ret = 0; diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index e4d1c706df8b..135afabe4ae2 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c @@ -25,6 +25,52 @@ #include <linux/mfd/palmas.h> #include <linux/of_device.h> +#define PALMAS_EXT_REQ (PALMAS_EXT_CONTROL_ENABLE1 | \ + PALMAS_EXT_CONTROL_ENABLE2 | \ + PALMAS_EXT_CONTROL_NSLEEP) + +struct palmas_sleep_requestor_info { + int id; + int reg_offset; + int bit_pos; +}; + +#define EXTERNAL_REQUESTOR(_id, _offset, _pos) \ + [PALMAS_EXTERNAL_REQSTR_ID_##_id] = { \ + .id = PALMAS_EXTERNAL_REQSTR_ID_##_id, \ + .reg_offset = _offset, \ + .bit_pos = _pos, \ + } + +static struct palmas_sleep_requestor_info sleep_req_info[] = { + EXTERNAL_REQUESTOR(REGEN1, 0, 0), + EXTERNAL_REQUESTOR(REGEN2, 0, 1), + EXTERNAL_REQUESTOR(SYSEN1, 0, 2), + EXTERNAL_REQUESTOR(SYSEN2, 0, 3), + EXTERNAL_REQUESTOR(CLK32KG, 0, 4), + EXTERNAL_REQUESTOR(CLK32KGAUDIO, 0, 5), + EXTERNAL_REQUESTOR(REGEN3, 0, 6), + EXTERNAL_REQUESTOR(SMPS12, 1, 0), + EXTERNAL_REQUESTOR(SMPS3, 1, 1), + EXTERNAL_REQUESTOR(SMPS45, 1, 2), + EXTERNAL_REQUESTOR(SMPS6, 1, 3), + EXTERNAL_REQUESTOR(SMPS7, 1, 4), + EXTERNAL_REQUESTOR(SMPS8, 1, 5), + EXTERNAL_REQUESTOR(SMPS9, 1, 6), + EXTERNAL_REQUESTOR(SMPS10, 1, 7), + EXTERNAL_REQUESTOR(LDO1, 2, 0), + EXTERNAL_REQUESTOR(LDO2, 2, 1), + EXTERNAL_REQUESTOR(LDO3, 2, 2), + EXTERNAL_REQUESTOR(LDO4, 2, 3), + EXTERNAL_REQUESTOR(LDO5, 2, 4), + EXTERNAL_REQUESTOR(LDO6, 2, 5), + EXTERNAL_REQUESTOR(LDO7, 2, 6), + EXTERNAL_REQUESTOR(LDO8, 2, 7), + EXTERNAL_REQUESTOR(LDO9, 3, 0), + EXTERNAL_REQUESTOR(LDOLN, 3, 1), + EXTERNAL_REQUESTOR(LDOUSB, 3, 2), +}; + static const struct regmap_config palmas_regmap_config[PALMAS_NUM_CLIENTS] = { { .reg_bits = 8, @@ -186,6 +232,57 @@ static struct regmap_irq_chip palmas_irq_chip = { PALMAS_INT1_MASK), }; +int palmas_ext_control_req_config(struct palmas *palmas, + enum palmas_external_requestor_id id, int ext_ctrl, bool enable) +{ + int preq_mask_bit = 0; + int reg_add = 0; + int bit_pos; + int ret; + + if (!(ext_ctrl & PALMAS_EXT_REQ)) + return 0; + + if (id >= PALMAS_EXTERNAL_REQSTR_ID_MAX) + return 0; + + if (ext_ctrl & PALMAS_EXT_CONTROL_NSLEEP) { + reg_add = PALMAS_NSLEEP_RES_ASSIGN; + preq_mask_bit = 0; + } else if (ext_ctrl & PALMAS_EXT_CONTROL_ENABLE1) { + reg_add = PALMAS_ENABLE1_RES_ASSIGN; + preq_mask_bit = 1; + } else if (ext_ctrl & PALMAS_EXT_CONTROL_ENABLE2) { + reg_add = PALMAS_ENABLE2_RES_ASSIGN; + preq_mask_bit = 2; + } + + bit_pos = sleep_req_info[id].bit_pos; + reg_add += sleep_req_info[id].reg_offset; + if (enable) + ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE, + reg_add, BIT(bit_pos), BIT(bit_pos)); + else + ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE, + reg_add, BIT(bit_pos), 0); + if (ret < 0) { + dev_err(palmas->dev, "Resource reg 0x%02x update failed %d\n", + reg_add, ret); + return ret; + } + + /* Unmask the PREQ */ + ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE, + PALMAS_POWER_CTRL, BIT(preq_mask_bit), 0); + if (ret < 0) { + dev_err(palmas->dev, "POWER_CTRL register update failed %d\n", + ret); + return ret; + } + return ret; +} +EXPORT_SYMBOL_GPL(palmas_ext_control_req_config); + static int palmas_set_pdata_irq_flag(struct i2c_client *i2c, struct palmas_platform_data *pdata) { @@ -229,6 +326,32 @@ static void palmas_dt_to_pdata(struct i2c_client *i2c, PALMAS_POWER_CTRL_ENABLE2_MASK; if (i2c->irq) palmas_set_pdata_irq_flag(i2c, pdata); + + pdata->pm_off = of_property_read_bool(node, + "ti,system-power-controller"); +} + +static struct palmas *palmas_dev; +static void palmas_power_off(void) +{ + unsigned int addr; + int ret, slave; + + if (!palmas_dev) + return; + + slave = PALMAS_BASE_TO_SLAVE(PALMAS_PMU_CONTROL_BASE); + addr = PALMAS_BASE_TO_REG(PALMAS_PMU_CONTROL_BASE, PALMAS_DEV_CTRL); + + ret = regmap_update_bits( + palmas_dev->regmap[slave], + addr, + PALMAS_DEV_CTRL_DEV_ON, + 0); + + if (ret) + pr_err("%s: Unable to write to DEV_CTRL_DEV_ON: %d\n", + __func__, ret); } static unsigned int palmas_features = PALMAS_PMIC_FEATURE_SMPS10_BOOST; @@ -423,10 +546,13 @@ no_irq: */ if (node) { ret = of_platform_populate(node, NULL, NULL, &i2c->dev); - if (ret < 0) + if (ret < 0) { goto err_irq; - else + } else if (pdata->pm_off && !pm_power_off) { + palmas_dev = palmas; + pm_power_off = palmas_power_off; return ret; + } } return ret; diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c index 18b53cb72fea..b8941a556d71 100644 --- a/drivers/mfd/pcf50633-adc.c +++ b/drivers/mfd/pcf50633-adc.c @@ -203,7 +203,7 @@ static int pcf50633_adc_probe(struct platform_device *pdev) { struct pcf50633_adc *adc; - adc = kzalloc(sizeof(*adc), GFP_KERNEL); + adc = devm_kzalloc(&pdev->dev, sizeof(*adc), GFP_KERNEL); if (!adc) return -ENOMEM; @@ -236,7 +236,6 @@ static int pcf50633_adc_remove(struct platform_device *pdev) kfree(adc->queue[i]); mutex_unlock(&adc->queue_mutex); - kfree(adc); return 0; } diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index d11567307fbe..6841d6805fd6 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -195,7 +195,7 @@ static int pcf50633_probe(struct i2c_client *client, const struct i2c_device_id *ids) { struct pcf50633 *pcf; - struct pcf50633_platform_data *pdata = client->dev.platform_data; + struct pcf50633_platform_data *pdata = dev_get_platdata(&client->dev); int i, ret; int version, variant; diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c index ecc137ffa8c3..a6841f77aa5e 100644 --- a/drivers/mfd/pm8921-core.c +++ b/drivers/mfd/pm8921-core.c @@ -14,6 +14,7 @@ #define pr_fmt(fmt) "%s: " fmt, __func__ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/err.h> @@ -106,7 +107,7 @@ static int pm8921_add_subdevices(const struct pm8921_platform_data static int pm8921_probe(struct platform_device *pdev) { - const struct pm8921_platform_data *pdata = pdev->dev.platform_data; + const struct pm8921_platform_data *pdata = dev_get_platdata(&pdev->dev); struct pm8921 *pmic; int rc; u8 val; @@ -117,7 +118,7 @@ static int pm8921_probe(struct platform_device *pdev) return -EINVAL; } - pmic = kzalloc(sizeof(struct pm8921), GFP_KERNEL); + pmic = devm_kzalloc(&pdev->dev, sizeof(struct pm8921), GFP_KERNEL); if (!pmic) { pr_err("Cannot alloc pm8921 struct\n"); return -ENOMEM; @@ -127,7 +128,7 @@ static int pm8921_probe(struct platform_device *pdev) rc = ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val)); if (rc) { pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc); - goto err_read_rev; + return rc; } pr_info("PMIC revision 1: %02X\n", val); rev = val; @@ -137,7 +138,7 @@ static int pm8921_probe(struct platform_device *pdev) if (rc) { pr_err("Failed to read hw rev 2 reg %d:rc=%d\n", REG_HWREV_2, rc); - goto err_read_rev; + return rc; } pr_info("PMIC revision 2: %02X\n", val); rev |= val << BITS_PER_BYTE; @@ -159,9 +160,6 @@ static int pm8921_probe(struct platform_device *pdev) err: mfd_remove_devices(pmic->dev); - platform_set_drvdata(pdev, NULL); -err_read_rev: - kfree(pmic); return rc; } @@ -179,8 +177,6 @@ static int pm8921_remove(struct platform_device *pdev) pm8xxx_irq_exit(pmic->irq_chip); pmic->irq_chip = NULL; } - platform_set_drvdata(pdev, NULL); - kfree(pmic); return 0; } diff --git a/drivers/mfd/rc5t583.c b/drivers/mfd/rc5t583.c index 14bdaccefbec..346330176afc 100644 --- a/drivers/mfd/rc5t583.c +++ b/drivers/mfd/rc5t583.c @@ -250,7 +250,7 @@ static int rc5t583_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct rc5t583 *rc5t583; - struct rc5t583_platform_data *pdata = i2c->dev.platform_data; + struct rc5t583_platform_data *pdata = dev_get_platdata(&i2c->dev); int ret; bool irq_init_success = false; diff --git a/drivers/mfd/rtl8411.c b/drivers/mfd/rtl8411.c index c436bf27e78d..52801351864d 100644 --- a/drivers/mfd/rtl8411.c +++ b/drivers/mfd/rtl8411.c @@ -1,6 +1,6 @@ /* Driver for Realtek PCI-Express card reader * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -17,7 +17,7 @@ * * Author: * Wei WANG <wei_wang@realsil.com.cn> - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China + * Roger Tseng <rogerable@realtek.com> */ #include <linux/module.h> @@ -47,19 +47,77 @@ static int rtl8411b_is_qfn48(struct rtsx_pcr *pcr) return 0; } +static void rtl8411_fetch_vendor_settings(struct rtsx_pcr *pcr) +{ + u32 reg1; + u8 reg3; + + rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®1); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg1); + + if (!rtsx_vendor_setting_valid(reg1)) + return; + + pcr->aspm_en = rtsx_reg_to_aspm(reg1); + pcr->sd30_drive_sel_1v8 = + map_sd_drive(rtsx_reg_to_sd30_drive_sel_1v8(reg1)); + pcr->card_drive_sel &= 0x3F; + pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg1); + + rtsx_pci_read_config_byte(pcr, PCR_SETTING_REG3, ®3); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG3, reg3); + pcr->sd30_drive_sel_3v3 = rtl8411_reg_to_sd30_drive_sel_3v3(reg3); +} + +static void rtl8411b_fetch_vendor_settings(struct rtsx_pcr *pcr) +{ + u32 reg; + + rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg); + + if (!rtsx_vendor_setting_valid(reg)) + return; + + pcr->aspm_en = rtsx_reg_to_aspm(reg); + pcr->sd30_drive_sel_1v8 = + map_sd_drive(rtsx_reg_to_sd30_drive_sel_1v8(reg)); + pcr->sd30_drive_sel_3v3 = + map_sd_drive(rtl8411b_reg_to_sd30_drive_sel_3v3(reg)); +} + +static void rtl8411_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) +{ + rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07); +} + static int rtl8411_extra_init_hw(struct rtsx_pcr *pcr) { - return rtsx_pci_write_register(pcr, CD_PAD_CTL, + rtsx_pci_init_cmd(pcr); + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL, + 0xFF, pcr->sd30_drive_sel_3v3); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CD_PAD_CTL, CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE); + + return rtsx_pci_send_cmd(pcr, 100); } static int rtl8411b_extra_init_hw(struct rtsx_pcr *pcr) { - if (rtl8411b_is_qfn48(pcr)) - rtsx_pci_write_register(pcr, CARD_PULL_CTL3, 0xFF, 0xF5); + rtsx_pci_init_cmd(pcr); - return rtsx_pci_write_register(pcr, CD_PAD_CTL, + if (rtl8411b_is_qfn48(pcr)) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + CARD_PULL_CTL3, 0xFF, 0xF5); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL, + 0xFF, pcr->sd30_drive_sel_3v3); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CD_PAD_CTL, CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, FUNC_FORCE_CTL, + 0x06, 0x00); + + return rtsx_pci_send_cmd(pcr, 100); } static int rtl8411_turn_on_led(struct rtsx_pcr *pcr) @@ -141,13 +199,13 @@ static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) mask = (BPP_REG_TUNED18 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_MASK; if (voltage == OUTPUT_3V3) { err = rtsx_pci_write_register(pcr, - SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_D); + SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3); if (err < 0) return err; val = (BPP_ASIC_3V3 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_3V3; } else if (voltage == OUTPUT_1V8) { err = rtsx_pci_write_register(pcr, - SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B); + SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8); if (err < 0) return err; val = (BPP_ASIC_1V8 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_1V8; @@ -222,6 +280,7 @@ static int rtl8411_conv_clk_and_div_n(int input, int dir) } static const struct pcr_ops rtl8411_pcr_ops = { + .fetch_vendor_settings = rtl8411_fetch_vendor_settings, .extra_init_hw = rtl8411_extra_init_hw, .optimize_phy = NULL, .turn_on_led = rtl8411_turn_on_led, @@ -233,9 +292,11 @@ static const struct pcr_ops rtl8411_pcr_ops = { .switch_output_voltage = rtl8411_switch_output_voltage, .cd_deglitch = rtl8411_cd_deglitch, .conv_clk_and_div_n = rtl8411_conv_clk_and_div_n, + .force_power_down = rtl8411_force_power_down, }; static const struct pcr_ops rtl8411b_pcr_ops = { + .fetch_vendor_settings = rtl8411b_fetch_vendor_settings, .extra_init_hw = rtl8411b_extra_init_hw, .optimize_phy = NULL, .turn_on_led = rtl8411_turn_on_led, @@ -247,6 +308,7 @@ static const struct pcr_ops rtl8411b_pcr_ops = { .switch_output_voltage = rtl8411_switch_output_voltage, .cd_deglitch = rtl8411_cd_deglitch, .conv_clk_and_div_n = rtl8411_conv_clk_and_div_n, + .force_power_down = rtl8411_force_power_down, }; /* SD Pull Control Enable: @@ -385,6 +447,14 @@ void rtl8411_init_params(struct rtsx_pcr *pcr) pcr->num_slots = 2; pcr->ops = &rtl8411_pcr_ops; + pcr->flags = 0; + pcr->card_drive_sel = RTL8411_CARD_DRIVE_DEFAULT; + pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B; + pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D; + pcr->aspm_en = ASPM_L1_EN; + pcr->tx_initial_phase = SET_CLOCK_PHASE(23, 7, 14); + pcr->rx_initial_phase = SET_CLOCK_PHASE(4, 3, 10); + pcr->ic_version = rtl8411_get_ic_version(pcr); pcr->sd_pull_ctl_enable_tbl = rtl8411_sd_pull_ctl_enable_tbl; pcr->sd_pull_ctl_disable_tbl = rtl8411_sd_pull_ctl_disable_tbl; @@ -398,6 +468,14 @@ void rtl8411b_init_params(struct rtsx_pcr *pcr) pcr->num_slots = 2; pcr->ops = &rtl8411b_pcr_ops; + pcr->flags = 0; + pcr->card_drive_sel = RTL8411_CARD_DRIVE_DEFAULT; + pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B; + pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D; + pcr->aspm_en = ASPM_L1_EN; + pcr->tx_initial_phase = SET_CLOCK_PHASE(23, 7, 14); + pcr->rx_initial_phase = SET_CLOCK_PHASE(4, 3, 10); + pcr->ic_version = rtl8411_get_ic_version(pcr); if (rtl8411b_is_qfn48(pcr)) { diff --git a/drivers/mfd/rts5209.c b/drivers/mfd/rts5209.c index ec78d9fb0879..cb04174a8924 100644 --- a/drivers/mfd/rts5209.c +++ b/drivers/mfd/rts5209.c @@ -1,6 +1,6 @@ /* Driver for Realtek PCI-Express card reader * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -17,7 +17,6 @@ * * Author: * Wei WANG <wei_wang@realsil.com.cn> - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China */ #include <linux/module.h> @@ -34,19 +33,34 @@ static u8 rts5209_get_ic_version(struct rtsx_pcr *pcr) return val & 0x0F; } -static void rts5209_init_vendor_cfg(struct rtsx_pcr *pcr) +static void rts5209_fetch_vendor_settings(struct rtsx_pcr *pcr) { - u32 val; + u32 reg; - rtsx_pci_read_config_dword(pcr, 0x724, &val); - dev_dbg(&(pcr->pci->dev), "Cfg 0x724: 0x%x\n", val); + rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg); - if (!(val & 0x80)) { - if (val & 0x08) - pcr->ms_pmos = false; - else - pcr->ms_pmos = true; + if (rts5209_vendor_setting1_valid(reg)) { + if (rts5209_reg_check_ms_pmos(reg)) + pcr->flags |= PCR_MS_PMOS; + pcr->aspm_en = rts5209_reg_to_aspm(reg); } + + rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, ®); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg); + + if (rts5209_vendor_setting2_valid(reg)) { + pcr->sd30_drive_sel_1v8 = + rts5209_reg_to_sd30_drive_sel_1v8(reg); + pcr->sd30_drive_sel_3v3 = + rts5209_reg_to_sd30_drive_sel_3v3(reg); + pcr->card_drive_sel = rts5209_reg_to_card_drive_sel(reg); + } +} + +static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) +{ + rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07); } static int rts5209_extra_init_hw(struct rtsx_pcr *pcr) @@ -55,8 +69,15 @@ static int rts5209_extra_init_hw(struct rtsx_pcr *pcr) /* Turn off LED */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO, 0xFF, 0x03); + /* Reset ASPM state to default value */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0); + /* Force CLKREQ# PIN to drive 0 to request clock */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08); /* Configure GPIO as output */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO_DIR, 0xFF, 0x03); + /* Configure driving */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL, + 0xFF, pcr->sd30_drive_sel_3v3); return rtsx_pci_send_cmd(pcr, 100); } @@ -95,7 +116,7 @@ static int rts5209_card_power_on(struct rtsx_pcr *pcr, int card) partial_pwr_on = SD_PARTIAL_POWER_ON; pwr_on = SD_POWER_ON; - if (pcr->ms_pmos && (card == RTSX_MS_CARD)) { + if ((pcr->flags & PCR_MS_PMOS) && (card == RTSX_MS_CARD)) { pwr_mask = MS_POWER_MASK; partial_pwr_on = MS_PARTIAL_POWER_ON; pwr_on = MS_POWER_ON; @@ -131,7 +152,7 @@ static int rts5209_card_power_off(struct rtsx_pcr *pcr, int card) pwr_mask = SD_POWER_MASK; pwr_off = SD_POWER_OFF; - if (pcr->ms_pmos && (card == RTSX_MS_CARD)) { + if ((pcr->flags & PCR_MS_PMOS) && (card == RTSX_MS_CARD)) { pwr_mask = MS_POWER_MASK; pwr_off = MS_POWER_OFF; } @@ -140,7 +161,7 @@ static int rts5209_card_power_off(struct rtsx_pcr *pcr, int card) rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL, pwr_mask | PMOS_STRG_MASK, pwr_off | PMOS_STRG_400mA); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, - LDO3318_PWR_MASK, 0X06); + LDO3318_PWR_MASK, 0x06); return rtsx_pci_send_cmd(pcr, 100); } @@ -150,7 +171,7 @@ static int rts5209_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) if (voltage == OUTPUT_3V3) { err = rtsx_pci_write_register(pcr, - SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_D); + SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3); if (err < 0) return err; err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24); @@ -158,7 +179,7 @@ static int rts5209_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) return err; } else if (voltage == OUTPUT_1V8) { err = rtsx_pci_write_register(pcr, - SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B); + SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8); if (err < 0) return err; err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24); @@ -172,6 +193,7 @@ static int rts5209_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) } static const struct pcr_ops rts5209_pcr_ops = { + .fetch_vendor_settings = rts5209_fetch_vendor_settings, .extra_init_hw = rts5209_extra_init_hw, .optimize_phy = rts5209_optimize_phy, .turn_on_led = rts5209_turn_on_led, @@ -183,6 +205,7 @@ static const struct pcr_ops rts5209_pcr_ops = { .switch_output_voltage = rts5209_switch_output_voltage, .cd_deglitch = NULL, .conv_clk_and_div_n = NULL, + .force_power_down = rts5209_force_power_down, }; /* SD Pull Control Enable: @@ -242,7 +265,13 @@ void rts5209_init_params(struct rtsx_pcr *pcr) pcr->num_slots = 2; pcr->ops = &rts5209_pcr_ops; - rts5209_init_vendor_cfg(pcr); + pcr->flags = 0; + pcr->card_drive_sel = RTS5209_CARD_DRIVE_DEFAULT; + pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B; + pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D; + pcr->aspm_en = ASPM_L1_EN; + pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 16); + pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5); pcr->ic_version = rts5209_get_ic_version(pcr); pcr->sd_pull_ctl_enable_tbl = rts5209_sd_pull_ctl_enable_tbl; diff --git a/drivers/mfd/rts5227.c b/drivers/mfd/rts5227.c index 164b7faa70c9..9c8eec80ceed 100644 --- a/drivers/mfd/rts5227.c +++ b/drivers/mfd/rts5227.c @@ -1,6 +1,6 @@ /* Driver for Realtek PCI-Express card reader * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -17,10 +17,7 @@ * * Author: * Wei WANG <wei_wang@realsil.com.cn> - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China - * * Roger Tseng <rogerable@realtek.com> - * No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan */ #include <linux/module.h> @@ -29,6 +26,73 @@ #include "rtsx_pcr.h" +static void rts5227_fill_driving(struct rtsx_pcr *pcr, u8 voltage) +{ + u8 driving_3v3[4][3] = { + {0x13, 0x13, 0x13}, + {0x96, 0x96, 0x96}, + {0x7F, 0x7F, 0x7F}, + {0x96, 0x96, 0x96}, + }; + u8 driving_1v8[4][3] = { + {0x99, 0x99, 0x99}, + {0xAA, 0xAA, 0xAA}, + {0xFE, 0xFE, 0xFE}, + {0xB3, 0xB3, 0xB3}, + }; + u8 (*driving)[3], drive_sel; + + if (voltage == OUTPUT_3V3) { + driving = driving_3v3; + drive_sel = pcr->sd30_drive_sel_3v3; + } else { + driving = driving_1v8; + drive_sel = pcr->sd30_drive_sel_1v8; + } + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL, + 0xFF, driving[drive_sel][0]); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL, + 0xFF, driving[drive_sel][1]); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL, + 0xFF, driving[drive_sel][2]); +} + +static void rts5227_fetch_vendor_settings(struct rtsx_pcr *pcr) +{ + u32 reg; + + rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg); + + if (!rtsx_vendor_setting_valid(reg)) + return; + + pcr->aspm_en = rtsx_reg_to_aspm(reg); + pcr->sd30_drive_sel_1v8 = rtsx_reg_to_sd30_drive_sel_1v8(reg); + pcr->card_drive_sel &= 0x3F; + pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg); + + rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, ®); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg); + pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg); + if (rtsx_reg_check_reverse_socket(reg)) + pcr->flags |= PCR_REVERSE_SOCKET; +} + +static void rts5227_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) +{ + /* Set relink_time to 0 */ + rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, 0xFF, 0); + rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, 0xFF, 0); + rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3, 0x01, 0); + + if (pm_state == HOST_ENTER_S3) + rtsx_pci_write_register(pcr, PM_CTRL3, 0x10, 0x10); + + rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03); +} + static int rts5227_extra_init_hw(struct rtsx_pcr *pcr) { u16 cap; @@ -37,6 +101,8 @@ static int rts5227_extra_init_hw(struct rtsx_pcr *pcr) /* Configure GPIO as output */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02); + /* Reset ASPM state to default value */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0); /* Switch LDO3318 source from DV33 to card_3v3 */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01); @@ -48,17 +114,16 @@ static int rts5227_extra_init_hw(struct rtsx_pcr *pcr) rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LTR_CTL, 0xFF, 0xA3); /* Configure OBFF */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OBFF_CFG, 0x03, 0x03); - /* Configure force_clock_req - * Maybe We should define 0xFF03 as some name - */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, 0xFF03, 0x08, 0x08); - /* Correct driving */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - SD30_CLK_DRIVE_SEL, 0xFF, 0x96); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - SD30_CMD_DRIVE_SEL, 0xFF, 0x96); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - SD30_DAT_DRIVE_SEL, 0xFF, 0x96); + /* Configure driving */ + rts5227_fill_driving(pcr, OUTPUT_3V3); + /* Configure force_clock_req */ + if (pcr->flags & PCR_REVERSE_SOCKET) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + AUTOLOAD_CFG_BASE + 3, 0xB8, 0xB8); + else + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + AUTOLOAD_CFG_BASE + 3, 0xB8, 0x88); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PM_CTRL3, 0x10, 0x00); return rtsx_pci_send_cmd(pcr, 100); } @@ -131,13 +196,11 @@ static int rts5227_card_power_off(struct rtsx_pcr *pcr, int card) static int rts5227_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) { int err; - u8 drive_sel; if (voltage == OUTPUT_3V3) { err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24); if (err < 0) return err; - drive_sel = 0x96; } else if (voltage == OUTPUT_1V8) { err = rtsx_pci_write_phy_register(pcr, 0x11, 0x3C02); if (err < 0) @@ -145,23 +208,18 @@ static int rts5227_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C80 | 0x24); if (err < 0) return err; - drive_sel = 0xB3; } else { return -EINVAL; } /* set pad drive */ rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL, - 0xFF, drive_sel); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL, - 0xFF, drive_sel); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL, - 0xFF, drive_sel); + rts5227_fill_driving(pcr, voltage); return rtsx_pci_send_cmd(pcr, 100); } static const struct pcr_ops rts5227_pcr_ops = { + .fetch_vendor_settings = rts5227_fetch_vendor_settings, .extra_init_hw = rts5227_extra_init_hw, .optimize_phy = rts5227_optimize_phy, .turn_on_led = rts5227_turn_on_led, @@ -173,6 +231,7 @@ static const struct pcr_ops rts5227_pcr_ops = { .switch_output_voltage = rts5227_switch_output_voltage, .cd_deglitch = NULL, .conv_clk_and_div_n = NULL, + .force_power_down = rts5227_force_power_down, }; /* SD Pull Control Enable: @@ -227,6 +286,14 @@ void rts5227_init_params(struct rtsx_pcr *pcr) pcr->num_slots = 2; pcr->ops = &rts5227_pcr_ops; + pcr->flags = 0; + pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT; + pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B; + pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B; + pcr->aspm_en = ASPM_L1_EN; + pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 15); + pcr->rx_initial_phase = SET_CLOCK_PHASE(30, 7, 7); + pcr->sd_pull_ctl_enable_tbl = rts5227_sd_pull_ctl_enable_tbl; pcr->sd_pull_ctl_disable_tbl = rts5227_sd_pull_ctl_disable_tbl; pcr->ms_pull_ctl_enable_tbl = rts5227_ms_pull_ctl_enable_tbl; diff --git a/drivers/mfd/rts5229.c b/drivers/mfd/rts5229.c index 58af4dbe3586..6353f5df087a 100644 --- a/drivers/mfd/rts5229.c +++ b/drivers/mfd/rts5229.c @@ -1,6 +1,6 @@ /* Driver for Realtek PCI-Express card reader * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -17,7 +17,6 @@ * * Author: * Wei WANG <wei_wang@realsil.com.cn> - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China */ #include <linux/module.h> @@ -34,17 +33,51 @@ static u8 rts5229_get_ic_version(struct rtsx_pcr *pcr) return val & 0x0F; } +static void rts5229_fetch_vendor_settings(struct rtsx_pcr *pcr) +{ + u32 reg; + + rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg); + + if (!rtsx_vendor_setting_valid(reg)) + return; + + pcr->aspm_en = rtsx_reg_to_aspm(reg); + pcr->sd30_drive_sel_1v8 = + map_sd_drive(rtsx_reg_to_sd30_drive_sel_1v8(reg)); + pcr->card_drive_sel &= 0x3F; + pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg); + + rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, ®); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg); + pcr->sd30_drive_sel_3v3 = + map_sd_drive(rtsx_reg_to_sd30_drive_sel_3v3(reg)); +} + +static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) +{ + rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03); +} + static int rts5229_extra_init_hw(struct rtsx_pcr *pcr) { rtsx_pci_init_cmd(pcr); /* Configure GPIO as output */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02); + /* Reset ASPM state to default value */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0); + /* Force CLKREQ# PIN to drive 0 to request clock */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08); /* Switch LDO3318 source from DV33 to card_3v3 */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01); /* LED shine disabled, set initial shine cycle period */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02); + /* Configure driving */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL, + 0xFF, pcr->sd30_drive_sel_3v3); return rtsx_pci_send_cmd(pcr, 100); } @@ -110,7 +143,7 @@ static int rts5229_card_power_off(struct rtsx_pcr *pcr, int card) SD_POWER_MASK | PMOS_STRG_MASK, SD_POWER_OFF | PMOS_STRG_400mA); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL, - LDO3318_PWR_MASK, 0X00); + LDO3318_PWR_MASK, 0x00); return rtsx_pci_send_cmd(pcr, 100); } @@ -120,7 +153,7 @@ static int rts5229_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) if (voltage == OUTPUT_3V3) { err = rtsx_pci_write_register(pcr, - SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_D); + SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3); if (err < 0) return err; err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24); @@ -128,7 +161,7 @@ static int rts5229_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) return err; } else if (voltage == OUTPUT_1V8) { err = rtsx_pci_write_register(pcr, - SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B); + SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8); if (err < 0) return err; err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24); @@ -142,6 +175,7 @@ static int rts5229_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) } static const struct pcr_ops rts5229_pcr_ops = { + .fetch_vendor_settings = rts5229_fetch_vendor_settings, .extra_init_hw = rts5229_extra_init_hw, .optimize_phy = rts5229_optimize_phy, .turn_on_led = rts5229_turn_on_led, @@ -153,6 +187,7 @@ static const struct pcr_ops rts5229_pcr_ops = { .switch_output_voltage = rts5229_switch_output_voltage, .cd_deglitch = NULL, .conv_clk_and_div_n = NULL, + .force_power_down = rts5229_force_power_down, }; /* SD Pull Control Enable: @@ -221,6 +256,14 @@ void rts5229_init_params(struct rtsx_pcr *pcr) pcr->num_slots = 2; pcr->ops = &rts5229_pcr_ops; + pcr->flags = 0; + pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT; + pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B; + pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D; + pcr->aspm_en = ASPM_L1_EN; + pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 15); + pcr->rx_initial_phase = SET_CLOCK_PHASE(30, 6, 6); + pcr->ic_version = rts5229_get_ic_version(pcr); if (pcr->ic_version == IC_VER_C) { pcr->sd_pull_ctl_enable_tbl = rts5229_sd_pull_ctl_enable_tbl2; diff --git a/drivers/mfd/rts5249.c b/drivers/mfd/rts5249.c index 15dc848bc081..3b835f593e35 100644 --- a/drivers/mfd/rts5249.c +++ b/drivers/mfd/rts5249.c @@ -17,7 +17,6 @@ * * Author: * Wei WANG <wei_wang@realsil.com.cn> - * No. 128, West Shenhu Road, Suzhou Industry Park, Suzhou, China */ #include <linux/module.h> @@ -34,24 +33,95 @@ static u8 rts5249_get_ic_version(struct rtsx_pcr *pcr) return val & 0x0F; } +static void rts5249_fill_driving(struct rtsx_pcr *pcr, u8 voltage) +{ + u8 driving_3v3[4][3] = { + {0x11, 0x11, 0x11}, + {0x55, 0x55, 0x5C}, + {0x99, 0x99, 0x92}, + {0x99, 0x99, 0x92}, + }; + u8 driving_1v8[4][3] = { + {0x3C, 0x3C, 0x3C}, + {0xB3, 0xB3, 0xB3}, + {0xFE, 0xFE, 0xFE}, + {0xC4, 0xC4, 0xC4}, + }; + u8 (*driving)[3], drive_sel; + + if (voltage == OUTPUT_3V3) { + driving = driving_3v3; + drive_sel = pcr->sd30_drive_sel_3v3; + } else { + driving = driving_1v8; + drive_sel = pcr->sd30_drive_sel_1v8; + } + + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL, + 0xFF, driving[drive_sel][0]); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL, + 0xFF, driving[drive_sel][1]); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL, + 0xFF, driving[drive_sel][2]); +} + +static void rts5249_fetch_vendor_settings(struct rtsx_pcr *pcr) +{ + u32 reg; + + rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, ®); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg); + + if (!rtsx_vendor_setting_valid(reg)) + return; + + pcr->aspm_en = rtsx_reg_to_aspm(reg); + pcr->sd30_drive_sel_1v8 = rtsx_reg_to_sd30_drive_sel_1v8(reg); + pcr->card_drive_sel &= 0x3F; + pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg); + + rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, ®); + dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg); + pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg); + if (rtsx_reg_check_reverse_socket(reg)) + pcr->flags |= PCR_REVERSE_SOCKET; +} + +static void rts5249_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) +{ + /* Set relink_time to 0 */ + rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, 0xFF, 0); + rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, 0xFF, 0); + rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3, 0x01, 0); + + if (pm_state == HOST_ENTER_S3) + rtsx_pci_write_register(pcr, PM_CTRL3, 0x10, 0x10); + + rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03); +} + static int rts5249_extra_init_hw(struct rtsx_pcr *pcr) { rtsx_pci_init_cmd(pcr); /* Configure GPIO as output */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02); + /* Reset ASPM state to default value */ + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0); /* Switch LDO3318 source from DV33 to card_3v3 */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01); /* LED shine disabled, set initial shine cycle period */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02); - /* Correct driving */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - SD30_CLK_DRIVE_SEL, 0xFF, 0x99); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - SD30_CMD_DRIVE_SEL, 0xFF, 0x99); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, - SD30_DAT_DRIVE_SEL, 0xFF, 0x92); + /* Configure driving */ + rts5249_fill_driving(pcr, OUTPUT_3V3); + if (pcr->flags & PCR_REVERSE_SOCKET) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + AUTOLOAD_CFG_BASE + 3, 0xB0, 0xB0); + else + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + AUTOLOAD_CFG_BASE + 3, 0xB0, 0x80); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PM_CTRL3, 0x10, 0x00); return rtsx_pci_send_cmd(pcr, 100); } @@ -129,15 +199,11 @@ static int rts5249_card_power_off(struct rtsx_pcr *pcr, int card) static int rts5249_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) { int err; - u8 clk_drive, cmd_drive, dat_drive; if (voltage == OUTPUT_3V3) { err = rtsx_pci_write_phy_register(pcr, PHY_TUNE, 0x4FC0 | 0x24); if (err < 0) return err; - clk_drive = 0x99; - cmd_drive = 0x99; - dat_drive = 0x92; } else if (voltage == OUTPUT_1V8) { err = rtsx_pci_write_phy_register(pcr, PHY_BACR, 0x3C02); if (err < 0) @@ -145,25 +211,18 @@ static int rts5249_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) err = rtsx_pci_write_phy_register(pcr, PHY_TUNE, 0x4C40 | 0x24); if (err < 0) return err; - clk_drive = 0xb3; - cmd_drive = 0xb3; - dat_drive = 0xb3; } else { return -EINVAL; } /* set pad drive */ rtsx_pci_init_cmd(pcr); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL, - 0xFF, clk_drive); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL, - 0xFF, cmd_drive); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL, - 0xFF, dat_drive); + rts5249_fill_driving(pcr, voltage); return rtsx_pci_send_cmd(pcr, 100); } static const struct pcr_ops rts5249_pcr_ops = { + .fetch_vendor_settings = rts5249_fetch_vendor_settings, .extra_init_hw = rts5249_extra_init_hw, .optimize_phy = rts5249_optimize_phy, .turn_on_led = rts5249_turn_on_led, @@ -173,6 +232,7 @@ static const struct pcr_ops rts5249_pcr_ops = { .card_power_on = rts5249_card_power_on, .card_power_off = rts5249_card_power_off, .switch_output_voltage = rts5249_switch_output_voltage, + .force_power_down = rts5249_force_power_down, }; /* SD Pull Control Enable: @@ -233,6 +293,14 @@ void rts5249_init_params(struct rtsx_pcr *pcr) pcr->num_slots = 2; pcr->ops = &rts5249_pcr_ops; + pcr->flags = 0; + pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT; + pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_C; + pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B; + pcr->aspm_en = ASPM_L1_EN; + pcr->tx_initial_phase = SET_CLOCK_PHASE(1, 29, 16); + pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5); + pcr->ic_version = rts5249_get_ic_version(pcr); pcr->sd_pull_ctl_enable_tbl = rts5249_sd_pull_ctl_enable_tbl; pcr->sd_pull_ctl_disable_tbl = rts5249_sd_pull_ctl_disable_tbl; diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c index dd186c4103c1..e6ae7720f9e1 100644 --- a/drivers/mfd/rtsx_pcr.c +++ b/drivers/mfd/rtsx_pcr.c @@ -1,6 +1,6 @@ /* Driver for Realtek PCI-Express card reader * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -17,7 +17,6 @@ * * Author: * Wei WANG <wei_wang@realsil.com.cn> - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China */ #include <linux/pci.h> @@ -73,6 +72,9 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr) pcr->state = PDEV_STAT_RUN; if (pcr->ops->enable_auto_blink) pcr->ops->enable_auto_blink(pcr); + + if (pcr->aspm_en) + rtsx_pci_write_config_byte(pcr, LCTLR, 0); } mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200)); @@ -717,7 +719,7 @@ int rtsx_pci_card_exclusive_check(struct rtsx_pcr *pcr, int card) [RTSX_MS_CARD] = MS_EXIST }; - if (!pcr->ms_pmos) { + if (!(pcr->flags & PCR_MS_PMOS)) { /* When using single PMOS, accessing card is not permitted * if the existing card is not the designated one. */ @@ -918,9 +920,27 @@ static void rtsx_pci_idle_work(struct work_struct *work) if (pcr->ops->turn_off_led) pcr->ops->turn_off_led(pcr); + if (pcr->aspm_en) + rtsx_pci_write_config_byte(pcr, LCTLR, pcr->aspm_en); + mutex_unlock(&pcr->pcr_mutex); } +static void rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state) +{ + if (pcr->ops->turn_off_led) + pcr->ops->turn_off_led(pcr); + + rtsx_pci_writel(pcr, RTSX_BIER, 0); + pcr->bier = 0; + + rtsx_pci_write_register(pcr, PETXCFG, 0x08, 0x08); + rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, pm_state); + + if (pcr->ops->force_power_down) + pcr->ops->force_power_down(pcr, pm_state); +} + static int rtsx_pci_init_hw(struct rtsx_pcr *pcr) { int err; @@ -951,13 +971,11 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr) rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, HOST_SLEEP_STATE, 0x03, 0x00); /* Disable card clock */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, 0x1E, 0); - /* Reset ASPM state to default value */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0); /* Reset delink mode */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CHANGE_LINK_STATE, 0x0A, 0); /* Card driving select */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL, - 0x07, DRIVER_TYPE_D); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DRIVE_SEL, + 0xFF, pcr->card_drive_sel); /* Enable SSC Clock */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, 0xFF, SSC_8X_EN | SSC_SEL_4M); @@ -982,13 +1000,13 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr) * 0: ELBI interrupt flag[31:22] & [7:0] only can be write clear */ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, NFTS_TX_CTRL, 0x02, 0); - /* Force CLKREQ# PIN to drive 0 to request clock */ - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08); err = rtsx_pci_send_cmd(pcr, 100); if (err < 0) return err; + rtsx_pci_write_config_byte(pcr, LCTLR, 0); + /* Enable clk_request_n to enable clock power management */ rtsx_pci_write_config_byte(pcr, 0x81, 1); /* Enter L1 when host tx idle */ @@ -1053,6 +1071,18 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr) if (!pcr->slots) return -ENOMEM; + if (pcr->ops->fetch_vendor_settings) + pcr->ops->fetch_vendor_settings(pcr); + + dev_dbg(&(pcr->pci->dev), "pcr->aspm_en = 0x%x\n", pcr->aspm_en); + dev_dbg(&(pcr->pci->dev), "pcr->sd30_drive_sel_1v8 = 0x%x\n", + pcr->sd30_drive_sel_1v8); + dev_dbg(&(pcr->pci->dev), "pcr->sd30_drive_sel_3v3 = 0x%x\n", + pcr->sd30_drive_sel_3v3); + dev_dbg(&(pcr->pci->dev), "pcr->card_drive_sel = 0x%x\n", + pcr->card_drive_sel); + dev_dbg(&(pcr->pci->dev), "pcr->flags = 0x%x\n", pcr->flags); + pcr->state = PDEV_STAT_IDLE; err = rtsx_pci_init_hw(pcr); if (err < 0) { @@ -1235,7 +1265,6 @@ static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state) { struct pcr_handle *handle; struct rtsx_pcr *pcr; - int ret = 0; dev_dbg(&(pcidev->dev), "--> %s\n", __func__); @@ -1247,14 +1276,7 @@ static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state) mutex_lock(&pcr->pcr_mutex); - if (pcr->ops->turn_off_led) - pcr->ops->turn_off_led(pcr); - - rtsx_pci_writel(pcr, RTSX_BIER, 0); - pcr->bier = 0; - - rtsx_pci_write_register(pcr, PETXCFG, 0x08, 0x08); - rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x02); + rtsx_pci_power_off(pcr, HOST_ENTER_S3); pci_save_state(pcidev); pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0); @@ -1262,7 +1284,7 @@ static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state) pci_set_power_state(pcidev, pci_choose_state(pcidev, state)); mutex_unlock(&pcr->pcr_mutex); - return ret; + return 0; } static int rtsx_pci_resume(struct pci_dev *pcidev) @@ -1300,10 +1322,25 @@ out: return ret; } +static void rtsx_pci_shutdown(struct pci_dev *pcidev) +{ + struct pcr_handle *handle; + struct rtsx_pcr *pcr; + + dev_dbg(&(pcidev->dev), "--> %s\n", __func__); + + handle = pci_get_drvdata(pcidev); + pcr = handle->pcr; + rtsx_pci_power_off(pcr, HOST_ENTER_S1); + + pci_disable_device(pcidev); +} + #else /* CONFIG_PM */ #define rtsx_pci_suspend NULL #define rtsx_pci_resume NULL +#define rtsx_pci_shutdown NULL #endif /* CONFIG_PM */ @@ -1314,6 +1351,7 @@ static struct pci_driver rtsx_pci_driver = { .remove = rtsx_pci_remove, .suspend = rtsx_pci_suspend, .resume = rtsx_pci_resume, + .shutdown = rtsx_pci_shutdown, }; module_pci_driver(rtsx_pci_driver); diff --git a/drivers/mfd/rtsx_pcr.h b/drivers/mfd/rtsx_pcr.h index c0cac7e8972f..947e79b05ceb 100644 --- a/drivers/mfd/rtsx_pcr.h +++ b/drivers/mfd/rtsx_pcr.h @@ -1,6 +1,6 @@ /* Driver for Realtek PCI-Express card reader * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -17,7 +17,6 @@ * * Author: * Wei WANG <wei_wang@realsil.com.cn> - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China */ #ifndef __RTSX_PCR_H @@ -35,4 +34,33 @@ void rts5227_init_params(struct rtsx_pcr *pcr); void rts5249_init_params(struct rtsx_pcr *pcr); void rtl8411b_init_params(struct rtsx_pcr *pcr); +static inline u8 map_sd_drive(int idx) +{ + u8 sd_drive[4] = { + 0x01, /* Type D */ + 0x02, /* Type C */ + 0x05, /* Type A */ + 0x03 /* Type B */ + }; + + return sd_drive[idx]; +} + +#define rtsx_vendor_setting_valid(reg) (!((reg) & 0x1000000)) +#define rts5209_vendor_setting1_valid(reg) (!((reg) & 0x80)) +#define rts5209_vendor_setting2_valid(reg) ((reg) & 0x80) + +#define rtsx_reg_to_aspm(reg) (((reg) >> 28) & 0x03) +#define rtsx_reg_to_sd30_drive_sel_1v8(reg) (((reg) >> 26) & 0x03) +#define rtsx_reg_to_sd30_drive_sel_3v3(reg) (((reg) >> 5) & 0x03) +#define rtsx_reg_to_card_drive_sel(reg) ((((reg) >> 25) & 0x01) << 6) +#define rtsx_reg_check_reverse_socket(reg) ((reg) & 0x4000) +#define rts5209_reg_to_aspm(reg) (((reg) >> 5) & 0x03) +#define rts5209_reg_check_ms_pmos(reg) (!((reg) & 0x08)) +#define rts5209_reg_to_sd30_drive_sel_1v8(reg) (((reg) >> 3) & 0x07) +#define rts5209_reg_to_sd30_drive_sel_3v3(reg) ((reg) & 0x07) +#define rts5209_reg_to_card_drive_sel(reg) ((reg) >> 8) +#define rtl8411_reg_to_sd30_drive_sel_3v3(reg) (((reg) >> 5) & 0x07) +#define rtl8411b_reg_to_sd30_drive_sel_3v3(reg) ((reg) & 0x03) + #endif diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 79767681483a..f530e4b73f19 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -61,7 +61,9 @@ static struct mfd_cell s5m8767_devs[] = { static struct mfd_cell s2mps11_devs[] = { { .name = "s2mps11-pmic", - }, + }, { + .name = "s2mps11-clk", + } }; #ifdef CONFIG_OF @@ -69,6 +71,9 @@ static struct of_device_id sec_dt_match[] = { { .compatible = "samsung,s5m8767-pmic", .data = (void *)S5M8767X, }, + { .compatible = "samsung,s2mps11-pmic", + .data = (void *)S2MPS11X, + }, {}, }; #endif @@ -103,6 +108,31 @@ int sec_reg_update(struct sec_pmic_dev *sec_pmic, u8 reg, u8 val, u8 mask) } EXPORT_SYMBOL_GPL(sec_reg_update); +static bool s2mps11_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case S2MPS11_REG_INT1M: + case S2MPS11_REG_INT2M: + case S2MPS11_REG_INT3M: + return false; + default: + return true; + } +} + +static bool s5m8763_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case S5M8763_REG_IRQM1: + case S5M8763_REG_IRQM2: + case S5M8763_REG_IRQM3: + case S5M8763_REG_IRQM4: + return false; + default: + return true; + } +} + static struct regmap_config sec_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -113,6 +143,8 @@ static struct regmap_config s2mps11_regmap_config = { .val_bits = 8, .max_register = S2MPS11_REG_L38CTRL, + .volatile_reg = s2mps11_volatile, + .cache_type = REGCACHE_FLAT, }; static struct regmap_config s5m8763_regmap_config = { @@ -120,6 +152,8 @@ static struct regmap_config s5m8763_regmap_config = { .val_bits = 8, .max_register = S5M8763_REG_LBCNFG2, + .volatile_reg = s5m8763_volatile, + .cache_type = REGCACHE_FLAT, }; static struct regmap_config s5m8767_regmap_config = { @@ -127,6 +161,8 @@ static struct regmap_config s5m8767_regmap_config = { .val_bits = 8, .max_register = S5M8767_REG_LDO28CTRL, + .volatile_reg = s2mps11_volatile, + .cache_type = REGCACHE_FLAT, }; #ifdef CONFIG_OF @@ -182,7 +218,7 @@ static inline int sec_i2c_get_driver_data(struct i2c_client *i2c, static int sec_pmic_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct sec_platform_data *pdata = i2c->dev.platform_data; + struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev); const struct regmap_config *regmap; struct sec_pmic_dev *sec_pmic; int ret; diff --git a/drivers/mfd/si476x-i2c.c b/drivers/mfd/si476x-i2c.c index f5bc8e4bd4bf..0e4a76daf187 100644 --- a/drivers/mfd/si476x-i2c.c +++ b/drivers/mfd/si476x-i2c.c @@ -718,7 +718,7 @@ static int si476x_core_probe(struct i2c_client *client, atomic_set(&core->is_alive, 0); core->power_state = SI476X_POWER_DOWN; - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); if (pdata) { memcpy(&core->power_up_parameters, &pdata->power_up_parameters, diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 9816c232e583..33f040c558d0 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -840,7 +840,7 @@ static int sm501_register_uart(struct sm501_devdata *sm, int devices) if (!pdev) return -ENOMEM; - uart_data = pdev->dev.platform_data; + uart_data = dev_get_platdata(&pdev->dev); if (devices & SM501_USE_UART0) { sm501_setup_uart_data(sm, uart_data++, 0x30000); @@ -1167,7 +1167,7 @@ static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm, if (!pdev) return -ENOMEM; - icd = pdev->dev.platform_data; + icd = dev_get_platdata(&pdev->dev); /* We keep the pin_sda and pin_scl fields relative in case the * same platform data is passed to >1 SM501. @@ -1403,7 +1403,7 @@ static int sm501_plat_probe(struct platform_device *dev) sm->dev = &dev->dev; sm->pdev_id = dev->id; - sm->platdata = dev->dev.platform_data; + sm->platdata = dev_get_platdata(&dev->dev); ret = platform_get_irq(dev, 0); if (ret < 0) { diff --git a/drivers/mfd/sta2x11-mfd.c b/drivers/mfd/sta2x11-mfd.c index d70a343078fd..65c6fa671acb 100644 --- a/drivers/mfd/sta2x11-mfd.c +++ b/drivers/mfd/sta2x11-mfd.c @@ -133,7 +133,7 @@ int sta2x11_mfd_get_regs_data(struct platform_device *dev, void __iomem **regs, spinlock_t **lock) { - struct pci_dev *pdev = *(struct pci_dev **)(dev->dev.platform_data); + struct pci_dev *pdev = *(struct pci_dev **)dev_get_platdata(&dev->dev); struct sta2x11_mfd *mfd; if (!pdev) @@ -312,7 +312,7 @@ static int sta2x11_mfd_platform_probe(struct platform_device *dev, const char *name = sta2x11_mfd_names[index]; struct regmap_config *regmap_config = sta2x11_mfd_regmap_configs[index]; - pdev = dev->dev.platform_data; + pdev = dev_get_platdata(&dev->dev); mfd = sta2x11_mfd_find(*pdev); if (!mfd) return -ENODEV; diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 5d5e6f90424a..fff63a41862c 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -1106,7 +1106,8 @@ static int stmpe_devices_init(struct stmpe *stmpe) return ret; } -void stmpe_of_probe(struct stmpe_platform_data *pdata, struct device_node *np) +static void stmpe_of_probe(struct stmpe_platform_data *pdata, + struct device_node *np) { struct device_node *child; diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index 962a6e17a01a..71841f9181bd 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -25,7 +25,6 @@ static struct platform_driver syscon_driver; struct syscon { - void __iomem *base; struct regmap *regmap; }; @@ -129,6 +128,7 @@ static int syscon_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct syscon *syscon; struct resource *res; + void __iomem *base; syscon = devm_kzalloc(dev, sizeof(*syscon), GFP_KERNEL); if (!syscon) @@ -138,12 +138,12 @@ static int syscon_probe(struct platform_device *pdev) if (!res) return -ENOENT; - syscon->base = devm_ioremap(dev, res->start, resource_size(res)); - if (!syscon->base) + base = devm_ioremap(dev, res->start, resource_size(res)); + if (!base) return -ENOMEM; syscon_regmap_config.max_register = res->end - res->start - 3; - syscon->regmap = devm_regmap_init_mmio(dev, syscon->base, + syscon->regmap = devm_regmap_init_mmio(dev, base, &syscon_regmap_config); if (IS_ERR(syscon->regmap)) { dev_err(dev, "regmap init failed\n"); diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index a21bff283a98..9e04a7485981 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -281,7 +281,7 @@ static void t7l66xb_detach_irq(struct platform_device *dev) static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state) { struct t7l66xb *t7l66xb = platform_get_drvdata(dev); - struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev); if (pdata && pdata->suspend) pdata->suspend(dev); @@ -293,7 +293,7 @@ static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state) static int t7l66xb_resume(struct platform_device *dev) { struct t7l66xb *t7l66xb = platform_get_drvdata(dev); - struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev); clk_enable(t7l66xb->clk48m); if (pdata && pdata->resume) @@ -313,7 +313,7 @@ static int t7l66xb_resume(struct platform_device *dev) static int t7l66xb_probe(struct platform_device *dev) { - struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev); struct t7l66xb *t7l66xb; struct resource *iomem, *rscr; int ret; @@ -409,7 +409,7 @@ err_noirq: static int t7l66xb_remove(struct platform_device *dev) { - struct t7l66xb_platform_data *pdata = dev->dev.platform_data; + struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev); struct t7l66xb *t7l66xb = platform_get_drvdata(dev); int ret; diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index 4cb92bb2aea2..70f4909fee13 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c @@ -325,7 +325,7 @@ static int tc3589x_of_probe(struct device_node *np, static int tc3589x_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - struct tc3589x_platform_data *pdata = i2c->dev.platform_data; + struct tc3589x_platform_data *pdata = dev_get_platdata(&i2c->dev); struct device_node *np = i2c->dev.of_node; struct tc3589x *tc3589x; int ret; diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c index 65c425a517c5..acd0f3a41044 100644 --- a/drivers/mfd/tc6387xb.c +++ b/drivers/mfd/tc6387xb.c @@ -48,7 +48,7 @@ static struct resource tc6387xb_mmc_resources[] = { static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state) { struct tc6387xb *tc6387xb = platform_get_drvdata(dev); - struct tc6387xb_platform_data *pdata = dev->dev.platform_data; + struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev); if (pdata && pdata->suspend) pdata->suspend(dev); @@ -60,7 +60,7 @@ static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state) static int tc6387xb_resume(struct platform_device *dev) { struct tc6387xb *tc6387xb = platform_get_drvdata(dev); - struct tc6387xb_platform_data *pdata = dev->dev.platform_data; + struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev); clk_enable(tc6387xb->clk32k); if (pdata && pdata->resume) @@ -140,7 +140,7 @@ static struct mfd_cell tc6387xb_cells[] = { static int tc6387xb_probe(struct platform_device *dev) { - struct tc6387xb_platform_data *pdata = dev->dev.platform_data; + struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev); struct resource *iomem, *rscr; struct clk *clk32k; struct tc6387xb *tc6387xb; diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index a563dfa3cf87..11c19e538551 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -604,7 +604,7 @@ static void tc6393xb_detach_irq(struct platform_device *dev) static int tc6393xb_probe(struct platform_device *dev) { - struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; + struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev); struct tc6393xb *tc6393xb; struct resource *iomem, *rscr; int ret, temp; @@ -733,7 +733,7 @@ err_kzalloc: static int tc6393xb_remove(struct platform_device *dev) { - struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; + struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev); struct tc6393xb *tc6393xb = platform_get_drvdata(dev); int ret; @@ -765,7 +765,7 @@ static int tc6393xb_remove(struct platform_device *dev) #ifdef CONFIG_PM static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state) { - struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; + struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev); struct tc6393xb *tc6393xb = platform_get_drvdata(dev); int i, ret; @@ -788,7 +788,7 @@ static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state) static int tc6393xb_resume(struct platform_device *dev) { - struct tc6393xb_platform_data *tcpd = dev->dev.platform_data; + struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev); struct tc6393xb *tc6393xb = platform_get_drvdata(dev); int ret; int i; diff --git a/drivers/mfd/ti-ssp.c b/drivers/mfd/ti-ssp.c index 09a14cec351b..1c2b994e1f6c 100644 --- a/drivers/mfd/ti-ssp.c +++ b/drivers/mfd/ti-ssp.c @@ -318,7 +318,7 @@ static irqreturn_t ti_ssp_interrupt(int irq, void *dev_data) static int ti_ssp_probe(struct platform_device *pdev) { static struct ti_ssp *ssp; - const struct ti_ssp_data *pdata = pdev->dev.platform_data; + const struct ti_ssp_data *pdata = dev_get_platdata(&pdev->dev); int error = 0, prediv = 0xff, id; unsigned long sysclk; struct device *dev = &pdev->dev; diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index b003a16ba227..baaf5a8123bb 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -57,20 +57,20 @@ EXPORT_SYMBOL_GPL(am335x_tsc_se_update); void am335x_tsc_se_set(struct ti_tscadc_dev *tsadc, u32 val) { spin_lock(&tsadc->reg_lock); + tsadc->reg_se_cache = tscadc_readl(tsadc, REG_SE); tsadc->reg_se_cache |= val; - spin_unlock(&tsadc->reg_lock); - am335x_tsc_se_update(tsadc); + spin_unlock(&tsadc->reg_lock); } EXPORT_SYMBOL_GPL(am335x_tsc_se_set); void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val) { spin_lock(&tsadc->reg_lock); + tsadc->reg_se_cache = tscadc_readl(tsadc, REG_SE); tsadc->reg_se_cache &= ~val; - spin_unlock(&tsadc->reg_lock); - am335x_tsc_se_update(tsadc); + spin_unlock(&tsadc->reg_lock); } EXPORT_SYMBOL_GPL(am335x_tsc_se_clr); @@ -197,24 +197,21 @@ static int ti_tscadc_probe(struct platform_device *pdev) clock_rate = clk_get_rate(clk); clk_put(clk); clk_value = clock_rate / ADC_CLK; - if (clk_value < MAX_CLK_DIV) { - dev_err(&pdev->dev, "clock input less than min clock requirement\n"); - err = -EINVAL; - goto err_disable_clk; - } + /* TSCADC_CLKDIV needs to be configured to the value minus 1 */ clk_value = clk_value - 1; tscadc_writel(tscadc, REG_CLKDIV, clk_value); /* Set the control register bits */ ctrl = CNTRLREG_STEPCONFIGWRT | - CNTRLREG_TSCENB | - CNTRLREG_STEPID | - CNTRLREG_4WIRE; + CNTRLREG_STEPID; + if (tsc_wires > 0) + ctrl |= CNTRLREG_4WIRE | CNTRLREG_TSCENB; tscadc_writel(tscadc, REG_CTRL, ctrl); /* Set register bits for Idle Config Mode */ - tscadc_idle_config(tscadc); + if (tsc_wires > 0) + tscadc_idle_config(tscadc); /* Enable the TSC module enable bit */ ctrl = tscadc_readl(tscadc, REG_CTRL); @@ -294,10 +291,13 @@ static int tscadc_resume(struct device *dev) pm_runtime_get_sync(dev); /* context restore */ - ctrl = CNTRLREG_STEPCONFIGWRT | CNTRLREG_TSCENB | - CNTRLREG_STEPID | CNTRLREG_4WIRE; + ctrl = CNTRLREG_STEPCONFIGWRT | CNTRLREG_STEPID; + if (tscadc_dev->tsc_cell != -1) + ctrl |= CNTRLREG_TSCENB | CNTRLREG_4WIRE; tscadc_writel(tscadc_dev, REG_CTRL, ctrl); - tscadc_idle_config(tscadc_dev); + + if (tscadc_dev->tsc_cell != -1) + tscadc_idle_config(tscadc_dev); am335x_tsc_se_update(tscadc_dev); restore = tscadc_readl(tscadc_dev, REG_CTRL); tscadc_writel(tscadc_dev, REG_CTRL, diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c index 0c1fcbc23d04..a6755ec7bd6a 100644 --- a/drivers/mfd/timberdale.c +++ b/drivers/mfd/timberdale.c @@ -115,11 +115,11 @@ static const struct resource timberdale_ocores_resources[] = { }, }; -const struct max7301_platform_data timberdale_max7301_platform_data = { +static const struct max7301_platform_data timberdale_max7301_platform_data = { .base = 200 }; -const struct mc33880_platform_data timberdale_mc33880_platform_data = { +static const struct mc33880_platform_data timberdale_mc33880_platform_data = { .base = 100 }; @@ -781,7 +781,6 @@ static int timb_probe(struct pci_dev *dev, priv->fw.major, priv->fw.minor, ip_setup); err = -ENODEV; goto err_mfd; - break; } if (err) { @@ -869,34 +868,7 @@ static struct pci_driver timberdale_pci_driver = { .remove = timb_remove, }; -static int __init timberdale_init(void) -{ - int err; - - err = pci_register_driver(&timberdale_pci_driver); - if (err < 0) { - printk(KERN_ERR - "Failed to register PCI driver for %s device.\n", - timberdale_pci_driver.name); - return -ENODEV; - } - - printk(KERN_INFO "Driver for %s has been successfully registered.\n", - timberdale_pci_driver.name); - - return 0; -} - -static void __exit timberdale_exit(void) -{ - pci_unregister_driver(&timberdale_pci_driver); - - printk(KERN_INFO "Driver for %s has been successfully unregistered.\n", - timberdale_pci_driver.name); -} - -module_init(timberdale_init); -module_exit(timberdale_exit); +module_pci_driver(timberdale_pci_driver); MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>"); MODULE_VERSION(DRV_VERSION); diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c index 1d302f583adf..b5dfa6e4e692 100644 --- a/drivers/mfd/tps6105x.c +++ b/drivers/mfd/tps6105x.c @@ -147,7 +147,7 @@ static int tps6105x_probe(struct i2c_client *client, i2c_set_clientdata(client, tps6105x); tps6105x->client = client; - pdata = client->dev.platform_data; + pdata = dev_get_platdata(&client->dev); tps6105x->pdata = pdata; mutex_init(&tps6105x->lock); diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c index da2691f22e11..743fb524fc8a 100644 --- a/drivers/mfd/tps65010.c +++ b/drivers/mfd/tps65010.c @@ -242,8 +242,8 @@ static int dbg_show(struct seq_file *s, void *_) seq_printf(s, "mask2 %s\n", buf); /* ignore ackint2 */ - schedule_delayed_work(&tps->work, POWER_POLL_DELAY); - + queue_delayed_work(system_power_efficient_wq, &tps->work, + POWER_POLL_DELAY); /* VMAIN voltage, enable lowpower, etc */ value = i2c_smbus_read_byte_data(tps->client, TPS_VDCDC1); @@ -400,7 +400,8 @@ static void tps65010_interrupt(struct tps65010 *tps) && (tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC))) poll = 1; if (poll) - schedule_delayed_work(&tps->work, POWER_POLL_DELAY); + queue_delayed_work(system_power_efficient_wq, &tps->work, + POWER_POLL_DELAY); /* also potentially gpio-in rise or fall */ } @@ -448,7 +449,7 @@ static irqreturn_t tps65010_irq(int irq, void *_tps) disable_irq_nosync(irq); set_bit(FLAG_IRQ_ENABLE, &tps->flags); - schedule_delayed_work(&tps->work, 0); + queue_delayed_work(system_power_efficient_wq, &tps->work, 0); return IRQ_HANDLED; } @@ -517,7 +518,7 @@ static struct tps65010 *the_tps; static int __exit tps65010_remove(struct i2c_client *client) { struct tps65010 *tps = i2c_get_clientdata(client); - struct tps65010_board *board = client->dev.platform_data; + struct tps65010_board *board = dev_get_platdata(&client->dev); if (board && board->teardown) { int status = board->teardown(client, board->context); @@ -529,7 +530,6 @@ static int __exit tps65010_remove(struct i2c_client *client) free_irq(client->irq, tps); cancel_delayed_work_sync(&tps->work); debugfs_remove(tps->file); - kfree(tps); the_tps = NULL; return 0; } @@ -539,7 +539,7 @@ static int tps65010_probe(struct i2c_client *client, { struct tps65010 *tps; int status; - struct tps65010_board *board = client->dev.platform_data; + struct tps65010_board *board = dev_get_platdata(&client->dev); if (the_tps) { dev_dbg(&client->dev, "only one tps6501x chip allowed\n"); @@ -549,7 +549,7 @@ static int tps65010_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EINVAL; - tps = kzalloc(sizeof *tps, GFP_KERNEL); + tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL); if (!tps) return -ENOMEM; @@ -567,7 +567,7 @@ static int tps65010_probe(struct i2c_client *client, if (status < 0) { dev_dbg(&client->dev, "can't get IRQ %d, err %d\n", client->irq, status); - goto fail1; + return status; } /* annoying race here, ideally we'd have an option * to claim the irq now and enable it later. @@ -667,9 +667,6 @@ static int tps65010_probe(struct i2c_client *client, } return 0; -fail1: - kfree(tps); - return status; } static const struct i2c_device_id tps65010_id[] = { @@ -718,7 +715,8 @@ int tps65010_set_vbus_draw(unsigned mA) && test_and_set_bit( FLAG_VBUS_CHANGED, &the_tps->flags)) { /* gadget drivers call this in_irq() */ - schedule_delayed_work(&the_tps->work, 0); + queue_delayed_work(system_power_efficient_wq, &the_tps->work, + 0); } local_irq_restore(flags); diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c index fbd6ee67b5a5..e6f03a733879 100644 --- a/drivers/mfd/tps65090.c +++ b/drivers/mfd/tps65090.c @@ -172,7 +172,7 @@ MODULE_DEVICE_TABLE(of, tps65090_of_match); static int tps65090_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct tps65090_platform_data *pdata = client->dev.platform_data; + struct tps65090_platform_data *pdata = dev_get_platdata(&client->dev); int irq_base = 0; struct tps65090 *tps65090; int ret; diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 4b93ed4d5cd6..f54fe4d4f77b 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -462,7 +462,7 @@ static void tps6586x_power_off(void) static int tps6586x_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct tps6586x_platform_data *pdata = client->dev.platform_data; + struct tps6586x_platform_data *pdata = dev_get_platdata(&client->dev); struct tps6586x *tps6586x; int ret; diff --git a/drivers/mfd/tps65912-core.c b/drivers/mfd/tps65912-core.c index 479886a4cf80..925a044cbdf6 100644 --- a/drivers/mfd/tps65912-core.c +++ b/drivers/mfd/tps65912-core.c @@ -123,7 +123,7 @@ EXPORT_SYMBOL_GPL(tps65912_reg_write); int tps65912_device_init(struct tps65912 *tps65912) { - struct tps65912_board *pmic_plat_data = tps65912->dev->platform_data; + struct tps65912_board *pmic_plat_data = dev_get_platdata(tps65912->dev); struct tps65912_platform_data *init_data; int ret, dcdc_avs, value; diff --git a/drivers/mfd/tps80031.c b/drivers/mfd/tps80031.c index c90a2c450f51..f15ee6d5cfbf 100644 --- a/drivers/mfd/tps80031.c +++ b/drivers/mfd/tps80031.c @@ -418,7 +418,7 @@ static const struct regmap_config tps80031_regmap_configs[] = { static int tps80031_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct tps80031_platform_data *pdata = client->dev.platform_data; + struct tps80031_platform_data *pdata = dev_get_platdata(&client->dev); struct tps80031 *tps80031; int ret; uint8_t es_version; diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 7f150d94d295..29473c2c95ae 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -1137,7 +1137,7 @@ static int twl_remove(struct i2c_client *client) static int twl_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct twl4030_platform_data *pdata = client->dev.platform_data; + struct twl4030_platform_data *pdata = dev_get_platdata(&client->dev); struct device_node *node = client->dev.of_node; struct platform_device *pdev; struct regmap_config *twl_regmap_config; diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c index a31fba96ef43..07fe542e6fc0 100644 --- a/drivers/mfd/twl4030-audio.c +++ b/drivers/mfd/twl4030-audio.c @@ -187,7 +187,7 @@ static bool twl4030_audio_has_vibra(struct twl4030_audio_data *pdata, static int twl4030_audio_probe(struct platform_device *pdev) { struct twl4030_audio *audio; - struct twl4030_audio_data *pdata = pdev->dev.platform_data; + struct twl4030_audio_data *pdata = dev_get_platdata(&pdev->dev); struct device_node *node = pdev->dev.of_node; struct mfd_cell *cell = NULL; int ret, childs = 0; diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index 1ea54d4d003a..4c583e471339 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c @@ -701,7 +701,7 @@ static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on) static int twl4030_madc_probe(struct platform_device *pdev) { struct twl4030_madc_data *madc; - struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data; + struct twl4030_madc_platform_data *pdata = dev_get_platdata(&pdev->dev); int ret; u8 regval; diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index a5fd3c738211..96162b62f3c0 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -493,7 +493,7 @@ int twl4030_remove_script(u8 flags) return err; } -int twl4030_power_configure_scripts(struct twl4030_power_data *pdata) +static int twl4030_power_configure_scripts(struct twl4030_power_data *pdata) { int err; int i; @@ -509,7 +509,7 @@ int twl4030_power_configure_scripts(struct twl4030_power_data *pdata) return 0; } -int twl4030_power_configure_resources(struct twl4030_power_data *pdata) +static int twl4030_power_configure_resources(struct twl4030_power_data *pdata) { struct twl4030_resconfig *resconfig = pdata->resource_config; int err; @@ -553,9 +553,9 @@ static bool twl4030_power_use_poweroff(struct twl4030_power_data *pdata, return false; } -int twl4030_power_probe(struct platform_device *pdev) +static int twl4030_power_probe(struct platform_device *pdev) { - struct twl4030_power_data *pdata = pdev->dev.platform_data; + struct twl4030_power_data *pdata = dev_get_platdata(&pdev->dev); struct device_node *node = pdev->dev.of_node; int err = 0; int err2 = 0; diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 277a8dba42d5..517eda832f79 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -41,6 +41,7 @@ #include <linux/suspend.h> #include <linux/of.h> #include <linux/irqdomain.h> +#include <linux/of_device.h> #include "twl-core.h" @@ -84,39 +85,77 @@ static int twl6030_interrupt_mapping[24] = { CHARGERFAULT_INTR_OFFSET, /* Bit 22 INT_CHRG */ RSV_INTR_OFFSET, /* Bit 23 Reserved */ }; + +static int twl6032_interrupt_mapping[24] = { + PWR_INTR_OFFSET, /* Bit 0 PWRON */ + PWR_INTR_OFFSET, /* Bit 1 RPWRON */ + PWR_INTR_OFFSET, /* Bit 2 SYS_VLOW */ + RTC_INTR_OFFSET, /* Bit 3 RTC_ALARM */ + RTC_INTR_OFFSET, /* Bit 4 RTC_PERIOD */ + HOTDIE_INTR_OFFSET, /* Bit 5 HOT_DIE */ + SMPSLDO_INTR_OFFSET, /* Bit 6 VXXX_SHORT */ + PWR_INTR_OFFSET, /* Bit 7 SPDURATION */ + + PWR_INTR_OFFSET, /* Bit 8 WATCHDOG */ + BATDETECT_INTR_OFFSET, /* Bit 9 BAT */ + SIMDETECT_INTR_OFFSET, /* Bit 10 SIM */ + MMCDETECT_INTR_OFFSET, /* Bit 11 MMC */ + MADC_INTR_OFFSET, /* Bit 12 GPADC_RT_EOC */ + MADC_INTR_OFFSET, /* Bit 13 GPADC_SW_EOC */ + GASGAUGE_INTR_OFFSET, /* Bit 14 CC_EOC */ + GASGAUGE_INTR_OFFSET, /* Bit 15 CC_AUTOCAL */ + + USBOTG_INTR_OFFSET, /* Bit 16 ID_WKUP */ + USBOTG_INTR_OFFSET, /* Bit 17 VBUS_WKUP */ + USBOTG_INTR_OFFSET, /* Bit 18 ID */ + USB_PRES_INTR_OFFSET, /* Bit 19 VBUS */ + CHARGER_INTR_OFFSET, /* Bit 20 CHRG_CTRL */ + CHARGERFAULT_INTR_OFFSET, /* Bit 21 EXT_CHRG */ + CHARGERFAULT_INTR_OFFSET, /* Bit 22 INT_CHRG */ + RSV_INTR_OFFSET, /* Bit 23 Reserved */ +}; + /*----------------------------------------------------------------------*/ -static unsigned twl6030_irq_base; -static int twl_irq; -static bool twl_irq_wake_enabled; +struct twl6030_irq { + unsigned int irq_base; + int twl_irq; + bool irq_wake_enabled; + atomic_t wakeirqs; + struct notifier_block pm_nb; + struct irq_chip irq_chip; + struct irq_domain *irq_domain; + const int *irq_mapping_tbl; +}; -static struct completion irq_event; -static atomic_t twl6030_wakeirqs = ATOMIC_INIT(0); +static struct twl6030_irq *twl6030_irq; static int twl6030_irq_pm_notifier(struct notifier_block *notifier, unsigned long pm_event, void *unused) { int chained_wakeups; + struct twl6030_irq *pdata = container_of(notifier, struct twl6030_irq, + pm_nb); switch (pm_event) { case PM_SUSPEND_PREPARE: - chained_wakeups = atomic_read(&twl6030_wakeirqs); + chained_wakeups = atomic_read(&pdata->wakeirqs); - if (chained_wakeups && !twl_irq_wake_enabled) { - if (enable_irq_wake(twl_irq)) + if (chained_wakeups && !pdata->irq_wake_enabled) { + if (enable_irq_wake(pdata->twl_irq)) pr_err("twl6030 IRQ wake enable failed\n"); else - twl_irq_wake_enabled = true; - } else if (!chained_wakeups && twl_irq_wake_enabled) { - disable_irq_wake(twl_irq); - twl_irq_wake_enabled = false; + pdata->irq_wake_enabled = true; + } else if (!chained_wakeups && pdata->irq_wake_enabled) { + disable_irq_wake(pdata->twl_irq); + pdata->irq_wake_enabled = false; } - disable_irq(twl_irq); + disable_irq(pdata->twl_irq); break; case PM_POST_SUSPEND: - enable_irq(twl_irq); + enable_irq(pdata->twl_irq); break; default: @@ -126,124 +165,77 @@ static int twl6030_irq_pm_notifier(struct notifier_block *notifier, return NOTIFY_DONE; } -static struct notifier_block twl6030_irq_pm_notifier_block = { - .notifier_call = twl6030_irq_pm_notifier, -}; - /* - * This thread processes interrupts reported by the Primary Interrupt Handler. - */ -static int twl6030_irq_thread(void *data) +* Threaded irq handler for the twl6030 interrupt. +* We query the interrupt controller in the twl6030 to determine +* which module is generating the interrupt request and call +* handle_nested_irq for that module. +*/ +static irqreturn_t twl6030_irq_thread(int irq, void *data) { - long irq = (long)data; - static unsigned i2c_errors; - static const unsigned max_i2c_errors = 100; - int ret; - - while (!kthread_should_stop()) { - int i; - union { + int i, ret; + union { u8 bytes[4]; u32 int_sts; - } sts; - - /* Wait for IRQ, then read PIH irq status (also blocking) */ - wait_for_completion_interruptible(&irq_event); - - /* read INT_STS_A, B and C in one shot using a burst read */ - ret = twl_i2c_read(TWL_MODULE_PIH, sts.bytes, - REG_INT_STS_A, 3); - if (ret) { - pr_warning("twl6030: I2C error %d reading PIH ISR\n", - ret); - if (++i2c_errors >= max_i2c_errors) { - printk(KERN_ERR "Maximum I2C error count" - " exceeded. Terminating %s.\n", - __func__); - break; - } - complete(&irq_event); - continue; - } - - + } sts; + struct twl6030_irq *pdata = data; + + /* read INT_STS_A, B and C in one shot using a burst read */ + ret = twl_i2c_read(TWL_MODULE_PIH, sts.bytes, REG_INT_STS_A, 3); + if (ret) { + pr_warn("twl6030_irq: I2C error %d reading PIH ISR\n", ret); + return IRQ_HANDLED; + } - sts.bytes[3] = 0; /* Only 24 bits are valid*/ + sts.bytes[3] = 0; /* Only 24 bits are valid*/ - /* - * Since VBUS status bit is not reliable for VBUS disconnect - * use CHARGER VBUS detection status bit instead. - */ - if (sts.bytes[2] & 0x10) - sts.bytes[2] |= 0x08; - - for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) { - local_irq_disable(); - if (sts.int_sts & 0x1) { - int module_irq = twl6030_irq_base + - twl6030_interrupt_mapping[i]; - generic_handle_irq(module_irq); - - } - local_irq_enable(); + /* + * Since VBUS status bit is not reliable for VBUS disconnect + * use CHARGER VBUS detection status bit instead. + */ + if (sts.bytes[2] & 0x10) + sts.bytes[2] |= 0x08; + + for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) + if (sts.int_sts & 0x1) { + int module_irq = + irq_find_mapping(pdata->irq_domain, + pdata->irq_mapping_tbl[i]); + if (module_irq) + handle_nested_irq(module_irq); + else + pr_err("twl6030_irq: Unmapped PIH ISR %u detected\n", + i); + pr_debug("twl6030_irq: PIH ISR %u, virq%u\n", + i, module_irq); } - /* - * NOTE: - * Simulation confirms that documentation is wrong w.r.t the - * interrupt status clear operation. A single *byte* write to - * any one of STS_A to STS_C register results in all three - * STS registers being reset. Since it does not matter which - * value is written, all three registers are cleared on a - * single byte write, so we just use 0x0 to clear. - */ - ret = twl_i2c_write_u8(TWL_MODULE_PIH, 0x00, REG_INT_STS_A); - if (ret) - pr_warning("twl6030: I2C error in clearing PIH ISR\n"); - - enable_irq(irq); - } - - return 0; -} + /* + * NOTE: + * Simulation confirms that documentation is wrong w.r.t the + * interrupt status clear operation. A single *byte* write to + * any one of STS_A to STS_C register results in all three + * STS registers being reset. Since it does not matter which + * value is written, all three registers are cleared on a + * single byte write, so we just use 0x0 to clear. + */ + ret = twl_i2c_write_u8(TWL_MODULE_PIH, 0x00, REG_INT_STS_A); + if (ret) + pr_warn("twl6030_irq: I2C error in clearing PIH ISR\n"); -/* - * handle_twl6030_int() is the desc->handle method for the twl6030 interrupt. - * This is a chained interrupt, so there is no desc->action method for it. - * Now we need to query the interrupt controller in the twl6030 to determine - * which module is generating the interrupt request. However, we can't do i2c - * transactions in interrupt context, so we must defer that work to a kernel - * thread. All we do here is acknowledge and mask the interrupt and wakeup - * the kernel thread. - */ -static irqreturn_t handle_twl6030_pih(int irq, void *devid) -{ - disable_irq_nosync(irq); - complete(devid); return IRQ_HANDLED; } /*----------------------------------------------------------------------*/ -static inline void activate_irq(int irq) -{ -#ifdef CONFIG_ARM - /* ARM requires an extra step to clear IRQ_NOREQUEST, which it - * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE. - */ - set_irq_flags(irq, IRQF_VALID); -#else - /* same effect on other architectures */ - irq_set_noprobe(irq); -#endif -} - static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on) { + struct twl6030_irq *pdata = irq_get_chip_data(d->irq); + if (on) - atomic_inc(&twl6030_wakeirqs); + atomic_inc(&pdata->wakeirqs); else - atomic_dec(&twl6030_wakeirqs); + atomic_dec(&pdata->wakeirqs); return 0; } @@ -318,7 +310,8 @@ int twl6030_mmc_card_detect_config(void) return ret; } - return twl6030_irq_base + MMCDETECT_INTR_OFFSET; + return irq_find_mapping(twl6030_irq->irq_domain, + MMCDETECT_INTR_OFFSET); } EXPORT_SYMBOL(twl6030_mmc_card_detect_config); @@ -347,99 +340,143 @@ int twl6030_mmc_card_detect(struct device *dev, int slot) } EXPORT_SYMBOL(twl6030_mmc_card_detect); +static int twl6030_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hwirq) +{ + struct twl6030_irq *pdata = d->host_data; + + irq_set_chip_data(virq, pdata); + irq_set_chip_and_handler(virq, &pdata->irq_chip, handle_simple_irq); + irq_set_nested_thread(virq, true); + irq_set_parent(virq, pdata->twl_irq); + +#ifdef CONFIG_ARM + /* + * ARM requires an extra step to clear IRQ_NOREQUEST, which it + * sets on behalf of every irq_chip. Also sets IRQ_NOPROBE. + */ + set_irq_flags(virq, IRQF_VALID); +#else + /* same effect on other architectures */ + irq_set_noprobe(virq); +#endif + + return 0; +} + +static void twl6030_irq_unmap(struct irq_domain *d, unsigned int virq) +{ +#ifdef CONFIG_ARM + set_irq_flags(virq, 0); +#endif + irq_set_chip_and_handler(virq, NULL, NULL); + irq_set_chip_data(virq, NULL); +} + +static struct irq_domain_ops twl6030_irq_domain_ops = { + .map = twl6030_irq_map, + .unmap = twl6030_irq_unmap, + .xlate = irq_domain_xlate_onetwocell, +}; + +static const struct of_device_id twl6030_of_match[] = { + {.compatible = "ti,twl6030", &twl6030_interrupt_mapping}, + {.compatible = "ti,twl6032", &twl6032_interrupt_mapping}, + { }, +}; + int twl6030_init_irq(struct device *dev, int irq_num) { struct device_node *node = dev->of_node; - int nr_irqs, irq_base, irq_end; - struct task_struct *task; - static struct irq_chip twl6030_irq_chip; - int status = 0; - int i; + int nr_irqs; + int status; u8 mask[3]; + const struct of_device_id *of_id; - nr_irqs = TWL6030_NR_IRQS; - - irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0); - if (IS_ERR_VALUE(irq_base)) { - dev_err(dev, "Fail to allocate IRQ descs\n"); - return irq_base; + of_id = of_match_device(twl6030_of_match, dev); + if (!of_id || !of_id->data) { + dev_err(dev, "Unknown TWL device model\n"); + return -EINVAL; } - irq_domain_add_legacy(node, nr_irqs, irq_base, 0, - &irq_domain_simple_ops, NULL); + nr_irqs = TWL6030_NR_IRQS; - irq_end = irq_base + nr_irqs; + twl6030_irq = devm_kzalloc(dev, sizeof(*twl6030_irq), GFP_KERNEL); + if (!twl6030_irq) { + dev_err(dev, "twl6030_irq: Memory allocation failed\n"); + return -ENOMEM; + } mask[0] = 0xFF; mask[1] = 0xFF; mask[2] = 0xFF; /* mask all int lines */ - twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3); + status = twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3); /* mask all int sts */ - twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_STS_A, 3); + status |= twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_STS_A, 3); /* clear INT_STS_A,B,C */ - twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_STS_A, 3); + status |= twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_STS_A, 3); - twl6030_irq_base = irq_base; + if (status < 0) { + dev_err(dev, "I2C err writing TWL_MODULE_PIH: %d\n", status); + return status; + } /* * install an irq handler for each of the modules; * clone dummy irq_chip since PIH can't *do* anything */ - twl6030_irq_chip = dummy_irq_chip; - twl6030_irq_chip.name = "twl6030"; - twl6030_irq_chip.irq_set_type = NULL; - twl6030_irq_chip.irq_set_wake = twl6030_irq_set_wake; - - for (i = irq_base; i < irq_end; i++) { - irq_set_chip_and_handler(i, &twl6030_irq_chip, - handle_simple_irq); - irq_set_chip_data(i, (void *)irq_num); - activate_irq(i); + twl6030_irq->irq_chip = dummy_irq_chip; + twl6030_irq->irq_chip.name = "twl6030"; + twl6030_irq->irq_chip.irq_set_type = NULL; + twl6030_irq->irq_chip.irq_set_wake = twl6030_irq_set_wake; + + twl6030_irq->pm_nb.notifier_call = twl6030_irq_pm_notifier; + atomic_set(&twl6030_irq->wakeirqs, 0); + twl6030_irq->irq_mapping_tbl = of_id->data; + + twl6030_irq->irq_domain = + irq_domain_add_linear(node, nr_irqs, + &twl6030_irq_domain_ops, twl6030_irq); + if (!twl6030_irq->irq_domain) { + dev_err(dev, "Can't add irq_domain\n"); + return -ENOMEM; } - dev_info(dev, "PIH (irq %d) chaining IRQs %d..%d\n", - irq_num, irq_base, irq_end); + dev_info(dev, "PIH (irq %d) nested IRQs\n", irq_num); /* install an irq handler to demultiplex the TWL6030 interrupt */ - init_completion(&irq_event); - - status = request_irq(irq_num, handle_twl6030_pih, 0, "TWL6030-PIH", - &irq_event); + status = request_threaded_irq(irq_num, NULL, twl6030_irq_thread, + IRQF_ONESHOT, "TWL6030-PIH", twl6030_irq); if (status < 0) { dev_err(dev, "could not claim irq %d: %d\n", irq_num, status); goto fail_irq; } - task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq"); - if (IS_ERR(task)) { - dev_err(dev, "could not create irq %d thread!\n", irq_num); - status = PTR_ERR(task); - goto fail_kthread; - } - - twl_irq = irq_num; - register_pm_notifier(&twl6030_irq_pm_notifier_block); - return irq_base; - -fail_kthread: - free_irq(irq_num, &irq_event); + twl6030_irq->twl_irq = irq_num; + register_pm_notifier(&twl6030_irq->pm_nb); + return 0; fail_irq: - for (i = irq_base; i < irq_end; i++) - irq_set_chip_and_handler(i, NULL, NULL); - + irq_domain_remove(twl6030_irq->irq_domain); return status; } int twl6030_exit_irq(void) { - unregister_pm_notifier(&twl6030_irq_pm_notifier_block); - - if (twl6030_irq_base) { - pr_err("twl6030: can't yet clean up IRQs?\n"); - return -ENOSYS; + if (twl6030_irq && twl6030_irq->twl_irq) { + unregister_pm_notifier(&twl6030_irq->pm_nb); + free_irq(twl6030_irq->twl_irq, NULL); + /* + * TODO: IRQ domain and allocated nested IRQ descriptors + * should be freed somehow here. Now It can't be done, because + * child devices will not be deleted during removing of + * TWL Core driver and they will still contain allocated + * virt IRQs in their Resources tables. + * The same prevents us from using devm_request_threaded_irq() + * in this module. + */ } return 0; } diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index 492ee2cd3400..daf66942071c 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -44,17 +44,12 @@ #define VIBRACTRL_MEMBER(reg) ((reg == TWL6040_REG_VIBCTLL) ? 0 : 1) #define TWL6040_NUM_SUPPLIES (2) -static bool twl6040_has_vibra(struct twl6040_platform_data *pdata, - struct device_node *node) +static bool twl6040_has_vibra(struct device_node *node) { - if (pdata && pdata->vibra) - return true; - #ifdef CONFIG_OF if (of_find_node_by_name(node, "vibra")) return true; #endif - return false; } @@ -63,15 +58,9 @@ int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg) int ret; unsigned int val; - /* Vibra control registers from cache */ - if (unlikely(reg == TWL6040_REG_VIBCTLL || - reg == TWL6040_REG_VIBCTLR)) { - val = twl6040->vibra_ctrl_cache[VIBRACTRL_MEMBER(reg)]; - } else { - ret = regmap_read(twl6040->regmap, reg, &val); - if (ret < 0) - return ret; - } + ret = regmap_read(twl6040->regmap, reg, &val); + if (ret < 0) + return ret; return val; } @@ -82,9 +71,6 @@ int twl6040_reg_write(struct twl6040 *twl6040, unsigned int reg, u8 val) int ret; ret = regmap_write(twl6040->regmap, reg, val); - /* Cache the vibra control registers */ - if (reg == TWL6040_REG_VIBCTLL || reg == TWL6040_REG_VIBCTLR) - twl6040->vibra_ctrl_cache[VIBRACTRL_MEMBER(reg)] = val; return ret; } @@ -461,9 +447,20 @@ EXPORT_SYMBOL(twl6040_get_sysclk); /* Get the combined status of the vibra control register */ int twl6040_get_vibralr_status(struct twl6040 *twl6040) { + unsigned int reg; + int ret; u8 status; - status = twl6040->vibra_ctrl_cache[0] | twl6040->vibra_ctrl_cache[1]; + ret = regmap_read(twl6040->regmap, TWL6040_REG_VIBCTLL, ®); + if (ret != 0) + return ret; + status = reg; + + ret = regmap_read(twl6040->regmap, TWL6040_REG_VIBCTLR, ®); + if (ret != 0) + return ret; + status |= reg; + status &= (TWL6040_VIBENA | TWL6040_VIBSEL); return status; @@ -490,12 +487,27 @@ static bool twl6040_readable_reg(struct device *dev, unsigned int reg) return true; } +static bool twl6040_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TWL6040_REG_VIBCTLL: + case TWL6040_REG_VIBCTLR: + case TWL6040_REG_INTMR: + return false; + default: + return true; + } +} + static struct regmap_config twl6040_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = TWL6040_REG_STATUS, /* 0x2e */ .readable_reg = twl6040_readable_reg, + .volatile_reg = twl6040_volatile_reg, + + .cache_type = REGCACHE_RBTREE, }; static const struct regmap_irq twl6040_irqs[] = { @@ -520,14 +532,13 @@ static struct regmap_irq_chip twl6040_irq_chip = { static int twl6040_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct twl6040_platform_data *pdata = client->dev.platform_data; struct device_node *node = client->dev.of_node; struct twl6040 *twl6040; struct mfd_cell *cell = NULL; int irq, ret, children = 0; - if (!pdata && !node) { - dev_err(&client->dev, "Platform data is missing\n"); + if (!node) { + dev_err(&client->dev, "of node is missing\n"); return -EINVAL; } @@ -539,23 +550,19 @@ static int twl6040_probe(struct i2c_client *client, twl6040 = devm_kzalloc(&client->dev, sizeof(struct twl6040), GFP_KERNEL); - if (!twl6040) { - ret = -ENOMEM; - goto err; - } + if (!twl6040) + return -ENOMEM; twl6040->regmap = devm_regmap_init_i2c(client, &twl6040_regmap_config); - if (IS_ERR(twl6040->regmap)) { - ret = PTR_ERR(twl6040->regmap); - goto err; - } + if (IS_ERR(twl6040->regmap)) + return PTR_ERR(twl6040->regmap); i2c_set_clientdata(client, twl6040); twl6040->supplies[0].supply = "vio"; twl6040->supplies[1].supply = "v2v1"; ret = devm_regulator_bulk_get(&client->dev, TWL6040_NUM_SUPPLIES, - twl6040->supplies); + twl6040->supplies); if (ret != 0) { dev_err(&client->dev, "Failed to get supplies: %d\n", ret); goto regulator_get_err; @@ -576,44 +583,40 @@ static int twl6040_probe(struct i2c_client *client, twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV); /* ERRATA: Automatic power-up is not possible in ES1.0 */ - if (twl6040_get_revid(twl6040) > TWL6040_REV_ES1_0) { - if (pdata) - twl6040->audpwron = pdata->audpwron_gpio; - else - twl6040->audpwron = of_get_named_gpio(node, - "ti,audpwron-gpio", 0); - } else + if (twl6040_get_revid(twl6040) > TWL6040_REV_ES1_0) + twl6040->audpwron = of_get_named_gpio(node, + "ti,audpwron-gpio", 0); + else twl6040->audpwron = -EINVAL; if (gpio_is_valid(twl6040->audpwron)) { ret = devm_gpio_request_one(&client->dev, twl6040->audpwron, - GPIOF_OUT_INIT_LOW, "audpwron"); + GPIOF_OUT_INIT_LOW, "audpwron"); if (ret) goto gpio_err; } - ret = regmap_add_irq_chip(twl6040->regmap, twl6040->irq, - IRQF_ONESHOT, 0, &twl6040_irq_chip, - &twl6040->irq_data); + ret = regmap_add_irq_chip(twl6040->regmap, twl6040->irq, IRQF_ONESHOT, + 0, &twl6040_irq_chip,&twl6040->irq_data); if (ret < 0) goto gpio_err; twl6040->irq_ready = regmap_irq_get_virq(twl6040->irq_data, - TWL6040_IRQ_READY); + TWL6040_IRQ_READY); twl6040->irq_th = regmap_irq_get_virq(twl6040->irq_data, - TWL6040_IRQ_TH); + TWL6040_IRQ_TH); ret = devm_request_threaded_irq(twl6040->dev, twl6040->irq_ready, NULL, - twl6040_readyint_handler, IRQF_ONESHOT, - "twl6040_irq_ready", twl6040); + twl6040_readyint_handler, IRQF_ONESHOT, + "twl6040_irq_ready", twl6040); if (ret) { dev_err(twl6040->dev, "READY IRQ request failed: %d\n", ret); goto readyirq_err; } ret = devm_request_threaded_irq(twl6040->dev, twl6040->irq_th, NULL, - twl6040_thint_handler, IRQF_ONESHOT, - "twl6040_irq_th", twl6040); + twl6040_thint_handler, IRQF_ONESHOT, + "twl6040_irq_th", twl6040); if (ret) { dev_err(twl6040->dev, "Thermal IRQ request failed: %d\n", ret); goto thirq_err; @@ -625,8 +628,6 @@ static int twl6040_probe(struct i2c_client *client, /* * The main functionality of twl6040 to provide audio on OMAP4+ systems. * We can add the ASoC codec child whenever this driver has been loaded. - * The ASoC codec can work without pdata, pass the platform_data only if - * it has been provided. */ irq = regmap_irq_get_virq(twl6040->irq_data, TWL6040_IRQ_PLUG); cell = &twl6040->cells[children]; @@ -635,13 +636,10 @@ static int twl6040_probe(struct i2c_client *client, twl6040_codec_rsrc[0].end = irq; cell->resources = twl6040_codec_rsrc; cell->num_resources = ARRAY_SIZE(twl6040_codec_rsrc); - if (pdata && pdata->codec) { - cell->platform_data = pdata->codec; - cell->pdata_size = sizeof(*pdata->codec); - } children++; - if (twl6040_has_vibra(pdata, node)) { + /* Vibra input driver support */ + if (twl6040_has_vibra(node)) { irq = regmap_irq_get_virq(twl6040->irq_data, TWL6040_IRQ_VIB); cell = &twl6040->cells[children]; @@ -650,28 +648,13 @@ static int twl6040_probe(struct i2c_client *client, twl6040_vibra_rsrc[0].end = irq; cell->resources = twl6040_vibra_rsrc; cell->num_resources = ARRAY_SIZE(twl6040_vibra_rsrc); - - if (pdata && pdata->vibra) { - cell->platform_data = pdata->vibra; - cell->pdata_size = sizeof(*pdata->vibra); - } children++; } - /* - * Enable the GPO driver in the following cases: - * DT booted kernel or legacy boot with valid gpo platform_data - */ - if (!pdata || (pdata && pdata->gpo)) { - cell = &twl6040->cells[children]; - cell->name = "twl6040-gpo"; - - if (pdata) { - cell->platform_data = pdata->gpo; - cell->pdata_size = sizeof(*pdata->gpo); - } - children++; - } + /* GPO support */ + cell = &twl6040->cells[children]; + cell->name = "twl6040-gpo"; + children++; ret = mfd_add_devices(&client->dev, -1, twl6040->cells, children, NULL, 0, NULL); @@ -690,7 +673,7 @@ gpio_err: regulator_bulk_disable(TWL6040_NUM_SUPPLIES, twl6040->supplies); regulator_get_err: i2c_set_clientdata(client, NULL); -err: + return ret; } diff --git a/drivers/mfd/ucb1400_core.c b/drivers/mfd/ucb1400_core.c index e9031fa9d53d..ebb20edf9c17 100644 --- a/drivers/mfd/ucb1400_core.c +++ b/drivers/mfd/ucb1400_core.c @@ -52,7 +52,7 @@ static int ucb1400_core_probe(struct device *dev) struct ucb1400_ts ucb_ts; struct ucb1400_gpio ucb_gpio; struct snd_ac97 *ac97; - struct ucb1400_pdata *pdata = dev->platform_data; + struct ucb1400_pdata *pdata = dev_get_platdata(dev); memset(&ucb_ts, 0, sizeof(ucb_ts)); memset(&ucb_gpio, 0, sizeof(ucb_gpio)); diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c index 70f02daeb22a..d5966e6b5a7d 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c @@ -393,22 +393,24 @@ static struct irq_chip ucb1x00_irqchip = { static int ucb1x00_add_dev(struct ucb1x00 *ucb, struct ucb1x00_driver *drv) { struct ucb1x00_dev *dev; - int ret = -ENOMEM; + int ret; dev = kmalloc(sizeof(struct ucb1x00_dev), GFP_KERNEL); - if (dev) { - dev->ucb = ucb; - dev->drv = drv; - - ret = drv->add(dev); - - if (ret == 0) { - list_add_tail(&dev->dev_node, &ucb->devs); - list_add_tail(&dev->drv_node, &drv->devs); - } else { - kfree(dev); - } + if (!dev) + return -ENOMEM; + + dev->ucb = ucb; + dev->drv = drv; + + ret = drv->add(dev); + if (ret) { + kfree(dev); + return ret; } + + list_add_tail(&dev->dev_node, &ucb->devs); + list_add_tail(&dev->drv_node, &drv->devs); + return ret; } @@ -669,9 +671,10 @@ void ucb1x00_unregister_driver(struct ucb1x00_driver *drv) mutex_unlock(&ucb1x00_mutex); } +#ifdef CONFIG_PM_SLEEP static int ucb1x00_suspend(struct device *dev) { - struct ucb1x00_plat_data *pdata = dev->platform_data; + struct ucb1x00_plat_data *pdata = dev_get_platdata(dev); struct ucb1x00 *ucb = dev_get_drvdata(dev); struct ucb1x00_dev *udev; @@ -703,7 +706,7 @@ static int ucb1x00_suspend(struct device *dev) static int ucb1x00_resume(struct device *dev) { - struct ucb1x00_plat_data *pdata = dev->platform_data; + struct ucb1x00_plat_data *pdata = dev_get_platdata(dev); struct ucb1x00 *ucb = dev_get_drvdata(dev); struct ucb1x00_dev *udev; @@ -736,6 +739,7 @@ static int ucb1x00_resume(struct device *dev) mutex_unlock(&ucb1x00_mutex); return 0; } +#endif static const struct dev_pm_ops ucb1x00_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(ucb1x00_suspend, ucb1x00_resume) diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c index edbe6c1b755a..f7c52d901040 100644 --- a/drivers/mfd/wl1273-core.c +++ b/drivers/mfd/wl1273-core.c @@ -172,12 +172,9 @@ static int wl1273_fm_set_volume(struct wl1273_core *core, unsigned int volume) static int wl1273_core_remove(struct i2c_client *client) { - struct wl1273_core *core = i2c_get_clientdata(client); - dev_dbg(&client->dev, "%s\n", __func__); mfd_remove_devices(&client->dev); - kfree(core); return 0; } @@ -185,7 +182,7 @@ static int wl1273_core_remove(struct i2c_client *client) static int wl1273_core_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct wl1273_fm_platform_data *pdata = client->dev.platform_data; + struct wl1273_fm_platform_data *pdata = dev_get_platdata(&client->dev); struct wl1273_core *core; struct mfd_cell *cell; int children = 0; @@ -203,7 +200,7 @@ static int wl1273_core_probe(struct i2c_client *client, return -EINVAL; } - core = kzalloc(sizeof(*core), GFP_KERNEL); + core = devm_kzalloc(&client->dev, sizeof(*core), GFP_KERNEL); if (!core) return -ENOMEM; @@ -249,7 +246,6 @@ static int wl1273_core_probe(struct i2c_client *client, err: pdata->free_resources(); - kfree(core); dev_dbg(&client->dev, "%s\n", __func__); diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 2a7972349159..3113e39b318e 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -468,12 +468,14 @@ static const struct reg_default wm5110_reg_default[] = { { 0x00000176, 0x0000 }, /* R374 - FLL1 Control 6 */ { 0x00000177, 0x0281 }, /* R375 - FLL1 Loop Filter Test 1 */ { 0x00000178, 0x0000 }, /* R376 - FLL1 NCO Test 0 */ + { 0x00000179, 0x0000 }, /* R376 - FLL1 Control 7 */ { 0x00000181, 0x0000 }, /* R385 - FLL1 Synchroniser 1 */ { 0x00000182, 0x0000 }, /* R386 - FLL1 Synchroniser 2 */ { 0x00000183, 0x0000 }, /* R387 - FLL1 Synchroniser 3 */ { 0x00000184, 0x0000 }, /* R388 - FLL1 Synchroniser 4 */ { 0x00000185, 0x0000 }, /* R389 - FLL1 Synchroniser 5 */ { 0x00000186, 0x0000 }, /* R390 - FLL1 Synchroniser 6 */ + { 0x00000187, 0x0001 }, /* R390 - FLL1 Synchroniser 7 */ { 0x00000189, 0x0000 }, /* R393 - FLL1 Spread Spectrum */ { 0x0000018A, 0x0004 }, /* R394 - FLL1 GPIO Clock */ { 0x00000191, 0x0000 }, /* R401 - FLL2 Control 1 */ @@ -484,12 +486,14 @@ static const struct reg_default wm5110_reg_default[] = { { 0x00000196, 0x0000 }, /* R406 - FLL2 Control 6 */ { 0x00000197, 0x0000 }, /* R407 - FLL2 Loop Filter Test 1 */ { 0x00000198, 0x0000 }, /* R408 - FLL2 NCO Test 0 */ + { 0x00000199, 0x0000 }, /* R408 - FLL2 Control 7 */ { 0x000001A1, 0x0000 }, /* R417 - FLL2 Synchroniser 1 */ { 0x000001A2, 0x0000 }, /* R418 - FLL2 Synchroniser 2 */ { 0x000001A3, 0x0000 }, /* R419 - FLL2 Synchroniser 3 */ { 0x000001A4, 0x0000 }, /* R420 - FLL2 Synchroniser 4 */ { 0x000001A5, 0x0000 }, /* R421 - FLL2 Synchroniser 5 */ { 0x000001A6, 0x0000 }, /* R422 - FLL2 Synchroniser 6 */ + { 0x000001A7, 0x0001 }, /* R422 - FLL2 Synchroniser 7 */ { 0x000001A9, 0x0000 }, /* R425 - FLL2 Spread Spectrum */ { 0x000001AA, 0x0004 }, /* R426 - FLL2 GPIO Clock */ { 0x00000200, 0x0006 }, /* R512 - Mic Charge Pump 1 */ @@ -503,6 +507,11 @@ static const struct reg_default wm5110_reg_default[] = { { 0x0000029C, 0x0000 }, /* R668 - Headphone Detect 2 */ { 0x000002A3, 0x1102 }, /* R675 - Mic Detect 1 */ { 0x000002A4, 0x009F }, /* R676 - Mic Detect 2 */ + { 0x000002A5, 0x0000 }, /* R677 - Mic Detect 3 */ + { 0x000002A6, 0x3737 }, /* R678 - Mic Detect Level 1 */ + { 0x000002A7, 0x372C }, /* R679 - Mic Detect Level 2 */ + { 0x000002A8, 0x1422 }, /* R680 - Mic Detect Level 3 */ + { 0x000002A9, 0x300A }, /* R681 - Mic Detect Level 4 */ { 0x000002C3, 0x0000 }, /* R707 - Mic noise mix control 1 */ { 0x000002D3, 0x0000 }, /* R723 - Jack detect analogue */ { 0x00000300, 0x0000 }, /* R768 - Input Enables */ @@ -1392,6 +1401,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_FLL1_CONTROL_4: case ARIZONA_FLL1_CONTROL_5: case ARIZONA_FLL1_CONTROL_6: + case ARIZONA_FLL1_CONTROL_7: case ARIZONA_FLL1_LOOP_FILTER_TEST_1: case ARIZONA_FLL1_NCO_TEST_0: case ARIZONA_FLL1_SYNCHRONISER_1: @@ -1400,6 +1410,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_FLL1_SYNCHRONISER_4: case ARIZONA_FLL1_SYNCHRONISER_5: case ARIZONA_FLL1_SYNCHRONISER_6: + case ARIZONA_FLL1_SYNCHRONISER_7: case ARIZONA_FLL1_SPREAD_SPECTRUM: case ARIZONA_FLL1_GPIO_CLOCK: case ARIZONA_FLL2_CONTROL_1: @@ -1408,6 +1419,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_FLL2_CONTROL_4: case ARIZONA_FLL2_CONTROL_5: case ARIZONA_FLL2_CONTROL_6: + case ARIZONA_FLL2_CONTROL_7: case ARIZONA_FLL2_LOOP_FILTER_TEST_1: case ARIZONA_FLL2_NCO_TEST_0: case ARIZONA_FLL2_SYNCHRONISER_1: @@ -1416,6 +1428,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_FLL2_SYNCHRONISER_4: case ARIZONA_FLL2_SYNCHRONISER_5: case ARIZONA_FLL2_SYNCHRONISER_6: + case ARIZONA_FLL2_SYNCHRONISER_7: case ARIZONA_FLL2_SPREAD_SPECTRUM: case ARIZONA_FLL2_GPIO_CLOCK: case ARIZONA_MIC_CHARGE_PUMP_1: @@ -1430,6 +1443,10 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_MIC_DETECT_1: case ARIZONA_MIC_DETECT_2: case ARIZONA_MIC_DETECT_3: + case ARIZONA_MIC_DETECT_LEVEL_1: + case ARIZONA_MIC_DETECT_LEVEL_2: + case ARIZONA_MIC_DETECT_LEVEL_3: + case ARIZONA_MIC_DETECT_LEVEL_4: case ARIZONA_MIC_NOISE_MIX_CONTROL_1: case ARIZONA_JACK_DETECT_ANALOGUE: case ARIZONA_INPUT_ENABLES: @@ -2332,6 +2349,7 @@ static bool wm5110_volatile_register(struct device *dev, unsigned int reg) case ARIZONA_IRQ_PIN_STATUS: case ARIZONA_AOD_IRQ1: case ARIZONA_AOD_IRQ2: + case ARIZONA_FX_CTRL2: case ARIZONA_ASRC_STATUS: case ARIZONA_DSP_STATUS: case ARIZONA_DSP1_CONTROL_1: diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 521340a708d3..5c459f469224 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -1618,7 +1618,7 @@ EXPORT_SYMBOL_GPL(wm831x_regmap_config); */ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) { - struct wm831x_pdata *pdata = wm831x->dev->platform_data; + struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev); int rev, wm831x_num; enum wm831x_parent parent; int ret, i; diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index 804e56ec99eb..64e512eadf17 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c @@ -571,7 +571,7 @@ static struct irq_domain_ops wm831x_irq_domain_ops = { int wm831x_irq_init(struct wm831x *wm831x, int irq) { - struct wm831x_pdata *pdata = wm831x->dev->platform_data; + struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev); struct irq_domain *domain; int i, ret, irq_base; diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c index e7ed14f661d8..07de3cc5a0d9 100644 --- a/drivers/mfd/wm831x-spi.c +++ b/drivers/mfd/wm831x-spi.c @@ -34,7 +34,6 @@ static int wm831x_spi_probe(struct spi_device *spi) if (wm831x == NULL) return -ENOMEM; - spi->bits_per_word = 16; spi->mode = SPI_MODE_0; spi_set_drvdata(spi, wm831x); diff --git a/drivers/mfd/wm8350-i2c.c b/drivers/mfd/wm8350-i2c.c index 2e57101c8d3d..f919def05e24 100644 --- a/drivers/mfd/wm8350-i2c.c +++ b/drivers/mfd/wm8350-i2c.c @@ -27,6 +27,7 @@ static int wm8350_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct wm8350 *wm8350; + struct wm8350_platform_data *pdata = dev_get_platdata(&i2c->dev); int ret = 0; wm8350 = devm_kzalloc(&i2c->dev, sizeof(struct wm8350), GFP_KERNEL); @@ -44,7 +45,7 @@ static int wm8350_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm8350); wm8350->dev = &i2c->dev; - return wm8350_device_init(wm8350, i2c->irq, i2c->dev.platform_data); + return wm8350_device_init(wm8350, i2c->irq, pdata); } static int wm8350_i2c_remove(struct i2c_client *i2c) diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index 639ca359242f..d66d256551fb 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c @@ -178,7 +178,7 @@ static int wm8400_i2c_probe(struct i2c_client *i2c, wm8400->dev = &i2c->dev; i2c_set_clientdata(i2c, wm8400); - ret = wm8400_init(wm8400, i2c->dev.platform_data); + ret = wm8400_init(wm8400, dev_get_platdata(&i2c->dev)); if (ret != 0) goto err; diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 781115e8dca9..e1c283e6d4e5 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -201,35 +201,7 @@ static int wm8994_suspend(struct device *dev) int ret; /* Don't actually go through with the suspend if the CODEC is - * still active (eg, for audio passthrough from CP. */ - ret = wm8994_reg_read(wm8994, WM8994_POWER_MANAGEMENT_1); - if (ret < 0) { - dev_err(dev, "Failed to read power status: %d\n", ret); - } else if (ret & WM8994_VMID_SEL_MASK) { - dev_dbg(dev, "CODEC still active, ignoring suspend\n"); - return 0; - } - - ret = wm8994_reg_read(wm8994, WM8994_POWER_MANAGEMENT_4); - if (ret < 0) { - dev_err(dev, "Failed to read power status: %d\n", ret); - } else if (ret & (WM8994_AIF2ADCL_ENA | WM8994_AIF2ADCR_ENA | - WM8994_AIF1ADC2L_ENA | WM8994_AIF1ADC2R_ENA | - WM8994_AIF1ADC1L_ENA | WM8994_AIF1ADC1R_ENA)) { - dev_dbg(dev, "CODEC still active, ignoring suspend\n"); - return 0; - } - - ret = wm8994_reg_read(wm8994, WM8994_POWER_MANAGEMENT_5); - if (ret < 0) { - dev_err(dev, "Failed to read power status: %d\n", ret); - } else if (ret & (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA | - WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA | - WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA)) { - dev_dbg(dev, "CODEC still active, ignoring suspend\n"); - return 0; - } - + * still active for accessory detect. */ switch (wm8994->type) { case WM8958: case WM1811: @@ -245,20 +217,6 @@ static int wm8994_suspend(struct device *dev) break; } - switch (wm8994->type) { - case WM1811: - ret = wm8994_reg_read(wm8994, WM8994_ANTIPOP_2); - if (ret < 0) { - dev_err(dev, "Failed to read jackdet: %d\n", ret); - } else if (ret & WM1811_JACKDET_MODE_MASK) { - dev_dbg(dev, "CODEC still active, ignoring suspend\n"); - return 0; - } - break; - default: - break; - } - /* Disable LDO pulldowns while the device is suspended if we * don't know that something will be driving them. */ if (!wm8994->ldo_ena_always_driven) diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c index d3a184a240f5..e74dedda5b55 100644 --- a/drivers/mfd/wm8994-irq.c +++ b/drivers/mfd/wm8994-irq.c @@ -193,7 +193,7 @@ int wm8994_irq_init(struct wm8994 *wm8994) { int ret; unsigned long irqflags; - struct wm8994_pdata *pdata = wm8994->dev->platform_data; + struct wm8994_pdata *pdata = dev_get_platdata(wm8994->dev); if (!wm8994->irq) { dev_warn(wm8994->dev, diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c index 82a35b91cdbc..375a880e0c5f 100644 --- a/drivers/mmc/host/rtsx_pci_sdmmc.c +++ b/drivers/mmc/host/rtsx_pci_sdmmc.c @@ -1,6 +1,6 @@ /* Realtek PCI-Express SD/MMC Card Interface driver * - * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved. + * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -17,7 +17,6 @@ * * Author: * Wei WANG <wei_wang@realsil.com.cn> - * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China */ #include <linux/module.h> @@ -56,7 +55,6 @@ struct realtek_pci_sdmmc { bool double_clk; bool eject; bool initial_mode; - bool ddr_mode; int power_state; #define SDMMC_POWER_ON 1 #define SDMMC_POWER_OFF 0 @@ -228,6 +226,7 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, int stat_idx = 0; u8 rsp_type; int rsp_len = 5; + bool clock_toggled = false; dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n", __func__, cmd_idx, arg); @@ -271,6 +270,8 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, 0xFF, SD_CLK_TOGGLE_EN); if (err < 0) goto out; + + clock_toggled = true; } rtsx_pci_init_cmd(pcr); @@ -351,6 +352,10 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host, out: cmd->error = err; + + if (err && clock_toggled) + rtsx_pci_write_register(pcr, SD_BUS_STAT, + SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); } static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq) @@ -475,18 +480,24 @@ static void sd_normal_rw(struct realtek_pci_sdmmc *host, kfree(buf); } -static int sd_change_phase(struct realtek_pci_sdmmc *host, u8 sample_point) +static int sd_change_phase(struct realtek_pci_sdmmc *host, + u8 sample_point, bool rx) { struct rtsx_pcr *pcr = host->pcr; int err; - dev_dbg(sdmmc_dev(host), "%s: sample_point = %d\n", - __func__, sample_point); + dev_dbg(sdmmc_dev(host), "%s(%s): sample_point = %d\n", + __func__, rx ? "RX" : "TX", sample_point); rtsx_pci_init_cmd(pcr); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CHANGE_CLK, CHANGE_CLK); - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPRX_CTL, 0x1F, sample_point); + if (rx) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + SD_VPRX_CTL, 0x1F, sample_point); + else + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, + SD_VPTX_CTL, 0x1F, sample_point); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, PHASE_NOT_RESET); @@ -602,7 +613,7 @@ static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host, int err; u8 cmd[5] = {0}; - err = sd_change_phase(host, sample_point); + err = sd_change_phase(host, sample_point, true); if (err < 0) return err; @@ -664,7 +675,7 @@ static int sd_tuning_rx(struct realtek_pci_sdmmc *host, u8 opcode) if (final_phase == 0xFF) return -EINVAL; - err = sd_change_phase(host, final_phase); + err = sd_change_phase(host, final_phase, true); if (err < 0) return err; } else { @@ -833,14 +844,11 @@ static int sd_set_power_mode(struct realtek_pci_sdmmc *host, return err; } -static int sd_set_timing(struct realtek_pci_sdmmc *host, - unsigned char timing, bool *ddr_mode) +static int sd_set_timing(struct realtek_pci_sdmmc *host, unsigned char timing) { struct rtsx_pcr *pcr = host->pcr; int err = 0; - *ddr_mode = false; - rtsx_pci_init_cmd(pcr); switch (timing) { @@ -857,8 +865,6 @@ static int sd_set_timing(struct realtek_pci_sdmmc *host, break; case MMC_TIMING_UHS_DDR50: - *ddr_mode = true; - rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, 0x0C | SD_ASYNC_FIFO_NOT_RST, SD_DDR_MODE | SD_ASYNC_FIFO_NOT_RST); @@ -926,7 +932,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) sd_set_bus_width(host, ios->bus_width); sd_set_power_mode(host, ios->power_mode); - sd_set_timing(host, ios->timing, &host->ddr_mode); + sd_set_timing(host, ios->timing); host->vpclk = false; host->double_clk = true; @@ -1121,11 +1127,11 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios) goto out; } +out: /* Stop toggle SD clock in idle */ err = rtsx_pci_write_register(pcr, SD_BUS_STAT, SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0); -out: mutex_unlock(&pcr->pcr_mutex); return err; @@ -1148,9 +1154,35 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode) rtsx_pci_start_run(pcr); - if (!host->ddr_mode) - err = sd_tuning_rx(host, MMC_SEND_TUNING_BLOCK); + /* Set initial TX phase */ + switch (mmc->ios.timing) { + case MMC_TIMING_UHS_SDR104: + err = sd_change_phase(host, SDR104_TX_PHASE(pcr), false); + break; + + case MMC_TIMING_UHS_SDR50: + err = sd_change_phase(host, SDR50_TX_PHASE(pcr), false); + break; + + case MMC_TIMING_UHS_DDR50: + err = sd_change_phase(host, DDR50_TX_PHASE(pcr), false); + break; + + default: + err = 0; + } + if (err) + goto out; + + /* Tuning RX phase */ + if ((mmc->ios.timing == MMC_TIMING_UHS_SDR104) || + (mmc->ios.timing == MMC_TIMING_UHS_SDR50)) + err = sd_tuning_rx(host, opcode); + else if (mmc->ios.timing == MMC_TIMING_UHS_DDR50) + err = sd_change_phase(host, DDR50_RX_PHASE(pcr), true); + +out: mutex_unlock(&pcr->pcr_mutex); return err; |