mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 03:27:44 -04:00
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/mfd-2.6: (59 commits) rtc: max8925: Add function to work as wakeup source mfd: Add pm ops to max8925 mfd: Convert aat2870 to dev_pm_ops mfd: Still check other interrupts if we get a wm831x touchscreen IRQ mfd: Introduce missing kfree in 88pm860x probe routine mfd: Add S5M series configuration mfd: Add s5m series irq driver mfd: Add S5M core driver mfd: Improve mc13xxx dt binding document mfd: Fix stmpe section mismatch mfd: Fix stmpe build warning mfd: Fix STMPE I2c build failure mfd: Constify aat2870-core i2c_device_id table gpio: Add support for stmpe variant 801 mfd: Add support for stmpe variant 801 mfd: Add support for stmpe variant 610 mfd: Add support for STMPE SPI interface mfd: Separate out STMPE controller and interface specific code misc: Remove max8997-muic sysfs attributes mfd: Remove unused wm831x_irq_data_to_mask_reg() ... Fix up trivial conflict in drivers/leds/Kconfig due to addition of LEDS_MAX8997 and LEDS_TCA6507 next to each other.
This commit is contained in:
commit
21ebd6c68b
98 changed files with 3636 additions and 547 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ config MFD_CORE
|
|||
config MFD_88PM860X
|
||||
bool "Support Marvell 88PM8606/88PM8607"
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
select REGMAP_I2C
|
||||
select MFD_CORE
|
||||
help
|
||||
This supports for Marvell 88PM8606/88PM8607 Power Management IC.
|
||||
|
|
@ -199,7 +200,7 @@ config MENELAUS
|
|||
|
||||
config TWL4030_CORE
|
||||
bool "Texas Instruments TWL4030/TWL5030/TWL6030/TPS659x0 Support"
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
depends on I2C=y && GENERIC_HARDIRQS && IRQ_DOMAIN
|
||||
help
|
||||
Say yes here if you have TWL4030 / TWL6030 family chip on your board.
|
||||
This core driver provides register access and IRQ handling
|
||||
|
|
@ -257,7 +258,7 @@ config TWL6040_CORE
|
|||
|
||||
config MFD_STMPE
|
||||
bool "Support STMicroelectronics STMPE"
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
depends on (I2C=y || SPI_MASTER=y) && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
help
|
||||
Support for the STMPE family of I/O Expanders from
|
||||
|
|
@ -278,6 +279,23 @@ config MFD_STMPE
|
|||
Keypad: stmpe-keypad
|
||||
Touchscreen: stmpe-ts
|
||||
|
||||
menu "STMPE Interface Drivers"
|
||||
depends on MFD_STMPE
|
||||
|
||||
config STMPE_I2C
|
||||
bool "STMPE I2C Inteface"
|
||||
depends on I2C=y
|
||||
default y
|
||||
help
|
||||
This is used to enable I2C interface of STMPE
|
||||
|
||||
config STMPE_SPI
|
||||
bool "STMPE SPI Inteface"
|
||||
depends on SPI_MASTER
|
||||
help
|
||||
This is used to enable SPI interface of STMPE
|
||||
endmenu
|
||||
|
||||
config MFD_TC3589X
|
||||
bool "Support Toshiba TC35892 and variants"
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
|
|
@ -311,7 +329,7 @@ config MFD_TC6387XB
|
|||
|
||||
config MFD_TC6393XB
|
||||
bool "Support Toshiba TC6393XB"
|
||||
depends on GPIOLIB && ARM
|
||||
depends on GPIOLIB && ARM && HAVE_CLK
|
||||
select MFD_CORE
|
||||
select MFD_TMIO
|
||||
help
|
||||
|
|
@ -399,6 +417,17 @@ config MFD_MAX8998
|
|||
additional drivers must be enabled in order to use the functionality
|
||||
of the device.
|
||||
|
||||
config MFD_S5M_CORE
|
||||
bool "SAMSUNG S5M Series Support"
|
||||
depends on I2C=y && GENERIC_HARDIRQS
|
||||
select MFD_CORE
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Support for the Samsung Electronics S5M MFD series.
|
||||
This driver provies common support for accessing the device,
|
||||
additional drivers must be enabled in order to use the functionality
|
||||
of the device
|
||||
|
||||
config MFD_WM8400
|
||||
tristate "Support Wolfson Microelectronics WM8400"
|
||||
select MFD_CORE
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 struct i2c_device_id aat2870_i2c_id_table[] = {
|
||||
static SIMPLE_DEV_PM_OPS(aat2870_pm_ops, aat2870_i2c_suspend,
|
||||
aat2870_i2c_resume);
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@
|
|||
#include <linux/irq.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/mfd/ab5500/ab5500.h>
|
||||
#include <linux/mfd/abx500.h>
|
||||
#include <linux/mfd/abx500/ab5500.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 <[email protected]>");
|
||||
|
|
|
|||
|
|
@ -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 <[email protected]>");
|
||||
|
|
|
|||
|
|
@ -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, }
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -26,9 +26,35 @@
|
|||
#define to_mcp(d) container_of(d, struct mcp, attached_device)
|
||||
#define to_mcp_driver(d) container_of(d, struct mcp_driver, drv)
|
||||
|
||||
static const struct mcp_device_id *mcp_match_id(const struct mcp_device_id *id,
|
||||
const char *codec)
|
||||
{
|
||||
while (id->name[0]) {
|
||||
if (strcmp(codec, id->name) == 0)
|
||||
return id;
|
||||
id++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct mcp_device_id *mcp_get_device_id(const struct mcp *mcp)
|
||||
{
|
||||
const struct mcp_driver *driver =
|
||||
to_mcp_driver(mcp->attached_device.driver);
|
||||
|
||||
return mcp_match_id(driver->id_table, mcp->codec);
|
||||
}
|
||||
EXPORT_SYMBOL(mcp_get_device_id);
|
||||
|
||||
static int mcp_bus_match(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
return 1;
|
||||
const struct mcp *mcp = to_mcp(dev);
|
||||
const struct mcp_driver *driver = to_mcp_driver(drv);
|
||||
|
||||
if (driver->id_table)
|
||||
return !!mcp_match_id(driver->id_table, mcp->codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mcp_bus_probe(struct device *dev)
|
||||
|
|
@ -74,9 +100,18 @@ static int mcp_bus_resume(struct device *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int mcp_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
struct mcp *mcp = to_mcp(dev);
|
||||
|
||||
add_uevent_var(env, "MODALIAS=%s%s", MCP_MODULE_PREFIX, mcp->codec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bus_type mcp_bus_type = {
|
||||
.name = "mcp",
|
||||
.match = mcp_bus_match,
|
||||
.uevent = mcp_bus_uevent,
|
||||
.probe = mcp_bus_probe,
|
||||
.remove = mcp_bus_remove,
|
||||
.suspend = mcp_bus_suspend,
|
||||
|
|
@ -212,9 +247,14 @@ struct mcp *mcp_host_alloc(struct device *parent, size_t size)
|
|||
}
|
||||
EXPORT_SYMBOL(mcp_host_alloc);
|
||||
|
||||
int mcp_host_register(struct mcp *mcp)
|
||||
int mcp_host_register(struct mcp *mcp, void *pdata)
|
||||
{
|
||||
if (!mcp->codec)
|
||||
return -EINVAL;
|
||||
|
||||
mcp->attached_device.platform_data = pdata;
|
||||
dev_set_name(&mcp->attached_device, "mcp0");
|
||||
request_module("%s%s", MCP_MODULE_PREFIX, mcp->codec);
|
||||
return device_register(&mcp->attached_device);
|
||||
}
|
||||
EXPORT_SYMBOL(mcp_host_register);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/mcp.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <mach/dma.h>
|
||||
#include <mach/hardware.h>
|
||||
|
|
@ -26,12 +27,19 @@
|
|||
#include <asm/system.h>
|
||||
#include <mach/mcp.h>
|
||||
|
||||
#include <mach/assabet.h>
|
||||
|
||||
/* Register offsets */
|
||||
#define MCCR0 0x00
|
||||
#define MCDR0 0x08
|
||||
#define MCDR1 0x0C
|
||||
#define MCDR2 0x10
|
||||
#define MCSR 0x18
|
||||
#define MCCR1 0x00
|
||||
|
||||
struct mcp_sa11x0 {
|
||||
u32 mccr0;
|
||||
u32 mccr1;
|
||||
u32 mccr0;
|
||||
u32 mccr1;
|
||||
unsigned char *mccr0_base;
|
||||
unsigned char *mccr1_base;
|
||||
};
|
||||
|
||||
#define priv(mcp) ((struct mcp_sa11x0 *)mcp_priv(mcp))
|
||||
|
|
@ -39,25 +47,25 @@ struct mcp_sa11x0 {
|
|||
static void
|
||||
mcp_sa11x0_set_telecom_divisor(struct mcp *mcp, unsigned int divisor)
|
||||
{
|
||||
unsigned int mccr0;
|
||||
struct mcp_sa11x0 *priv = priv(mcp);
|
||||
|
||||
divisor /= 32;
|
||||
|
||||
mccr0 = Ser4MCCR0 & ~0x00007f00;
|
||||
mccr0 |= divisor << 8;
|
||||
Ser4MCCR0 = mccr0;
|
||||
priv->mccr0 &= ~0x00007f00;
|
||||
priv->mccr0 |= divisor << 8;
|
||||
__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
|
||||
}
|
||||
|
||||
static void
|
||||
mcp_sa11x0_set_audio_divisor(struct mcp *mcp, unsigned int divisor)
|
||||
{
|
||||
unsigned int mccr0;
|
||||
struct mcp_sa11x0 *priv = priv(mcp);
|
||||
|
||||
divisor /= 32;
|
||||
|
||||
mccr0 = Ser4MCCR0 & ~0x0000007f;
|
||||
mccr0 |= divisor;
|
||||
Ser4MCCR0 = mccr0;
|
||||
priv->mccr0 &= ~0x0000007f;
|
||||
priv->mccr0 |= divisor;
|
||||
__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -71,12 +79,16 @@ mcp_sa11x0_write(struct mcp *mcp, unsigned int reg, unsigned int val)
|
|||
{
|
||||
int ret = -ETIME;
|
||||
int i;
|
||||
u32 mcpreg;
|
||||
struct mcp_sa11x0 *priv = priv(mcp);
|
||||
|
||||
Ser4MCDR2 = reg << 17 | MCDR2_Wr | (val & 0xffff);
|
||||
mcpreg = reg << 17 | MCDR2_Wr | (val & 0xffff);
|
||||
__raw_writel(mcpreg, priv->mccr0_base + MCDR2);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
udelay(mcp->rw_timeout);
|
||||
if (Ser4MCSR & MCSR_CWC) {
|
||||
mcpreg = __raw_readl(priv->mccr0_base + MCSR);
|
||||
if (mcpreg & MCSR_CWC) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
|
|
@ -97,13 +109,18 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
|
|||
{
|
||||
int ret = -ETIME;
|
||||
int i;
|
||||
u32 mcpreg;
|
||||
struct mcp_sa11x0 *priv = priv(mcp);
|
||||
|
||||
Ser4MCDR2 = reg << 17 | MCDR2_Rd;
|
||||
mcpreg = reg << 17 | MCDR2_Rd;
|
||||
__raw_writel(mcpreg, priv->mccr0_base + MCDR2);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
udelay(mcp->rw_timeout);
|
||||
if (Ser4MCSR & MCSR_CRC) {
|
||||
ret = Ser4MCDR2 & 0xffff;
|
||||
mcpreg = __raw_readl(priv->mccr0_base + MCSR);
|
||||
if (mcpreg & MCSR_CRC) {
|
||||
ret = __raw_readl(priv->mccr0_base + MCDR2)
|
||||
& 0xffff;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -116,13 +133,19 @@ mcp_sa11x0_read(struct mcp *mcp, unsigned int reg)
|
|||
|
||||
static void mcp_sa11x0_enable(struct mcp *mcp)
|
||||
{
|
||||
Ser4MCSR = -1;
|
||||
Ser4MCCR0 |= MCCR0_MCE;
|
||||
struct mcp_sa11x0 *priv = priv(mcp);
|
||||
|
||||
__raw_writel(-1, priv->mccr0_base + MCSR);
|
||||
priv->mccr0 |= MCCR0_MCE;
|
||||
__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
|
||||
}
|
||||
|
||||
static void mcp_sa11x0_disable(struct mcp *mcp)
|
||||
{
|
||||
Ser4MCCR0 &= ~MCCR0_MCE;
|
||||
struct mcp_sa11x0 *priv = priv(mcp);
|
||||
|
||||
priv->mccr0 &= ~MCCR0_MCE;
|
||||
__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -142,50 +165,69 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
|
|||
struct mcp_plat_data *data = pdev->dev.platform_data;
|
||||
struct mcp *mcp;
|
||||
int ret;
|
||||
struct mcp_sa11x0 *priv;
|
||||
struct resource *res_mem0, *res_mem1;
|
||||
u32 size0, size1;
|
||||
|
||||
if (!data)
|
||||
return -ENODEV;
|
||||
|
||||
if (!request_mem_region(0x80060000, 0x60, "sa11x0-mcp"))
|
||||
if (!data->codec)
|
||||
return -ENODEV;
|
||||
|
||||
res_mem0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res_mem0)
|
||||
return -ENODEV;
|
||||
size0 = res_mem0->end - res_mem0->start + 1;
|
||||
|
||||
res_mem1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!res_mem1)
|
||||
return -ENODEV;
|
||||
size1 = res_mem1->end - res_mem1->start + 1;
|
||||
|
||||
if (!request_mem_region(res_mem0->start, size0, "sa11x0-mcp"))
|
||||
return -EBUSY;
|
||||
|
||||
if (!request_mem_region(res_mem1->start, size1, "sa11x0-mcp")) {
|
||||
ret = -EBUSY;
|
||||
goto release;
|
||||
}
|
||||
|
||||
mcp = mcp_host_alloc(&pdev->dev, sizeof(struct mcp_sa11x0));
|
||||
if (!mcp) {
|
||||
ret = -ENOMEM;
|
||||
goto release;
|
||||
goto release2;
|
||||
}
|
||||
|
||||
priv = priv(mcp);
|
||||
|
||||
mcp->owner = THIS_MODULE;
|
||||
mcp->ops = &mcp_sa11x0;
|
||||
mcp->sclk_rate = data->sclk_rate;
|
||||
mcp->dma_audio_rd = DMA_Ser4MCP0Rd;
|
||||
mcp->dma_audio_wr = DMA_Ser4MCP0Wr;
|
||||
mcp->dma_telco_rd = DMA_Ser4MCP1Rd;
|
||||
mcp->dma_telco_wr = DMA_Ser4MCP1Wr;
|
||||
mcp->gpio_base = data->gpio_base;
|
||||
mcp->dma_audio_rd = DDAR_DevAdd(res_mem0->start + MCDR0)
|
||||
+ DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev;
|
||||
mcp->dma_audio_wr = DDAR_DevAdd(res_mem0->start + MCDR0)
|
||||
+ DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev;
|
||||
mcp->dma_telco_rd = DDAR_DevAdd(res_mem0->start + MCDR1)
|
||||
+ DDAR_DevRd + DDAR_Brst4 + DDAR_8BitDev;
|
||||
mcp->dma_telco_wr = DDAR_DevAdd(res_mem0->start + MCDR1)
|
||||
+ DDAR_DevWr + DDAR_Brst4 + DDAR_8BitDev;
|
||||
mcp->codec = data->codec;
|
||||
|
||||
platform_set_drvdata(pdev, mcp);
|
||||
|
||||
if (machine_is_assabet()) {
|
||||
ASSABET_BCR_set(ASSABET_BCR_CODEC_RST);
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup the PPC unit correctly.
|
||||
*/
|
||||
PPDR &= ~PPC_RXD4;
|
||||
PPDR |= PPC_TXD4 | PPC_SCLK | PPC_SFRM;
|
||||
PSDR |= PPC_RXD4;
|
||||
PSDR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
|
||||
PPSR &= ~(PPC_TXD4 | PPC_SCLK | PPC_SFRM);
|
||||
|
||||
/*
|
||||
* Initialise device. Note that we initially
|
||||
* set the sampling rate to minimum.
|
||||
*/
|
||||
Ser4MCSR = -1;
|
||||
Ser4MCCR1 = data->mccr1;
|
||||
Ser4MCCR0 = data->mccr0 | 0x7f7f;
|
||||
priv->mccr0_base = ioremap(res_mem0->start, size0);
|
||||
priv->mccr1_base = ioremap(res_mem1->start, size1);
|
||||
|
||||
__raw_writel(-1, priv->mccr0_base + MCSR);
|
||||
priv->mccr1 = data->mccr1;
|
||||
priv->mccr0 = data->mccr0 | 0x7f7f;
|
||||
__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
|
||||
__raw_writel(priv->mccr1, priv->mccr1_base + MCCR1);
|
||||
|
||||
/*
|
||||
* Calculate the read/write timeout (us) from the bit clock
|
||||
|
|
@ -195,36 +237,53 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
|
|||
mcp->rw_timeout = (64 * 3 * 1000000 + mcp->sclk_rate - 1) /
|
||||
mcp->sclk_rate;
|
||||
|
||||
ret = mcp_host_register(mcp);
|
||||
ret = mcp_host_register(mcp, data->codec_pdata);
|
||||
if (ret == 0)
|
||||
goto out;
|
||||
|
||||
release2:
|
||||
release_mem_region(res_mem1->start, size1);
|
||||
release:
|
||||
release_mem_region(0x80060000, 0x60);
|
||||
release_mem_region(res_mem0->start, size0);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mcp_sa11x0_remove(struct platform_device *dev)
|
||||
static int mcp_sa11x0_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mcp *mcp = platform_get_drvdata(dev);
|
||||
struct mcp *mcp = platform_get_drvdata(pdev);
|
||||
struct mcp_sa11x0 *priv = priv(mcp);
|
||||
struct resource *res_mem;
|
||||
u32 size;
|
||||
|
||||
platform_set_drvdata(dev, NULL);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
mcp_host_unregister(mcp);
|
||||
release_mem_region(0x80060000, 0x60);
|
||||
|
||||
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (res_mem) {
|
||||
size = res_mem->end - res_mem->start + 1;
|
||||
release_mem_region(res_mem->start, size);
|
||||
}
|
||||
res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (res_mem) {
|
||||
size = res_mem->end - res_mem->start + 1;
|
||||
release_mem_region(res_mem->start, size);
|
||||
}
|
||||
iounmap(priv->mccr0_base);
|
||||
iounmap(priv->mccr1_base);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
|
||||
{
|
||||
struct mcp *mcp = platform_get_drvdata(dev);
|
||||
struct mcp_sa11x0 *priv = priv(mcp);
|
||||
u32 mccr0;
|
||||
|
||||
priv(mcp)->mccr0 = Ser4MCCR0;
|
||||
priv(mcp)->mccr1 = Ser4MCCR1;
|
||||
Ser4MCCR0 &= ~MCCR0_MCE;
|
||||
mccr0 = priv->mccr0 & ~MCCR0_MCE;
|
||||
__raw_writel(mccr0, priv->mccr0_base + MCCR0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -232,9 +291,10 @@ static int mcp_sa11x0_suspend(struct platform_device *dev, pm_message_t state)
|
|||
static int mcp_sa11x0_resume(struct platform_device *dev)
|
||||
{
|
||||
struct mcp *mcp = platform_get_drvdata(dev);
|
||||
struct mcp_sa11x0 *priv = priv(mcp);
|
||||
|
||||
Ser4MCCR1 = priv(mcp)->mccr1;
|
||||
Ser4MCCR0 = priv(mcp)->mccr0;
|
||||
__raw_writel(priv->mccr0, priv->mccr0_base + MCCR0);
|
||||
__raw_writel(priv->mccr1, priv->mccr1_base + MCCR1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -251,24 +311,14 @@ static struct platform_driver mcp_sa11x0_driver = {
|
|||
.resume = mcp_sa11x0_resume,
|
||||
.driver = {
|
||||
.name = "sa11x0-mcp",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* This needs re-working
|
||||
*/
|
||||
static int __init mcp_sa11x0_init(void)
|
||||
{
|
||||
return platform_driver_register(&mcp_sa11x0_driver);
|
||||
}
|
||||
|
||||
static void __exit mcp_sa11x0_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&mcp_sa11x0_driver);
|
||||
}
|
||||
|
||||
module_init(mcp_sa11x0_init);
|
||||
module_exit(mcp_sa11x0_exit);
|
||||
module_platform_driver(mcp_sa11x0_driver);
|
||||
|
||||
MODULE_AUTHOR("Russell King <[email protected]>");
|
||||
MODULE_DESCRIPTION("SA11x0 multimedia communications port driver");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 <[email protected]>");
|
||||
MODULE_DESCRIPTION("PCF50633 adc driver");
|
||||
|
|
|
|||
176
drivers/mfd/s5m-core.c
Normal file
176
drivers/mfd/s5m-core.c
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* s5m87xx.c
|
||||
*
|
||||
* Copyright (c) 2011 Samsung Electronics Co., Ltd
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/s5m87xx/s5m-core.h>
|
||||
#include <linux/mfd/s5m87xx/s5m-pmic.h>
|
||||
#include <linux/mfd/s5m87xx/s5m-rtc.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
static struct mfd_cell s5m87xx_devs[] = {
|
||||
{
|
||||
.name = "s5m8767-pmic",
|
||||
}, {
|
||||
.name = "s5m-rtc",
|
||||
},
|
||||
};
|
||||
|
||||
int s5m_reg_read(struct s5m87xx_dev *s5m87xx, u8 reg, void *dest)
|
||||
{
|
||||
return regmap_read(s5m87xx->regmap, reg, dest);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(s5m_reg_read);
|
||||
|
||||
int s5m_bulk_read(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
|
||||
{
|
||||
return regmap_bulk_read(s5m87xx->regmap, reg, buf, count);;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(s5m_bulk_read);
|
||||
|
||||
int s5m_reg_write(struct s5m87xx_dev *s5m87xx, u8 reg, u8 value)
|
||||
{
|
||||
return regmap_write(s5m87xx->regmap, reg, value);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(s5m_reg_write);
|
||||
|
||||
int s5m_bulk_write(struct s5m87xx_dev *s5m87xx, u8 reg, int count, u8 *buf)
|
||||
{
|
||||
return regmap_raw_write(s5m87xx->regmap, reg, buf, count * sizeof(u16));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(s5m_bulk_write);
|
||||
|
||||
int s5m_reg_update(struct s5m87xx_dev *s5m87xx, u8 reg, u8 val, u8 mask)
|
||||
{
|
||||
return regmap_update_bits(s5m87xx->regmap, reg, mask, val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(s5m_reg_update);
|
||||
|
||||
static struct regmap_config s5m_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
};
|
||||
|
||||
static int s5m87xx_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct s5m_platform_data *pdata = i2c->dev.platform_data;
|
||||
struct s5m87xx_dev *s5m87xx;
|
||||
int ret = 0;
|
||||
int error;
|
||||
|
||||
s5m87xx = kzalloc(sizeof(struct s5m87xx_dev), GFP_KERNEL);
|
||||
if (s5m87xx == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(i2c, s5m87xx);
|
||||
s5m87xx->dev = &i2c->dev;
|
||||
s5m87xx->i2c = i2c;
|
||||
s5m87xx->irq = i2c->irq;
|
||||
s5m87xx->type = id->driver_data;
|
||||
|
||||
if (pdata) {
|
||||
s5m87xx->device_type = pdata->device_type;
|
||||
s5m87xx->ono = pdata->ono;
|
||||
s5m87xx->irq_base = pdata->irq_base;
|
||||
s5m87xx->wakeup = pdata->wakeup;
|
||||
}
|
||||
|
||||
s5m87xx->regmap = regmap_init_i2c(i2c, &s5m_regmap_config);
|
||||
if (IS_ERR(s5m87xx->regmap)) {
|
||||
error = PTR_ERR(s5m87xx->regmap);
|
||||
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
|
||||
error);
|
||||
goto err;
|
||||
}
|
||||
|
||||
s5m87xx->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
|
||||
i2c_set_clientdata(s5m87xx->rtc, s5m87xx);
|
||||
|
||||
if (pdata->cfg_pmic_irq)
|
||||
pdata->cfg_pmic_irq();
|
||||
|
||||
s5m_irq_init(s5m87xx);
|
||||
|
||||
pm_runtime_set_active(s5m87xx->dev);
|
||||
|
||||
ret = mfd_add_devices(s5m87xx->dev, -1,
|
||||
s5m87xx_devs, ARRAY_SIZE(s5m87xx_devs),
|
||||
NULL, 0);
|
||||
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
return ret;
|
||||
|
||||
err:
|
||||
mfd_remove_devices(s5m87xx->dev);
|
||||
s5m_irq_exit(s5m87xx);
|
||||
i2c_unregister_device(s5m87xx->rtc);
|
||||
regmap_exit(s5m87xx->regmap);
|
||||
kfree(s5m87xx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int s5m87xx_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
struct s5m87xx_dev *s5m87xx = i2c_get_clientdata(i2c);
|
||||
|
||||
mfd_remove_devices(s5m87xx->dev);
|
||||
s5m_irq_exit(s5m87xx);
|
||||
i2c_unregister_device(s5m87xx->rtc);
|
||||
regmap_exit(s5m87xx->regmap);
|
||||
kfree(s5m87xx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id s5m87xx_i2c_id[] = {
|
||||
{ "s5m87xx", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, s5m87xx_i2c_id);
|
||||
|
||||
static struct i2c_driver s5m87xx_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "s5m87xx",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = s5m87xx_i2c_probe,
|
||||
.remove = s5m87xx_i2c_remove,
|
||||
.id_table = s5m87xx_i2c_id,
|
||||
};
|
||||
|
||||
static int __init s5m87xx_i2c_init(void)
|
||||
{
|
||||
return i2c_add_driver(&s5m87xx_i2c_driver);
|
||||
}
|
||||
|
||||
subsys_initcall(s5m87xx_i2c_init);
|
||||
|
||||
static void __exit s5m87xx_i2c_exit(void)
|
||||
{
|
||||
i2c_del_driver(&s5m87xx_i2c_driver);
|
||||
}
|
||||
module_exit(s5m87xx_i2c_exit);
|
||||
|
||||
MODULE_AUTHOR("Sangbeom Kim <[email protected]>");
|
||||
MODULE_DESCRIPTION("Core support for the S5M MFD");
|
||||
MODULE_LICENSE("GPL");
|
||||
487
drivers/mfd/s5m-irq.c
Normal file
487
drivers/mfd/s5m-irq.c
Normal file
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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, },
|
||||
};
|
||||
|
|
|
|||
109
drivers/mfd/stmpe-i2c.c
Normal file
109
drivers/mfd/stmpe-i2c.c
Normal file
|
|
@ -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 <[email protected]>");
|
||||
150
drivers/mfd/stmpe-spi.c
Normal file
150
drivers/mfd/stmpe-spi.c
Normal file
|
|
@ -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 <[email protected]>");
|
||||
|
|
@ -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)
|
||||
/* Called from client specific probe routines */
|
||||
int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 = {
|
||||
static int stmpe_suspend(struct device *dev)
|
||||
{
|
||||
struct stmpe *stmpe = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(stmpe->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmpe_resume(struct device *dev)
|
||||
{
|
||||
struct stmpe *stmpe = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(stmpe->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct dev_pm_ops stmpe_dev_pm_ops = {
|
||||
.suspend = stmpe_suspend,
|
||||
.resume = stmpe_resume,
|
||||
};
|
||||
#endif
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
static int __init stmpe_init(void)
|
||||
{
|
||||
return i2c_add_driver(&stmpe_driver);
|
||||
}
|
||||
subsys_initcall(stmpe_init);
|
||||
|
||||
static void __exit stmpe_exit(void)
|
||||
{
|
||||
i2c_del_driver(&stmpe_driver);
|
||||
}
|
||||
module_exit(stmpe_exit);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("STMPE MFD core driver");
|
||||
MODULE_AUTHOR("Rabin Vincent <[email protected]>");
|
||||
|
|
|
|||
|
|
@ -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,10 +75,54 @@ 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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -172,15 +172,12 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
|
|||
|
||||
tps65910_gpio_init(tps65910, pmic_plat_data->gpio_base);
|
||||
|
||||
ret = tps65910_irq_init(tps65910, init_data->irq, init_data);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
tps65910_irq_init(tps65910, init_data->irq, init_data);
|
||||
|
||||
kfree(init_data);
|
||||
return ret;
|
||||
|
||||
err:
|
||||
mfd_remove_devices(tps65910->dev);
|
||||
kfree(tps65910);
|
||||
kfree(init_data);
|
||||
return ret;
|
||||
|
|
@ -190,8 +187,8 @@ static int tps65910_i2c_remove(struct i2c_client *i2c)
|
|||
{
|
||||
struct tps65910 *tps65910 = i2c_get_clientdata(i2c);
|
||||
|
||||
mfd_remove_devices(tps65910->dev);
|
||||
tps65910_irq_exit(tps65910);
|
||||
mfd_remove_devices(tps65910->dev);
|
||||
kfree(tps65910);
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -34,6 +34,11 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/irqdomain.h>
|
||||
|
||||
#include <linux/regulator/machine.h>
|
||||
|
||||
|
|
@ -144,6 +149,9 @@
|
|||
|
||||
#define TWL_MODULE_LAST TWL4030_MODULE_LAST
|
||||
|
||||
#define TWL4030_NR_IRQS 8
|
||||
#define TWL6030_NR_IRQS 20
|
||||
|
||||
/* Base Address defns for twl4030_map[] */
|
||||
|
||||
/* subchip/slave 0 - USB ID */
|
||||
|
|
@ -255,6 +263,7 @@ struct twl_client {
|
|||
|
||||
static struct twl_client twl_modules[TWL_NUM_SLAVES];
|
||||
|
||||
static struct irq_domain domain;
|
||||
|
||||
/* mapping the module id to slave id and base address */
|
||||
struct twl_mapping {
|
||||
|
|
@ -1183,14 +1192,48 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
int status;
|
||||
unsigned i;
|
||||
struct twl4030_platform_data *pdata = client->dev.platform_data;
|
||||
struct device_node *node = client->dev.of_node;
|
||||
u8 temp;
|
||||
int ret = 0;
|
||||
int nr_irqs = TWL4030_NR_IRQS;
|
||||
|
||||
if ((id->driver_data) & TWL6030_CLASS)
|
||||
nr_irqs = TWL6030_NR_IRQS;
|
||||
|
||||
if (node && !pdata) {
|
||||
/*
|
||||
* XXX: Temporary pdata until the information is correctly
|
||||
* retrieved by every TWL modules from DT.
|
||||
*/
|
||||
pdata = devm_kzalloc(&client->dev,
|
||||
sizeof(struct twl4030_platform_data),
|
||||
GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!pdata) {
|
||||
dev_dbg(&client->dev, "no platform data?\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
status = irq_alloc_descs(-1, pdata->irq_base, nr_irqs, 0);
|
||||
if (IS_ERR_VALUE(status)) {
|
||||
dev_err(&client->dev, "Fail to allocate IRQ descs\n");
|
||||
return status;
|
||||
}
|
||||
|
||||
pdata->irq_base = status;
|
||||
pdata->irq_end = pdata->irq_base + nr_irqs;
|
||||
|
||||
domain.irq_base = pdata->irq_base;
|
||||
domain.nr_irq = nr_irqs;
|
||||
#ifdef CONFIG_OF_IRQ
|
||||
domain.of_node = of_node_get(node);
|
||||
domain.ops = &irq_domain_simple_ops;
|
||||
#endif
|
||||
irq_domain_add(&domain);
|
||||
|
||||
if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
|
||||
dev_dbg(&client->dev, "can't talk I2C?\n");
|
||||
return -EIO;
|
||||
|
|
@ -1270,7 +1313,13 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
|
||||
}
|
||||
|
||||
status = add_children(pdata, id->driver_data);
|
||||
#ifdef CONFIG_OF_DEVICE
|
||||
if (node)
|
||||
status = of_platform_populate(node, NULL, NULL, &client->dev);
|
||||
else
|
||||
#endif
|
||||
status = add_children(pdata, id->driver_data);
|
||||
|
||||
fail:
|
||||
if (status < 0)
|
||||
twl_remove(client);
|
||||
|
|
|
|||
|
|
@ -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 <[email protected]>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -34,7 +34,8 @@
|
|||
static u8 twl4030_start_script_address = 0x2b;
|
||||
|
||||
#define PWR_P1_SW_EVENTS 0x10
|
||||
#define PWR_DEVOFF (1<<0)
|
||||
#define PWR_DEVOFF (1 << 0)
|
||||
#define SEQ_OFFSYNC (1 << 0)
|
||||
|
||||
#define PHY_TO_OFF_PM_MASTER(p) (p - 0x36)
|
||||
#define PHY_TO_OFF_PM_RECEIVER(p) (p - 0x5b)
|
||||
|
|
@ -511,12 +512,27 @@ int twl4030_remove_script(u8 flags)
|
|||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* In master mode, start the power off sequence.
|
||||
* After a successful execution, TWL shuts down the power to the SoC
|
||||
* and all peripherals connected to it.
|
||||
*/
|
||||
void twl4030_power_off(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, PWR_DEVOFF,
|
||||
TWL4030_PM_MASTER_P1_SW_EVENTS);
|
||||
if (err)
|
||||
pr_err("TWL4030 Unable to power off\n");
|
||||
}
|
||||
|
||||
void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
|
||||
{
|
||||
int err = 0;
|
||||
int i;
|
||||
struct twl4030_resconfig *resconfig;
|
||||
u8 address = twl4030_start_script_address;
|
||||
u8 val, address = twl4030_start_script_address;
|
||||
|
||||
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
|
||||
TWL4030_PM_MASTER_KEY_CFG1,
|
||||
|
|
@ -548,6 +564,28 @@ void __init twl4030_power_init(struct twl4030_power_data *twl4030_scripts)
|
|||
}
|
||||
}
|
||||
|
||||
/* Board has to be wired properly to use this feature */
|
||||
if (twl4030_scripts->use_poweroff && !pm_power_off) {
|
||||
/* Default for SEQ_OFFSYNC is set, lets ensure this */
|
||||
err = twl_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val,
|
||||
TWL4030_PM_MASTER_CFG_P123_TRANSITION);
|
||||
if (err) {
|
||||
pr_warning("TWL4030 Unable to read registers\n");
|
||||
|
||||
} else if (!(val & SEQ_OFFSYNC)) {
|
||||
val |= SEQ_OFFSYNC;
|
||||
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val,
|
||||
TWL4030_PM_MASTER_CFG_P123_TRANSITION);
|
||||
if (err) {
|
||||
pr_err("TWL4030 Unable to setup SEQ_OFFSYNC\n");
|
||||
goto relock;
|
||||
}
|
||||
}
|
||||
|
||||
pm_power_off = twl4030_power_off;
|
||||
}
|
||||
|
||||
relock:
|
||||
err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0,
|
||||
TWL4030_PM_MASTER_PROTECT_KEY);
|
||||
if (err)
|
||||
|
|
|
|||
|
|
@ -509,13 +509,10 @@ static int __devinit twl6040_probe(struct platform_device *pdev)
|
|||
twl6040->audpwron = -EINVAL;
|
||||
|
||||
if (gpio_is_valid(twl6040->audpwron)) {
|
||||
ret = gpio_request(twl6040->audpwron, "audpwron");
|
||||
ret = gpio_request_one(twl6040->audpwron, GPIOF_OUT_INIT_LOW,
|
||||
"audpwron");
|
||||
if (ret)
|
||||
goto gpio1_err;
|
||||
|
||||
ret = gpio_direction_output(twl6040->audpwron, 0);
|
||||
if (ret)
|
||||
goto gpio2_err;
|
||||
}
|
||||
|
||||
/* codec interrupt */
|
||||
|
|
@ -619,18 +616,7 @@ static struct platform_driver twl6040_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
static int __devinit twl6040_init(void)
|
||||
{
|
||||
return platform_driver_register(&twl6040_driver);
|
||||
}
|
||||
module_init(twl6040_init);
|
||||
|
||||
static void __devexit twl6040_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&twl6040_driver);
|
||||
}
|
||||
|
||||
module_exit(twl6040_exit);
|
||||
module_platform_driver(twl6040_driver);
|
||||
|
||||
MODULE_DESCRIPTION("TWL6040 MFD");
|
||||
MODULE_AUTHOR("Misael Lopez Cruz <[email protected]>");
|
||||
|
|
|
|||
|
|
@ -36,6 +36,15 @@ static DEFINE_MUTEX(ucb1x00_mutex);
|
|||
static LIST_HEAD(ucb1x00_drivers);
|
||||
static LIST_HEAD(ucb1x00_devices);
|
||||
|
||||
static struct mcp_device_id ucb1x00_id[] = {
|
||||
{ "ucb1x00", 0 }, /* auto-detection */
|
||||
{ "ucb1200", UCB_ID_1200 },
|
||||
{ "ucb1300", UCB_ID_1300 },
|
||||
{ "tc35143", UCB_ID_TC35143 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(mcp, ucb1x00_id);
|
||||
|
||||
/**
|
||||
* ucb1x00_io_set_dir - set IO direction
|
||||
* @ucb: UCB1x00 structure describing chip
|
||||
|
|
@ -527,17 +536,33 @@ static struct class ucb1x00_class = {
|
|||
|
||||
static int ucb1x00_probe(struct mcp *mcp)
|
||||
{
|
||||
const struct mcp_device_id *mid;
|
||||
struct ucb1x00 *ucb;
|
||||
struct ucb1x00_driver *drv;
|
||||
struct ucb1x00_plat_data *pdata;
|
||||
unsigned int id;
|
||||
int ret = -ENODEV;
|
||||
int temp;
|
||||
|
||||
mcp_enable(mcp);
|
||||
id = mcp_reg_read(mcp, UCB_ID);
|
||||
mid = mcp_get_device_id(mcp);
|
||||
|
||||
if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) {
|
||||
printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id);
|
||||
if (mid && mid->driver_data) {
|
||||
if (id != mid->driver_data) {
|
||||
printk(KERN_WARNING "%s wrong ID %04x found: %04x\n",
|
||||
mid->name, (unsigned int) mid->driver_data, id);
|
||||
goto err_disable;
|
||||
}
|
||||
} else {
|
||||
mid = &ucb1x00_id[1];
|
||||
while (mid->driver_data) {
|
||||
if (id == mid->driver_data)
|
||||
break;
|
||||
mid++;
|
||||
}
|
||||
printk(KERN_WARNING "%s ID not found: %04x\n",
|
||||
ucb1x00_id[0].name, id);
|
||||
goto err_disable;
|
||||
}
|
||||
|
||||
|
|
@ -546,28 +571,28 @@ static int ucb1x00_probe(struct mcp *mcp)
|
|||
if (!ucb)
|
||||
goto err_disable;
|
||||
|
||||
|
||||
pdata = mcp->attached_device.platform_data;
|
||||
ucb->dev.class = &ucb1x00_class;
|
||||
ucb->dev.parent = &mcp->attached_device;
|
||||
dev_set_name(&ucb->dev, "ucb1x00");
|
||||
dev_set_name(&ucb->dev, mid->name);
|
||||
|
||||
spin_lock_init(&ucb->lock);
|
||||
spin_lock_init(&ucb->io_lock);
|
||||
sema_init(&ucb->adc_sem, 1);
|
||||
|
||||
ucb->id = id;
|
||||
ucb->id = mid;
|
||||
ucb->mcp = mcp;
|
||||
ucb->irq = ucb1x00_detect_irq(ucb);
|
||||
if (ucb->irq == NO_IRQ) {
|
||||
printk(KERN_ERR "UCB1x00: IRQ probe failed\n");
|
||||
printk(KERN_ERR "%s: IRQ probe failed\n", mid->name);
|
||||
ret = -ENODEV;
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
ucb->gpio.base = -1;
|
||||
if (mcp->gpio_base != 0) {
|
||||
if (pdata && (pdata->gpio_base >= 0)) {
|
||||
ucb->gpio.label = dev_name(&ucb->dev);
|
||||
ucb->gpio.base = mcp->gpio_base;
|
||||
ucb->gpio.base = pdata->gpio_base;
|
||||
ucb->gpio.ngpio = 10;
|
||||
ucb->gpio.set = ucb1x00_gpio_set;
|
||||
ucb->gpio.get = ucb1x00_gpio_get;
|
||||
|
|
@ -580,10 +605,10 @@ static int ucb1x00_probe(struct mcp *mcp)
|
|||
dev_info(&ucb->dev, "gpio_base not set so no gpiolib support");
|
||||
|
||||
ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING,
|
||||
"UCB1x00", ucb);
|
||||
mid->name, ucb);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
|
||||
ucb->irq, ret);
|
||||
printk(KERN_ERR "%s: unable to grab irq%d: %d\n",
|
||||
mid->name, ucb->irq, ret);
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
|
|
@ -705,6 +730,7 @@ static struct mcp_driver ucb1x00_driver = {
|
|||
.remove = ucb1x00_remove,
|
||||
.suspend = ucb1x00_suspend,
|
||||
.resume = ucb1x00_resume,
|
||||
.id_table = ucb1x00_id,
|
||||
};
|
||||
|
||||
static int __init ucb1x00_init(void)
|
||||
|
|
|
|||
|
|
@ -382,7 +382,7 @@ static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
|
|||
ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
|
||||
|
||||
idev->name = "Touchscreen panel";
|
||||
idev->id.product = ts->ucb->id;
|
||||
idev->id.product = ts->ucb->id->driver_data;
|
||||
idev->open = ucb1x00_ts_open;
|
||||
idev->close = ucb1x00_ts_close;
|
||||
|
||||
|
|
|
|||
|
|
@ -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, }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue