diff options
Diffstat (limited to 'drivers/mfd')
63 files changed, 3141 insertions, 828 deletions
diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c index e017dc88622a..f93dd9571c3c 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 c8322eefc865..1489c3540f96 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. @@ -200,6 +201,7 @@ config MENELAUS config TWL4030_CORE bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support" depends on I2C=y && GENERIC_HARDIRQS + select 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 +259,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 +280,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 +330,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 @@ -399,6 +418,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 @@ -505,6 +535,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 d5f574306c7f..b953bab934f7 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 @@ -109,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 02c42015ba51..3aa36eb5c79b 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 ec10629a0b0b..54d0fe40845f 100644 --- a/drivers/mfd/ab5500-core.c +++ b/drivers/mfd/ab5500-core.c @@ -22,13 +22,12 @@ #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> #include <linux/mfd/core.h> -#include <linux/version.h> #include <linux/mfd/db5500-prcmu.h> #include "ab5500-core.h" diff --git a/drivers/mfd/ab5500-debugfs.c b/drivers/mfd/ab5500-debugfs.c index b7b2d3483fd4..72006940937a 100644 --- a/drivers/mfd/ab5500-debugfs.c +++ b/drivers/mfd/ab5500-debugfs.c @@ -7,8 +7,8 @@ #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 d3d572b2317b..d295941c9a3d 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> /* @@ -956,11 +956,12 @@ int __devinit ab8500_init(struct ab8500 *ab8500) return ret; out_freeirq: - if (ab8500->irq_base) { + if (ab8500->irq_base) free_irq(ab8500->irq, ab8500); out_removeirq: + if (ab8500->irq_base) ab8500_irq_remove(ab8500); - } + return ret; } diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index dedb7f65cea6..9a0211aa8897 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 e985d1701a83..c39fc716e1dc 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 9be541c6b004..087fecd71ce0 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 f20feefac190..c28d4eb1eff0 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/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c index 155fa0407882..315fef5d466a 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/dm355evm_msp.c b/drivers/mfd/dm355evm_msp.c index 8ad88da647b9..7710227d284e 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 97c27762174f..b76657eb0c51 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/janz-cmodio.c b/drivers/mfd/janz-cmodio.c index 5c2a06acb77f..a9223ed1b7c5 100644 --- a/drivers/mfd/janz-cmodio.c +++ b/drivers/mfd/janz-cmodio.c @@ -33,7 +33,7 @@ /* Module Parameters */ static unsigned int num_modules = CMODIO_MAX_MODULES; -static unsigned char *modules[CMODIO_MAX_MODULES] = { +static char *modules[CMODIO_MAX_MODULES] = { "empty", "empty", "empty", "empty", }; diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index ef39528088f2..87662a17dec6 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c @@ -181,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", @@ -338,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 ea1169b04779..abc421364a45 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 e1e59c92f758..ca881efedf75 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 0219115e00c7..d9e4b36edee9 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 5be53ae9b61c..cb83a7ab53e7 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 de4096aee248..6ef56d28c056 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 e9619acc0237..7122386b4e3c 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 84815f9ef636..86cc3f7841cd 100644 --- a/drivers/mfd/mcp-core.c +++ b/drivers/mfd/mcp-core.c @@ -93,9 +93,11 @@ static struct bus_type mcp_bus_type = { */ void mcp_set_telecom_divisor(struct mcp *mcp, unsigned int div) { - spin_lock_irq(&mcp->lock); + unsigned long flags; + + spin_lock_irqsave(&mcp->lock, flags); mcp->ops->set_telecom_divisor(mcp, div); - spin_unlock_irq(&mcp->lock); + spin_unlock_irqrestore(&mcp->lock, flags); } EXPORT_SYMBOL(mcp_set_telecom_divisor); @@ -108,9 +110,11 @@ EXPORT_SYMBOL(mcp_set_telecom_divisor); */ void mcp_set_audio_divisor(struct mcp *mcp, unsigned int div) { - spin_lock_irq(&mcp->lock); + unsigned long flags; + + spin_lock_irqsave(&mcp->lock, flags); mcp->ops->set_audio_divisor(mcp, div); - spin_unlock_irq(&mcp->lock); + spin_unlock_irqrestore(&mcp->lock, flags); } EXPORT_SYMBOL(mcp_set_audio_divisor); @@ -163,10 +167,11 @@ EXPORT_SYMBOL(mcp_reg_read); */ void mcp_enable(struct mcp *mcp) { - spin_lock_irq(&mcp->lock); + unsigned long flags; + spin_lock_irqsave(&mcp->lock, flags); if (mcp->use_count++ == 0) mcp->ops->enable(mcp); - spin_unlock_irq(&mcp->lock); + spin_unlock_irqrestore(&mcp->lock, flags); } EXPORT_SYMBOL(mcp_enable); diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c index 2dab02d9ac8b..02c53a0766c4 100644 --- a/drivers/mfd/mcp-sa11x0.c +++ b/drivers/mfd/mcp-sa11x0.c @@ -257,18 +257,7 @@ static struct platform_driver mcp_sa11x0_driver = { /* * 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/mfd-core.c b/drivers/mfd/mfd-core.c index 0f5922812bff..411f523d4878 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -123,7 +123,7 @@ static int mfd_add_device(struct device *parent, int id, } if (!cell->ignore_resource_conflicts) { - ret = acpi_check_resource_conflict(res); + ret = acpi_check_resource_conflict(&res[r]); if (ret) goto fail_res; } diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 3f565ef3e149..68ac2c55d5ae 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -503,19 +503,13 @@ static void omap_usbhs_init(struct device *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(pdata->ehci_data->reset_gpio_port[0], - "USB1 PHY reset"); - gpio_direction_output - (pdata->ehci_data->reset_gpio_port[0], 0); - } + 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(pdata->ehci_data->reset_gpio_port[1], - "USB2 PHY reset"); - gpio_direction_output - (pdata->ehci_data->reset_gpio_port[1], 0); - } + 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); diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c index aed0d2a9b032..3927c17e4175 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 000000000000..caadabeed8e9 --- /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 && 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 000000000000..de76dfb6f0ad --- /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 df3702c1756d..f4d86117f44a 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 000000000000..373f423b1181 --- /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 000000000000..b58c43c7ea93 --- /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 2963689cf45c..e07947e56b2a 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 e4ee38956583..7b8e13f5b764 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 91ad21ef7721..2d9e8799e733 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 71bc835324d8..d20a284ad4ba 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 af9ab0e5ca64..4fb0e6c8e8fe 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 02d65692ceb4..0ba26fb12cf5 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/tps65910-irq.c b/drivers/mfd/tps65910-irq.c index a56be931551c..95c0d7978bec 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 c1da84bc1573..4392f6bca156 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -168,19 +168,16 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, goto err; init_data->irq = pmic_plat_data->irq; - init_data->irq_base = pmic_plat_data->irq; + init_data->irq_base = pmic_plat_data->irq_base; 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-core.c b/drivers/mfd/tps65912-core.c index 5fec23a9ac03..74fd8cb5f372 100644 --- a/drivers/mfd/tps65912-core.c +++ b/drivers/mfd/tps65912-core.c @@ -151,7 +151,7 @@ int tps65912_device_init(struct tps65912 *tps65912) goto err; init_data->irq = pmic_plat_data->irq; - init_data->irq_base = pmic_plat_data->irq; + init_data->irq_base = pmic_plat_data->irq_base; ret = tps65912_irq_init(tps65912, init_data->irq, init_data); if (ret < 0) goto err; diff --git a/drivers/mfd/tps65912-spi.c b/drivers/mfd/tps65912-spi.c index 6d71e0d25744..27d3302d56b8 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 61e70cfaa774..806680d1bbb4 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -34,6 +34,12 @@ #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/irq.h> +#include <linux/irqdomain.h> #include <linux/regulator/machine.h> @@ -144,6 +150,9 @@ #define TWL_MODULE_LAST TWL4030_MODULE_LAST +#define TWL4030_NR_IRQS 34 /* core:8, power:8, gpio: 18 */ +#define TWL6030_NR_IRQS 20 + /* Base Address defns for twl4030_map[] */ /* subchip/slave 0 - USB ID */ @@ -255,7 +264,6 @@ struct twl_client { static struct twl_client twl_modules[TWL_NUM_SLAVES]; - /* mapping the module id to slave id and base address */ struct twl_mapping { unsigned char sid; /* Slave ID */ @@ -610,6 +618,8 @@ add_regulator_linked(int num, struct regulator_init_data *pdata, unsigned num_consumers, unsigned long features) { unsigned sub_chip_id; + struct twl_regulator_driver_data drv_data; + /* regulator framework demands init_data ... */ if (!pdata) return NULL; @@ -619,7 +629,19 @@ add_regulator_linked(int num, struct regulator_init_data *pdata, pdata->num_consumer_supplies = num_consumers; } - pdata->driver_data = (void *)features; + if (pdata->driver_data) { + /* If we have existing drv_data, just add the flags */ + struct twl_regulator_driver_data *tmp; + tmp = pdata->driver_data; + tmp->features |= features; + } else { + /* add new driver data struct, used only during init */ + drv_data.features = features; + drv_data.set_voltage = NULL; + drv_data.get_voltage = NULL; + drv_data.data = NULL; + pdata->driver_data = &drv_data; + } /* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */ sub_chip_id = twl_map[TWL_MODULE_PM_MASTER].sid; @@ -742,9 +764,9 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) /* we need to connect regulators to this transceiver */ if (twl_has_regulator() && child) { - usb1v5.dev = child; - usb1v8.dev = child; - usb3v1.dev = child; + usb1v5.dev_name = dev_name(child); + usb1v8.dev_name = dev_name(child); + usb3v1.dev_name = dev_name(child); } } if (twl_has_usb() && pdata->usb && twl_class_is_6030()) { @@ -790,7 +812,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) return PTR_ERR(child); /* we need to connect regulators to this transceiver */ if (twl_has_regulator() && child) - usb3v3.dev = child; + usb3v3.dev_name = dev_name(child); } else if (twl_has_regulator() && twl_class_is_6030()) { if (features & TWL6025_SUBCLASS) child = add_regulator(TWL6025_REG_LDOUSB, @@ -926,6 +948,31 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) /* twl6030 regulators */ if (twl_has_regulator() && twl_class_is_6030() && !(features & TWL6025_SUBCLASS)) { + child = add_regulator(TWL6030_REG_VDD1, pdata->vdd1, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + + child = add_regulator(TWL6030_REG_VDD2, pdata->vdd2, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + + child = add_regulator(TWL6030_REG_VDD3, pdata->vdd3, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + + child = add_regulator(TWL6030_REG_V1V8, pdata->v1v8, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + + child = add_regulator(TWL6030_REG_V2V1, pdata->v2v1, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc, features); if (IS_ERR(child)) @@ -1183,14 +1230,42 @@ 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; + irq_domain_add_legacy(node, nr_irqs, pdata->irq_base, 0, + &irq_domain_simple_ops, NULL); + if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) { dev_dbg(&client->dev, "can't talk I2C?\n"); return -EIO; @@ -1270,7 +1345,12 @@ 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); + status = -ENODEV; + if (node) + status = of_platform_populate(node, NULL, NULL, &client->dev); + if (status) + 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 ae51ab5d0e5d..838ce4eb444e 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 29f11e0765fe..b69bb517b102 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -492,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; @@ -667,6 +667,7 @@ 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); } diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index 834f824d3c11..456ecb5ac4fe 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 a764676f0922..79ca33dfacca 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) @@ -123,7 +124,7 @@ static u8 res_config_addrs[] = { [RES_MAIN_REF] = 0x94, }; -static int __init twl4030_write_script_byte(u8 address, u8 byte) +static int __devinit twl4030_write_script_byte(u8 address, u8 byte) { int err; @@ -137,7 +138,7 @@ out: return err; } -static int __init twl4030_write_script_ins(u8 address, u16 pmb_message, +static int __devinit twl4030_write_script_ins(u8 address, u16 pmb_message, u8 delay, u8 next) { int err; @@ -157,7 +158,7 @@ out: return err; } -static int __init twl4030_write_script(u8 address, struct twl4030_ins *script, +static int __devinit twl4030_write_script(u8 address, struct twl4030_ins *script, int len) { int err; @@ -182,7 +183,7 @@ static int __init twl4030_write_script(u8 address, struct twl4030_ins *script, return err; } -static int __init twl4030_config_wakeup3_sequence(u8 address) +static int __devinit twl4030_config_wakeup3_sequence(u8 address) { int err; u8 data; @@ -207,7 +208,7 @@ out: return err; } -static int __init twl4030_config_wakeup12_sequence(u8 address) +static int __devinit twl4030_config_wakeup12_sequence(u8 address) { int err = 0; u8 data; @@ -261,7 +262,7 @@ out: return err; } -static int __init twl4030_config_sleep_sequence(u8 address) +static int __devinit twl4030_config_sleep_sequence(u8 address) { int err; @@ -275,7 +276,7 @@ static int __init twl4030_config_sleep_sequence(u8 address) return err; } -static int __init twl4030_config_warmreset_sequence(u8 address) +static int __devinit twl4030_config_warmreset_sequence(u8 address) { int err; u8 rd_data; @@ -323,7 +324,7 @@ out: return err; } -static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig) +static int __devinit twl4030_configure_resource(struct twl4030_resconfig *rconfig) { int rconfig_addr; int err; @@ -415,7 +416,7 @@ static int __init twl4030_configure_resource(struct twl4030_resconfig *rconfig) return 0; } -static int __init load_twl4030_script(struct twl4030_script *tscript, +static int __devinit load_twl4030_script(struct twl4030_script *tscript, u8 address) { int err; @@ -511,12 +512,27 @@ int twl4030_remove_script(u8 flags) return err; } -void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts) +/* + * 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 __devinit 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/twl6040-core.c b/drivers/mfd/twl6040-core.c index 268f80fd0439..b2d8e512d3cb 100644 --- a/drivers/mfd/twl6040-core.c +++ b/drivers/mfd/twl6040-core.c @@ -282,6 +282,7 @@ int twl6040_power(struct twl6040 *twl6040, int on) /* Default PLL configuration after power up */ twl6040->pll = TWL6040_SYSCLK_SEL_LPPLL; twl6040->sysclk = 19200000; + twl6040->mclk = 32768; } else { /* already powered-down */ if (!twl6040->power_count) { @@ -305,6 +306,7 @@ int twl6040_power(struct twl6040 *twl6040, int on) twl6040_power_down(twl6040); } twl6040->sysclk = 0; + twl6040->mclk = 0; } out: @@ -324,23 +326,38 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, hppllctl = twl6040_reg_read(twl6040, TWL6040_REG_HPPLLCTL); lppllctl = twl6040_reg_read(twl6040, TWL6040_REG_LPPLLCTL); + /* Force full reconfiguration when switching between PLL */ + if (pll_id != twl6040->pll) { + twl6040->sysclk = 0; + twl6040->mclk = 0; + } + switch (pll_id) { case TWL6040_SYSCLK_SEL_LPPLL: /* low-power PLL divider */ - switch (freq_out) { - case 17640000: - lppllctl |= TWL6040_LPLLFIN; - break; - case 19200000: - lppllctl &= ~TWL6040_LPLLFIN; - break; - default: - dev_err(twl6040->dev, - "freq_out %d not supported\n", freq_out); - ret = -EINVAL; - goto pll_out; + /* Change the sysclk configuration only if it has been canged */ + if (twl6040->sysclk != freq_out) { + switch (freq_out) { + case 17640000: + lppllctl |= TWL6040_LPLLFIN; + break; + case 19200000: + lppllctl &= ~TWL6040_LPLLFIN; + break; + default: + dev_err(twl6040->dev, + "freq_out %d not supported\n", + freq_out); + ret = -EINVAL; + goto pll_out; + } + twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, + lppllctl); } - twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl); + + /* The PLL in use has not been change, we can exit */ + if (twl6040->pll == pll_id) + break; switch (freq_in) { case 32768: @@ -371,48 +388,56 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, goto pll_out; } - hppllctl &= ~TWL6040_MCLK_MSK; + if (twl6040->mclk != freq_in) { + hppllctl &= ~TWL6040_MCLK_MSK; + + switch (freq_in) { + case 12000000: + /* PLL enabled, active mode */ + hppllctl |= TWL6040_MCLK_12000KHZ | + TWL6040_HPLLENA; + break; + case 19200000: + /* + * PLL disabled + * (enable PLL if MCLK jitter quality + * doesn't meet specification) + */ + hppllctl |= TWL6040_MCLK_19200KHZ; + break; + case 26000000: + /* PLL enabled, active mode */ + hppllctl |= TWL6040_MCLK_26000KHZ | + TWL6040_HPLLENA; + break; + case 38400000: + /* PLL enabled, active mode */ + hppllctl |= TWL6040_MCLK_38400KHZ | + TWL6040_HPLLENA; + break; + default: + dev_err(twl6040->dev, + "freq_in %d not supported\n", freq_in); + ret = -EINVAL; + goto pll_out; + } - switch (freq_in) { - case 12000000: - /* PLL enabled, active mode */ - hppllctl |= TWL6040_MCLK_12000KHZ | - TWL6040_HPLLENA; - break; - case 19200000: /* - * PLL disabled - * (enable PLL if MCLK jitter quality - * doesn't meet specification) + * enable clock slicer to ensure input waveform is + * square */ - hppllctl |= TWL6040_MCLK_19200KHZ; - break; - case 26000000: - /* PLL enabled, active mode */ - hppllctl |= TWL6040_MCLK_26000KHZ | - TWL6040_HPLLENA; - break; - case 38400000: - /* PLL enabled, active mode */ - hppllctl |= TWL6040_MCLK_38400KHZ | - TWL6040_HPLLENA; - break; - default: - dev_err(twl6040->dev, - "freq_in %d not supported\n", freq_in); - ret = -EINVAL; - goto pll_out; - } + hppllctl |= TWL6040_HPLLSQRENA; - /* enable clock slicer to ensure input waveform is square */ - hppllctl |= TWL6040_HPLLSQRENA; - - twl6040_reg_write(twl6040, TWL6040_REG_HPPLLCTL, hppllctl); - usleep_range(500, 700); - lppllctl |= TWL6040_HPLLSEL; - twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl); - lppllctl &= ~TWL6040_LPLLENA; - twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl); + twl6040_reg_write(twl6040, TWL6040_REG_HPPLLCTL, + hppllctl); + usleep_range(500, 700); + lppllctl |= TWL6040_HPLLSEL; + twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, + lppllctl); + lppllctl &= ~TWL6040_LPLLENA; + twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, + lppllctl); + } break; default: dev_err(twl6040->dev, "unknown pll id %d\n", pll_id); @@ -421,6 +446,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id, } twl6040->sysclk = freq_out; + twl6040->mclk = freq_in; twl6040->pll = pll_id; pll_out: @@ -509,13 +535,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 +642,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 b281217334eb..febc90cdef7e 100644 --- a/drivers/mfd/ucb1x00-core.c +++ b/drivers/mfd/ucb1x00-core.c @@ -148,16 +148,22 @@ static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset { struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio); unsigned long flags; + unsigned old, mask = 1 << offset; spin_lock_irqsave(&ucb->io_lock, flags); - ucb->io_dir |= (1 << offset); - ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir); - + old = ucb->io_out; if (value) - ucb->io_out |= 1 << offset; + ucb->io_out |= mask; else - ucb->io_out &= ~(1 << offset); - ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); + ucb->io_out &= ~mask; + + if (old != ucb->io_out) + ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); + + if (!(ucb->io_dir & mask)) { + ucb->io_dir |= mask; + ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir); + } spin_unlock_irqrestore(&ucb->io_lock, flags); return 0; @@ -687,6 +693,7 @@ static int ucb1x00_resume(struct mcp *mcp) struct ucb1x00 *ucb = mcp_get_drvdata(mcp); struct ucb1x00_dev *dev; + ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out); ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir); mutex_lock(&ucb1x00_mutex); list_for_each_entry(dev, &ucb->devs, dev_node) { diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c index 38ffbd50a0d2..63a3cbdfa3f3 100644 --- a/drivers/mfd/ucb1x00-ts.c +++ b/drivers/mfd/ucb1x00-ts.c @@ -47,7 +47,6 @@ struct ucb1x00_ts { u16 x_res; u16 y_res; - unsigned int restart:1; unsigned int adcsync:1; }; @@ -207,15 +206,17 @@ static int ucb1x00_thread(void *_ts) { struct ucb1x00_ts *ts = _ts; DECLARE_WAITQUEUE(wait, current); + bool frozen, ignore = false; int valid = 0; set_freezable(); add_wait_queue(&ts->irq_wait, &wait); - while (!kthread_should_stop()) { + while (!kthread_freezable_should_stop(&frozen)) { unsigned int x, y, p; signed long timeout; - ts->restart = 0; + if (frozen) + ignore = true; ucb1x00_adc_enable(ts->ucb); @@ -258,7 +259,7 @@ static int ucb1x00_thread(void *_ts) * space. We therefore leave it to user space * to do any filtering they please. */ - if (!ts->restart) { + if (!ignore) { ucb1x00_ts_evt_add(ts, p, x, y); valid = 1; } @@ -267,8 +268,6 @@ static int ucb1x00_thread(void *_ts) timeout = HZ / 100; } - try_to_freeze(); - schedule_timeout(timeout); } @@ -340,26 +339,6 @@ static void ucb1x00_ts_close(struct input_dev *idev) ucb1x00_disable(ts->ucb); } -#ifdef CONFIG_PM -static int ucb1x00_ts_resume(struct ucb1x00_dev *dev) -{ - struct ucb1x00_ts *ts = dev->priv; - - if (ts->rtask != NULL) { - /* - * Restart the TS thread to ensure the - * TS interrupt mode is set up again - * after sleep. - */ - ts->restart = 1; - wake_up(&ts->irq_wait); - } - return 0; -} -#else -#define ucb1x00_ts_resume NULL -#endif - /* * Initialisation. @@ -425,7 +404,6 @@ static void ucb1x00_ts_remove(struct ucb1x00_dev *dev) static struct ucb1x00_driver ucb1x00_ts_driver = { .add = ucb1x00_ts_add, .remove = ucb1x00_ts_remove, - .resume = ucb1x00_ts_resume, }; static int __init ucb1x00_ts_init(void) diff --git a/drivers/mfd/vx855.c b/drivers/mfd/vx855.c index d698703dbd46..b73cc15e0081 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 0a2b8d41a702..f5e54fae8ada 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 ac8da1d439da..cb15609b0a48 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 f4747a4a9a93..bec4d0539160 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 8d6a9a969dbc..62ef3254105f 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 e81cc31e4202..dd1caaac55e4 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 5fe5de166adb..d955faaf27c4 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/wm8350-irq.c b/drivers/mfd/wm8350-irq.c index 8a1fafd0bf7d..9fd01bf63c51 100644 --- a/drivers/mfd/wm8350-irq.c +++ b/drivers/mfd/wm8350-irq.c @@ -496,7 +496,6 @@ int wm8350_irq_init(struct wm8350 *wm8350, int irq, mutex_init(&wm8350->irq_lock); wm8350->chip_irq = irq; - wm8350->irq_base = pdata->irq_base; if (pdata && pdata->irq_base > 0) irq_base = pdata->irq_base; diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index 62b4626f4561..2204893444a6 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 61894fced8ea..a04b3c108c8c 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. * @@ -252,6 +242,34 @@ 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; + } + + 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) @@ -259,25 +277,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; @@ -294,7 +301,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) @@ -307,27 +314,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, @@ -336,6 +329,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 @@ -361,19 +359,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); @@ -402,9 +397,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; @@ -432,7 +427,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, @@ -482,25 +477,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; @@ -516,12 +540,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 @@ -560,12 +588,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; } @@ -577,18 +602,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; @@ -597,12 +628,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; } @@ -620,6 +650,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 }, { } @@ -634,6 +665,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 d682f7bd112c..46b20c445ecf 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 000000000000..bc0c5096539a --- /dev/null +++ b/drivers/mfd/wm8994-regmap.c @@ -0,0 +1,1239 @@ +/* + * 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_DC_SERVO_4E: + 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 000000000000..6f39a84eeadf --- /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 |