diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-15 06:58:16 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-10-15 06:58:16 +0200 |
commit | fcc3a5d277571bc6048e7b4ef8cd391b935de629 (patch) | |
tree | 143954c115011c657f747a0e1470973b94ab3690 /drivers/mfd | |
parent | 50fa86172bec2769979b5eb0cd1a244391ae4bb0 (diff) | |
parent | d86c21fd31114e3ef9fae64be335c76aa22859dc (diff) |
Merge tag 'mfd-for-linus-3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd
Pull MFD updates from Lee Jones:
"Changes to existing drivers:
- DT clean-ups in da9055-core, max14577, rn5t618, arizona, hi6421, stmpe, twl4030
- Export symbols for use in modules in max14577
- Plenty of static code analysis/Coccinelle fixes throughout the SS
- Regmap clean-ups in arizona, wm5102, wm5110, da9052, tps65217, rk808
- Remove unused/duplicate code in da9052, 88pm860x, ti_ssp, lpc_sch, arizona
- Bug fixes in ti_am335x_tscadc, da9052, ti_am335x_tscadc, rtsx_pcr
- IRQ fixups in arizona, stmpe, max14577
- Regulator related changes in axp20x
- Pass DMA coherency information from parent => child in MFD core
- Rename DT document files for consistency
- Add ACPI support to the MFD core
- Add Andreas Werner to MAINTAINERS for MEN F21BMC
New drivers/supported devices:
- New driver for MEN 14F021P00 Board Management Controller
- New driver for Ricoh RN5T618 PMIC
- New driver for Rockchip RK808
- New driver for HiSilicon Hi6421 PMIC
- New driver for Qualcomm SPMI PMICs
- Add support for Intel Braswell in lpc_ich
- Add support for Intel 9 Series PCH in lpc_ich
- Add support for Intel Quark ILB in lpc_sch"
[ Delayed to after the poweer/reset pull due to Kconfig problems with
recursive Kconfig select/depends-on chains. - Linus ]
* tag 'mfd-for-linus-3.18' of git://git.kernel.org/pub/scm/linux/kernel/git/lee/mfd: (79 commits)
mfd: cros_ec: wait for completion of commands that return IN_PROGRESS
i2c: i2c-cros-ec-tunnel: Set retries to 3
mfd: cros_ec: move locking into cros_ec_cmd_xfer
mfd: cros_ec: stop calling ->cmd_xfer() directly
mfd: cros_ec: Delay for 50ms when we see EC_CMD_REBOOT_EC
MAINTAINERS: Adds Andreas Werner to maintainers list for MEN F21BMC
mfd: arizona: Correct mask to allow setting micbias external cap
mfd: Add ACPI support
Revert "mfd: wm5102: Manually apply register patch"
mfd: ti_am335x_tscadc: Update logic in CTRL register for 5-wire TS
mfd: dt-bindings: atmel-gpbr: Rename doc file to conform to naming convention
mfd: dt-bindings: qcom-pm8xxx: Rename doc file to conform to naming convention
mfd: Inherit coherent_dma_mask from parent device
mfd: Document DT bindings for Qualcomm SPMI PMICs
mfd: Add support for Qualcomm SPMI PMICs
mfd: dt-bindings: pm8xxx: Add new compatible string
mfd: axp209x: Drop the parent supplies field
mfd: twl4030-power: Use 'ti,system-power-controller' as alternative way to support system power off
mfd: dt-bindings: twl4030-power: Use the standard property to mark power control
mfd: syscon: Add Atmel GPBR DT bindings documention
...
Diffstat (limited to 'drivers/mfd')
41 files changed, 1047 insertions, 290 deletions
diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c index a93b4d0134a2..84e313107233 100644 --- a/drivers/mfd/88pm860x-i2c.c +++ b/drivers/mfd/88pm860x-i2c.c @@ -122,7 +122,7 @@ static int read_device(struct i2c_client *i2c, int reg, static int write_device(struct i2c_client *i2c, int reg, int bytes, void *src) { - unsigned char buf[bytes + 1]; + unsigned char buf[2]; struct i2c_adapter *adap = i2c->adapter; struct i2c_msg msg; int ret; @@ -140,26 +140,6 @@ static int write_device(struct i2c_client *i2c, int reg, return 0; } -int pm860x_page_reg_read(struct i2c_client *i2c, int reg) -{ - unsigned char zero = 0; - unsigned char data; - int ret; - - i2c_lock_adapter(i2c->adapter); - read_device(i2c, 0xFA, 0, &zero); - read_device(i2c, 0xFB, 0, &zero); - read_device(i2c, 0xFF, 0, &zero); - ret = read_device(i2c, reg, 1, &data); - if (ret >= 0) - ret = (int)data; - read_device(i2c, 0xFE, 0, &zero); - read_device(i2c, 0xFC, 0, &zero); - i2c_unlock_adapter(i2c->adapter); - return ret; -} -EXPORT_SYMBOL(pm860x_page_reg_read); - int pm860x_page_reg_write(struct i2c_client *i2c, int reg, unsigned char data) { @@ -195,47 +175,3 @@ int pm860x_page_bulk_read(struct i2c_client *i2c, int reg, return ret; } EXPORT_SYMBOL(pm860x_page_bulk_read); - -int pm860x_page_bulk_write(struct i2c_client *i2c, int reg, - int count, unsigned char *buf) -{ - unsigned char zero = 0; - int ret; - - i2c_lock_adapter(i2c->adapter); - read_device(i2c, 0xFA, 0, &zero); - read_device(i2c, 0xFB, 0, &zero); - read_device(i2c, 0xFF, 0, &zero); - ret = write_device(i2c, reg, count, buf); - read_device(i2c, 0xFE, 0, &zero); - read_device(i2c, 0xFC, 0, &zero); - i2c_unlock_adapter(i2c->adapter); - i2c_unlock_adapter(i2c->adapter); - return ret; -} -EXPORT_SYMBOL(pm860x_page_bulk_write); - -int pm860x_page_set_bits(struct i2c_client *i2c, int reg, - unsigned char mask, unsigned char data) -{ - unsigned char zero; - unsigned char value; - int ret; - - i2c_lock_adapter(i2c->adapter); - read_device(i2c, 0xFA, 0, &zero); - read_device(i2c, 0xFB, 0, &zero); - read_device(i2c, 0xFF, 0, &zero); - ret = read_device(i2c, reg, 1, &value); - if (ret < 0) - goto out; - value &= ~mask; - value |= data; - ret = write_device(i2c, reg, 1, &value); -out: - read_device(i2c, 0xFE, 0, &zero); - read_device(i2c, 0xFC, 0, &zero); - i2c_unlock_adapter(i2c->adapter); - return ret; -} -EXPORT_SYMBOL(pm860x_page_set_bits); diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index cf66ef1ffaf3..1456ea70bbc7 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -210,6 +210,19 @@ config MFD_MC13XXX_I2C help Select this if your MC13xxx is connected via an I2C bus. +config MFD_HI6421_PMIC + tristate "HiSilicon Hi6421 PMU/Codec IC" + depends on OF + select MFD_CORE + select REGMAP_MMIO + help + Add support for HiSilicon Hi6421 PMIC. Hi6421 includes multi- + functions, such as regulators, RTC, codec, Coulomb counter, etc. + This driver includes core APIs _only_. You have to select + individul components like voltage regulators under corresponding + menus in order to enable them. + We communicate with the Hi6421 via memory-mapped I/O. + config HTC_EGPIO bool "HTC EGPIO support" depends on GPIOLIB && ARM @@ -554,6 +567,21 @@ config MFD_PM8921_CORE Say M here if you want to include support for PM8921 chip as a module. This will build a module called "pm8921-core". +config MFD_SPMI_PMIC + tristate "Qualcomm SPMI PMICs" + depends on ARCH_QCOM || COMPILE_TEST + depends on OF + depends on SPMI + select REGMAP_SPMI + help + This enables support for the Qualcomm SPMI PMICs. + These PMICs are currently used with the Snapdragon 800 series of + SoCs. Note, that this will only be useful paired with descriptions + of the independent functions as children nodes in the device tree. + + Say M here if you want to include support for the SPMI PMIC + series as a module. The module will be called "qcom-spmi-pmic". + config MFD_RDC321X tristate "RDC R-321x southbridge" select MFD_CORE @@ -597,6 +625,30 @@ config MFD_RC5T583 Additional drivers must be enabled in order to use the different functionality of the device. +config MFD_RK808 + tristate "Rockchip RK808 Power Management chip" + depends on I2C && OF + select MFD_CORE + select REGMAP_I2C + select REGMAP_IRQ + help + If you say yes here you get support for the RK808 + Power Management chips. + This driver provides common support for accessing the device + through I2C interface. The device supports multiple sub-devices + including interrupts, RTC, LDO & DCDC regulators, and onkey. + +config MFD_RN5T618 + tristate "Ricoh RN5T5618 PMIC" + depends on I2C + select MFD_CORE + select REGMAP_I2C + help + Say yes here to add support for the Ricoh RN5T618 PMIC. This + driver provides common support for accessing the device, + additional drivers must be enabled in order to use the + functionality of the device. + config MFD_SEC_CORE bool "SAMSUNG Electronics PMIC Series Support" depends on I2C=y @@ -1243,11 +1295,11 @@ config MFD_WM8350_I2C selected to enable support for the functionality of the chip. config MFD_WM8994 - bool "Wolfson Microelectronics WM8994" + tristate "Wolfson Microelectronics WM8994" select MFD_CORE select REGMAP_I2C select REGMAP_IRQ - depends on I2C=y + depends on I2C help The WM8994 is a highly integrated hi-fi CODEC designed for smartphone applicatiosn. As well as audio functionality it diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index d58068aa8aa9..8bd54b1253af 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -153,6 +153,7 @@ obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o ssbi.o +obj-$(CONFIG_MFD_SPMI_PMIC) += qcom-spmi-pmic.o obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o obj-$(CONFIG_MFD_TPS65090) += tps65090.o obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o @@ -160,6 +161,8 @@ obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o obj-$(CONFIG_MFD_PALMAS) += palmas.o obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o +obj-$(CONFIG_MFD_RK808) += rk808.o +obj-$(CONFIG_MFD_RN5T618) += rn5t618.o obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o obj-$(CONFIG_MFD_SYSCON) += syscon.o obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o @@ -170,6 +173,7 @@ obj-$(CONFIG_MFD_AS3722) += as3722.o obj-$(CONFIG_MFD_STW481X) += stw481x.o obj-$(CONFIG_MFD_IPAQ_MICRO) += ipaq-micro.o obj-$(CONFIG_MFD_MENF21BMC) += menf21bmc.o +obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-pmic-core.o intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 10a0cb90619a..bce7c0784b6b 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -393,18 +393,6 @@ static int arizona_runtime_resume(struct device *dev) break; } - switch (arizona->type) { - case WM5102: - ret = wm5102_patch(arizona); - if (ret != 0) { - dev_err(arizona->dev, "Failed to apply patch: %d\n", - ret); - goto err; - } - default: - break; - } - ret = regcache_sync(arizona->regmap); if (ret != 0) { dev_err(arizona->dev, "Failed to restore register cache\n"); @@ -534,7 +522,11 @@ EXPORT_SYMBOL_GPL(arizona_of_get_named_gpio); static int arizona_of_get_core_pdata(struct arizona *arizona) { struct arizona_pdata *pdata = &arizona->pdata; + struct property *prop; + const __be32 *cur; + u32 val; int ret, i; + int count = 0; pdata->reset = arizona_of_get_named_gpio(arizona, "wlf,reset", true); @@ -560,6 +552,15 @@ static int arizona_of_get_core_pdata(struct arizona *arizona) ret); } + of_property_for_each_u32(arizona->dev->of_node, "wlf,inmode", prop, + cur, val) { + if (count == ARRAY_SIZE(arizona->pdata.inmode)) + break; + + arizona->pdata.inmode[count] = val; + count++; + } + return 0; } @@ -784,7 +785,8 @@ int arizona_dev_init(struct arizona *arizona) /* Ensure device startup is complete */ switch (arizona->type) { case WM5102: - ret = regmap_read(arizona->regmap, 0x19, &val); + ret = regmap_read(arizona->regmap, + ARIZONA_WRITE_SEQUENCER_CTRL_3, &val); if (ret != 0) dev_err(dev, "Failed to check write sequencer state: %d\n", @@ -945,6 +947,7 @@ int arizona_dev_init(struct arizona *arizona) regmap_update_bits(arizona->regmap, ARIZONA_MIC_BIAS_CTRL_1 + i, ARIZONA_MICB1_LVL_MASK | + ARIZONA_MICB1_EXT_CAP | ARIZONA_MICB1_DISCH | ARIZONA_MICB1_BYPASS | ARIZONA_MICB1_RATE, val); diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index d420dbc0e2b0..3a3fe7cc6d61 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -152,10 +152,18 @@ static void arizona_irq_disable(struct irq_data *data) { } +static int arizona_irq_set_wake(struct irq_data *data, unsigned int on) +{ + struct arizona *arizona = irq_data_get_irq_chip_data(data); + + return irq_set_irq_wake(arizona->irq, on); +} + static struct irq_chip arizona_irq_chip = { .name = "arizona", .irq_disable = arizona_irq_disable, .irq_enable = arizona_irq_enable, + .irq_set_wake = arizona_irq_set_wake, }; static int arizona_irq_map(struct irq_domain *h, unsigned int virq, @@ -164,7 +172,7 @@ static int arizona_irq_map(struct irq_domain *h, unsigned int virq, struct regmap_irq_chip_data *data = h->host_data; irq_set_chip_data(virq, data); - irq_set_chip_and_handler(virq, &arizona_irq_chip, handle_edge_irq); + irq_set_chip_and_handler(virq, &arizona_irq_chip, handle_simple_irq); irq_set_nested_thread(virq, 1); /* ARM needs us to explicitly flag the IRQ as valid @@ -282,7 +290,7 @@ int arizona_irq_init(struct arizona *arizona) ret = regmap_add_irq_chip(arizona->regmap, irq_create_mapping(arizona->virq, 0), - IRQF_ONESHOT, -1, aod, + IRQF_ONESHOT, 0, aod, &arizona->aod_irq_chip); if (ret != 0) { dev_err(arizona->dev, "Failed to add AOD IRQs: %d\n", ret); @@ -291,7 +299,7 @@ int arizona_irq_init(struct arizona *arizona) ret = regmap_add_irq_chip(arizona->regmap, irq_create_mapping(arizona->virq, 1), - IRQF_ONESHOT, -1, irq, + IRQF_ONESHOT, 0, irq, &arizona->irq_chip); if (ret != 0) { dev_err(arizona->dev, "Failed to add main IRQs: %d\n", ret); diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index dee653989e3a..6231adbb295d 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -140,15 +140,6 @@ static const struct regmap_irq_chip axp20x_regmap_irq_chip = { .init_ack_masked = true, }; -static const char * const axp20x_supplies[] = { - "acin", - "vin2", - "vin3", - "ldo24in", - "ldo3in", - "ldo5in", -}; - static struct mfd_cell axp20x_cells[] = { { .name = "axp20x-pek", @@ -156,8 +147,6 @@ static struct mfd_cell axp20x_cells[] = { .resources = axp20x_pek_resources, }, { .name = "axp20x-regulator", - .parent_supplies = axp20x_supplies, - .num_parent_supplies = ARRAY_SIZE(axp20x_supplies), }, }; diff --git a/drivers/mfd/cros_ec.c b/drivers/mfd/cros_ec.c index 4873f9c50452..fc0c81ef04ff 100644 --- a/drivers/mfd/cros_ec.c +++ b/drivers/mfd/cros_ec.c @@ -23,6 +23,9 @@ #include <linux/mfd/core.h> #include <linux/mfd/cros_ec.h> #include <linux/mfd/cros_ec_commands.h> +#include <linux/delay.h> + +#define EC_COMMAND_RETRIES 50 int cros_ec_prepare_tx(struct cros_ec_device *ec_dev, struct cros_ec_command *msg) @@ -62,6 +65,49 @@ int cros_ec_check_result(struct cros_ec_device *ec_dev, } EXPORT_SYMBOL(cros_ec_check_result); +int cros_ec_cmd_xfer(struct cros_ec_device *ec_dev, + struct cros_ec_command *msg) +{ + int ret; + + mutex_lock(&ec_dev->lock); + ret = ec_dev->cmd_xfer(ec_dev, msg); + if (msg->result == EC_RES_IN_PROGRESS) { + int i; + struct cros_ec_command status_msg; + struct ec_response_get_comms_status status; + + status_msg.version = 0; + status_msg.command = EC_CMD_GET_COMMS_STATUS; + status_msg.outdata = NULL; + status_msg.outsize = 0; + status_msg.indata = (uint8_t *)&status; + status_msg.insize = sizeof(status); + + /* + * Query the EC's status until it's no longer busy or + * we encounter an error. + */ + for (i = 0; i < EC_COMMAND_RETRIES; i++) { + usleep_range(10000, 11000); + + ret = ec_dev->cmd_xfer(ec_dev, &status_msg); + if (ret < 0) + break; + + msg->result = status_msg.result; + if (status_msg.result != EC_RES_SUCCESS) + break; + if (!(status.flags & EC_COMMS_STATUS_PROCESSING)) + break; + } + } + mutex_unlock(&ec_dev->lock); + + return ret; +} +EXPORT_SYMBOL(cros_ec_cmd_xfer); + static const struct mfd_cell cros_devs[] = { { .name = "cros-ec-keyb", @@ -91,6 +137,8 @@ int cros_ec_register(struct cros_ec_device *ec_dev) return -ENOMEM; } + mutex_init(&ec_dev->lock); + err = mfd_add_devices(dev, 0, cros_devs, ARRAY_SIZE(cros_devs), NULL, ec_dev->irq, NULL); diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c index 588c700af39c..bf6e08e8013e 100644 --- a/drivers/mfd/cros_ec_spi.c +++ b/drivers/mfd/cros_ec_spi.c @@ -65,6 +65,12 @@ */ #define EC_SPI_RECOVERY_TIME_NS (200 * 1000) +/* + * The EC is unresponsive for a time after a reboot command. Add a + * simple delay to make sure that the bus stays locked. + */ +#define EC_REBOOT_DELAY_MS 50 + /** * struct cros_ec_spi - information about a SPI-connected EC * @@ -73,13 +79,11 @@ * if no record * @end_of_msg_delay: used to set the delay_usecs on the spi_transfer that * is sent when we want to turn off CS at the end of a transaction. - * @lock: mutex to ensure only one user of cros_ec_cmd_xfer_spi at a time */ struct cros_ec_spi { struct spi_device *spi; s64 last_transfer_ns; unsigned int end_of_msg_delay; - struct mutex lock; }; static void debug_packet(struct device *dev, const char *name, u8 *ptr, @@ -226,13 +230,6 @@ static int cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev, int sum; int ret = 0, final_ret; - /* - * We have the shared ec_dev buffer plus we do lots of separate spi_sync - * calls, so we need to make sure only one person is using this at a - * time. - */ - mutex_lock(&ec_spi->lock); - len = cros_ec_prepare_tx(ec_dev, ec_msg); dev_dbg(ec_dev->dev, "prepared, len=%d\n", len); @@ -318,7 +315,9 @@ static int cros_ec_cmd_xfer_spi(struct cros_ec_device *ec_dev, ret = len; exit: - mutex_unlock(&ec_spi->lock); + if (ec_msg->command == EC_CMD_REBOOT_EC) + msleep(EC_REBOOT_DELAY_MS); + return ret; } @@ -350,7 +349,6 @@ static int cros_ec_spi_probe(struct spi_device *spi) if (ec_spi == NULL) return -ENOMEM; ec_spi->spi = spi; - mutex_init(&ec_spi->lock); ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL); if (!ec_dev) return -ENOMEM; diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c index e8af816d73a9..52a0c2f6264f 100644 --- a/drivers/mfd/da9052-core.c +++ b/drivers/mfd/da9052-core.c @@ -522,7 +522,7 @@ static const struct mfd_cell da9052_subdev_info[] = { }, }; -struct regmap_config da9052_regmap_config = { +const struct regmap_config da9052_regmap_config = { .reg_bits = 8, .val_bits = 8, diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c index 6da8ec8ff800..ec39287a245b 100644 --- a/drivers/mfd/da9052-i2c.c +++ b/drivers/mfd/da9052-i2c.c @@ -140,13 +140,6 @@ static int da9052_i2c_probe(struct i2c_client *client, if (!da9052) return -ENOMEM; - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_info(&client->dev, "Error in %s:i2c_check_functionality\n", - __func__); - return -ENODEV; - } - da9052->dev = &client->dev; da9052->chip_irq = client->irq; da9052->fix_io = da9052_i2c_fix; diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c index 17666b40b70c..45ae0b7d13ef 100644 --- a/drivers/mfd/da9052-spi.c +++ b/drivers/mfd/da9052-spi.c @@ -23,6 +23,7 @@ static int da9052_spi_probe(struct spi_device *spi) { + struct regmap_config config; int ret; const struct spi_device_id *id = spi_get_device_id(spi); struct da9052 *da9052; @@ -40,10 +41,10 @@ static int da9052_spi_probe(struct spi_device *spi) spi_set_drvdata(spi, da9052); - da9052_regmap_config.read_flag_mask = 1; - da9052_regmap_config.write_flag_mask = 0; + config = da9052_regmap_config; + config.read_flag_mask = 1; - da9052->regmap = devm_regmap_init_spi(spi, &da9052_regmap_config); + da9052->regmap = devm_regmap_init_spi(spi, &config); if (IS_ERR(da9052->regmap)) { ret = PTR_ERR(da9052->regmap); dev_err(&spi->dev, "Failed to allocate register map: %d\n", diff --git a/drivers/mfd/hi6421-pmic-core.c b/drivers/mfd/hi6421-pmic-core.c new file mode 100644 index 000000000000..321a2656fd00 --- /dev/null +++ b/drivers/mfd/hi6421-pmic-core.c @@ -0,0 +1,113 @@ +/* + * Device driver for Hi6421 IC + * + * Copyright (c) <2011-2014> HiSilicon Technologies Co., Ltd. + * http://www.hisilicon.com + * Copyright (c) <2013-2014> Linaro Ltd. + * http://www.linaro.org + * + * Author: Guodong Xu <guodong.xu@linaro.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/mfd/core.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/mfd/hi6421-pmic.h> + +static const struct mfd_cell hi6421_devs[] = { + { .name = "hi6421-regulator", }, +}; + +static struct regmap_config hi6421_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 8, + .max_register = HI6421_REG_TO_BUS_ADDR(HI6421_REG_MAX), +}; + +static int hi6421_pmic_probe(struct platform_device *pdev) +{ + struct hi6421_pmic *pmic; + struct resource *res; + void __iomem *base; + int ret; + + pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); + if (!pmic) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + pmic->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base, + &hi6421_regmap_config); + if (IS_ERR(pmic->regmap)) { + dev_err(&pdev->dev, + "regmap init failed: %ld\n", PTR_ERR(pmic->regmap)); + return PTR_ERR(pmic->regmap); + } + + /* set over-current protection debounce 8ms */ + regmap_update_bits(pmic->regmap, HI6421_OCP_DEB_CTRL_REG, + (HI6421_OCP_DEB_SEL_MASK + | HI6421_OCP_EN_DEBOUNCE_MASK + | HI6421_OCP_AUTO_STOP_MASK), + (HI6421_OCP_DEB_SEL_8MS + | HI6421_OCP_EN_DEBOUNCE_ENABLE)); + + platform_set_drvdata(pdev, pmic); + + ret = mfd_add_devices(&pdev->dev, 0, hi6421_devs, + ARRAY_SIZE(hi6421_devs), NULL, 0, NULL); + if (ret) { + dev_err(&pdev->dev, "add mfd devices failed: %d\n", ret); + return ret; + } + + return 0; +} + +static int hi6421_pmic_remove(struct platform_device *pdev) +{ + mfd_remove_devices(&pdev->dev); + + return 0; +} + +static struct of_device_id of_hi6421_pmic_match_tbl[] = { + { .compatible = "hisilicon,hi6421-pmic", }, + { }, +}; + +static struct platform_driver hi6421_pmic_driver = { + .driver = { + .name = "hi6421_pmic", + .of_match_table = of_hi6421_pmic_match_tbl, + }, + .probe = hi6421_pmic_probe, + .remove = hi6421_pmic_remove, +}; +module_platform_driver(hi6421_pmic_driver); + +MODULE_AUTHOR("Guodong Xu <guodong.xu@linaro.org>"); +MODULE_DESCRIPTION("Hi6421 PMIC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c index adbbce0ff630..ebb9cf19e347 100644 --- a/drivers/mfd/htc-i2cpld.c +++ b/drivers/mfd/htc-i2cpld.c @@ -227,15 +227,12 @@ static irqreturn_t htcpld_handler(int irq, void *dev) static void htcpld_chip_set(struct gpio_chip *chip, unsigned offset, int val) { struct i2c_client *client; - struct htcpld_chip *chip_data; + struct htcpld_chip *chip_data = + container_of(chip, struct htcpld_chip, chip_out); unsigned long flags; - chip_data = container_of(chip, struct htcpld_chip, chip_out); - if (!chip_data) - return; - client = chip_data->client; - if (client == NULL) + if (!client) return; spin_lock_irqsave(&chip_data->lock, flags); @@ -261,31 +258,18 @@ static void htcpld_chip_set_ni(struct work_struct *work) static int htcpld_chip_get(struct gpio_chip *chip, unsigned offset) { struct htcpld_chip *chip_data; - int val = 0; - int is_input = 0; - - /* Try out first */ - chip_data = container_of(chip, struct htcpld_chip, chip_out); - if (!chip_data) { - /* Try in */ - is_input = 1; - chip_data = container_of(chip, struct htcpld_chip, chip_in); - if (!chip_data) - return -EINVAL; - } + u8 cache; - /* Determine if this is an input or output GPIO */ - if (!is_input) - /* Use the output cache */ - val = (chip_data->cache_out >> offset) & 1; - else - /* Use the input cache */ - val = (chip_data->cache_in >> offset) & 1; + if (!strncmp(chip->label, "htcpld-out", 10)) { + chip_data = container_of(chip, struct htcpld_chip, chip_out); + cache = chip_data->cache_out; + } else if (!strncmp(chip->label, "htcpld-in", 9)) { + chip_data = container_of(chip, struct htcpld_chip, chip_in); + cache = chip_data->cache_in; + } else + return -EINVAL; - if (val) - return 1; - else - return 0; + return (cache >> offset) & 1; } static int htcpld_direction_output(struct gpio_chip *chip, @@ -376,7 +360,7 @@ static int htcpld_register_chip_i2c( plat_chip_data = &pdata->chip[chip_index]; adapter = i2c_get_adapter(pdata->i2c_adapter_id); - if (adapter == NULL) { + if (!adapter) { /* Eek, no such I2C adapter! Bail out. */ dev_warn(dev, "Chip at i2c address 0x%x: Invalid i2c adapter %d\n", plat_chip_data->addr, pdata->i2c_adapter_id); diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c index 2720922f90b4..df7b0642a5b4 100644 --- a/drivers/mfd/intel_soc_pmic_core.c +++ b/drivers/mfd/intel_soc_pmic_core.c @@ -115,6 +115,7 @@ static void intel_soc_pmic_shutdown(struct i2c_client *i2c) return; } +#if defined(CONFIG_PM_SLEEP) static int intel_soc_pmic_suspend(struct device *dev) { struct intel_soc_pmic *pmic = dev_get_drvdata(dev); @@ -132,6 +133,7 @@ static int intel_soc_pmic_resume(struct device *dev) return 0; } +#endif static SIMPLE_DEV_PM_OPS(intel_soc_pmic_pm_ops, intel_soc_pmic_suspend, intel_soc_pmic_resume); diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 7d8482ff5868..f35d4280b2f7 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -54,6 +54,7 @@ * document number TBD : Avoton SoC * document number TBD : Coleto Creek * document number TBD : Wildcat Point-LP + * document number TBD : 9 Series */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -216,6 +217,8 @@ enum lpc_chipsets { LPC_BAYTRAIL, /* Bay Trail SoC */ LPC_COLETO, /* Coleto Creek */ LPC_WPT_LP, /* Wildcat Point-LP */ + LPC_BRASWELL, /* Braswell SoC */ + LPC_9S, /* 9 Series */ }; static struct lpc_ich_info lpc_chipset_info[] = { @@ -519,6 +522,14 @@ static struct lpc_ich_info lpc_chipset_info[] = { .name = "Wildcat Point_LP", .iTCO_version = 2, }, + [LPC_BRASWELL] = { + .name = "Braswell SoC", + .iTCO_version = 3, + }, + [LPC_9S] = { + .name = "9 Series", + .iTCO_version = 2, + }, }; /* @@ -745,6 +756,12 @@ static const struct pci_device_id lpc_ich_ids[] = { { PCI_VDEVICE(INTEL, 0x9cc6), LPC_WPT_LP}, { PCI_VDEVICE(INTEL, 0x9cc7), LPC_WPT_LP}, { PCI_VDEVICE(INTEL, 0x9cc9), LPC_WPT_LP}, + { PCI_VDEVICE(INTEL, 0x229c), LPC_BRASWELL}, + { PCI_VDEVICE(INTEL, 0x8cc1), LPC_9S}, + { PCI_VDEVICE(INTEL, 0x8cc2), LPC_9S}, + { PCI_VDEVICE(INTEL, 0x8cc3), LPC_9S}, + { PCI_VDEVICE(INTEL, 0x8cc4), LPC_9S}, + { PCI_VDEVICE(INTEL, 0x8cc6), LPC_9S}, { 0, }, /* End of list */ }; MODULE_DEVICE_TABLE(pci, lpc_ich_ids); diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c index 4ee755034f3b..c980da479a35 100644 --- a/drivers/mfd/lpc_sch.c +++ b/drivers/mfd/lpc_sch.c @@ -7,6 +7,7 @@ * Configuration Registers. * * Copyright (c) 2010 CompuLab Ltd + * Copyright (c) 2014 Intel Corp. * Author: Denis Turischev <denis@compulab.co.il> * * This program is free software; you can redistribute it and/or modify @@ -17,10 +18,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/kernel.h> @@ -37,123 +34,165 @@ #define GPIO_IO_SIZE 64 #define GPIO_IO_SIZE_CENTERTON 128 +/* Intel Quark X1000 GPIO IRQ Number */ +#define GPIO_IRQ_QUARK_X1000 9 + #define WDTBASE 0x84 #define WDT_IO_SIZE 64 -static struct resource smbus_sch_resource = { - .flags = IORESOURCE_IO, -}; - -static struct resource gpio_sch_resource = { - .flags = IORESOURCE_IO, -}; - -static struct resource wdt_sch_resource = { - .flags = IORESOURCE_IO, +enum sch_chipsets { + LPC_SCH = 0, /* Intel Poulsbo SCH */ + LPC_ITC, /* Intel Tunnel Creek */ + LPC_CENTERTON, /* Intel Centerton */ + LPC_QUARK_X1000, /* Intel Quark X1000 */ }; -static struct mfd_cell lpc_sch_cells[3]; - -static struct mfd_cell isch_smbus_cell = { - .name = "isch_smbus", - .num_resources = 1, - .resources = &smbus_sch_resource, - .ignore_resource_conflicts = true, +struct lpc_sch_info { + unsigned int io_size_smbus; + unsigned int io_size_gpio; + unsigned int io_size_wdt; + int irq_gpio; }; -static struct mfd_cell sch_gpio_cell = { - .name = "sch_gpio", - .num_resources = 1, - .resources = &gpio_sch_resource, - .ignore_resource_conflicts = true, -}; - -static struct mfd_cell wdt_sch_cell = { - .name = "ie6xx_wdt", - .num_resources = 1, - .resources = &wdt_sch_resource, - .ignore_resource_conflicts = true, +static struct lpc_sch_info sch_chipset_info[] = { + [LPC_SCH] = { + .io_size_smbus = SMBUS_IO_SIZE, + .io_size_gpio = GPIO_IO_SIZE, + .irq_gpio = -1, + }, + [LPC_ITC] = { + .io_size_smbus = SMBUS_IO_SIZE, + .io_size_gpio = GPIO_IO_SIZE, + .io_size_wdt = WDT_IO_SIZE, + .irq_gpio = -1, + }, + [LPC_CENTERTON] = { + .io_size_smbus = SMBUS_IO_SIZE, + .io_size_gpio = GPIO_IO_SIZE_CENTERTON, + .io_size_wdt = WDT_IO_SIZE, + .irq_gpio = -1, + }, + [LPC_QUARK_X1000] = { + .io_size_gpio = GPIO_IO_SIZE, + .irq_gpio = GPIO_IRQ_QUARK_X1000, + }, }; static const struct pci_device_id lpc_sch_ids[] = { - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CENTERTON_ILB) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SCH_LPC), LPC_SCH }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ITC_LPC), LPC_ITC }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CENTERTON_ILB), LPC_CENTERTON }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_QUARK_X1000_ILB), LPC_QUARK_X1000 }, { 0, } }; MODULE_DEVICE_TABLE(pci, lpc_sch_ids); -static int lpc_sch_probe(struct pci_dev *dev, - const struct pci_device_id *id) +#define LPC_NO_RESOURCE 1 +#define LPC_SKIP_RESOURCE 2 + +static int lpc_sch_get_io(struct pci_dev *pdev, int where, const char *name, + struct resource *res, int size) { unsigned int base_addr_cfg; unsigned short base_addr; - int i, cells = 0; - int ret; - pci_read_config_dword(dev, SMBASE, &base_addr_cfg); + if (size == 0) + return LPC_NO_RESOURCE; + + pci_read_config_dword(pdev, where, &base_addr_cfg); base_addr = 0; if (!(base_addr_cfg & (1 << 31))) - dev_warn(&dev->dev, "Decode of the SMBus I/O range disabled\n"); + dev_warn(&pdev->dev, "Decode of the %s I/O range disabled\n", + name); else base_addr = (unsigned short)base_addr_cfg; if (base_addr == 0) { - dev_warn(&dev->dev, "I/O space for SMBus uninitialized\n"); - } else { - lpc_sch_cells[cells++] = isch_smbus_cell; - smbus_sch_resource.start = base_addr; - smbus_sch_resource.end = base_addr + SMBUS_IO_SIZE - 1; + dev_warn(&pdev->dev, "I/O space for %s uninitialized\n", name); + return LPC_SKIP_RESOURCE; } - pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg); - base_addr = 0; - if (!(base_addr_cfg & (1 << 31))) - dev_warn(&dev->dev, "Decode of the GPIO I/O range disabled\n"); - else - base_addr = (unsigned short)base_addr_cfg; + res->start = base_addr; + res->end = base_addr + size - 1; + res->flags = IORESOURCE_IO; - if (base_addr == 0) { - dev_warn(&dev->dev, "I/O space for GPIO uninitialized\n"); - } else { - lpc_sch_cells[cells++] = sch_gpio_cell; - gpio_sch_resource.start = base_addr; - if (id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) - gpio_sch_resource.end = base_addr + GPIO_IO_SIZE_CENTERTON - 1; - else - gpio_sch_resource.end = base_addr + GPIO_IO_SIZE - 1; - } + return 0; +} - if (id->device == PCI_DEVICE_ID_INTEL_ITC_LPC - || id->device == PCI_DEVICE_ID_INTEL_CENTERTON_ILB) { - pci_read_config_dword(dev, WDTBASE, &base_addr_cfg); - base_addr = 0; - if (!(base_addr_cfg & (1 << 31))) - dev_warn(&dev->dev, "Decode of the WDT I/O range disabled\n"); - else - base_addr = (unsigned short)base_addr_cfg; - if (base_addr == 0) - dev_warn(&dev->dev, "I/O space for WDT uninitialized\n"); - else { - lpc_sch_cells[cells++] = wdt_sch_cell; - wdt_sch_resource.start = base_addr; - wdt_sch_resource.end = base_addr + WDT_IO_SIZE - 1; - } - } +static int lpc_sch_populate_cell(struct pci_dev *pdev, int where, + const char *name, int size, int irq, + int id, struct mfd_cell *cell) +{ + struct resource *res; + int ret; - if (WARN_ON(cells > ARRAY_SIZE(lpc_sch_cells))) { - dev_err(&dev->dev, "Cell count exceeds array size"); - return -ENODEV; - } + res = devm_kcalloc(&pdev->dev, 2, sizeof(*res), GFP_KERNEL); + if (!res) + return -ENOMEM; + + ret = lpc_sch_get_io(pdev, where, name, res, size); + if (ret) + return ret; + + memset(cell, 0, sizeof(*cell)); + + cell->name = name; + cell->resources = res; + cell->num_resources = 1; + cell->ignore_resource_conflicts = true; + cell->id = id; + + /* Check if we need to add an IRQ resource */ + if (irq < 0) + return 0; + + res++; + + res->start = irq; + res->end = irq; + res->flags = IORESOURCE_IRQ; + + cell->num_resources++; + + return 0; +} + +static int lpc_sch_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct mfd_cell lpc_sch_cells[3]; + struct lpc_sch_info *info = &sch_chipset_info[id->driver_data]; + unsigned int cells = 0; + int ret; + + ret = lpc_sch_populate_cell(dev, SMBASE, "isch_smbus", + info->io_size_smbus, -1, + id->device, &lpc_sch_cells[cells]); + if (ret < 0) + return ret; + if (ret == 0) + cells++; + + ret = lpc_sch_populate_cell(dev, GPIOBASE, "sch_gpio", + info->io_size_gpio, info->irq_gpio, + id->device, &lpc_sch_cells[cells]); + if (ret < 0) + return ret; + if (ret == 0) + cells++; + + ret = lpc_sch_populate_cell(dev, WDTBASE, "ie6xx_wdt", + info->io_size_wdt, -1, + id->device, &lpc_sch_cells[cells]); + if (ret < 0) + return ret; + if (ret == 0) + cells++; if (cells == 0) { dev_err(&dev->dev, "All decode registers disabled.\n"); return -ENODEV; } - for (i = 0; i < cells; i++) - lpc_sch_cells[i].id = id->device; - ret = mfd_add_devices(&dev->dev, 0, lpc_sch_cells, cells, NULL, 0, NULL); if (ret) mfd_remove_devices(&dev->dev); diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c index b8af263be594..de96b7fb1f6d 100644 --- a/drivers/mfd/max14577.c +++ b/drivers/mfd/max14577.c @@ -456,8 +456,7 @@ static int max14577_i2c_probe(struct i2c_client *i2c, } ret = mfd_add_devices(max14577->dev, -1, mfd_devs, - mfd_devs_size, NULL, 0, - regmap_irq_get_domain(max14577->irq_data)); + mfd_devs_size, NULL, 0, NULL); if (ret < 0) goto err_mfd; diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c index 86e552348db4..929795eae9fc 100644 --- a/drivers/mfd/max77686.c +++ b/drivers/mfd/max77686.c @@ -52,7 +52,7 @@ static const struct mfd_cell max77802_devs[] = { static bool max77802_pmic_is_accessible_reg(struct device *dev, unsigned int reg) { - return (reg >= MAX77802_REG_DEVICE_ID && reg < MAX77802_REG_PMIC_END); + return reg < MAX77802_REG_PMIC_END; } static bool max77802_rtc_is_accessible_reg(struct device *dev, diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c index 249c139ef04a..cf008f45968c 100644 --- a/drivers/mfd/max77693.c +++ b/drivers/mfd/max77693.c @@ -44,9 +44,12 @@ static const struct mfd_cell max77693_devs[] = { { .name = "max77693-pmic", }, { .name = "max77693-charger", }, - { .name = "max77693-flash", }, { .name = "max77693-muic", }, { .name = "max77693-haptic", }, + { + .name = "max77693-flash", + .of_compatible = "maxim,max77693-flash", + }, }; static const struct regmap_config max77693_regmap_config = { diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c index ecbe78ead3b6..c880c895c5a6 100644 --- a/drivers/mfd/max8925-i2c.c +++ b/drivers/mfd/max8925-i2c.c @@ -37,7 +37,7 @@ static inline int max8925_read_device(struct i2c_client *i2c, static inline int max8925_write_device(struct i2c_client *i2c, int reg, int bytes, void *src) { - unsigned char buf[bytes + 1]; + unsigned char buf[9]; int ret; buf[0] = (unsigned char)reg; diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 2b6bc868cd3d..64dde5d24b32 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -36,6 +36,9 @@ #define MC34708_REVISION_FIN (0x07 << 6) #define MC34708_REVISION_FAB (0x07 << 9) +#define MC13XXX_PWRCTRL 15 +#define MC13XXX_PWRCTRL_WDIRESET (1 << 12) + #define MC13XXX_ADC1 44 #define MC13XXX_ADC1_ADEN (1 << 0) #define MC13XXX_ADC1_RAND (1 << 1) @@ -416,6 +419,11 @@ int mc13xxx_common_init(struct device *dev) mc13xxx->variant->print_revision(mc13xxx, revision); + ret = mc13xxx_reg_rmw(mc13xxx, MC13XXX_PWRCTRL, + MC13XXX_PWRCTRL_WDIRESET, MC13XXX_PWRCTRL_WDIRESET); + if (ret) + return ret; + for (i = 0; i < ARRAY_SIZE(mc13xxx->irqs); i++) { mc13xxx->irqs[i].reg_offset = i / MC13XXX_IRQ_PER_REG; mc13xxx->irqs[i].mask = BIT(i % MC13XXX_IRQ_PER_REG); diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c index 5e2667afe2bc..9f01aef539dd 100644 --- a/drivers/mfd/menelaus.c +++ b/drivers/mfd/menelaus.c @@ -466,8 +466,6 @@ 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) - goto set_voltage; ret = menelaus_read_reg(vtg->vtg_reg); if (ret < 0) @@ -482,7 +480,6 @@ static int menelaus_set_voltage(const struct menelaus_vtg *vtg, int mV, ret = menelaus_write_reg(vtg->vtg_reg, val); if (ret < 0) goto out; -set_voltage: ret = menelaus_write_reg(vtg->mode_reg, mode); out: mutex_unlock(&the_menelaus->lock); @@ -1186,7 +1183,7 @@ static int menelaus_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct menelaus_chip *menelaus; - int rev = 0, val; + int rev = 0; int err = 0; struct menelaus_platform_data *menelaus_pdata = dev_get_platdata(&client->dev); @@ -1239,10 +1236,10 @@ static int menelaus_probe(struct i2c_client *client, pr_info("Menelaus rev %d.%d\n", rev >> 4, rev & 0x0f); - val = menelaus_read_reg(MENELAUS_VCORE_CTRL1); - if (val < 0) + err = menelaus_read_reg(MENELAUS_VCORE_CTRL1); + if (err < 0) goto fail; - if (val & (1 << 7)) + if (err & BIT(7)) menelaus->vcore_hw_mode = 1; else menelaus->vcore_hw_mode = 0; diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 892d343193ad..f3338fe9d069 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -78,6 +78,44 @@ static int mfd_platform_add_cell(struct platform_device *pdev, return 0; } +#if IS_ENABLED(CONFIG_ACPI) +static void mfd_acpi_add_device(const struct mfd_cell *cell, + struct platform_device *pdev) +{ + struct acpi_device *parent_adev; + struct acpi_device *adev; + + parent_adev = ACPI_COMPANION(pdev->dev.parent); + if (!parent_adev) + return; + + /* + * MFD child device gets its ACPI handle either from the ACPI + * device directly under the parent that matches the acpi_pnpid or + * it will use the parent handle if is no acpi_pnpid is given. + */ + adev = parent_adev; + if (cell->acpi_pnpid) { + struct acpi_device_id ids[2] = {}; + struct acpi_device *child_adev; + + strlcpy(ids[0].id, cell->acpi_pnpid, sizeof(ids[0].id)); + list_for_each_entry(child_adev, &parent_adev->children, node) + if (acpi_match_device_ids(child_adev, ids)) { + adev = child_adev; + break; + } + } + + ACPI_COMPANION_SET(&pdev->dev, adev); +} +#else +static inline void mfd_acpi_add_device(const struct mfd_cell *cell, + struct platform_device *pdev) +{ +} +#endif + static int mfd_add_device(struct device *parent, int id, const struct mfd_cell *cell, atomic_t *usage_count, struct resource *mem_base, @@ -101,6 +139,7 @@ static int mfd_add_device(struct device *parent, int id, pdev->dev.type = &mfd_dev_type; pdev->dev.dma_mask = parent->dma_mask; pdev->dev.dma_parms = parent->dma_parms; + pdev->dev.coherent_dma_mask = parent->coherent_dma_mask; ret = regulator_bulk_register_supply_alias( &pdev->dev, cell->parent_supplies, @@ -118,6 +157,8 @@ static int mfd_add_device(struct device *parent, int id, } } + mfd_acpi_add_device(cell, pdev); + if (cell->pdata_size) { ret = platform_device_add_data(pdev, cell->platform_data, cell->pdata_size); diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index c87f7a0a53f8..43664eb69c93 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -106,10 +106,7 @@ static ssize_t show_dump_regs(struct device *dev, struct device_attribute *attr, } else dump[n1] = pcf50633_reg_read(pcf, n + n1); - hex_dump_to_buffer(dump, sizeof(dump), 16, 1, buf1, 128, 0); - buf1 += strlen(buf1); - *buf1++ = '\n'; - *buf1 = '\0'; + buf1 += sprintf(buf1, "%*ph\n", (int)sizeof(dump), dump); } return buf1 - buf; @@ -195,8 +192,9 @@ static int pcf50633_probe(struct i2c_client *client, const struct i2c_device_id *ids) { struct pcf50633 *pcf; + struct platform_device *pdev; struct pcf50633_platform_data *pdata = dev_get_platdata(&client->dev); - int i, ret; + int i, j, ret; int version, variant; if (!client->irq) { @@ -243,9 +241,6 @@ static int pcf50633_probe(struct i2c_client *client, for (i = 0; i < PCF50633_NUM_REGULATORS; i++) { - struct platform_device *pdev; - int j; - pdev = platform_device_alloc("pcf50633-regulator", i); if (!pdev) return -ENOMEM; @@ -253,25 +248,31 @@ static int pcf50633_probe(struct i2c_client *client, pdev->dev.parent = pcf->dev; ret = platform_device_add_data(pdev, &pdata->reg_init_data[i], sizeof(pdata->reg_init_data[i])); - if (ret) { - platform_device_put(pdev); - for (j = 0; j < i; j++) - platform_device_put(pcf->regulator_pdev[j]); - return ret; - } - pcf->regulator_pdev[i] = pdev; + if (ret) + goto err; + + ret = platform_device_add(pdev); + if (ret) + goto err; - platform_device_add(pdev); + pcf->regulator_pdev[i] = pdev; } ret = sysfs_create_group(&client->dev.kobj, &pcf_attr_group); if (ret) - dev_err(pcf->dev, "error creating sysfs entries\n"); + dev_warn(pcf->dev, "error creating sysfs entries\n"); if (pdata->probe_done) pdata->probe_done(pcf); return 0; + +err: + platform_device_put(pdev); + for (j = 0; j < i; j++) + platform_device_put(pcf->regulator_pdev[j]); + + return ret; } static int pcf50633_remove(struct i2c_client *client) diff --git a/drivers/mfd/qcom-spmi-pmic.c b/drivers/mfd/qcom-spmi-pmic.c new file mode 100644 index 000000000000..4b8beb2a1579 --- /dev/null +++ b/drivers/mfd/qcom-spmi-pmic.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/spmi.h> +#include <linux/regmap.h> +#include <linux/of_platform.h> + +static const struct regmap_config spmi_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .max_register = 0xffff, + .fast_io = true, +}; + +static int pmic_spmi_probe(struct spmi_device *sdev) +{ + struct device_node *root = sdev->dev.of_node; + struct regmap *regmap; + + regmap = devm_regmap_init_spmi_ext(sdev, &spmi_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return of_platform_populate(root, NULL, NULL, &sdev->dev); +} + +static void pmic_spmi_remove(struct spmi_device *sdev) +{ + of_platform_depopulate(&sdev->dev); +} + +static const struct of_device_id pmic_spmi_id_table[] = { + { .compatible = "qcom,spmi-pmic" }, + { .compatible = "qcom,pm8941" }, + { .compatible = "qcom,pm8841" }, + { .compatible = "qcom,pma8084" }, + { } +}; +MODULE_DEVICE_TABLE(of, pmic_spmi_id_table); + +static struct spmi_driver pmic_spmi_driver = { + .probe = pmic_spmi_probe, + .remove = pmic_spmi_remove, + .driver = { + .name = "pmic-spmi", + .of_match_table = pmic_spmi_id_table, + }, +}; +module_spmi_driver(pmic_spmi_driver); + +MODULE_DESCRIPTION("Qualcomm SPMI PMIC driver"); +MODULE_ALIAS("spmi:spmi-pmic"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Josh Cartwright <joshc@codeaurora.org>"); +MODULE_AUTHOR("Stanimir Varbanov <svarbanov@mm-sol.com>"); diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c new file mode 100644 index 000000000000..bd0215069875 --- /dev/null +++ b/drivers/mfd/rk808.c @@ -0,0 +1,275 @@ +/* + * MFD core driver for Rockchip RK808 + * + * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd + * + * Author: Chris Zhong <zyw@rock-chips.com> + * Author: Zhang Qing <zhangqing@rock-chips.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/mfd/rk808.h> +#include <linux/mfd/core.h> +#include <linux/module.h> +#include <linux/regmap.h> + +struct rk808_reg_data { + int addr; + int mask; + int value; +}; + +static bool rk808_is_volatile_reg(struct device *dev, unsigned int reg) +{ + /* + * Notes: + * - Technically the ROUND_30s bit makes RTC_CTRL_REG volatile, but + * we don't use that feature. It's better to cache. + * - It's unlikely we care that RK808_DEVCTRL_REG is volatile since + * bits are cleared in case when we shutoff anyway, but better safe. + */ + + switch (reg) { + case RK808_SECONDS_REG ... RK808_WEEKS_REG: + case RK808_RTC_STATUS_REG: + case RK808_VB_MON_REG: + case RK808_THERMAL_REG: + case RK808_DCDC_UV_STS_REG: + case RK808_LDO_UV_STS_REG: + case RK808_DCDC_PG_REG: + case RK808_LDO_PG_REG: + case RK808_DEVCTRL_REG: + case RK808_INT_STS_REG1: + case RK808_INT_STS_REG2: + return true; + } + + return false; +} + +static const struct regmap_config rk808_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RK808_IO_POL_REG, + .cache_type = REGCACHE_RBTREE, + .volatile_reg = rk808_is_volatile_reg, +}; + +static struct resource rtc_resources[] = { + { + .start = RK808_IRQ_RTC_ALARM, + .end = RK808_IRQ_RTC_ALARM, + .flags = IORESOURCE_IRQ, + } +}; + +static const struct mfd_cell rk808s[] = { + { .name = "rk808-clkout", }, + { .name = "rk808-regulator", }, + { + .name = "rk808-rtc", + .num_resources = ARRAY_SIZE(rtc_resources), + .resources = &rtc_resources[0], + }, +}; + +static const struct rk808_reg_data pre_init_reg[] = { + { RK808_BUCK3_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_150MA }, + { RK808_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK, BUCK_ILMIN_200MA }, + { RK808_BOOST_CONFIG_REG, BOOST_ILMIN_MASK, BOOST_ILMIN_100MA }, + { RK808_BUCK1_CONFIG_REG, BUCK1_RATE_MASK, BUCK_ILMIN_200MA }, + { RK808_BUCK2_CONFIG_REG, BUCK2_RATE_MASK, BUCK_ILMIN_200MA }, + { RK808_VB_MON_REG, MASK_ALL, VB_LO_ACT | + VB_LO_SEL_3500MV }, +}; + +static const struct regmap_irq rk808_irqs[] = { + /* INT_STS */ + [RK808_IRQ_VOUT_LO] = { + .mask = RK808_IRQ_VOUT_LO_MSK, + .reg_offset = 0, + }, + [RK808_IRQ_VB_LO] = { + .mask = RK808_IRQ_VB_LO_MSK, + .reg_offset = 0, + }, + [RK808_IRQ_PWRON] = { + .mask = RK808_IRQ_PWRON_MSK, + .reg_offset = 0, + }, + [RK808_IRQ_PWRON_LP] = { + .mask = RK808_IRQ_PWRON_LP_MSK, + .reg_offset = 0, + }, + [RK808_IRQ_HOTDIE] = { + .mask = RK808_IRQ_HOTDIE_MSK, + .reg_offset = 0, + }, + [RK808_IRQ_RTC_ALARM] = { + .mask = RK808_IRQ_RTC_ALARM_MSK, + .reg_offset = 0, + }, + [RK808_IRQ_RTC_PERIOD] = { + .mask = RK808_IRQ_RTC_PERIOD_MSK, + .reg_offset = 0, + }, + + /* INT_STS2 */ + [RK808_IRQ_PLUG_IN_INT] = { + .mask = RK808_IRQ_PLUG_IN_INT_MSK, + .reg_offset = 1, + }, + [RK808_IRQ_PLUG_OUT_INT] = { + .mask = RK808_IRQ_PLUG_OUT_INT_MSK, + .reg_offset = 1, + }, +}; + +static struct regmap_irq_chip rk808_irq_chip = { + .name = "rk808", + .irqs = rk808_irqs, + .num_irqs = ARRAY_SIZE(rk808_irqs), + .num_regs = 2, + .irq_reg_stride = 2, + .status_base = RK808_INT_STS_REG1, + .mask_base = RK808_INT_STS_MSK_REG1, + .ack_base = RK808_INT_STS_REG1, + .init_ack_masked = true, +}; + +static struct i2c_client *rk808_i2c_client; +static void rk808_device_shutdown(void) +{ + int ret; + struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client); + + if (!rk808) { + dev_warn(&rk808_i2c_client->dev, + "have no rk808, so do nothing here\n"); + return; + } + + ret = regmap_update_bits(rk808->regmap, + RK808_DEVCTRL_REG, + DEV_OFF_RST, DEV_OFF_RST); + if (ret) + dev_err(&rk808_i2c_client->dev, "power off error!\n"); +} + +static int rk808_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device_node *np = client->dev.of_node; + struct rk808 *rk808; + int pm_off = 0; + int ret; + int i; + + if (!client->irq) { + dev_err(&client->dev, "No interrupt support, no core IRQ\n"); + return -EINVAL; + } + + rk808 = devm_kzalloc(&client->dev, sizeof(*rk808), GFP_KERNEL); + if (!rk808) + return -ENOMEM; + + rk808->regmap = devm_regmap_init_i2c(client, &rk808_regmap_config); + if (IS_ERR(rk808->regmap)) { + dev_err(&client->dev, "regmap initialization failed\n"); + return PTR_ERR(rk808->regmap); + } + + for (i = 0; i < ARRAY_SIZE(pre_init_reg); i++) { + ret = regmap_update_bits(rk808->regmap, pre_init_reg[i].addr, + pre_init_reg[i].mask, + pre_init_reg[i].value); + if (ret) { + dev_err(&client->dev, + "0x%x write err\n", pre_init_reg[i].addr); + return ret; + } + } + + ret = regmap_add_irq_chip(rk808->regmap, client->irq, + IRQF_ONESHOT, -1, + &rk808_irq_chip, &rk808->irq_data); + if (ret) { + dev_err(&client->dev, "Failed to add irq_chip %d\n", ret); + return ret; + } + + rk808->i2c = client; + i2c_set_clientdata(client, rk808); + + ret = mfd_add_devices(&client->dev, -1, + rk808s, ARRAY_SIZE(rk808s), + NULL, 0, regmap_irq_get_domain(rk808->irq_data)); + if (ret) { + dev_err(&client->dev, "failed to add MFD devices %d\n", ret); + goto err_irq; + } + + pm_off = of_property_read_bool(np, + "rockchip,system-power-controller"); + if (pm_off && !pm_power_off) { + rk808_i2c_client = client; + pm_power_off = rk808_device_shutdown; + } + + return 0; + +err_irq: + regmap_del_irq_chip(client->irq, rk808->irq_data); + return ret; +} + +static int rk808_remove(struct i2c_client *client) +{ + struct rk808 *rk808 = i2c_get_clientdata(client); + + regmap_del_irq_chip(client->irq, rk808->irq_data); + mfd_remove_devices(&client->dev); + pm_power_off = NULL; + + return 0; +} + +static struct of_device_id rk808_of_match[] = { + { .compatible = "rockchip,rk808" }, + { }, +}; +MODULE_DEVICE_TABLE(of, rk808_of_match); + +static const struct i2c_device_id rk808_ids[] = { + { "rk808" }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, rk808_ids); + +static struct i2c_driver rk808_i2c_driver = { + .driver = { + .name = "rk808", + .of_match_table = rk808_of_match, + }, + .probe = rk808_probe, + .remove = rk808_remove, + .id_table = rk808_ids, +}; + +module_i2c_driver(rk808_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Chris Zhong <zyw@rock-chips.com>"); +MODULE_AUTHOR("Zhang Qing <zhangqing@rock-chips.com>"); +MODULE_DESCRIPTION("RK808 PMIC driver"); diff --git a/drivers/mfd/rn5t618.c b/drivers/mfd/rn5t618.c new file mode 100644 index 000000000000..666857192dbe --- /dev/null +++ b/drivers/mfd/rn5t618.c @@ -0,0 +1,134 @@ +/* + * MFD core driver for Ricoh RN5T618 PMIC + * + * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/i2c.h> +#include <linux/mfd/core.h> +#include <linux/mfd/rn5t618.h> +#include <linux/module.h> +#include <linux/regmap.h> + +static const struct mfd_cell rn5t618_cells[] = { + { .name = "rn5t618-regulator" }, + { .name = "rn5t618-wdt" }, +}; + +static bool rn5t618_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RN5T618_WATCHDOGCNT: + case RN5T618_DCIRQ: + case RN5T618_ILIMDATAH ... RN5T618_AIN0DATAL: + case RN5T618_IR_ADC1 ... RN5T618_IR_ADC3: + case RN5T618_IR_GPR: + case RN5T618_IR_GPF: + case RN5T618_MON_IOIN: + case RN5T618_INTMON: + return true; + default: + return false; + } +} + +static const struct regmap_config rn5t618_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .volatile_reg = rn5t618_volatile_reg, + .max_register = RN5T618_MAX_REG, + .cache_type = REGCACHE_RBTREE, +}; + +static struct rn5t618 *rn5t618_pm_power_off; + +static void rn5t618_power_off(void) +{ + /* disable automatic repower-on */ + regmap_update_bits(rn5t618_pm_power_off->regmap, RN5T618_REPCNT, + RN5T618_REPCNT_REPWRON, 0); + /* start power-off sequence */ + regmap_update_bits(rn5t618_pm_power_off->regmap, RN5T618_SLPCNT, + RN5T618_SLPCNT_SWPWROFF, RN5T618_SLPCNT_SWPWROFF); +} + +static int rn5t618_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rn5t618 *priv; + int ret; + + priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + i2c_set_clientdata(i2c, priv); + + priv->regmap = devm_regmap_init_i2c(i2c, &rn5t618_regmap_config); + if (IS_ERR(priv->regmap)) { + ret = PTR_ERR(priv->regmap); + dev_err(&i2c->dev, "regmap init failed: %d\n", ret); + return ret; + } + + ret = mfd_add_devices(&i2c->dev, -1, rn5t618_cells, + ARRAY_SIZE(rn5t618_cells), NULL, 0, NULL); + if (ret) { + dev_err(&i2c->dev, "failed to add sub-devices: %d\n", ret); + return ret; + } + + if (!pm_power_off) { + rn5t618_pm_power_off = priv; + pm_power_off = rn5t618_power_off; + } + + return 0; +} + +static int rn5t618_i2c_remove(struct i2c_client *i2c) +{ + struct rn5t618 *priv = i2c_get_clientdata(i2c); + + if (priv == rn5t618_pm_power_off) { + rn5t618_pm_power_off = NULL; + pm_power_off = NULL; + } + + mfd_remove_devices(&i2c->dev); + return 0; +} + +static const struct of_device_id rn5t618_of_match[] = { + { .compatible = "ricoh,rn5t618" }, + { } +}; +MODULE_DEVICE_TABLE(of, rn5t618_of_match); + +static const struct i2c_device_id rn5t618_i2c_id[] = { + { } +}; +MODULE_DEVICE_TABLE(i2c, rn5t618_i2c_id); + +static struct i2c_driver rn5t618_i2c_driver = { + .driver = { + .name = "rn5t618", + .of_match_table = of_match_ptr(rn5t618_of_match), + }, + .probe = rn5t618_i2c_probe, + .remove = rn5t618_i2c_remove, + .id_table = rn5t618_i2c_id, +}; + +module_i2c_driver(rn5t618_i2c_driver); + +MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>"); +MODULE_DESCRIPTION("Ricoh RN5T618 MFD driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c index d01b8c249231..f2643c221d34 100644 --- a/drivers/mfd/rtsx_pcr.c +++ b/drivers/mfd/rtsx_pcr.c @@ -1197,7 +1197,7 @@ static int rtsx_pci_probe(struct pci_dev *pcidev, pcr->msi_en = msi_en; if (pcr->msi_en) { ret = pci_enable_msi(pcidev); - if (ret < 0) + if (ret) pcr->msi_en = false; } diff --git a/drivers/mfd/rtsx_usb.c b/drivers/mfd/rtsx_usb.c index 71f387ce8cbd..9cf98d142d9a 100644 --- a/drivers/mfd/rtsx_usb.c +++ b/drivers/mfd/rtsx_usb.c @@ -684,7 +684,7 @@ static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message) struct rtsx_ucr *ucr = (struct rtsx_ucr *)usb_get_intfdata(intf); - dev_dbg(&intf->dev, "%s called with pm message 0x%04u\n", + dev_dbg(&intf->dev, "%s called with pm message 0x%04x\n", __func__, message.event); /* diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 02027b7f1223..6ce6e6200359 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -514,9 +514,9 @@ unsigned long sm501_set_clock(struct device *dev, unsigned long mode = smc501_readl(sm->regs + SM501_POWER_MODE_CONTROL); unsigned long gate = smc501_readl(sm->regs + SM501_CURRENT_GATE); unsigned long clock = smc501_readl(sm->regs + SM501_CURRENT_CLOCK); - unsigned char reg; unsigned int pll_reg = 0; unsigned long sm501_freq; /* the actual frequency achieved */ + u64 reg; struct sm501_clock to; diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 02a17c388e87..e2f9df1c0c36 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -249,7 +249,7 @@ int stmpe_set_altfunc(struct stmpe *stmpe, u32 pins, enum stmpe_block block) int af_bits = variant->af_bits; int numregs = DIV_ROUND_UP(stmpe->num_gpios * af_bits, 8); int mask = (1 << af_bits) - 1; - u8 regs[numregs]; + u8 regs[8]; int af, afperreg, ret; if (!variant->get_altfunc) @@ -854,7 +854,7 @@ static irqreturn_t stmpe_irq(int irq, void *data) struct stmpe_variant_info *variant = stmpe->variant; int num = DIV_ROUND_UP(variant->num_irqs, 8); u8 israddr; - u8 isr[num]; + u8 isr[3]; int ret; int i; @@ -1122,7 +1122,12 @@ static void stmpe_of_probe(struct stmpe_platform_data *pdata, if (pdata->id < 0) pdata->id = -1; - pdata->irq_trigger = IRQF_TRIGGER_NONE; + pdata->irq_gpio = of_get_named_gpio_flags(np, "irq-gpio", 0, + &pdata->irq_trigger); + if (gpio_is_valid(pdata->irq_gpio)) + pdata->irq_over_gpio = 1; + else + pdata->irq_trigger = IRQF_TRIGGER_NONE; of_property_read_u32(np, "st,autosleep-timeout", &pdata->autosleep_timeout); diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index dd4bf5816221..d877e777cce6 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -53,11 +53,11 @@ void am335x_tsc_se_set_cache(struct ti_tscadc_dev *tsadc, u32 val) unsigned long flags; spin_lock_irqsave(&tsadc->reg_lock, flags); - tsadc->reg_se_cache = val; + tsadc->reg_se_cache |= val; if (tsadc->adc_waiting) wake_up(&tsadc->reg_se_wait); else if (!tsadc->adc_in_use) - tscadc_writel(tsadc, REG_SE, val); + tscadc_writel(tsadc, REG_SE, tsadc->reg_se_cache); spin_unlock_irqrestore(&tsadc->reg_lock, flags); } @@ -96,6 +96,7 @@ static void am335x_tscadc_need_adc(struct ti_tscadc_dev *tsadc) void am335x_tsc_se_set_once(struct ti_tscadc_dev *tsadc, u32 val) { spin_lock_irq(&tsadc->reg_lock); + tsadc->reg_se_cache |= val; am335x_tscadc_need_adc(tsadc); tscadc_writel(tsadc, REG_SE, val); @@ -241,18 +242,20 @@ static int ti_tscadc_probe(struct platform_device *pdev) tscadc_writel(tscadc, REG_CLKDIV, tscadc->clk_div); /* Set the control register bits */ - ctrl = CNTRLREG_STEPCONFIGWRT | - CNTRLREG_STEPID; - if (tsc_wires > 0) - ctrl |= CNTRLREG_4WIRE | CNTRLREG_TSCENB; + ctrl = CNTRLREG_STEPCONFIGWRT | CNTRLREG_STEPID; tscadc_writel(tscadc, REG_CTRL, ctrl); /* Set register bits for Idle Config Mode */ - if (tsc_wires > 0) + if (tsc_wires > 0) { + tscadc->tsc_wires = tsc_wires; + if (tsc_wires == 5) + ctrl |= CNTRLREG_5WIRE | CNTRLREG_TSCENB; + else + ctrl |= CNTRLREG_4WIRE | CNTRLREG_TSCENB; tscadc_idle_config(tscadc); + } /* Enable the TSC module enable bit */ - ctrl = tscadc_readl(tscadc, REG_CTRL); ctrl |= CNTRLREG_TSCSSENB; tscadc_writel(tscadc, REG_CTRL, ctrl); @@ -324,21 +327,23 @@ static int tscadc_suspend(struct device *dev) static int tscadc_resume(struct device *dev) { struct ti_tscadc_dev *tscadc_dev = dev_get_drvdata(dev); - unsigned int restore, ctrl; + u32 ctrl; pm_runtime_get_sync(dev); /* context restore */ ctrl = CNTRLREG_STEPCONFIGWRT | CNTRLREG_STEPID; - if (tscadc_dev->tsc_cell != -1) - ctrl |= CNTRLREG_TSCENB | CNTRLREG_4WIRE; tscadc_writel(tscadc_dev, REG_CTRL, ctrl); - if (tscadc_dev->tsc_cell != -1) + if (tscadc_dev->tsc_cell != -1) { + if (tscadc_dev->tsc_wires == 5) + ctrl |= CNTRLREG_5WIRE | CNTRLREG_TSCENB; + else + ctrl |= CNTRLREG_4WIRE | CNTRLREG_TSCENB; tscadc_idle_config(tscadc_dev); - restore = tscadc_readl(tscadc_dev, REG_CTRL); - tscadc_writel(tscadc_dev, REG_CTRL, - (restore | CNTRLREG_TSCSSENB)); + } + ctrl |= CNTRLREG_TSCSSENB; + tscadc_writel(tscadc_dev, REG_CTRL, ctrl); tscadc_writel(tscadc_dev, REG_CLKDIV, tscadc_dev->clk_div); diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index 3cc4c7084b92..a8ee52c95f2f 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -146,6 +146,8 @@ EXPORT_SYMBOL_GPL(tps65217_clear_bits); static struct regmap_config tps65217_regmap_config = { .reg_bits = 8, .val_bits = 8, + + .max_register = TPS65217_REG_MAX, }; static const struct of_device_id tps65217_of_match[] = { diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index f243e75d28f3..7612d89850dd 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -486,6 +486,11 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, tps65910->i2c_client = i2c; tps65910->id = chip_id; + /* Work around silicon erratum SWCZ010: the tps65910 may miss the + * first I2C transfer. So issue a dummy transfer before the first + * real transfer. + */ + i2c_master_send(i2c, "", 1); tps65910->regmap = devm_regmap_init_i2c(i2c, &tps65910_regmap_config); if (IS_ERR(tps65910->regmap)) { ret = PTR_ERR(tps65910->regmap); diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index b1dabba763cf..1b772ef761cb 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -396,13 +396,17 @@ static int twl4030_init_sih_modules(unsigned line) status = twl_i2c_read(sih->module, rxbuf, sih->mask[line].isr_offset, sih->bytes_ixr); if (status < 0) - pr_err("twl4030: err %d initializing %s %s\n", + pr_warn("twl4030: err %d initializing %s %s\n", status, sih->name, "ISR"); - if (!sih->set_cor) + if (!sih->set_cor) { status = twl_i2c_write(sih->module, buf, sih->mask[line].isr_offset, sih->bytes_ixr); + if (status < 0) + pr_warn("twl4030: write failed: %d\n", + status); + } /* * else COR=1 means read sufficed. * (for most SIH modules...) diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index 4d3ff3771491..cf92a6d1c532 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -627,6 +627,9 @@ static bool twl4030_power_use_poweroff(const struct twl4030_power_data *pdata, if (pdata && pdata->use_poweroff) return true; + if (of_property_read_bool(node, "ti,system-power-controller")) + return true; + if (of_property_read_bool(node, "ti,use_poweroff")) return true; diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index f9c06c542a41..9687645162ae 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -679,6 +679,7 @@ static int twl6040_probe(struct i2c_client *client, if (twl6040->rev < 0) { dev_err(&client->dev, "Failed to read revision register: %d\n", twl6040->rev); + ret = twl6040->rev; goto gpio_err; } diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index fb4d4bb0f47d..d6f35bbf795b 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c @@ -87,6 +87,7 @@ int wm5102_patch(struct arizona *arizona) case 0: wm5102_patch = wm5102_reva_patch; patch_size = ARRAY_SIZE(wm5102_reva_patch); + break; default: wm5102_patch = wm5102_revb_patch; patch_size = ARRAY_SIZE(wm5102_revb_patch); @@ -245,9 +246,6 @@ const struct regmap_irq_chip wm5102_irq = { static const struct reg_default wm5102_reg_default[] = { { 0x00000008, 0x0019 }, /* R8 - Ctrl IF SPI CFG 1 */ { 0x00000009, 0x0001 }, /* R9 - Ctrl IF I2C1 CFG 1 */ - { 0x00000016, 0x0000 }, /* R22 - Write Sequencer Ctrl 0 */ - { 0x00000017, 0x0000 }, /* R23 - Write Sequencer Ctrl 1 */ - { 0x00000018, 0x0000 }, /* R24 - Write Sequencer Ctrl 2 */ { 0x00000020, 0x0000 }, /* R32 - Tone Generator 1 */ { 0x00000021, 0x1000 }, /* R33 - Tone Generator 2 */ { 0x00000022, 0x0000 }, /* R34 - Tone Generator 3 */ @@ -1016,6 +1014,7 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg) case ARIZONA_WRITE_SEQUENCER_CTRL_0: case ARIZONA_WRITE_SEQUENCER_CTRL_1: case ARIZONA_WRITE_SEQUENCER_CTRL_2: + case ARIZONA_WRITE_SEQUENCER_CTRL_3: case ARIZONA_WRITE_SEQUENCER_PROM: case ARIZONA_TONE_GENERATOR_1: case ARIZONA_TONE_GENERATOR_2: @@ -1060,6 +1059,8 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg) case ARIZONA_ASYNC_CLOCK_1: case ARIZONA_ASYNC_SAMPLE_RATE_1: case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS: + case ARIZONA_ASYNC_SAMPLE_RATE_2: + case ARIZONA_ASYNC_SAMPLE_RATE_2_STATUS: case ARIZONA_OUTPUT_SYSTEM_CLOCK: case ARIZONA_OUTPUT_ASYNC_CLOCK: case ARIZONA_RATE_ESTIMATOR_1: @@ -1880,6 +1881,10 @@ static bool wm5102_volatile_register(struct device *dev, unsigned int reg) switch (reg) { case ARIZONA_SOFTWARE_RESET: case ARIZONA_DEVICE_REVISION: + case ARIZONA_WRITE_SEQUENCER_CTRL_0: + case ARIZONA_WRITE_SEQUENCER_CTRL_1: + case ARIZONA_WRITE_SEQUENCER_CTRL_2: + case ARIZONA_WRITE_SEQUENCER_CTRL_3: case ARIZONA_OUTPUT_STATUS_1: case ARIZONA_RAW_OUTPUT_STATUS_1: case ARIZONA_SLIMBUS_RX_PORT_STATUS: @@ -1889,8 +1894,13 @@ static bool wm5102_volatile_register(struct device *dev, unsigned int reg) case ARIZONA_SAMPLE_RATE_3_STATUS: case ARIZONA_HAPTICS_STATUS: case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS: + case ARIZONA_ASYNC_SAMPLE_RATE_2_STATUS: case ARIZONA_FLL1_NCO_TEST_0: case ARIZONA_FLL2_NCO_TEST_0: + case ARIZONA_DAC_COMP_1: + case ARIZONA_DAC_COMP_2: + case ARIZONA_DAC_COMP_3: + case ARIZONA_DAC_COMP_4: case ARIZONA_FX_CTRL2: case ARIZONA_INTERRUPT_STATUS_1: case ARIZONA_INTERRUPT_STATUS_2: diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 9b98ee559188..4642b5b816a0 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -666,9 +666,6 @@ static const struct reg_default wm5110_reg_default[] = { { 0x0000000A, 0x0001 }, /* R10 - Ctrl IF I2C2 CFG 1 */ { 0x0000000B, 0x0036 }, /* R11 - Ctrl IF I2C1 CFG 2 */ { 0x0000000C, 0x0036 }, /* R12 - Ctrl IF I2C2 CFG 2 */ - { 0x00000016, 0x0000 }, /* R22 - Write Sequencer Ctrl 0 */ - { 0x00000017, 0x0000 }, /* R23 - Write Sequencer Ctrl 1 */ - { 0x00000018, 0x0000 }, /* R24 - Write Sequencer Ctrl 2 */ { 0x00000020, 0x0000 }, /* R32 - Tone Generator 1 */ { 0x00000021, 0x1000 }, /* R33 - Tone Generator 2 */ { 0x00000022, 0x0000 }, /* R34 - Tone Generator 3 */ @@ -705,6 +702,7 @@ static const struct reg_default wm5110_reg_default[] = { { 0x00000104, 0x0011 }, /* R260 - Sample rate 3 */ { 0x00000112, 0x0305 }, /* R274 - Async clock 1 */ { 0x00000113, 0x0011 }, /* R275 - Async sample rate 1 */ + { 0x00000114, 0x0011 }, /* R276 - Async sample rate 2 */ { 0x00000149, 0x0000 }, /* R329 - Output system clock */ { 0x0000014A, 0x0000 }, /* R330 - Output async clock */ { 0x00000152, 0x0000 }, /* R338 - Rate Estimator 1 */ @@ -1741,6 +1739,8 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_ASYNC_CLOCK_1: case ARIZONA_ASYNC_SAMPLE_RATE_1: case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS: + case ARIZONA_ASYNC_SAMPLE_RATE_2: + case ARIZONA_ASYNC_SAMPLE_RATE_2_STATUS: case ARIZONA_OUTPUT_SYSTEM_CLOCK: case ARIZONA_OUTPUT_ASYNC_CLOCK: case ARIZONA_RATE_ESTIMATOR_1: @@ -2815,11 +2815,15 @@ static bool wm5110_volatile_register(struct device *dev, unsigned int reg) switch (reg) { case ARIZONA_SOFTWARE_RESET: case ARIZONA_DEVICE_REVISION: + case ARIZONA_WRITE_SEQUENCER_CTRL_0: + case ARIZONA_WRITE_SEQUENCER_CTRL_1: + case ARIZONA_WRITE_SEQUENCER_CTRL_2: case ARIZONA_HAPTICS_STATUS: case ARIZONA_SAMPLE_RATE_1_STATUS: case ARIZONA_SAMPLE_RATE_2_STATUS: case ARIZONA_SAMPLE_RATE_3_STATUS: case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS: + case ARIZONA_ASYNC_SAMPLE_RATE_2_STATUS: case ARIZONA_MIC_DETECT_3: case ARIZONA_HEADPHONE_DETECT_2: case ARIZONA_INPUT_ENABLES_STATUS: diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c index e74dedda5b55..a14407edbd89 100644 --- a/drivers/mfd/wm8994-irq.c +++ b/drivers/mfd/wm8994-irq.c @@ -262,8 +262,10 @@ int wm8994_irq_init(struct wm8994 *wm8994) return 0; } +EXPORT_SYMBOL(wm8994_irq_init); void wm8994_irq_exit(struct wm8994 *wm8994) { regmap_del_irq_chip(wm8994->irq, wm8994->irq_data); } +EXPORT_SYMBOL(wm8994_irq_exit); diff --git a/drivers/mfd/wm8994-regmap.c b/drivers/mfd/wm8994-regmap.c index 770a25696468..300e9b6a2e96 100644 --- a/drivers/mfd/wm8994-regmap.c +++ b/drivers/mfd/wm8994-regmap.c @@ -1252,6 +1252,7 @@ struct regmap_config wm1811_regmap_config = { .volatile_reg = wm1811_volatile_register, .readable_reg = wm1811_readable_register, }; +EXPORT_SYMBOL(wm1811_regmap_config); struct regmap_config wm8994_regmap_config = { .reg_bits = 16, @@ -1266,6 +1267,7 @@ struct regmap_config wm8994_regmap_config = { .volatile_reg = wm8994_volatile_register, .readable_reg = wm8994_readable_register, }; +EXPORT_SYMBOL(wm8994_regmap_config); struct regmap_config wm8958_regmap_config = { .reg_bits = 16, @@ -1280,8 +1282,10 @@ struct regmap_config wm8958_regmap_config = { .volatile_reg = wm8958_volatile_register, .readable_reg = wm8958_readable_register, }; +EXPORT_SYMBOL(wm8958_regmap_config); struct regmap_config wm8994_base_regmap_config = { .reg_bits = 16, .val_bits = 16, }; +EXPORT_SYMBOL(wm8994_base_regmap_config); |