summaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/88pm860x-i2c.c241
-rw-r--r--drivers/mfd/Kconfig64
-rw-r--r--drivers/mfd/Makefile10
-rw-r--r--drivers/mfd/aat2870-core.c25
-rw-r--r--drivers/mfd/ab5500-core.c3
-rw-r--r--drivers/mfd/ab5500-debugfs.c3
-rw-r--r--drivers/mfd/ab8500-core.c4
-rw-r--r--drivers/mfd/ab8500-debugfs.c2
-rw-r--r--drivers/mfd/ab8500-gpadc.c4
-rw-r--r--drivers/mfd/ab8500-i2c.c2
-rw-r--r--drivers/mfd/ab8500-sysctrl.c4
-rw-r--r--drivers/mfd/adp5520.c2
-rw-r--r--drivers/mfd/cs5535-mfd.c8
-rw-r--r--drivers/mfd/da903x.c3
-rw-r--r--drivers/mfd/da9052-core.c694
-rw-r--r--drivers/mfd/da9052-i2c.c140
-rw-r--r--drivers/mfd/da9052-spi.c115
-rw-r--r--drivers/mfd/db8500-prcmu.c7
-rw-r--r--drivers/mfd/dm355evm_msp.c3
-rw-r--r--drivers/mfd/intel_msic.c12
-rw-r--r--drivers/mfd/jz4740-adc.c15
-rw-r--r--drivers/mfd/lpc_sch.c2
-rw-r--r--drivers/mfd/max8925-core.c15
-rw-r--r--drivers/mfd/max8925-i2c.c27
-rw-r--r--drivers/mfd/max8997.c3
-rw-r--r--drivers/mfd/max8998.c6
-rw-r--r--drivers/mfd/mc13xxx-core.c111
-rw-r--r--drivers/mfd/mcp-core.c44
-rw-r--r--drivers/mfd/mcp-sa11x0.c182
-rw-r--r--drivers/mfd/omap-usb-host.c763
-rw-r--r--drivers/mfd/pcf50633-adc.c12
-rw-r--r--drivers/mfd/s5m-core.c176
-rw-r--r--drivers/mfd/s5m-irq.c487
-rw-r--r--drivers/mfd/sm501.c2
-rw-r--r--drivers/mfd/stmpe-i2c.c109
-rw-r--r--drivers/mfd/stmpe-spi.c150
-rw-r--r--drivers/mfd/stmpe.c277
-rw-r--r--drivers/mfd/stmpe.h53
-rw-r--r--drivers/mfd/t7l66xb.c16
-rw-r--r--drivers/mfd/tc6387xb.c14
-rw-r--r--drivers/mfd/ti-ssp.c12
-rw-r--r--drivers/mfd/timberdale.c2
-rw-r--r--drivers/mfd/tps6586x.c2
-rw-r--r--drivers/mfd/tps65910-irq.c3
-rw-r--r--drivers/mfd/tps65910.c9
-rw-r--r--drivers/mfd/tps65912-spi.c1
-rw-r--r--drivers/mfd/twl-core.c67
-rw-r--r--drivers/mfd/twl4030-audio.c12
-rw-r--r--drivers/mfd/twl4030-irq.c21
-rw-r--r--drivers/mfd/twl4030-madc.c14
-rw-r--r--drivers/mfd/twl4030-power.c42
-rw-r--r--drivers/mfd/twl6030-irq.c2
-rw-r--r--drivers/mfd/twl6040-core.c20
-rw-r--r--drivers/mfd/ucb1x00-core.c48
-rw-r--r--drivers/mfd/ucb1x00-ts.c2
-rw-r--r--drivers/mfd/vx855.c2
-rw-r--r--drivers/mfd/wm831x-core.c4
-rw-r--r--drivers/mfd/wm831x-i2c.c3
-rw-r--r--drivers/mfd/wm831x-irq.c8
-rw-r--r--drivers/mfd/wm831x-spi.c4
-rw-r--r--drivers/mfd/wm8350-core.c2
-rw-r--r--drivers/mfd/wm8350-i2c.c4
-rw-r--r--drivers/mfd/wm8400-core.c7
-rw-r--r--drivers/mfd/wm8994-core.c159
-rw-r--r--drivers/mfd/wm8994-irq.c206
-rw-r--r--drivers/mfd/wm8994-regmap.c1238
-rw-r--r--drivers/mfd/wm8994.h25
67 files changed, 4474 insertions, 1255 deletions
diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c
index e017dc88622..f93dd9571c3 100644
--- a/drivers/mfd/88pm860x-i2c.c
+++ b/drivers/mfd/88pm860x-i2c.c
@@ -12,51 +12,20 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/regmap.h>
#include <linux/mfd/88pm860x.h>
#include <linux/slab.h>
-static inline int pm860x_read_device(struct i2c_client *i2c,
- int reg, int bytes, void *dest)
-{
- unsigned char data;
- int ret;
-
- data = (unsigned char)reg;
- ret = i2c_master_send(i2c, &data, 1);
- if (ret < 0)
- return ret;
-
- ret = i2c_master_recv(i2c, dest, bytes);
- if (ret < 0)
- return ret;
- return 0;
-}
-
-static inline int pm860x_write_device(struct i2c_client *i2c,
- int reg, int bytes, void *src)
-{
- unsigned char buf[bytes + 1];
- int ret;
-
- buf[0] = (unsigned char)reg;
- memcpy(&buf[1], src, bytes);
-
- ret = i2c_master_send(i2c, buf, bytes + 1);
- if (ret < 0)
- return ret;
- return 0;
-}
-
int pm860x_reg_read(struct i2c_client *i2c, int reg)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
- unsigned char data;
+ struct regmap *map = (i2c == chip->client) ? chip->regmap
+ : chip->regmap_companion;
+ unsigned int data;
int ret;
- mutex_lock(&chip->io_lock);
- ret = pm860x_read_device(i2c, reg, 1, &data);
- mutex_unlock(&chip->io_lock);
-
+ ret = regmap_read(map, reg, &data);
if (ret < 0)
return ret;
else
@@ -68,12 +37,11 @@ int pm860x_reg_write(struct i2c_client *i2c, int reg,
unsigned char data)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+ struct regmap *map = (i2c == chip->client) ? chip->regmap
+ : chip->regmap_companion;
int ret;
- mutex_lock(&chip->io_lock);
- ret = pm860x_write_device(i2c, reg, 1, &data);
- mutex_unlock(&chip->io_lock);
-
+ ret = regmap_write(map, reg, data);
return ret;
}
EXPORT_SYMBOL(pm860x_reg_write);
@@ -82,12 +50,11 @@ int pm860x_bulk_read(struct i2c_client *i2c, int reg,
int count, unsigned char *buf)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+ struct regmap *map = (i2c == chip->client) ? chip->regmap
+ : chip->regmap_companion;
int ret;
- mutex_lock(&chip->io_lock);
- ret = pm860x_read_device(i2c, reg, count, buf);
- mutex_unlock(&chip->io_lock);
-
+ ret = regmap_raw_read(map, reg, buf, count);
return ret;
}
EXPORT_SYMBOL(pm860x_bulk_read);
@@ -96,12 +63,11 @@ int pm860x_bulk_write(struct i2c_client *i2c, int reg,
int count, unsigned char *buf)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+ struct regmap *map = (i2c == chip->client) ? chip->regmap
+ : chip->regmap_companion;
int ret;
- mutex_lock(&chip->io_lock);
- ret = pm860x_write_device(i2c, reg, count, buf);
- mutex_unlock(&chip->io_lock);
-
+ ret = regmap_raw_write(map, reg, buf, count);
return ret;
}
EXPORT_SYMBOL(pm860x_bulk_write);
@@ -110,39 +76,78 @@ int pm860x_set_bits(struct i2c_client *i2c, int reg,
unsigned char mask, unsigned char data)
{
struct pm860x_chip *chip = i2c_get_clientdata(i2c);
- unsigned char value;
+ struct regmap *map = (i2c == chip->client) ? chip->regmap
+ : chip->regmap_companion;
int ret;
- mutex_lock(&chip->io_lock);
- ret = pm860x_read_device(i2c, reg, 1, &value);
- if (ret < 0)
- goto out;
- value &= ~mask;
- value |= data;
- ret = pm860x_write_device(i2c, reg, 1, &value);
-out:
- mutex_unlock(&chip->io_lock);
+ ret = regmap_update_bits(map, reg, mask, data);
return ret;
}
EXPORT_SYMBOL(pm860x_set_bits);
+static int read_device(struct i2c_client *i2c, int reg,
+ int bytes, void *dest)
+{
+ unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX + 3];
+ unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX + 2];
+ struct i2c_adapter *adap = i2c->adapter;
+ struct i2c_msg msg[2] = {{i2c->addr, 0, 1, msgbuf0},
+ {i2c->addr, I2C_M_RD, 0, msgbuf1},
+ };
+ int num = 1, ret = 0;
+
+ if (dest == NULL)
+ return -EINVAL;
+ msgbuf0[0] = (unsigned char)reg; /* command */
+ msg[1].len = bytes;
+
+ /* if data needs to read back, num should be 2 */
+ if (bytes > 0)
+ num = 2;
+ ret = adap->algo->master_xfer(adap, msg, num);
+ memcpy(dest, msgbuf1, bytes);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int write_device(struct i2c_client *i2c, int reg,
+ int bytes, void *src)
+{
+ unsigned char buf[bytes + 1];
+ struct i2c_adapter *adap = i2c->adapter;
+ struct i2c_msg msg;
+ int ret;
+
+ buf[0] = (unsigned char)reg;
+ memcpy(&buf[1], src, bytes);
+ msg.addr = i2c->addr;
+ msg.flags = 0;
+ msg.len = bytes + 1;
+ msg.buf = buf;
+
+ ret = adap->algo->master_xfer(adap, &msg, 1);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
int pm860x_page_reg_read(struct i2c_client *i2c, int reg)
{
- struct pm860x_chip *chip = i2c_get_clientdata(i2c);
unsigned char zero = 0;
unsigned char data;
int ret;
- mutex_lock(&chip->io_lock);
- pm860x_write_device(i2c, 0xFA, 0, &zero);
- pm860x_write_device(i2c, 0xFB, 0, &zero);
- pm860x_write_device(i2c, 0xFF, 0, &zero);
- ret = pm860x_read_device(i2c, reg, 1, &data);
+ 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;
- pm860x_write_device(i2c, 0xFE, 0, &zero);
- pm860x_write_device(i2c, 0xFC, 0, &zero);
- mutex_unlock(&chip->io_lock);
+ 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);
@@ -150,18 +155,17 @@ EXPORT_SYMBOL(pm860x_page_reg_read);
int pm860x_page_reg_write(struct i2c_client *i2c, int reg,
unsigned char data)
{
- struct pm860x_chip *chip = i2c_get_clientdata(i2c);
unsigned char zero;
int ret;
- mutex_lock(&chip->io_lock);
- pm860x_write_device(i2c, 0xFA, 0, &zero);
- pm860x_write_device(i2c, 0xFB, 0, &zero);
- pm860x_write_device(i2c, 0xFF, 0, &zero);
- ret = pm860x_write_device(i2c, reg, 1, &data);
- pm860x_write_device(i2c, 0xFE, 0, &zero);
- pm860x_write_device(i2c, 0xFC, 0, &zero);
- mutex_unlock(&chip->io_lock);
+ 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, 1, &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_write);
@@ -169,18 +173,17 @@ EXPORT_SYMBOL(pm860x_page_reg_write);
int pm860x_page_bulk_read(struct i2c_client *i2c, int reg,
int count, unsigned char *buf)
{
- struct pm860x_chip *chip = i2c_get_clientdata(i2c);
unsigned char zero = 0;
int ret;
- mutex_lock(&chip->io_lock);
- pm860x_write_device(i2c, 0xFA, 0, &zero);
- pm860x_write_device(i2c, 0xFB, 0, &zero);
- pm860x_write_device(i2c, 0xFF, 0, &zero);
- ret = pm860x_read_device(i2c, reg, count, buf);
- pm860x_write_device(i2c, 0xFE, 0, &zero);
- pm860x_write_device(i2c, 0xFC, 0, &zero);
- mutex_unlock(&chip->io_lock);
+ 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, count, buf);
+ read_device(i2c, 0xFE, 0, &zero);
+ read_device(i2c, 0xFC, 0, &zero);
+ i2c_unlock_adapter(i2c->adapter);
return ret;
}
EXPORT_SYMBOL(pm860x_page_bulk_read);
@@ -188,18 +191,18 @@ EXPORT_SYMBOL(pm860x_page_bulk_read);
int pm860x_page_bulk_write(struct i2c_client *i2c, int reg,
int count, unsigned char *buf)
{
- struct pm860x_chip *chip = i2c_get_clientdata(i2c);
unsigned char zero = 0;
int ret;
- mutex_lock(&chip->io_lock);
- pm860x_write_device(i2c, 0xFA, 0, &zero);
- pm860x_write_device(i2c, 0xFB, 0, &zero);
- pm860x_write_device(i2c, 0xFF, 0, &zero);
- ret = pm860x_write_device(i2c, reg, count, buf);
- pm860x_write_device(i2c, 0xFE, 0, &zero);
- pm860x_write_device(i2c, 0xFC, 0, &zero);
- mutex_unlock(&chip->io_lock);
+ 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);
@@ -207,25 +210,24 @@ EXPORT_SYMBOL(pm860x_page_bulk_write);
int pm860x_page_set_bits(struct i2c_client *i2c, int reg,
unsigned char mask, unsigned char data)
{
- struct pm860x_chip *chip = i2c_get_clientdata(i2c);
unsigned char zero;
unsigned char value;
int ret;
- mutex_lock(&chip->io_lock);
- pm860x_write_device(i2c, 0xFA, 0, &zero);
- pm860x_write_device(i2c, 0xFB, 0, &zero);
- pm860x_write_device(i2c, 0xFF, 0, &zero);
- ret = pm860x_read_device(i2c, reg, 1, &value);
+ 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 = pm860x_write_device(i2c, reg, 1, &value);
+ ret = write_device(i2c, reg, 1, &value);
out:
- pm860x_write_device(i2c, 0xFE, 0, &zero);
- pm860x_write_device(i2c, 0xFC, 0, &zero);
- mutex_unlock(&chip->io_lock);
+ 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);
@@ -257,11 +259,17 @@ static int verify_addr(struct i2c_client *i2c)
return 0;
}
+static struct regmap_config pm860x_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
static int __devinit pm860x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pm860x_platform_data *pdata = client->dev.platform_data;
struct pm860x_chip *chip;
+ int ret;
if (!pdata) {
pr_info("No platform data in %s!\n", __func__);
@@ -273,10 +281,17 @@ static int __devinit pm860x_probe(struct i2c_client *client,
return -ENOMEM;
chip->id = verify_addr(client);
+ chip->regmap = regmap_init_i2c(client, &pm860x_regmap_config);
+ if (IS_ERR(chip->regmap)) {
+ ret = PTR_ERR(chip->regmap);
+ dev_err(&client->dev, "Failed to allocate register map: %d\n",
+ ret);
+ kfree(chip);
+ return ret;
+ }
chip->client = client;
i2c_set_clientdata(client, chip);
chip->dev = &client->dev;
- mutex_init(&chip->io_lock);
dev_set_drvdata(chip->dev, chip);
/*
@@ -290,6 +305,14 @@ static int __devinit pm860x_probe(struct i2c_client *client,
chip->companion_addr = pdata->companion_addr;
chip->companion = i2c_new_dummy(chip->client->adapter,
chip->companion_addr);
+ chip->regmap_companion = regmap_init_i2c(chip->companion,
+ &pm860x_regmap_config);
+ if (IS_ERR(chip->regmap_companion)) {
+ ret = PTR_ERR(chip->regmap_companion);
+ dev_err(&chip->companion->dev,
+ "Failed to allocate register map: %d\n", ret);
+ return ret;
+ }
i2c_set_clientdata(chip->companion, chip);
}
@@ -302,7 +325,11 @@ static int __devexit pm860x_remove(struct i2c_client *client)
struct pm860x_chip *chip = i2c_get_clientdata(client);
pm860x_device_exit(chip);
- i2c_unregister_device(chip->companion);
+ if (chip->companion) {
+ regmap_exit(chip->regmap_companion);
+ i2c_unregister_device(chip->companion);
+ }
+ regmap_exit(chip->regmap);
kfree(chip);
return 0;
}
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index f1391c21ef2..cd13e9f2f5e 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -12,6 +12,7 @@ config MFD_CORE
config MFD_88PM860X
bool "Support Marvell 88PM8606/88PM8607"
depends on I2C=y && GENERIC_HARDIRQS
+ select REGMAP_I2C
select MFD_CORE
help
This supports for Marvell 88PM8606/88PM8607 Power Management IC.
@@ -199,7 +200,7 @@ config MENELAUS
config TWL4030_CORE
bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support"
- depends on I2C=y && GENERIC_HARDIRQS
+ depends on I2C=y && GENERIC_HARDIRQS && IRQ_DOMAIN
help
Say yes here if you have TWL4030 / TWL6030 family chip on your board.
This core driver provides register access and IRQ handling
@@ -257,7 +258,7 @@ config TWL6040_CORE
config MFD_STMPE
bool "Support STMicroelectronics STMPE"
- depends on I2C=y && GENERIC_HARDIRQS
+ depends on (I2C=y || SPI_MASTER=y) && GENERIC_HARDIRQS
select MFD_CORE
help
Support for the STMPE family of I/O Expanders from
@@ -278,6 +279,23 @@ config MFD_STMPE
Keypad: stmpe-keypad
Touchscreen: stmpe-ts
+menu "STMPE Interface Drivers"
+depends on MFD_STMPE
+
+config STMPE_I2C
+ bool "STMPE I2C Inteface"
+ depends on I2C=y
+ default y
+ help
+ This is used to enable I2C interface of STMPE
+
+config STMPE_SPI
+ bool "STMPE SPI Inteface"
+ depends on SPI_MASTER
+ help
+ This is used to enable SPI interface of STMPE
+endmenu
+
config MFD_TC3589X
bool "Support Toshiba TC35892 and variants"
depends on I2C=y && GENERIC_HARDIRQS
@@ -311,7 +329,7 @@ config MFD_TC6387XB
config MFD_TC6393XB
bool "Support Toshiba TC6393XB"
- depends on GPIOLIB && ARM
+ depends on GPIOLIB && ARM && HAVE_CLK
select MFD_CORE
select MFD_TMIO
help
@@ -328,6 +346,34 @@ config PMIC_DA903X
individual components like LCD backlight, voltage regulators,
LEDs and battery-charger under the corresponding menus.
+config PMIC_DA9052
+ bool
+ select MFD_CORE
+
+config MFD_DA9052_SPI
+ bool "Support Dialog Semiconductor DA9052/53 PMIC variants with SPI"
+ select REGMAP_SPI
+ select REGMAP_IRQ
+ select PMIC_DA9052
+ depends on SPI_MASTER=y
+ help
+ Support for the Dialog Semiconductor DA9052 PMIC
+ when controlled using SPI. 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_DA9052_I2C
+ bool "Support Dialog Semiconductor DA9052/53 PMIC variants with I2C"
+ select REGMAP_I2C
+ select REGMAP_IRQ
+ select PMIC_DA9052
+ depends on I2C=y
+ help
+ Support for the Dialog Semiconductor DA9052 PMIC
+ when controlled using I2C. This driver provides common support
+ for accessing the device, additional drivers must be enabled in
+ order to use the functionality of the device.
+
config PMIC_ADP5520
bool "Analog Devices ADP5520/01 MFD PMIC Core Support"
depends on I2C=y
@@ -371,6 +417,17 @@ config MFD_MAX8998
additional drivers must be enabled in order to use the functionality
of the device.
+config MFD_S5M_CORE
+ bool "SAMSUNG S5M Series Support"
+ depends on I2C=y && GENERIC_HARDIRQS
+ select MFD_CORE
+ select REGMAP_I2C
+ help
+ Support for the Samsung Electronics S5M MFD series.
+ This driver provies common support for accessing the device,
+ additional drivers must be enabled in order to use the functionality
+ of the device
+
config MFD_WM8400
tristate "Support Wolfson Microelectronics WM8400"
select MFD_CORE
@@ -477,6 +534,7 @@ config MFD_WM8994
bool "Support Wolfson Microelectronics WM8994"
select MFD_CORE
select REGMAP_I2C
+ select REGMAP_IRQ
depends on I2C=y && GENERIC_HARDIRQS
help
The WM8994 is a highly integrated hi-fi CODEC designed for
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index b2292eb7524..b953bab934f 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -16,6 +16,8 @@ obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
obj-$(CONFIG_MFD_TI_SSP) += ti-ssp.o
obj-$(CONFIG_MFD_STMPE) += stmpe.o
+obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o
+obj-$(CONFIG_STMPE_SPI) += stmpe-spi.o
obj-$(CONFIG_MFD_TC3589X) += tc3589x.o
obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o
obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o
@@ -31,7 +33,7 @@ wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o
wm8350-objs += wm8350-irq.o
obj-$(CONFIG_MFD_WM8350) += wm8350.o
obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o
-obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o
+obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o wm8994-regmap.o
obj-$(CONFIG_TPS6105X) += tps6105x.o
obj-$(CONFIG_TPS65010) += tps65010.o
@@ -67,6 +69,11 @@ endif
obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o
obj-$(CONFIG_PMIC_DA903X) += da903x.o
+
+obj-$(CONFIG_PMIC_DA9052) += da9052-core.o
+obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o
+obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o
+
max8925-objs := max8925-core.o max8925-i2c.o
obj-$(CONFIG_MFD_MAX8925) += max8925.o
obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o
@@ -104,3 +111,4 @@ obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o
+obj-$(CONFIG_MFD_S5M_CORE) += s5m-core.o s5m-irq.o
diff --git a/drivers/mfd/aat2870-core.c b/drivers/mfd/aat2870-core.c
index 02c42015ba5..3aa36eb5c79 100644
--- a/drivers/mfd/aat2870-core.c
+++ b/drivers/mfd/aat2870-core.c
@@ -407,13 +407,13 @@ static int aat2870_i2c_probe(struct i2c_client *client,
aat2870->init(aat2870);
if (aat2870->en_pin >= 0) {
- ret = gpio_request(aat2870->en_pin, "aat2870-en");
+ ret = gpio_request_one(aat2870->en_pin, GPIOF_OUT_INIT_HIGH,
+ "aat2870-en");
if (ret < 0) {
dev_err(&client->dev,
"Failed to request GPIO %d\n", aat2870->en_pin);
goto out_kfree;
}
- gpio_direction_output(aat2870->en_pin, 1);
}
aat2870_enable(aat2870);
@@ -468,9 +468,10 @@ static int aat2870_i2c_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
-static int aat2870_i2c_suspend(struct i2c_client *client, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int aat2870_i2c_suspend(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct aat2870_data *aat2870 = i2c_get_clientdata(client);
aat2870_disable(aat2870);
@@ -478,8 +479,9 @@ static int aat2870_i2c_suspend(struct i2c_client *client, pm_message_t state)
return 0;
}
-static int aat2870_i2c_resume(struct i2c_client *client)
+static int aat2870_i2c_resume(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
struct aat2870_data *aat2870 = i2c_get_clientdata(client);
struct aat2870_register *reg = NULL;
int i;
@@ -495,12 +497,12 @@ static int aat2870_i2c_resume(struct i2c_client *client)
return 0;
}
-#else
-#define aat2870_i2c_suspend NULL
-#define aat2870_i2c_resume NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(aat2870_pm_ops, aat2870_i2c_suspend,
+ aat2870_i2c_resume);
-static struct i2c_device_id aat2870_i2c_id_table[] = {
+static const struct i2c_device_id aat2870_i2c_id_table[] = {
{ "aat2870", 0 },
{ }
};
@@ -510,11 +512,10 @@ static struct i2c_driver aat2870_i2c_driver = {
.driver = {
.name = "aat2870",
.owner = THIS_MODULE,
+ .pm = &aat2870_pm_ops,
},
.probe = aat2870_i2c_probe,
.remove = aat2870_i2c_remove,
- .suspend = aat2870_i2c_suspend,
- .resume = aat2870_i2c_resume,
.id_table = aat2870_i2c_id_table,
};
diff --git a/drivers/mfd/ab5500-core.c b/drivers/mfd/ab5500-core.c
index 4175544b491..bd56a764dea 100644
--- a/drivers/mfd/ab5500-core.c
+++ b/drivers/mfd/ab5500-core.c
@@ -13,6 +13,7 @@
* TODO: Event handling with irq_chip. Waiting for PRCMU fw support.
*/
+#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/err.h>
#include <linux/platform_device.h>
@@ -21,8 +22,8 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/random.h>
-#include <linux/mfd/ab5500/ab5500.h>
#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab5500.h>
#include <linux/list.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>
diff --git a/drivers/mfd/ab5500-debugfs.c b/drivers/mfd/ab5500-debugfs.c
index 6be1fe6b5f9..72006940937 100644
--- a/drivers/mfd/ab5500-debugfs.c
+++ b/drivers/mfd/ab5500-debugfs.c
@@ -4,10 +4,11 @@
* Debugfs support for the AB5500 MFD driver
*/
+#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
-#include <linux/mfd/ab5500/ab5500.h>
#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab5500.h>
#include <linux/uaccess.h>
#include "ab5500-core.h"
diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c
index 1e9173804ed..53e2a80f42f 100644
--- a/drivers/mfd/ab8500-core.c
+++ b/drivers/mfd/ab8500-core.c
@@ -17,7 +17,7 @@
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/abx500.h>
-#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500/ab8500.h>
#include <linux/regulator/ab8500.h>
/*
@@ -620,6 +620,7 @@ static struct resource __devinitdata ab8500_fg_resources[] = {
static struct resource __devinitdata ab8500_chargalg_resources[] = {};
+#ifdef CONFIG_DEBUG_FS
static struct resource __devinitdata ab8500_debug_resources[] = {
{
.name = "IRQ_FIRST",
@@ -634,6 +635,7 @@ static struct resource __devinitdata ab8500_debug_resources[] = {
.flags = IORESOURCE_IRQ,
},
};
+#endif
static struct resource __devinitdata ab8500_usb_resources[] = {
{
diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c
index dedb7f65cea..9a0211aa889 100644
--- a/drivers/mfd/ab8500-debugfs.c
+++ b/drivers/mfd/ab8500-debugfs.c
@@ -13,7 +13,7 @@
#include <linux/platform_device.h>
#include <linux/mfd/abx500.h>
-#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500/ab8500.h>
static u32 debug_bank;
static u32 debug_address;
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
index e985d1701a8..c39fc716e1d 100644
--- a/drivers/mfd/ab8500-gpadc.c
+++ b/drivers/mfd/ab8500-gpadc.c
@@ -18,9 +18,9 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/list.h>
-#include <linux/mfd/ab8500.h>
#include <linux/mfd/abx500.h>
-#include <linux/mfd/ab8500/gpadc.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-gpadc.h>
/*
* GPADC register offsets
diff --git a/drivers/mfd/ab8500-i2c.c b/drivers/mfd/ab8500-i2c.c
index 9be541c6b00..087fecd71ce 100644
--- a/drivers/mfd/ab8500-i2c.c
+++ b/drivers/mfd/ab8500-i2c.c
@@ -10,7 +10,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/mfd/ab8500.h>
+#include <linux/mfd/abx500/ab8500.h>
#include <linux/mfd/db8500-prcmu.h>
static int ab8500_i2c_write(struct ab8500 *ab8500, u16 addr, u8 data)
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
index f20feefac19..c28d4eb1eff 100644
--- a/drivers/mfd/ab8500-sysctrl.c
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -7,9 +7,9 @@
#include <linux/err.h>
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <linux/mfd/ab8500.h>
#include <linux/mfd/abx500.h>
-#include <linux/mfd/ab8500/sysctrl.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-sysctrl.h>
static struct device *sysctrl_dev;
diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c
index f1d88483112..8d816cce832 100644
--- a/drivers/mfd/adp5520.c
+++ b/drivers/mfd/adp5520.c
@@ -109,7 +109,7 @@ int adp5520_set_bits(struct device *dev, int reg, uint8_t bit_mask)
ret = __adp5520_read(chip->client, reg, &reg_val);
- if (!ret && ((reg_val & bit_mask) == 0)) {
+ if (!ret && ((reg_val & bit_mask) != bit_mask)) {
reg_val |= bit_mask;
ret = __adp5520_write(chip->client, reg, reg_val);
}
diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c
index 155fa040788..315fef5d466 100644
--- a/drivers/mfd/cs5535-mfd.c
+++ b/drivers/mfd/cs5535-mfd.c
@@ -172,14 +172,14 @@ static void __devexit cs5535_mfd_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
}
-static struct pci_device_id cs5535_mfd_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(cs5535_mfd_pci_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, cs5535_mfd_pci_tbl);
-static struct pci_driver cs5535_mfd_drv = {
+static struct pci_driver cs5535_mfd_driver = {
.name = DRV_NAME,
.id_table = cs5535_mfd_pci_tbl,
.probe = cs5535_mfd_probe,
@@ -188,12 +188,12 @@ static struct pci_driver cs5535_mfd_drv = {
static int __init cs5535_mfd_init(void)
{
- return pci_register_driver(&cs5535_mfd_drv);
+ return pci_register_driver(&cs5535_mfd_driver);
}
static void __exit cs5535_mfd_exit(void)
{
- pci_unregister_driver(&cs5535_mfd_drv);
+ pci_unregister_driver(&cs5535_mfd_driver);
}
module_init(cs5535_mfd_init);
diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c
index 1b79c37fd59..1924b857a0f 100644
--- a/drivers/mfd/da903x.c
+++ b/drivers/mfd/da903x.c
@@ -182,7 +182,7 @@ int da903x_set_bits(struct device *dev, int reg, uint8_t bit_mask)
if (ret)
goto out;
- if ((reg_val & bit_mask) == 0) {
+ if ((reg_val & bit_mask) != bit_mask) {
reg_val |= bit_mask;
ret = __da903x_write(chip->client, reg, reg_val);
}
@@ -549,6 +549,7 @@ static int __devexit da903x_remove(struct i2c_client *client)
struct da903x_chip *chip = i2c_get_clientdata(client);
da903x_remove_subdevs(chip);
+ free_irq(client->irq, chip);
kfree(chip);
return 0;
}
diff --git a/drivers/mfd/da9052-core.c b/drivers/mfd/da9052-core.c
new file mode 100644
index 00000000000..5ddde2a9176
--- /dev/null
+++ b/drivers/mfd/da9052-core.c
@@ -0,0 +1,694 @@
+/*
+ * Device access for Dialog DA9052 PMICs.
+ *
+ * Copyright(c) 2011 Dialog Semiconductor Ltd.
+ *
+ * Author: David Dajun Chen <dchen@diasemi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mutex.h>
+#include <linux/mfd/core.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/pdata.h>
+#include <linux/mfd/da9052/reg.h>
+
+#define DA9052_NUM_IRQ_REGS 4
+#define DA9052_IRQ_MASK_POS_1 0x01
+#define DA9052_IRQ_MASK_POS_2 0x02
+#define DA9052_IRQ_MASK_POS_3 0x04
+#define DA9052_IRQ_MASK_POS_4 0x08
+#define DA9052_IRQ_MASK_POS_5 0x10
+#define DA9052_IRQ_MASK_POS_6 0x20
+#define DA9052_IRQ_MASK_POS_7 0x40
+#define DA9052_IRQ_MASK_POS_8 0x80
+
+static bool da9052_reg_readable(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case DA9052_PAGE0_CON_REG:
+ case DA9052_STATUS_A_REG:
+ case DA9052_STATUS_B_REG:
+ case DA9052_STATUS_C_REG:
+ case DA9052_STATUS_D_REG:
+ case DA9052_EVENT_A_REG:
+ case DA9052_EVENT_B_REG:
+ case DA9052_EVENT_C_REG:
+ case DA9052_EVENT_D_REG:
+ case DA9052_FAULTLOG_REG:
+ case DA9052_IRQ_MASK_A_REG:
+ case DA9052_IRQ_MASK_B_REG:
+ case DA9052_IRQ_MASK_C_REG:
+ case DA9052_IRQ_MASK_D_REG:
+ case DA9052_CONTROL_A_REG:
+ case DA9052_CONTROL_B_REG:
+ case DA9052_CONTROL_C_REG:
+ case DA9052_CONTROL_D_REG:
+ case DA9052_PDDIS_REG:
+ case DA9052_INTERFACE_REG:
+ case DA9052_RESET_REG:
+ case DA9052_GPIO_0_1_REG:
+ case DA9052_GPIO_2_3_REG:
+ case DA9052_GPIO_4_5_REG:
+ case DA9052_GPIO_6_7_REG:
+ case DA9052_GPIO_14_15_REG:
+ case DA9052_ID_0_1_REG:
+ case DA9052_ID_2_3_REG:
+ case DA9052_ID_4_5_REG:
+ case DA9052_ID_6_7_REG:
+ case DA9052_ID_8_9_REG:
+ case DA9052_ID_10_11_REG:
+ case DA9052_ID_12_13_REG:
+ case DA9052_ID_14_15_REG:
+ case DA9052_ID_16_17_REG:
+ case DA9052_ID_18_19_REG:
+ case DA9052_ID_20_21_REG:
+ case DA9052_SEQ_STATUS_REG:
+ case DA9052_SEQ_A_REG:
+ case DA9052_SEQ_B_REG:
+ case DA9052_SEQ_TIMER_REG:
+ case DA9052_BUCKA_REG:
+ case DA9052_BUCKB_REG:
+ case DA9052_BUCKCORE_REG:
+ case DA9052_BUCKPRO_REG:
+ case DA9052_BUCKMEM_REG:
+ case DA9052_BUCKPERI_REG:
+ case DA9052_LDO1_REG:
+ case DA9052_LDO2_REG:
+ case DA9052_LDO3_REG:
+ case DA9052_LDO4_REG:
+ case DA9052_LDO5_REG:
+ case DA9052_LDO6_REG:
+ case DA9052_LDO7_REG:
+ case DA9052_LDO8_REG:
+ case DA9052_LDO9_REG:
+ case DA9052_LDO10_REG:
+ case DA9052_SUPPLY_REG:
+ case DA9052_PULLDOWN_REG:
+ case DA9052_CHGBUCK_REG:
+ case DA9052_WAITCONT_REG:
+ case DA9052_ISET_REG:
+ case DA9052_BATCHG_REG:
+ case DA9052_CHG_CONT_REG:
+ case DA9052_INPUT_CONT_REG:
+ case DA9052_CHG_TIME_REG:
+ case DA9052_BBAT_CONT_REG:
+ case DA9052_BOOST_REG:
+ case DA9052_LED_CONT_REG:
+ case DA9052_LEDMIN123_REG:
+ case DA9052_LED1_CONF_REG:
+ case DA9052_LED2_CONF_REG:
+ case DA9052_LED3_CONF_REG:
+ case DA9052_LED1CONT_REG:
+ case DA9052_LED2CONT_REG:
+ case DA9052_LED3CONT_REG:
+ case DA9052_LED_CONT_4_REG:
+ case DA9052_LED_CONT_5_REG:
+ case DA9052_ADC_MAN_REG:
+ case DA9052_ADC_CONT_REG:
+ case DA9052_ADC_RES_L_REG:
+ case DA9052_ADC_RES_H_REG:
+ case DA9052_VDD_RES_REG:
+ case DA9052_VDD_MON_REG:
+ case DA9052_ICHG_AV_REG:
+ case DA9052_ICHG_THD_REG:
+ case DA9052_ICHG_END_REG:
+ case DA9052_TBAT_RES_REG:
+ case DA9052_TBAT_HIGHP_REG:
+ case DA9052_TBAT_HIGHN_REG:
+ case DA9052_TBAT_LOW_REG:
+ case DA9052_T_OFFSET_REG:
+ case DA9052_ADCIN4_RES_REG:
+ case DA9052_AUTO4_HIGH_REG:
+ case DA9052_AUTO4_LOW_REG:
+ case DA9052_ADCIN5_RES_REG:
+ case DA9052_AUTO5_HIGH_REG:
+ case DA9052_AUTO5_LOW_REG:
+ case DA9052_ADCIN6_RES_REG:
+ case DA9052_AUTO6_HIGH_REG:
+ case DA9052_AUTO6_LOW_REG:
+ case DA9052_TJUNC_RES_REG:
+ case DA9052_TSI_CONT_A_REG:
+ case DA9052_TSI_CONT_B_REG:
+ case DA9052_TSI_X_MSB_REG:
+ case DA9052_TSI_Y_MSB_REG:
+ case DA9052_TSI_LSB_REG:
+ case DA9052_TSI_Z_MSB_REG:
+ case DA9052_COUNT_S_REG:
+ case DA9052_COUNT_MI_REG:
+ case DA9052_COUNT_H_REG:
+ case DA9052_COUNT_D_REG:
+ case DA9052_COUNT_MO_REG:
+ case DA9052_COUNT_Y_REG:
+ case DA9052_ALARM_MI_REG:
+ case DA9052_ALARM_H_REG:
+ case DA9052_ALARM_D_REG:
+ case DA9052_ALARM_MO_REG:
+ case DA9052_ALARM_Y_REG:
+ case DA9052_SECOND_A_REG:
+ case DA9052_SECOND_B_REG:
+ case DA9052_SECOND_C_REG:
+ case DA9052_SECOND_D_REG:
+ case DA9052_PAGE1_CON_REG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool da9052_reg_writeable(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case DA9052_PAGE0_CON_REG:
+ case DA9052_EVENT_A_REG:
+ case DA9052_EVENT_B_REG:
+ case DA9052_EVENT_C_REG:
+ case DA9052_EVENT_D_REG:
+ case DA9052_IRQ_MASK_A_REG:
+ case DA9052_IRQ_MASK_B_REG:
+ case DA9052_IRQ_MASK_C_REG:
+ case DA9052_IRQ_MASK_D_REG:
+ case DA9052_CONTROL_A_REG:
+ case DA9052_CONTROL_B_REG:
+ case DA9052_CONTROL_C_REG:
+ case DA9052_CONTROL_D_REG:
+ case DA9052_PDDIS_REG:
+ case DA9052_RESET_REG:
+ case DA9052_GPIO_0_1_REG:
+ case DA9052_GPIO_2_3_REG:
+ case DA9052_GPIO_4_5_REG:
+ case DA9052_GPIO_6_7_REG:
+ case DA9052_GPIO_14_15_REG:
+ case DA9052_ID_0_1_REG:
+ case DA9052_ID_2_3_REG:
+ case DA9052_ID_4_5_REG:
+ case DA9052_ID_6_7_REG:
+ case DA9052_ID_8_9_REG:
+ case DA9052_ID_10_11_REG:
+ case DA9052_ID_12_13_REG:
+ case DA9052_ID_14_15_REG:
+ case DA9052_ID_16_17_REG:
+ case DA9052_ID_18_19_REG:
+ case DA9052_ID_20_21_REG:
+ case DA9052_SEQ_STATUS_REG:
+ case DA9052_SEQ_A_REG:
+ case DA9052_SEQ_B_REG:
+ case DA9052_SEQ_TIMER_REG:
+ case DA9052_BUCKA_REG:
+ case DA9052_BUCKB_REG:
+ case DA9052_BUCKCORE_REG:
+ case DA9052_BUCKPRO_REG:
+ case DA9052_BUCKMEM_REG:
+ case DA9052_BUCKPERI_REG:
+ case DA9052_LDO1_REG:
+ case DA9052_LDO2_REG:
+ case DA9052_LDO3_REG:
+ case DA9052_LDO4_REG:
+ case DA9052_LDO5_REG:
+ case DA9052_LDO6_REG:
+ case DA9052_LDO7_REG:
+ case DA9052_LDO8_REG:
+ case DA9052_LDO9_REG:
+ case DA9052_LDO10_REG:
+ case DA9052_SUPPLY_REG:
+ case DA9052_PULLDOWN_REG:
+ case DA9052_CHGBUCK_REG:
+ case DA9052_WAITCONT_REG:
+ case DA9052_ISET_REG:
+ case DA9052_BATCHG_REG:
+ case DA9052_CHG_CONT_REG:
+ case DA9052_INPUT_CONT_REG:
+ case DA9052_BBAT_CONT_REG:
+ case DA9052_BOOST_REG:
+ case DA9052_LED_CONT_REG:
+ case DA9052_LEDMIN123_REG:
+ case DA9052_LED1_CONF_REG:
+ case DA9052_LED2_CONF_REG:
+ case DA9052_LED3_CONF_REG:
+ case DA9052_LED1CONT_REG:
+ case DA9052_LED2CONT_REG:
+ case DA9052_LED3CONT_REG:
+ case DA9052_LED_CONT_4_REG:
+ case DA9052_LED_CONT_5_REG:
+ case DA9052_ADC_MAN_REG:
+ case DA9052_ADC_CONT_REG:
+ case DA9052_ADC_RES_L_REG:
+ case DA9052_ADC_RES_H_REG:
+ case DA9052_VDD_RES_REG:
+ case DA9052_VDD_MON_REG:
+ case DA9052_ICHG_THD_REG:
+ case DA9052_ICHG_END_REG:
+ case DA9052_TBAT_HIGHP_REG:
+ case DA9052_TBAT_HIGHN_REG:
+ case DA9052_TBAT_LOW_REG:
+ case DA9052_T_OFFSET_REG:
+ case DA9052_AUTO4_HIGH_REG:
+ case DA9052_AUTO4_LOW_REG:
+ case DA9052_AUTO5_HIGH_REG:
+ case DA9052_AUTO5_LOW_REG:
+ case DA9052_AUTO6_HIGH_REG:
+ case DA9052_AUTO6_LOW_REG:
+ case DA9052_TSI_CONT_A_REG:
+ case DA9052_TSI_CONT_B_REG:
+ case DA9052_COUNT_S_REG:
+ case DA9052_COUNT_MI_REG:
+ case DA9052_COUNT_H_REG:
+ case DA9052_COUNT_D_REG:
+ case DA9052_COUNT_MO_REG:
+ case DA9052_COUNT_Y_REG:
+ case DA9052_ALARM_MI_REG:
+ case DA9052_ALARM_H_REG:
+ case DA9052_ALARM_D_REG:
+ case DA9052_ALARM_MO_REG:
+ case DA9052_ALARM_Y_REG:
+ case DA9052_PAGE1_CON_REG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool da9052_reg_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case DA9052_STATUS_A_REG:
+ case DA9052_STATUS_B_REG:
+ case DA9052_STATUS_C_REG:
+ case DA9052_STATUS_D_REG:
+ case DA9052_EVENT_A_REG:
+ case DA9052_EVENT_B_REG:
+ case DA9052_EVENT_C_REG:
+ case DA9052_EVENT_D_REG:
+ case DA9052_FAULTLOG_REG:
+ case DA9052_CHG_TIME_REG:
+ case DA9052_ADC_RES_L_REG:
+ case DA9052_ADC_RES_H_REG:
+ case DA9052_VDD_RES_REG:
+ case DA9052_ICHG_AV_REG:
+ case DA9052_TBAT_RES_REG:
+ case DA9052_ADCIN4_RES_REG:
+ case DA9052_ADCIN5_RES_REG:
+ case DA9052_ADCIN6_RES_REG:
+ case DA9052_TJUNC_RES_REG:
+ case DA9052_TSI_X_MSB_REG:
+ case DA9052_TSI_Y_MSB_REG:
+ case DA9052_TSI_LSB_REG:
+ case DA9052_TSI_Z_MSB_REG:
+ case DA9052_COUNT_S_REG:
+ case DA9052_COUNT_MI_REG:
+ case DA9052_COUNT_H_REG:
+ case DA9052_COUNT_D_REG:
+ case DA9052_COUNT_MO_REG:
+ case DA9052_COUNT_Y_REG:
+ case DA9052_ALARM_MI_REG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static struct resource da9052_rtc_resource = {
+ .name = "ALM",
+ .start = DA9052_IRQ_ALARM,
+ .end = DA9052_IRQ_ALARM,
+ .flags = IORESOURCE_IRQ,
+};
+
+static struct resource da9052_onkey_resource = {
+ .name = "ONKEY",
+ .start = DA9052_IRQ_NONKEY,
+ .end = DA9052_IRQ_NONKEY,
+ .flags = IORESOURCE_IRQ,
+};
+
+static struct resource da9052_bat_resources[] = {
+ {
+ .name = "BATT TEMP",
+ .start = DA9052_IRQ_TBAT,
+ .end = DA9052_IRQ_TBAT,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "DCIN DET",
+ .start = DA9052_IRQ_DCIN,
+ .end = DA9052_IRQ_DCIN,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "DCIN REM",
+ .start = DA9052_IRQ_DCINREM,
+ .end = DA9052_IRQ_DCINREM,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS DET",
+ .start = DA9052_IRQ_VBUS,
+ .end = DA9052_IRQ_VBUS,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "VBUS REM",
+ .start = DA9052_IRQ_VBUSREM,
+ .end = DA9052_IRQ_VBUSREM,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "CHG END",
+ .start = DA9052_IRQ_CHGEND,
+ .end = DA9052_IRQ_CHGEND,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource da9052_tsi_resources[] = {
+ {
+ .name = "PENDWN",
+ .start = DA9052_IRQ_PENDOWN,
+ .end = DA9052_IRQ_PENDOWN,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "TSIRDY",
+ .start = DA9052_IRQ_TSIREADY,
+ .end = DA9052_IRQ_TSIREADY,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mfd_cell __devinitdata da9052_subdev_info[] = {
+ {
+ .name = "da9052-regulator",
+ .id = 1,
+ },
+ {
+ .name = "da9052-regulator",
+ .id = 2,
+ },
+ {
+ .name = "da9052-regulator",
+ .id = 3,
+ },
+ {
+ .name = "da9052-regulator",
+ .id = 4,
+ },
+ {
+ .name = "da9052-regulator",
+ .id = 5,
+ },
+ {
+ .name = "da9052-regulator",
+ .id = 6,
+ },
+ {
+ .name = "da9052-regulator",
+ .id = 7,
+ },
+ {
+ .name = "da9052-regulator",
+ .id = 8,
+ },
+ {
+ .name = "da9052-regulator",
+ .id = 9,
+ },
+ {
+ .name = "da9052-regulator",
+ .id = 10,
+ },
+ {
+ .name = "da9052-regulator",
+ .id = 11,
+ },
+ {
+ .name = "da9052-regulator",
+ .id = 12,
+ },
+ {
+ .name = "da9052-regulator",
+ .id = 13,
+ },
+ {
+ .name = "da9052-regulator",
+ .id = 14,
+ },
+ {
+ .name = "da9052-onkey",
+ .resources = &da9052_onkey_resource,
+ .num_resources = 1,
+ },
+ {
+ .name = "da9052-rtc",
+ .resources = &da9052_rtc_resource,
+ .num_resources = 1,
+ },
+ {
+ .name = "da9052-gpio",
+ },
+ {
+ .name = "da9052-hwmon",
+ },
+ {
+ .name = "da9052-leds",
+ },
+ {
+ .name = "da9052-wled1",
+ },
+ {
+ .name = "da9052-wled2",
+ },
+ {
+ .name = "da9052-wled3",
+ },
+ {
+ .name = "da9052-tsi",
+ .resources = da9052_tsi_resources,
+ .num_resources = ARRAY_SIZE(da9052_tsi_resources),
+ },
+ {
+ .name = "da9052-bat",
+ .resources = da9052_bat_resources,
+ .num_resources = ARRAY_SIZE(da9052_bat_resources),
+ },
+ {
+ .name = "da9052-watchdog",
+ },
+};
+
+static struct regmap_irq da9052_irqs[] = {
+ [DA9052_IRQ_DCIN] = {
+ .reg_offset = 0,
+ .mask = DA9052_IRQ_MASK_POS_1,
+ },
+ [DA9052_IRQ_VBUS] = {
+ .reg_offset = 0,
+ .mask = DA9052_IRQ_MASK_POS_2,
+ },
+ [DA9052_IRQ_DCINREM] = {
+ .reg_offset = 0,
+ .mask = DA9052_IRQ_MASK_POS_3,
+ },
+ [DA9052_IRQ_VBUSREM] = {
+ .reg_offset = 0,
+ .mask = DA9052_IRQ_MASK_POS_4,
+ },
+ [DA9052_IRQ_VDDLOW] = {
+ .reg_offset = 0,
+ .mask = DA9052_IRQ_MASK_POS_5,
+ },
+ [DA9052_IRQ_ALARM] = {
+ .reg_offset = 0,
+ .mask = DA9052_IRQ_MASK_POS_6,
+ },
+ [DA9052_IRQ_SEQRDY] = {
+ .reg_offset = 0,
+ .mask = DA9052_IRQ_MASK_POS_7,
+ },
+ [DA9052_IRQ_COMP1V2] = {
+ .reg_offset = 0,
+ .mask = DA9052_IRQ_MASK_POS_8,
+ },
+ [DA9052_IRQ_NONKEY] = {
+ .reg_offset = 1,
+ .mask = DA9052_IRQ_MASK_POS_1,
+ },
+ [DA9052_IRQ_IDFLOAT] = {
+ .reg_offset = 1,
+ .mask = DA9052_IRQ_MASK_POS_2,
+ },
+ [DA9052_IRQ_IDGND] = {
+ .reg_offset = 1,
+ .mask = DA9052_IRQ_MASK_POS_3,
+ },
+ [DA9052_IRQ_CHGEND] = {
+ .reg_offset = 1,
+ .mask = DA9052_IRQ_MASK_POS_4,
+ },
+ [DA9052_IRQ_TBAT] = {
+ .reg_offset = 1,
+ .mask = DA9052_IRQ_MASK_POS_5,
+ },
+ [DA9052_IRQ_ADC_EOM] = {
+ .reg_offset = 1,
+ .mask = DA9052_IRQ_MASK_POS_6,
+ },
+ [DA9052_IRQ_PENDOWN] = {
+ .reg_offset = 1,
+ .mask = DA9052_IRQ_MASK_POS_7,
+ },
+ [DA9052_IRQ_TSIREADY] = {
+ .reg_offset = 1,
+ .mask = DA9052_IRQ_MASK_POS_8,
+ },
+ [DA9052_IRQ_GPI0] = {
+ .reg_offset = 2,
+ .mask = DA9052_IRQ_MASK_POS_1,
+ },
+ [DA9052_IRQ_GPI1] = {
+ .reg_offset = 2,
+ .mask = DA9052_IRQ_MASK_POS_2,
+ },
+ [DA9052_IRQ_GPI2] = {
+ .reg_offset = 2,
+ .mask = DA9052_IRQ_MASK_POS_3,
+ },
+ [DA9052_IRQ_GPI3] = {
+ .reg_offset = 2,
+ .mask = DA9052_IRQ_MASK_POS_4,
+ },
+ [DA9052_IRQ_GPI4] = {
+ .reg_offset = 2,
+ .mask = DA9052_IRQ_MASK_POS_5,
+ },
+ [DA9052_IRQ_GPI5] = {
+ .reg_offset = 2,
+ .mask = DA9052_IRQ_MASK_POS_6,
+ },
+ [DA9052_IRQ_GPI6] = {
+ .reg_offset = 2,
+ .mask = DA9052_IRQ_MASK_POS_7,
+ },
+ [DA9052_IRQ_GPI7] = {
+ .reg_offset = 2,
+ .mask = DA9052_IRQ_MASK_POS_8,
+ },
+ [DA9052_IRQ_GPI8] = {
+ .reg_offset = 3,
+ .mask = DA9052_IRQ_MASK_POS_1,
+ },
+ [DA9052_IRQ_GPI9] = {
+ .reg_offset = 3,
+ .mask = DA9052_IRQ_MASK_POS_2,
+ },
+ [DA9052_IRQ_GPI10] = {
+ .reg_offset = 3,
+ .mask = DA9052_IRQ_MASK_POS_3,
+ },
+ [DA9052_IRQ_GPI11] = {
+ .reg_offset = 3,
+ .mask = DA9052_IRQ_MASK_POS_4,
+ },
+ [DA9052_IRQ_GPI12] = {
+ .reg_offset = 3,
+ .mask = DA9052_IRQ_MASK_POS_5,
+ },
+ [DA9052_IRQ_GPI13] = {
+ .reg_offset = 3,
+ .mask = DA9052_IRQ_MASK_POS_6,
+ },
+ [DA9052_IRQ_GPI14] = {
+ .reg_offset = 3,
+ .mask = DA9052_IRQ_MASK_POS_7,
+ },
+ [DA9052_IRQ_GPI15] = {
+ .reg_offset = 3,
+ .mask = DA9052_IRQ_MASK_POS_8,
+ },
+};
+
+static struct regmap_irq_chip da9052_regmap_irq_chip = {
+ .name = "da9052_irq",
+ .status_base = DA9052_EVENT_A_REG,
+ .mask_base = DA9052_IRQ_MASK_A_REG,
+ .ack_base = DA9052_EVENT_A_REG,
+ .num_regs = DA9052_NUM_IRQ_REGS,
+ .irqs = da9052_irqs,
+ .num_irqs = ARRAY_SIZE(da9052_irqs),
+};
+
+struct regmap_config da9052_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .cache_type = REGCACHE_RBTREE,
+
+ .max_register = DA9052_PAGE1_CON_REG,
+ .readable_reg = da9052_reg_readable,
+ .writeable_reg = da9052_reg_writeable,
+ .volatile_reg = da9052_reg_volatile,
+};
+EXPORT_SYMBOL_GPL(da9052_regmap_config);
+
+int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id)
+{
+ struct da9052_pdata *pdata = da9052->dev->platform_data;
+ struct irq_desc *desc;
+ int ret;
+
+ mutex_init(&da9052->io_lock);
+
+ if (pdata && pdata->init != NULL)
+ pdata->init(da9052);
+
+ da9052->chip_id = chip_id;
+
+ if (!pdata || !pdata->irq_base)
+ da9052->irq_base = -1;
+ else
+ da9052->irq_base = pdata->irq_base;
+
+ ret = regmap_add_irq_chip(da9052->regmap, da9052->chip_irq,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ da9052->irq_base, &da9052_regmap_irq_chip,
+ NULL);
+ if (ret < 0)
+ goto regmap_err;
+
+ desc = irq_to_desc(da9052->chip_irq);
+ da9052->irq_base = regmap_irq_chip_get_base(desc->action->dev_id);
+
+ ret = mfd_add_devices(da9052->dev, -1, da9052_subdev_info,
+ ARRAY_SIZE(da9052_subdev_info), NULL, 0);
+ if (ret)
+ goto err;
+
+ return 0;
+
+err:
+ mfd_remove_devices(da9052->dev);
+regmap_err:
+ return ret;
+}
+
+void da9052_device_exit(struct da9052 *da9052)
+{
+ regmap_del_irq_chip(da9052->chip_irq,
+ irq_get_irq_data(da9052->irq_base)->chip_data);
+ mfd_remove_devices(da9052->dev);
+}
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("DA9052 MFD Core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/da9052-i2c.c b/drivers/mfd/da9052-i2c.c
new file mode 100644
index 00000000000..44b97c70a61
--- /dev/null
+++ b/drivers/mfd/da9052-i2c.c
@@ -0,0 +1,140 @@
+/*
+ * I2C access for DA9052 PMICs.
+ *
+ * Copyright(c) 2011 Dialog Semiconductor Ltd.
+ *
+ * Author: David Dajun Chen <dchen@diasemi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/mfd/core.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+
+static int da9052_i2c_enable_multiwrite(struct da9052 *da9052)
+{
+ int reg_val, ret;
+
+ ret = regmap_read(da9052->regmap, DA9052_CONTROL_B_REG, &reg_val);
+ if (ret < 0)
+ return ret;
+
+ if (reg_val & DA9052_CONTROL_B_WRITEMODE) {
+ reg_val &= ~DA9052_CONTROL_B_WRITEMODE;
+ ret = regmap_write(da9052->regmap, DA9052_CONTROL_B_REG,
+ reg_val);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __devinit da9052_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct da9052 *da9052;
+ int ret;
+
+ da9052 = kzalloc(sizeof(struct da9052), GFP_KERNEL);
+ 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__);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ da9052->dev = &client->dev;
+ da9052->chip_irq = client->irq;
+
+ i2c_set_clientdata(client, da9052);
+
+ da9052->regmap = regmap_init_i2c(client, &da9052_regmap_config);
+ if (IS_ERR(da9052->regmap)) {
+ ret = PTR_ERR(da9052->regmap);
+ dev_err(&client->dev, "Failed to allocate register map: %d\n",
+ ret);
+ goto err;
+ }
+
+ ret = da9052_i2c_enable_multiwrite(da9052);
+ if (ret < 0)
+ goto err;
+
+ ret = da9052_device_init(da9052, id->driver_data);
+ if (ret != 0)
+ goto err;
+
+ return 0;
+
+err:
+ kfree(da9052);
+ return ret;
+}
+
+static int da9052_i2c_remove(struct i2c_client *client)
+{
+ struct da9052 *da9052 = i2c_get_clientdata(client);
+
+ da9052_device_exit(da9052);
+ kfree(da9052);
+
+ return 0;
+}
+
+static struct i2c_device_id da9052_i2c_id[] = {
+ {"da9052", DA9052},
+ {"da9053-aa", DA9053_AA},
+ {"da9053-ba", DA9053_BA},
+ {"da9053-bb", DA9053_BB},
+ {}
+};
+
+static struct i2c_driver da9052_i2c_driver = {
+ .probe = da9052_i2c_probe,
+ .remove = da9052_i2c_remove,
+ .id_table = da9052_i2c_id,
+ .driver = {
+ .name = "da9052",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init da9052_i2c_init(void)
+{
+ int ret;
+
+ ret = i2c_add_driver(&da9052_i2c_driver);
+ if (ret != 0) {
+ pr_err("DA9052 I2C registration failed %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+subsys_initcall(da9052_i2c_init);
+
+static void __exit da9052_i2c_exit(void)
+{
+ i2c_del_driver(&da9052_i2c_driver);
+}
+module_exit(da9052_i2c_exit);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("I2C driver for Dialog DA9052 PMIC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/da9052-spi.c b/drivers/mfd/da9052-spi.c
new file mode 100644
index 00000000000..cdbc7cad326
--- /dev/null
+++ b/drivers/mfd/da9052-spi.c
@@ -0,0 +1,115 @@
+/*
+ * SPI access for Dialog DA9052 PMICs.
+ *
+ * Copyright(c) 2011 Dialog Semiconductor Ltd.
+ *
+ * Author: David Dajun Chen <dchen@diasemi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/mfd/core.h>
+#include <linux/spi/spi.h>
+#include <linux/err.h>
+
+#include <linux/mfd/da9052/da9052.h>
+
+static int da9052_spi_probe(struct spi_device *spi)
+{
+ int ret;
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ struct da9052 *da9052 = kzalloc(sizeof(struct da9052), GFP_KERNEL);
+
+ if (!da9052)
+ return -ENOMEM;
+
+ spi->mode = SPI_MODE_0 | SPI_CPOL;
+ spi->bits_per_word = 8;
+ spi_setup(spi);
+
+ da9052->dev = &spi->dev;
+ da9052->chip_irq = spi->irq;
+
+ dev_set_drvdata(&spi->dev, da9052);
+
+ da9052_regmap_config.read_flag_mask = 1;
+ da9052_regmap_config.write_flag_mask = 0;
+
+ da9052->regmap = regmap_init_spi(spi, &da9052_regmap_config);
+ if (IS_ERR(da9052->regmap)) {
+ ret = PTR_ERR(da9052->regmap);
+ dev_err(&spi->dev, "Failed to allocate register map: %d\n",
+ ret);
+ goto err;
+ }
+
+ ret = da9052_device_init(da9052, id->driver_data);
+ if (ret != 0)
+ goto err;
+
+ return 0;
+
+err:
+ kfree(da9052);
+ return ret;
+}
+
+static int da9052_spi_remove(struct spi_device *spi)
+{
+ struct da9052 *da9052 = dev_get_drvdata(&spi->dev);
+
+ da9052_device_exit(da9052);
+ kfree(da9052);
+
+ return 0;
+}
+
+static struct spi_device_id da9052_spi_id[] = {
+ {"da9052", DA9052},
+ {"da9053-aa", DA9053_AA},
+ {"da9053-ba", DA9053_BA},
+ {"da9053-bb", DA9053_BB},
+ {}
+};
+
+static struct spi_driver da9052_spi_driver = {
+ .probe = da9052_spi_probe,
+ .remove = __devexit_p(da9052_spi_remove),
+ .id_table = da9052_spi_id,
+ .driver = {
+ .name = "da9052",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init da9052_spi_init(void)
+{
+ int ret;
+
+ ret = spi_register_driver(&da9052_spi_driver);
+ if (ret != 0) {
+ pr_err("Failed to register DA9052 SPI driver, %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+subsys_initcall(da9052_spi_init);
+
+static void __exit da9052_spi_exit(void)
+{
+ spi_unregister_driver(&da9052_spi_driver);
+}
+module_exit(da9052_spi_exit);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("SPI driver for Dialog DA9052 PMIC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index a25ab9c6b5a..af8e0efedbe 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -2102,14 +2102,11 @@ static struct irq_chip prcmu_irq_chip = {
void __init db8500_prcmu_early_init(void)
{
unsigned int i;
-
- if (cpu_is_u8500v1()) {
- tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE_V1);
- } else if (cpu_is_u8500v2()) {
+ if (cpu_is_u8500v2()) {
void *tcpm_base = ioremap_nocache(U8500_PRCMU_TCPM_BASE, SZ_4K);
if (tcpm_base != NULL) {
- int version;
+ u32 version;
version = readl(tcpm_base + PRCMU_FW_VERSION_OFFSET);
prcmu_version.project_number = version & 0xFF;
prcmu_version.api_version = (version >> 8) & 0xFF;
diff --git a/drivers/mfd/dm355evm_msp.c b/drivers/mfd/dm355evm_msp.c
index 8ad88da647b..7710227d284 100644
--- a/drivers/mfd/dm355evm_msp.c
+++ b/drivers/mfd/dm355evm_msp.c
@@ -308,8 +308,7 @@ static int add_children(struct i2c_client *client)
for (i = 0; i < ARRAY_SIZE(config_inputs); i++) {
int gpio = dm355evm_msp_gpio.base + config_inputs[i].offset;
- gpio_request(gpio, config_inputs[i].label);
- gpio_direction_input(gpio);
+ gpio_request_one(gpio, GPIOF_IN, config_inputs[i].label);
/* make it easy for userspace to see these */
gpio_export(gpio, false);
diff --git a/drivers/mfd/intel_msic.c b/drivers/mfd/intel_msic.c
index 97c27762174..b76657eb0c5 100644
--- a/drivers/mfd/intel_msic.c
+++ b/drivers/mfd/intel_msic.c
@@ -485,17 +485,7 @@ static struct platform_driver intel_msic_driver = {
},
};
-static int __init intel_msic_init(void)
-{
- return platform_driver_register(&intel_msic_driver);
-}
-module_init(intel_msic_init);
-
-static void __exit intel_msic_exit(void)
-{
- platform_driver_unregister(&intel_msic_driver);
-}
-module_exit(intel_msic_exit);
+module_platform_driver(intel_msic_driver);
MODULE_DESCRIPTION("Driver for Intel MSIC");
MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c
index 1e9ee533eac..87662a17dec 100644
--- a/drivers/mfd/jz4740-adc.c
+++ b/drivers/mfd/jz4740-adc.c
@@ -16,6 +16,7 @@
*/
#include <linux/err.h>
+#include <linux/io.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
@@ -180,7 +181,7 @@ static struct resource jz4740_battery_resources[] = {
},
};
-const struct mfd_cell jz4740_adc_cells[] = {
+static struct mfd_cell jz4740_adc_cells[] = {
{
.id = 0,
.name = "jz4740-hwmon",
@@ -337,17 +338,7 @@ static struct platform_driver jz4740_adc_driver = {
},
};
-static int __init jz4740_adc_init(void)
-{
- return platform_driver_register(&jz4740_adc_driver);
-}
-module_init(jz4740_adc_init);
-
-static void __exit jz4740_adc_exit(void)
-{
- platform_driver_unregister(&jz4740_adc_driver);
-}
-module_exit(jz4740_adc_exit);
+module_platform_driver(jz4740_adc_driver);
MODULE_DESCRIPTION("JZ4740 SoC ADC driver");
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c
index ea1169b0477..abc421364a4 100644
--- a/drivers/mfd/lpc_sch.c
+++ b/drivers/mfd/lpc_sch.c
@@ -74,7 +74,7 @@ static struct mfd_cell tunnelcreek_cells[] = {
},
};
-static struct pci_device_id lpc_sch_ids[] = {
+static DEFINE_PCI_DEVICE_TABLE(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) },
{ 0, }
diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c
index e1e59c92f75..ca881efedf7 100644
--- a/drivers/mfd/max8925-core.c
+++ b/drivers/mfd/max8925-core.c
@@ -210,21 +210,6 @@ static struct max8925_irq_data max8925_irqs[] = {
.mask_reg = MAX8925_CHG_IRQ1_MASK,
.offs = 1 << 2,
},
- [MAX8925_IRQ_VCHG_USB_OVP] = {
- .reg = MAX8925_CHG_IRQ1,
- .mask_reg = MAX8925_CHG_IRQ1_MASK,
- .offs = 1 << 3,
- },
- [MAX8925_IRQ_VCHG_USB_F] = {
- .reg = MAX8925_CHG_IRQ1,
- .mask_reg = MAX8925_CHG_IRQ1_MASK,
- .offs = 1 << 4,
- },
- [MAX8925_IRQ_VCHG_USB_R] = {
- .reg = MAX8925_CHG_IRQ1,
- .mask_reg = MAX8925_CHG_IRQ1_MASK,
- .offs = 1 << 5,
- },
[MAX8925_IRQ_VCHG_THM_OK_R] = {
.reg = MAX8925_CHG_IRQ2,
.mask_reg = MAX8925_CHG_IRQ2_MASK,
diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c
index 0219115e00c..d9e4b36edee 100644
--- a/drivers/mfd/max8925-i2c.c
+++ b/drivers/mfd/max8925-i2c.c
@@ -161,6 +161,8 @@ static int __devinit max8925_probe(struct i2c_client *client,
chip->adc = i2c_new_dummy(chip->i2c->adapter, ADC_I2C_ADDR);
i2c_set_clientdata(chip->adc, chip);
+ device_init_wakeup(&client->dev, 1);
+
max8925_device_init(chip, pdata);
return 0;
@@ -177,10 +179,35 @@ static int __devexit max8925_remove(struct i2c_client *client)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int max8925_suspend(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct max8925_chip *chip = i2c_get_clientdata(client);
+
+ if (device_may_wakeup(dev) && chip->wakeup_flag)
+ enable_irq_wake(chip->core_irq);
+ return 0;
+}
+
+static int max8925_resume(struct device *dev)
+{
+ struct i2c_client *client = container_of(dev, struct i2c_client, dev);
+ struct max8925_chip *chip = i2c_get_clientdata(client);
+
+ if (device_may_wakeup(dev) && chip->wakeup_flag)
+ disable_irq_wake(chip->core_irq);
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(max8925_pm_ops, max8925_suspend, max8925_resume);
+
static struct i2c_driver max8925_driver = {
.driver = {
.name = "max8925",
.owner = THIS_MODULE,
+ .pm = &max8925_pm_ops,
},
.probe = max8925_probe,
.remove = __devexit_p(max8925_remove),
diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c
index 5be53ae9b61..cb83a7ab53e 100644
--- a/drivers/mfd/max8997.c
+++ b/drivers/mfd/max8997.c
@@ -43,7 +43,8 @@ static struct mfd_cell max8997_devs[] = {
{ .name = "max8997-battery", },
{ .name = "max8997-haptic", },
{ .name = "max8997-muic", },
- { .name = "max8997-flash", },
+ { .name = "max8997-led", .id = 1 },
+ { .name = "max8997-led", .id = 2 },
};
int max8997_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest)
diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c
index de4096aee24..6ef56d28c05 100644
--- a/drivers/mfd/max8998.c
+++ b/drivers/mfd/max8998.c
@@ -176,6 +176,8 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
if (ret < 0)
goto err;
+ device_init_wakeup(max8998->dev, max8998->wakeup);
+
return ret;
err:
@@ -210,7 +212,7 @@ static int max8998_suspend(struct device *dev)
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
- if (max8998->wakeup)
+ if (device_may_wakeup(dev))
irq_set_irq_wake(max8998->irq, 1);
return 0;
}
@@ -220,7 +222,7 @@ static int max8998_resume(struct device *dev)
struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
struct max8998_dev *max8998 = i2c_get_clientdata(i2c);
- if (max8998->wakeup)
+ if (device_may_wakeup(dev))
irq_set_irq_wake(max8998->irq, 0);
/*
* In LP3974, if IRQ registers are not "read & clear"
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index e9619acc023..7122386b4e3 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -18,11 +18,15 @@
#include <linux/spi/spi.h>
#include <linux/mfd/core.h>
#include <linux/mfd/mc13xxx.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
struct mc13xxx {
struct spi_device *spidev;
struct mutex lock;
int irq;
+ int flags;
irq_handler_t irqhandler[MC13XXX_NUM_IRQ];
void *irqdata[MC13XXX_NUM_IRQ];
@@ -550,10 +554,7 @@ static const char *mc13xxx_get_chipname(struct mc13xxx *mc13xxx)
int mc13xxx_get_flags(struct mc13xxx *mc13xxx)
{
- struct mc13xxx_platform_data *pdata =
- dev_get_platdata(&mc13xxx->spidev->dev);
-
- return pdata->flags;
+ return mc13xxx->flags;
}
EXPORT_SYMBOL(mc13xxx_get_flags);
@@ -615,13 +616,13 @@ int mc13xxx_adc_do_conversion(struct mc13xxx *mc13xxx, unsigned int mode,
break;
case MC13XXX_ADC_MODE_SINGLE_CHAN:
- adc0 |= old_adc0 & MC13XXX_ADC0_TSMOD_MASK;
+ adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK;
adc1 |= (channel & 0x7) << MC13XXX_ADC1_CHAN0_SHIFT;
adc1 |= MC13XXX_ADC1_RAND;
break;
case MC13XXX_ADC_MODE_MULT_CHAN:
- adc0 |= old_adc0 & MC13XXX_ADC0_TSMOD_MASK;
+ adc0 |= old_adc0 & MC13XXX_ADC0_CONFIG_MASK;
adc1 |= 4 << MC13XXX_ADC1_CHAN1_SHIFT;
break;
@@ -696,17 +697,67 @@ static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format)
return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0);
}
+#ifdef CONFIG_OF
+static int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx)
+{
+ struct device_node *np = mc13xxx->spidev->dev.of_node;
+
+ if (!np)
+ return -ENODEV;
+
+ if (of_get_property(np, "fsl,mc13xxx-uses-adc", NULL))
+ mc13xxx->flags |= MC13XXX_USE_ADC;
+
+ if (of_get_property(np, "fsl,mc13xxx-uses-codec", NULL))
+ mc13xxx->flags |= MC13XXX_USE_CODEC;
+
+ if (of_get_property(np, "fsl,mc13xxx-uses-rtc", NULL))
+ mc13xxx->flags |= MC13XXX_USE_RTC;
+
+ if (of_get_property(np, "fsl,mc13xxx-uses-touch", NULL))
+ mc13xxx->flags |= MC13XXX_USE_TOUCHSCREEN;
+
+ return 0;
+}
+#else
+static inline int mc13xxx_probe_flags_dt(struct mc13xxx *mc13xxx)
+{
+ return -ENODEV;
+}
+#endif
+
+static const struct spi_device_id mc13xxx_device_id[] = {
+ {
+ .name = "mc13783",
+ .driver_data = MC13XXX_ID_MC13783,
+ }, {
+ .name = "mc13892",
+ .driver_data = MC13XXX_ID_MC13892,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(spi, mc13xxx_device_id);
+
+static const struct of_device_id mc13xxx_dt_ids[] = {
+ { .compatible = "fsl,mc13783", .data = (void *) MC13XXX_ID_MC13783, },
+ { .compatible = "fsl,mc13892", .data = (void *) MC13XXX_ID_MC13892, },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mc13xxx_dt_ids);
+
static int mc13xxx_probe(struct spi_device *spi)
{
+ const struct of_device_id *of_id;
+ struct spi_driver *sdrv = to_spi_driver(spi->dev.driver);
struct mc13xxx *mc13xxx;
struct mc13xxx_platform_data *pdata = dev_get_platdata(&spi->dev);
enum mc13xxx_id id;
int ret;
- if (!pdata) {
- dev_err(&spi->dev, "invalid platform data\n");
- return -EINVAL;
- }
+ of_id = of_match_device(mc13xxx_dt_ids, &spi->dev);
+ if (of_id)
+ sdrv->id_table = &mc13xxx_device_id[(enum mc13xxx_id) of_id->data];
mc13xxx = kzalloc(sizeof(*mc13xxx), GFP_KERNEL);
if (!mc13xxx)
@@ -749,28 +800,33 @@ err_revision:
mc13xxx_unlock(mc13xxx);
- if (pdata->flags & MC13XXX_USE_ADC)
+ if (mc13xxx_probe_flags_dt(mc13xxx) < 0 && pdata)
+ mc13xxx->flags = pdata->flags;
+
+ if (mc13xxx->flags & MC13XXX_USE_ADC)
mc13xxx_add_subdevice(mc13xxx, "%s-adc");
- if (pdata->flags & MC13XXX_USE_CODEC)
+ if (mc13xxx->flags & MC13XXX_USE_CODEC)
mc13xxx_add_subdevice(mc13xxx, "%s-codec");
- mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
- &pdata->regulators, sizeof(pdata->regulators));
-
- if (pdata->flags & MC13XXX_USE_RTC)
+ if (mc13xxx->flags & MC13XXX_USE_RTC)
mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
- if (pdata->flags & MC13XXX_USE_TOUCHSCREEN)
+ if (mc13xxx->flags & MC13XXX_USE_TOUCHSCREEN)
mc13xxx_add_subdevice(mc13xxx, "%s-ts");
- if (pdata->leds)
+ if (pdata) {
+ mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator",
+ &pdata->regulators, sizeof(pdata->regulators));
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led",
pdata->leds, sizeof(*pdata->leds));
-
- if (pdata->buttons)
mc13xxx_add_subdevice_pdata(mc13xxx, "%s-pwrbutton",
pdata->buttons, sizeof(*pdata->buttons));
+ } else {
+ mc13xxx_add_subdevice(mc13xxx, "%s-regulator");
+ mc13xxx_add_subdevice(mc13xxx, "%s-led");
+ mc13xxx_add_subdevice(mc13xxx, "%s-pwrbutton");
+ }
return 0;
}
@@ -788,25 +844,12 @@ static int __devexit mc13xxx_remove(struct spi_device *spi)
return 0;
}
-static const struct spi_device_id mc13xxx_device_id[] = {
- {
- .name = "mc13783",
- .driver_data = MC13XXX_ID_MC13783,
- }, {
- .name = "mc13892",
- .driver_data = MC13XXX_ID_MC13892,
- }, {
- /* sentinel */
- }
-};
-MODULE_DEVICE_TABLE(spi, mc13xxx_device_id);
-
static struct spi_driver mc13xxx_driver = {
.id_table = mc13xxx_device_id,
.driver = {
.name = "mc13xxx",
- .bus = &spi_bus_type,
.owner = THIS_MODULE,
+ .of_match_table = mc13xxx_dt_ids,
},
.probe = mc13xxx_probe,
.remove = __devexit_p(mc13xxx_remove),
diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c
index 84815f9ef63..63be60bc345 100644
--- a/drivers/mfd/mcp-core.c
+++ b/drivers/mfd/mcp-core.c
@@ -26,9 +26,35 @@
#define to_mcp(d) container_of(d, struct mcp, attached_device)
#define to_mcp_driver(d) container_of(d, struct mcp_driver, drv)
+static const struct mcp_device_id *mcp_match_id(const struct mcp_device_id *id,
+ const char *codec)
+{
+ while (id->name[0]) {
+ if (strcmp(codec, id->name) == 0)
+ return id;
+ id++;
+ }
+ return NULL;
+}
+
+const struct mcp_device_id *mcp_get_device_id(const struct mcp *mcp)
+{
+ const struct mcp_driver *driver =
+ to_mcp_driver(mcp->attached_device.driver);
+
+ return mcp_match_id(driver->id_table, mcp->codec);
+}
+EXPORT_SYMBOL(mcp_get_device_id);
+
static int mcp_bus_match(struct device *dev, struct device_driver *drv)
{
- return 1;
+ const struct mcp *mcp = to_mcp(dev);
+ const struct mcp_driver *driver = to_mcp_driver(drv);
+
+ if (driver->id_table)
+ return !!mcp_match_id(driver->id_table, mcp->codec);
+
+ return 0;
}
static int mcp_bus_probe(struct device *dev)
@@ -74,9 +100,18 @@ static int mcp_bus_resume(struct device *dev)
return ret;
}
+static int mcp_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct mcp *mcp = to_mcp(dev);
+
+ add_uevent_var(env, "MODALIAS=%s%s", MCP_MODULE_PREFIX, mcp->codec);
+ return 0;
+}
+
static struct bus_type mcp_bus_type = {
.name = "mcp",
.match = mcp_bus_match,
+ .uevent = mcp_bus_uevent,
.probe = mcp_bus_probe,
.remove = mcp_bus_remove,
.suspend = mcp_bus_suspend,
@@ -212,9 +247,14 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
}
EXPORT_SYMBOL(mcp_host_alloc);
-int mcp_host_register(struct mcp *mcp)
+int mcp_host_register(struct mcp *mcp, void *pdata)
{
+ if (!mcp->codec)
+ return -EINVAL;
+
+ mcp->attached_device.platform_data = pdata;
dev_set_name(&mcp->attached_device, "mcp0");
+ request_module("%s%s", MCP_MODULE_PREFIX, mcp->codec);
return device_register(&mcp->attached_device);
}
EXPORT_SYMBOL(mcp_host_register);
diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
index 2dab02d9ac8..9adc2eb6949 100644
--- a/drivers/mfd/mcp-sa11x0.c
+++ b/drivers/mfd/mcp-sa11x0.c
@@ -19,6 +19,7 @@
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/mfd/mcp.h>
+#include <linux/io.h>
#include <mach/dma.h>
#include <mach/hardware.h>
@@ -26,12 +27,19 @@
#include <asm/system.h>
#include <mach/mcp.h>
-#include <mach/assabet.h>
-
+/* Register offsets */
+#define MCCR0 0x00
+#define MCDR0 0x08
+#define MCDR1 0x0C
+#define MCDR2 0x10
+#define MCSR 0x18
+#define MCCR1 0x00
struct mcp_sa11x0 {
- u32 mccr0;
- u32 mccr1;
+ u32 mccr0;
+ u32 mccr1;
+ unsigned char *mccr0_base;
+ unsigned char *mccr1_base;
};
#define priv(mcp) ((struct mcp_sa11x0 *)mcp_priv(mcp))
@@ -39,25 +47,25 @@ struct mcp_sa11x0 {
static void
mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
{
- unsigned int mccr0;
+ struct mcp_sa11x0 *priv = priv(mcp);
divisor /= 32;
- mccr0 = Ser4MCCR0 & ~0x00007f00;
- mccr0 |= divisor << 8;
- Ser4MCCR0 = mccr0;
+ priv->mccr0 &= ~0x00007f00;
+ priv->mccr0 |= divisor << 8;
+ __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
}
static void
mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
{
- unsigned int mccr0;
+ struct mcp_sa11x0 *priv = priv(mcp);
divisor /= 32;
- mccr0 = Ser4MCCR0 & ~0x0000007f;
- mccr0 |= divisor;
- Ser4MCCR0 = mccr0;
+ priv->mccr0 &= ~0x0000007f;
+ priv->mccr0 |= divisor;
+ __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
}
/*
@@ -71,12 +79,16 @@ mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
{
int ret = -ETIME;
int i;
+ u32 mcpreg;
+ struct mcp_sa11x0 *priv = priv(mcp);
- Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff);
+ mcpreg = reg << 17 | MCDR2_Wr | (val & 0xffff);
+ __raw_writel(mcpreg, priv->mccr0_base + MCDR2);
for (i = 0; i < 2; i++) {
udelay(mcp->rw_timeout);
- if (Ser4MCSR & MCSR_CWC) {
+ mcpreg = __raw_readl(priv->mccr0_base + MCSR);
+ if (mcpreg & MCSR_CWC) {
ret = 0;
break;
}
@@ -97,13 +109,18 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
{
int ret = -ETIME;
int i;
+ u32 mcpreg;
+ struct mcp_sa11x0 *priv = priv(mcp);
- Ser4MCDR2 = reg << 17 | MCDR2_Rd;
+ mcpreg = reg << 17 | MCDR2_Rd;
+ __raw_writel(mcpreg, priv->mccr0_base + MCDR2);
for (i = 0; i < 2; i++) {
udelay(mcp->rw_timeout);
- if (Ser4MCSR & MCSR_CRC) {
- ret = Ser4MCDR2 & 0xffff;
+ mcpreg = __raw_readl(priv->mccr0_base + MCSR);
+ if (mcpreg & MCSR_CRC) {
+ ret = __raw_readl(priv->mccr0_base + MCDR2)
+ & 0xffff;
break;
}
}
@@ -116,13 +133,19 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
static void mcp_sa11x0_enable(struct mcp *mcp)
{
- Ser4MCSR = -1;
- Ser4MCCR0 |= MCCR0_MCE;
+ struct mcp_sa11x0 *priv = priv(mcp);
+
+ __raw_writel(-1, priv->mccr0_base + MCSR);
+ priv->mccr0 |= MCCR0_MCE;
+ __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
}
static void mcp_sa11x0_disable(struct mcp *mcp)
{
- Ser4MCCR0 &= ~MCCR0_MCE;
+ struct mcp_sa11x0 *priv = priv(mcp);
+
+ priv->mccr0 &= ~MCCR0_MCE;
+ __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
}
/*
@@ -142,50 +165,69 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
struct mcp_plat_data *data = pdev->dev.platform_data;
struct mcp *mcp;
int ret;
+ struct mcp_sa11x0 *priv;
+ struct resource *res_mem0, *res_mem1;
+ u32 size0, size1;
if (!data)
return -ENODEV;
- if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp"))
+ if (!data->codec)
+ return -ENODEV;
+
+ res_mem0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res_mem0)
+ return -ENODEV;
+ size0 = res_mem0->end - res_mem0->start + 1;
+
+ res_mem1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res_mem1)
+ return -ENODEV;
+ size1 = res_mem1->end - res_mem1->start + 1;
+
+ if (!request_mem_region(res_mem0->start, size0, "sa11x0-mcp"))
return -EBUSY;
+ if (!request_mem_region(res_mem1->start, size1, "sa11x0-mcp")) {
+ ret = -EBUSY;
+ goto release;
+ }
+
mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0));
if (!mcp) {
ret = -ENOMEM;
- goto release;
+ goto release2;
}
+ priv = priv(mcp);
+
mcp->owner = THIS_MODULE;
mcp->ops = &mcp_sa11x0;
mcp->sclk_rate = data->sclk_rate;
- mcp->dma_audio_rd = DMA_Ser4MCP0Rd;
- mcp->dma_audio_wr = DMA_Ser4MCP0Wr;
- mcp->dma_telco_rd = DMA_Ser4MCP1Rd;
- mcp->dma_telco_wr = DMA_Ser4MCP1Wr;
- mcp->gpio_base = data->gpio_base;
+ mcp->dma_audio_rd = DDAR_DevAdd(res_mem0->start + MCDR0)
+ + DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev;
+ mcp->dma_audio_wr = DDAR_DevAdd(res_mem0->start + MCDR0)
+ + DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev;
+ mcp->dma_telco_rd = DDAR_DevAdd(res_mem0->start + MCDR1)
+ + DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev;
+ mcp->dma_telco_wr = DDAR_DevAdd(res_mem0->start + MCDR1)
+ + DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev;
+ mcp->codec = data->codec;
platform_set_drvdata(pdev, mcp);
- if (machine_is_assabet()) {
- ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
- }
-
- /*
- * Setup the PPC unit correctly.
- */
- PPDR &= ~PPC_RXD4;
- PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
- PSDR |= PPC_RXD4;
- PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
- PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
-
/*
* Initialise device. Note that we initially
* set the sampling rate to minimum.
*/
- Ser4MCSR = -1;
- Ser4MCCR1 = data->mccr1;
- Ser4MCCR0 = data->mccr0 | 0x7f7f;
+ priv->mccr0_base = ioremap(res_mem0->start, size0);
+ priv->mccr1_base = ioremap(res_mem1->start, size1);
+
+ __raw_writel(-1, priv->mccr0_base + MCSR);
+ priv->mccr1 = data->mccr1;
+ priv->mccr0 = data->mccr0 | 0x7f7f;
+ __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
+ __raw_writel(priv->mccr1, priv->mccr1_base + MCCR1);
/*
* Calculate the read/write timeout (us) from the bit clock
@@ -195,36 +237,53 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
mcp->sclk_rate;
- ret = mcp_host_register(mcp);
+ ret = mcp_host_register(mcp, data->codec_pdata);
if (ret == 0)
goto out;
+ release2:
+ release_mem_region(res_mem1->start, size1);
release:
- release_mem_region(0x80060000, 0x60);
+ release_mem_region(res_mem0->start, size0);
platform_set_drvdata(pdev, NULL);
out:
return ret;
}
-static int mcp_sa11x0_remove(struct platform_device *dev)
+static int mcp_sa11x0_remove(struct platform_device *pdev)
{
- struct mcp *mcp = platform_get_drvdata(dev);
+ struct mcp *mcp = platform_get_drvdata(pdev);
+ struct mcp_sa11x0 *priv = priv(mcp);
+ struct resource *res_mem;
+ u32 size;
- platform_set_drvdata(dev, NULL);
+ platform_set_drvdata(pdev, NULL);
mcp_host_unregister(mcp);
- release_mem_region(0x80060000, 0x60);
+ res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res_mem) {
+ size = res_mem->end - res_mem->start + 1;
+ release_mem_region(res_mem->start, size);
+ }
+ res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (res_mem) {
+ size = res_mem->end - res_mem->start + 1;
+ release_mem_region(res_mem->start, size);
+ }
+ iounmap(priv->mccr0_base);
+ iounmap(priv->mccr1_base);
return 0;
}
static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
{
struct mcp *mcp = platform_get_drvdata(dev);
+ struct mcp_sa11x0 *priv = priv(mcp);
+ u32 mccr0;
- priv(mcp)->mccr0 = Ser4MCCR0;
- priv(mcp)->mccr1 = Ser4MCCR1;
- Ser4MCCR0 &= ~MCCR0_MCE;
+ mccr0 = priv->mccr0 & ~MCCR0_MCE;
+ __raw_writel(mccr0, priv->mccr0_base + MCCR0);
return 0;
}
@@ -232,9 +291,10 @@ static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
static int mcp_sa11x0_resume(struct platform_device *dev)
{
struct mcp *mcp = platform_get_drvdata(dev);
+ struct mcp_sa11x0 *priv = priv(mcp);
- Ser4MCCR1 = priv(mcp)->mccr1;
- Ser4MCCR0 = priv(mcp)->mccr0;
+ __raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
+ __raw_writel(priv->mccr1, priv->mccr1_base + MCCR1);
return 0;
}
@@ -251,24 +311,14 @@ static struct platform_driver mcp_sa11x0_driver = {
.resume = mcp_sa11x0_resume,
.driver = {
.name = "sa11x0-mcp",
+ .owner = THIS_MODULE,
},
};
/*
* This needs re-working
*/
-static int __init mcp_sa11x0_init(void)
-{
- return platform_driver_register(&mcp_sa11x0_driver);
-}
-
-static void __exit mcp_sa11x0_exit(void)
-{
- platform_driver_unregister(&mcp_sa11x0_driver);
-}
-
-module_init(mcp_sa11x0_init);
-module_exit(mcp_sa11x0_exit);
+module_platform_driver(mcp_sa11x0_driver);
MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 86e14583a08..68ac2c55d5a 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -27,8 +27,9 @@
#include <linux/spinlock.h>
#include <linux/gpio.h>
#include <plat/usb.h>
+#include <linux/pm_runtime.h>
-#define USBHS_DRIVER_NAME "usbhs-omap"
+#define USBHS_DRIVER_NAME "usbhs_omap"
#define OMAP_EHCI_DEVICE "ehci-omap"
#define OMAP_OHCI_DEVICE "ohci-omap3"
@@ -147,9 +148,6 @@
struct usbhs_hcd_omap {
- struct clk *usbhost_ick;
- struct clk *usbhost_hs_fck;
- struct clk *usbhost_fs_fck;
struct clk *xclk60mhsp1_ck;
struct clk *xclk60mhsp2_ck;
struct clk *utmi_p1_fck;
@@ -159,8 +157,7 @@ struct usbhs_hcd_omap {
struct clk *usbhost_p2_fck;
struct clk *usbtll_p2_fck;
struct clk *init_60m_fclk;
- struct clk *usbtll_fck;
- struct clk *usbtll_ick;
+ struct clk *ehci_logic_fck;
void __iomem *uhh_base;
void __iomem *tll_base;
@@ -169,7 +166,6 @@ struct usbhs_hcd_omap {
u32 usbhs_rev;
spinlock_t lock;
- int count;
};
/*-------------------------------------------------------------------------*/
@@ -319,269 +315,6 @@ err_end:
return ret;
}
-/**
- * usbhs_omap_probe - initialize TI-based HCDs
- *
- * Allocates basic resources for this USB host controller.
- */
-static int __devinit usbhs_omap_probe(struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct usbhs_omap_platform_data *pdata = dev->platform_data;
- struct usbhs_hcd_omap *omap;
- struct resource *res;
- int ret = 0;
- int i;
-
- if (!pdata) {
- dev_err(dev, "Missing platform data\n");
- ret = -ENOMEM;
- goto end_probe;
- }
-
- omap = kzalloc(sizeof(*omap), GFP_KERNEL);
- if (!omap) {
- dev_err(dev, "Memory allocation failed\n");
- ret = -ENOMEM;
- goto end_probe;
- }
-
- spin_lock_init(&omap->lock);
-
- for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
- omap->platdata.port_mode[i] = pdata->port_mode[i];
-
- omap->platdata.ehci_data = pdata->ehci_data;
- omap->platdata.ohci_data = pdata->ohci_data;
-
- omap->usbhost_ick = clk_get(dev, "usbhost_ick");
- if (IS_ERR(omap->usbhost_ick)) {
- ret = PTR_ERR(omap->usbhost_ick);
- dev_err(dev, "usbhost_ick failed error:%d\n", ret);
- goto err_end;
- }
-
- omap->usbhost_hs_fck = clk_get(dev, "hs_fck");
- if (IS_ERR(omap->usbhost_hs_fck)) {
- ret = PTR_ERR(omap->usbhost_hs_fck);
- dev_err(dev, "usbhost_hs_fck failed error:%d\n", ret);
- goto err_usbhost_ick;
- }
-
- omap->usbhost_fs_fck = clk_get(dev, "fs_fck");
- if (IS_ERR(omap->usbhost_fs_fck)) {
- ret = PTR_ERR(omap->usbhost_fs_fck);
- dev_err(dev, "usbhost_fs_fck failed error:%d\n", ret);
- goto err_usbhost_hs_fck;
- }
-
- omap->usbtll_fck = clk_get(dev, "usbtll_fck");
- if (IS_ERR(omap->usbtll_fck)) {
- ret = PTR_ERR(omap->usbtll_fck);
- dev_err(dev, "usbtll_fck failed error:%d\n", ret);
- goto err_usbhost_fs_fck;
- }
-
- omap->usbtll_ick = clk_get(dev, "usbtll_ick");
- if (IS_ERR(omap->usbtll_ick)) {
- ret = PTR_ERR(omap->usbtll_ick);
- dev_err(dev, "usbtll_ick failed error:%d\n", ret);
- goto err_usbtll_fck;
- }
-
- omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
- if (IS_ERR(omap->utmi_p1_fck)) {
- ret = PTR_ERR(omap->utmi_p1_fck);
- dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
- goto err_usbtll_ick;
- }
-
- omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
- if (IS_ERR(omap->xclk60mhsp1_ck)) {
- ret = PTR_ERR(omap->xclk60mhsp1_ck);
- dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret);
- goto err_utmi_p1_fck;
- }
-
- omap->utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk");
- if (IS_ERR(omap->utmi_p2_fck)) {
- ret = PTR_ERR(omap->utmi_p2_fck);
- dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
- goto err_xclk60mhsp1_ck;
- }
-
- omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
- if (IS_ERR(omap->xclk60mhsp2_ck)) {
- ret = PTR_ERR(omap->xclk60mhsp2_ck);
- dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret);
- goto err_utmi_p2_fck;
- }
-
- omap->usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk");
- if (IS_ERR(omap->usbhost_p1_fck)) {
- ret = PTR_ERR(omap->usbhost_p1_fck);
- dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret);
- goto err_xclk60mhsp2_ck;
- }
-
- omap->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk");
- if (IS_ERR(omap->usbtll_p1_fck)) {
- ret = PTR_ERR(omap->usbtll_p1_fck);
- dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret);
- goto err_usbhost_p1_fck;
- }
-
- omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk");
- if (IS_ERR(omap->usbhost_p2_fck)) {
- ret = PTR_ERR(omap->usbhost_p2_fck);
- dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret);
- goto err_usbtll_p1_fck;
- }
-
- omap->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk");
- if (IS_ERR(omap->usbtll_p2_fck)) {
- ret = PTR_ERR(omap->usbtll_p2_fck);
- dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret);
- goto err_usbhost_p2_fck;
- }
-
- omap->init_60m_fclk = clk_get(dev, "init_60m_fclk");
- if (IS_ERR(omap->init_60m_fclk)) {
- ret = PTR_ERR(omap->init_60m_fclk);
- dev_err(dev, "init_60m_fclk failed error:%d\n", ret);
- goto err_usbtll_p2_fck;
- }
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh");
- if (!res) {
- dev_err(dev, "UHH EHCI get resource failed\n");
- ret = -ENODEV;
- goto err_init_60m_fclk;
- }
-
- omap->uhh_base = ioremap(res->start, resource_size(res));
- if (!omap->uhh_base) {
- dev_err(dev, "UHH ioremap failed\n");
- ret = -ENOMEM;
- goto err_init_60m_fclk;
- }
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tll");
- if (!res) {
- dev_err(dev, "UHH EHCI get resource failed\n");
- ret = -ENODEV;
- goto err_tll;
- }
-
- omap->tll_base = ioremap(res->start, resource_size(res));
- if (!omap->tll_base) {
- dev_err(dev, "TLL ioremap failed\n");
- ret = -ENOMEM;
- goto err_tll;
- }
-
- platform_set_drvdata(pdev, omap);
-
- ret = omap_usbhs_alloc_children(pdev);
- if (ret) {
- dev_err(dev, "omap_usbhs_alloc_children failed\n");
- goto err_alloc;
- }
-
- goto end_probe;
-
-err_alloc:
- iounmap(omap->tll_base);
-
-err_tll:
- iounmap(omap->uhh_base);
-
-err_init_60m_fclk:
- clk_put(omap->init_60m_fclk);
-
-err_usbtll_p2_fck:
- clk_put(omap->usbtll_p2_fck);
-
-err_usbhost_p2_fck:
- clk_put(omap->usbhost_p2_fck);
-
-err_usbtll_p1_fck:
- clk_put(omap->usbtll_p1_fck);
-
-err_usbhost_p1_fck:
- clk_put(omap->usbhost_p1_fck);
-
-err_xclk60mhsp2_ck:
- clk_put(omap->xclk60mhsp2_ck);
-
-err_utmi_p2_fck:
- clk_put(omap->utmi_p2_fck);
-
-err_xclk60mhsp1_ck:
- clk_put(omap->xclk60mhsp1_ck);
-
-err_utmi_p1_fck:
- clk_put(omap->utmi_p1_fck);
-
-err_usbtll_ick:
- clk_put(omap->usbtll_ick);
-
-err_usbtll_fck:
- clk_put(omap->usbtll_fck);
-
-err_usbhost_fs_fck:
- clk_put(omap->usbhost_fs_fck);
-
-err_usbhost_hs_fck:
- clk_put(omap->usbhost_hs_fck);
-
-err_usbhost_ick:
- clk_put(omap->usbhost_ick);
-
-err_end:
- kfree(omap);
-
-end_probe:
- return ret;
-}
-
-/**
- * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs
- * @pdev: USB Host Controller being removed
- *
- * Reverses the effect of usbhs_omap_probe().
- */
-static int __devexit usbhs_omap_remove(struct platform_device *pdev)
-{
- struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev);
-
- if (omap->count != 0) {
- dev_err(&pdev->dev,
- "Either EHCI or OHCI is still using usbhs core\n");
- return -EBUSY;
- }
-
- iounmap(omap->tll_base);
- iounmap(omap->uhh_base);
- clk_put(omap->init_60m_fclk);
- clk_put(omap->usbtll_p2_fck);
- clk_put(omap->usbhost_p2_fck);
- clk_put(omap->usbtll_p1_fck);
- clk_put(omap->usbhost_p1_fck);
- clk_put(omap->xclk60mhsp2_ck);
- clk_put(omap->utmi_p2_fck);
- clk_put(omap->xclk60mhsp1_ck);
- clk_put(omap->utmi_p1_fck);
- clk_put(omap->usbtll_ick);
- clk_put(omap->usbtll_fck);
- clk_put(omap->usbhost_fs_fck);
- clk_put(omap->usbhost_hs_fck);
- clk_put(omap->usbhost_ick);
- kfree(omap);
-
- return 0;
-}
-
static bool is_ohci_port(enum usbhs_omap_port_mode pmode)
{
switch (pmode) {
@@ -689,96 +422,101 @@ static void usbhs_omap_tll_init(struct device *dev, u8 tll_channel_count)
}
}
-static int usbhs_enable(struct device *dev)
+static int usbhs_runtime_resume(struct device *dev)
{
struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
struct usbhs_omap_platform_data *pdata = &omap->platdata;
- unsigned long flags = 0;
- int ret = 0;
- unsigned long timeout;
- unsigned reg;
+ unsigned long flags;
+
+ dev_dbg(dev, "usbhs_runtime_resume\n");
- dev_dbg(dev, "starting TI HSUSB Controller\n");
if (!pdata) {
dev_dbg(dev, "missing platform_data\n");
return -ENODEV;
}
spin_lock_irqsave(&omap->lock, flags);
- if (omap->count > 0)
- goto end_count;
- clk_enable(omap->usbhost_ick);
- clk_enable(omap->usbhost_hs_fck);
- clk_enable(omap->usbhost_fs_fck);
- clk_enable(omap->usbtll_fck);
- clk_enable(omap->usbtll_ick);
+ if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck))
+ clk_enable(omap->ehci_logic_fck);
- if (pdata->ehci_data->phy_reset) {
- if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) {
- gpio_request(pdata->ehci_data->reset_gpio_port[0],
- "USB1 PHY reset");
- gpio_direction_output
- (pdata->ehci_data->reset_gpio_port[0], 0);
- }
+ if (is_ehci_tll_mode(pdata->port_mode[0])) {
+ clk_enable(omap->usbhost_p1_fck);
+ clk_enable(omap->usbtll_p1_fck);
+ }
+ if (is_ehci_tll_mode(pdata->port_mode[1])) {
+ clk_enable(omap->usbhost_p2_fck);
+ clk_enable(omap->usbtll_p2_fck);
+ }
+ clk_enable(omap->utmi_p1_fck);
+ clk_enable(omap->utmi_p2_fck);
- if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) {
- gpio_request(pdata->ehci_data->reset_gpio_port[1],
- "USB2 PHY reset");
- gpio_direction_output
- (pdata->ehci_data->reset_gpio_port[1], 0);
- }
+ spin_unlock_irqrestore(&omap->lock, flags);
- /* Hold the PHY in RESET for enough time till DIR is high */
- udelay(10);
- }
+ return 0;
+}
- omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
- dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev);
+static int usbhs_runtime_suspend(struct device *dev)
+{
+ struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
+ struct usbhs_omap_platform_data *pdata = &omap->platdata;
+ unsigned long flags;
- /* perform TLL soft reset, and wait until reset is complete */
- usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
- OMAP_USBTLL_SYSCONFIG_SOFTRESET);
+ dev_dbg(dev, "usbhs_runtime_suspend\n");
- /* Wait for TLL reset to complete */
- timeout = jiffies + msecs_to_jiffies(1000);
- while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
- & OMAP_USBTLL_SYSSTATUS_RESETDONE)) {
- cpu_relax();
+ if (!pdata) {
+ dev_dbg(dev, "missing platform_data\n");
+ return -ENODEV;
+ }
- if (time_after(jiffies, timeout)) {
- dev_dbg(dev, "operation timed out\n");
- ret = -EINVAL;
- goto err_tll;
- }
+ spin_lock_irqsave(&omap->lock, flags);
+
+ if (is_ehci_tll_mode(pdata->port_mode[0])) {
+ clk_disable(omap->usbhost_p1_fck);
+ clk_disable(omap->usbtll_p1_fck);
+ }
+ if (is_ehci_tll_mode(pdata->port_mode[1])) {
+ clk_disable(omap->usbhost_p2_fck);
+ clk_disable(omap->usbtll_p2_fck);
}
+ clk_disable(omap->utmi_p2_fck);
+ clk_disable(omap->utmi_p1_fck);
- dev_dbg(dev, "TLL RESET DONE\n");
+ if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck))
+ clk_disable(omap->ehci_logic_fck);
- /* (1<<3) = no idle mode only for initial debugging */
- usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG,
- OMAP_USBTLL_SYSCONFIG_ENAWAKEUP |
- OMAP_USBTLL_SYSCONFIG_SIDLEMODE |
- OMAP_USBTLL_SYSCONFIG_AUTOIDLE);
+ spin_unlock_irqrestore(&omap->lock, flags);
- /* Put UHH in NoIdle/NoStandby mode */
- reg = usbhs_read(omap->uhh_base, OMAP_UHH_SYSCONFIG);
- if (is_omap_usbhs_rev1(omap)) {
- reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP
- | OMAP_UHH_SYSCONFIG_SIDLEMODE
- | OMAP_UHH_SYSCONFIG_CACTIVITY
- | OMAP_UHH_SYSCONFIG_MIDLEMODE);
- reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE;
+ return 0;
+}
+
+static void omap_usbhs_init(struct device *dev)
+{
+ struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
+ struct usbhs_omap_platform_data *pdata = &omap->platdata;
+ unsigned long flags;
+ unsigned reg;
+ dev_dbg(dev, "starting TI HSUSB Controller\n");
- } else if (is_omap_usbhs_rev2(omap)) {
- reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR;
- reg |= OMAP4_UHH_SYSCONFIG_NOIDLE;
- reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR;
- reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY;
+ pm_runtime_get_sync(dev);
+ spin_lock_irqsave(&omap->lock, flags);
+
+ if (pdata->ehci_data->phy_reset) {
+ if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
+ gpio_request_one(pdata->ehci_data->reset_gpio_port[0],
+ GPIOF_OUT_INIT_LOW, "USB1 PHY reset");
+
+ if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
+ gpio_request_one(pdata->ehci_data->reset_gpio_port[1],
+ GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
+
+ /* Hold the PHY in RESET for enough time till DIR is high */
+ udelay(10);
}
- usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);
+ omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION);
+ dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev);
reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
/* setup ULPI bypass and burst configurations */
@@ -825,49 +563,6 @@ static int usbhs_enable(struct device *dev)
reg &= ~OMAP4_P1_MODE_CLEAR;
reg &= ~OMAP4_P2_MODE_CLEAR;
- if (is_ehci_phy_mode(pdata->port_mode[0])) {
- ret = clk_set_parent(omap->utmi_p1_fck,
- omap->xclk60mhsp1_ck);
- if (ret != 0) {
- dev_err(dev, "xclk60mhsp1_ck set parent"
- "failed error:%d\n", ret);
- goto err_tll;
- }
- } else if (is_ehci_tll_mode(pdata->port_mode[0])) {
- ret = clk_set_parent(omap->utmi_p1_fck,
- omap->init_60m_fclk);
- if (ret != 0) {
- dev_err(dev, "init_60m_fclk set parent"
- "failed error:%d\n", ret);
- goto err_tll;
- }
- clk_enable(omap->usbhost_p1_fck);
- clk_enable(omap->usbtll_p1_fck);
- }
-
- if (is_ehci_phy_mode(pdata->port_mode[1])) {
- ret = clk_set_parent(omap->utmi_p2_fck,
- omap->xclk60mhsp2_ck);
- if (ret != 0) {
- dev_err(dev, "xclk60mhsp1_ck set parent"
- "failed error:%d\n", ret);
- goto err_tll;
- }
- } else if (is_ehci_tll_mode(pdata->port_mode[1])) {
- ret = clk_set_parent(omap->utmi_p2_fck,
- omap->init_60m_fclk);
- if (ret != 0) {
- dev_err(dev, "init_60m_fclk set parent"
- "failed error:%d\n", ret);
- goto err_tll;
- }
- clk_enable(omap->usbhost_p2_fck);
- clk_enable(omap->usbtll_p2_fck);
- }
-
- clk_enable(omap->utmi_p1_fck);
- clk_enable(omap->utmi_p2_fck);
-
if (is_ehci_tll_mode(pdata->port_mode[0]) ||
(is_ohci_port(pdata->port_mode[0])))
reg |= OMAP4_P1_MODE_TLL;
@@ -913,12 +608,15 @@ static int usbhs_enable(struct device *dev)
(pdata->ehci_data->reset_gpio_port[1], 1);
}
-end_count:
- omap->count++;
spin_unlock_irqrestore(&omap->lock, flags);
- return 0;
+ pm_runtime_put_sync(dev);
+}
+
+static void omap_usbhs_deinit(struct device *dev)
+{
+ struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
+ struct usbhs_omap_platform_data *pdata = &omap->platdata;
-err_tll:
if (pdata->ehci_data->phy_reset) {
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
gpio_free(pdata->ehci_data->reset_gpio_port[0]);
@@ -926,123 +624,272 @@ err_tll:
if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
gpio_free(pdata->ehci_data->reset_gpio_port[1]);
}
-
- clk_disable(omap->usbtll_ick);
- clk_disable(omap->usbtll_fck);
- clk_disable(omap->usbhost_fs_fck);
- clk_disable(omap->usbhost_hs_fck);
- clk_disable(omap->usbhost_ick);
- spin_unlock_irqrestore(&omap->lock, flags);
- return ret;
}
-static void usbhs_disable(struct device *dev)
+
+/**
+ * usbhs_omap_probe - initialize TI-based HCDs
+ *
+ * Allocates basic resources for this USB host controller.
+ */
+static int __devinit usbhs_omap_probe(struct platform_device *pdev)
{
- struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
- struct usbhs_omap_platform_data *pdata = &omap->platdata;
- unsigned long flags = 0;
- unsigned long timeout;
+ struct device *dev = &pdev->dev;
+ struct usbhs_omap_platform_data *pdata = dev->platform_data;
+ struct usbhs_hcd_omap *omap;
+ struct resource *res;
+ int ret = 0;
+ int i;
- dev_dbg(dev, "stopping TI HSUSB Controller\n");
+ if (!pdata) {
+ dev_err(dev, "Missing platform data\n");
+ ret = -ENOMEM;
+ goto end_probe;
+ }
- spin_lock_irqsave(&omap->lock, flags);
+ omap = kzalloc(sizeof(*omap), GFP_KERNEL);
+ if (!omap) {
+ dev_err(dev, "Memory allocation failed\n");
+ ret = -ENOMEM;
+ goto end_probe;
+ }
- if (omap->count == 0)
- goto end_disble;
+ spin_lock_init(&omap->lock);
- omap->count--;
+ for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
+ omap->platdata.port_mode[i] = pdata->port_mode[i];
- if (omap->count != 0)
- goto end_disble;
+ omap->platdata.ehci_data = pdata->ehci_data;
+ omap->platdata.ohci_data = pdata->ohci_data;
+
+ pm_runtime_enable(dev);
- /* Reset OMAP modules for insmod/rmmod to work */
- usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG,
- is_omap_usbhs_rev2(omap) ?
- OMAP4_UHH_SYSCONFIG_SOFTRESET :
- OMAP_UHH_SYSCONFIG_SOFTRESET);
- timeout = jiffies + msecs_to_jiffies(100);
- while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS)
- & (1 << 0))) {
- cpu_relax();
+ for (i = 0; i < OMAP3_HS_USB_PORTS; i++)
+ if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) ||
+ is_ehci_hsic_mode(i)) {
+ omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck");
+ if (IS_ERR(omap->ehci_logic_fck)) {
+ ret = PTR_ERR(omap->ehci_logic_fck);
+ dev_warn(dev, "ehci_logic_fck failed:%d\n",
+ ret);
+ }
+ break;
+ }
- if (time_after(jiffies, timeout))
- dev_dbg(dev, "operation timed out\n");
+ omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
+ if (IS_ERR(omap->utmi_p1_fck)) {
+ ret = PTR_ERR(omap->utmi_p1_fck);
+ dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
+ goto err_end;
}
- while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS)
- & (1 << 1))) {
- cpu_relax();
+ omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
+ if (IS_ERR(omap->xclk60mhsp1_ck)) {
+ ret = PTR_ERR(omap->xclk60mhsp1_ck);
+ dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret);
+ goto err_utmi_p1_fck;
+ }
+
+ omap->utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk");
+ if (IS_ERR(omap->utmi_p2_fck)) {
+ ret = PTR_ERR(omap->utmi_p2_fck);
+ dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
+ goto err_xclk60mhsp1_ck;
+ }
+
+ omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
+ if (IS_ERR(omap->xclk60mhsp2_ck)) {
+ ret = PTR_ERR(omap->xclk60mhsp2_ck);
+ dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret);
+ goto err_utmi_p2_fck;
+ }
- if (time_after(jiffies, timeout))
- dev_dbg(dev, "operation timed out\n");
+ omap->usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk");
+ if (IS_ERR(omap->usbhost_p1_fck)) {
+ ret = PTR_ERR(omap->usbhost_p1_fck);
+ dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret);
+ goto err_xclk60mhsp2_ck;
+ }
+
+ omap->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk");
+ if (IS_ERR(omap->usbtll_p1_fck)) {
+ ret = PTR_ERR(omap->usbtll_p1_fck);
+ dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret);
+ goto err_usbhost_p1_fck;
+ }
+
+ omap->usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk");
+ if (IS_ERR(omap->usbhost_p2_fck)) {
+ ret = PTR_ERR(omap->usbhost_p2_fck);
+ dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret);
+ goto err_usbtll_p1_fck;
}
- while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS)
- & (1 << 2))) {
- cpu_relax();
+ omap->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk");
+ if (IS_ERR(omap->usbtll_p2_fck)) {
+ ret = PTR_ERR(omap->usbtll_p2_fck);
+ dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret);
+ goto err_usbhost_p2_fck;
+ }
- if (time_after(jiffies, timeout))
- dev_dbg(dev, "operation timed out\n");
+ omap->init_60m_fclk = clk_get(dev, "init_60m_fclk");
+ if (IS_ERR(omap->init_60m_fclk)) {
+ ret = PTR_ERR(omap->init_60m_fclk);
+ dev_err(dev, "init_60m_fclk failed error:%d\n", ret);
+ goto err_usbtll_p2_fck;
}
- usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, (1 << 1));
+ if (is_ehci_phy_mode(pdata->port_mode[0])) {
+ /* for OMAP3 , the clk set paretn fails */
+ ret = clk_set_parent(omap->utmi_p1_fck,
+ omap->xclk60mhsp1_ck);
+ if (ret != 0)
+ dev_err(dev, "xclk60mhsp1_ck set parent"
+ "failed error:%d\n", ret);
+ } else if (is_ehci_tll_mode(pdata->port_mode[0])) {
+ ret = clk_set_parent(omap->utmi_p1_fck,
+ omap->init_60m_fclk);
+ if (ret != 0)
+ dev_err(dev, "init_60m_fclk set parent"
+ "failed error:%d\n", ret);
+ }
- while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS)
- & (1 << 0))) {
- cpu_relax();
+ if (is_ehci_phy_mode(pdata->port_mode[1])) {
+ ret = clk_set_parent(omap->utmi_p2_fck,
+ omap->xclk60mhsp2_ck);
+ if (ret != 0)
+ dev_err(dev, "xclk60mhsp2_ck set parent"
+ "failed error:%d\n", ret);
+ } else if (is_ehci_tll_mode(pdata->port_mode[1])) {
+ ret = clk_set_parent(omap->utmi_p2_fck,
+ omap->init_60m_fclk);
+ if (ret != 0)
+ dev_err(dev, "init_60m_fclk set parent"
+ "failed error:%d\n", ret);
+ }
- if (time_after(jiffies, timeout))
- dev_dbg(dev, "operation timed out\n");
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "uhh");
+ if (!res) {
+ dev_err(dev, "UHH EHCI get resource failed\n");
+ ret = -ENODEV;
+ goto err_init_60m_fclk;
}
- if (is_omap_usbhs_rev2(omap)) {
- if (is_ehci_tll_mode(pdata->port_mode[0]))
- clk_disable(omap->usbtll_p1_fck);
- if (is_ehci_tll_mode(pdata->port_mode[1]))
- clk_disable(omap->usbtll_p2_fck);
- clk_disable(omap->utmi_p2_fck);
- clk_disable(omap->utmi_p1_fck);
+ omap->uhh_base = ioremap(res->start, resource_size(res));
+ if (!omap->uhh_base) {
+ dev_err(dev, "UHH ioremap failed\n");
+ ret = -ENOMEM;
+ goto err_init_60m_fclk;
}
- clk_disable(omap->usbtll_ick);
- clk_disable(omap->usbtll_fck);
- clk_disable(omap->usbhost_fs_fck);
- clk_disable(omap->usbhost_hs_fck);
- clk_disable(omap->usbhost_ick);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tll");
+ if (!res) {
+ dev_err(dev, "UHH EHCI get resource failed\n");
+ ret = -ENODEV;
+ goto err_tll;
+ }
- /* The gpio_free migh sleep; so unlock the spinlock */
- spin_unlock_irqrestore(&omap->lock, flags);
+ omap->tll_base = ioremap(res->start, resource_size(res));
+ if (!omap->tll_base) {
+ dev_err(dev, "TLL ioremap failed\n");
+ ret = -ENOMEM;
+ goto err_tll;
+ }
- if (pdata->ehci_data->phy_reset) {
- if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0]))
- gpio_free(pdata->ehci_data->reset_gpio_port[0]);
+ platform_set_drvdata(pdev, omap);
- if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1]))
- gpio_free(pdata->ehci_data->reset_gpio_port[1]);
+ ret = omap_usbhs_alloc_children(pdev);
+ if (ret) {
+ dev_err(dev, "omap_usbhs_alloc_children failed\n");
+ goto err_alloc;
}
- return;
-end_disble:
- spin_unlock_irqrestore(&omap->lock, flags);
-}
+ omap_usbhs_init(dev);
-int omap_usbhs_enable(struct device *dev)
-{
- return usbhs_enable(dev->parent);
+ goto end_probe;
+
+err_alloc:
+ iounmap(omap->tll_base);
+
+err_tll:
+ iounmap(omap->uhh_base);
+
+err_init_60m_fclk:
+ clk_put(omap->init_60m_fclk);
+
+err_usbtll_p2_fck:
+ clk_put(omap->usbtll_p2_fck);
+
+err_usbhost_p2_fck:
+ clk_put(omap->usbhost_p2_fck);
+
+err_usbtll_p1_fck:
+ clk_put(omap->usbtll_p1_fck);
+
+err_usbhost_p1_fck:
+ clk_put(omap->usbhost_p1_fck);
+
+err_xclk60mhsp2_ck:
+ clk_put(omap->xclk60mhsp2_ck);
+
+err_utmi_p2_fck:
+ clk_put(omap->utmi_p2_fck);
+
+err_xclk60mhsp1_ck:
+ clk_put(omap->xclk60mhsp1_ck);
+
+err_utmi_p1_fck:
+ clk_put(omap->utmi_p1_fck);
+
+err_end:
+ clk_put(omap->ehci_logic_fck);
+ pm_runtime_disable(dev);
+ kfree(omap);
+
+end_probe:
+ return ret;
}
-EXPORT_SYMBOL_GPL(omap_usbhs_enable);
-void omap_usbhs_disable(struct device *dev)
+/**
+ * usbhs_omap_remove - shutdown processing for UHH & TLL HCDs
+ * @pdev: USB Host Controller being removed
+ *
+ * Reverses the effect of usbhs_omap_probe().
+ */
+static int __devexit usbhs_omap_remove(struct platform_device *pdev)
{
- usbhs_disable(dev->parent);
+ struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev);
+
+ omap_usbhs_deinit(&pdev->dev);
+ iounmap(omap->tll_base);
+ iounmap(omap->uhh_base);
+ clk_put(omap->init_60m_fclk);
+ clk_put(omap->usbtll_p2_fck);
+ clk_put(omap->usbhost_p2_fck);
+ clk_put(omap->usbtll_p1_fck);
+ clk_put(omap->usbhost_p1_fck);
+ clk_put(omap->xclk60mhsp2_ck);
+ clk_put(omap->utmi_p2_fck);
+ clk_put(omap->xclk60mhsp1_ck);
+ clk_put(omap->utmi_p1_fck);
+ clk_put(omap->ehci_logic_fck);
+ pm_runtime_disable(&pdev->dev);
+ kfree(omap);
+
+ return 0;
}
-EXPORT_SYMBOL_GPL(omap_usbhs_disable);
+
+static const struct dev_pm_ops usbhsomap_dev_pm_ops = {
+ .runtime_suspend = usbhs_runtime_suspend,
+ .runtime_resume = usbhs_runtime_resume,
+};
static struct platform_driver usbhs_omap_driver = {
.driver = {
.name = (char *)usbhs_driver_name,
.owner = THIS_MODULE,
+ .pm = &usbhsomap_dev_pm_ops,
},
.remove = __exit_p(usbhs_omap_remove),
};
diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c
index aed0d2a9b03..3927c17e417 100644
--- a/drivers/mfd/pcf50633-adc.c
+++ b/drivers/mfd/pcf50633-adc.c
@@ -249,17 +249,7 @@ static struct platform_driver pcf50633_adc_driver = {
.remove = __devexit_p(pcf50633_adc_remove),
};
-static int __init pcf50633_adc_init(void)
-{
- return platform_driver_register(&pcf50633_adc_driver);
-}
-module_init(pcf50633_adc_init);
-
-static void __exit pcf50633_adc_exit(void)
-{
- platform_driver_unregister(&pcf50633_adc_driver);
-}
-module_exit(pcf50633_adc_exit);
+module_platform_driver(pcf50633_adc_driver);
MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
MODULE_DESCRIPTION("PCF50633 adc driver");
diff --git a/drivers/mfd/s5m-core.c b/drivers/mfd/s5m-core.c
new file mode 100644
index 00000000000..e075c113eec
--- /dev/null
+++ b/drivers/mfd/s5m-core.c
@@ -0,0 +1,176 @@
+/*
+ * s5m87xx.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ * http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/mutex.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/s5m87xx/s5m-core.h>
+#include <linux/mfd/s5m87xx/s5m-pmic.h>
+#include <linux/mfd/s5m87xx/s5m-rtc.h>
+#include <linux/regmap.h>
+
+static struct mfd_cell s5m87xx_devs[] = {
+ {
+ .name = "s5m8767-pmic",
+ }, {
+ .name = "s5m-rtc",
+ },
+};
+
+int s5m_reg_read(struct s5m87xx_dev *s5m87xx, u8 reg, void *dest)
+{
+ return regmap_read(s5m87xx->regmap, reg, dest);
+}
+EXPORT_SYMBOL_GPL(s5m_reg_read);
+
+int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
+{
+ return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);;
+}
+EXPORT_SYMBOL_GPL(s5m_bulk_read);
+
+int s5m_reg_write(struct s5m87xx_dev *s5m87xx, u8 reg, u8 value)
+{
+ return regmap_write(s5m87xx->regmap, reg, value);
+}
+EXPORT_SYMBOL_GPL(s5m_reg_write);
+
+int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
+{
+ return regmap_raw_write(s5m87xx->regmap, reg, buf, count * sizeof(u16));
+}
+EXPORT_SYMBOL_GPL(s5m_bulk_write);
+
+int s5m_reg_update(struct s5m87xx_dev *s5m87xx, u8 reg, u8 val, u8 mask)
+{
+ return regmap_update_bits(s5m87xx->regmap, reg, mask, val);
+}
+EXPORT_SYMBOL_GPL(s5m_reg_update);
+
+static struct regmap_config s5m_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int s5m87xx_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct s5m_platform_data *pdata = i2c->dev.platform_data;
+ struct s5m87xx_dev *s5m87xx;
+ int ret = 0;
+ int error;
+
+ s5m87xx = kzalloc(sizeof(struct s5m87xx_dev), GFP_KERNEL);
+ if (s5m87xx == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, s5m87xx);
+ s5m87xx->dev = &i2c->dev;
+ s5m87xx->i2c = i2c;
+ s5m87xx->irq = i2c->irq;
+ s5m87xx->type = id->driver_data;
+
+ if (pdata) {
+ s5m87xx->device_type = pdata->device_type;
+ s5m87xx->ono = pdata->ono;
+ s5m87xx->irq_base = pdata->irq_base;
+ s5m87xx->wakeup = pdata->wakeup;
+ }
+
+ s5m87xx->regmap = regmap_init_i2c(i2c, &s5m_regmap_config);
+ if (IS_ERR(s5m87xx->regmap)) {
+ error = PTR_ERR(s5m87xx->regmap);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ error);
+ goto err;
+ }
+
+ s5m87xx->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
+ i2c_set_clientdata(s5m87xx->rtc, s5m87xx);
+
+ if (pdata->cfg_pmic_irq)
+ pdata->cfg_pmic_irq();
+
+ s5m_irq_init(s5m87xx);
+
+ pm_runtime_set_active(s5m87xx->dev);
+
+ ret = mfd_add_devices(s5m87xx->dev, -1,
+ s5m87xx_devs, ARRAY_SIZE(s5m87xx_devs),
+ NULL, 0);
+
+ if (ret < 0)
+ goto err;
+
+ return ret;
+
+err:
+ mfd_remove_devices(s5m87xx->dev);
+ s5m_irq_exit(s5m87xx);
+ i2c_unregister_device(s5m87xx->rtc);
+ regmap_exit(s5m87xx->regmap);
+ kfree(s5m87xx);
+ return ret;
+}
+
+static int s5m87xx_i2c_remove(struct i2c_client *i2c)
+{
+ struct s5m87xx_dev *s5m87xx = i2c_get_clientdata(i2c);
+
+ mfd_remove_devices(s5m87xx->dev);
+ s5m_irq_exit(s5m87xx);
+ i2c_unregister_device(s5m87xx->rtc);
+ regmap_exit(s5m87xx->regmap);
+ kfree(s5m87xx);
+ return 0;
+}
+
+static const struct i2c_device_id s5m87xx_i2c_id[] = {
+ { "s5m87xx", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, s5m87xx_i2c_id);
+
+static struct i2c_driver s5m87xx_i2c_driver = {
+ .driver = {
+ .name = "s5m87xx",
+ .owner = THIS_MODULE,
+ },
+ .probe = s5m87xx_i2c_probe,
+ .remove = s5m87xx_i2c_remove,
+ .id_table = s5m87xx_i2c_id,
+};
+
+static int __init s5m87xx_i2c_init(void)
+{
+ return i2c_add_driver(&s5m87xx_i2c_driver);
+}
+
+subsys_initcall(s5m87xx_i2c_init);
+
+static void __exit s5m87xx_i2c_exit(void)
+{
+ i2c_del_driver(&s5m87xx_i2c_driver);
+}
+module_exit(s5m87xx_i2c_exit);
+
+MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
+MODULE_DESCRIPTION("Core support for the S5M MFD");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/s5m-irq.c b/drivers/mfd/s5m-irq.c
new file mode 100644
index 00000000000..de76dfb6f0a
--- /dev/null
+++ b/drivers/mfd/s5m-irq.c
@@ -0,0 +1,487 @@
+/*
+ * s5m-irq.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd
+ * http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mfd/s5m87xx/s5m-core.h>
+
+struct s5m_irq_data {
+ int reg;
+ int mask;
+};
+
+static struct s5m_irq_data s5m8767_irqs[] = {
+ [S5M8767_IRQ_PWRR] = {
+ .reg = 1,
+ .mask = S5M8767_IRQ_PWRR_MASK,
+ },
+ [S5M8767_IRQ_PWRF] = {
+ .reg = 1,
+ .mask = S5M8767_IRQ_PWRF_MASK,
+ },
+ [S5M8767_IRQ_PWR1S] = {
+ .reg = 1,
+ .mask = S5M8767_IRQ_PWR1S_MASK,
+ },
+ [S5M8767_IRQ_JIGR] = {
+ .reg = 1,
+ .mask = S5M8767_IRQ_JIGR_MASK,
+ },
+ [S5M8767_IRQ_JIGF] = {
+ .reg = 1,
+ .mask = S5M8767_IRQ_JIGF_MASK,
+ },
+ [S5M8767_IRQ_LOWBAT2] = {
+ .reg = 1,
+ .mask = S5M8767_IRQ_LOWBAT2_MASK,
+ },
+ [S5M8767_IRQ_LOWBAT1] = {
+ .reg = 1,
+ .mask = S5M8767_IRQ_LOWBAT1_MASK,
+ },
+ [S5M8767_IRQ_MRB] = {
+ .reg = 2,
+ .mask = S5M8767_IRQ_MRB_MASK,
+ },
+ [S5M8767_IRQ_DVSOK2] = {
+ .reg = 2,
+ .mask = S5M8767_IRQ_DVSOK2_MASK,
+ },
+ [S5M8767_IRQ_DVSOK3] = {
+ .reg = 2,
+ .mask = S5M8767_IRQ_DVSOK3_MASK,
+ },
+ [S5M8767_IRQ_DVSOK4] = {
+ .reg = 2,
+ .mask = S5M8767_IRQ_DVSOK4_MASK,
+ },
+ [S5M8767_IRQ_RTC60S] = {
+ .reg = 3,
+ .mask = S5M8767_IRQ_RTC60S_MASK,
+ },
+ [S5M8767_IRQ_RTCA1] = {
+ .reg = 3,
+ .mask = S5M8767_IRQ_RTCA1_MASK,
+ },
+ [S5M8767_IRQ_RTCA2] = {
+ .reg = 3,
+ .mask = S5M8767_IRQ_RTCA2_MASK,
+ },
+ [S5M8767_IRQ_SMPL] = {
+ .reg = 3,
+ .mask = S5M8767_IRQ_SMPL_MASK,
+ },
+ [S5M8767_IRQ_RTC1S] = {
+ .reg = 3,
+ .mask = S5M8767_IRQ_RTC1S_MASK,
+ },
+ [S5M8767_IRQ_WTSR] = {
+ .reg = 3,
+ .mask = S5M8767_IRQ_WTSR_MASK,
+ },
+};
+
+static struct s5m_irq_data s5m8763_irqs[] = {
+ [S5M8763_IRQ_DCINF] = {
+ .reg = 1,
+ .mask = S5M8763_IRQ_DCINF_MASK,
+ },
+ [S5M8763_IRQ_DCINR] = {
+ .reg = 1,
+ .mask = S5M8763_IRQ_DCINR_MASK,
+ },
+ [S5M8763_IRQ_JIGF] = {
+ .reg = 1,
+ .mask = S5M8763_IRQ_JIGF_MASK,
+ },
+ [S5M8763_IRQ_JIGR] = {
+ .reg = 1,
+ .mask = S5M8763_IRQ_JIGR_MASK,
+ },
+ [S5M8763_IRQ_PWRONF] = {
+ .reg = 1,
+ .mask = S5M8763_IRQ_PWRONF_MASK,
+ },
+ [S5M8763_IRQ_PWRONR] = {
+ .reg = 1,
+ .mask = S5M8763_IRQ_PWRONR_MASK,
+ },
+ [S5M8763_IRQ_WTSREVNT] = {
+ .reg = 2,
+ .mask = S5M8763_IRQ_WTSREVNT_MASK,
+ },
+ [S5M8763_IRQ_SMPLEVNT] = {
+ .reg = 2,
+ .mask = S5M8763_IRQ_SMPLEVNT_MASK,
+ },
+ [S5M8763_IRQ_ALARM1] = {
+ .reg = 2,
+ .mask = S5M8763_IRQ_ALARM1_MASK,
+ },
+ [S5M8763_IRQ_ALARM0] = {
+ .reg = 2,
+ .mask = S5M8763_IRQ_ALARM0_MASK,
+ },
+ [S5M8763_IRQ_ONKEY1S] = {
+ .reg = 3,
+ .mask = S5M8763_IRQ_ONKEY1S_MASK,
+ },
+ [S5M8763_IRQ_TOPOFFR] = {
+ .reg = 3,
+ .mask = S5M8763_IRQ_TOPOFFR_MASK,
+ },
+ [S5M8763_IRQ_DCINOVPR] = {
+ .reg = 3,
+ .mask = S5M8763_IRQ_DCINOVPR_MASK,
+ },
+ [S5M8763_IRQ_CHGRSTF] = {
+ .reg = 3,
+ .mask = S5M8763_IRQ_CHGRSTF_MASK,
+ },
+ [S5M8763_IRQ_DONER] = {
+ .reg = 3,
+ .mask = S5M8763_IRQ_DONER_MASK,
+ },
+ [S5M8763_IRQ_CHGFAULT] = {
+ .reg = 3,
+ .mask = S5M8763_IRQ_CHGFAULT_MASK,
+ },
+ [S5M8763_IRQ_LOBAT1] = {
+ .reg = 4,
+ .mask = S5M8763_IRQ_LOBAT1_MASK,
+ },
+ [S5M8763_IRQ_LOBAT2] = {
+ .reg = 4,
+ .mask = S5M8763_IRQ_LOBAT2_MASK,
+ },
+};
+
+static inline struct s5m_irq_data *
+irq_to_s5m8767_irq(struct s5m87xx_dev *s5m87xx, int irq)
+{
+ return &s5m8767_irqs[irq - s5m87xx->irq_base];
+}
+
+static void s5m8767_irq_lock(struct irq_data *data)
+{
+ struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+
+ mutex_lock(&s5m87xx->irqlock);
+}
+
+static void s5m8767_irq_sync_unlock(struct irq_data *data)
+{
+ struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(s5m87xx->irq_masks_cur); i++) {
+ if (s5m87xx->irq_masks_cur[i] != s5m87xx->irq_masks_cache[i]) {
+ s5m87xx->irq_masks_cache[i] = s5m87xx->irq_masks_cur[i];
+ s5m_reg_write(s5m87xx, S5M8767_REG_INT1M + i,
+ s5m87xx->irq_masks_cur[i]);
+ }
+ }
+
+ mutex_unlock(&s5m87xx->irqlock);
+}
+
+static void s5m8767_irq_unmask(struct irq_data *data)
+{
+ struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+ struct s5m_irq_data *irq_data = irq_to_s5m8767_irq(s5m87xx,
+ data->irq);
+
+ s5m87xx->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
+}
+
+static void s5m8767_irq_mask(struct irq_data *data)
+{
+ struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+ struct s5m_irq_data *irq_data = irq_to_s5m8767_irq(s5m87xx,
+ data->irq);
+
+ s5m87xx->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
+}
+
+static struct irq_chip s5m8767_irq_chip = {
+ .name = "s5m8767",
+ .irq_bus_lock = s5m8767_irq_lock,
+ .irq_bus_sync_unlock = s5m8767_irq_sync_unlock,
+ .irq_mask = s5m8767_irq_mask,
+ .irq_unmask = s5m8767_irq_unmask,
+};
+
+static inline struct s5m_irq_data *
+irq_to_s5m8763_irq(struct s5m87xx_dev *s5m87xx, int irq)
+{
+ return &s5m8763_irqs[irq - s5m87xx->irq_base];
+}
+
+static void s5m8763_irq_lock(struct irq_data *data)
+{
+ struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+
+ mutex_lock(&s5m87xx->irqlock);
+}
+
+static void s5m8763_irq_sync_unlock(struct irq_data *data)
+{
+ struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(s5m87xx->irq_masks_cur); i++) {
+ if (s5m87xx->irq_masks_cur[i] != s5m87xx->irq_masks_cache[i]) {
+ s5m87xx->irq_masks_cache[i] = s5m87xx->irq_masks_cur[i];
+ s5m_reg_write(s5m87xx, S5M8763_REG_IRQM1 + i,
+ s5m87xx->irq_masks_cur[i]);
+ }
+ }
+
+ mutex_unlock(&s5m87xx->irqlock);
+}
+
+static void s5m8763_irq_unmask(struct irq_data *data)
+{
+ struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+ struct s5m_irq_data *irq_data = irq_to_s5m8763_irq(s5m87xx,
+ data->irq);
+
+ s5m87xx->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
+}
+
+static void s5m8763_irq_mask(struct irq_data *data)
+{
+ struct s5m87xx_dev *s5m87xx = irq_data_get_irq_chip_data(data);
+ struct s5m_irq_data *irq_data = irq_to_s5m8763_irq(s5m87xx,
+ data->irq);
+
+ s5m87xx->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
+}
+
+static struct irq_chip s5m8763_irq_chip = {
+ .name = "s5m8763",
+ .irq_bus_lock = s5m8763_irq_lock,
+ .irq_bus_sync_unlock = s5m8763_irq_sync_unlock,
+ .irq_mask = s5m8763_irq_mask,
+ .irq_unmask = s5m8763_irq_unmask,
+};
+
+
+static irqreturn_t s5m8767_irq_thread(int irq, void *data)
+{
+ struct s5m87xx_dev *s5m87xx = data;
+ u8 irq_reg[NUM_IRQ_REGS-1];
+ int ret;
+ int i;
+
+
+ ret = s5m_bulk_read(s5m87xx, S5M8767_REG_INT1,
+ NUM_IRQ_REGS - 1, irq_reg);
+ if (ret < 0) {
+ dev_err(s5m87xx->dev, "Failed to read interrupt register: %d\n",
+ ret);
+ return IRQ_NONE;
+ }
+
+ for (i = 0; i < NUM_IRQ_REGS - 1; i++)
+ irq_reg[i] &= ~s5m87xx->irq_masks_cur[i];
+
+ for (i = 0; i < S5M8767_IRQ_NR; i++) {
+ if (irq_reg[s5m8767_irqs[i].reg - 1] & s5m8767_irqs[i].mask)
+ handle_nested_irq(s5m87xx->irq_base + i);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t s5m8763_irq_thread(int irq, void *data)
+{
+ struct s5m87xx_dev *s5m87xx = data;
+ u8 irq_reg[NUM_IRQ_REGS];
+ int ret;
+ int i;
+
+ ret = s5m_bulk_read(s5m87xx, S5M8763_REG_IRQ1,
+ NUM_IRQ_REGS, irq_reg);
+ if (ret < 0) {
+ dev_err(s5m87xx->dev, "Failed to read interrupt register: %d\n",
+ ret);
+ return IRQ_NONE;
+ }
+
+ for (i = 0; i < NUM_IRQ_REGS; i++)
+ irq_reg[i] &= ~s5m87xx->irq_masks_cur[i];
+
+ for (i = 0; i < S5M8763_IRQ_NR; i++) {
+ if (irq_reg[s5m8763_irqs[i].reg - 1] & s5m8763_irqs[i].mask)
+ handle_nested_irq(s5m87xx->irq_base + i);
+ }
+
+ return IRQ_HANDLED;
+}
+
+int s5m_irq_resume(struct s5m87xx_dev *s5m87xx)
+{
+ if (s5m87xx->irq && s5m87xx->irq_base){
+ switch (s5m87xx->device_type) {
+ case S5M8763X:
+ s5m8763_irq_thread(s5m87xx->irq_base, s5m87xx);
+ break;
+ case S5M8767X:
+ s5m8767_irq_thread(s5m87xx->irq_base, s5m87xx);
+ break;
+ default:
+ break;
+
+ }
+ }
+ return 0;
+}
+
+int s5m_irq_init(struct s5m87xx_dev *s5m87xx)
+{
+ int i;
+ int cur_irq;
+ int ret = 0;
+ int type = s5m87xx->device_type;
+
+ if (!s5m87xx->irq) {
+ dev_warn(s5m87xx->dev,
+ "No interrupt specified, no interrupts\n");
+ s5m87xx->irq_base = 0;
+ return 0;
+ }
+
+ if (!s5m87xx->irq_base) {
+ dev_err(s5m87xx->dev,
+ "No interrupt base specified, no interrupts\n");
+ return 0;
+ }
+
+ mutex_init(&s5m87xx->irqlock);
+
+ switch (type) {
+ case S5M8763X:
+ for (i = 0; i < NUM_IRQ_REGS; i++) {
+ s5m87xx->irq_masks_cur[i] = 0xff;
+ s5m87xx->irq_masks_cache[i] = 0xff;
+ s5m_reg_write(s5m87xx, S5M8763_REG_IRQM1 + i,
+ 0xff);
+ }
+
+ s5m_reg_write(s5m87xx, S5M8763_REG_STATUSM1, 0xff);
+ s5m_reg_write(s5m87xx, S5M8763_REG_STATUSM2, 0xff);
+
+ for (i = 0; i < S5M8763_IRQ_NR; i++) {
+ cur_irq = i + s5m87xx->irq_base;
+ irq_set_chip_data(cur_irq, s5m87xx);
+ irq_set_chip_and_handler(cur_irq, &s5m8763_irq_chip,
+ handle_edge_irq);
+ irq_set_nested_thread(cur_irq, 1);
+#ifdef CONFIG_ARM
+ set_irq_flags(cur_irq, IRQF_VALID);
+#else
+ irq_set_noprobe(cur_irq);
+#endif
+ }
+
+ ret = request_threaded_irq(s5m87xx->irq, NULL,
+ s5m8763_irq_thread,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "s5m87xx-irq", s5m87xx);
+ if (ret) {
+ dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
+ s5m87xx->irq, ret);
+ return ret;
+ }
+ break;
+ case S5M8767X:
+ for (i = 0; i < NUM_IRQ_REGS - 1; i++) {
+ s5m87xx->irq_masks_cur[i] = 0xff;
+ s5m87xx->irq_masks_cache[i] = 0xff;
+ s5m_reg_write(s5m87xx, S5M8767_REG_INT1M + i,
+ 0xff);
+ }
+ for (i = 0; i < S5M8767_IRQ_NR; i++) {
+ cur_irq = i + s5m87xx->irq_base;
+ irq_set_chip_data(cur_irq, s5m87xx);
+ if (ret) {
+ dev_err(s5m87xx->dev,
+ "Failed to irq_set_chip_data %d: %d\n",
+ s5m87xx->irq, ret);
+ return ret;
+ }
+
+ irq_set_chip_and_handler(cur_irq, &s5m8767_irq_chip,
+ handle_edge_irq);
+ irq_set_nested_thread(cur_irq, 1);
+#ifdef CONFIG_ARM
+ set_irq_flags(cur_irq, IRQF_VALID);
+#else
+ irq_set_noprobe(cur_irq);
+#endif
+ }
+
+ ret = request_threaded_irq(s5m87xx->irq, NULL,
+ s5m8767_irq_thread,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "s5m87xx-irq", s5m87xx);
+ if (ret) {
+ dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
+ s5m87xx->irq, ret);
+ return ret;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!s5m87xx->ono)
+ return 0;
+
+ switch (type) {
+ case S5M8763X:
+ ret = request_threaded_irq(s5m87xx->ono, NULL,
+ s5m8763_irq_thread,
+ IRQF_TRIGGER_FALLING |
+ IRQF_TRIGGER_RISING |
+ IRQF_ONESHOT, "s5m87xx-ono",
+ s5m87xx);
+ break;
+ case S5M8767X:
+ ret = request_threaded_irq(s5m87xx->ono, NULL,
+ s5m8767_irq_thread,
+ IRQF_TRIGGER_FALLING |
+ IRQF_TRIGGER_RISING |
+ IRQF_ONESHOT, "s5m87xx-ono", s5m87xx);
+ break;
+ default:
+ break;
+ }
+
+ if (ret)
+ dev_err(s5m87xx->dev, "Failed to request IRQ %d: %d\n",
+ s5m87xx->ono, ret);
+
+ return 0;
+}
+
+void s5m_irq_exit(struct s5m87xx_dev *s5m87xx)
+{
+ if (s5m87xx->ono)
+ free_irq(s5m87xx->ono, s5m87xx);
+
+ if (s5m87xx->irq)
+ free_irq(s5m87xx->irq, s5m87xx);
+}
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index df3702c1756..f4d86117f44 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -1720,7 +1720,7 @@ static int sm501_plat_remove(struct platform_device *dev)
return 0;
}
-static struct pci_device_id sm501_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(sm501_pci_tbl) = {
{ 0x126f, 0x0501, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0, },
};
diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c
new file mode 100644
index 00000000000..373f423b118
--- /dev/null
+++ b/drivers/mfd/stmpe-i2c.c
@@ -0,0 +1,109 @@
+/*
+ * ST Microelectronics MFD: stmpe's i2c client specific driver
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Copyright (C) ST Microelectronics SA 2011
+ *
+ * License Terms: GNU General Public License, version 2
+ * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
+ * Author: Viresh Kumar <viresh.kumar@st.com> for ST Microelectronics
+ */
+
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include "stmpe.h"
+
+static int i2c_reg_read(struct stmpe *stmpe, u8 reg)
+{
+ struct i2c_client *i2c = stmpe->client;
+
+ return i2c_smbus_read_byte_data(i2c, reg);
+}
+
+static int i2c_reg_write(struct stmpe *stmpe, u8 reg, u8 val)
+{
+ struct i2c_client *i2c = stmpe->client;
+
+ return i2c_smbus_write_byte_data(i2c, reg, val);
+}
+
+static int i2c_block_read(struct stmpe *stmpe, u8 reg, u8 length, u8 *values)
+{
+ struct i2c_client *i2c = stmpe->client;
+
+ return i2c_smbus_read_i2c_block_data(i2c, reg, length, values);
+}
+
+static int i2c_block_write(struct stmpe *stmpe, u8 reg, u8 length,
+ const u8 *values)
+{
+ struct i2c_client *i2c = stmpe->client;
+
+ return i2c_smbus_write_i2c_block_data(i2c, reg, length, values);
+}
+
+static struct stmpe_client_info i2c_ci = {
+ .read_byte = i2c_reg_read,
+ .write_byte = i2c_reg_write,
+ .read_block = i2c_block_read,
+ .write_block = i2c_block_write,
+};
+
+static int __devinit
+stmpe_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+ i2c_ci.data = (void *)id;
+ i2c_ci.irq = i2c->irq;
+ i2c_ci.client = i2c;
+ i2c_ci.dev = &i2c->dev;
+
+ return stmpe_probe(&i2c_ci, id->driver_data);
+}
+
+static int __devexit stmpe_i2c_remove(struct i2c_client *i2c)
+{
+ struct stmpe *stmpe = dev_get_drvdata(&i2c->dev);
+
+ return stmpe_remove(stmpe);
+}
+
+static const struct i2c_device_id stmpe_i2c_id[] = {
+ { "stmpe610", STMPE610 },
+ { "stmpe801", STMPE801 },
+ { "stmpe811", STMPE811 },
+ { "stmpe1601", STMPE1601 },
+ { "stmpe2401", STMPE2401 },
+ { "stmpe2403", STMPE2403 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, stmpe_id);
+
+static struct i2c_driver stmpe_i2c_driver = {
+ .driver.name = "stmpe-i2c",
+ .driver.owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .driver.pm = &stmpe_dev_pm_ops,
+#endif
+ .probe = stmpe_i2c_probe,
+ .remove = __devexit_p(stmpe_i2c_remove),
+ .id_table = stmpe_i2c_id,
+};
+
+static int __init stmpe_init(void)
+{
+ return i2c_add_driver(&stmpe_i2c_driver);
+}
+subsys_initcall(stmpe_init);
+
+static void __exit stmpe_exit(void)
+{
+ i2c_del_driver(&stmpe_i2c_driver);
+}
+module_exit(stmpe_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("STMPE MFD I2C Interface Driver");
+MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>");
diff --git a/drivers/mfd/stmpe-spi.c b/drivers/mfd/stmpe-spi.c
new file mode 100644
index 00000000000..b58c43c7ea9
--- /dev/null
+++ b/drivers/mfd/stmpe-spi.c
@@ -0,0 +1,150 @@
+/*
+ * ST Microelectronics MFD: stmpe's spi client specific driver
+ *
+ * Copyright (C) ST Microelectronics SA 2011
+ *
+ * License Terms: GNU General Public License, version 2
+ * Author: Viresh Kumar <viresh.kumar@st.com> for ST Microelectronics
+ */
+
+#include <linux/spi/spi.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include "stmpe.h"
+
+#define READ_CMD (1 << 7)
+
+static int spi_reg_read(struct stmpe *stmpe, u8 reg)
+{
+ struct spi_device *spi = stmpe->client;
+ int status = spi_w8r16(spi, reg | READ_CMD);
+
+ return (status < 0) ? status : status >> 8;
+}
+
+static int spi_reg_write(struct stmpe *stmpe, u8 reg, u8 val)
+{
+ struct spi_device *spi = stmpe->client;
+ u16 cmd = (val << 8) | reg;
+
+ return spi_write(spi, (const u8 *)&cmd, 2);
+}
+
+static int spi_block_read(struct stmpe *stmpe, u8 reg, u8 length, u8 *values)
+{
+ int ret, i;
+
+ for (i = 0; i < length; i++) {
+ ret = spi_reg_read(stmpe, reg + i);
+ if (ret < 0)
+ return ret;
+ *(values + i) = ret;
+ }
+
+ return 0;
+}
+
+static int spi_block_write(struct stmpe *stmpe, u8 reg, u8 length,
+ const u8 *values)
+{
+ int ret = 0, i;
+
+ for (i = length; i > 0; i--, reg++) {
+ ret = spi_reg_write(stmpe, reg, *(values + i - 1));
+ if (ret < 0)
+ return ret;
+ }
+
+ return ret;
+}
+
+static void spi_init(struct stmpe *stmpe)
+{
+ struct spi_device *spi = stmpe->client;
+
+ spi->bits_per_word = 8;
+
+ /* This register is only present for stmpe811 */
+ if (stmpe->variant->id_val == 0x0811)
+ spi_reg_write(stmpe, STMPE811_REG_SPI_CFG, spi->mode);
+
+ if (spi_setup(spi) < 0)
+ dev_dbg(&spi->dev, "spi_setup failed\n");
+}
+
+static struct stmpe_client_info spi_ci = {
+ .read_byte = spi_reg_read,
+ .write_byte = spi_reg_write,
+ .read_block = spi_block_read,
+ .write_block = spi_block_write,
+ .init = spi_init,
+};
+
+static int __devinit
+stmpe_spi_probe(struct spi_device *spi)
+{
+ const struct spi_device_id *id = spi_get_device_id(spi);
+
+ /* don't exceed max specified rate - 1MHz - Limitation of STMPE */
+ if (spi->max_speed_hz > 1000000) {
+ dev_dbg(&spi->dev, "f(sample) %d KHz?\n",
+ (spi->max_speed_hz/1000));
+ return -EINVAL;
+ }
+
+ spi_ci.irq = spi->irq;
+ spi_ci.client = spi;
+ spi_ci.dev = &spi->dev;
+
+ return stmpe_probe(&spi_ci, id->driver_data);
+}
+
+static int __devexit stmpe_spi_remove(struct spi_device *spi)
+{
+ struct stmpe *stmpe = dev_get_drvdata(&spi->dev);
+
+ return stmpe_remove(stmpe);
+}
+
+static const struct spi_device_id stmpe_spi_id[] = {
+ { "stmpe610", STMPE610 },
+ { "stmpe801", STMPE801 },
+ { "stmpe811", STMPE811 },
+ { "stmpe1601", STMPE1601 },
+ { "stmpe2401", STMPE2401 },
+ { "stmpe2403", STMPE2403 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, stmpe_id);
+
+static struct spi_driver stmpe_spi_driver = {
+ .driver = {
+ .name = "stmpe-spi",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_PM
+ .pm = &stmpe_dev_pm_ops,
+#endif
+ },
+ .probe = stmpe_spi_probe,
+ .remove = __devexit_p(stmpe_spi_remove),
+ .id_table = stmpe_spi_id,
+};
+
+static int __init stmpe_init(void)
+{
+ return spi_register_driver(&stmpe_spi_driver);
+}
+subsys_initcall(stmpe_init);
+
+static void __exit stmpe_exit(void)
+{
+ spi_unregister_driver(&stmpe_spi_driver);
+}
+module_exit(stmpe_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("STMPE MFD SPI Interface Driver");
+MODULE_AUTHOR("Viresh Kumar <viresh.kumar@st.com>");
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c
index 2963689cf45..e07947e56b2 100644
--- a/drivers/mfd/stmpe.c
+++ b/drivers/mfd/stmpe.c
@@ -1,18 +1,20 @@
/*
+ * ST Microelectronics MFD: stmpe's driver
+ *
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License, version 2
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
*/
+#include <linux/gpio.h>
+#include <linux/export.h>
#include <linux/kernel.h>
-#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/pm.h>
#include <linux/slab.h>
-#include <linux/i2c.h>
#include <linux/mfd/core.h>
-#include <linux/mfd/stmpe.h>
#include "stmpe.h"
static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks)
@@ -29,10 +31,9 @@ static int __stmpe_reg_read(struct stmpe *stmpe, u8 reg)
{
int ret;
- ret = i2c_smbus_read_byte_data(stmpe->i2c, reg);
+ ret = stmpe->ci->read_byte(stmpe, reg);
if (ret < 0)
- dev_err(stmpe->dev, "failed to read reg %#x: %d\n",
- reg, ret);
+ dev_err(stmpe->dev, "failed to read reg %#x: %d\n", reg, ret);
dev_vdbg(stmpe->dev, "rd: reg %#x => data %#x\n", reg, ret);
@@ -45,10 +46,9 @@ static int __stmpe_reg_write(struct stmpe *stmpe, u8 reg, u8 val)
dev_vdbg(stmpe->dev, "wr: reg %#x <= %#x\n", reg, val);
- ret = i2c_smbus_write_byte_data(stmpe->i2c, reg, val);
+ ret = stmpe->ci->write_byte(stmpe, reg, val);
if (ret < 0)
- dev_err(stmpe->dev, "failed to write reg %#x: %d\n",
- reg, ret);
+ dev_err(stmpe->dev, "failed to write reg %#x: %d\n", reg, ret);
return ret;
}
@@ -72,10 +72,9 @@ static int __stmpe_block_read(struct stmpe *stmpe, u8 reg, u8 length,
{
int ret;
- ret = i2c_smbus_read_i2c_block_data(stmpe->i2c, reg, length, values);
+ ret = stmpe->ci->read_block(stmpe, reg, length, values);
if (ret < 0)
- dev_err(stmpe->dev, "failed to read regs %#x: %d\n",
- reg, ret);
+ dev_err(stmpe->dev, "failed to read regs %#x: %d\n", reg, ret);
dev_vdbg(stmpe->dev, "rd: reg %#x (%d) => ret %#x\n", reg, length, ret);
stmpe_dump_bytes("stmpe rd: ", values, length);
@@ -91,11 +90,9 @@ static int __stmpe_block_write(struct stmpe *stmpe, u8 reg, u8 length,
dev_vdbg(stmpe->dev, "wr: regs %#x (%d)\n", reg, length);
stmpe_dump_bytes("stmpe wr: ", values, length);
- ret = i2c_smbus_write_i2c_block_data(stmpe->i2c, reg, length,
- values);
+ ret = stmpe->ci->write_block(stmpe, reg, length, values);
if (ret < 0)
- dev_err(stmpe->dev, "failed to write regs %#x: %d\n",
- reg, ret);
+ dev_err(stmpe->dev, "failed to write regs %#x: %d\n", reg, ret);
return ret;
}
@@ -245,12 +242,14 @@ int stmpe_set_altfunc(struct stmpe *stmpe, u32 pins, enum stmpe_block block)
u8 regaddr = stmpe->regs[STMPE_IDX_GPAFR_U_MSB];
int af_bits = variant->af_bits;
int numregs = DIV_ROUND_UP(stmpe->num_gpios * af_bits, 8);
- int afperreg = 8 / af_bits;
int mask = (1 << af_bits) - 1;
u8 regs[numregs];
- int af;
- int ret;
+ int af, afperreg, ret;
+
+ if (!variant->get_altfunc)
+ return 0;
+ afperreg = 8 / af_bits;
mutex_lock(&stmpe->lock);
ret = __stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
@@ -325,7 +324,51 @@ static struct mfd_cell stmpe_keypad_cell = {
};
/*
- * Touchscreen (STMPE811)
+ * STMPE801
+ */
+static const u8 stmpe801_regs[] = {
+ [STMPE_IDX_CHIP_ID] = STMPE801_REG_CHIP_ID,
+ [STMPE_IDX_ICR_LSB] = STMPE801_REG_SYS_CTRL,
+ [STMPE_IDX_GPMR_LSB] = STMPE801_REG_GPIO_MP_STA,
+ [STMPE_IDX_GPSR_LSB] = STMPE801_REG_GPIO_SET_PIN,
+ [STMPE_IDX_GPCR_LSB] = STMPE801_REG_GPIO_SET_PIN,
+ [STMPE_IDX_GPDR_LSB] = STMPE801_REG_GPIO_DIR,
+ [STMPE_IDX_IEGPIOR_LSB] = STMPE801_REG_GPIO_INT_EN,
+ [STMPE_IDX_ISGPIOR_MSB] = STMPE801_REG_GPIO_INT_STA,
+
+};
+
+static struct stmpe_variant_block stmpe801_blocks[] = {
+ {
+ .cell = &stmpe_gpio_cell,
+ .irq = 0,
+ .block = STMPE_BLOCK_GPIO,
+ },
+};
+
+static int stmpe801_enable(struct stmpe *stmpe, unsigned int blocks,
+ bool enable)
+{
+ if (blocks & STMPE_BLOCK_GPIO)
+ return 0;
+ else
+ return -EINVAL;
+}
+
+static struct stmpe_variant_info stmpe801 = {
+ .name = "stmpe801",
+ .id_val = STMPE801_ID,
+ .id_mask = 0xffff,
+ .num_gpios = 8,
+ .regs = stmpe801_regs,
+ .blocks = stmpe801_blocks,
+ .num_blocks = ARRAY_SIZE(stmpe801_blocks),
+ .num_irqs = STMPE801_NR_INTERNAL_IRQS,
+ .enable = stmpe801_enable,
+};
+
+/*
+ * Touchscreen (STMPE811 or STMPE610)
*/
static struct resource stmpe_ts_resources[] = {
@@ -350,7 +393,7 @@ static struct mfd_cell stmpe_ts_cell = {
};
/*
- * STMPE811
+ * STMPE811 or STMPE610
*/
static const u8 stmpe811_regs[] = {
@@ -421,6 +464,21 @@ static struct stmpe_variant_info stmpe811 = {
.get_altfunc = stmpe811_get_altfunc,
};
+/* Similar to 811, except number of gpios */
+static struct stmpe_variant_info stmpe610 = {
+ .name = "stmpe610",
+ .id_val = 0x0811,
+ .id_mask = 0xffff,
+ .num_gpios = 6,
+ .af_bits = 1,
+ .regs = stmpe811_regs,
+ .blocks = stmpe811_blocks,
+ .num_blocks = ARRAY_SIZE(stmpe811_blocks),
+ .num_irqs = STMPE811_NR_INTERNAL_IRQS,
+ .enable = stmpe811_enable,
+ .get_altfunc = stmpe811_get_altfunc,
+};
+
/*
* STMPE1601
*/
@@ -655,6 +713,8 @@ static struct stmpe_variant_info stmpe2403 = {
};
static struct stmpe_variant_info *stmpe_variant_info[] = {
+ [STMPE610] = &stmpe610,
+ [STMPE801] = &stmpe801,
[STMPE811] = &stmpe811,
[STMPE1601] = &stmpe1601,
[STMPE2401] = &stmpe2401,
@@ -671,6 +731,11 @@ static irqreturn_t stmpe_irq(int irq, void *data)
int ret;
int i;
+ if (variant->id_val == STMPE801_ID) {
+ handle_nested_irq(stmpe->irq_base);
+ return IRQ_HANDLED;
+ }
+
ret = stmpe_block_read(stmpe, israddr, num, isr);
if (ret < 0)
return IRQ_NONE;
@@ -757,14 +822,17 @@ static struct irq_chip stmpe_irq_chip = {
static int __devinit stmpe_irq_init(struct stmpe *stmpe)
{
+ struct irq_chip *chip = NULL;
int num_irqs = stmpe->variant->num_irqs;
int base = stmpe->irq_base;
int irq;
+ if (stmpe->variant->id_val != STMPE801_ID)
+ chip = &stmpe_irq_chip;
+
for (irq = base; irq < base + num_irqs; irq++) {
irq_set_chip_data(irq, stmpe);
- irq_set_chip_and_handler(irq, &stmpe_irq_chip,
- handle_edge_irq);
+ irq_set_chip_and_handler(irq, chip, handle_edge_irq);
irq_set_nested_thread(irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
@@ -796,7 +864,7 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
unsigned int irq_trigger = stmpe->pdata->irq_trigger;
int autosleep_timeout = stmpe->pdata->autosleep_timeout;
struct stmpe_variant_info *variant = stmpe->variant;
- u8 icr = STMPE_ICR_LSB_GIM;
+ u8 icr;
unsigned int id;
u8 data[2];
int ret;
@@ -819,16 +887,32 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
if (ret)
return ret;
- if (irq_trigger == IRQF_TRIGGER_FALLING ||
- irq_trigger == IRQF_TRIGGER_RISING)
- icr |= STMPE_ICR_LSB_EDGE;
+ if (id == STMPE801_ID)
+ icr = STMPE801_REG_SYS_CTRL_INT_EN;
+ else
+ icr = STMPE_ICR_LSB_GIM;
+
+ /* STMPE801 doesn't support Edge interrupts */
+ if (id != STMPE801_ID) {
+ if (irq_trigger == IRQF_TRIGGER_FALLING ||
+ irq_trigger == IRQF_TRIGGER_RISING)
+ icr |= STMPE_ICR_LSB_EDGE;
+ }
if (irq_trigger == IRQF_TRIGGER_RISING ||
- irq_trigger == IRQF_TRIGGER_HIGH)
- icr |= STMPE_ICR_LSB_HIGH;
+ irq_trigger == IRQF_TRIGGER_HIGH) {
+ if (id == STMPE801_ID)
+ icr |= STMPE801_REG_SYS_CTRL_INT_HI;
+ else
+ icr |= STMPE_ICR_LSB_HIGH;
+ }
- if (stmpe->pdata->irq_invert_polarity)
- icr ^= STMPE_ICR_LSB_HIGH;
+ if (stmpe->pdata->irq_invert_polarity) {
+ if (id == STMPE801_ID)
+ icr ^= STMPE801_REG_SYS_CTRL_INT_HI;
+ else
+ icr ^= STMPE_ICR_LSB_HIGH;
+ }
if (stmpe->pdata->autosleep) {
ret = stmpe_autosleep(stmpe, autosleep_timeout);
@@ -873,32 +957,10 @@ static int __devinit stmpe_devices_init(struct stmpe *stmpe)
return ret;
}
-#ifdef CONFIG_PM
-static int stmpe_suspend(struct device *dev)
-{
- struct i2c_client *i2c = to_i2c_client(dev);
-
- if (device_may_wakeup(&i2c->dev))
- enable_irq_wake(i2c->irq);
-
- return 0;
-}
-
-static int stmpe_resume(struct device *dev)
-{
- struct i2c_client *i2c = to_i2c_client(dev);
-
- if (device_may_wakeup(&i2c->dev))
- disable_irq_wake(i2c->irq);
-
- return 0;
-}
-#endif
-
-static int __devinit stmpe_probe(struct i2c_client *i2c,
- const struct i2c_device_id *id)
+/* Called from client specific probe routines */
+int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
{
- struct stmpe_platform_data *pdata = i2c->dev.platform_data;
+ struct stmpe_platform_data *pdata = dev_get_platdata(ci->dev);
struct stmpe *stmpe;
int ret;
@@ -912,30 +974,43 @@ static int __devinit stmpe_probe(struct i2c_client *i2c,
mutex_init(&stmpe->irq_lock);
mutex_init(&stmpe->lock);
- stmpe->dev = &i2c->dev;
- stmpe->i2c = i2c;
-
+ stmpe->dev = ci->dev;
+ stmpe->client = ci->client;
stmpe->pdata = pdata;
stmpe->irq_base = pdata->irq_base;
-
- stmpe->partnum = id->driver_data;
- stmpe->variant = stmpe_variant_info[stmpe->partnum];
+ stmpe->ci = ci;
+ stmpe->partnum = partnum;
+ stmpe->variant = stmpe_variant_info[partnum];
stmpe->regs = stmpe->variant->regs;
stmpe->num_gpios = stmpe->variant->num_gpios;
+ dev_set_drvdata(stmpe->dev, stmpe);
- i2c_set_clientdata(i2c, stmpe);
+ if (ci->init)
+ ci->init(stmpe);
+
+ if (pdata->irq_over_gpio) {
+ ret = gpio_request_one(pdata->irq_gpio, GPIOF_DIR_IN, "stmpe");
+ if (ret) {
+ dev_err(stmpe->dev, "failed to request IRQ GPIO: %d\n",
+ ret);
+ goto out_free;
+ }
+
+ stmpe->irq = gpio_to_irq(pdata->irq_gpio);
+ } else {
+ stmpe->irq = ci->irq;
+ }
ret = stmpe_chip_init(stmpe);
if (ret)
- goto out_free;
+ goto free_gpio;
ret = stmpe_irq_init(stmpe);
if (ret)
- goto out_free;
+ goto free_gpio;
- ret = request_threaded_irq(stmpe->i2c->irq, NULL, stmpe_irq,
- pdata->irq_trigger | IRQF_ONESHOT,
- "stmpe", stmpe);
+ ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq,
+ pdata->irq_trigger | IRQF_ONESHOT, "stmpe", stmpe);
if (ret) {
dev_err(stmpe->dev, "failed to request IRQ: %d\n", ret);
goto out_removeirq;
@@ -951,67 +1026,55 @@ static int __devinit stmpe_probe(struct i2c_client *i2c,
out_removedevs:
mfd_remove_devices(stmpe->dev);
- free_irq(stmpe->i2c->irq, stmpe);
+ free_irq(stmpe->irq, stmpe);
out_removeirq:
stmpe_irq_remove(stmpe);
+free_gpio:
+ if (pdata->irq_over_gpio)
+ gpio_free(pdata->irq_gpio);
out_free:
kfree(stmpe);
return ret;
}
-static int __devexit stmpe_remove(struct i2c_client *client)
+int stmpe_remove(struct stmpe *stmpe)
{
- struct stmpe *stmpe = i2c_get_clientdata(client);
-
mfd_remove_devices(stmpe->dev);
- free_irq(stmpe->i2c->irq, stmpe);
+ free_irq(stmpe->irq, stmpe);
stmpe_irq_remove(stmpe);
+ if (stmpe->pdata->irq_over_gpio)
+ gpio_free(stmpe->pdata->irq_gpio);
+
kfree(stmpe);
return 0;
}
-static const struct i2c_device_id stmpe_id[] = {
- { "stmpe811", STMPE811 },
- { "stmpe1601", STMPE1601 },
- { "stmpe2401", STMPE2401 },
- { "stmpe2403", STMPE2403 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, stmpe_id);
-
#ifdef CONFIG_PM
-static const struct dev_pm_ops stmpe_dev_pm_ops = {
- .suspend = stmpe_suspend,
- .resume = stmpe_resume,
-};
-#endif
+static int stmpe_suspend(struct device *dev)
+{
+ struct stmpe *stmpe = dev_get_drvdata(dev);
-static struct i2c_driver stmpe_driver = {
- .driver.name = "stmpe",
- .driver.owner = THIS_MODULE,
-#ifdef CONFIG_PM
- .driver.pm = &stmpe_dev_pm_ops,
-#endif
- .probe = stmpe_probe,
- .remove = __devexit_p(stmpe_remove),
- .id_table = stmpe_id,
-};
+ if (device_may_wakeup(dev))
+ enable_irq_wake(stmpe->irq);
-static int __init stmpe_init(void)
-{
- return i2c_add_driver(&stmpe_driver);
+ return 0;
}
-subsys_initcall(stmpe_init);
-static void __exit stmpe_exit(void)
+static int stmpe_resume(struct device *dev)
{
- i2c_del_driver(&stmpe_driver);
+ struct stmpe *stmpe = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(stmpe->irq);
+
+ return 0;
}
-module_exit(stmpe_exit);
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("STMPE MFD core driver");
-MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>");
+const struct dev_pm_ops stmpe_dev_pm_ops = {
+ .suspend = stmpe_suspend,
+ .resume = stmpe_resume,
+};
+#endif
diff --git a/drivers/mfd/stmpe.h b/drivers/mfd/stmpe.h
index e4ee3895658..7b8e13f5b76 100644
--- a/drivers/mfd/stmpe.h
+++ b/drivers/mfd/stmpe.h
@@ -8,6 +8,14 @@
#ifndef __STMPE_H
#define __STMPE_H
+#include <linux/device.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/stmpe.h>
+#include <linux/printk.h>
+#include <linux/types.h>
+
+extern const struct dev_pm_ops stmpe_dev_pm_ops;
+
#ifdef STMPE_DUMP_BYTES
static inline void stmpe_dump_bytes(const char *str, const void *buf,
size_t len)
@@ -67,11 +75,55 @@ struct stmpe_variant_info {
int (*enable_autosleep)(struct stmpe *stmpe, int autosleep_timeout);
};
+/**
+ * struct stmpe_client_info - i2c or spi specific routines/info
+ * @data: client specific data
+ * @read_byte: read single byte
+ * @write_byte: write single byte
+ * @read_block: read block or multiple bytes
+ * @write_block: write block or multiple bytes
+ * @init: client init routine, called during probe
+ */
+struct stmpe_client_info {
+ void *data;
+ int irq;
+ void *client;
+ struct device *dev;
+ int (*read_byte)(struct stmpe *stmpe, u8 reg);
+ int (*write_byte)(struct stmpe *stmpe, u8 reg, u8 val);
+ int (*read_block)(struct stmpe *stmpe, u8 reg, u8 len, u8 *values);
+ int (*write_block)(struct stmpe *stmpe, u8 reg, u8 len,
+ const u8 *values);
+ void (*init)(struct stmpe *stmpe);
+};
+
+int stmpe_probe(struct stmpe_client_info *ci, int partnum);
+int stmpe_remove(struct stmpe *stmpe);
+
#define STMPE_ICR_LSB_HIGH (1 << 2)
#define STMPE_ICR_LSB_EDGE (1 << 1)
#define STMPE_ICR_LSB_GIM (1 << 0)
/*
+ * STMPE801
+ */
+#define STMPE801_ID 0x0108
+#define STMPE801_NR_INTERNAL_IRQS 1
+
+#define STMPE801_REG_CHIP_ID 0x00
+#define STMPE801_REG_VERSION_ID 0x02
+#define STMPE801_REG_SYS_CTRL 0x04
+#define STMPE801_REG_GPIO_INT_EN 0x08
+#define STMPE801_REG_GPIO_INT_STA 0x09
+#define STMPE801_REG_GPIO_MP_STA 0x10
+#define STMPE801_REG_GPIO_SET_PIN 0x11
+#define STMPE801_REG_GPIO_DIR 0x12
+
+#define STMPE801_REG_SYS_CTRL_RESET (1 << 7)
+#define STMPE801_REG_SYS_CTRL_INT_EN (1 << 2)
+#define STMPE801_REG_SYS_CTRL_INT_HI (1 << 0)
+
+/*
* STMPE811
*/
@@ -87,6 +139,7 @@ struct stmpe_variant_info {
#define STMPE811_REG_CHIP_ID 0x00
#define STMPE811_REG_SYS_CTRL2 0x04
+#define STMPE811_REG_SPI_CFG 0x08
#define STMPE811_REG_INT_CTRL 0x09
#define STMPE811_REG_INT_EN 0x0A
#define STMPE811_REG_INT_STA 0x0B
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c
index 91ad21ef772..2d9e8799e73 100644
--- a/drivers/mfd/t7l66xb.c
+++ b/drivers/mfd/t7l66xb.c
@@ -442,21 +442,7 @@ static struct platform_driver t7l66xb_platform_driver = {
/*--------------------------------------------------------------------------*/
-static int __init t7l66xb_init(void)
-{
- int retval = 0;
-
- retval = platform_driver_register(&t7l66xb_platform_driver);
- return retval;
-}
-
-static void __exit t7l66xb_exit(void)
-{
- platform_driver_unregister(&t7l66xb_platform_driver);
-}
-
-module_init(t7l66xb_init);
-module_exit(t7l66xb_exit);
+module_platform_driver(t7l66xb_platform_driver);
MODULE_DESCRIPTION("Toshiba T7L66XB core driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c
index 71bc835324d..d20a284ad4b 100644
--- a/drivers/mfd/tc6387xb.c
+++ b/drivers/mfd/tc6387xb.c
@@ -234,19 +234,7 @@ static struct platform_driver tc6387xb_platform_driver = {
.resume = tc6387xb_resume,
};
-
-static int __init tc6387xb_init(void)
-{
- return platform_driver_register(&tc6387xb_platform_driver);
-}
-
-static void __exit tc6387xb_exit(void)
-{
- platform_driver_unregister(&tc6387xb_platform_driver);
-}
-
-module_init(tc6387xb_init);
-module_exit(tc6387xb_exit);
+module_platform_driver(tc6387xb_platform_driver);
MODULE_DESCRIPTION("Toshiba TC6387XB core driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/ti-ssp.c b/drivers/mfd/ti-ssp.c
index af9ab0e5ca6..4fb0e6c8e8f 100644
--- a/drivers/mfd/ti-ssp.c
+++ b/drivers/mfd/ti-ssp.c
@@ -458,17 +458,7 @@ static struct platform_driver ti_ssp_driver = {
}
};
-static int __init ti_ssp_init(void)
-{
- return platform_driver_register(&ti_ssp_driver);
-}
-module_init(ti_ssp_init);
-
-static void __exit ti_ssp_exit(void)
-{
- platform_driver_unregister(&ti_ssp_driver);
-}
-module_exit(ti_ssp_exit);
+module_platform_driver(ti_ssp_driver);
MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver");
MODULE_AUTHOR("Cyril Chemparathy");
diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c
index 02d65692ceb..0ba26fb12cf 100644
--- a/drivers/mfd/timberdale.c
+++ b/drivers/mfd/timberdale.c
@@ -857,7 +857,7 @@ static void __devexit timb_remove(struct pci_dev *dev)
kfree(priv);
}
-static struct pci_device_id timberdale_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(timberdale_pci_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_TIMB, PCI_DEVICE_ID_TIMB) },
{ 0 }
};
diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c
index bba26d96c24..a5ddf31b60c 100644
--- a/drivers/mfd/tps6586x.c
+++ b/drivers/mfd/tps6586x.c
@@ -197,7 +197,7 @@ int tps6586x_set_bits(struct device *dev, int reg, uint8_t bit_mask)
if (ret)
goto out;
- if ((reg_val & bit_mask) == 0) {
+ if ((reg_val & bit_mask) != bit_mask) {
reg_val |= bit_mask;
ret = __tps6586x_write(to_i2c_client(dev), reg, reg_val);
}
diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c
index a56be931551..95c0d7978be 100644
--- a/drivers/mfd/tps65910-irq.c
+++ b/drivers/mfd/tps65910-irq.c
@@ -215,6 +215,7 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq,
int tps65910_irq_exit(struct tps65910 *tps65910)
{
- free_irq(tps65910->chip_irq, tps65910);
+ if (tps65910->chip_irq)
+ free_irq(tps65910->chip_irq, tps65910);
return 0;
}
diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c
index 6f5b8cf2f65..01cf5012a08 100644
--- a/drivers/mfd/tps65910.c
+++ b/drivers/mfd/tps65910.c
@@ -120,7 +120,7 @@ int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask)
goto out;
}
- data &= mask;
+ data &= ~mask;
err = tps65910_i2c_write(tps65910, reg, 1, &data);
if (err)
dev_err(tps65910->dev, "write to reg %x failed\n", reg);
@@ -172,15 +172,12 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base);
- ret = tps65910_irq_init(tps65910, init_data->irq, init_data);
- if (ret < 0)
- goto err;
+ tps65910_irq_init(tps65910, init_data->irq, init_data);
kfree(init_data);
return ret;
err:
- mfd_remove_devices(tps65910->dev);
kfree(tps65910);
kfree(init_data);
return ret;
@@ -190,8 +187,8 @@ static int tps65910_i2c_remove(struct i2c_client *i2c)
{
struct tps65910 *tps65910 = i2c_get_clientdata(i2c);
- mfd_remove_devices(tps65910->dev);
tps65910_irq_exit(tps65910);
+ mfd_remove_devices(tps65910->dev);
kfree(tps65910);
return 0;
diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c
index 6d71e0d2574..27d3302d56b 100644
--- a/drivers/mfd/tps65912-spi.c
+++ b/drivers/mfd/tps65912-spi.c
@@ -111,7 +111,6 @@ static int __devexit tps65912_spi_remove(struct spi_device *spi)
static struct spi_driver tps65912_spi_driver = {
.driver = {
.name = "tps65912",
- .bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = tps65912_spi_probe,
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index bfbd66021af..e04e04ddc15 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -34,6 +34,11 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/irqdomain.h>
#include <linux/regulator/machine.h>
@@ -144,6 +149,9 @@
#define TWL_MODULE_LAST TWL4030_MODULE_LAST
+#define TWL4030_NR_IRQS 8
+#define TWL6030_NR_IRQS 20
+
/* Base Address defns for twl4030_map[] */
/* subchip/slave 0 - USB ID */
@@ -255,6 +263,7 @@ struct twl_client {
static struct twl_client twl_modules[TWL_NUM_SLAVES];
+static struct irq_domain domain;
/* mapping the module id to slave id and base address */
struct twl_mapping {
@@ -363,13 +372,13 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
return -EPERM;
}
- sid = twl_map[mod_no].sid;
- twl = &twl_modules[sid];
-
if (unlikely(!inuse)) {
- pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid);
+ pr_err("%s: not initialized\n", DRIVER_NAME);
return -EPERM;
}
+ sid = twl_map[mod_no].sid;
+ twl = &twl_modules[sid];
+
mutex_lock(&twl->xfer_lock);
/*
* [MSG1]: fill the register address data
@@ -420,13 +429,13 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no);
return -EPERM;
}
- sid = twl_map[mod_no].sid;
- twl = &twl_modules[sid];
-
if (unlikely(!inuse)) {
- pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid);
+ pr_err("%s: not initialized\n", DRIVER_NAME);
return -EPERM;
}
+ sid = twl_map[mod_no].sid;
+ twl = &twl_modules[sid];
+
mutex_lock(&twl->xfer_lock);
/* [MSG1] fill the register address data */
msg = &twl->xfer_msg[0];
@@ -1183,14 +1192,48 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
int status;
unsigned i;
struct twl4030_platform_data *pdata = client->dev.platform_data;
+ struct device_node *node = client->dev.of_node;
u8 temp;
int ret = 0;
+ int nr_irqs = TWL4030_NR_IRQS;
+
+ if ((id->driver_data) & TWL6030_CLASS)
+ nr_irqs = TWL6030_NR_IRQS;
+
+ if (node && !pdata) {
+ /*
+ * XXX: Temporary pdata until the information is correctly
+ * retrieved by every TWL modules from DT.
+ */
+ pdata = devm_kzalloc(&client->dev,
+ sizeof(struct twl4030_platform_data),
+ GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+ }
if (!pdata) {
dev_dbg(&client->dev, "no platform data?\n");
return -EINVAL;
}
+ status = irq_alloc_descs(-1, pdata->irq_base, nr_irqs, 0);
+ if (IS_ERR_VALUE(status)) {
+ dev_err(&client->dev, "Fail to allocate IRQ descs\n");
+ return status;
+ }
+
+ pdata->irq_base = status;
+ pdata->irq_end = pdata->irq_base + nr_irqs;
+
+ domain.irq_base = pdata->irq_base;
+ domain.nr_irq = nr_irqs;
+#ifdef CONFIG_OF_IRQ
+ domain.of_node = of_node_get(node);
+ domain.ops = &irq_domain_simple_ops;
+#endif
+ irq_domain_add(&domain);
+
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
dev_dbg(&client->dev, "can't talk I2C?\n");
return -EIO;
@@ -1270,7 +1313,13 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
}
- status = add_children(pdata, id->driver_data);
+#ifdef CONFIG_OF_DEVICE
+ if (node)
+ status = of_platform_populate(node, NULL, NULL, &client->dev);
+ else
+#endif
+ status = add_children(pdata, id->driver_data);
+
fail:
if (status < 0)
twl_remove(client);
diff --git a/drivers/mfd/twl4030-audio.c b/drivers/mfd/twl4030-audio.c
index ae51ab5d0e5..838ce4eb444 100644
--- a/drivers/mfd/twl4030-audio.c
+++ b/drivers/mfd/twl4030-audio.c
@@ -261,17 +261,7 @@ static struct platform_driver twl4030_audio_driver = {
},
};
-static int __devinit twl4030_audio_init(void)
-{
- return platform_driver_register(&twl4030_audio_driver);
-}
-module_init(twl4030_audio_init);
-
-static void __devexit twl4030_audio_exit(void)
-{
- platform_driver_unregister(&twl4030_audio_driver);
-}
-module_exit(twl4030_audio_exit);
+module_platform_driver(twl4030_audio_driver);
MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c
index f062c8cc6c3..b69bb517b10 100644
--- a/drivers/mfd/twl4030-irq.c
+++ b/drivers/mfd/twl4030-irq.c
@@ -432,6 +432,7 @@ struct sih_agent {
u32 edge_change;
struct mutex irq_lock;
+ char *irq_name;
};
/*----------------------------------------------------------------------*/
@@ -491,7 +492,7 @@ static void twl4030_sih_bus_sync_unlock(struct irq_data *data)
u8 bytes[4];
} imr;
- /* byte[0] gets overwriten as we write ... */
+ /* byte[0] gets overwritten as we write ... */
imr.word = cpu_to_le32(agent->imr << 8);
agent->imr_change_pending = false;
@@ -589,7 +590,7 @@ static inline int sih_read_isr(const struct sih *sih)
* Generic handler for SIH interrupts ... we "know" this is called
* in task context, with IRQs enabled.
*/
-static void handle_twl4030_sih(unsigned irq, struct irq_desc *desc)
+static irqreturn_t handle_twl4030_sih(int irq, void *data)
{
struct sih_agent *agent = irq_get_handler_data(irq);
const struct sih *sih = agent->sih;
@@ -602,7 +603,7 @@ static void handle_twl4030_sih(unsigned irq, struct irq_desc *desc)
pr_err("twl4030: %s SIH, read ISR error %d\n",
sih->name, isr);
/* REVISIT: recover; eventually mask it all, etc */
- return;
+ return IRQ_HANDLED;
}
while (isr) {
@@ -616,6 +617,7 @@ static void handle_twl4030_sih(unsigned irq, struct irq_desc *desc)
pr_err("twl4030: %s SIH, invalid ISR bit %d\n",
sih->name, irq);
}
+ return IRQ_HANDLED;
}
static unsigned twl4030_irq_next;
@@ -665,21 +667,23 @@ int twl4030_sih_setup(int module)
irq_set_chip_data(irq, agent);
irq_set_chip_and_handler(irq, &twl4030_sih_irq_chip,
handle_edge_irq);
+ irq_set_nested_thread(irq, 1);
activate_irq(irq);
}
- status = irq_base;
twl4030_irq_next += i;
/* replace generic PIH handler (handle_simple_irq) */
irq = sih_mod + twl4030_irq_base;
irq_set_handler_data(irq, agent);
- irq_set_chained_handler(irq, handle_twl4030_sih);
+ agent->irq_name = kasprintf(GFP_KERNEL, "twl4030_%s", sih->name);
+ status = request_threaded_irq(irq, NULL, handle_twl4030_sih, 0,
+ agent->irq_name ?: sih->name, NULL);
pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", sih->name,
irq, irq_base, twl4030_irq_next - 1);
- return status;
+ return status < 0 ? status : irq_base;
}
/* FIXME need a call to reverse twl4030_sih_setup() ... */
@@ -733,8 +737,9 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
}
/* install an irq handler to demultiplex the TWL4030 interrupt */
- status = request_threaded_irq(irq_num, NULL, handle_twl4030_pih, 0,
- "TWL4030-PIH", NULL);
+ status = request_threaded_irq(irq_num, NULL, handle_twl4030_pih,
+ IRQF_ONESHOT,
+ "TWL4030-PIH", NULL);
if (status < 0) {
pr_err("twl4030: could not claim irq%d: %d\n", irq_num, status);
goto fail_rqirq;
diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c
index 834f824d3c1..456ecb5ac4f 100644
--- a/drivers/mfd/twl4030-madc.c
+++ b/drivers/mfd/twl4030-madc.c
@@ -807,19 +807,7 @@ static struct platform_driver twl4030_madc_driver = {
},
};
-static int __init twl4030_madc_init(void)
-{
- return platform_driver_register(&twl4030_madc_driver);
-}
-
-module_init(twl4030_madc_init);
-
-static void __exit twl4030_madc_exit(void)
-{
- platform_driver_unregister(&twl4030_madc_driver);
-}
-
-module_exit(twl4030_madc_exit);
+module_platform_driver(twl4030_madc_driver);
MODULE_DESCRIPTION("TWL4030 ADC driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index a764676f092..d905f517115 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -34,7 +34,8 @@
static u8 twl4030_start_script_address = 0x2b;
#define PWR_P1_SW_EVENTS 0x10
-#define PWR_DEVOFF (1<<0)
+#define PWR_DEVOFF (1 << 0)
+#define SEQ_OFFSYNC (1 << 0)
#define PHY_TO_OFF_PM_MASTER(p) (p - 0x36)
#define PHY_TO_OFF_PM_RECEIVER(p) (p - 0x5b)
@@ -511,12 +512,27 @@ int twl4030_remove_script(u8 flags)
return err;
}
+/*
+ * In master mode, start the power off sequence.
+ * After a successful execution, TWL shuts down the power to the SoC
+ * and all peripherals connected to it.
+ */
+void twl4030_power_off(void)
+{
+ int err;
+
+ err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, PWR_DEVOFF,
+ TWL4030_PM_MASTER_P1_SW_EVENTS);
+ if (err)
+ pr_err("TWL4030 Unable to power off\n");
+}
+
void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
{
int err = 0;
int i;
struct twl4030_resconfig *resconfig;
- u8 address = twl4030_start_script_address;
+ u8 val, address = twl4030_start_script_address;
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
TWL4030_PM_MASTER_KEY_CFG1,
@@ -548,6 +564,28 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
}
}
+ /* Board has to be wired properly to use this feature */
+ if (twl4030_scripts->use_poweroff && !pm_power_off) {
+ /* Default for SEQ_OFFSYNC is set, lets ensure this */
+ err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val,
+ TWL4030_PM_MASTER_CFG_P123_TRANSITION);
+ if (err) {
+ pr_warning("TWL4030 Unable to read registers\n");
+
+ } else if (!(val & SEQ_OFFSYNC)) {
+ val |= SEQ_OFFSYNC;
+ err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val,
+ TWL4030_PM_MASTER_CFG_P123_TRANSITION);
+ if (err) {
+ pr_err("TWL4030 Unable to setup SEQ_OFFSYNC\n");
+ goto relock;
+ }
+ }
+
+ pm_power_off = twl4030_power_off;
+ }
+
+relock:
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0,
TWL4030_PM_MASTER_PROTECT_KEY);
if (err)
diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c
index 3eee45ffb09..c6b456ad734 100644
--- a/drivers/mfd/twl6030-irq.c
+++ b/drivers/mfd/twl6030-irq.c
@@ -138,8 +138,6 @@ static int twl6030_irq_thread(void *data)
static const unsigned max_i2c_errors = 100;
int ret;
- current->flags |= PF_NOFREEZE;
-
while (!kthread_should_stop()) {
int i;
union {
diff --git a/drivers/mfd/twl6040-core.c b/drivers/mfd/twl6040-core.c
index 268f80fd043..dda86293dc9 100644
--- a/drivers/mfd/twl6040-core.c
+++ b/drivers/mfd/twl6040-core.c
@@ -509,13 +509,10 @@ static int __devinit twl6040_probe(struct platform_device *pdev)
twl6040->audpwron = -EINVAL;
if (gpio_is_valid(twl6040->audpwron)) {
- ret = gpio_request(twl6040->audpwron, "audpwron");
+ ret = gpio_request_one(twl6040->audpwron, GPIOF_OUT_INIT_LOW,
+ "audpwron");
if (ret)
goto gpio1_err;
-
- ret = gpio_direction_output(twl6040->audpwron, 0);
- if (ret)
- goto gpio2_err;
}
/* codec interrupt */
@@ -619,18 +616,7 @@ static struct platform_driver twl6040_driver = {
},
};
-static int __devinit twl6040_init(void)
-{
- return platform_driver_register(&twl6040_driver);
-}
-module_init(twl6040_init);
-
-static void __devexit twl6040_exit(void)
-{
- platform_driver_unregister(&twl6040_driver);
-}
-
-module_exit(twl6040_exit);
+module_platform_driver(twl6040_driver);
MODULE_DESCRIPTION("TWL6040 MFD");
MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index b281217334e..91c4f25e0e5 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -36,6 +36,15 @@ static DEFINE_MUTEX(ucb1x00_mutex);
static LIST_HEAD(ucb1x00_drivers);
static LIST_HEAD(ucb1x00_devices);
+static struct mcp_device_id ucb1x00_id[] = {
+ { "ucb1x00", 0 }, /* auto-detection */
+ { "ucb1200", UCB_ID_1200 },
+ { "ucb1300", UCB_ID_1300 },
+ { "tc35143", UCB_ID_TC35143 },
+ { }
+};
+MODULE_DEVICE_TABLE(mcp, ucb1x00_id);
+
/**
* ucb1x00_io_set_dir - set IO direction
* @ucb: UCB1x00 structure describing chip
@@ -527,17 +536,33 @@ static struct class ucb1x00_class = {
static int ucb1x00_probe(struct mcp *mcp)
{
+ const struct mcp_device_id *mid;
struct ucb1x00 *ucb;
struct ucb1x00_driver *drv;
+ struct ucb1x00_plat_data *pdata;
unsigned int id;
int ret = -ENODEV;
int temp;
mcp_enable(mcp);
id = mcp_reg_read(mcp, UCB_ID);
+ mid = mcp_get_device_id(mcp);
- if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) {
- printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id);
+ if (mid && mid->driver_data) {
+ if (id != mid->driver_data) {
+ printk(KERN_WARNING "%s wrong ID %04x found: %04x\n",
+ mid->name, (unsigned int) mid->driver_data, id);
+ goto err_disable;
+ }
+ } else {
+ mid = &ucb1x00_id[1];
+ while (mid->driver_data) {
+ if (id == mid->driver_data)
+ break;
+ mid++;
+ }
+ printk(KERN_WARNING "%s ID not found: %04x\n",
+ ucb1x00_id[0].name, id);
goto err_disable;
}
@@ -546,28 +571,28 @@ static int ucb1x00_probe(struct mcp *mcp)
if (!ucb)
goto err_disable;
-
+ pdata = mcp->attached_device.platform_data;
ucb->dev.class = &ucb1x00_class;
ucb->dev.parent = &mcp->attached_device;
- dev_set_name(&ucb->dev, "ucb1x00");
+ dev_set_name(&ucb->dev, mid->name);
spin_lock_init(&ucb->lock);
spin_lock_init(&ucb->io_lock);
sema_init(&ucb->adc_sem, 1);
- ucb->id = id;
+ ucb->id = mid;
ucb->mcp = mcp;
ucb->irq = ucb1x00_detect_irq(ucb);
if (ucb->irq == NO_IRQ) {
- printk(KERN_ERR "UCB1x00: IRQ probe failed\n");
+ printk(KERN_ERR "%s: IRQ probe failed\n", mid->name);
ret = -ENODEV;
goto err_free;
}
ucb->gpio.base = -1;
- if (mcp->gpio_base != 0) {
+ if (pdata && (pdata->gpio_base >= 0)) {
ucb->gpio.label = dev_name(&ucb->dev);
- ucb->gpio.base = mcp->gpio_base;
+ ucb->gpio.base = pdata->gpio_base;
ucb->gpio.ngpio = 10;
ucb->gpio.set = ucb1x00_gpio_set;
ucb->gpio.get = ucb1x00_gpio_get;
@@ -580,10 +605,10 @@ static int ucb1x00_probe(struct mcp *mcp)
dev_info(&ucb->dev, "gpio_base not set so no gpiolib support");
ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING,
- "UCB1x00", ucb);
+ mid->name, ucb);
if (ret) {
- printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
- ucb->irq, ret);
+ printk(KERN_ERR "%s: unable to grab irq%d: %d\n",
+ mid->name, ucb->irq, ret);
goto err_gpio;
}
@@ -705,6 +730,7 @@ static struct mcp_driver ucb1x00_driver = {
.remove = ucb1x00_remove,
.suspend = ucb1x00_suspend,
.resume = ucb1x00_resume,
+ .id_table = ucb1x00_id,
};
static int __init ucb1x00_init(void)
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
index 38ffbd50a0d..40ec3c11886 100644
--- a/drivers/mfd/ucb1x00-ts.c
+++ b/drivers/mfd/ucb1x00-ts.c
@@ -382,7 +382,7 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
idev->name = "Touchscreen panel";
- idev->id.product = ts->ucb->id;
+ idev->id.product = ts->ucb->id->driver_data;
idev->open = ucb1x00_ts_open;
idev->close = ucb1x00_ts_close;
diff --git a/drivers/mfd/vx855.c b/drivers/mfd/vx855.c
index d698703dbd4..b73cc15e008 100644
--- a/drivers/mfd/vx855.c
+++ b/drivers/mfd/vx855.c
@@ -118,7 +118,7 @@ static void __devexit vx855_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
}
-static struct pci_device_id vx855_pci_tbl[] = {
+static DEFINE_PCI_DEVICE_TABLE(vx855_pci_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855) },
{ 0, }
};
diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c
index 0a2b8d41a70..f5e54fae8ad 100644
--- a/drivers/mfd/wm831x-core.c
+++ b/drivers/mfd/wm831x-core.c
@@ -559,6 +559,8 @@ static int wm831x_write(struct wm831x *wm831x, unsigned short reg,
dev_vdbg(wm831x->dev, "Write %04x to R%d(0x%x)\n",
buf[i], reg + i, reg + i);
ret = regmap_write(wm831x->regmap, reg + i, buf[i]);
+ if (ret != 0)
+ return ret;
}
return 0;
@@ -1875,7 +1877,6 @@ err_irq:
err_regmap:
mfd_remove_devices(wm831x->dev);
regmap_exit(wm831x->regmap);
- kfree(wm831x);
return ret;
}
@@ -1887,7 +1888,6 @@ void wm831x_device_exit(struct wm831x *wm831x)
free_irq(wm831x->irq_base + WM831X_IRQ_AUXADC_DATA, wm831x);
wm831x_irq_exit(wm831x);
regmap_exit(wm831x->regmap);
- kfree(wm831x);
}
int wm831x_device_suspend(struct wm831x *wm831x)
diff --git a/drivers/mfd/wm831x-i2c.c b/drivers/mfd/wm831x-i2c.c
index ac8da1d439d..cb15609b0a4 100644
--- a/drivers/mfd/wm831x-i2c.c
+++ b/drivers/mfd/wm831x-i2c.c
@@ -30,7 +30,7 @@ static int wm831x_i2c_probe(struct i2c_client *i2c,
struct wm831x *wm831x;
int ret;
- wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
+ wm831x = devm_kzalloc(&i2c->dev, sizeof(struct wm831x), GFP_KERNEL);
if (wm831x == NULL)
return -ENOMEM;
@@ -42,7 +42,6 @@ static int wm831x_i2c_probe(struct i2c_client *i2c,
ret = PTR_ERR(wm831x->regmap);
dev_err(wm831x->dev, "Failed to allocate register map: %d\n",
ret);
- kfree(wm831x);
return ret;
}
diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c
index f4747a4a9a9..bec4d053916 100644
--- a/drivers/mfd/wm831x-irq.c
+++ b/drivers/mfd/wm831x-irq.c
@@ -325,11 +325,6 @@ static inline int irq_data_to_status_reg(struct wm831x_irq_data *irq_data)
return WM831X_INTERRUPT_STATUS_1 - 1 + irq_data->reg;
}
-static inline int irq_data_to_mask_reg(struct wm831x_irq_data *irq_data)
-{
- return WM831X_INTERRUPT_STATUS_1_MASK - 1 + irq_data->reg;
-}
-
static inline struct wm831x_irq_data *irq_to_wm831x_irq(struct wm831x *wm831x,
int irq)
{
@@ -477,8 +472,7 @@ static irqreturn_t wm831x_irq_thread(int irq, void *data)
handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHPD);
if (primary & WM831X_TCHDATA_INT)
handle_nested_irq(wm831x->irq_base + WM831X_IRQ_TCHDATA);
- if (primary & (WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT))
- goto out;
+ primary &= ~(WM831X_TCHDATA_EINT | WM831X_TCHPD_EINT);
for (i = 0; i < ARRAY_SIZE(wm831x_irqs); i++) {
int offset = wm831x_irqs[i].reg - 1;
diff --git a/drivers/mfd/wm831x-spi.c b/drivers/mfd/wm831x-spi.c
index 8d6a9a969db..62ef3254105 100644
--- a/drivers/mfd/wm831x-spi.c
+++ b/drivers/mfd/wm831x-spi.c
@@ -30,7 +30,7 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi)
type = (enum wm831x_parent)id->driver_data;
- wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
+ wm831x = devm_kzalloc(&spi->dev, sizeof(struct wm831x), GFP_KERNEL);
if (wm831x == NULL)
return -ENOMEM;
@@ -45,7 +45,6 @@ static int __devinit wm831x_spi_probe(struct spi_device *spi)
ret = PTR_ERR(wm831x->regmap);
dev_err(wm831x->dev, "Failed to allocate register map: %d\n",
ret);
- kfree(wm831x);
return ret;
}
@@ -95,7 +94,6 @@ MODULE_DEVICE_TABLE(spi, wm831x_spi_id);
static struct spi_driver wm831x_spi_driver = {
.driver = {
.name = "wm831x",
- .bus = &spi_bus_type,
.owner = THIS_MODULE,
.pm = &wm831x_spi_pm,
},
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c
index e81cc31e420..dd1caaac55e 100644
--- a/drivers/mfd/wm8350-core.c
+++ b/drivers/mfd/wm8350-core.c
@@ -573,6 +573,8 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
u16 id1, id2, mask_rev;
u16 cust_id, mode, chip_rev;
+ dev_set_drvdata(wm8350->dev, wm8350);
+
/* get WM8350 revision and config mode */
ret = wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1);
if (ret != 0) {
diff --git a/drivers/mfd/wm8350-i2c.c b/drivers/mfd/wm8350-i2c.c
index 5fe5de166ad..d955faaf27c 100644
--- a/drivers/mfd/wm8350-i2c.c
+++ b/drivers/mfd/wm8350-i2c.c
@@ -63,7 +63,7 @@ static int wm8350_i2c_probe(struct i2c_client *i2c,
struct wm8350 *wm8350;
int ret = 0;
- wm8350 = kzalloc(sizeof(struct wm8350), GFP_KERNEL);
+ wm8350 = devm_kzalloc(&i2c->dev, sizeof(struct wm8350), GFP_KERNEL);
if (wm8350 == NULL)
return -ENOMEM;
@@ -80,7 +80,6 @@ static int wm8350_i2c_probe(struct i2c_client *i2c,
return ret;
err:
- kfree(wm8350);
return ret;
}
@@ -89,7 +88,6 @@ static int wm8350_i2c_remove(struct i2c_client *i2c)
struct wm8350 *wm8350 = i2c_get_clientdata(i2c);
wm8350_device_exit(wm8350);
- kfree(wm8350);
return 0;
}
diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c
index 62b4626f456..2204893444a 100644
--- a/drivers/mfd/wm8400-core.c
+++ b/drivers/mfd/wm8400-core.c
@@ -344,7 +344,7 @@ static int wm8400_i2c_probe(struct i2c_client *i2c,
struct wm8400 *wm8400;
int ret;
- wm8400 = kzalloc(sizeof(struct wm8400), GFP_KERNEL);
+ wm8400 = devm_kzalloc(&i2c->dev, sizeof(struct wm8400), GFP_KERNEL);
if (wm8400 == NULL) {
ret = -ENOMEM;
goto err;
@@ -353,7 +353,7 @@ static int wm8400_i2c_probe(struct i2c_client *i2c,
wm8400->regmap = regmap_init_i2c(i2c, &wm8400_regmap_config);
if (IS_ERR(wm8400->regmap)) {
ret = PTR_ERR(wm8400->regmap);
- goto struct_err;
+ goto err;
}
wm8400->dev = &i2c->dev;
@@ -367,8 +367,6 @@ static int wm8400_i2c_probe(struct i2c_client *i2c,
map_err:
regmap_exit(wm8400->regmap);
-struct_err:
- kfree(wm8400);
err:
return ret;
}
@@ -379,7 +377,6 @@ static int wm8400_i2c_remove(struct i2c_client *i2c)
wm8400_release(wm8400);
regmap_exit(wm8400->regmap);
- kfree(wm8400);
return 0;
}
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index 5d6ba132837..f117e7fb932 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -28,11 +28,7 @@
#include <linux/mfd/wm8994/pdata.h>
#include <linux/mfd/wm8994/registers.h>
-static int wm8994_read(struct wm8994 *wm8994, unsigned short reg,
- int bytes, void *dest)
-{
- return regmap_raw_read(wm8994->regmap, reg, dest, bytes);
-}
+#include "wm8994.h"
/**
* wm8994_reg_read: Read a single WM8994 register.
@@ -68,12 +64,6 @@ int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg,
return regmap_bulk_read(wm8994->regmap, reg, buf, count);
}
-static int wm8994_write(struct wm8994 *wm8994, unsigned short reg,
- int bytes, const void *src)
-{
- return regmap_raw_write(wm8994->regmap, reg, src, bytes);
-}
-
/**
* wm8994_reg_write: Write a single WM8994 register.
*
@@ -239,6 +229,7 @@ static int wm8994_suspend(struct device *dev)
switch (wm8994->type) {
case WM8958:
+ case WM1811:
ret = wm8994_reg_read(wm8994, WM8958_MIC_DETECT_1);
if (ret < 0) {
dev_err(dev, "Failed to read power status: %d\n", ret);
@@ -251,6 +242,20 @@ static int wm8994_suspend(struct device *dev)
break;
}
+ switch (wm8994->type) {
+ case WM1811:
+ ret = wm8994_reg_read(wm8994, WM8994_ANTIPOP_2);
+ if (ret < 0) {
+ dev_err(dev, "Failed to read jackdet: %d\n", ret);
+ } else if (ret & WM1811_JACKDET_MODE_MASK) {
+ dev_dbg(dev, "CODEC still active, ignoring suspend\n");
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+
/* Disable LDO pulldowns while the device is suspended if we
* don't know that something will be driving them. */
if (!wm8994->ldo_ena_always_driven)
@@ -258,25 +263,14 @@ static int wm8994_suspend(struct device *dev)
WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD,
WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD);
- /* GPIO configuration state is saved here since we may be configuring
- * the GPIO alternate functions even if we're not using the gpiolib
- * driver for them.
- */
- ret = wm8994_read(wm8994, WM8994_GPIO_1, WM8994_NUM_GPIO_REGS * 2,
- &wm8994->gpio_regs);
- if (ret < 0)
- dev_err(dev, "Failed to save GPIO registers: %d\n", ret);
-
- /* For similar reasons we also stash the regulator states */
- ret = wm8994_read(wm8994, WM8994_LDO_1, WM8994_NUM_LDO_REGS * 2,
- &wm8994->ldo_regs);
- if (ret < 0)
- dev_err(dev, "Failed to save LDO registers: %d\n", ret);
-
/* Explicitly put the device into reset in case regulators
* don't get disabled in order to ensure consistent restart.
*/
- wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET, 0x8994);
+ wm8994_reg_write(wm8994, WM8994_SOFTWARE_RESET,
+ wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET));
+
+ regcache_cache_only(wm8994->regmap, true);
+ regcache_mark_dirty(wm8994->regmap);
wm8994->suspended = true;
@@ -293,7 +287,7 @@ static int wm8994_suspend(struct device *dev)
static int wm8994_resume(struct device *dev)
{
struct wm8994 *wm8994 = dev_get_drvdata(dev);
- int ret, i;
+ int ret;
/* We may have lied to the PM core about suspending */
if (!wm8994->suspended)
@@ -306,27 +300,13 @@ static int wm8994_resume(struct device *dev)
return ret;
}
- /* Write register at a time as we use the cache on the CPU so store
- * it in native endian.
- */
- for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
- ret = wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1_MASK
- + i, wm8994->irq_masks_cur[i]);
- if (ret < 0)
- dev_err(dev, "Failed to restore interrupt masks: %d\n",
- ret);
+ regcache_cache_only(wm8994->regmap, false);
+ ret = regcache_sync(wm8994->regmap);
+ if (ret != 0) {
+ dev_err(dev, "Failed to restore register map: %d\n", ret);
+ goto err_enable;
}
- ret = wm8994_write(wm8994, WM8994_LDO_1, WM8994_NUM_LDO_REGS * 2,
- &wm8994->ldo_regs);
- if (ret < 0)
- dev_err(dev, "Failed to restore LDO registers: %d\n", ret);
-
- ret = wm8994_write(wm8994, WM8994_GPIO_1, WM8994_NUM_GPIO_REGS * 2,
- &wm8994->gpio_regs);
- if (ret < 0)
- dev_err(dev, "Failed to restore GPIO registers: %d\n", ret);
-
/* Disable LDO pulldowns while the device is active */
wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2,
WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD,
@@ -335,6 +315,11 @@ static int wm8994_resume(struct device *dev)
wm8994->suspended = false;
return 0;
+
+err_enable:
+ regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies);
+
+ return ret;
}
#endif
@@ -360,19 +345,16 @@ static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo)
}
#endif
-static struct regmap_config wm8994_regmap_config = {
- .reg_bits = 16,
- .val_bits = 16,
-};
-
/*
* Instantiate the generic non-control parts of the device.
*/
static int wm8994_device_init(struct wm8994 *wm8994, int irq)
{
struct wm8994_pdata *pdata = wm8994->dev->platform_data;
+ struct regmap_config *regmap_config;
const char *devname;
int ret, i;
+ int pulls = 0;
dev_set_drvdata(wm8994->dev, wm8994);
@@ -401,9 +383,9 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
goto err_regmap;
}
- wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
- wm8994->num_supplies,
- GFP_KERNEL);
+ wm8994->supplies = devm_kzalloc(wm8994->dev,
+ sizeof(struct regulator_bulk_data) *
+ wm8994->num_supplies, GFP_KERNEL);
if (!wm8994->supplies) {
ret = -ENOMEM;
goto err_regmap;
@@ -431,7 +413,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
wm8994->supplies);
if (ret != 0) {
dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret);
- goto err_supplies;
+ goto err_regmap;
}
ret = regulator_bulk_enable(wm8994->num_supplies,
@@ -481,25 +463,54 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
ret);
goto err_enable;
}
+ wm8994->revision = ret;
switch (wm8994->type) {
case WM8994:
- switch (ret) {
+ switch (wm8994->revision) {
case 0:
case 1:
dev_warn(wm8994->dev,
"revision %c not fully supported\n",
- 'A' + ret);
+ 'A' + wm8994->revision);
break;
default:
break;
}
break;
+ case WM1811:
+ /* Revision C did not change the relevant layer */
+ if (wm8994->revision > 1)
+ wm8994->revision++;
+ break;
default:
break;
}
- dev_info(wm8994->dev, "%s revision %c\n", devname, 'A' + ret);
+ dev_info(wm8994->dev, "%s revision %c\n", devname,
+ 'A' + wm8994->revision);
+
+ switch (wm8994->type) {
+ case WM1811:
+ regmap_config = &wm1811_regmap_config;
+ break;
+ case WM8994:
+ regmap_config = &wm8994_regmap_config;
+ break;
+ case WM8958:
+ regmap_config = &wm8958_regmap_config;
+ break;
+ default:
+ dev_err(wm8994->dev, "Unknown device type %d\n", wm8994->type);
+ return -EINVAL;
+ }
+
+ ret = regmap_reinit_cache(wm8994->regmap, regmap_config);
+ if (ret != 0) {
+ dev_err(wm8994->dev, "Failed to reinit register cache: %d\n",
+ ret);
+ return ret;
+ }
if (pdata) {
wm8994->irq_base = pdata->irq_base;
@@ -515,12 +526,16 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
}
wm8994->ldo_ena_always_driven = pdata->ldo_ena_always_driven;
+
+ if (pdata->spkmode_pu)
+ pulls |= WM8994_SPKMODE_PU;
}
- /* Disable LDO pulldowns while the device is active */
+ /* Disable unneeded pulls */
wm8994_set_bits(wm8994, WM8994_PULL_CONTROL_2,
- WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD,
- 0);
+ WM8994_LDO1ENA_PD | WM8994_LDO2ENA_PD |
+ WM8994_SPKMODE_PU | WM8994_CSNADDR_PD,
+ pulls);
/* In some system designs where the regulators are not in use,
* we can achieve a small reduction in leakage currents by
@@ -559,12 +574,9 @@ err_enable:
wm8994->supplies);
err_get:
regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
-err_supplies:
- kfree(wm8994->supplies);
err_regmap:
regmap_exit(wm8994->regmap);
mfd_remove_devices(wm8994->dev);
- kfree(wm8994);
return ret;
}
@@ -576,18 +588,24 @@ static void wm8994_device_exit(struct wm8994 *wm8994)
regulator_bulk_disable(wm8994->num_supplies,
wm8994->supplies);
regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
- kfree(wm8994->supplies);
regmap_exit(wm8994->regmap);
- kfree(wm8994);
}
+static const struct of_device_id wm8994_of_match[] = {
+ { .compatible = "wlf,wm1811", },
+ { .compatible = "wlf,wm8994", },
+ { .compatible = "wlf,wm8958", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wm8994_of_match);
+
static int wm8994_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8994 *wm8994;
int ret;
- wm8994 = kzalloc(sizeof(struct wm8994), GFP_KERNEL);
+ wm8994 = devm_kzalloc(&i2c->dev, sizeof(struct wm8994), GFP_KERNEL);
if (wm8994 == NULL)
return -ENOMEM;
@@ -596,12 +614,11 @@ static int wm8994_i2c_probe(struct i2c_client *i2c,
wm8994->irq = i2c->irq;
wm8994->type = id->driver_data;
- wm8994->regmap = regmap_init_i2c(i2c, &wm8994_regmap_config);
+ wm8994->regmap = regmap_init_i2c(i2c, &wm8994_base_regmap_config);
if (IS_ERR(wm8994->regmap)) {
ret = PTR_ERR(wm8994->regmap);
dev_err(wm8994->dev, "Failed to allocate register map: %d\n",
ret);
- kfree(wm8994);
return ret;
}
@@ -619,6 +636,7 @@ static int wm8994_i2c_remove(struct i2c_client *i2c)
static const struct i2c_device_id wm8994_i2c_id[] = {
{ "wm1811", WM1811 },
+ { "wm1811a", WM1811 },
{ "wm8994", WM8994 },
{ "wm8958", WM8958 },
{ }
@@ -633,6 +651,7 @@ static struct i2c_driver wm8994_i2c_driver = {
.name = "wm8994",
.owner = THIS_MODULE,
.pm = &wm8994_pm_ops,
+ .of_match_table = wm8994_of_match,
},
.probe = wm8994_i2c_probe,
.remove = wm8994_i2c_remove,
diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c
index d682f7bd112..46b20c445ec 100644
--- a/drivers/mfd/wm8994-irq.c
+++ b/drivers/mfd/wm8994-irq.c
@@ -18,248 +18,127 @@
#include <linux/irq.h>
#include <linux/mfd/core.h>
#include <linux/interrupt.h>
+#include <linux/regmap.h>
#include <linux/mfd/wm8994/core.h>
#include <linux/mfd/wm8994/registers.h>
#include <linux/delay.h>
-struct wm8994_irq_data {
- int reg;
- int mask;
-};
-
-static struct wm8994_irq_data wm8994_irqs[] = {
+static struct regmap_irq wm8994_irqs[] = {
[WM8994_IRQ_TEMP_SHUT] = {
- .reg = 2,
+ .reg_offset = 1,
.mask = WM8994_TEMP_SHUT_EINT,
},
[WM8994_IRQ_MIC1_DET] = {
- .reg = 2,
+ .reg_offset = 1,
.mask = WM8994_MIC1_DET_EINT,
},
[WM8994_IRQ_MIC1_SHRT] = {
- .reg = 2,
+ .reg_offset = 1,
.mask = WM8994_MIC1_SHRT_EINT,
},
[WM8994_IRQ_MIC2_DET] = {
- .reg = 2,
+ .reg_offset = 1,
.mask = WM8994_MIC2_DET_EINT,
},
[WM8994_IRQ_MIC2_SHRT] = {
- .reg = 2,
+ .reg_offset = 1,
.mask = WM8994_MIC2_SHRT_EINT,
},
[WM8994_IRQ_FLL1_LOCK] = {
- .reg = 2,
+ .reg_offset = 1,
.mask = WM8994_FLL1_LOCK_EINT,
},
[WM8994_IRQ_FLL2_LOCK] = {
- .reg = 2,
+ .reg_offset = 1,
.mask = WM8994_FLL2_LOCK_EINT,
},
[WM8994_IRQ_SRC1_LOCK] = {
- .reg = 2,
+ .reg_offset = 1,
.mask = WM8994_SRC1_LOCK_EINT,
},
[WM8994_IRQ_SRC2_LOCK] = {
- .reg = 2,
+ .reg_offset = 1,
.mask = WM8994_SRC2_LOCK_EINT,
},
[WM8994_IRQ_AIF1DRC1_SIG_DET] = {
- .reg = 2,
+ .reg_offset = 1,
.mask = WM8994_AIF1DRC1_SIG_DET,
},
[WM8994_IRQ_AIF1DRC2_SIG_DET] = {
- .reg = 2,
+ .reg_offset = 1,
.mask = WM8994_AIF1DRC2_SIG_DET_EINT,
},
[WM8994_IRQ_AIF2DRC_SIG_DET] = {
- .reg = 2,
+ .reg_offset = 1,
.mask = WM8994_AIF2DRC_SIG_DET_EINT,
},
[WM8994_IRQ_FIFOS_ERR] = {
- .reg = 2,
+ .reg_offset = 1,
.mask = WM8994_FIFOS_ERR_EINT,
},
[WM8994_IRQ_WSEQ_DONE] = {
- .reg = 2,
+ .reg_offset = 1,
.mask = WM8994_WSEQ_DONE_EINT,
},
[WM8994_IRQ_DCS_DONE] = {
- .reg = 2,
+ .reg_offset = 1,
.mask = WM8994_DCS_DONE_EINT,
},
[WM8994_IRQ_TEMP_WARN] = {
- .reg = 2,
+ .reg_offset = 1,
.mask = WM8994_TEMP_WARN_EINT,
},
[WM8994_IRQ_GPIO(1)] = {
- .reg = 1,
.mask = WM8994_GP1_EINT,
},
[WM8994_IRQ_GPIO(2)] = {
- .reg = 1,
.mask = WM8994_GP2_EINT,
},
[WM8994_IRQ_GPIO(3)] = {
- .reg = 1,
.mask = WM8994_GP3_EINT,
},
[WM8994_IRQ_GPIO(4)] = {
- .reg = 1,
.mask = WM8994_GP4_EINT,
},
[WM8994_IRQ_GPIO(5)] = {
- .reg = 1,
.mask = WM8994_GP5_EINT,
},
[WM8994_IRQ_GPIO(6)] = {
- .reg = 1,
.mask = WM8994_GP6_EINT,
},
[WM8994_IRQ_GPIO(7)] = {
- .reg = 1,
.mask = WM8994_GP7_EINT,
},
[WM8994_IRQ_GPIO(8)] = {
- .reg = 1,
.mask = WM8994_GP8_EINT,
},
[WM8994_IRQ_GPIO(9)] = {
- .reg = 1,
.mask = WM8994_GP8_EINT,
},
[WM8994_IRQ_GPIO(10)] = {
- .reg = 1,
.mask = WM8994_GP10_EINT,
},
[WM8994_IRQ_GPIO(11)] = {
- .reg = 1,
.mask = WM8994_GP11_EINT,
},
};
-static inline int irq_data_to_status_reg(struct wm8994_irq_data *irq_data)
-{
- return WM8994_INTERRUPT_STATUS_1 - 1 + irq_data->reg;
-}
-
-static inline int irq_data_to_mask_reg(struct wm8994_irq_data *irq_data)
-{
- return WM8994_INTERRUPT_STATUS_1_MASK - 1 + irq_data->reg;
-}
-
-static inline struct wm8994_irq_data *irq_to_wm8994_irq(struct wm8994 *wm8994,
- int irq)
-{
- return &wm8994_irqs[irq - wm8994->irq_base];
-}
-
-static void wm8994_irq_lock(struct irq_data *data)
-{
- struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
-
- mutex_lock(&wm8994->irq_lock);
-}
-
-static void wm8994_irq_sync_unlock(struct irq_data *data)
-{
- struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
- /* If there's been a change in the mask write it back
- * to the hardware. */
- if (wm8994->irq_masks_cur[i] != wm8994->irq_masks_cache[i]) {
- wm8994->irq_masks_cache[i] = wm8994->irq_masks_cur[i];
- wm8994_reg_write(wm8994,
- WM8994_INTERRUPT_STATUS_1_MASK + i,
- wm8994->irq_masks_cur[i]);
- }
- }
-
- mutex_unlock(&wm8994->irq_lock);
-}
-
-static void wm8994_irq_enable(struct irq_data *data)
-{
- struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
- struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
- data->irq);
-
- wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
-}
-
-static void wm8994_irq_disable(struct irq_data *data)
-{
- struct wm8994 *wm8994 = irq_data_get_irq_chip_data(data);
- struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994,
- data->irq);
-
- wm8994->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
-}
+static struct regmap_irq_chip wm8994_irq_chip = {
+ .name = "wm8994",
+ .irqs = wm8994_irqs,
+ .num_irqs = ARRAY_SIZE(wm8994_irqs),
-static struct irq_chip wm8994_irq_chip = {
- .name = "wm8994",
- .irq_bus_lock = wm8994_irq_lock,
- .irq_bus_sync_unlock = wm8994_irq_sync_unlock,
- .irq_disable = wm8994_irq_disable,
- .irq_enable = wm8994_irq_enable,
+ .num_regs = 2,
+ .status_base = WM8994_INTERRUPT_STATUS_1,
+ .mask_base = WM8994_INTERRUPT_STATUS_1_MASK,
+ .ack_base = WM8994_INTERRUPT_STATUS_1,
};
-/* The processing of the primary interrupt occurs in a thread so that
- * we can interact with the device over I2C or SPI. */
-static irqreturn_t wm8994_irq_thread(int irq, void *data)
-{
- struct wm8994 *wm8994 = data;
- unsigned int i;
- u16 status[WM8994_NUM_IRQ_REGS];
- int ret;
-
- ret = wm8994_bulk_read(wm8994, WM8994_INTERRUPT_STATUS_1,
- WM8994_NUM_IRQ_REGS, status);
- if (ret < 0) {
- dev_err(wm8994->dev, "Failed to read interrupt status: %d\n",
- ret);
- return IRQ_NONE;
- }
-
- /* Bit swap and apply masking */
- for (i = 0; i < WM8994_NUM_IRQ_REGS; i++) {
- status[i] = be16_to_cpu(status[i]);
- status[i] &= ~wm8994->irq_masks_cur[i];
- }
-
- /* Ack any unmasked IRQs */
- for (i = 0; i < ARRAY_SIZE(status); i++) {
- if (status[i])
- wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1 + i,
- status[i]);
- }
-
- /* Report */
- for (i = 0; i < ARRAY_SIZE(wm8994_irqs); i++) {
- if (status[wm8994_irqs[i].reg - 1] & wm8994_irqs[i].mask)
- handle_nested_irq(wm8994->irq_base + i);
- }
-
- return IRQ_HANDLED;
-}
-
int wm8994_irq_init(struct wm8994 *wm8994)
{
- int i, cur_irq, ret;
-
- mutex_init(&wm8994->irq_lock);
-
- /* Mask the individual interrupt sources */
- for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
- wm8994->irq_masks_cur[i] = 0xffff;
- wm8994->irq_masks_cache[i] = 0xffff;
- wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1_MASK + i,
- 0xffff);
- }
+ int ret;
if (!wm8994->irq) {
dev_warn(wm8994->dev,
@@ -274,30 +153,12 @@ int wm8994_irq_init(struct wm8994 *wm8994)
return 0;
}
- /* Register them with genirq */
- for (cur_irq = wm8994->irq_base;
- cur_irq < ARRAY_SIZE(wm8994_irqs) + wm8994->irq_base;
- cur_irq++) {
- irq_set_chip_data(cur_irq, wm8994);
- irq_set_chip_and_handler(cur_irq, &wm8994_irq_chip,
- handle_edge_irq);
- irq_set_nested_thread(cur_irq, 1);
-
- /* ARM needs us to explicitly flag the IRQ as valid
- * and will set them noprobe when we do so. */
-#ifdef CONFIG_ARM
- set_irq_flags(cur_irq, IRQF_VALID);
-#else
- irq_set_noprobe(cur_irq);
-#endif
- }
-
- ret = request_threaded_irq(wm8994->irq, NULL, wm8994_irq_thread,
- IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
- "wm8994", wm8994);
+ ret = regmap_add_irq_chip(wm8994->regmap, wm8994->irq,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ wm8994->irq_base, &wm8994_irq_chip,
+ &wm8994->irq_data);
if (ret != 0) {
- dev_err(wm8994->dev, "Failed to request IRQ %d: %d\n",
- wm8994->irq, ret);
+ dev_err(wm8994->dev, "Failed to register IRQ chip: %d\n", ret);
return ret;
}
@@ -309,6 +170,5 @@ int wm8994_irq_init(struct wm8994 *wm8994)
void wm8994_irq_exit(struct wm8994 *wm8994)
{
- if (wm8994->irq)
- free_irq(wm8994->irq, wm8994);
+ regmap_del_irq_chip(wm8994->irq, wm8994->irq_data);
}
diff --git a/drivers/mfd/wm8994-regmap.c b/drivers/mfd/wm8994-regmap.c
new file mode 100644
index 00000000000..c598ae69b8f
--- /dev/null
+++ b/drivers/mfd/wm8994-regmap.c
@@ -0,0 +1,1238 @@
+/*
+ * wm8994-regmap.c -- Register map data for WM8994 series devices
+ *
+ * Copyright 2011 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/mfd/wm8994/core.h>
+#include <linux/mfd/wm8994/registers.h>
+#include <linux/regmap.h>
+
+#include "wm8994.h"
+
+static struct reg_default wm1811_defaults[] = {
+ { 0x0000, 0x1811 }, /* R0 - Software Reset */
+ { 0x0001, 0x0000 }, /* R1 - Power Management (1) */
+ { 0x0002, 0x6000 }, /* R2 - Power Management (2) */
+ { 0x0003, 0x0000 }, /* R3 - Power Management (3) */
+ { 0x0004, 0x0000 }, /* R4 - Power Management (4) */
+ { 0x0005, 0x0000 }, /* R5 - Power Management (5) */
+ { 0x0006, 0x0000 }, /* R6 - Power Management (6) */
+ { 0x0015, 0x0000 }, /* R21 - Input Mixer (1) */
+ { 0x0018, 0x008B }, /* R24 - Left Line Input 1&2 Volume */
+ { 0x0019, 0x008B }, /* R25 - Left Line Input 3&4 Volume */
+ { 0x001A, 0x008B }, /* R26 - Right Line Input 1&2 Volume */
+ { 0x001B, 0x008B }, /* R27 - Right Line Input 3&4 Volume */
+ { 0x001C, 0x006D }, /* R28 - Left Output Volume */
+ { 0x001D, 0x006D }, /* R29 - Right Output Volume */
+ { 0x001E, 0x0066 }, /* R30 - Line Outputs Volume */
+ { 0x001F, 0x0020 }, /* R31 - HPOUT2 Volume */
+ { 0x0020, 0x0079 }, /* R32 - Left OPGA Volume */
+ { 0x0021, 0x0079 }, /* R33 - Right OPGA Volume */
+ { 0x0022, 0x0003 }, /* R34 - SPKMIXL Attenuation */
+ { 0x0023, 0x0003 }, /* R35 - SPKMIXR Attenuation */
+ { 0x0024, 0x0011 }, /* R36 - SPKOUT Mixers */
+ { 0x0025, 0x0140 }, /* R37 - ClassD */
+ { 0x0026, 0x0079 }, /* R38 - Speaker Volume Left */
+ { 0x0027, 0x0079 }, /* R39 - Speaker Volume Right */
+ { 0x0028, 0x0000 }, /* R40 - Input Mixer (2) */
+ { 0x0029, 0x0000 }, /* R41 - Input Mixer (3) */
+ { 0x002A, 0x0000 }, /* R42 - Input Mixer (4) */
+ { 0x002B, 0x0000 }, /* R43 - Input Mixer (5) */
+ { 0x002C, 0x0000 }, /* R44 - Input Mixer (6) */
+ { 0x002D, 0x0000 }, /* R45 - Output Mixer (1) */
+ { 0x002E, 0x0000 }, /* R46 - Output Mixer (2) */
+ { 0x002F, 0x0000 }, /* R47 - Output Mixer (3) */
+ { 0x0030, 0x0000 }, /* R48 - Output Mixer (4) */
+ { 0x0031, 0x0000 }, /* R49 - Output Mixer (5) */
+ { 0x0032, 0x0000 }, /* R50 - Output Mixer (6) */
+ { 0x0033, 0x0000 }, /* R51 - HPOUT2 Mixer */
+ { 0x0034, 0x0000 }, /* R52 - Line Mixer (1) */
+ { 0x0035, 0x0000 }, /* R53 - Line Mixer (2) */
+ { 0x0036, 0x0000 }, /* R54 - Speaker Mixer */
+ { 0x0037, 0x0000 }, /* R55 - Additional Control */
+ { 0x0038, 0x0000 }, /* R56 - AntiPOP (1) */
+ { 0x0039, 0x0180 }, /* R57 - AntiPOP (2) */
+ { 0x003B, 0x000D }, /* R59 - LDO 1 */
+ { 0x003C, 0x0003 }, /* R60 - LDO 2 */
+ { 0x003D, 0x0039 }, /* R61 - MICBIAS1 */
+ { 0x003E, 0x0039 }, /* R62 - MICBIAS2 */
+ { 0x004C, 0x1F25 }, /* R76 - Charge Pump (1) */
+ { 0x004D, 0xAB19 }, /* R77 - Charge Pump (2) */
+ { 0x0051, 0x0004 }, /* R81 - Class W (1) */
+ { 0x0054, 0x0000 }, /* R84 - DC Servo (1) */
+ { 0x0055, 0x054A }, /* R85 - DC Servo (2) */
+ { 0x0058, 0x0000 }, /* R88 - DC Servo Readback */
+ { 0x0059, 0x0000 }, /* R89 - DC Servo (4) */
+ { 0x0060, 0x0000 }, /* R96 - Analogue HP (1) */
+ { 0x00C5, 0x0000 }, /* R197 - Class D Test (5) */
+ { 0x00D0, 0x7600 }, /* R208 - Mic Detect 1 */
+ { 0x00D1, 0x007F }, /* R209 - Mic Detect 2 */
+ { 0x00D2, 0x0000 }, /* R210 - Mic Detect 3 */
+ { 0x0100, 0x0100 }, /* R256 - Chip Revision */
+ { 0x0101, 0x8004 }, /* R257 - Control Interface */
+ { 0x0200, 0x0000 }, /* R512 - AIF1 Clocking (1) */
+ { 0x0201, 0x0000 }, /* R513 - AIF1 Clocking (2) */
+ { 0x0204, 0x0000 }, /* R516 - AIF2 Clocking (1) */
+ { 0x0205, 0x0000 }, /* R517 - AIF2 Clocking (2) */
+ { 0x0208, 0x0000 }, /* R520 - Clocking (1) */
+ { 0x0209, 0x0000 }, /* R521 - Clocking (2) */
+ { 0x0210, 0x0083 }, /* R528 - AIF1 Rate */
+ { 0x0211, 0x0083 }, /* R529 - AIF2 Rate */
+ { 0x0212, 0x0000 }, /* R530 - Rate Status */
+ { 0x0220, 0x0000 }, /* R544 - FLL1 Control (1) */
+ { 0x0221, 0x0000 }, /* R545 - FLL1 Control (2) */
+ { 0x0222, 0x0000 }, /* R546 - FLL1 Control (3) */
+ { 0x0223, 0x0000 }, /* R547 - FLL1 Control (4) */
+ { 0x0224, 0x0C80 }, /* R548 - FLL1 Control (5) */
+ { 0x0226, 0x0000 }, /* R550 - FLL1 EFS 1 */
+ { 0x0227, 0x0006 }, /* R551 - FLL1 EFS 2 */
+ { 0x0240, 0x0000 }, /* R576 - FLL2Control (1) */
+ { 0x0241, 0x0000 }, /* R577 - FLL2Control (2) */
+ { 0x0242, 0x0000 }, /* R578 - FLL2Control (3) */
+ { 0x0243, 0x0000 }, /* R579 - FLL2 Control (4) */
+ { 0x0244, 0x0C80 }, /* R580 - FLL2Control (5) */
+ { 0x0246, 0x0000 }, /* R582 - FLL2 EFS 1 */
+ { 0x0247, 0x0006 }, /* R583 - FLL2 EFS 2 */
+ { 0x0300, 0x4050 }, /* R768 - AIF1 Control (1) */
+ { 0x0301, 0x4000 }, /* R769 - AIF1 Control (2) */
+ { 0x0302, 0x0000 }, /* R770 - AIF1 Master/Slave */
+ { 0x0303, 0x0040 }, /* R771 - AIF1 BCLK */
+ { 0x0304, 0x0040 }, /* R772 - AIF1ADC LRCLK */
+ { 0x0305, 0x0040 }, /* R773 - AIF1DAC LRCLK */
+ { 0x0306, 0x0004 }, /* R774 - AIF1DAC Data */
+ { 0x0307, 0x0100 }, /* R775 - AIF1ADC Data */
+ { 0x0310, 0x4050 }, /* R784 - AIF2 Control (1) */
+ { 0x0311, 0x4000 }, /* R785 - AIF2 Control (2) */
+ { 0x0312, 0x0000 }, /* R786 - AIF2 Master/Slave */
+ { 0x0313, 0x0040 }, /* R787 - AIF2 BCLK */
+ { 0x0314, 0x0040 }, /* R788 - AIF2ADC LRCLK */
+ { 0x0315, 0x0040 }, /* R789 - AIF2DAC LRCLK */
+ { 0x0316, 0x0000 }, /* R790 - AIF2DAC Data */
+ { 0x0317, 0x0000 }, /* R791 - AIF2ADC Data */
+ { 0x0318, 0x0003 }, /* R792 - AIF2TX Control */
+ { 0x0320, 0x0040 }, /* R800 - AIF3 Control (1) */
+ { 0x0321, 0x0000 }, /* R801 - AIF3 Control (2) */
+ { 0x0322, 0x0000 }, /* R802 - AIF3DAC Data */
+ { 0x0323, 0x0000 }, /* R803 - AIF3ADC Data */
+ { 0x0400, 0x00C0 }, /* R1024 - AIF1 ADC1 Left Volume */
+ { 0x0401, 0x00C0 }, /* R1025 - AIF1 ADC1 Right Volume */
+ { 0x0402, 0x00C0 }, /* R1026 - AIF1 DAC1 Left Volume */
+ { 0x0403, 0x00C0 }, /* R1027 - AIF1 DAC1 Right Volume */
+ { 0x0410, 0x0000 }, /* R1040 - AIF1 ADC1 Filters */
+ { 0x0420, 0x0200 }, /* R1056 - AIF1 DAC1 Filters (1) */
+ { 0x0421, 0x0010 }, /* R1057 - AIF1 DAC1 Filters (2) */
+ { 0x0430, 0x0068 }, /* R1072 - AIF1 DAC1 Noise Gate */
+ { 0x0440, 0x0098 }, /* R1088 - AIF1 DRC1 (1) */
+ { 0x0441, 0x0845 }, /* R1089 - AIF1 DRC1 (2) */
+ { 0x0442, 0x0000 }, /* R1090 - AIF1 DRC1 (3) */
+ { 0x0443, 0x0000 }, /* R1091 - AIF1 DRC1 (4) */
+ { 0x0444, 0x0000 }, /* R1092 - AIF1 DRC1 (5) */
+ { 0x0480, 0x6318 }, /* R1152 - AIF1 DAC1 EQ Gains (1) */
+ { 0x0481, 0x6300 }, /* R1153 - AIF1 DAC1 EQ Gains (2) */
+ { 0x0482, 0x0FCA }, /* R1154 - AIF1 DAC1 EQ Band 1 A */
+ { 0x0483, 0x0400 }, /* R1155 - AIF1 DAC1 EQ Band 1 B */
+ { 0x0484, 0x00D8 }, /* R1156 - AIF1 DAC1 EQ Band 1 PG */
+ { 0x0485, 0x1EB5 }, /* R1157 - AIF1 DAC1 EQ Band 2 A */
+ { 0x0486, 0xF145 }, /* R1158 - AIF1 DAC1 EQ Band 2 B */
+ { 0x0487, 0x0B75 }, /* R1159 - AIF1 DAC1 EQ Band 2 C */
+ { 0x0488, 0x01C5 }, /* R1160 - AIF1 DAC1 EQ Band 2 PG */
+ { 0x0489, 0x1C58 }, /* R1161 - AIF1 DAC1 EQ Band 3 A */
+ { 0x048A, 0xF373 }, /* R1162 - AIF1 DAC1 EQ Band 3 B */
+ { 0x048B, 0x0A54 }, /* R1163 - AIF1 DAC1 EQ Band 3 C */
+ { 0x048C, 0x0558 }, /* R1164 - AIF1 DAC1 EQ Band 3 PG */
+ { 0x048D, 0x168E }, /* R1165 - AIF1 DAC1 EQ Band 4 A */
+ { 0x048E, 0xF829 }, /* R1166 - AIF1 DAC1 EQ Band 4 B */
+ { 0x048F, 0x07AD }, /* R1167 - AIF1 DAC1 EQ Band 4 C */
+ { 0x0490, 0x1103 }, /* R1168 - AIF1 DAC1 EQ Band 4 PG */
+ { 0x0491, 0x0564 }, /* R1169 - AIF1 DAC1 EQ Band 5 A */
+ { 0x0492, 0x0559 }, /* R1170 - AIF1 DAC1 EQ Band 5 B */
+ { 0x0493, 0x4000 }, /* R1171 - AIF1 DAC1 EQ Band 5 PG */
+ { 0x0494, 0x0000 }, /* R1172 - AIF1 DAC1 EQ Band 1 C */
+ { 0x0500, 0x00C0 }, /* R1280 - AIF2 ADC Left Volume */
+ { 0x0501, 0x00C0 }, /* R1281 - AIF2 ADC Right Volume */
+ { 0x0502, 0x00C0 }, /* R1282 - AIF2 DAC Left Volume */
+ { 0x0503, 0x00C0 }, /* R1283 - AIF2 DAC Right Volume */
+ { 0x0510, 0x0000 }, /* R1296 - AIF2 ADC Filters */
+ { 0x0520, 0x0200 }, /* R1312 - AIF2 DAC Filters (1) */
+ { 0x0521, 0x0010 }, /* R1313 - AIF2 DAC Filters (2) */
+ { 0x0530, 0x0068 }, /* R1328 - AIF2 DAC Noise Gate */
+ { 0x0540, 0x0098 }, /* R1344 - AIF2 DRC (1) */
+ { 0x0541, 0x0845 }, /* R1345 - AIF2 DRC (2) */
+ { 0x0542, 0x0000 }, /* R1346 - AIF2 DRC (3) */
+ { 0x0543, 0x0000 }, /* R1347 - AIF2 DRC (4) */
+ { 0x0544, 0x0000 }, /* R1348 - AIF2 DRC (5) */
+ { 0x0580, 0x6318 }, /* R1408 - AIF2 EQ Gains (1) */
+ { 0x0581, 0x6300 }, /* R1409 - AIF2 EQ Gains (2) */
+ { 0x0582, 0x0FCA }, /* R1410 - AIF2 EQ Band 1 A */
+ { 0x0583, 0x0400 }, /* R1411 - AIF2 EQ Band 1 B */
+ { 0x0584, 0x00D8 }, /* R1412 - AIF2 EQ Band 1 PG */
+ { 0x0585, 0x1EB5 }, /* R1413 - AIF2 EQ Band 2 A */
+ { 0x0586, 0xF145 }, /* R1414 - AIF2 EQ Band 2 B */
+ { 0x0587, 0x0B75 }, /* R1415 - AIF2 EQ Band 2 C */
+ { 0x0588, 0x01C5 }, /* R1416 - AIF2 EQ Band 2 PG */
+ { 0x0589, 0x1C58 }, /* R1417 - AIF2 EQ Band 3 A */
+ { 0x058A, 0xF373 }, /* R1418 - AIF2 EQ Band 3 B */
+ { 0x058B, 0x0A54 }, /* R1419 - AIF2 EQ Band 3 C */
+ { 0x058C, 0x0558 }, /* R1420 - AIF2 EQ Band 3 PG */
+ { 0x058D, 0x168E }, /* R1421 - AIF2 EQ Band 4 A */
+ { 0x058E, 0xF829 }, /* R1422 - AIF2 EQ Band 4 B */
+ { 0x058F, 0x07AD }, /* R1423 - AIF2 EQ Band 4 C */
+ { 0x0590, 0x1103 }, /* R1424 - AIF2 EQ Band 4 PG */
+ { 0x0591, 0x0564 }, /* R1425 - AIF2 EQ Band 5 A */
+ { 0x0592, 0x0559 }, /* R1426 - AIF2 EQ Band 5 B */
+ { 0x0593, 0x4000 }, /* R1427 - AIF2 EQ Band 5 PG */
+ { 0x0594, 0x0000 }, /* R1428 - AIF2 EQ Band 1 C */
+ { 0x0600, 0x0000 }, /* R1536 - DAC1 Mixer Volumes */
+ { 0x0601, 0x0000 }, /* R1537 - DAC1 Left Mixer Routing */
+ { 0x0602, 0x0000 }, /* R1538 - DAC1 Right Mixer Routing */
+ { 0x0603, 0x0000 }, /* R1539 - AIF2ADC Mixer Volumes */
+ { 0x0604, 0x0000 }, /* R1540 - AIF2ADC Left Mixer Routing */
+ { 0x0605, 0x0000 }, /* R1541 - AIF2ADC Right Mixer Routing */
+ { 0x0606, 0x0000 }, /* R1542 - AIF1 ADC1 Left Mixer Routing */
+ { 0x0607, 0x0000 }, /* R1543 - AIF1 ADC1 Right Mixer Routing */
+ { 0x0610, 0x02C0 }, /* R1552 - DAC1 Left Volume */
+ { 0x0611, 0x02C0 }, /* R1553 - DAC1 Right Volume */
+ { 0x0612, 0x02C0 }, /* R1554 - AIF2TX Left Volume */
+ { 0x0613, 0x02C0 }, /* R1555 - AIF2TX Right Volume */
+ { 0x0614, 0x0000 }, /* R1556 - DAC Softmute */
+ { 0x0620, 0x0002 }, /* R1568 - Oversampling */
+ { 0x0621, 0x0000 }, /* R1569 - Sidetone */
+ { 0x0700, 0x8100 }, /* R1792 - GPIO 1 */
+ { 0x0701, 0xA101 }, /* R1793 - Pull Control (MCLK2) */
+ { 0x0702, 0xA101 }, /* R1794 - Pull Control (BCLK2) */
+ { 0x0703, 0xA101 }, /* R1795 - Pull Control (DACLRCLK2) */
+ { 0x0704, 0xA101 }, /* R1796 - Pull Control (DACDAT2) */
+ { 0x0707, 0xA101 }, /* R1799 - GPIO 8 */
+ { 0x0708, 0xA101 }, /* R1800 - GPIO 9 */
+ { 0x0709, 0xA101 }, /* R1801 - GPIO 10 */
+ { 0x070A, 0xA101 }, /* R1802 - GPIO 11 */
+ { 0x0720, 0x0000 }, /* R1824 - Pull Control (1) */
+ { 0x0721, 0x0156 }, /* R1825 - Pull Control (2) */
+ { 0x0730, 0x0000 }, /* R1840 - Interrupt Status 1 */
+ { 0x0731, 0x0000 }, /* R1841 - Interrupt Status 2 */
+ { 0x0732, 0x0000 }, /* R1842 - Interrupt Raw Status 2 */
+ { 0x0738, 0x07FF }, /* R1848 - Interrupt Status 1 Mask */
+ { 0x0739, 0xDFEF }, /* R1849 - Interrupt Status 2 Mask */
+ { 0x0740, 0x0000 }, /* R1856 - Interrupt Control */
+ { 0x0748, 0x003F }, /* R1864 - IRQ Debounce */
+};
+
+static struct reg_default wm8994_defaults[] = {
+ { 0x0000, 0x8994 }, /* R0 - Software Reset */
+ { 0x0001, 0x0000 }, /* R1 - Power Management (1) */
+ { 0x0002, 0x6000 }, /* R2 - Power Management (2) */
+ { 0x0003, 0x0000 }, /* R3 - Power Management (3) */
+ { 0x0004, 0x0000 }, /* R4 - Power Management (4) */
+ { 0x0005, 0x0000 }, /* R5 - Power Management (5) */
+ { 0x0006, 0x0000 }, /* R6 - Power Management (6) */
+ { 0x0015, 0x0000 }, /* R21 - Input Mixer (1) */
+ { 0x0018, 0x008B }, /* R24 - Left Line Input 1&2 Volume */
+ { 0x0019, 0x008B }, /* R25 - Left Line Input 3&4 Volume */
+ { 0x001A, 0x008B }, /* R26 - Right Line Input 1&2 Volume */
+ { 0x001B, 0x008B }, /* R27 - Right Line Input 3&4 Volume */
+ { 0x001C, 0x006D }, /* R28 - Left Output Volume */
+ { 0x001D, 0x006D }, /* R29 - Right Output Volume */
+ { 0x001E, 0x0066 }, /* R30 - Line Outputs Volume */
+ { 0x001F, 0x0020 }, /* R31 - HPOUT2 Volume */
+ { 0x0020, 0x0079 }, /* R32 - Left OPGA Volume */
+ { 0x0021, 0x0079 }, /* R33 - Right OPGA Volume */
+ { 0x0022, 0x0003 }, /* R34 - SPKMIXL Attenuation */
+ { 0x0023, 0x0003 }, /* R35 - SPKMIXR Attenuation */
+ { 0x0024, 0x0011 }, /* R36 - SPKOUT Mixers */
+ { 0x0025, 0x0140 }, /* R37 - ClassD */
+ { 0x0026, 0x0079 }, /* R38 - Speaker Volume Left */
+ { 0x0027, 0x0079 }, /* R39 - Speaker Volume Right */
+ { 0x0028, 0x0000 }, /* R40 - Input Mixer (2) */
+ { 0x0029, 0x0000 }, /* R41 - Input Mixer (3) */
+ { 0x002A, 0x0000 }, /* R42 - Input Mixer (4) */
+ { 0x002B, 0x0000 }, /* R43 - Input Mixer (5) */
+ { 0x002C, 0x0000 }, /* R44 - Input Mixer (6) */
+ { 0x002D, 0x0000 }, /* R45 - Output Mixer (1) */
+ { 0x002E, 0x0000 }, /* R46 - Output Mixer (2) */
+ { 0x002F, 0x0000 }, /* R47 - Output Mixer (3) */
+ { 0x0030, 0x0000 }, /* R48 - Output Mixer (4) */
+ { 0x0031, 0x0000 }, /* R49 - Output Mixer (5) */
+ { 0x0032, 0x0000 }, /* R50 - Output Mixer (6) */
+ { 0x0033, 0x0000 }, /* R51 - HPOUT2 Mixer */
+ { 0x0034, 0x0000 }, /* R52 - Line Mixer (1) */
+ { 0x0035, 0x0000 }, /* R53 - Line Mixer (2) */
+ { 0x0036, 0x0000 }, /* R54 - Speaker Mixer */
+ { 0x0037, 0x0000 }, /* R55 - Additional Control */
+ { 0x0038, 0x0000 }, /* R56 - AntiPOP (1) */
+ { 0x0039, 0x0000 }, /* R57 - AntiPOP (2) */
+ { 0x003A, 0x0000 }, /* R58 - MICBIAS */
+ { 0x003B, 0x000D }, /* R59 - LDO 1 */
+ { 0x003C, 0x0003 }, /* R60 - LDO 2 */
+ { 0x004C, 0x1F25 }, /* R76 - Charge Pump (1) */
+ { 0x0051, 0x0004 }, /* R81 - Class W (1) */
+ { 0x0054, 0x0000 }, /* R84 - DC Servo (1) */
+ { 0x0055, 0x054A }, /* R85 - DC Servo (2) */
+ { 0x0057, 0x0000 }, /* R87 - DC Servo (4) */
+ { 0x0058, 0x0000 }, /* R88 - DC Servo Readback */
+ { 0x0060, 0x0000 }, /* R96 - Analogue HP (1) */
+ { 0x0100, 0x0003 }, /* R256 - Chip Revision */
+ { 0x0101, 0x8004 }, /* R257 - Control Interface */
+ { 0x0110, 0x0000 }, /* R272 - Write Sequencer Ctrl (1) */
+ { 0x0111, 0x0000 }, /* R273 - Write Sequencer Ctrl (2) */
+ { 0x0200, 0x0000 }, /* R512 - AIF1 Clocking (1) */
+ { 0x0201, 0x0000 }, /* R513 - AIF1 Clocking (2) */
+ { 0x0204, 0x0000 }, /* R516 - AIF2 Clocking (1) */
+ { 0x0205, 0x0000 }, /* R517 - AIF2 Clocking (2) */
+ { 0x0208, 0x0000 }, /* R520 - Clocking (1) */
+ { 0x0209, 0x0000 }, /* R521 - Clocking (2) */
+ { 0x0210, 0x0083 }, /* R528 - AIF1 Rate */
+ { 0x0211, 0x0083 }, /* R529 - AIF2 Rate */
+ { 0x0212, 0x0000 }, /* R530 - Rate Status */
+ { 0x0220, 0x0000 }, /* R544 - FLL1 Control (1) */
+ { 0x0221, 0x0000 }, /* R545 - FLL1 Control (2) */
+ { 0x0222, 0x0000 }, /* R546 - FLL1 Control (3) */
+ { 0x0223, 0x0000 }, /* R547 - FLL1 Control (4) */
+ { 0x0224, 0x0C80 }, /* R548 - FLL1 Control (5) */
+ { 0x0240, 0x0000 }, /* R576 - FLL2 Control (1) */
+ { 0x0241, 0x0000 }, /* R577 - FLL2 Control (2) */
+ { 0x0242, 0x0000 }, /* R578 - FLL2 Control (3) */
+ { 0x0243, 0x0000 }, /* R579 - FLL2 Control (4) */
+ { 0x0244, 0x0C80 }, /* R580 - FLL2 Control (5) */
+ { 0x0300, 0x4050 }, /* R768 - AIF1 Control (1) */
+ { 0x0301, 0x4000 }, /* R769 - AIF1 Control (2) */
+ { 0x0302, 0x0000 }, /* R770 - AIF1 Master/Slave */
+ { 0x0303, 0x0040 }, /* R771 - AIF1 BCLK */
+ { 0x0304, 0x0040 }, /* R772 - AIF1ADC LRCLK */
+ { 0x0305, 0x0040 }, /* R773 - AIF1DAC LRCLK */
+ { 0x0306, 0x0004 }, /* R774 - AIF1DAC Data */
+ { 0x0307, 0x0100 }, /* R775 - AIF1ADC Data */
+ { 0x0310, 0x4050 }, /* R784 - AIF2 Control (1) */
+ { 0x0311, 0x4000 }, /* R785 - AIF2 Control (2) */
+ { 0x0312, 0x0000 }, /* R786 - AIF2 Master/Slave */
+ { 0x0313, 0x0040 }, /* R787 - AIF2 BCLK */
+ { 0x0314, 0x0040 }, /* R788 - AIF2ADC LRCLK */
+ { 0x0315, 0x0040 }, /* R789 - AIF2DAC LRCLK */
+ { 0x0316, 0x0000 }, /* R790 - AIF2DAC Data */
+ { 0x0317, 0x0000 }, /* R791 - AIF2ADC Data */
+ { 0x0400, 0x00C0 }, /* R1024 - AIF1 ADC1 Left Volume */
+ { 0x0401, 0x00C0 }, /* R1025 - AIF1 ADC1 Right Volume */
+ { 0x0402, 0x00C0 }, /* R1026 - AIF1 DAC1 Left Volume */
+ { 0x0403, 0x00C0 }, /* R1027 - AIF1 DAC1 Right Volume */
+ { 0x0404, 0x00C0 }, /* R1028 - AIF1 ADC2 Left Volume */
+ { 0x0405, 0x00C0 }, /* R1029 - AIF1 ADC2 Right Volume */
+ { 0x0406, 0x00C0 }, /* R1030 - AIF1 DAC2 Left Volume */
+ { 0x0407, 0x00C0 }, /* R1031 - AIF1 DAC2 Right Volume */
+ { 0x0410, 0x0000 }, /* R1040 - AIF1 ADC1 Filters */
+ { 0x0411, 0x0000 }, /* R1041 - AIF1 ADC2 Filters */
+ { 0x0420, 0x0200 }, /* R1056 - AIF1 DAC1 Filters (1) */
+ { 0x0421, 0x0010 }, /* R1057 - AIF1 DAC1 Filters (2) */
+ { 0x0422, 0x0200 }, /* R1058 - AIF1 DAC2 Filters (1) */
+ { 0x0423, 0x0010 }, /* R1059 - AIF1 DAC2 Filters (2) */
+ { 0x0440, 0x0098 }, /* R1088 - AIF1 DRC1 (1) */
+ { 0x0441, 0x0845 }, /* R1089 - AIF1 DRC1 (2) */
+ { 0x0442, 0x0000 }, /* R1090 - AIF1 DRC1 (3) */
+ { 0x0443, 0x0000 }, /* R1091 - AIF1 DRC1 (4) */
+ { 0x0444, 0x0000 }, /* R1092 - AIF1 DRC1 (5) */
+ { 0x0450, 0x0098 }, /* R1104 - AIF1 DRC2 (1) */
+ { 0x0451, 0x0845 }, /* R1105 - AIF1 DRC2 (2) */
+ { 0x0452, 0x0000 }, /* R1106 - AIF1 DRC2 (3) */
+ { 0x0453, 0x0000 }, /* R1107 - AIF1 DRC2 (4) */
+ { 0x0454, 0x0000 }, /* R1108 - AIF1 DRC2 (5) */
+ { 0x0480, 0x6318 }, /* R1152 - AIF1 DAC1 EQ Gains (1) */
+ { 0x0481, 0x6300 }, /* R1153 - AIF1 DAC1 EQ Gains (2) */
+ { 0x0482, 0x0FCA }, /* R1154 - AIF1 DAC1 EQ Band 1 A */
+ { 0x0483, 0x0400 }, /* R1155 - AIF1 DAC1 EQ Band 1 B */
+ { 0x0484, 0x00D8 }, /* R1156 - AIF1 DAC1 EQ Band 1 PG */
+ { 0x0485, 0x1EB5 }, /* R1157 - AIF1 DAC1 EQ Band 2 A */
+ { 0x0486, 0xF145 }, /* R1158 - AIF1 DAC1 EQ Band 2 B */
+ { 0x0487, 0x0B75 }, /* R1159 - AIF1 DAC1 EQ Band 2 C */
+ { 0x0488, 0x01C5 }, /* R1160 - AIF1 DAC1 EQ Band 2 PG */
+ { 0x0489, 0x1C58 }, /* R1161 - AIF1 DAC1 EQ Band 3 A */
+ { 0x048A, 0xF373 }, /* R1162 - AIF1 DAC1 EQ Band 3 B */
+ { 0x048B, 0x0A54 }, /* R1163 - AIF1 DAC1 EQ Band 3 C */
+ { 0x048C, 0x0558 }, /* R1164 - AIF1 DAC1 EQ Band 3 PG */
+ { 0x048D, 0x168E }, /* R1165 - AIF1 DAC1 EQ Band 4 A */
+ { 0x048E, 0xF829 }, /* R1166 - AIF1 DAC1 EQ Band 4 B */
+ { 0x048F, 0x07AD }, /* R1167 - AIF1 DAC1 EQ Band 4 C */
+ { 0x0490, 0x1103 }, /* R1168 - AIF1 DAC1 EQ Band 4 PG */
+ { 0x0491, 0x0564 }, /* R1169 - AIF1 DAC1 EQ Band 5 A */
+ { 0x0492, 0x0559 }, /* R1170 - AIF1 DAC1 EQ Band 5 B */
+ { 0x0493, 0x4000 }, /* R1171 - AIF1 DAC1 EQ Band 5 PG */
+ { 0x04A0, 0x6318 }, /* R1184 - AIF1 DAC2 EQ Gains (1) */
+ { 0x04A1, 0x6300 }, /* R1185 - AIF1 DAC2 EQ Gains (2) */
+ { 0x04A2, 0x0FCA }, /* R1186 - AIF1 DAC2 EQ Band 1 A */
+ { 0x04A3, 0x0400 }, /* R1187 - AIF1 DAC2 EQ Band 1 B */
+ { 0x04A4, 0x00D8 }, /* R1188 - AIF1 DAC2 EQ Band 1 PG */
+ { 0x04A5, 0x1EB5 }, /* R1189 - AIF1 DAC2 EQ Band 2 A */
+ { 0x04A6, 0xF145 }, /* R1190 - AIF1 DAC2 EQ Band 2 B */
+ { 0x04A7, 0x0B75 }, /* R1191 - AIF1 DAC2 EQ Band 2 C */
+ { 0x04A8, 0x01C5 }, /* R1192 - AIF1 DAC2 EQ Band 2 PG */
+ { 0x04A9, 0x1C58 }, /* R1193 - AIF1 DAC2 EQ Band 3 A */
+ { 0x04AA, 0xF373 }, /* R1194 - AIF1 DAC2 EQ Band 3 B */
+ { 0x04AB, 0x0A54 }, /* R1195 - AIF1 DAC2 EQ Band 3 C */
+ { 0x04AC, 0x0558 }, /* R1196 - AIF1 DAC2 EQ Band 3 PG */
+ { 0x04AD, 0x168E }, /* R1197 - AIF1 DAC2 EQ Band 4 A */
+ { 0x04AE, 0xF829 }, /* R1198 - AIF1 DAC2 EQ Band 4 B */
+ { 0x04AF, 0x07AD }, /* R1199 - AIF1 DAC2 EQ Band 4 C */
+ { 0x04B0, 0x1103 }, /* R1200 - AIF1 DAC2 EQ Band 4 PG */
+ { 0x04B1, 0x0564 }, /* R1201 - AIF1 DAC2 EQ Band 5 A */
+ { 0x04B2, 0x0559 }, /* R1202 - AIF1 DAC2 EQ Band 5 B */
+ { 0x04B3, 0x4000 }, /* R1203 - AIF1 DAC2 EQ Band 5 PG */
+ { 0x0500, 0x00C0 }, /* R1280 - AIF2 ADC Left Volume */
+ { 0x0501, 0x00C0 }, /* R1281 - AIF2 ADC Right Volume */
+ { 0x0502, 0x00C0 }, /* R1282 - AIF2 DAC Left Volume */
+ { 0x0503, 0x00C0 }, /* R1283 - AIF2 DAC Right Volume */
+ { 0x0510, 0x0000 }, /* R1296 - AIF2 ADC Filters */
+ { 0x0520, 0x0200 }, /* R1312 - AIF2 DAC Filters (1) */
+ { 0x0521, 0x0010 }, /* R1313 - AIF2 DAC Filters (2) */
+ { 0x0540, 0x0098 }, /* R1344 - AIF2 DRC (1) */
+ { 0x0541, 0x0845 }, /* R1345 - AIF2 DRC (2) */
+ { 0x0542, 0x0000 }, /* R1346 - AIF2 DRC (3) */
+ { 0x0543, 0x0000 }, /* R1347 - AIF2 DRC (4) */
+ { 0x0544, 0x0000 }, /* R1348 - AIF2 DRC (5) */
+ { 0x0580, 0x6318 }, /* R1408 - AIF2 EQ Gains (1) */
+ { 0x0581, 0x6300 }, /* R1409 - AIF2 EQ Gains (2) */
+ { 0x0582, 0x0FCA }, /* R1410 - AIF2 EQ Band 1 A */
+ { 0x0583, 0x0400 }, /* R1411 - AIF2 EQ Band 1 B */
+ { 0x0584, 0x00D8 }, /* R1412 - AIF2 EQ Band 1 PG */
+ { 0x0585, 0x1EB5 }, /* R1413 - AIF2 EQ Band 2 A */
+ { 0x0586, 0xF145 }, /* R1414 - AIF2 EQ Band 2 B */
+ { 0x0587, 0x0B75 }, /* R1415 - AIF2 EQ Band 2 C */
+ { 0x0588, 0x01C5 }, /* R1416 - AIF2 EQ Band 2 PG */
+ { 0x0589, 0x1C58 }, /* R1417 - AIF2 EQ Band 3 A */
+ { 0x058A, 0xF373 }, /* R1418 - AIF2 EQ Band 3 B */
+ { 0x058B, 0x0A54 }, /* R1419 - AIF2 EQ Band 3 C */
+ { 0x058C, 0x0558 }, /* R1420 - AIF2 EQ Band 3 PG */
+ { 0x058D, 0x168E }, /* R1421 - AIF2 EQ Band 4 A */
+ { 0x058E, 0xF829 }, /* R1422 - AIF2 EQ Band 4 B */
+ { 0x058F, 0x07AD }, /* R1423 - AIF2 EQ Band 4 C */
+ { 0x0590, 0x1103 }, /* R1424 - AIF2 EQ Band 4 PG */
+ { 0x0591, 0x0564 }, /* R1425 - AIF2 EQ Band 5 A */
+ { 0x0592, 0x0559 }, /* R1426 - AIF2 EQ Band 5 B */
+ { 0x0593, 0x4000 }, /* R1427 - AIF2 EQ Band 5 PG */
+ { 0x0600, 0x0000 }, /* R1536 - DAC1 Mixer Volumes */
+ { 0x0601, 0x0000 }, /* R1537 - DAC1 Left Mixer Routing */
+ { 0x0602, 0x0000 }, /* R1538 - DAC1 Right Mixer Routing */
+ { 0x0603, 0x0000 }, /* R1539 - DAC2 Mixer Volumes */
+ { 0x0604, 0x0000 }, /* R1540 - DAC2 Left Mixer Routing */
+ { 0x0605, 0x0000 }, /* R1541 - DAC2 Right Mixer Routing */
+ { 0x0606, 0x0000 }, /* R1542 - AIF1 ADC1 Left Mixer Routing */
+ { 0x0607, 0x0000 }, /* R1543 - AIF1 ADC1 Right Mixer Routing */
+ { 0x0608, 0x0000 }, /* R1544 - AIF1 ADC2 Left Mixer Routing */
+ { 0x0609, 0x0000 }, /* R1545 - AIF1 ADC2 Right mixer Routing */
+ { 0x0610, 0x02C0 }, /* R1552 - DAC1 Left Volume */
+ { 0x0611, 0x02C0 }, /* R1553 - DAC1 Right Volume */
+ { 0x0612, 0x02C0 }, /* R1554 - DAC2 Left Volume */
+ { 0x0613, 0x02C0 }, /* R1555 - DAC2 Right Volume */
+ { 0x0614, 0x0000 }, /* R1556 - DAC Softmute */
+ { 0x0620, 0x0002 }, /* R1568 - Oversampling */
+ { 0x0621, 0x0000 }, /* R1569 - Sidetone */
+ { 0x0700, 0x8100 }, /* R1792 - GPIO 1 */
+ { 0x0701, 0xA101 }, /* R1793 - GPIO 2 */
+ { 0x0702, 0xA101 }, /* R1794 - GPIO 3 */
+ { 0x0703, 0xA101 }, /* R1795 - GPIO 4 */
+ { 0x0704, 0xA101 }, /* R1796 - GPIO 5 */
+ { 0x0705, 0xA101 }, /* R1797 - GPIO 6 */
+ { 0x0706, 0xA101 }, /* R1798 - GPIO 7 */
+ { 0x0707, 0xA101 }, /* R1799 - GPIO 8 */
+ { 0x0708, 0xA101 }, /* R1800 - GPIO 9 */
+ { 0x0709, 0xA101 }, /* R1801 - GPIO 10 */
+ { 0x070A, 0xA101 }, /* R1802 - GPIO 11 */
+ { 0x0720, 0x0000 }, /* R1824 - Pull Control (1) */
+ { 0x0721, 0x0156 }, /* R1825 - Pull Control (2) */
+ { 0x0730, 0x0000 }, /* R1840 - Interrupt Status 1 */
+ { 0x0731, 0x0000 }, /* R1841 - Interrupt Status 2 */
+ { 0x0732, 0x0000 }, /* R1842 - Interrupt Raw Status 2 */
+ { 0x0738, 0x07FF }, /* R1848 - Interrupt Status 1 Mask */
+ { 0x0739, 0xFFFF }, /* R1849 - Interrupt Status 2 Mask */
+ { 0x0740, 0x0000 }, /* R1856 - Interrupt Control */
+ { 0x0748, 0x003F }, /* R1864 - IRQ Debounce */
+};
+
+static struct reg_default wm8958_defaults[] = {
+ { 0x0000, 0x8958 }, /* R0 - Software Reset */
+ { 0x0001, 0x0000 }, /* R1 - Power Management (1) */
+ { 0x0002, 0x6000 }, /* R2 - Power Management (2) */
+ { 0x0003, 0x0000 }, /* R3 - Power Management (3) */
+ { 0x0004, 0x0000 }, /* R4 - Power Management (4) */
+ { 0x0005, 0x0000 }, /* R5 - Power Management (5) */
+ { 0x0006, 0x0000 }, /* R6 - Power Management (6) */
+ { 0x0015, 0x0000 }, /* R21 - Input Mixer (1) */
+ { 0x0018, 0x008B }, /* R24 - Left Line Input 1&2 Volume */
+ { 0x0019, 0x008B }, /* R25 - Left Line Input 3&4 Volume */
+ { 0x001A, 0x008B }, /* R26 - Right Line Input 1&2 Volume */
+ { 0x001B, 0x008B }, /* R27 - Right Line Input 3&4 Volume */
+ { 0x001C, 0x006D }, /* R28 - Left Output Volume */
+ { 0x001D, 0x006D }, /* R29 - Right Output Volume */
+ { 0x001E, 0x0066 }, /* R30 - Line Outputs Volume */
+ { 0x001F, 0x0020 }, /* R31 - HPOUT2 Volume */
+ { 0x0020, 0x0079 }, /* R32 - Left OPGA Volume */
+ { 0x0021, 0x0079 }, /* R33 - Right OPGA Volume */
+ { 0x0022, 0x0003 }, /* R34 - SPKMIXL Attenuation */
+ { 0x0023, 0x0003 }, /* R35 - SPKMIXR Attenuation */
+ { 0x0024, 0x0011 }, /* R36 - SPKOUT Mixers */
+ { 0x0025, 0x0140 }, /* R37 - ClassD */
+ { 0x0026, 0x0079 }, /* R38 - Speaker Volume Left */
+ { 0x0027, 0x0079 }, /* R39 - Speaker Volume Right */
+ { 0x0028, 0x0000 }, /* R40 - Input Mixer (2) */
+ { 0x0029, 0x0000 }, /* R41 - Input Mixer (3) */
+ { 0x002A, 0x0000 }, /* R42 - Input Mixer (4) */
+ { 0x002B, 0x0000 }, /* R43 - Input Mixer (5) */
+ { 0x002C, 0x0000 }, /* R44 - Input Mixer (6) */
+ { 0x002D, 0x0000 }, /* R45 - Output Mixer (1) */
+ { 0x002E, 0x0000 }, /* R46 - Output Mixer (2) */
+ { 0x002F, 0x0000 }, /* R47 - Output Mixer (3) */
+ { 0x0030, 0x0000 }, /* R48 - Output Mixer (4) */
+ { 0x0031, 0x0000 }, /* R49 - Output Mixer (5) */
+ { 0x0032, 0x0000 }, /* R50 - Output Mixer (6) */
+ { 0x0033, 0x0000 }, /* R51 - HPOUT2 Mixer */
+ { 0x0034, 0x0000 }, /* R52 - Line Mixer (1) */
+ { 0x0035, 0x0000 }, /* R53 - Line Mixer (2) */
+ { 0x0036, 0x0000 }, /* R54 - Speaker Mixer */
+ { 0x0037, 0x0000 }, /* R55 - Additional Control */
+ { 0x0038, 0x0000 }, /* R56 - AntiPOP (1) */
+ { 0x0039, 0x0180 }, /* R57 - AntiPOP (2) */
+ { 0x003B, 0x000D }, /* R59 - LDO 1 */
+ { 0x003C, 0x0005 }, /* R60 - LDO 2 */
+ { 0x003D, 0x0039 }, /* R61 - MICBIAS1 */
+ { 0x003E, 0x0039 }, /* R62 - MICBIAS2 */
+ { 0x004C, 0x1F25 }, /* R76 - Charge Pump (1) */
+ { 0x004D, 0xAB19 }, /* R77 - Charge Pump (2) */
+ { 0x0051, 0x0004 }, /* R81 - Class W (1) */
+ { 0x0055, 0x054A }, /* R85 - DC Servo (2) */
+ { 0x0057, 0x0000 }, /* R87 - DC Servo (4) */
+ { 0x0060, 0x0000 }, /* R96 - Analogue HP (1) */
+ { 0x00C5, 0x0000 }, /* R197 - Class D Test (5) */
+ { 0x00D0, 0x5600 }, /* R208 - Mic Detect 1 */
+ { 0x00D1, 0x007F }, /* R209 - Mic Detect 2 */
+ { 0x0101, 0x8004 }, /* R257 - Control Interface */
+ { 0x0110, 0x0000 }, /* R272 - Write Sequencer Ctrl (1) */
+ { 0x0111, 0x0000 }, /* R273 - Write Sequencer Ctrl (2) */
+ { 0x0200, 0x0000 }, /* R512 - AIF1 Clocking (1) */
+ { 0x0201, 0x0000 }, /* R513 - AIF1 Clocking (2) */
+ { 0x0204, 0x0000 }, /* R516 - AIF2 Clocking (1) */
+ { 0x0205, 0x0000 }, /* R517 - AIF2 Clocking (2) */
+ { 0x0208, 0x0000 }, /* R520 - Clocking (1) */
+ { 0x0209, 0x0000 }, /* R521 - Clocking (2) */
+ { 0x0210, 0x0083 }, /* R528 - AIF1 Rate */
+ { 0x0211, 0x0083 }, /* R529 - AIF2 Rate */
+ { 0x0220, 0x0000 }, /* R544 - FLL1 Control (1) */
+ { 0x0221, 0x0000 }, /* R545 - FLL1 Control (2) */
+ { 0x0222, 0x0000 }, /* R546 - FLL1 Control (3) */
+ { 0x0223, 0x0000 }, /* R547 - FLL1 Control (4) */
+ { 0x0224, 0x0C80 }, /* R548 - FLL1 Control (5) */
+ { 0x0226, 0x0000 }, /* R550 - FLL1 EFS 1 */
+ { 0x0227, 0x0006 }, /* R551 - FLL1 EFS 2 */
+ { 0x0240, 0x0000 }, /* R576 - FLL2Control (1) */
+ { 0x0241, 0x0000 }, /* R577 - FLL2Control (2) */
+ { 0x0242, 0x0000 }, /* R578 - FLL2Control (3) */
+ { 0x0243, 0x0000 }, /* R579 - FLL2 Control (4) */
+ { 0x0244, 0x0C80 }, /* R580 - FLL2Control (5) */
+ { 0x0246, 0x0000 }, /* R582 - FLL2 EFS 1 */
+ { 0x0247, 0x0006 }, /* R583 - FLL2 EFS 2 */
+ { 0x0300, 0x4050 }, /* R768 - AIF1 Control (1) */
+ { 0x0301, 0x4000 }, /* R769 - AIF1 Control (2) */
+ { 0x0302, 0x0000 }, /* R770 - AIF1 Master/Slave */
+ { 0x0303, 0x0040 }, /* R771 - AIF1 BCLK */
+ { 0x0304, 0x0040 }, /* R772 - AIF1ADC LRCLK */
+ { 0x0305, 0x0040 }, /* R773 - AIF1DAC LRCLK */
+ { 0x0306, 0x0004 }, /* R774 - AIF1DAC Data */
+ { 0x0307, 0x0100 }, /* R775 - AIF1ADC Data */
+ { 0x0310, 0x4053 }, /* R784 - AIF2 Control (1) */
+ { 0x0311, 0x4000 }, /* R785 - AIF2 Control (2) */
+ { 0x0312, 0x0000 }, /* R786 - AIF2 Master/Slave */
+ { 0x0313, 0x0040 }, /* R787 - AIF2 BCLK */
+ { 0x0314, 0x0040 }, /* R788 - AIF2ADC LRCLK */
+ { 0x0315, 0x0040 }, /* R789 - AIF2DAC LRCLK */
+ { 0x0316, 0x0000 }, /* R790 - AIF2DAC Data */
+ { 0x0317, 0x0000 }, /* R791 - AIF2ADC Data */
+ { 0x0320, 0x0040 }, /* R800 - AIF3 Control (1) */
+ { 0x0321, 0x0000 }, /* R801 - AIF3 Control (2) */
+ { 0x0322, 0x0000 }, /* R802 - AIF3DAC Data */
+ { 0x0323, 0x0000 }, /* R803 - AIF3ADC Data */
+ { 0x0400, 0x00C0 }, /* R1024 - AIF1 ADC1 Left Volume */
+ { 0x0401, 0x00C0 }, /* R1025 - AIF1 ADC1 Right Volume */
+ { 0x0402, 0x00C0 }, /* R1026 - AIF1 DAC1 Left Volume */
+ { 0x0403, 0x00C0 }, /* R1027 - AIF1 DAC1 Right Volume */
+ { 0x0404, 0x00C0 }, /* R1028 - AIF1 ADC2 Left Volume */
+ { 0x0405, 0x00C0 }, /* R1029 - AIF1 ADC2 Right Volume */
+ { 0x0406, 0x00C0 }, /* R1030 - AIF1 DAC2 Left Volume */
+ { 0x0407, 0x00C0 }, /* R1031 - AIF1 DAC2 Right Volume */
+ { 0x0410, 0x0000 }, /* R1040 - AIF1 ADC1 Filters */
+ { 0x0411, 0x0000 }, /* R1041 - AIF1 ADC2 Filters */
+ { 0x0420, 0x0200 }, /* R1056 - AIF1 DAC1 Filters (1) */
+ { 0x0421, 0x0010 }, /* R1057 - AIF1 DAC1 Filters (2) */
+ { 0x0422, 0x0200 }, /* R1058 - AIF1 DAC2 Filters (1) */
+ { 0x0423, 0x0010 }, /* R1059 - AIF1 DAC2 Filters (2) */
+ { 0x0430, 0x0068 }, /* R1072 - AIF1 DAC1 Noise Gate */
+ { 0x0431, 0x0068 }, /* R1073 - AIF1 DAC2 Noise Gate */
+ { 0x0440, 0x0098 }, /* R1088 - AIF1 DRC1 (1) */
+ { 0x0441, 0x0845 }, /* R1089 - AIF1 DRC1 (2) */
+ { 0x0442, 0x0000 }, /* R1090 - AIF1 DRC1 (3) */
+ { 0x0443, 0x0000 }, /* R1091 - AIF1 DRC1 (4) */
+ { 0x0444, 0x0000 }, /* R1092 - AIF1 DRC1 (5) */
+ { 0x0450, 0x0098 }, /* R1104 - AIF1 DRC2 (1) */
+ { 0x0451, 0x0845 }, /* R1105 - AIF1 DRC2 (2) */
+ { 0x0452, 0x0000 }, /* R1106 - AIF1 DRC2 (3) */
+ { 0x0453, 0x0000 }, /* R1107 - AIF1 DRC2 (4) */
+ { 0x0454, 0x0000 }, /* R1108 - AIF1 DRC2 (5) */
+ { 0x0480, 0x6318 }, /* R1152 - AIF1 DAC1 EQ Gains (1) */
+ { 0x0481, 0x6300 }, /* R1153 - AIF1 DAC1 EQ Gains (2) */
+ { 0x0482, 0x0FCA }, /* R1154 - AIF1 DAC1 EQ Band 1 A */
+ { 0x0483, 0x0400 }, /* R1155 - AIF1 DAC1 EQ Band 1 B */
+ { 0x0484, 0x00D8 }, /* R1156 - AIF1 DAC1 EQ Band 1 PG */
+ { 0x0485, 0x1EB5 }, /* R1157 - AIF1 DAC1 EQ Band 2 A */
+ { 0x0486, 0xF145 }, /* R1158 - AIF1 DAC1 EQ Band 2 B */
+ { 0x0487, 0x0B75 }, /* R1159 - AIF1 DAC1 EQ Band 2 C */
+ { 0x0488, 0x01C5 }, /* R1160 - AIF1 DAC1 EQ Band 2 PG */
+ { 0x0489, 0x1C58 }, /* R1161 - AIF1 DAC1 EQ Band 3 A */
+ { 0x048A, 0xF373 }, /* R1162 - AIF1 DAC1 EQ Band 3 B */
+ { 0x048B, 0x0A54 }, /* R1163 - AIF1 DAC1 EQ Band 3 C */
+ { 0x048C, 0x0558 }, /* R1164 - AIF1 DAC1 EQ Band 3 PG */
+ { 0x048D, 0x168E }, /* R1165 - AIF1 DAC1 EQ Band 4 A */
+ { 0x048E, 0xF829 }, /* R1166 - AIF1 DAC1 EQ Band 4 B */
+ { 0x048F, 0x07AD }, /* R1167 - AIF1 DAC1 EQ Band 4 C */
+ { 0x0490, 0x1103 }, /* R1168 - AIF1 DAC1 EQ Band 4 PG */
+ { 0x0491, 0x0564 }, /* R1169 - AIF1 DAC1 EQ Band 5 A */
+ { 0x0492, 0x0559 }, /* R1170 - AIF1 DAC1 EQ Band 5 B */
+ { 0x0493, 0x4000 }, /* R1171 - AIF1 DAC1 EQ Band 5 PG */
+ { 0x0494, 0x0000 }, /* R1172 - AIF1 DAC1 EQ Band 1 C */
+ { 0x04A0, 0x6318 }, /* R1184 - AIF1 DAC2 EQ Gains (1) */
+ { 0x04A1, 0x6300 }, /* R1185 - AIF1 DAC2 EQ Gains (2) */
+ { 0x04A2, 0x0FCA }, /* R1186 - AIF1 DAC2 EQ Band 1 A */
+ { 0x04A3, 0x0400 }, /* R1187 - AIF1 DAC2 EQ Band 1 B */
+ { 0x04A4, 0x00D8 }, /* R1188 - AIF1 DAC2 EQ Band 1 PG */
+ { 0x04A5, 0x1EB5 }, /* R1189 - AIF1 DAC2 EQ Band 2 A */
+ { 0x04A6, 0xF145 }, /* R1190 - AIF1 DAC2 EQ Band 2 B */
+ { 0x04A7, 0x0B75 }, /* R1191 - AIF1 DAC2 EQ Band 2 C */
+ { 0x04A8, 0x01C5 }, /* R1192 - AIF1 DAC2 EQ Band 2 PG */
+ { 0x04A9, 0x1C58 }, /* R1193 - AIF1 DAC2 EQ Band 3 A */
+ { 0x04AA, 0xF373 }, /* R1194 - AIF1 DAC2 EQ Band 3 B */
+ { 0x04AB, 0x0A54 }, /* R1195 - AIF1 DAC2 EQ Band 3 C */
+ { 0x04AC, 0x0558 }, /* R1196 - AIF1 DAC2 EQ Band 3 PG */
+ { 0x04AD, 0x168E }, /* R1197 - AIF1 DAC2 EQ Band 4 A */
+ { 0x04AE, 0xF829 }, /* R1198 - AIF1 DAC2 EQ Band 4 B */
+ { 0x04AF, 0x07AD }, /* R1199 - AIF1 DAC2 EQ Band 4 C */
+ { 0x04B0, 0x1103 }, /* R1200 - AIF1 DAC2 EQ Band 4 PG */
+ { 0x04B1, 0x0564 }, /* R1201 - AIF1 DAC2 EQ Band 5 A */
+ { 0x04B2, 0x0559 }, /* R1202 - AIF1 DAC2 EQ Band 5 B */
+ { 0x04B3, 0x4000 }, /* R1203 - AIF1 DAC2 EQ Band 5 PG */
+ { 0x04B4, 0x0000 }, /* R1204 - AIF1 DAC2EQ Band 1 C */
+ { 0x0500, 0x00C0 }, /* R1280 - AIF2 ADC Left Volume */
+ { 0x0501, 0x00C0 }, /* R1281 - AIF2 ADC Right Volume */
+ { 0x0502, 0x00C0 }, /* R1282 - AIF2 DAC Left Volume */
+ { 0x0503, 0x00C0 }, /* R1283 - AIF2 DAC Right Volume */
+ { 0x0510, 0x0000 }, /* R1296 - AIF2 ADC Filters */
+ { 0x0520, 0x0200 }, /* R1312 - AIF2 DAC Filters (1) */
+ { 0x0521, 0x0010 }, /* R1313 - AIF2 DAC Filters (2) */
+ { 0x0530, 0x0068 }, /* R1328 - AIF2 DAC Noise Gate */
+ { 0x0540, 0x0098 }, /* R1344 - AIF2 DRC (1) */
+ { 0x0541, 0x0845 }, /* R1345 - AIF2 DRC (2) */
+ { 0x0542, 0x0000 }, /* R1346 - AIF2 DRC (3) */
+ { 0x0543, 0x0000 }, /* R1347 - AIF2 DRC (4) */
+ { 0x0544, 0x0000 }, /* R1348 - AIF2 DRC (5) */
+ { 0x0580, 0x6318 }, /* R1408 - AIF2 EQ Gains (1) */
+ { 0x0581, 0x6300 }, /* R1409 - AIF2 EQ Gains (2) */
+ { 0x0582, 0x0FCA }, /* R1410 - AIF2 EQ Band 1 A */
+ { 0x0583, 0x0400 }, /* R1411 - AIF2 EQ Band 1 B */
+ { 0x0584, 0x00D8 }, /* R1412 - AIF2 EQ Band 1 PG */
+ { 0x0585, 0x1EB5 }, /* R1413 - AIF2 EQ Band 2 A */
+ { 0x0586, 0xF145 }, /* R1414 - AIF2 EQ Band 2 B */
+ { 0x0587, 0x0B75 }, /* R1415 - AIF2 EQ Band 2 C */
+ { 0x0588, 0x01C5 }, /* R1416 - AIF2 EQ Band 2 PG */
+ { 0x0589, 0x1C58 }, /* R1417 - AIF2 EQ Band 3 A */
+ { 0x058A, 0xF373 }, /* R1418 - AIF2 EQ Band 3 B */
+ { 0x058B, 0x0A54 }, /* R1419 - AIF2 EQ Band 3 C */
+ { 0x058C, 0x0558 }, /* R1420 - AIF2 EQ Band 3 PG */
+ { 0x058D, 0x168E }, /* R1421 - AIF2 EQ Band 4 A */
+ { 0x058E, 0xF829 }, /* R1422 - AIF2 EQ Band 4 B */
+ { 0x058F, 0x07AD }, /* R1423 - AIF2 EQ Band 4 C */
+ { 0x0590, 0x1103 }, /* R1424 - AIF2 EQ Band 4 PG */
+ { 0x0591, 0x0564 }, /* R1425 - AIF2 EQ Band 5 A */
+ { 0x0592, 0x0559 }, /* R1426 - AIF2 EQ Band 5 B */
+ { 0x0593, 0x4000 }, /* R1427 - AIF2 EQ Band 5 PG */
+ { 0x0594, 0x0000 }, /* R1428 - AIF2 EQ Band 1 C */
+ { 0x0600, 0x0000 }, /* R1536 - DAC1 Mixer Volumes */
+ { 0x0601, 0x0000 }, /* R1537 - DAC1 Left Mixer Routing */
+ { 0x0602, 0x0000 }, /* R1538 - DAC1 Right Mixer Routing */
+ { 0x0603, 0x0000 }, /* R1539 - DAC2 Mixer Volumes */
+ { 0x0604, 0x0000 }, /* R1540 - DAC2 Left Mixer Routing */
+ { 0x0605, 0x0000 }, /* R1541 - DAC2 Right Mixer Routing */
+ { 0x0606, 0x0000 }, /* R1542 - AIF1 ADC1 Left Mixer Routing */
+ { 0x0607, 0x0000 }, /* R1543 - AIF1 ADC1 Right Mixer Routing */
+ { 0x0608, 0x0000 }, /* R1544 - AIF1 ADC2 Left Mixer Routing */
+ { 0x0609, 0x0000 }, /* R1545 - AIF1 ADC2 Right mixer Routing */
+ { 0x0610, 0x02C0 }, /* R1552 - DAC1 Left Volume */
+ { 0x0611, 0x02C0 }, /* R1553 - DAC1 Right Volume */
+ { 0x0612, 0x02C0 }, /* R1554 - DAC2 Left Volume */
+ { 0x0613, 0x02C0 }, /* R1555 - DAC2 Right Volume */
+ { 0x0614, 0x0000 }, /* R1556 - DAC Softmute */
+ { 0x0620, 0x0002 }, /* R1568 - Oversampling */
+ { 0x0621, 0x0000 }, /* R1569 - Sidetone */
+ { 0x0700, 0x8100 }, /* R1792 - GPIO 1 */
+ { 0x0701, 0xA101 }, /* R1793 - Pull Control (MCLK2) */
+ { 0x0702, 0xA101 }, /* R1794 - Pull Control (BCLK2) */
+ { 0x0703, 0xA101 }, /* R1795 - Pull Control (DACLRCLK2) */
+ { 0x0704, 0xA101 }, /* R1796 - Pull Control (DACDAT2) */
+ { 0x0705, 0xA101 }, /* R1797 - GPIO 6 */
+ { 0x0707, 0xA101 }, /* R1799 - GPIO 8 */
+ { 0x0708, 0xA101 }, /* R1800 - GPIO 9 */
+ { 0x0709, 0xA101 }, /* R1801 - GPIO 10 */
+ { 0x070A, 0xA101 }, /* R1802 - GPIO 11 */
+ { 0x0720, 0x0000 }, /* R1824 - Pull Control (1) */
+ { 0x0721, 0x0156 }, /* R1825 - Pull Control (2) */
+ { 0x0738, 0x07FF }, /* R1848 - Interrupt Status 1 Mask */
+ { 0x0739, 0xFFEF }, /* R1849 - Interrupt Status 2 Mask */
+ { 0x0740, 0x0000 }, /* R1856 - Interrupt Control */
+ { 0x0748, 0x003F }, /* R1864 - IRQ Debounce */
+ { 0x0900, 0x1C00 }, /* R2304 - DSP2_Program */
+ { 0x0901, 0x0000 }, /* R2305 - DSP2_Config */
+ { 0x0A0D, 0x0000 }, /* R2573 - DSP2_ExecControl */
+ { 0x2400, 0x003F }, /* R9216 - MBC Band 1 K (1) */
+ { 0x2401, 0x8BD8 }, /* R9217 - MBC Band 1 K (2) */
+ { 0x2402, 0x0032 }, /* R9218 - MBC Band 1 N1 (1) */
+ { 0x2403, 0xF52D }, /* R9219 - MBC Band 1 N1 (2) */
+ { 0x2404, 0x0065 }, /* R9220 - MBC Band 1 N2 (1) */
+ { 0x2405, 0xAC8C }, /* R9221 - MBC Band 1 N2 (2) */
+ { 0x2406, 0x006B }, /* R9222 - MBC Band 1 N3 (1) */
+ { 0x2407, 0xE087 }, /* R9223 - MBC Band 1 N3 (2) */
+ { 0x2408, 0x0072 }, /* R9224 - MBC Band 1 N4 (1) */
+ { 0x2409, 0x1483 }, /* R9225 - MBC Band 1 N4 (2) */
+ { 0x240A, 0x0072 }, /* R9226 - MBC Band 1 N5 (1) */
+ { 0x240B, 0x1483 }, /* R9227 - MBC Band 1 N5 (2) */
+ { 0x240C, 0x0043 }, /* R9228 - MBC Band 1 X1 (1) */
+ { 0x240D, 0x3525 }, /* R9229 - MBC Band 1 X1 (2) */
+ { 0x240E, 0x0006 }, /* R9230 - MBC Band 1 X2 (1) */
+ { 0x240F, 0x6A4A }, /* R9231 - MBC Band 1 X2 (2) */
+ { 0x2410, 0x0043 }, /* R9232 - MBC Band 1 X3 (1) */
+ { 0x2411, 0x6079 }, /* R9233 - MBC Band 1 X3 (2) */
+ { 0x2412, 0x000C }, /* R9234 - MBC Band 1 Attack (1) */
+ { 0x2413, 0xCCCD }, /* R9235 - MBC Band 1 Attack (2) */
+ { 0x2414, 0x0000 }, /* R9236 - MBC Band 1 Decay (1) */
+ { 0x2415, 0x0800 }, /* R9237 - MBC Band 1 Decay (2) */
+ { 0x2416, 0x003F }, /* R9238 - MBC Band 2 K (1) */
+ { 0x2417, 0x8BD8 }, /* R9239 - MBC Band 2 K (2) */
+ { 0x2418, 0x0032 }, /* R9240 - MBC Band 2 N1 (1) */
+ { 0x2419, 0xF52D }, /* R9241 - MBC Band 2 N1 (2) */
+ { 0x241A, 0x0065 }, /* R9242 - MBC Band 2 N2 (1) */
+ { 0x241B, 0xAC8C }, /* R9243 - MBC Band 2 N2 (2) */
+ { 0x241C, 0x006B }, /* R9244 - MBC Band 2 N3 (1) */
+ { 0x241D, 0xE087 }, /* R9245 - MBC Band 2 N3 (2) */
+ { 0x241E, 0x0072 }, /* R9246 - MBC Band 2 N4 (1) */
+ { 0x241F, 0x1483 }, /* R9247 - MBC Band 2 N4 (2) */
+ { 0x2420, 0x0072 }, /* R9248 - MBC Band 2 N5 (1) */
+ { 0x2421, 0x1483 }, /* R9249 - MBC Band 2 N5 (2) */
+ { 0x2422, 0x0043 }, /* R9250 - MBC Band 2 X1 (1) */
+ { 0x2423, 0x3525 }, /* R9251 - MBC Band 2 X1 (2) */
+ { 0x2424, 0x0006 }, /* R9252 - MBC Band 2 X2 (1) */
+ { 0x2425, 0x6A4A }, /* R9253 - MBC Band 2 X2 (2) */
+ { 0x2426, 0x0043 }, /* R9254 - MBC Band 2 X3 (1) */
+ { 0x2427, 0x6079 }, /* R9255 - MBC Band 2 X3 (2) */
+ { 0x2428, 0x000C }, /* R9256 - MBC Band 2 Attack (1) */
+ { 0x2429, 0xCCCD }, /* R9257 - MBC Band 2 Attack (2) */
+ { 0x242A, 0x0000 }, /* R9258 - MBC Band 2 Decay (1) */
+ { 0x242B, 0x0800 }, /* R9259 - MBC Band 2 Decay (2) */
+ { 0x242C, 0x005A }, /* R9260 - MBC_B2_PG2 (1) */
+ { 0x242D, 0x7EFA }, /* R9261 - MBC_B2_PG2 (2) */
+ { 0x242E, 0x005A }, /* R9262 - MBC_B1_PG2 (1) */
+ { 0x242F, 0x7EFA }, /* R9263 - MBC_B1_PG2 (2) */
+ { 0x2600, 0x00A7 }, /* R9728 - MBC Crossover (1) */
+ { 0x2601, 0x0D1C }, /* R9729 - MBC Crossover (2) */
+ { 0x2602, 0x0083 }, /* R9730 - MBC HPF (1) */
+ { 0x2603, 0x98AD }, /* R9731 - MBC HPF (2) */
+ { 0x2606, 0x0008 }, /* R9734 - MBC LPF (1) */
+ { 0x2607, 0xE7A2 }, /* R9735 - MBC LPF (2) */
+ { 0x260A, 0x0055 }, /* R9738 - MBC RMS Limit (1) */
+ { 0x260B, 0x8C4B }, /* R9739 - MBC RMS Limit (2) */
+};
+
+static bool wm1811_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WM8994_SOFTWARE_RESET:
+ case WM8994_POWER_MANAGEMENT_1:
+ case WM8994_POWER_MANAGEMENT_2:
+ case WM8994_POWER_MANAGEMENT_3:
+ case WM8994_POWER_MANAGEMENT_4:
+ case WM8994_POWER_MANAGEMENT_5:
+ case WM8994_POWER_MANAGEMENT_6:
+ case WM8994_INPUT_MIXER_1:
+ case WM8994_LEFT_LINE_INPUT_1_2_VOLUME:
+ case WM8994_LEFT_LINE_INPUT_3_4_VOLUME:
+ case WM8994_RIGHT_LINE_INPUT_1_2_VOLUME:
+ case WM8994_RIGHT_LINE_INPUT_3_4_VOLUME:
+ case WM8994_LEFT_OUTPUT_VOLUME:
+ case WM8994_RIGHT_OUTPUT_VOLUME:
+ case WM8994_LINE_OUTPUTS_VOLUME:
+ case WM8994_HPOUT2_VOLUME:
+ case WM8994_LEFT_OPGA_VOLUME:
+ case WM8994_RIGHT_OPGA_VOLUME:
+ case WM8994_SPKMIXL_ATTENUATION:
+ case WM8994_SPKMIXR_ATTENUATION:
+ case WM8994_SPKOUT_MIXERS:
+ case WM8994_CLASSD:
+ case WM8994_SPEAKER_VOLUME_LEFT:
+ case WM8994_SPEAKER_VOLUME_RIGHT:
+ case WM8994_INPUT_MIXER_2:
+ case WM8994_INPUT_MIXER_3:
+ case WM8994_INPUT_MIXER_4:
+ case WM8994_INPUT_MIXER_5:
+ case WM8994_INPUT_MIXER_6:
+ case WM8994_OUTPUT_MIXER_1:
+ case WM8994_OUTPUT_MIXER_2:
+ case WM8994_OUTPUT_MIXER_3:
+ case WM8994_OUTPUT_MIXER_4:
+ case WM8994_OUTPUT_MIXER_5:
+ case WM8994_OUTPUT_MIXER_6:
+ case WM8994_HPOUT2_MIXER:
+ case WM8994_LINE_MIXER_1:
+ case WM8994_LINE_MIXER_2:
+ case WM8994_SPEAKER_MIXER:
+ case WM8994_ADDITIONAL_CONTROL:
+ case WM8994_ANTIPOP_1:
+ case WM8994_ANTIPOP_2:
+ case WM8994_LDO_1:
+ case WM8994_LDO_2:
+ case WM8958_MICBIAS1:
+ case WM8958_MICBIAS2:
+ case WM8994_CHARGE_PUMP_1:
+ case WM8958_CHARGE_PUMP_2:
+ case WM8994_CLASS_W_1:
+ case WM8994_DC_SERVO_1:
+ case WM8994_DC_SERVO_2:
+ case WM8994_DC_SERVO_READBACK:
+ case WM8994_DC_SERVO_4:
+ case WM8994_ANALOGUE_HP_1:
+ case WM8958_MIC_DETECT_1:
+ case WM8958_MIC_DETECT_2:
+ case WM8958_MIC_DETECT_3:
+ case WM8994_CHIP_REVISION:
+ case WM8994_CONTROL_INTERFACE:
+ case WM8994_AIF1_CLOCKING_1:
+ case WM8994_AIF1_CLOCKING_2:
+ case WM8994_AIF2_CLOCKING_1:
+ case WM8994_AIF2_CLOCKING_2:
+ case WM8994_CLOCKING_1:
+ case WM8994_CLOCKING_2:
+ case WM8994_AIF1_RATE:
+ case WM8994_AIF2_RATE:
+ case WM8994_RATE_STATUS:
+ case WM8994_FLL1_CONTROL_1:
+ case WM8994_FLL1_CONTROL_2:
+ case WM8994_FLL1_CONTROL_3:
+ case WM8994_FLL1_CONTROL_4:
+ case WM8994_FLL1_CONTROL_5:
+ case WM8958_FLL1_EFS_1:
+ case WM8958_FLL1_EFS_2:
+ case WM8994_FLL2_CONTROL_1:
+ case WM8994_FLL2_CONTROL_2:
+ case WM8994_FLL2_CONTROL_3:
+ case WM8994_FLL2_CONTROL_4:
+ case WM8994_FLL2_CONTROL_5:
+ case WM8958_FLL2_EFS_1:
+ case WM8958_FLL2_EFS_2:
+ case WM8994_AIF1_CONTROL_1:
+ case WM8994_AIF1_CONTROL_2:
+ case WM8994_AIF1_MASTER_SLAVE:
+ case WM8994_AIF1_BCLK:
+ case WM8994_AIF1ADC_LRCLK:
+ case WM8994_AIF1DAC_LRCLK:
+ case WM8994_AIF1DAC_DATA:
+ case WM8994_AIF1ADC_DATA:
+ case WM8994_AIF2_CONTROL_1:
+ case WM8994_AIF2_CONTROL_2:
+ case WM8994_AIF2_MASTER_SLAVE:
+ case WM8994_AIF2_BCLK:
+ case WM8994_AIF2ADC_LRCLK:
+ case WM8994_AIF2DAC_LRCLK:
+ case WM8994_AIF2DAC_DATA:
+ case WM8994_AIF2ADC_DATA:
+ case WM1811_AIF2TX_CONTROL:
+ case WM8958_AIF3_CONTROL_1:
+ case WM8958_AIF3_CONTROL_2:
+ case WM8958_AIF3DAC_DATA:
+ case WM8958_AIF3ADC_DATA:
+ case WM8994_AIF1_ADC1_LEFT_VOLUME:
+ case WM8994_AIF1_ADC1_RIGHT_VOLUME:
+ case WM8994_AIF1_DAC1_LEFT_VOLUME:
+ case WM8994_AIF1_DAC1_RIGHT_VOLUME:
+ case WM8994_AIF1_ADC1_FILTERS:
+ case WM8994_AIF1_DAC1_FILTERS_1:
+ case WM8994_AIF1_DAC1_FILTERS_2:
+ case WM8958_AIF1_DAC1_NOISE_GATE:
+ case WM8994_AIF1_DRC1_1:
+ case WM8994_AIF1_DRC1_2:
+ case WM8994_AIF1_DRC1_3:
+ case WM8994_AIF1_DRC1_4:
+ case WM8994_AIF1_DRC1_5:
+ case WM8994_AIF1_DAC1_EQ_GAINS_1:
+ case WM8994_AIF1_DAC1_EQ_GAINS_2:
+ case WM8994_AIF1_DAC1_EQ_BAND_1_A:
+ case WM8994_AIF1_DAC1_EQ_BAND_1_B:
+ case WM8994_AIF1_DAC1_EQ_BAND_1_PG:
+ case WM8994_AIF1_DAC1_EQ_BAND_2_A:
+ case WM8994_AIF1_DAC1_EQ_BAND_2_B:
+ case WM8994_AIF1_DAC1_EQ_BAND_2_C:
+ case WM8994_AIF1_DAC1_EQ_BAND_2_PG:
+ case WM8994_AIF1_DAC1_EQ_BAND_3_A:
+ case WM8994_AIF1_DAC1_EQ_BAND_3_B:
+ case WM8994_AIF1_DAC1_EQ_BAND_3_C:
+ case WM8994_AIF1_DAC1_EQ_BAND_3_PG:
+ case WM8994_AIF1_DAC1_EQ_BAND_4_A:
+ case WM8994_AIF1_DAC1_EQ_BAND_4_B:
+ case WM8994_AIF1_DAC1_EQ_BAND_4_C:
+ case WM8994_AIF1_DAC1_EQ_BAND_4_PG:
+ case WM8994_AIF1_DAC1_EQ_BAND_5_A:
+ case WM8994_AIF1_DAC1_EQ_BAND_5_B:
+ case WM8994_AIF1_DAC1_EQ_BAND_5_PG:
+ case WM8994_AIF1_DAC1_EQ_BAND_1_C:
+ case WM8994_AIF2_ADC_LEFT_VOLUME:
+ case WM8994_AIF2_ADC_RIGHT_VOLUME:
+ case WM8994_AIF2_DAC_LEFT_VOLUME:
+ case WM8994_AIF2_DAC_RIGHT_VOLUME:
+ case WM8994_AIF2_ADC_FILTERS:
+ case WM8994_AIF2_DAC_FILTERS_1:
+ case WM8994_AIF2_DAC_FILTERS_2:
+ case WM8958_AIF2_DAC_NOISE_GATE:
+ case WM8994_AIF2_DRC_1:
+ case WM8994_AIF2_DRC_2:
+ case WM8994_AIF2_DRC_3:
+ case WM8994_AIF2_DRC_4:
+ case WM8994_AIF2_DRC_5:
+ case WM8994_AIF2_EQ_GAINS_1:
+ case WM8994_AIF2_EQ_GAINS_2:
+ case WM8994_AIF2_EQ_BAND_1_A:
+ case WM8994_AIF2_EQ_BAND_1_B:
+ case WM8994_AIF2_EQ_BAND_1_PG:
+ case WM8994_AIF2_EQ_BAND_2_A:
+ case WM8994_AIF2_EQ_BAND_2_B:
+ case WM8994_AIF2_EQ_BAND_2_C:
+ case WM8994_AIF2_EQ_BAND_2_PG:
+ case WM8994_AIF2_EQ_BAND_3_A:
+ case WM8994_AIF2_EQ_BAND_3_B:
+ case WM8994_AIF2_EQ_BAND_3_C:
+ case WM8994_AIF2_EQ_BAND_3_PG:
+ case WM8994_AIF2_EQ_BAND_4_A:
+ case WM8994_AIF2_EQ_BAND_4_B:
+ case WM8994_AIF2_EQ_BAND_4_C:
+ case WM8994_AIF2_EQ_BAND_4_PG:
+ case WM8994_AIF2_EQ_BAND_5_A:
+ case WM8994_AIF2_EQ_BAND_5_B:
+ case WM8994_AIF2_EQ_BAND_5_PG:
+ case WM8994_AIF2_EQ_BAND_1_C:
+ case WM8994_DAC1_MIXER_VOLUMES:
+ case WM8994_DAC1_LEFT_MIXER_ROUTING:
+ case WM8994_DAC1_RIGHT_MIXER_ROUTING:
+ case WM8994_DAC2_MIXER_VOLUMES:
+ case WM8994_DAC2_LEFT_MIXER_ROUTING:
+ case WM8994_DAC2_RIGHT_MIXER_ROUTING:
+ case WM8994_AIF1_ADC1_LEFT_MIXER_ROUTING:
+ case WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING:
+ case WM8994_DAC1_LEFT_VOLUME:
+ case WM8994_DAC1_RIGHT_VOLUME:
+ case WM8994_DAC2_LEFT_VOLUME:
+ case WM8994_DAC2_RIGHT_VOLUME:
+ case WM8994_DAC_SOFTMUTE:
+ case WM8994_OVERSAMPLING:
+ case WM8994_SIDETONE:
+ case WM8994_GPIO_1:
+ case WM8994_GPIO_2:
+ case WM8994_GPIO_3:
+ case WM8994_GPIO_4:
+ case WM8994_GPIO_5:
+ case WM8994_GPIO_6:
+ case WM8994_GPIO_8:
+ case WM8994_GPIO_9:
+ case WM8994_GPIO_10:
+ case WM8994_GPIO_11:
+ case WM8994_PULL_CONTROL_1:
+ case WM8994_PULL_CONTROL_2:
+ case WM8994_INTERRUPT_STATUS_1:
+ case WM8994_INTERRUPT_STATUS_2:
+ case WM8994_INTERRUPT_RAW_STATUS_2:
+ case WM8994_INTERRUPT_STATUS_1_MASK:
+ case WM8994_INTERRUPT_STATUS_2_MASK:
+ case WM8994_INTERRUPT_CONTROL:
+ case WM8994_IRQ_DEBOUNCE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool wm8994_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WM8994_DC_SERVO_READBACK:
+ case WM8994_WRITE_SEQUENCER_CTRL_1:
+ case WM8994_WRITE_SEQUENCER_CTRL_2:
+ case WM8994_AIF1_ADC2_LEFT_VOLUME:
+ case WM8994_AIF1_ADC2_RIGHT_VOLUME:
+ case WM8994_AIF1_DAC2_LEFT_VOLUME:
+ case WM8994_AIF1_DAC2_RIGHT_VOLUME:
+ case WM8994_AIF1_ADC2_FILTERS:
+ case WM8994_AIF1_DAC2_FILTERS_1:
+ case WM8994_AIF1_DAC2_FILTERS_2:
+ case WM8958_AIF1_DAC2_NOISE_GATE:
+ case WM8994_AIF1_DRC2_1:
+ case WM8994_AIF1_DRC2_2:
+ case WM8994_AIF1_DRC2_3:
+ case WM8994_AIF1_DRC2_4:
+ case WM8994_AIF1_DRC2_5:
+ case WM8994_AIF1_DAC2_EQ_GAINS_1:
+ case WM8994_AIF1_DAC2_EQ_GAINS_2:
+ case WM8994_AIF1_DAC2_EQ_BAND_1_A:
+ case WM8994_AIF1_DAC2_EQ_BAND_1_B:
+ case WM8994_AIF1_DAC2_EQ_BAND_1_PG:
+ case WM8994_AIF1_DAC2_EQ_BAND_2_A:
+ case WM8994_AIF1_DAC2_EQ_BAND_2_B:
+ case WM8994_AIF1_DAC2_EQ_BAND_2_C:
+ case WM8994_AIF1_DAC2_EQ_BAND_2_PG:
+ case WM8994_AIF1_DAC2_EQ_BAND_3_A:
+ case WM8994_AIF1_DAC2_EQ_BAND_3_B:
+ case WM8994_AIF1_DAC2_EQ_BAND_3_C:
+ case WM8994_AIF1_DAC2_EQ_BAND_3_PG:
+ case WM8994_AIF1_DAC2_EQ_BAND_4_A:
+ case WM8994_AIF1_DAC2_EQ_BAND_4_B:
+ case WM8994_AIF1_DAC2_EQ_BAND_4_C:
+ case WM8994_AIF1_DAC2_EQ_BAND_4_PG:
+ case WM8994_AIF1_DAC2_EQ_BAND_5_A:
+ case WM8994_AIF1_DAC2_EQ_BAND_5_B:
+ case WM8994_AIF1_DAC2_EQ_BAND_5_PG:
+ case WM8994_AIF1_DAC2_EQ_BAND_1_C:
+ case WM8994_DAC2_MIXER_VOLUMES:
+ case WM8994_DAC2_LEFT_MIXER_ROUTING:
+ case WM8994_DAC2_RIGHT_MIXER_ROUTING:
+ case WM8994_AIF1_ADC2_LEFT_MIXER_ROUTING:
+ case WM8994_AIF1_ADC2_RIGHT_MIXER_ROUTING:
+ case WM8994_DAC2_LEFT_VOLUME:
+ case WM8994_DAC2_RIGHT_VOLUME:
+ return true;
+ default:
+ return wm1811_readable_register(dev, reg);
+ }
+}
+
+static bool wm8958_readable_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WM8958_DSP2_PROGRAM:
+ case WM8958_DSP2_CONFIG:
+ case WM8958_DSP2_MAGICNUM:
+ case WM8958_DSP2_RELEASEYEAR:
+ case WM8958_DSP2_RELEASEMONTHDAY:
+ case WM8958_DSP2_RELEASETIME:
+ case WM8958_DSP2_VERMAJMIN:
+ case WM8958_DSP2_VERBUILD:
+ case WM8958_DSP2_TESTREG:
+ case WM8958_DSP2_XORREG:
+ case WM8958_DSP2_SHIFTMAXX:
+ case WM8958_DSP2_SHIFTMAXY:
+ case WM8958_DSP2_SHIFTMAXZ:
+ case WM8958_DSP2_SHIFTMAXEXTLO:
+ case WM8958_DSP2_AESSELECT:
+ case WM8958_DSP2_EXECCONTROL:
+ case WM8958_DSP2_SAMPLEBREAK:
+ case WM8958_DSP2_COUNTBREAK:
+ case WM8958_DSP2_INTSTATUS:
+ case WM8958_DSP2_EVENTSTATUS:
+ case WM8958_DSP2_INTMASK:
+ case WM8958_DSP2_CONFIGDWIDTH:
+ case WM8958_DSP2_CONFIGINSTR:
+ case WM8958_DSP2_CONFIGDMEM:
+ case WM8958_DSP2_CONFIGDELAYS:
+ case WM8958_DSP2_CONFIGNUMIO:
+ case WM8958_DSP2_CONFIGEXTDEPTH:
+ case WM8958_DSP2_CONFIGMULTIPLIER:
+ case WM8958_DSP2_CONFIGCTRLDWIDTH:
+ case WM8958_DSP2_CONFIGPIPELINE:
+ case WM8958_DSP2_SHIFTMAXEXTHI:
+ case WM8958_DSP2_SWVERSIONREG:
+ case WM8958_DSP2_CONFIGXMEM:
+ case WM8958_DSP2_CONFIGYMEM:
+ case WM8958_DSP2_CONFIGZMEM:
+ case WM8958_FW_BUILD_1:
+ case WM8958_FW_BUILD_0:
+ case WM8958_FW_ID_1:
+ case WM8958_FW_ID_0:
+ case WM8958_FW_MAJOR_1:
+ case WM8958_FW_MAJOR_0:
+ case WM8958_FW_MINOR_1:
+ case WM8958_FW_MINOR_0:
+ case WM8958_FW_PATCH_1:
+ case WM8958_FW_PATCH_0:
+ case WM8958_MBC_BAND_1_K_1:
+ case WM8958_MBC_BAND_1_K_2:
+ case WM8958_MBC_BAND_1_N1_1:
+ case WM8958_MBC_BAND_1_N1_2:
+ case WM8958_MBC_BAND_1_N2_1:
+ case WM8958_MBC_BAND_1_N2_2:
+ case WM8958_MBC_BAND_1_N3_1:
+ case WM8958_MBC_BAND_1_N3_2:
+ case WM8958_MBC_BAND_1_N4_1:
+ case WM8958_MBC_BAND_1_N4_2:
+ case WM8958_MBC_BAND_1_N5_1:
+ case WM8958_MBC_BAND_1_N5_2:
+ case WM8958_MBC_BAND_1_X1_1:
+ case WM8958_MBC_BAND_1_X1_2:
+ case WM8958_MBC_BAND_1_X2_1:
+ case WM8958_MBC_BAND_1_X2_2:
+ case WM8958_MBC_BAND_1_X3_1:
+ case WM8958_MBC_BAND_1_X3_2:
+ case WM8958_MBC_BAND_1_ATTACK_1:
+ case WM8958_MBC_BAND_1_ATTACK_2:
+ case WM8958_MBC_BAND_1_DECAY_1:
+ case WM8958_MBC_BAND_1_DECAY_2:
+ case WM8958_MBC_BAND_2_K_1:
+ case WM8958_MBC_BAND_2_K_2:
+ case WM8958_MBC_BAND_2_N1_1:
+ case WM8958_MBC_BAND_2_N1_2:
+ case WM8958_MBC_BAND_2_N2_1:
+ case WM8958_MBC_BAND_2_N2_2:
+ case WM8958_MBC_BAND_2_N3_1:
+ case WM8958_MBC_BAND_2_N3_2:
+ case WM8958_MBC_BAND_2_N4_1:
+ case WM8958_MBC_BAND_2_N4_2:
+ case WM8958_MBC_BAND_2_N5_1:
+ case WM8958_MBC_BAND_2_N5_2:
+ case WM8958_MBC_BAND_2_X1_1:
+ case WM8958_MBC_BAND_2_X1_2:
+ case WM8958_MBC_BAND_2_X2_1:
+ case WM8958_MBC_BAND_2_X2_2:
+ case WM8958_MBC_BAND_2_X3_1:
+ case WM8958_MBC_BAND_2_X3_2:
+ case WM8958_MBC_BAND_2_ATTACK_1:
+ case WM8958_MBC_BAND_2_ATTACK_2:
+ case WM8958_MBC_BAND_2_DECAY_1:
+ case WM8958_MBC_BAND_2_DECAY_2:
+ case WM8958_MBC_B2_PG2_1:
+ case WM8958_MBC_B2_PG2_2:
+ case WM8958_MBC_B1_PG2_1:
+ case WM8958_MBC_B1_PG2_2:
+ case WM8958_MBC_CROSSOVER_1:
+ case WM8958_MBC_CROSSOVER_2:
+ case WM8958_MBC_HPF_1:
+ case WM8958_MBC_HPF_2:
+ case WM8958_MBC_LPF_1:
+ case WM8958_MBC_LPF_2:
+ case WM8958_MBC_RMS_LIMIT_1:
+ case WM8958_MBC_RMS_LIMIT_2:
+ return true;
+ default:
+ return wm8994_readable_register(dev, reg);
+ }
+}
+
+static bool wm8994_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WM8994_SOFTWARE_RESET:
+ case WM8994_DC_SERVO_1:
+ case WM8994_DC_SERVO_READBACK:
+ case WM8994_RATE_STATUS:
+ case WM8958_MIC_DETECT_3:
+ case WM8994_DC_SERVO_4E:
+ case WM8994_CHIP_REVISION:
+ case WM8994_INTERRUPT_STATUS_1:
+ case WM8994_INTERRUPT_STATUS_2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool wm1811_volatile_register(struct device *dev, unsigned int reg)
+{
+ struct wm8994 *wm8994 = dev_get_drvdata(dev);
+
+ switch (reg) {
+ case WM8994_GPIO_6:
+ if (wm8994->revision > 1)
+ return true;
+ else
+ return false;
+ default:
+ return wm8994_volatile_register(dev, reg);
+ }
+}
+
+static bool wm8958_volatile_register(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case WM8958_DSP2_MAGICNUM:
+ case WM8958_DSP2_RELEASEYEAR:
+ case WM8958_DSP2_RELEASEMONTHDAY:
+ case WM8958_DSP2_RELEASETIME:
+ case WM8958_DSP2_VERMAJMIN:
+ case WM8958_DSP2_VERBUILD:
+ case WM8958_DSP2_EXECCONTROL:
+ case WM8958_DSP2_SWVERSIONREG:
+ case WM8958_DSP2_CONFIGXMEM:
+ case WM8958_DSP2_CONFIGYMEM:
+ case WM8958_DSP2_CONFIGZMEM:
+ case WM8958_FW_BUILD_1:
+ case WM8958_FW_BUILD_0:
+ case WM8958_FW_ID_1:
+ case WM8958_FW_ID_0:
+ case WM8958_FW_MAJOR_1:
+ case WM8958_FW_MAJOR_0:
+ case WM8958_FW_MINOR_1:
+ case WM8958_FW_MINOR_0:
+ case WM8958_FW_PATCH_1:
+ case WM8958_FW_PATCH_0:
+ return true;
+ default:
+ return wm8994_volatile_register(dev, reg);
+ }
+}
+
+struct regmap_config wm1811_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 16,
+
+ .cache_type = REGCACHE_RBTREE,
+
+ .reg_defaults = wm1811_defaults,
+ .num_reg_defaults = ARRAY_SIZE(wm1811_defaults),
+
+ .max_register = WM8994_MAX_REGISTER,
+ .volatile_reg = wm1811_volatile_register,
+ .readable_reg = wm1811_readable_register,
+};
+
+struct regmap_config wm8994_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 16,
+
+ .cache_type = REGCACHE_RBTREE,
+
+ .reg_defaults = wm8994_defaults,
+ .num_reg_defaults = ARRAY_SIZE(wm8994_defaults),
+
+ .max_register = WM8994_MAX_REGISTER,
+ .volatile_reg = wm8994_volatile_register,
+ .readable_reg = wm8994_readable_register,
+};
+
+struct regmap_config wm8958_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 16,
+
+ .cache_type = REGCACHE_RBTREE,
+
+ .reg_defaults = wm8958_defaults,
+ .num_reg_defaults = ARRAY_SIZE(wm8958_defaults),
+
+ .max_register = WM8994_MAX_REGISTER,
+ .volatile_reg = wm8958_volatile_register,
+ .readable_reg = wm8958_readable_register,
+};
+
+struct regmap_config wm8994_base_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 16,
+};
diff --git a/drivers/mfd/wm8994.h b/drivers/mfd/wm8994.h
new file mode 100644
index 00000000000..6f39a84eead
--- /dev/null
+++ b/drivers/mfd/wm8994.h
@@ -0,0 +1,25 @@
+/*
+ * wm8994.h -- WM8994 MFD internals
+ *
+ * Copyright 2011 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef __MFD_WM8994_H__
+#define __MFD_WM8994_H__
+
+#include <linux/regmap.h>
+
+extern struct regmap_config wm1811_regmap_config;
+extern struct regmap_config wm8994_regmap_config;
+extern struct regmap_config wm8958_regmap_config;
+extern struct regmap_config wm8994_base_regmap_config;
+
+#endif