summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/busses/i2c-cros-ec-tunnel.c5
-rw-r--r--drivers/input/keyboard/cros_ec_keyb.c2
-rw-r--r--drivers/mfd/88pm860x-i2c.c66
-rw-r--r--drivers/mfd/Kconfig56
-rw-r--r--drivers/mfd/Makefile4
-rw-r--r--drivers/mfd/arizona-core.c29
-rw-r--r--drivers/mfd/arizona-irq.c14
-rw-r--r--drivers/mfd/axp20x.c11
-rw-r--r--drivers/mfd/cros_ec.c48
-rw-r--r--drivers/mfd/cros_ec_spi.c20
-rw-r--r--drivers/mfd/da9052-core.c2
-rw-r--r--drivers/mfd/da9052-i2c.c7
-rw-r--r--drivers/mfd/da9052-spi.c7
-rw-r--r--drivers/mfd/hi6421-pmic-core.c113
-rw-r--r--drivers/mfd/htc-i2cpld.c44
-rw-r--r--drivers/mfd/intel_soc_pmic_core.c2
-rw-r--r--drivers/mfd/lpc_ich.c17
-rw-r--r--drivers/mfd/lpc_sch.c211
-rw-r--r--drivers/mfd/max14577.c3
-rw-r--r--drivers/mfd/max77686.c2
-rw-r--r--drivers/mfd/max77693.c5
-rw-r--r--drivers/mfd/max8925-i2c.c2
-rw-r--r--drivers/mfd/mc13xxx-core.c8
-rw-r--r--drivers/mfd/menelaus.c11
-rw-r--r--drivers/mfd/mfd-core.c41
-rw-r--r--drivers/mfd/pcf50633-core.c35
-rw-r--r--drivers/mfd/qcom-spmi-pmic.c67
-rw-r--r--drivers/mfd/rk808.c275
-rw-r--r--drivers/mfd/rn5t618.c134
-rw-r--r--drivers/mfd/rtsx_pcr.c2
-rw-r--r--drivers/mfd/rtsx_usb.c2
-rw-r--r--drivers/mfd/sm501.c2
-rw-r--r--drivers/mfd/stmpe.c11
-rw-r--r--drivers/mfd/ti_am335x_tscadc.c35
-rw-r--r--drivers/mfd/tps65217.c2
-rw-r--r--drivers/mfd/tps65910.c5
-rw-r--r--drivers/mfd/twl4030-irq.c8
-rw-r--r--drivers/mfd/twl4030-power.c3
-rw-r--r--drivers/mfd/twl6040.c1
-rw-r--r--drivers/mfd/wm5102-tables.c16
-rw-r--r--drivers/mfd/wm5110-tables.c10
-rw-r--r--drivers/mfd/wm8994-irq.c2
-rw-r--r--drivers/mfd/wm8994-regmap.c4
43 files changed, 1052 insertions, 292 deletions
diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c
index 05e033c98115..8ca5cbbcec91 100644
--- a/drivers/i2c/busses/i2c-cros-ec-tunnel.c
+++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c
@@ -16,6 +16,8 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
+#define I2C_MAX_RETRIES 3
+
/**
* struct ec_i2c_device - Driver data for I2C tunnel
*
@@ -227,7 +229,7 @@ static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[],
msg.indata = response;
msg.insize = response_len;
- result = bus->ec->cmd_xfer(bus->ec, &msg);
+ result = cros_ec_cmd_xfer(bus->ec, &msg);
if (result < 0)
goto exit;
@@ -290,6 +292,7 @@ static int ec_i2c_probe(struct platform_device *pdev)
bus->adap.algo_data = bus;
bus->adap.dev.parent = &pdev->dev;
bus->adap.dev.of_node = np;
+ bus->adap.retries = I2C_MAX_RETRIES;
err = i2c_add_adapter(&bus->adap);
if (err) {
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c
index 72d3499bb029..5d773d20230a 100644
--- a/drivers/input/keyboard/cros_ec_keyb.c
+++ b/drivers/input/keyboard/cros_ec_keyb.c
@@ -157,7 +157,7 @@ static int cros_ec_keyb_get_state(struct cros_ec_keyb *ckdev, uint8_t *kb_state)
.insize = ckdev->cols,
};
- return ckdev->ec->cmd_xfer(ckdev->ec, &msg);
+ return cros_ec_cmd_xfer(ckdev->ec, &msg);
}
static irqreturn_t cros_ec_keyb_irq(int irq, void *data)
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);