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: (40 commits)
  mfd: Fix incorrect kfree(i2c) in wm8994-core i2c_driver probe
  mfd: Fix incorrect kfree(i2c) in wm831x-core i2c_driver probe
  mfd: Fix incorrect kfree(i2c) in tps6507x i2c_driver probe
  mfd: Add TPS6586x driver
  mfd: Use macros instead of some constant magic numbers for menelaus
  mfd: Fix menelaus mmc slot 2 misconfiguration
  mfd: Missing slab.h includes
  mfd: Fix wrong wm8350-core kfree in error path
  mfd: Fix wm8994_device_init() return value
  mfd: Avoid calling platform_device_put() twice in ucb1400 probe error path
  mfd: Annotate tc6387xb probe/remove routines with __devinit/__devexit
  mfd: Fix tc6387xb resource reclaim
  mfd: Fix wrong goto labels for tc6393xb error handling
  mfd: Get rid of now unused mc13783 private header
  hwmon: Don't access struct mc13783 directly from mc13783-adc
  mfd: New mc13783 function exposing flags
  mfd: Check jz4740-adc kmalloc() result
  mfd: Fix jz4740-adc resource reclaim in probe error path
  mfd: Add WM8321 support
  mfd: Add stmpe auto sleep feature
  ...
This commit is contained in:
Linus Torvalds 2010-08-12 10:01:06 -07:00
commit e83ddb3354
43 changed files with 3933 additions and 339 deletions

View File

@ -206,6 +206,13 @@ config GPIO_SX150X
8 bits: sx1508q
16 bits: sx1509q
config GPIO_STMPE
bool "STMPE GPIOs"
depends on MFD_STMPE
help
This enables support for the GPIOs found on the STMPE I/O
Expanders.
config GPIO_TC35892
bool "TC35892 GPIOs"
depends on MFD_TC35892

View File

@ -20,6 +20,7 @@ obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o
obj-$(CONFIG_GPIO_PCA953X) += pca953x.o
obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o
obj-$(CONFIG_GPIO_PL061) += pl061.o
obj-$(CONFIG_GPIO_STMPE) += stmpe-gpio.o
obj-$(CONFIG_GPIO_TC35892) += tc35892-gpio.o
obj-$(CONFIG_GPIO_TIMBERDALE) += timbgpio.o
obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o

399
drivers/gpio/stmpe-gpio.c Normal file
View File

@ -0,0 +1,399 @@
/*
* 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/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/mfd/stmpe.h>
/*
* These registers are modified under the irq bus lock and cached to avoid
* unnecessary writes in bus_sync_unlock.
*/
enum { REG_RE, REG_FE, REG_IE };
#define CACHE_NR_REGS 3
#define CACHE_NR_BANKS (STMPE_NR_GPIOS / 8)
struct stmpe_gpio {
struct gpio_chip chip;
struct stmpe *stmpe;
struct device *dev;
struct mutex irq_lock;
int irq_base;
/* Caches of interrupt control registers for bus_lock */
u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
};
static inline struct stmpe_gpio *to_stmpe_gpio(struct gpio_chip *chip)
{
return container_of(chip, struct stmpe_gpio, chip);
}
static int stmpe_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
struct stmpe *stmpe = stmpe_gpio->stmpe;
u8 reg = stmpe->regs[STMPE_IDX_GPMR_LSB] - (offset / 8);
u8 mask = 1 << (offset % 8);
int ret;
ret = stmpe_reg_read(stmpe, reg);
if (ret < 0)
return ret;
return ret & mask;
}
static void stmpe_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
{
struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
struct stmpe *stmpe = stmpe_gpio->stmpe;
int which = val ? STMPE_IDX_GPSR_LSB : STMPE_IDX_GPCR_LSB;
u8 reg = stmpe->regs[which] - (offset / 8);
u8 mask = 1 << (offset % 8);
stmpe_reg_write(stmpe, reg, mask);
}
static int stmpe_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int val)
{
struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
struct stmpe *stmpe = stmpe_gpio->stmpe;
u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
u8 mask = 1 << (offset % 8);
stmpe_gpio_set(chip, offset, val);
return stmpe_set_bits(stmpe, reg, mask, mask);
}
static int stmpe_gpio_direction_input(struct gpio_chip *chip,
unsigned offset)
{
struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
struct stmpe *stmpe = stmpe_gpio->stmpe;
u8 reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8);
u8 mask = 1 << (offset % 8);
return stmpe_set_bits(stmpe, reg, mask, 0);
}
static int stmpe_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
return stmpe_gpio->irq_base + offset;
}
static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset)
{
struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip);
struct stmpe *stmpe = stmpe_gpio->stmpe;
return stmpe_set_altfunc(stmpe, 1 << offset, STMPE_BLOCK_GPIO);
}
static struct gpio_chip template_chip = {
.label = "stmpe",
.owner = THIS_MODULE,
.direction_input = stmpe_gpio_direction_input,
.get = stmpe_gpio_get,
.direction_output = stmpe_gpio_direction_output,
.set = stmpe_gpio_set,
.to_irq = stmpe_gpio_to_irq,
.request = stmpe_gpio_request,
.can_sleep = 1,
};
static int stmpe_gpio_irq_set_type(unsigned int irq, unsigned int type)
{
struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq);
int offset = irq - stmpe_gpio->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
return -EINVAL;
if (type == IRQ_TYPE_EDGE_RISING)
stmpe_gpio->regs[REG_RE][regoffset] |= mask;
else
stmpe_gpio->regs[REG_RE][regoffset] &= ~mask;
if (type == IRQ_TYPE_EDGE_FALLING)
stmpe_gpio->regs[REG_FE][regoffset] |= mask;
else
stmpe_gpio->regs[REG_FE][regoffset] &= ~mask;
return 0;
}
static void stmpe_gpio_irq_lock(unsigned int irq)
{
struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq);
mutex_lock(&stmpe_gpio->irq_lock);
}
static void stmpe_gpio_irq_sync_unlock(unsigned int irq)
{
struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq);
struct stmpe *stmpe = stmpe_gpio->stmpe;
int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
static const u8 regmap[] = {
[REG_RE] = STMPE_IDX_GPRER_LSB,
[REG_FE] = STMPE_IDX_GPFER_LSB,
[REG_IE] = STMPE_IDX_IEGPIOR_LSB,
};
int i, j;
for (i = 0; i < CACHE_NR_REGS; i++) {
for (j = 0; j < num_banks; j++) {
u8 old = stmpe_gpio->oldregs[i][j];
u8 new = stmpe_gpio->regs[i][j];
if (new == old)
continue;
stmpe_gpio->oldregs[i][j] = new;
stmpe_reg_write(stmpe, stmpe->regs[regmap[i]] - j, new);
}
}
mutex_unlock(&stmpe_gpio->irq_lock);
}
static void stmpe_gpio_irq_mask(unsigned int irq)
{
struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq);
int offset = irq - stmpe_gpio->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
stmpe_gpio->regs[REG_IE][regoffset] &= ~mask;
}
static void stmpe_gpio_irq_unmask(unsigned int irq)
{
struct stmpe_gpio *stmpe_gpio = get_irq_chip_data(irq);
int offset = irq - stmpe_gpio->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
stmpe_gpio->regs[REG_IE][regoffset] |= mask;
}
static struct irq_chip stmpe_gpio_irq_chip = {
.name = "stmpe-gpio",
.bus_lock = stmpe_gpio_irq_lock,
.bus_sync_unlock = stmpe_gpio_irq_sync_unlock,
.mask = stmpe_gpio_irq_mask,
.unmask = stmpe_gpio_irq_unmask,
.set_type = stmpe_gpio_irq_set_type,
};
static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
{
struct stmpe_gpio *stmpe_gpio = dev;
struct stmpe *stmpe = stmpe_gpio->stmpe;
u8 statmsbreg = stmpe->regs[STMPE_IDX_ISGPIOR_MSB];
int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8);
u8 status[num_banks];
int ret;
int i;
ret = stmpe_block_read(stmpe, statmsbreg, num_banks, status);
if (ret < 0)
return IRQ_NONE;
for (i = 0; i < num_banks; i++) {
int bank = num_banks - i - 1;
unsigned int enabled = stmpe_gpio->regs[REG_IE][bank];
unsigned int stat = status[i];
stat &= enabled;
if (!stat)
continue;
while (stat) {
int bit = __ffs(stat);
int line = bank * 8 + bit;
handle_nested_irq(stmpe_gpio->irq_base + line);
stat &= ~(1 << bit);
}
stmpe_reg_write(stmpe, statmsbreg + i, status[i]);
stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_GPEDR_MSB] + i,
status[i]);
}
return IRQ_HANDLED;
}
static int __devinit stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio)
{
int base = stmpe_gpio->irq_base;
int irq;
for (irq = base; irq < base + stmpe_gpio->chip.ngpio; irq++) {
set_irq_chip_data(irq, stmpe_gpio);
set_irq_chip_and_handler(irq, &stmpe_gpio_irq_chip,
handle_simple_irq);
set_irq_nested_thread(irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
#else
set_irq_noprobe(irq);
#endif
}
return 0;
}
static void stmpe_gpio_irq_remove(struct stmpe_gpio *stmpe_gpio)
{
int base = stmpe_gpio->irq_base;
int irq;
for (irq = base; irq < base + stmpe_gpio->chip.ngpio; irq++) {
#ifdef CONFIG_ARM
set_irq_flags(irq, 0);
#endif
set_irq_chip_and_handler(irq, NULL, NULL);
set_irq_chip_data(irq, NULL);
}
}
static int __devinit stmpe_gpio_probe(struct platform_device *pdev)
{
struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
struct stmpe_gpio_platform_data *pdata;
struct stmpe_gpio *stmpe_gpio;
int ret;
int irq;
pdata = stmpe->pdata->gpio;
if (!pdata)
return -ENODEV;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL);
if (!stmpe_gpio)
return -ENOMEM;
mutex_init(&stmpe_gpio->irq_lock);
stmpe_gpio->dev = &pdev->dev;
stmpe_gpio->stmpe = stmpe;
stmpe_gpio->chip = template_chip;
stmpe_gpio->chip.ngpio = stmpe->num_gpios;
stmpe_gpio->chip.dev = &pdev->dev;
stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1;
stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0);
ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
if (ret)
return ret;
ret = stmpe_gpio_irq_init(stmpe_gpio);
if (ret)
goto out_free;
ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, IRQF_ONESHOT,
"stmpe-gpio", stmpe_gpio);
if (ret) {
dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
goto out_removeirq;
}
ret = gpiochip_add(&stmpe_gpio->chip);
if (ret) {
dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
goto out_freeirq;
}
if (pdata && pdata->setup)
pdata->setup(stmpe, stmpe_gpio->chip.base);
platform_set_drvdata(pdev, stmpe_gpio);
return 0;
out_freeirq:
free_irq(irq, stmpe_gpio);
out_removeirq:
stmpe_gpio_irq_remove(stmpe_gpio);
out_free:
kfree(stmpe_gpio);
return ret;
}
static int __devexit stmpe_gpio_remove(struct platform_device *pdev)
{
struct stmpe_gpio *stmpe_gpio = platform_get_drvdata(pdev);
struct stmpe *stmpe = stmpe_gpio->stmpe;
struct stmpe_gpio_platform_data *pdata = stmpe->pdata->gpio;
int irq = platform_get_irq(pdev, 0);
int ret;
if (pdata && pdata->remove)
pdata->remove(stmpe, stmpe_gpio->chip.base);
ret = gpiochip_remove(&stmpe_gpio->chip);
if (ret < 0) {
dev_err(stmpe_gpio->dev,
"unable to remove gpiochip: %d\n", ret);
return ret;
}
stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
free_irq(irq, stmpe_gpio);
stmpe_gpio_irq_remove(stmpe_gpio);
platform_set_drvdata(pdev, NULL);
kfree(stmpe_gpio);
return 0;
}
static struct platform_driver stmpe_gpio_driver = {
.driver.name = "stmpe-gpio",
.driver.owner = THIS_MODULE,
.probe = stmpe_gpio_probe,
.remove = __devexit_p(stmpe_gpio_remove),
};
static int __init stmpe_gpio_init(void)
{
return platform_driver_register(&stmpe_gpio_driver);
}
subsys_initcall(stmpe_gpio_init);
static void __exit stmpe_gpio_exit(void)
{
platform_driver_unregister(&stmpe_gpio_driver);
}
module_exit(stmpe_gpio_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("STMPExxxx GPIO driver");
MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>");

View File

@ -108,6 +108,37 @@ static int wm831x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
return wm831x->irq_base + WM831X_IRQ_GPIO_1 + offset;
}
static int wm831x_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
unsigned debounce)
{
struct wm831x_gpio *wm831x_gpio = to_wm831x_gpio(chip);
struct wm831x *wm831x = wm831x_gpio->wm831x;
int reg = WM831X_GPIO1_CONTROL + offset;
int ret, fn;
ret = wm831x_reg_read(wm831x, reg);
if (ret < 0)
return ret;
switch (ret & WM831X_GPN_FN_MASK) {
case 0:
case 1:
break;
default:
/* Not in GPIO mode */
return -EBUSY;
}
if (debounce >= 32 && debounce <= 64)
fn = 0;
else if (debounce >= 4000 && debounce <= 8000)
fn = 1;
else
return -EINVAL;
return wm831x_set_bits(wm831x, reg, WM831X_GPN_FN_MASK, fn);
}
#ifdef CONFIG_DEBUG_FS
static void wm831x_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
@ -208,6 +239,7 @@ static struct gpio_chip template_chip = {
.direction_output = wm831x_gpio_direction_out,
.set = wm831x_gpio_set,
.to_irq = wm831x_gpio_to_irq,
.set_debounce = wm831x_gpio_set_debounce,
.dbg_show = wm831x_gpio_dbg_show,
.can_sleep = 1,
};

View File

@ -18,7 +18,7 @@
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/mfd/mc13783-private.h>
#include <linux/mfd/mc13783.h>
#include <linux/platform_device.h>
#include <linux/hwmon-sysfs.h>
#include <linux/kernel.h>
@ -144,6 +144,14 @@ static const struct attribute_group mc13783_group_ts = {
.attrs = mc13783_attr_ts,
};
static int mc13783_adc_use_touchscreen(struct platform_device *pdev)
{
struct mc13783_adc_priv *priv = platform_get_drvdata(pdev);
unsigned flags = mc13783_get_flags(priv->mc13783);
return flags & MC13783_USE_TOUCHSCREEN;
}
static int __init mc13783_adc_probe(struct platform_device *pdev)
{
struct mc13783_adc_priv *priv;
@ -162,10 +170,11 @@ static int __init mc13783_adc_probe(struct platform_device *pdev)
if (ret)
goto out_err_create1;
if (!(priv->mc13783->flags & MC13783_USE_TOUCHSCREEN))
if (!mc13783_adc_use_touchscreen(pdev)) {
ret = sysfs_create_group(&pdev->dev.kobj, &mc13783_group_ts);
if (ret)
goto out_err_create2;
}
priv->hwmon_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(priv->hwmon_dev)) {
@ -180,7 +189,7 @@ static int __init mc13783_adc_probe(struct platform_device *pdev)
out_err_register:
if (!(priv->mc13783->flags & MC13783_USE_TOUCHSCREEN))
if (!mc13783_adc_use_touchscreen(pdev))
sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
out_err_create2:
@ -199,7 +208,7 @@ static int __devexit mc13783_adc_remove(struct platform_device *pdev)
hwmon_device_unregister(priv->hwmon_dev);
if (!(priv->mc13783->flags & MC13783_USE_TOUCHSCREEN))
if (!mc13783_adc_use_touchscreen(pdev))
sysfs_remove_group(&pdev->dev.kobj, &mc13783_group_ts);
sysfs_remove_group(&pdev->dev.kobj, &mc13783_group);

View File

@ -395,6 +395,16 @@ config KEYBOARD_SH_KEYSC
To compile this driver as a module, choose M here: the
module will be called sh_keysc.
config KEYBOARD_STMPE
tristate "STMPE keypad support"
depends on MFD_STMPE
help
Say Y here if you want to use the keypad controller on STMPE I/O
expanders.
To compile this driver as a module, choose M here: the module will be
called stmpe-keypad.
config KEYBOARD_DAVINCI
tristate "TI DaVinci Key Scan"
depends on ARCH_DAVINCI_DM365

View File

@ -35,6 +35,7 @@ obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o
obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o
obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o
obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o

View File

@ -0,0 +1,386 @@
/*
* 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/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/input/matrix_keypad.h>
#include <linux/mfd/stmpe.h>
/* These are at the same addresses in all STMPE variants */
#define STMPE_KPC_COL 0x60
#define STMPE_KPC_ROW_MSB 0x61
#define STMPE_KPC_ROW_LSB 0x62
#define STMPE_KPC_CTRL_MSB 0x63
#define STMPE_KPC_CTRL_LSB 0x64
#define STMPE_KPC_COMBI_KEY_0 0x65
#define STMPE_KPC_COMBI_KEY_1 0x66
#define STMPE_KPC_COMBI_KEY_2 0x67
#define STMPE_KPC_DATA_BYTE0 0x68
#define STMPE_KPC_DATA_BYTE1 0x69
#define STMPE_KPC_DATA_BYTE2 0x6a
#define STMPE_KPC_DATA_BYTE3 0x6b
#define STMPE_KPC_DATA_BYTE4 0x6c
#define STMPE_KPC_CTRL_LSB_SCAN (0x1 << 0)
#define STMPE_KPC_CTRL_LSB_DEBOUNCE (0x7f << 1)
#define STMPE_KPC_CTRL_MSB_SCAN_COUNT (0xf << 4)
#define STMPE_KPC_ROW_MSB_ROWS 0xff
#define STMPE_KPC_DATA_UP (0x1 << 7)
#define STMPE_KPC_DATA_ROW (0xf << 3)
#define STMPE_KPC_DATA_COL (0x7 << 0)
#define STMPE_KPC_DATA_NOKEY_MASK 0x78
#define STMPE_KEYPAD_MAX_DEBOUNCE 127
#define STMPE_KEYPAD_MAX_SCAN_COUNT 15
#define STMPE_KEYPAD_MAX_ROWS 8
#define STMPE_KEYPAD_MAX_COLS 8
#define STMPE_KEYPAD_ROW_SHIFT 3
#define STMPE_KEYPAD_KEYMAP_SIZE \
(STMPE_KEYPAD_MAX_ROWS * STMPE_KEYPAD_MAX_COLS)
/**
* struct stmpe_keypad_variant - model-specific attributes
* @auto_increment: whether the KPC_DATA_BYTE register address
* auto-increments on multiple read
* @num_data: number of data bytes
* @num_normal_data: number of normal keys' data bytes
* @max_cols: maximum number of columns supported
* @max_rows: maximum number of rows supported
* @col_gpios: bitmask of gpios which can be used for columns
* @row_gpios: bitmask of gpios which can be used for rows
*/
struct stmpe_keypad_variant {
bool auto_increment;
int num_data;
int num_normal_data;
int max_cols;
int max_rows;
unsigned int col_gpios;
unsigned int row_gpios;
};
static const struct stmpe_keypad_variant stmpe_keypad_variants[] = {
[STMPE1601] = {
.auto_increment = true,
.num_data = 5,
.num_normal_data = 3,
.max_cols = 8,
.max_rows = 8,
.col_gpios = 0x000ff, /* GPIO 0 - 7 */
.row_gpios = 0x0ff00, /* GPIO 8 - 15 */
},
[STMPE2401] = {
.auto_increment = false,
.num_data = 3,
.num_normal_data = 2,
.max_cols = 8,
.max_rows = 12,
.col_gpios = 0x0000ff, /* GPIO 0 - 7*/
.row_gpios = 0x1fef00, /* GPIO 8-14, 16-20 */
},
[STMPE2403] = {
.auto_increment = true,
.num_data = 5,
.num_normal_data = 3,
.max_cols = 8,
.max_rows = 12,
.col_gpios = 0x0000ff, /* GPIO 0 - 7*/
.row_gpios = 0x1fef00, /* GPIO 8-14, 16-20 */
},
};
struct stmpe_keypad {
struct stmpe *stmpe;
struct input_dev *input;
const struct stmpe_keypad_variant *variant;
const struct stmpe_keypad_platform_data *plat;
unsigned int rows;
unsigned int cols;
unsigned short keymap[STMPE_KEYPAD_KEYMAP_SIZE];
};
static int stmpe_keypad_read_data(struct stmpe_keypad *keypad, u8 *data)
{
const struct stmpe_keypad_variant *variant = keypad->variant;
struct stmpe *stmpe = keypad->stmpe;
int ret;
int i;
if (variant->auto_increment)
return stmpe_block_read(stmpe, STMPE_KPC_DATA_BYTE0,
variant->num_data, data);
for (i = 0; i < variant->num_data; i++) {
ret = stmpe_reg_read(stmpe, STMPE_KPC_DATA_BYTE0 + i);
if (ret < 0)
return ret;
data[i] = ret;
}
return 0;
}
static irqreturn_t stmpe_keypad_irq(int irq, void *dev)
{
struct stmpe_keypad *keypad = dev;
struct input_dev *input = keypad->input;
const struct stmpe_keypad_variant *variant = keypad->variant;
u8 fifo[variant->num_data];
int ret;
int i;
ret = stmpe_keypad_read_data(keypad, fifo);
if (ret < 0)
return IRQ_NONE;
for (i = 0; i < variant->num_normal_data; i++) {
u8 data = fifo[i];
int row = (data & STMPE_KPC_DATA_ROW) >> 3;
int col = data & STMPE_KPC_DATA_COL;
int code = MATRIX_SCAN_CODE(row, col, STMPE_KEYPAD_ROW_SHIFT);
bool up = data & STMPE_KPC_DATA_UP;
if ((data & STMPE_KPC_DATA_NOKEY_MASK)
== STMPE_KPC_DATA_NOKEY_MASK)
continue;
input_event(input, EV_MSC, MSC_SCAN, code);
input_report_key(input, keypad->keymap[code], !up);
input_sync(input);
}
return IRQ_HANDLED;
}
static int __devinit stmpe_keypad_altfunc_init(struct stmpe_keypad *keypad)
{
const struct stmpe_keypad_variant *variant = keypad->variant;
unsigned int col_gpios = variant->col_gpios;
unsigned int row_gpios = variant->row_gpios;
struct stmpe *stmpe = keypad->stmpe;
unsigned int pins = 0;
int i;
/*
* Figure out which pins need to be set to the keypad alternate
* function.
*
* {cols,rows}_gpios are bitmasks of which pins on the chip can be used
* for the keypad.
*
* keypad->{cols,rows} are a bitmask of which pins (of the ones useable
* for the keypad) are used on the board.
*/
for (i = 0; i < variant->max_cols; i++) {
int num = __ffs(col_gpios);
if (keypad->cols & (1 << i))
pins |= 1 << num;
col_gpios &= ~(1 << num);
}
for (i = 0; i < variant->max_rows; i++) {
int num = __ffs(row_gpios);
if (keypad->rows & (1 << i))
pins |= 1 << num;
row_gpios &= ~(1 << num);
}
return stmpe_set_altfunc(stmpe, pins, STMPE_BLOCK_KEYPAD);
}
static int __devinit stmpe_keypad_chip_init(struct stmpe_keypad *keypad)
{
const struct stmpe_keypad_platform_data *plat = keypad->plat;
const struct stmpe_keypad_variant *variant = keypad->variant;
struct stmpe *stmpe = keypad->stmpe;
int ret;
if (plat->debounce_ms > STMPE_KEYPAD_MAX_DEBOUNCE)
return -EINVAL;
if (plat->scan_count > STMPE_KEYPAD_MAX_SCAN_COUNT)
return -EINVAL;
ret = stmpe_enable(stmpe, STMPE_BLOCK_KEYPAD);
if (ret < 0)
return ret;
ret = stmpe_keypad_altfunc_init(keypad);
if (ret < 0)
return ret;
ret = stmpe_reg_write(stmpe, STMPE_KPC_COL, keypad->cols);
if (ret < 0)
return ret;
ret = stmpe_reg_write(stmpe, STMPE_KPC_ROW_LSB, keypad->rows);
if (ret < 0)
return ret;
if (variant->max_rows > 8) {
ret = stmpe_set_bits(stmpe, STMPE_KPC_ROW_MSB,
STMPE_KPC_ROW_MSB_ROWS,
keypad->rows >> 8);
if (ret < 0)
return ret;
}
ret = stmpe_set_bits(stmpe, STMPE_KPC_CTRL_MSB,
STMPE_KPC_CTRL_MSB_SCAN_COUNT,
plat->scan_count << 4);
if (ret < 0)
return ret;
return stmpe_set_bits(stmpe, STMPE_KPC_CTRL_LSB,
STMPE_KPC_CTRL_LSB_SCAN |
STMPE_KPC_CTRL_LSB_DEBOUNCE,
STMPE_KPC_CTRL_LSB_SCAN |
(plat->debounce_ms << 1));
}
static int __devinit stmpe_keypad_probe(struct platform_device *pdev)
{
struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
struct stmpe_keypad_platform_data *plat;
struct stmpe_keypad *keypad;
struct input_dev *input;
int ret;
int irq;
int i;
plat = stmpe->pdata->keypad;
if (!plat)
return -ENODEV;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
keypad = kzalloc(sizeof(struct stmpe_keypad), GFP_KERNEL);
if (!keypad)
return -ENOMEM;
input = input_allocate_device();
if (!input) {
ret = -ENOMEM;
goto out_freekeypad;
}
input->name = "STMPE keypad";
input->id.bustype = BUS_I2C;
input->dev.parent = &pdev->dev;
input_set_capability(input, EV_MSC, MSC_SCAN);
__set_bit(EV_KEY, input->evbit);
if (!plat->no_autorepeat)
__set_bit(EV_REP, input->evbit);
input->keycode = keypad->keymap;
input->keycodesize = sizeof(keypad->keymap[0]);
input->keycodemax = ARRAY_SIZE(keypad->keymap);
matrix_keypad_build_keymap(plat->keymap_data, STMPE_KEYPAD_ROW_SHIFT,
input->keycode, input->keybit);
for (i = 0; i < plat->keymap_data->keymap_size; i++) {
unsigned int key = plat->keymap_data->keymap[i];
keypad->cols |= 1 << KEY_COL(key);
keypad->rows |= 1 << KEY_ROW(key);
}
keypad->stmpe = stmpe;
keypad->plat = plat;
keypad->input = input;
keypad->variant = &stmpe_keypad_variants[stmpe->partnum];
ret = stmpe_keypad_chip_init(keypad);
if (ret < 0)
goto out_freeinput;
ret = input_register_device(input);
if (ret) {
dev_err(&pdev->dev,
"unable to register input device: %d\n", ret);
goto out_freeinput;
}
ret = request_threaded_irq(irq, NULL, stmpe_keypad_irq, IRQF_ONESHOT,
"stmpe-keypad", keypad);
if (ret) {
dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
goto out_unregisterinput;
}
platform_set_drvdata(pdev, keypad);
return 0;
out_unregisterinput:
input_unregister_device(input);
input = NULL;
out_freeinput:
input_free_device(input);
out_freekeypad:
kfree(keypad);
return ret;
}
static int __devexit stmpe_keypad_remove(struct platform_device *pdev)
{
struct stmpe_keypad *keypad = platform_get_drvdata(pdev);
struct stmpe *stmpe = keypad->stmpe;
int irq = platform_get_irq(pdev, 0);
stmpe_disable(stmpe, STMPE_BLOCK_KEYPAD);
free_irq(irq, keypad);
input_unregister_device(keypad->input);
platform_set_drvdata(pdev, NULL);
kfree(keypad);
return 0;
}
static struct platform_driver stmpe_keypad_driver = {
.driver.name = "stmpe-keypad",
.driver.owner = THIS_MODULE,
.probe = stmpe_keypad_probe,
.remove = __devexit_p(stmpe_keypad_remove),
};
static int __init stmpe_keypad_init(void)
{
return platform_driver_register(&stmpe_keypad_driver);
}
module_init(stmpe_keypad_init);
static void __exit stmpe_keypad_exit(void)
{
platform_driver_unregister(&stmpe_keypad_driver);
}
module_exit(stmpe_keypad_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("STMPExxxx keypad driver");
MODULE_AUTHOR("Rabin Vincent <rabin.vincent@stericsson.com>");

View File

@ -628,4 +628,14 @@ config TOUCHSCREEN_TPS6507X
To compile this driver as a module, choose M here: the
module will be called tps6507x_ts.
config TOUCHSCREEN_STMPE
tristate "STMicroelectronics STMPE touchscreens"
depends on MFD_STMPE
help
Say Y here if you want support for STMicroelectronics
STMPE touchscreen controllers.
To compile this driver as a module, choose M here: the
module will be called stmpe-ts.
endif

View File

@ -36,6 +36,7 @@ obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
obj-$(CONFIG_TOUCHSCREEN_QT602240) += qt602240_ts.o
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o

View File

@ -0,0 +1,397 @@
/* STMicroelectronics STMPE811 Touchscreen Driver
*
* (C) 2010 Luotao Fu <l.fu@pengutronix.de>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>
#include <linux/mfd/stmpe.h>
/* Register layouts and functionalities are identical on all stmpexxx variants
* with touchscreen controller
*/
#define STMPE_REG_INT_STA 0x0B
#define STMPE_REG_ADC_CTRL1 0x20
#define STMPE_REG_ADC_CTRL2 0x21
#define STMPE_REG_TSC_CTRL 0x40
#define STMPE_REG_TSC_CFG 0x41
#define STMPE_REG_FIFO_TH 0x4A
#define STMPE_REG_FIFO_STA 0x4B
#define STMPE_REG_FIFO_SIZE 0x4C
#define STMPE_REG_TSC_DATA_XYZ 0x52
#define STMPE_REG_TSC_FRACTION_Z 0x56
#define STMPE_REG_TSC_I_DRIVE 0x58
#define OP_MOD_XYZ 0
#define STMPE_TSC_CTRL_TSC_EN (1<<0)
#define STMPE_FIFO_STA_RESET (1<<0)
#define STMPE_IRQ_TOUCH_DET 0
#define SAMPLE_TIME(x) ((x & 0xf) << 4)
#define MOD_12B(x) ((x & 0x1) << 3)
#define REF_SEL(x) ((x & 0x1) << 1)
#define ADC_FREQ(x) (x & 0x3)
#define AVE_CTRL(x) ((x & 0x3) << 6)
#define DET_DELAY(x) ((x & 0x7) << 3)
#define SETTLING(x) (x & 0x7)
#define FRACTION_Z(x) (x & 0x7)
#define I_DRIVE(x) (x & 0x1)
#define OP_MODE(x) ((x & 0x7) << 1)
#define STMPE_TS_NAME "stmpe-ts"
#define XY_MASK 0xfff
struct stmpe_touch {
struct stmpe *stmpe;
struct input_dev *idev;
struct delayed_work work;
struct device *dev;
u8 sample_time;
u8 mod_12b;
u8 ref_sel;
u8 adc_freq;
u8 ave_ctrl;
u8 touch_det_delay;
u8 settling;
u8 fraction_z;
u8 i_drive;
};
static int __stmpe_reset_fifo(struct stmpe *stmpe)
{
int ret;
ret = stmpe_set_bits(stmpe, STMPE_REG_FIFO_STA,
STMPE_FIFO_STA_RESET, STMPE_FIFO_STA_RESET);
if (ret)
return ret;
return stmpe_set_bits(stmpe, STMPE_REG_FIFO_STA,
STMPE_FIFO_STA_RESET, 0);
}
static void stmpe_work(struct work_struct *work)
{
int int_sta;
u32 timeout = 40;
struct stmpe_touch *ts =
container_of(work, struct stmpe_touch, work.work);
int_sta = stmpe_reg_read(ts->stmpe, STMPE_REG_INT_STA);
/*
* touch_det sometimes get desasserted or just get stuck. This appears
* to be a silicon bug, We still have to clearify this with the
* manufacture. As a workaround We release the key anyway if the
* touch_det keeps coming in after 4ms, while the FIFO contains no value
* during the whole time.
*/
while ((int_sta & (1 << STMPE_IRQ_TOUCH_DET)) && (timeout > 0)) {
timeout--;
int_sta = stmpe_reg_read(ts->stmpe, STMPE_REG_INT_STA);
udelay(100);
}
/* reset the FIFO before we report release event */
__stmpe_reset_fifo(ts->stmpe);
input_report_abs(ts->idev, ABS_PRESSURE, 0);
input_sync(ts->idev);
}
static irqreturn_t stmpe_ts_handler(int irq, void *data)
{
u8 data_set[4];
int x, y, z;
struct stmpe_touch *ts = data;
/*
* Cancel scheduled polling for release if we have new value
* available. Wait if the polling is already running.
*/
cancel_delayed_work_sync(&ts->work);
/*
* The FIFO sometimes just crashes and stops generating interrupts. This
* appears to be a silicon bug. We still have to clearify this with
* the manufacture. As a workaround we disable the TSC while we are
* collecting data and flush the FIFO after reading
*/
stmpe_set_bits(ts->stmpe, STMPE_REG_TSC_CTRL,
STMPE_TSC_CTRL_TSC_EN, 0);
stmpe_block_read(ts->stmpe, STMPE_REG_TSC_DATA_XYZ, 4, data_set);
x = (data_set[0] << 4) | (data_set[1] >> 4);
y = ((data_set[1] & 0xf) << 8) | data_set[2];
z = data_set[3];
input_report_abs(ts->idev, ABS_X, x);
input_report_abs(ts->idev, ABS_Y, y);
input_report_abs(ts->idev, ABS_PRESSURE, z);
input_sync(ts->idev);
/* flush the FIFO after we have read out our values. */
__stmpe_reset_fifo(ts->stmpe);
/* reenable the tsc */
stmpe_set_bits(ts->stmpe, STMPE_REG_TSC_CTRL,
STMPE_TSC_CTRL_TSC_EN, STMPE_TSC_CTRL_TSC_EN);
/* start polling for touch_det to detect release */
schedule_delayed_work(&ts->work, HZ / 50);
return IRQ_HANDLED;
}
static int __devinit stmpe_init_hw(struct stmpe_touch *ts)
{
int ret;
u8 adc_ctrl1, adc_ctrl1_mask, tsc_cfg, tsc_cfg_mask;
struct stmpe *stmpe = ts->stmpe;
struct device *dev = ts->dev;
ret = stmpe_enable(stmpe, STMPE_BLOCK_TOUCHSCREEN | STMPE_BLOCK_ADC);
if (ret) {
dev_err(dev, "Could not enable clock for ADC and TS\n");
return ret;
}
adc_ctrl1 = SAMPLE_TIME(ts->sample_time) | MOD_12B(ts->mod_12b) |
REF_SEL(ts->ref_sel);
adc_ctrl1_mask = SAMPLE_TIME(0xff) | MOD_12B(0xff) | REF_SEL(0xff);
ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL1,
adc_ctrl1_mask, adc_ctrl1);
if (ret) {
dev_err(dev, "Could not setup ADC\n");
return ret;
}
ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL2,
ADC_FREQ(0xff), ADC_FREQ(ts->adc_freq));
if (ret) {
dev_err(dev, "Could not setup ADC\n");
return ret;
}
tsc_cfg = AVE_CTRL(ts->ave_ctrl) | DET_DELAY(ts->touch_det_delay) |
SETTLING(ts->settling);
tsc_cfg_mask = AVE_CTRL(0xff) | DET_DELAY(0xff) | SETTLING(0xff);
ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_CFG, tsc_cfg_mask, tsc_cfg);
if (ret) {
dev_err(dev, "Could not config touch\n");
return ret;
}
ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_FRACTION_Z,
FRACTION_Z(0xff), FRACTION_Z(ts->fraction_z));
if (ret) {
dev_err(dev, "Could not config touch\n");
return ret;
}
ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_I_DRIVE,
I_DRIVE(0xff), I_DRIVE(ts->i_drive));
if (ret) {
dev_err(dev, "Could not config touch\n");
return ret;
}
/* set FIFO to 1 for single point reading */
ret = stmpe_reg_write(stmpe, STMPE_REG_FIFO_TH, 1);
if (ret) {
dev_err(dev, "Could not set FIFO\n");
return ret;
}
ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_CTRL,
OP_MODE(0xff), OP_MODE(OP_MOD_XYZ));
if (ret) {
dev_err(dev, "Could not set mode\n");
return ret;
}
return 0;
}
static int stmpe_ts_open(struct input_dev *dev)
{
struct stmpe_touch *ts = input_get_drvdata(dev);
int ret = 0;
ret = __stmpe_reset_fifo(ts->stmpe);
if (ret)
return ret;
return stmpe_set_bits(ts->stmpe, STMPE_REG_TSC_CTRL,
STMPE_TSC_CTRL_TSC_EN, STMPE_TSC_CTRL_TSC_EN);
}
static void stmpe_ts_close(struct input_dev *dev)
{
struct stmpe_touch *ts = input_get_drvdata(dev);
cancel_delayed_work_sync(&ts->work);
stmpe_set_bits(ts->stmpe, STMPE_REG_TSC_CTRL,
STMPE_TSC_CTRL_TSC_EN, 0);
}
static int __devinit stmpe_input_probe(struct platform_device *pdev)
{
struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
struct stmpe_platform_data *pdata = stmpe->pdata;
struct stmpe_touch *ts;
struct input_dev *idev;
struct stmpe_ts_platform_data *ts_pdata = NULL;
int ret = 0;
int ts_irq;
ts_irq = platform_get_irq_byname(pdev, "FIFO_TH");
if (ts_irq < 0)
return ts_irq;
ts = kzalloc(sizeof(*ts), GFP_KERNEL);
if (!ts)
goto err_out;
idev = input_allocate_device();
if (!idev)
goto err_free_ts;
platform_set_drvdata(pdev, ts);
ts->stmpe = stmpe;
ts->idev = idev;
ts->dev = &pdev->dev;
if (pdata)
ts_pdata = pdata->ts;
if (ts_pdata) {
ts->sample_time = ts_pdata->sample_time;
ts->mod_12b = ts_pdata->mod_12b;
ts->ref_sel = ts_pdata->ref_sel;
ts->adc_freq = ts_pdata->adc_freq;
ts->ave_ctrl = ts_pdata->ave_ctrl;
ts->touch_det_delay = ts_pdata->touch_det_delay;
ts->settling = ts_pdata->settling;
ts->fraction_z = ts_pdata->fraction_z;
ts->i_drive = ts_pdata->i_drive;
}
INIT_DELAYED_WORK(&ts->work, stmpe_work);
ret = request_threaded_irq(ts_irq, NULL, stmpe_ts_handler,
IRQF_ONESHOT, STMPE_TS_NAME, ts);
if (ret) {
dev_err(&pdev->dev, "Failed to request IRQ %d\n", ts_irq);
goto err_free_input;
}
ret = stmpe_init_hw(ts);
if (ret)
goto err_free_irq;
idev->name = STMPE_TS_NAME;
idev->id.bustype = BUS_I2C;
idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
idev->open = stmpe_ts_open;
idev->close = stmpe_ts_close;
input_set_drvdata(idev, ts);
input_set_abs_params(idev, ABS_X, 0, XY_MASK, 0, 0);
input_set_abs_params(idev, ABS_Y, 0, XY_MASK, 0, 0);
input_set_abs_params(idev, ABS_PRESSURE, 0x0, 0xff, 0, 0);
ret = input_register_device(idev);
if (ret) {
dev_err(&pdev->dev, "Could not register input device\n");
goto err_free_irq;
}
return ret;
err_free_irq:
free_irq(ts_irq, ts);
err_free_input:
input_free_device(idev);
platform_set_drvdata(pdev, NULL);
err_free_ts:
kfree(ts);
err_out:
return ret;
}
static int __devexit stmpe_ts_remove(struct platform_device *pdev)
{
struct stmpe_touch *ts = platform_get_drvdata(pdev);
unsigned int ts_irq = platform_get_irq_byname(pdev, "FIFO_TH");
stmpe_disable(ts->stmpe, STMPE_BLOCK_TOUCHSCREEN);
free_irq(ts_irq, ts);
platform_set_drvdata(pdev, NULL);
input_unregister_device(ts->idev);
input_free_device(ts->idev);
kfree(ts);
return 0;
}
static struct platform_driver stmpe_ts_driver = {
.driver = {
.name = STMPE_TS_NAME,
.owner = THIS_MODULE,
},
.probe = stmpe_input_probe,
.remove = __devexit_p(stmpe_ts_remove),
};
static int __init stmpe_ts_init(void)
{
return platform_driver_register(&stmpe_ts_driver);
}
module_init(stmpe_ts_init);
static void __exit stmpe_ts_exit(void)
{
platform_driver_unregister(&stmpe_ts_driver);
}
module_exit(stmpe_ts_exit);
MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
MODULE_DESCRIPTION("STMPEXXX touchscreen driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" STMPE_TS_NAME);

View File

@ -74,12 +74,12 @@ static struct mfd_cell backlight_devs[] = {
}
static struct resource led_resources[] = {
PM8606_LED_RESOURCE(PM8606_LED1_RED, RGB2B),
PM8606_LED_RESOURCE(PM8606_LED1_GREEN, RGB2C),
PM8606_LED_RESOURCE(PM8606_LED1_BLUE, RGB2D),
PM8606_LED_RESOURCE(PM8606_LED2_RED, RGB1B),
PM8606_LED_RESOURCE(PM8606_LED2_GREEN, RGB1C),
PM8606_LED_RESOURCE(PM8606_LED2_BLUE, RGB1D),
PM8606_LED_RESOURCE(PM8606_LED1_RED, RGB1B),
PM8606_LED_RESOURCE(PM8606_LED1_GREEN, RGB1C),
PM8606_LED_RESOURCE(PM8606_LED1_BLUE, RGB1D),
PM8606_LED_RESOURCE(PM8606_LED2_RED, RGB2B),
PM8606_LED_RESOURCE(PM8606_LED2_GREEN, RGB2C),
PM8606_LED_RESOURCE(PM8606_LED2_BLUE, RGB2D),
};
#define PM8606_LED_DEVS(_i) \
@ -428,52 +428,44 @@ static int __devinit device_gpadc_init(struct pm860x_chip *chip,
{
struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
: chip->companion;
int use_gpadc = 0, data, ret;
int data;
int ret;
/* initialize GPADC without activating it */
if (pdata && pdata->touch) {
/* set GPADC MISC1 register */
data = 0;
data |= (pdata->touch->gpadc_prebias << 1)
& PM8607_GPADC_PREBIAS_MASK;
data |= (pdata->touch->slot_cycle << 3)
& PM8607_GPADC_SLOT_CYCLE_MASK;
data |= (pdata->touch->off_scale << 5)
& PM8607_GPADC_OFF_SCALE_MASK;
data |= (pdata->touch->sw_cal << 7)
& PM8607_GPADC_SW_CAL_MASK;
if (data) {
ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data);
if (ret < 0)
goto out;
}
/* set tsi prebias time */
if (pdata->touch->tsi_prebias) {
data = pdata->touch->tsi_prebias;
ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data);
if (ret < 0)
goto out;
}
/* set prebias & prechg time of pen detect */
data = 0;
data |= pdata->touch->pen_prebias & PM8607_PD_PREBIAS_MASK;
data |= (pdata->touch->pen_prechg << 5)
& PM8607_PD_PRECHG_MASK;
if (data) {
ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data);
if (ret < 0)
goto out;
}
if (!pdata || !pdata->touch)
return -EINVAL;
use_gpadc = 1;
/* set GPADC MISC1 register */
data = 0;
data |= (pdata->touch->gpadc_prebias << 1) & PM8607_GPADC_PREBIAS_MASK;
data |= (pdata->touch->slot_cycle << 3) & PM8607_GPADC_SLOT_CYCLE_MASK;
data |= (pdata->touch->off_scale << 5) & PM8607_GPADC_OFF_SCALE_MASK;
data |= (pdata->touch->sw_cal << 7) & PM8607_GPADC_SW_CAL_MASK;
if (data) {
ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data);
if (ret < 0)
goto out;
}
/* set tsi prebias time */
if (pdata->touch->tsi_prebias) {
data = pdata->touch->tsi_prebias;
ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data);
if (ret < 0)
goto out;
}
/* set prebias & prechg time of pen detect */
data = 0;
data |= pdata->touch->pen_prebias & PM8607_PD_PREBIAS_MASK;
data |= (pdata->touch->pen_prechg << 5) & PM8607_PD_PRECHG_MASK;
if (data) {
ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data);
if (ret < 0)
goto out;
}
/* turn on GPADC */
if (use_gpadc) {
ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1,
PM8607_GPADC_EN, PM8607_GPADC_EN);
}
ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1,
PM8607_GPADC_EN, PM8607_GPADC_EN);
out:
return ret;
}

View File

@ -7,7 +7,16 @@ menuconfig MFD_SUPPORT
depends on HAS_IOMEM
default y
help
Configure MFD device drivers.
Multifunction devices embed several functions (e.g. GPIOs,
touchscreens, keyboards, current regulators, power management chips,
etc...) in one single integrated circuit. They usually talk to the
main CPU through one or more IRQ lines and low speed data busses (SPI,
I2C, etc..). They appear as one single device to the main system
through the data bus and the MFD framework allows for sub devices
(a.k.a. functions) to appear as discrete platform devices.
MFDs are typically found on embedded platforms.
This option alone does not add any kernel code.
if MFD_SUPPORT
@ -177,6 +186,38 @@ config TWL4030_CODEC
select MFD_CORE
default n
config TWL6030_PWM
tristate "TWL6030 PWM (Pulse Width Modulator) Support"
depends on TWL4030_CORE
select HAVE_PWM
default n
help
Say yes here if you want support for TWL6030 PWM.
This is used to control charging LED brightness.
config MFD_STMPE
bool "Support STMicroelectronics STMPE"
depends on I2C=y && GENERIC_HARDIRQS
select MFD_CORE
help
Support for the STMPE family of I/O Expanders from
STMicroelectronics.
Currently supported devices are:
STMPE811: GPIO, Touchscreen
STMPE1601: GPIO, Keypad
STMPE2401: GPIO, Keypad
STMPE2403: GPIO, Keypad
This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the functionality
of the device. Currently available sub drivers are:
GPIO: stmpe-gpio
Keypad: stmpe-keypad
Touchscreen: stmpe-ts
config MFD_TC35892
bool "Support Toshiba TC35892"
depends on I2C=y && GENERIC_HARDIRQS
@ -482,6 +523,28 @@ config MFD_JANZ_CMODIO
host many different types of MODULbus daughterboards, including
CAN and GPIO controllers.
config MFD_JZ4740_ADC
tristate "Support for the JZ4740 SoC ADC core"
select MFD_CORE
depends on MACH_JZ4740
help
Say yes here if you want support for the ADC unit in the JZ4740 SoC.
This driver is necessary for jz4740-battery and jz4740-hwmon driver.
config MFD_TPS6586X
tristate "TPS6586x Power Management chips"
depends on I2C && GPIOLIB
select MFD_CORE
help
If you say yes here you get support for the TPS6586X series of
Power Management chips.
This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the
functionality of the device.
This driver can also be built as a module. If so, the module
will be called tps6586x.
endif # MFD_SUPPORT
menu "Multimedia Capabilities Port drivers"

View File

@ -15,6 +15,7 @@ obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o
obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o
obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
obj-$(CONFIG_MFD_STMPE) += stmpe.o
obj-$(CONFIG_MFD_TC35892) += tc35892.o
obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o
obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o
@ -36,6 +37,7 @@ obj-$(CONFIG_MENELAUS) += menelaus.o
obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o
obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o
obj-$(CONFIG_TWL4030_CODEC) += twl4030-codec.o
obj-$(CONFIG_TWL6030_PWM) += twl6030-pwm.o
obj-$(CONFIG_MFD_MC13783) += mc13783-core.o
@ -71,3 +73,5 @@ obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
obj-$(CONFIG_LPC_SCH) += lpc_sch.o
obj-$(CONFIG_MFD_RDC321X) += rdc321x-southbridge.o
obj-$(CONFIG_MFD_JANZ_CMODIO) += janz-cmodio.o
obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o
obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o

View File

@ -199,7 +199,7 @@ static int __init ab3100_otp_probe(struct platform_device *pdev)
err = ab3100_otp_read(otp);
if (err)
return err;
goto err_otp_read;
dev_info(&pdev->dev, "AB3100 OTP readout registered\n");
@ -208,21 +208,21 @@ static int __init ab3100_otp_probe(struct platform_device *pdev)
err = device_create_file(&pdev->dev,
&ab3100_otp_attrs[i]);
if (err)
goto out_no_sysfs;
goto err_create_file;
}
/* debugfs entries */
err = ab3100_otp_init_debugfs(&pdev->dev, otp);
if (err)
goto out_no_debugfs;
goto err_init_debugfs;
return 0;
out_no_sysfs:
for (i = 0; i < ARRAY_SIZE(ab3100_otp_attrs); i++)
device_remove_file(&pdev->dev,
&ab3100_otp_attrs[i]);
out_no_debugfs:
err_init_debugfs:
err_create_file:
while (--i >= 0)
device_remove_file(&pdev->dev, &ab3100_otp_attrs[i]);
err_otp_read:
kfree(otp);
return err;
}

View File

@ -589,16 +589,16 @@ static bool reg_read_allowed(const struct ab3550_reg_ranges *ranges, u8 reg)
}
/*
* The exported register access functionality.
* The register access functionality.
*/
int ab3550_get_chip_id(struct device *dev)
static int ab3550_get_chip_id(struct device *dev)
{
struct ab3550 *ab = dev_get_drvdata(dev->parent);
return (int)ab->chip_id;
}
int ab3550_mask_and_set_register_interruptible(struct device *dev, u8 bank,
u8 reg, u8 bitmask, u8 bitvalues)
static int ab3550_mask_and_set_register_interruptible(struct device *dev,
u8 bank, u8 reg, u8 bitmask, u8 bitvalues)
{
struct ab3550 *ab;
struct platform_device *pdev = to_platform_device(dev);
@ -612,15 +612,15 @@ int ab3550_mask_and_set_register_interruptible(struct device *dev, u8 bank,
bitmask, bitvalues);
}
int ab3550_set_register_interruptible(struct device *dev, u8 bank, u8 reg,
u8 value)
static int ab3550_set_register_interruptible(struct device *dev, u8 bank,
u8 reg, u8 value)
{
return ab3550_mask_and_set_register_interruptible(dev, bank, reg, 0xFF,
value);
}
int ab3550_get_register_interruptible(struct device *dev, u8 bank, u8 reg,
u8 *value)
static int ab3550_get_register_interruptible(struct device *dev, u8 bank,
u8 reg, u8 *value)
{
struct ab3550 *ab;
struct platform_device *pdev = to_platform_device(dev);
@ -633,7 +633,7 @@ int ab3550_get_register_interruptible(struct device *dev, u8 bank, u8 reg,
return get_register_interruptible(ab, bank, reg, value);
}
int ab3550_get_register_page_interruptible(struct device *dev, u8 bank,
static int ab3550_get_register_page_interruptible(struct device *dev, u8 bank,
u8 first_reg, u8 *regvals, u8 numregs)
{
struct ab3550 *ab;
@ -649,7 +649,8 @@ int ab3550_get_register_page_interruptible(struct device *dev, u8 bank,
numregs);
}
int ab3550_event_registers_startup_state_get(struct device *dev, u8 *event)
static int ab3550_event_registers_startup_state_get(struct device *dev,
u8 *event)
{
struct ab3550 *ab;
@ -661,7 +662,7 @@ int ab3550_event_registers_startup_state_get(struct device *dev, u8 *event)
return 0;
}
int ab3550_startup_irq_enabled(struct device *dev, unsigned int irq)
static int ab3550_startup_irq_enabled(struct device *dev, unsigned int irq)
{
struct ab3550 *ab;
struct ab3550_platform_data *plf_data;

View File

@ -68,7 +68,12 @@ static int ab8500_spi_read(struct ab8500 *ab8500, u16 addr)
ret = spi_sync(spi, &msg);
if (!ret)
ret = ab8500->rx_buf[0];
/*
* Only the 8 lowermost bytes are
* defined with value, the rest may
* vary depending on chip/board noise.
*/
ret = ab8500->rx_buf[0] & 0xFFU;
return ret;
}

View File

@ -36,7 +36,7 @@ int abx500_register_ops(struct device *dev, struct abx500_ops *ops)
struct abx500_device_entry *dev_entry;
dev_entry = kzalloc(sizeof(struct abx500_device_entry), GFP_KERNEL);
if (IS_ERR(dev_entry)) {
if (!dev_entry) {
dev_err(dev, "register_ops kzalloc failed");
return -ENOMEM;
}

View File

@ -94,7 +94,8 @@ static int __init davinci_vc_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!res) {
dev_err(&pdev->dev, "no DMA resource\n");
return -ENXIO;
ret = -ENXIO;
goto fail4;
}
davinci_vc->davinci_vcif.dma_tx_channel = res->start;
@ -104,7 +105,8 @@ static int __init davinci_vc_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!res) {
dev_err(&pdev->dev, "no DMA resource\n");
return -ENXIO;
ret = -ENXIO;
goto fail4;
}
davinci_vc->davinci_vcif.dma_rx_channel = res->start;

View File

@ -18,6 +18,7 @@
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mfd/core.h>
#include <linux/mfd/janz.h>

394
drivers/mfd/jz4740-adc.c Normal file
View File

@ -0,0 +1,394 @@
/*
* Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
* JZ4740 SoC ADC driver
*
* 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.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
* This driver synchronizes access to the JZ4740 ADC core between the
* JZ4740 battery and hwmon drivers.
*/
#include <linux/err.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/clk.h>
#include <linux/mfd/core.h>
#include <linux/jz4740-adc.h>
#define JZ_REG_ADC_ENABLE 0x00
#define JZ_REG_ADC_CFG 0x04
#define JZ_REG_ADC_CTRL 0x08
#define JZ_REG_ADC_STATUS 0x0c
#define JZ_REG_ADC_TOUCHSCREEN_BASE 0x10
#define JZ_REG_ADC_BATTERY_BASE 0x1c
#define JZ_REG_ADC_HWMON_BASE 0x20
#define JZ_ADC_ENABLE_TOUCH BIT(2)
#define JZ_ADC_ENABLE_BATTERY BIT(1)
#define JZ_ADC_ENABLE_ADCIN BIT(0)
enum {
JZ_ADC_IRQ_ADCIN = 0,
JZ_ADC_IRQ_BATTERY,
JZ_ADC_IRQ_TOUCH,
JZ_ADC_IRQ_PENUP,
JZ_ADC_IRQ_PENDOWN,
};
struct jz4740_adc {
struct resource *mem;
void __iomem *base;
int irq;
int irq_base;
struct clk *clk;
atomic_t clk_ref;
spinlock_t lock;
};
static inline void jz4740_adc_irq_set_masked(struct jz4740_adc *adc, int irq,
bool masked)
{
unsigned long flags;
uint8_t val;
irq -= adc->irq_base;
spin_lock_irqsave(&adc->lock, flags);
val = readb(adc->base + JZ_REG_ADC_CTRL);
if (masked)
val |= BIT(irq);
else
val &= ~BIT(irq);
writeb(val, adc->base + JZ_REG_ADC_CTRL);
spin_unlock_irqrestore(&adc->lock, flags);
}
static void jz4740_adc_irq_mask(unsigned int irq)
{
struct jz4740_adc *adc = get_irq_chip_data(irq);
jz4740_adc_irq_set_masked(adc, irq, true);
}
static void jz4740_adc_irq_unmask(unsigned int irq)
{
struct jz4740_adc *adc = get_irq_chip_data(irq);
jz4740_adc_irq_set_masked(adc, irq, false);
}
static void jz4740_adc_irq_ack(unsigned int irq)
{
struct jz4740_adc *adc = get_irq_chip_data(irq);
irq -= adc->irq_base;
writeb(BIT(irq), adc->base + JZ_REG_ADC_STATUS);
}
static struct irq_chip jz4740_adc_irq_chip = {
.name = "jz4740-adc",
.mask = jz4740_adc_irq_mask,
.unmask = jz4740_adc_irq_unmask,
.ack = jz4740_adc_irq_ack,
};
static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc)
{
struct jz4740_adc *adc = get_irq_desc_data(desc);
uint8_t status;
unsigned int i;
status = readb(adc->base + JZ_REG_ADC_STATUS);
for (i = 0; i < 5; ++i) {
if (status & BIT(i))
generic_handle_irq(adc->irq_base + i);
}
}
/* Refcounting for the ADC clock is done in here instead of in the clock
* framework, because it is the only clock which is shared between multiple
* devices and thus is the only clock which needs refcounting */
static inline void jz4740_adc_clk_enable(struct jz4740_adc *adc)
{
if (atomic_inc_return(&adc->clk_ref) == 1)
clk_enable(adc->clk);
}
static inline void jz4740_adc_clk_disable(struct jz4740_adc *adc)
{
if (atomic_dec_return(&adc->clk_ref) == 0)
clk_disable(adc->clk);
}
static inline void jz4740_adc_set_enabled(struct jz4740_adc *adc, int engine,
bool enabled)
{
unsigned long flags;
uint8_t val;
spin_lock_irqsave(&adc->lock, flags);
val = readb(adc->base + JZ_REG_ADC_ENABLE);
if (enabled)
val |= BIT(engine);
else
val &= BIT(engine);
writeb(val, adc->base + JZ_REG_ADC_ENABLE);
spin_unlock_irqrestore(&adc->lock, flags);
}
static int jz4740_adc_cell_enable(struct platform_device *pdev)
{
struct jz4740_adc *adc = dev_get_drvdata(pdev->dev.parent);
jz4740_adc_clk_enable(adc);
jz4740_adc_set_enabled(adc, pdev->id, true);
return 0;
}
static int jz4740_adc_cell_disable(struct platform_device *pdev)
{
struct jz4740_adc *adc = dev_get_drvdata(pdev->dev.parent);
jz4740_adc_set_enabled(adc, pdev->id, false);
jz4740_adc_clk_disable(adc);
return 0;
}
int jz4740_adc_set_config(struct device *dev, uint32_t mask, uint32_t val)
{
struct jz4740_adc *adc = dev_get_drvdata(dev);
unsigned long flags;
uint32_t cfg;
if (!adc)
return -ENODEV;
spin_lock_irqsave(&adc->lock, flags);
cfg = readl(adc->base + JZ_REG_ADC_CFG);
cfg &= ~mask;
cfg |= val;
writel(cfg, adc->base + JZ_REG_ADC_CFG);
spin_unlock_irqrestore(&adc->lock, flags);
return 0;
}
EXPORT_SYMBOL_GPL(jz4740_adc_set_config);
static struct resource jz4740_hwmon_resources[] = {
{
.start = JZ_ADC_IRQ_ADCIN,
.flags = IORESOURCE_IRQ,
},
{
.start = JZ_REG_ADC_HWMON_BASE,
.end = JZ_REG_ADC_HWMON_BASE + 3,
.flags = IORESOURCE_MEM,
},
};
static struct resource jz4740_battery_resources[] = {
{
.start = JZ_ADC_IRQ_BATTERY,
.flags = IORESOURCE_IRQ,
},
{
.start = JZ_REG_ADC_BATTERY_BASE,
.end = JZ_REG_ADC_BATTERY_BASE + 3,
.flags = IORESOURCE_MEM,
},
};
const struct mfd_cell jz4740_adc_cells[] = {
{
.id = 0,
.name = "jz4740-hwmon",
.num_resources = ARRAY_SIZE(jz4740_hwmon_resources),
.resources = jz4740_hwmon_resources,
.platform_data = (void *)&jz4740_adc_cells[0],
.data_size = sizeof(struct mfd_cell),
.enable = jz4740_adc_cell_enable,
.disable = jz4740_adc_cell_disable,
},
{
.id = 1,
.name = "jz4740-battery",
.num_resources = ARRAY_SIZE(jz4740_battery_resources),
.resources = jz4740_battery_resources,
.platform_data = (void *)&jz4740_adc_cells[1],
.data_size = sizeof(struct mfd_cell),
.enable = jz4740_adc_cell_enable,
.disable = jz4740_adc_cell_disable,
},
};
static int __devinit jz4740_adc_probe(struct platform_device *pdev)
{
int ret;
struct jz4740_adc *adc;
struct resource *mem_base;
int irq;
adc = kmalloc(sizeof(*adc), GFP_KERNEL);
if (!adc) {
dev_err(&pdev->dev, "Failed to allocate driver structure\n");
return -ENOMEM;
}
adc->irq = platform_get_irq(pdev, 0);
if (adc->irq < 0) {
ret = adc->irq;
dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
goto err_free;
}
adc->irq_base = platform_get_irq(pdev, 1);
if (adc->irq_base < 0) {
ret = adc->irq_base;
dev_err(&pdev->dev, "Failed to get irq base: %d\n", ret);
goto err_free;
}
mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem_base) {
ret = -ENOENT;
dev_err(&pdev->dev, "Failed to get platform mmio resource\n");
goto err_free;
}
/* Only request the shared registers for the MFD driver */
adc->mem = request_mem_region(mem_base->start, JZ_REG_ADC_STATUS,
pdev->name);
if (!adc->mem) {
ret = -EBUSY;
dev_err(&pdev->dev, "Failed to request mmio memory region\n");
goto err_free;
}
adc->base = ioremap_nocache(adc->mem->start, resource_size(adc->mem));
if (!adc->base) {
ret = -EBUSY;
dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
goto err_release_mem_region;
}
adc->clk = clk_get(&pdev->dev, "adc");
if (IS_ERR(adc->clk)) {
ret = PTR_ERR(adc->clk);
dev_err(&pdev->dev, "Failed to get clock: %d\n", ret);
goto err_iounmap;
}
spin_lock_init(&adc->lock);
atomic_set(&adc->clk_ref, 0);
platform_set_drvdata(pdev, adc);
for (irq = adc->irq_base; irq < adc->irq_base + 5; ++irq) {
set_irq_chip_data(irq, adc);
set_irq_chip_and_handler(irq, &jz4740_adc_irq_chip,
handle_level_irq);
}
set_irq_data(adc->irq, adc);
set_irq_chained_handler(adc->irq, jz4740_adc_irq_demux);
writeb(0x00, adc->base + JZ_REG_ADC_ENABLE);
writeb(0xff, adc->base + JZ_REG_ADC_CTRL);
ret = mfd_add_devices(&pdev->dev, 0, jz4740_adc_cells,
ARRAY_SIZE(jz4740_adc_cells), mem_base, adc->irq_base);
if (ret < 0)
goto err_clk_put;
return 0;
err_clk_put:
clk_put(adc->clk);
err_iounmap:
platform_set_drvdata(pdev, NULL);
iounmap(adc->base);
err_release_mem_region:
release_mem_region(adc->mem->start, resource_size(adc->mem));
err_free:
kfree(adc);
return ret;
}
static int __devexit jz4740_adc_remove(struct platform_device *pdev)
{
struct jz4740_adc *adc = platform_get_drvdata(pdev);
mfd_remove_devices(&pdev->dev);
set_irq_data(adc->irq, NULL);
set_irq_chained_handler(adc->irq, NULL);
iounmap(adc->base);
release_mem_region(adc->mem->start, resource_size(adc->mem));
clk_put(adc->clk);
platform_set_drvdata(pdev, NULL);
kfree(adc);
return 0;
}
struct platform_driver jz4740_adc_driver = {
.probe = jz4740_adc_probe,
.remove = __devexit_p(jz4740_adc_remove),
.driver = {
.name = "jz4740-adc",
.owner = THIS_MODULE,
},
};
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_DESCRIPTION("JZ4740 SoC ADC driver");
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:jz4740-adc");

View File

@ -90,6 +90,24 @@ static struct mfd_cell rtc_devs[] = {
},
};
static struct resource onkey_resources[] = {
{
.name = "max8925-onkey",
.start = MAX8925_IRQ_GPM_SW_3SEC,
.end = MAX8925_IRQ_GPM_SW_3SEC,
.flags = IORESOURCE_IRQ,
},
};
static struct mfd_cell onkey_devs[] = {
{
.name = "max8925-onkey",
.num_resources = 1,
.resources = &onkey_resources[0],
.id = -1,
},
};
#define MAX8925_REG_RESOURCE(_start, _end) \
{ \
.start = MAX8925_##_start, \
@ -596,6 +614,15 @@ int __devinit max8925_device_init(struct max8925_chip *chip,
dev_err(chip->dev, "Failed to add rtc subdev\n");
goto out;
}
ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
ARRAY_SIZE(onkey_devs),
&onkey_resources[0], 0);
if (ret < 0) {
dev_err(chip->dev, "Failed to add onkey subdev\n");
goto out_dev;
}
if (pdata && pdata->regulator[0]) {
ret = mfd_add_devices(chip->dev, 0, &regulator_devs[0],
ARRAY_SIZE(regulator_devs),

View File

@ -11,9 +11,31 @@
*/
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/interrupt.h>
#include <linux/spi/spi.h>
#include <linux/mfd/core.h>
#include <linux/mfd/mc13783-private.h>
#include <linux/mfd/mc13783.h>
struct mc13783 {
struct spi_device *spidev;
struct mutex lock;
int irq;
int flags;
irq_handler_t irqhandler[MC13783_NUM_IRQ];
void *irqdata[MC13783_NUM_IRQ];
/* XXX these should go as platformdata to the regulator subdevice */
struct mc13783_regulator_init_data *regulators;
int num_regulators;
};
#define MC13783_REG_REVISION 7
#define MC13783_REG_ADC_0 43
#define MC13783_REG_ADC_1 44
#define MC13783_REG_ADC_2 45
#define MC13783_IRQSTAT0 0
#define MC13783_IRQSTAT0_ADCDONEI (1 << 0)
@ -226,6 +248,12 @@ int mc13783_reg_rmw(struct mc13783 *mc13783, unsigned int offset,
}
EXPORT_SYMBOL(mc13783_reg_rmw);
int mc13783_get_flags(struct mc13783 *mc13783)
{
return mc13783->flags;
}
EXPORT_SYMBOL(mc13783_get_flags);
int mc13783_irq_mask(struct mc13783 *mc13783, int irq)
{
int ret;

View File

@ -128,6 +128,39 @@
#define MENELAUS_RESERVED14_IRQ 14 /* Reserved */
#define MENELAUS_RESERVED15_IRQ 15 /* Reserved */
/* VCORE_CTRL1 register */
#define VCORE_CTRL1_BYP_COMP (1 << 5)
#define VCORE_CTRL1_HW_NSW (1 << 7)
/* GPIO_CTRL register */
#define GPIO_CTRL_SLOTSELEN (1 << 5)
#define GPIO_CTRL_SLPCTLEN (1 << 6)
#define GPIO1_DIR_INPUT (1 << 0)
#define GPIO2_DIR_INPUT (1 << 1)
#define GPIO3_DIR_INPUT (1 << 2)
/* MCT_CTRL1 register */
#define MCT_CTRL1_S1_CMD_OD (1 << 2)
#define MCT_CTRL1_S2_CMD_OD (1 << 3)
/* MCT_CTRL2 register */
#define MCT_CTRL2_VS2_SEL_D0 (1 << 0)
#define MCT_CTRL2_VS2_SEL_D1 (1 << 1)
#define MCT_CTRL2_S1CD_BUFEN (1 << 4)
#define MCT_CTRL2_S2CD_BUFEN (1 << 5)
#define MCT_CTRL2_S1CD_DBEN (1 << 6)
#define MCT_CTRL2_S2CD_BEN (1 << 7)
/* MCT_CTRL3 register */
#define MCT_CTRL3_SLOT1_EN (1 << 0)
#define MCT_CTRL3_SLOT2_EN (1 << 1)
#define MCT_CTRL3_S1_AUTO_EN (1 << 2)
#define MCT_CTRL3_S2_AUTO_EN (1 << 3)
/* MCT_PIN_ST register */
#define MCT_PIN_ST_S1_CD_ST (1 << 0)
#define MCT_PIN_ST_S2_CD_ST (1 << 1)
static void menelaus_work(struct work_struct *_menelaus);
struct menelaus_chip {
@ -249,10 +282,10 @@ static void menelaus_mmc_cd_work(struct menelaus_chip *menelaus_hw)
return;
if (!(reg & 0x1))
card_mask |= (1 << 0);
card_mask |= MCT_PIN_ST_S1_CD_ST;
if (!(reg & 0x2))
card_mask |= (1 << 1);
card_mask |= MCT_PIN_ST_S2_CD_ST;
if (menelaus_hw->mmc_callback)
menelaus_hw->mmc_callback(menelaus_hw->mmc_callback_data,
@ -277,14 +310,14 @@ int menelaus_set_mmc_opendrain(int slot, int enable)
val = ret;
if (slot == 1) {
if (enable)
val |= 1 << 2;
val |= MCT_CTRL1_S1_CMD_OD;
else
val &= ~(1 << 2);
val &= ~MCT_CTRL1_S1_CMD_OD;
} else {
if (enable)
val |= 1 << 3;
val |= MCT_CTRL1_S2_CMD_OD;
else
val &= ~(1 << 3);
val &= ~MCT_CTRL1_S2_CMD_OD;
}
ret = menelaus_write_reg(MENELAUS_MCT_CTRL1, val);
mutex_unlock(&the_menelaus->lock);
@ -301,11 +334,11 @@ int menelaus_set_slot_sel(int enable)
ret = menelaus_read_reg(MENELAUS_GPIO_CTRL);
if (ret < 0)
goto out;
ret |= 0x02;
ret |= GPIO2_DIR_INPUT;
if (enable)
ret |= 1 << 5;
ret |= GPIO_CTRL_SLOTSELEN;
else
ret &= ~(1 << 5);
ret &= ~GPIO_CTRL_SLOTSELEN;
ret = menelaus_write_reg(MENELAUS_GPIO_CTRL, ret);
out:
mutex_unlock(&the_menelaus->lock);
@ -330,14 +363,14 @@ int menelaus_set_mmc_slot(int slot, int enable, int power, int cd_en)
val = ret;
if (slot == 1) {
if (cd_en)
val |= (1 << 4) | (1 << 6);
val |= MCT_CTRL2_S1CD_BUFEN | MCT_CTRL2_S1CD_DBEN;
else
val &= ~((1 << 4) | (1 << 6));
val &= ~(MCT_CTRL2_S1CD_BUFEN | MCT_CTRL2_S1CD_DBEN);
} else {
if (cd_en)
val |= (1 << 5) | (1 << 7);
val |= MCT_CTRL2_S2CD_BUFEN | MCT_CTRL2_S2CD_BEN;
else
val &= ~((1 << 5) | (1 << 7));
val &= ~(MCT_CTRL2_S2CD_BUFEN | MCT_CTRL2_S2CD_BEN);
}
ret = menelaus_write_reg(MENELAUS_MCT_CTRL2, val);
if (ret < 0)
@ -349,25 +382,25 @@ int menelaus_set_mmc_slot(int slot, int enable, int power, int cd_en)
val = ret;
if (slot == 1) {
if (enable)
val |= 1 << 0;
val |= MCT_CTRL3_SLOT1_EN;
else
val &= ~(1 << 0);
val &= ~MCT_CTRL3_SLOT1_EN;
} else {
int b;
if (enable)
ret |= 1 << 1;
val |= MCT_CTRL3_SLOT2_EN;
else
ret &= ~(1 << 1);
val &= ~MCT_CTRL3_SLOT2_EN;
b = menelaus_read_reg(MENELAUS_MCT_CTRL2);
b &= ~0x03;
b &= ~(MCT_CTRL2_VS2_SEL_D0 | MCT_CTRL2_VS2_SEL_D1);
b |= power;
ret = menelaus_write_reg(MENELAUS_MCT_CTRL2, b);
if (ret < 0)
goto out;
}
/* Disable autonomous shutdown */
val &= ~(0x03 << 2);
val &= ~(MCT_CTRL3_S1_AUTO_EN | MCT_CTRL3_S2_AUTO_EN);
ret = menelaus_write_reg(MENELAUS_MCT_CTRL3, val);
out:
mutex_unlock(&the_menelaus->lock);
@ -552,7 +585,7 @@ int menelaus_set_vcore_hw(unsigned int roof_mV, unsigned int floor_mV)
if (!the_menelaus->vcore_hw_mode) {
val = menelaus_read_reg(MENELAUS_VCORE_CTRL1);
/* HW mode, turn OFF byte comparator */
val |= ((1 << 7) | (1 << 5));
val |= (VCORE_CTRL1_HW_NSW | VCORE_CTRL1_BYP_COMP);
ret = menelaus_write_reg(MENELAUS_VCORE_CTRL1, val);
the_menelaus->vcore_hw_mode = 1;
}
@ -749,7 +782,7 @@ int menelaus_set_regulator_sleep(int enable, u32 val)
ret = menelaus_read_reg(MENELAUS_GPIO_CTRL);
if (ret < 0)
goto out;
t = ((1 << 6) | 0x04);
t = (GPIO_CTRL_SLPCTLEN | GPIO3_DIR_INPUT);
if (enable)
ret |= t;
else

View File

@ -70,7 +70,9 @@ static int mfd_add_device(struct device *parent, int id,
goto fail_res;
}
platform_device_add_resources(pdev, res, cell->num_resources);
ret = platform_device_add_resources(pdev, res, cell->num_resources);
if (ret)
goto fail_res;
ret = platform_device_add(pdev);
if (ret)

985
drivers/mfd/stmpe.c Normal file
View File

@ -0,0 +1,985 @@
/*
* 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/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.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)
{
return stmpe->variant->enable(stmpe, blocks, true);
}
static int __stmpe_disable(struct stmpe *stmpe, unsigned int blocks)
{
return stmpe->variant->enable(stmpe, blocks, false);
}
static int __stmpe_reg_read(struct stmpe *stmpe, u8 reg)
{
int ret;
ret = i2c_smbus_read_byte_data(stmpe->i2c, reg);
if (ret < 0)
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);
return ret;
}
static int __stmpe_reg_write(struct stmpe *stmpe, u8 reg, u8 val)
{
int ret;
dev_vdbg(stmpe->dev, "wr: reg %#x <= %#x\n", reg, val);
ret = i2c_smbus_write_byte_data(stmpe->i2c, reg, val);
if (ret < 0)
dev_err(stmpe->dev, "failed to write reg %#x: %d\n",
reg, ret);
return ret;
}
static int __stmpe_set_bits(struct stmpe *stmpe, u8 reg, u8 mask, u8 val)
{
int ret;
ret = __stmpe_reg_read(stmpe, reg);
if (ret < 0)
return ret;
ret &= ~mask;
ret |= val;
return __stmpe_reg_write(stmpe, reg, ret);
}
static int __stmpe_block_read(struct stmpe *stmpe, u8 reg, u8 length,
u8 *values)
{
int ret;
ret = i2c_smbus_read_i2c_block_data(stmpe->i2c, reg, length, values);
if (ret < 0)
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);
return ret;
}
static int __stmpe_block_write(struct stmpe *stmpe, u8 reg, u8 length,
const u8 *values)
{
int ret;
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);
if (ret < 0)
dev_err(stmpe->dev, "failed to write regs %#x: %d\n",
reg, ret);
return ret;
}
/**
* stmpe_enable - enable blocks on an STMPE device
* @stmpe: Device to work on
* @blocks: Mask of blocks (enum stmpe_block values) to enable
*/
int stmpe_enable(struct stmpe *stmpe, unsigned int blocks)
{
int ret;
mutex_lock(&stmpe->lock);
ret = __stmpe_enable(stmpe, blocks);
mutex_unlock(&stmpe->lock);
return ret;
}
EXPORT_SYMBOL_GPL(stmpe_enable);
/**
* stmpe_disable - disable blocks on an STMPE device
* @stmpe: Device to work on
* @blocks: Mask of blocks (enum stmpe_block values) to enable
*/
int stmpe_disable(struct stmpe *stmpe, unsigned int blocks)
{
int ret;
mutex_lock(&stmpe->lock);
ret = __stmpe_disable(stmpe, blocks);
mutex_unlock(&stmpe->lock);
return ret;
}
EXPORT_SYMBOL_GPL(stmpe_disable);
/**
* stmpe_reg_read() - read a single STMPE register
* @stmpe: Device to read from
* @reg: Register to read
*/
int stmpe_reg_read(struct stmpe *stmpe, u8 reg)
{
int ret;
mutex_lock(&stmpe->lock);
ret = __stmpe_reg_read(stmpe, reg);
mutex_unlock(&stmpe->lock);
return ret;
}
EXPORT_SYMBOL_GPL(stmpe_reg_read);
/**
* stmpe_reg_write() - write a single STMPE register
* @stmpe: Device to write to
* @reg: Register to write
* @val: Value to write
*/
int stmpe_reg_write(struct stmpe *stmpe, u8 reg, u8 val)
{
int ret;
mutex_lock(&stmpe->lock);
ret = __stmpe_reg_write(stmpe, reg, val);
mutex_unlock(&stmpe->lock);
return ret;
}
EXPORT_SYMBOL_GPL(stmpe_reg_write);
/**
* stmpe_set_bits() - set the value of a bitfield in a STMPE register
* @stmpe: Device to write to
* @reg: Register to write
* @mask: Mask of bits to set
* @val: Value to set
*/
int stmpe_set_bits(struct stmpe *stmpe, u8 reg, u8 mask, u8 val)
{
int ret;
mutex_lock(&stmpe->lock);
ret = __stmpe_set_bits(stmpe, reg, mask, val);
mutex_unlock(&stmpe->lock);
return ret;
}
EXPORT_SYMBOL_GPL(stmpe_set_bits);
/**
* stmpe_block_read() - read multiple STMPE registers
* @stmpe: Device to read from
* @reg: First register
* @length: Number of registers
* @values: Buffer to write to
*/
int stmpe_block_read(struct stmpe *stmpe, u8 reg, u8 length, u8 *values)
{
int ret;
mutex_lock(&stmpe->lock);
ret = __stmpe_block_read(stmpe, reg, length, values);
mutex_unlock(&stmpe->lock);
return ret;
}
EXPORT_SYMBOL_GPL(stmpe_block_read);
/**
* stmpe_block_write() - write multiple STMPE registers
* @stmpe: Device to write to
* @reg: First register
* @length: Number of registers
* @values: Values to write
*/
int stmpe_block_write(struct stmpe *stmpe, u8 reg, u8 length,
const u8 *values)
{
int ret;
mutex_lock(&stmpe->lock);
ret = __stmpe_block_write(stmpe, reg, length, values);
mutex_unlock(&stmpe->lock);
return ret;
}
EXPORT_SYMBOL_GPL(stmpe_block_write);
/**
* stmpe_set_altfunc: set the alternate function for STMPE pins
* @stmpe: Device to configure
* @pins: Bitmask of pins to affect
* @block: block to enable alternate functions for
*
* @pins is assumed to have a bit set for each of the bits whose alternate
* function is to be changed, numbered according to the GPIOXY numbers.
*
* If the GPIO module is not enabled, this function automatically enables it in
* order to perform the change.
*/
int stmpe_set_altfunc(struct stmpe *stmpe, u32 pins, enum stmpe_block block)
{
struct stmpe_variant_info *variant = stmpe->variant;
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;
mutex_lock(&stmpe->lock);
ret = __stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
if (ret < 0)
goto out;
ret = __stmpe_block_read(stmpe, regaddr, numregs, regs);
if (ret < 0)
goto out;
af = variant->get_altfunc(stmpe, block);
while (pins) {
int pin = __ffs(pins);
int regoffset = numregs - (pin / afperreg) - 1;
int pos = (pin % afperreg) * (8 / afperreg);
regs[regoffset] &= ~(mask << pos);
regs[regoffset] |= af << pos;
pins &= ~(1 << pin);
}
ret = __stmpe_block_write(stmpe, regaddr, numregs, regs);
out:
mutex_unlock(&stmpe->lock);
return ret;
}
EXPORT_SYMBOL_GPL(stmpe_set_altfunc);
/*
* GPIO (all variants)
*/
static struct resource stmpe_gpio_resources[] = {
/* Start and end filled dynamically */
{
.flags = IORESOURCE_IRQ,
},
};
static struct mfd_cell stmpe_gpio_cell = {
.name = "stmpe-gpio",
.resources = stmpe_gpio_resources,
.num_resources = ARRAY_SIZE(stmpe_gpio_resources),
};
/*
* Keypad (1601, 2401, 2403)
*/
static struct resource stmpe_keypad_resources[] = {
{
.name = "KEYPAD",
.start = 0,
.end = 0,
.flags = IORESOURCE_IRQ,
},
{
.name = "KEYPAD_OVER",
.start = 1,
.end = 1,
.flags = IORESOURCE_IRQ,
},
};
static struct mfd_cell stmpe_keypad_cell = {
.name = "stmpe-keypad",
.resources = stmpe_keypad_resources,
.num_resources = ARRAY_SIZE(stmpe_keypad_resources),
};
/*
* Touchscreen (STMPE811)
*/
static struct resource stmpe_ts_resources[] = {
{
.name = "TOUCH_DET",
.start = 0,
.end = 0,
.flags = IORESOURCE_IRQ,
},
{
.name = "FIFO_TH",
.start = 1,
.end = 1,
.flags = IORESOURCE_IRQ,
},
};
static struct mfd_cell stmpe_ts_cell = {
.name = "stmpe-ts",
.resources = stmpe_ts_resources,
.num_resources = ARRAY_SIZE(stmpe_ts_resources),
};
/*
* STMPE811
*/
static const u8 stmpe811_regs[] = {
[STMPE_IDX_CHIP_ID] = STMPE811_REG_CHIP_ID,
[STMPE_IDX_ICR_LSB] = STMPE811_REG_INT_CTRL,
[STMPE_IDX_IER_LSB] = STMPE811_REG_INT_EN,
[STMPE_IDX_ISR_MSB] = STMPE811_REG_INT_STA,
[STMPE_IDX_GPMR_LSB] = STMPE811_REG_GPIO_MP_STA,
[STMPE_IDX_GPSR_LSB] = STMPE811_REG_GPIO_SET_PIN,
[STMPE_IDX_GPCR_LSB] = STMPE811_REG_GPIO_CLR_PIN,
[STMPE_IDX_GPDR_LSB] = STMPE811_REG_GPIO_DIR,
[STMPE_IDX_GPRER_LSB] = STMPE811_REG_GPIO_RE,
[STMPE_IDX_GPFER_LSB] = STMPE811_REG_GPIO_FE,
[STMPE_IDX_GPAFR_U_MSB] = STMPE811_REG_GPIO_AF,
[STMPE_IDX_IEGPIOR_LSB] = STMPE811_REG_GPIO_INT_EN,
[STMPE_IDX_ISGPIOR_MSB] = STMPE811_REG_GPIO_INT_STA,
[STMPE_IDX_GPEDR_MSB] = STMPE811_REG_GPIO_ED,
};
static struct stmpe_variant_block stmpe811_blocks[] = {
{
.cell = &stmpe_gpio_cell,
.irq = STMPE811_IRQ_GPIOC,
.block = STMPE_BLOCK_GPIO,
},
{
.cell = &stmpe_ts_cell,
.irq = STMPE811_IRQ_TOUCH_DET,
.block = STMPE_BLOCK_TOUCHSCREEN,
},
};
static int stmpe811_enable(struct stmpe *stmpe, unsigned int blocks,
bool enable)
{
unsigned int mask = 0;
if (blocks & STMPE_BLOCK_GPIO)
mask |= STMPE811_SYS_CTRL2_GPIO_OFF;
if (blocks & STMPE_BLOCK_ADC)
mask |= STMPE811_SYS_CTRL2_ADC_OFF;
if (blocks & STMPE_BLOCK_TOUCHSCREEN)
mask |= STMPE811_SYS_CTRL2_TSC_OFF;
return __stmpe_set_bits(stmpe, STMPE811_REG_SYS_CTRL2, mask,
enable ? 0 : mask);
}
static int stmpe811_get_altfunc(struct stmpe *stmpe, enum stmpe_block block)
{
/* 0 for touchscreen, 1 for GPIO */
return block != STMPE_BLOCK_TOUCHSCREEN;
}
static struct stmpe_variant_info stmpe811 = {
.name = "stmpe811",
.id_val = 0x0811,
.id_mask = 0xffff,
.num_gpios = 8,
.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
*/
static const u8 stmpe1601_regs[] = {
[STMPE_IDX_CHIP_ID] = STMPE1601_REG_CHIP_ID,
[STMPE_IDX_ICR_LSB] = STMPE1601_REG_ICR_LSB,
[STMPE_IDX_IER_LSB] = STMPE1601_REG_IER_LSB,
[STMPE_IDX_ISR_MSB] = STMPE1601_REG_ISR_MSB,
[STMPE_IDX_GPMR_LSB] = STMPE1601_REG_GPIO_MP_LSB,
[STMPE_IDX_GPSR_LSB] = STMPE1601_REG_GPIO_SET_LSB,
[STMPE_IDX_GPCR_LSB] = STMPE1601_REG_GPIO_CLR_LSB,
[STMPE_IDX_GPDR_LSB] = STMPE1601_REG_GPIO_SET_DIR_LSB,
[STMPE_IDX_GPRER_LSB] = STMPE1601_REG_GPIO_RE_LSB,
[STMPE_IDX_GPFER_LSB] = STMPE1601_REG_GPIO_FE_LSB,
[STMPE_IDX_GPAFR_U_MSB] = STMPE1601_REG_GPIO_AF_U_MSB,
[STMPE_IDX_IEGPIOR_LSB] = STMPE1601_REG_INT_EN_GPIO_MASK_LSB,
[STMPE_IDX_ISGPIOR_MSB] = STMPE1601_REG_INT_STA_GPIO_MSB,
[STMPE_IDX_GPEDR_MSB] = STMPE1601_REG_GPIO_ED_MSB,
};
static struct stmpe_variant_block stmpe1601_blocks[] = {
{
.cell = &stmpe_gpio_cell,
.irq = STMPE24XX_IRQ_GPIOC,
.block = STMPE_BLOCK_GPIO,
},
{
.cell = &stmpe_keypad_cell,
.irq = STMPE24XX_IRQ_KEYPAD,
.block = STMPE_BLOCK_KEYPAD,
},
};
/* supported autosleep timeout delay (in msecs) */
static const int stmpe_autosleep_delay[] = {
4, 16, 32, 64, 128, 256, 512, 1024,
};
static int stmpe_round_timeout(int timeout)
{
int i;
for (i = 0; i < ARRAY_SIZE(stmpe_autosleep_delay); i++) {
if (stmpe_autosleep_delay[i] >= timeout)
return i;
}
/*
* requests for delays longer than supported should not return the
* longest supported delay
*/
return -EINVAL;
}
static int stmpe_autosleep(struct stmpe *stmpe, int autosleep_timeout)
{
int ret;
if (!stmpe->variant->enable_autosleep)
return -ENOSYS;
mutex_lock(&stmpe->lock);
ret = stmpe->variant->enable_autosleep(stmpe, autosleep_timeout);
mutex_unlock(&stmpe->lock);
return ret;
}
/*
* Both stmpe 1601/2403 support same layout for autosleep
*/
static int stmpe1601_autosleep(struct stmpe *stmpe,
int autosleep_timeout)
{
int ret, timeout;
/* choose the best available timeout */
timeout = stmpe_round_timeout(autosleep_timeout);
if (timeout < 0) {
dev_err(stmpe->dev, "invalid timeout\n");
return timeout;
}
ret = __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL2,
STMPE1601_AUTOSLEEP_TIMEOUT_MASK,
timeout);
if (ret < 0)
return ret;
return __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL2,
STPME1601_AUTOSLEEP_ENABLE,
STPME1601_AUTOSLEEP_ENABLE);
}
static int stmpe1601_enable(struct stmpe *stmpe, unsigned int blocks,
bool enable)
{
unsigned int mask = 0;
if (blocks & STMPE_BLOCK_GPIO)
mask |= STMPE1601_SYS_CTRL_ENABLE_GPIO;
if (blocks & STMPE_BLOCK_KEYPAD)
mask |= STMPE1601_SYS_CTRL_ENABLE_KPC;
return __stmpe_set_bits(stmpe, STMPE1601_REG_SYS_CTRL, mask,
enable ? mask : 0);
}
static int stmpe1601_get_altfunc(struct stmpe *stmpe, enum stmpe_block block)
{
switch (block) {
case STMPE_BLOCK_PWM:
return 2;
case STMPE_BLOCK_KEYPAD:
return 1;
case STMPE_BLOCK_GPIO:
default:
return 0;
}
}
static struct stmpe_variant_info stmpe1601 = {
.name = "stmpe1601",
.id_val = 0x0210,
.id_mask = 0xfff0, /* at least 0x0210 and 0x0212 */
.num_gpios = 16,
.af_bits = 2,
.regs = stmpe1601_regs,
.blocks = stmpe1601_blocks,
.num_blocks = ARRAY_SIZE(stmpe1601_blocks),
.num_irqs = STMPE1601_NR_INTERNAL_IRQS,
.enable = stmpe1601_enable,
.get_altfunc = stmpe1601_get_altfunc,
.enable_autosleep = stmpe1601_autosleep,
};
/*
* STMPE24XX
*/
static const u8 stmpe24xx_regs[] = {
[STMPE_IDX_CHIP_ID] = STMPE24XX_REG_CHIP_ID,
[STMPE_IDX_ICR_LSB] = STMPE24XX_REG_ICR_LSB,
[STMPE_IDX_IER_LSB] = STMPE24XX_REG_IER_LSB,
[STMPE_IDX_ISR_MSB] = STMPE24XX_REG_ISR_MSB,
[STMPE_IDX_GPMR_LSB] = STMPE24XX_REG_GPMR_LSB,
[STMPE_IDX_GPSR_LSB] = STMPE24XX_REG_GPSR_LSB,
[STMPE_IDX_GPCR_LSB] = STMPE24XX_REG_GPCR_LSB,
[STMPE_IDX_GPDR_LSB] = STMPE24XX_REG_GPDR_LSB,
[STMPE_IDX_GPRER_LSB] = STMPE24XX_REG_GPRER_LSB,
[STMPE_IDX_GPFER_LSB] = STMPE24XX_REG_GPFER_LSB,
[STMPE_IDX_GPAFR_U_MSB] = STMPE24XX_REG_GPAFR_U_MSB,
[STMPE_IDX_IEGPIOR_LSB] = STMPE24XX_REG_IEGPIOR_LSB,
[STMPE_IDX_ISGPIOR_MSB] = STMPE24XX_REG_ISGPIOR_MSB,
[STMPE_IDX_GPEDR_MSB] = STMPE24XX_REG_GPEDR_MSB,
};
static struct stmpe_variant_block stmpe24xx_blocks[] = {
{
.cell = &stmpe_gpio_cell,
.irq = STMPE24XX_IRQ_GPIOC,
.block = STMPE_BLOCK_GPIO,
},
{
.cell = &stmpe_keypad_cell,
.irq = STMPE24XX_IRQ_KEYPAD,
.block = STMPE_BLOCK_KEYPAD,
},
};
static int stmpe24xx_enable(struct stmpe *stmpe, unsigned int blocks,
bool enable)
{
unsigned int mask = 0;
if (blocks & STMPE_BLOCK_GPIO)
mask |= STMPE24XX_SYS_CTRL_ENABLE_GPIO;
if (blocks & STMPE_BLOCK_KEYPAD)
mask |= STMPE24XX_SYS_CTRL_ENABLE_KPC;
return __stmpe_set_bits(stmpe, STMPE24XX_REG_SYS_CTRL, mask,
enable ? mask : 0);
}
static int stmpe24xx_get_altfunc(struct stmpe *stmpe, enum stmpe_block block)
{
switch (block) {
case STMPE_BLOCK_ROTATOR:
return 2;
case STMPE_BLOCK_KEYPAD:
return 1;
case STMPE_BLOCK_GPIO:
default:
return 0;
}
}
static struct stmpe_variant_info stmpe2401 = {
.name = "stmpe2401",
.id_val = 0x0101,
.id_mask = 0xffff,
.num_gpios = 24,
.af_bits = 2,
.regs = stmpe24xx_regs,
.blocks = stmpe24xx_blocks,
.num_blocks = ARRAY_SIZE(stmpe24xx_blocks),
.num_irqs = STMPE24XX_NR_INTERNAL_IRQS,
.enable = stmpe24xx_enable,
.get_altfunc = stmpe24xx_get_altfunc,
};
static struct stmpe_variant_info stmpe2403 = {
.name = "stmpe2403",
.id_val = 0x0120,
.id_mask = 0xffff,
.num_gpios = 24,
.af_bits = 2,
.regs = stmpe24xx_regs,
.blocks = stmpe24xx_blocks,
.num_blocks = ARRAY_SIZE(stmpe24xx_blocks),
.num_irqs = STMPE24XX_NR_INTERNAL_IRQS,
.enable = stmpe24xx_enable,
.get_altfunc = stmpe24xx_get_altfunc,
.enable_autosleep = stmpe1601_autosleep, /* same as stmpe1601 */
};
static struct stmpe_variant_info *stmpe_variant_info[] = {
[STMPE811] = &stmpe811,
[STMPE1601] = &stmpe1601,
[STMPE2401] = &stmpe2401,
[STMPE2403] = &stmpe2403,
};
static irqreturn_t stmpe_irq(int irq, void *data)
{
struct stmpe *stmpe = data;
struct stmpe_variant_info *variant = stmpe->variant;
int num = DIV_ROUND_UP(variant->num_irqs, 8);
u8 israddr = stmpe->regs[STMPE_IDX_ISR_MSB];
u8 isr[num];
int ret;
int i;
ret = stmpe_block_read(stmpe, israddr, num, isr);
if (ret < 0)
return IRQ_NONE;
for (i = 0; i < num; i++) {
int bank = num - i - 1;
u8 status = isr[i];
u8 clear;
status &= stmpe->ier[bank];
if (!status)
continue;
clear = status;
while (status) {
int bit = __ffs(status);
int line = bank * 8 + bit;
handle_nested_irq(stmpe->irq_base + line);
status &= ~(1 << bit);
}
stmpe_reg_write(stmpe, israddr + i, clear);
}
return IRQ_HANDLED;
}
static void stmpe_irq_lock(unsigned int irq)
{
struct stmpe *stmpe = get_irq_chip_data(irq);
mutex_lock(&stmpe->irq_lock);
}
static void stmpe_irq_sync_unlock(unsigned int irq)
{
struct stmpe *stmpe = get_irq_chip_data(irq);
struct stmpe_variant_info *variant = stmpe->variant;
int num = DIV_ROUND_UP(variant->num_irqs, 8);
int i;
for (i = 0; i < num; i++) {
u8 new = stmpe->ier[i];
u8 old = stmpe->oldier[i];
if (new == old)
continue;
stmpe->oldier[i] = new;
stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_IER_LSB] - i, new);
}
mutex_unlock(&stmpe->irq_lock);
}
static void stmpe_irq_mask(unsigned int irq)
{
struct stmpe *stmpe = get_irq_chip_data(irq);
int offset = irq - stmpe->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
stmpe->ier[regoffset] &= ~mask;
}
static void stmpe_irq_unmask(unsigned int irq)
{
struct stmpe *stmpe = get_irq_chip_data(irq);
int offset = irq - stmpe->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
stmpe->ier[regoffset] |= mask;
}
static struct irq_chip stmpe_irq_chip = {
.name = "stmpe",
.bus_lock = stmpe_irq_lock,
.bus_sync_unlock = stmpe_irq_sync_unlock,
.mask = stmpe_irq_mask,
.unmask = stmpe_irq_unmask,
};
static int __devinit stmpe_irq_init(struct stmpe *stmpe)
{
int num_irqs = stmpe->variant->num_irqs;
int base = stmpe->irq_base;
int irq;
for (irq = base; irq < base + num_irqs; irq++) {
set_irq_chip_data(irq, stmpe);
set_irq_chip_and_handler(irq, &stmpe_irq_chip,
handle_edge_irq);
set_irq_nested_thread(irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
#else
set_irq_noprobe(irq);
#endif
}
return 0;
}
static void stmpe_irq_remove(struct stmpe *stmpe)
{
int num_irqs = stmpe->variant->num_irqs;
int base = stmpe->irq_base;
int irq;
for (irq = base; irq < base + num_irqs; irq++) {
#ifdef CONFIG_ARM
set_irq_flags(irq, 0);
#endif
set_irq_chip_and_handler(irq, NULL, NULL);
set_irq_chip_data(irq, NULL);
}
}
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;
unsigned int id;
u8 data[2];
int ret;
ret = stmpe_block_read(stmpe, stmpe->regs[STMPE_IDX_CHIP_ID],
ARRAY_SIZE(data), data);
if (ret < 0)
return ret;
id = (data[0] << 8) | data[1];
if ((id & variant->id_mask) != variant->id_val) {
dev_err(stmpe->dev, "unknown chip id: %#x\n", id);
return -EINVAL;
}
dev_info(stmpe->dev, "%s detected, chip id: %#x\n", variant->name, id);
/* Disable all modules -- subdrivers should enable what they need. */
ret = stmpe_disable(stmpe, ~0);
if (ret)
return ret;
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;
if (stmpe->pdata->irq_invert_polarity)
icr ^= STMPE_ICR_LSB_HIGH;
if (stmpe->pdata->autosleep) {
ret = stmpe_autosleep(stmpe, autosleep_timeout);
if (ret)
return ret;
}
return stmpe_reg_write(stmpe, stmpe->regs[STMPE_IDX_ICR_LSB], icr);
}
static int __devinit stmpe_add_device(struct stmpe *stmpe,
struct mfd_cell *cell, int irq)
{
return mfd_add_devices(stmpe->dev, stmpe->pdata->id, cell, 1,
NULL, stmpe->irq_base + irq);
}
static int __devinit stmpe_devices_init(struct stmpe *stmpe)
{
struct stmpe_variant_info *variant = stmpe->variant;
unsigned int platform_blocks = stmpe->pdata->blocks;
int ret = -EINVAL;
int i;
for (i = 0; i < variant->num_blocks; i++) {
struct stmpe_variant_block *block = &variant->blocks[i];
if (!(platform_blocks & block->block))
continue;
platform_blocks &= ~block->block;
ret = stmpe_add_device(stmpe, block->cell, block->irq);
if (ret)
return ret;
}
if (platform_blocks)
dev_warn(stmpe->dev,
"platform wants blocks (%#x) not present on variant",
platform_blocks);
return ret;
}
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 *stmpe;
int ret;
if (!pdata)
return -EINVAL;
stmpe = kzalloc(sizeof(struct stmpe), GFP_KERNEL);
if (!stmpe)
return -ENOMEM;
mutex_init(&stmpe->irq_lock);
mutex_init(&stmpe->lock);
stmpe->dev = &i2c->dev;
stmpe->i2c = i2c;
stmpe->pdata = pdata;
stmpe->irq_base = pdata->irq_base;
stmpe->partnum = id->driver_data;
stmpe->variant = stmpe_variant_info[stmpe->partnum];
stmpe->regs = stmpe->variant->regs;
stmpe->num_gpios = stmpe->variant->num_gpios;
i2c_set_clientdata(i2c, stmpe);
ret = stmpe_chip_init(stmpe);
if (ret)
goto out_free;
ret = stmpe_irq_init(stmpe);
if (ret)
goto out_free;
ret = request_threaded_irq(stmpe->i2c->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;
}
ret = stmpe_devices_init(stmpe);
if (ret) {
dev_err(stmpe->dev, "failed to add children\n");
goto out_removedevs;
}
return 0;
out_removedevs:
mfd_remove_devices(stmpe->dev);
free_irq(stmpe->i2c->irq, stmpe);
out_removeirq:
stmpe_irq_remove(stmpe);
out_free:
kfree(stmpe);
return ret;
}
static int __devexit stmpe_remove(struct i2c_client *client)
{
struct stmpe *stmpe = i2c_get_clientdata(client);
mfd_remove_devices(stmpe->dev);
free_irq(stmpe->i2c->irq, stmpe);
stmpe_irq_remove(stmpe);
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);
static struct i2c_driver stmpe_driver = {
.driver.name = "stmpe",
.driver.owner = THIS_MODULE,
.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 <rabin.vincent@stericsson.com>");

183
drivers/mfd/stmpe.h Normal file
View File

@ -0,0 +1,183 @@
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License, version 2
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
*/
#ifndef __STMPE_H
#define __STMPE_H
#ifdef STMPE_DUMP_BYTES
static inline void stmpe_dump_bytes(const char *str, const void *buf,
size_t len)
{
print_hex_dump_bytes(str, DUMP_PREFIX_OFFSET, buf, len);
}
#else
static inline void stmpe_dump_bytes(const char *str, const void *buf,
size_t len)
{
}
#endif
/**
* struct stmpe_variant_block - information about block
* @cell: base mfd cell
* @irq: interrupt number to be added to each IORESOURCE_IRQ
* in the cell
* @block: block id; used for identification with platform data and for
* enable and altfunc callbacks
*/
struct stmpe_variant_block {
struct mfd_cell *cell;
int irq;
enum stmpe_block block;
};
/**
* struct stmpe_variant_info - variant-specific information
* @name: part name
* @id_val: content of CHIPID register
* @id_mask: bits valid in CHIPID register for comparison with id_val
* @num_gpios: number of GPIOS
* @af_bits: number of bits used to specify the alternate function
* @blocks: list of blocks present on this device
* @num_blocks: number of blocks present on this device
* @num_irqs: number of internal IRQs available on this device
* @enable: callback to enable the specified blocks.
* Called with the I/O lock held.
* @get_altfunc: callback to get the alternate function number for the
* specific block
* @enable_autosleep: callback to configure autosleep with specified timeout
*/
struct stmpe_variant_info {
const char *name;
u16 id_val;
u16 id_mask;
int num_gpios;
int af_bits;
const u8 *regs;
struct stmpe_variant_block *blocks;
int num_blocks;
int num_irqs;
int (*enable)(struct stmpe *stmpe, unsigned int blocks, bool enable);
int (*get_altfunc)(struct stmpe *stmpe, enum stmpe_block block);
int (*enable_autosleep)(struct stmpe *stmpe, int autosleep_timeout);
};
#define STMPE_ICR_LSB_HIGH (1 << 2)
#define STMPE_ICR_LSB_EDGE (1 << 1)
#define STMPE_ICR_LSB_GIM (1 << 0)
/*
* STMPE811
*/
#define STMPE811_IRQ_TOUCH_DET 0
#define STMPE811_IRQ_FIFO_TH 1
#define STMPE811_IRQ_FIFO_OFLOW 2
#define STMPE811_IRQ_FIFO_FULL 3
#define STMPE811_IRQ_FIFO_EMPTY 4
#define STMPE811_IRQ_TEMP_SENS 5
#define STMPE811_IRQ_ADC 6
#define STMPE811_IRQ_GPIOC 7
#define STMPE811_NR_INTERNAL_IRQS 8
#define STMPE811_REG_CHIP_ID 0x00
#define STMPE811_REG_SYS_CTRL2 0x04
#define STMPE811_REG_INT_CTRL 0x09
#define STMPE811_REG_INT_EN 0x0A
#define STMPE811_REG_INT_STA 0x0B
#define STMPE811_REG_GPIO_INT_EN 0x0C
#define STMPE811_REG_GPIO_INT_STA 0x0D
#define STMPE811_REG_GPIO_SET_PIN 0x10
#define STMPE811_REG_GPIO_CLR_PIN 0x11
#define STMPE811_REG_GPIO_MP_STA 0x12
#define STMPE811_REG_GPIO_DIR 0x13
#define STMPE811_REG_GPIO_ED 0x14
#define STMPE811_REG_GPIO_RE 0x15
#define STMPE811_REG_GPIO_FE 0x16
#define STMPE811_REG_GPIO_AF 0x17
#define STMPE811_SYS_CTRL2_ADC_OFF (1 << 0)
#define STMPE811_SYS_CTRL2_TSC_OFF (1 << 1)
#define STMPE811_SYS_CTRL2_GPIO_OFF (1 << 2)
#define STMPE811_SYS_CTRL2_TS_OFF (1 << 3)
/*
* STMPE1601
*/
#define STMPE1601_IRQ_GPIOC 8
#define STMPE1601_IRQ_PWM3 7
#define STMPE1601_IRQ_PWM2 6
#define STMPE1601_IRQ_PWM1 5
#define STMPE1601_IRQ_PWM0 4
#define STMPE1601_IRQ_KEYPAD_OVER 2
#define STMPE1601_IRQ_KEYPAD 1
#define STMPE1601_IRQ_WAKEUP 0
#define STMPE1601_NR_INTERNAL_IRQS 9
#define STMPE1601_REG_SYS_CTRL 0x02
#define STMPE1601_REG_SYS_CTRL2 0x03
#define STMPE1601_REG_ICR_LSB 0x11
#define STMPE1601_REG_IER_LSB 0x13
#define STMPE1601_REG_ISR_MSB 0x14
#define STMPE1601_REG_CHIP_ID 0x80
#define STMPE1601_REG_INT_EN_GPIO_MASK_LSB 0x17
#define STMPE1601_REG_INT_STA_GPIO_MSB 0x18
#define STMPE1601_REG_GPIO_MP_LSB 0x87
#define STMPE1601_REG_GPIO_SET_LSB 0x83
#define STMPE1601_REG_GPIO_CLR_LSB 0x85
#define STMPE1601_REG_GPIO_SET_DIR_LSB 0x89
#define STMPE1601_REG_GPIO_ED_MSB 0x8A
#define STMPE1601_REG_GPIO_RE_LSB 0x8D
#define STMPE1601_REG_GPIO_FE_LSB 0x8F
#define STMPE1601_REG_GPIO_AF_U_MSB 0x92
#define STMPE1601_SYS_CTRL_ENABLE_GPIO (1 << 3)
#define STMPE1601_SYS_CTRL_ENABLE_KPC (1 << 1)
#define STMPE1601_SYSCON_ENABLE_SPWM (1 << 0)
/* The 1601/2403 share the same masks */
#define STMPE1601_AUTOSLEEP_TIMEOUT_MASK (0x7)
#define STPME1601_AUTOSLEEP_ENABLE (1 << 3)
/*
* STMPE24xx
*/
#define STMPE24XX_IRQ_GPIOC 8
#define STMPE24XX_IRQ_PWM2 7
#define STMPE24XX_IRQ_PWM1 6
#define STMPE24XX_IRQ_PWM0 5
#define STMPE24XX_IRQ_ROT_OVER 4
#define STMPE24XX_IRQ_ROT 3
#define STMPE24XX_IRQ_KEYPAD_OVER 2
#define STMPE24XX_IRQ_KEYPAD 1
#define STMPE24XX_IRQ_WAKEUP 0
#define STMPE24XX_NR_INTERNAL_IRQS 9
#define STMPE24XX_REG_SYS_CTRL 0x02
#define STMPE24XX_REG_ICR_LSB 0x11
#define STMPE24XX_REG_IER_LSB 0x13
#define STMPE24XX_REG_ISR_MSB 0x14
#define STMPE24XX_REG_CHIP_ID 0x80
#define STMPE24XX_REG_IEGPIOR_LSB 0x18
#define STMPE24XX_REG_ISGPIOR_MSB 0x19
#define STMPE24XX_REG_GPMR_LSB 0xA5
#define STMPE24XX_REG_GPSR_LSB 0x85
#define STMPE24XX_REG_GPCR_LSB 0x88
#define STMPE24XX_REG_GPDR_LSB 0x8B
#define STMPE24XX_REG_GPEDR_MSB 0x8C
#define STMPE24XX_REG_GPRER_LSB 0x91
#define STMPE24XX_REG_GPFER_LSB 0x94
#define STMPE24XX_REG_GPAFR_U_MSB 0x9B
#define STMPE24XX_SYS_CTRL_ENABLE_GPIO (1 << 3)
#define STMPE24XX_SYSCON_ENABLE_PWM (1 << 2)
#define STMPE24XX_SYS_CTRL_ENABLE_KPC (1 << 1)
#define STMPE24XX_SYSCON_ENABLE_ROT (1 << 0)
#endif

View File

@ -350,7 +350,6 @@ static int t7l66xb_probe(struct platform_device *dev)
t7l66xb->clk48m = clk_get(&dev->dev, "CLK_CK48M");
if (IS_ERR(t7l66xb->clk48m)) {
ret = PTR_ERR(t7l66xb->clk48m);
clk_put(t7l66xb->clk32k);
goto err_clk48m_get;
}
@ -425,6 +424,8 @@ static int t7l66xb_remove(struct platform_device *dev)
ret = pdata->disable(dev);
clk_disable(t7l66xb->clk48m);
clk_put(t7l66xb->clk48m);
clk_disable(t7l66xb->clk32k);
clk_put(t7l66xb->clk32k);
t7l66xb_detach_irq(dev);
iounmap(t7l66xb->scr);
release_resource(&t7l66xb->rscr);

View File

@ -137,7 +137,7 @@ static struct mfd_cell tc6387xb_cells[] = {
},
};
static int tc6387xb_probe(struct platform_device *dev)
static int __devinit tc6387xb_probe(struct platform_device *dev)
{
struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
struct resource *iomem, *rscr;
@ -201,6 +201,7 @@ static int tc6387xb_probe(struct platform_device *dev)
if (!ret)
return 0;
iounmap(tc6387xb->scr);
err_ioremap:
release_resource(&tc6387xb->rscr);
err_resource:
@ -211,14 +212,17 @@ err_no_irq:
return ret;
}
static int tc6387xb_remove(struct platform_device *dev)
static int __devexit tc6387xb_remove(struct platform_device *dev)
{
struct clk *clk32k = platform_get_drvdata(dev);
struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
mfd_remove_devices(&dev->dev);
clk_disable(clk32k);
clk_put(clk32k);
iounmap(tc6387xb->scr);
release_resource(&tc6387xb->rscr);
clk_disable(tc6387xb->clk32k);
clk_put(tc6387xb->clk32k);
platform_set_drvdata(dev, NULL);
kfree(tc6387xb);
return 0;
}
@ -229,7 +233,7 @@ static struct platform_driver tc6387xb_platform_driver = {
.name = "tc6387xb",
},
.probe = tc6387xb_probe,
.remove = tc6387xb_remove,
.remove = __devexit_p(tc6387xb_remove),
.suspend = tc6387xb_suspend,
.resume = tc6387xb_resume,
};

View File

@ -732,9 +732,9 @@ err_gpio_add:
if (tc6393xb->gpio.base != -1)
temp = gpiochip_remove(&tc6393xb->gpio);
tcpd->disable(dev);
err_clk_enable:
clk_disable(tc6393xb->clk);
err_enable:
clk_disable(tc6393xb->clk);
err_clk_enable:
iounmap(tc6393xb->scr);
err_ioremap:
release_resource(&tc6393xb->rscr);

View File

@ -89,10 +89,8 @@ static int tps6507x_i2c_probe(struct i2c_client *i2c,
int ret = 0;
tps6507x = kzalloc(sizeof(struct tps6507x_dev), GFP_KERNEL);
if (tps6507x == NULL) {
kfree(i2c);
if (tps6507x == NULL)
return -ENOMEM;
}
i2c_set_clientdata(i2c, tps6507x);
tps6507x->dev = &i2c->dev;

375
drivers/mfd/tps6586x.c Normal file
View File

@ -0,0 +1,375 @@
/*
* Core driver for TI TPS6586x PMIC family
*
* Copyright (c) 2010 CompuLab Ltd.
* Mike Rapoport <mike@compulab.co.il>
*
* Based on da903x.c.
* Copyright (C) 2008 Compulab, Ltd.
* Mike Rapoport <mike@compulab.co.il>
* Copyright (C) 2006-2008 Marvell International Ltd.
* Eric Miao <eric.miao@marvell.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tps6586x.h>
/* GPIO control registers */
#define TPS6586X_GPIOSET1 0x5d
#define TPS6586X_GPIOSET2 0x5e
/* device id */
#define TPS6586X_VERSIONCRC 0xcd
#define TPS658621A_VERSIONCRC 0x15
struct tps6586x {
struct mutex lock;
struct device *dev;
struct i2c_client *client;
struct gpio_chip gpio;
};
static inline int __tps6586x_read(struct i2c_client *client,
int reg, uint8_t *val)
{
int ret;
ret = i2c_smbus_read_byte_data(client, reg);
if (ret < 0) {
dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
return ret;
}
*val = (uint8_t)ret;
return 0;
}
static inline int __tps6586x_reads(struct i2c_client *client, int reg,
int len, uint8_t *val)
{
int ret;
ret = i2c_smbus_read_i2c_block_data(client, reg, len, val);
if (ret < 0) {
dev_err(&client->dev, "failed reading from 0x%02x\n", reg);
return ret;
}
return 0;
}
static inline int __tps6586x_write(struct i2c_client *client,
int reg, uint8_t val)
{
int ret;
ret = i2c_smbus_write_byte_data(client, reg, val);
if (ret < 0) {
dev_err(&client->dev, "failed writing 0x%02x to 0x%02x\n",
val, reg);
return ret;
}
return 0;
}
static inline int __tps6586x_writes(struct i2c_client *client, int reg,
int len, uint8_t *val)
{
int ret;
ret = i2c_smbus_write_i2c_block_data(client, reg, len, val);
if (ret < 0) {
dev_err(&client->dev, "failed writings to 0x%02x\n", reg);
return ret;
}
return 0;
}
int tps6586x_write(struct device *dev, int reg, uint8_t val)
{
return __tps6586x_write(to_i2c_client(dev), reg, val);
}
EXPORT_SYMBOL_GPL(tps6586x_write);
int tps6586x_writes(struct device *dev, int reg, int len, uint8_t *val)
{
return __tps6586x_writes(to_i2c_client(dev), reg, len, val);
}
EXPORT_SYMBOL_GPL(tps6586x_writes);
int tps6586x_read(struct device *dev, int reg, uint8_t *val)
{
return __tps6586x_read(to_i2c_client(dev), reg, val);
}
EXPORT_SYMBOL_GPL(tps6586x_read);
int tps6586x_reads(struct device *dev, int reg, int len, uint8_t *val)
{
return __tps6586x_reads(to_i2c_client(dev), reg, len, val);
}
EXPORT_SYMBOL_GPL(tps6586x_reads);
int tps6586x_set_bits(struct device *dev, int reg, uint8_t bit_mask)
{
struct tps6586x *tps6586x = dev_get_drvdata(dev);
uint8_t reg_val;
int ret = 0;
mutex_lock(&tps6586x->lock);
ret = __tps6586x_read(to_i2c_client(dev), reg, &reg_val);
if (ret)
goto out;
if ((reg_val & bit_mask) == 0) {
reg_val |= bit_mask;
ret = __tps6586x_write(to_i2c_client(dev), reg, reg_val);
}
out:
mutex_unlock(&tps6586x->lock);
return ret;
}
EXPORT_SYMBOL_GPL(tps6586x_set_bits);
int tps6586x_clr_bits(struct device *dev, int reg, uint8_t bit_mask)
{
struct tps6586x *tps6586x = dev_get_drvdata(dev);
uint8_t reg_val;
int ret = 0;
mutex_lock(&tps6586x->lock);
ret = __tps6586x_read(to_i2c_client(dev), reg, &reg_val);
if (ret)
goto out;
if (reg_val & bit_mask) {
reg_val &= ~bit_mask;
ret = __tps6586x_write(to_i2c_client(dev), reg, reg_val);
}
out:
mutex_unlock(&tps6586x->lock);
return ret;
}
EXPORT_SYMBOL_GPL(tps6586x_clr_bits);
int tps6586x_update(struct device *dev, int reg, uint8_t val, uint8_t mask)
{
struct tps6586x *tps6586x = dev_get_drvdata(dev);
uint8_t reg_val;
int ret = 0;
mutex_lock(&tps6586x->lock);
ret = __tps6586x_read(tps6586x->client, reg, &reg_val);
if (ret)
goto out;
if ((reg_val & mask) != val) {
reg_val = (reg_val & ~mask) | val;
ret = __tps6586x_write(tps6586x->client, reg, reg_val);
}
out:
mutex_unlock(&tps6586x->lock);
return ret;
}
EXPORT_SYMBOL_GPL(tps6586x_update);
static int tps6586x_gpio_get(struct gpio_chip *gc, unsigned offset)
{
struct tps6586x *tps6586x = container_of(gc, struct tps6586x, gpio);
uint8_t val;
int ret;
ret = __tps6586x_read(tps6586x->client, TPS6586X_GPIOSET2, &val);
if (ret)
return ret;
return !!(val & (1 << offset));
}
static void tps6586x_gpio_set(struct gpio_chip *chip, unsigned offset,
int value)
{
struct tps6586x *tps6586x = container_of(chip, struct tps6586x, gpio);
__tps6586x_write(tps6586x->client, TPS6586X_GPIOSET2,
value << offset);
}
static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset,
int value)
{
struct tps6586x *tps6586x = container_of(gc, struct tps6586x, gpio);
uint8_t val, mask;
tps6586x_gpio_set(gc, offset, value);
val = 0x1 << (offset * 2);
mask = 0x3 << (offset * 2);
return tps6586x_update(tps6586x->dev, TPS6586X_GPIOSET1, val, mask);
}
static void tps6586x_gpio_init(struct tps6586x *tps6586x, int gpio_base)
{
int ret;
if (!gpio_base)
return;
tps6586x->gpio.owner = THIS_MODULE;
tps6586x->gpio.label = tps6586x->client->name;
tps6586x->gpio.dev = tps6586x->dev;
tps6586x->gpio.base = gpio_base;
tps6586x->gpio.ngpio = 4;
tps6586x->gpio.can_sleep = 1;
/* FIXME: add handling of GPIOs as dedicated inputs */
tps6586x->gpio.direction_output = tps6586x_gpio_output;
tps6586x->gpio.set = tps6586x_gpio_set;
tps6586x->gpio.get = tps6586x_gpio_get;
ret = gpiochip_add(&tps6586x->gpio);
if (ret)
dev_warn(tps6586x->dev, "GPIO registration failed: %d\n", ret);
}
static int __remove_subdev(struct device *dev, void *unused)
{
platform_device_unregister(to_platform_device(dev));
return 0;
}
static int tps6586x_remove_subdevs(struct tps6586x *tps6586x)
{
return device_for_each_child(tps6586x->dev, NULL, __remove_subdev);
}
static int __devinit tps6586x_add_subdevs(struct tps6586x *tps6586x,
struct tps6586x_platform_data *pdata)
{
struct tps6586x_subdev_info *subdev;
struct platform_device *pdev;
int i, ret = 0;
for (i = 0; i < pdata->num_subdevs; i++) {
subdev = &pdata->subdevs[i];
pdev = platform_device_alloc(subdev->name, subdev->id);
pdev->dev.parent = tps6586x->dev;
pdev->dev.platform_data = subdev->platform_data;
ret = platform_device_add(pdev);
if (ret)
goto failed;
}
return 0;
failed:
tps6586x_remove_subdevs(tps6586x);
return ret;
}
static int __devinit tps6586x_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct tps6586x_platform_data *pdata = client->dev.platform_data;
struct tps6586x *tps6586x;
int ret;
if (!pdata) {
dev_err(&client->dev, "tps6586x requires platform data\n");
return -ENOTSUPP;
}
ret = i2c_smbus_read_byte_data(client, TPS6586X_VERSIONCRC);
if (ret < 0) {
dev_err(&client->dev, "Chip ID read failed: %d\n", ret);
return -EIO;
}
if (ret != TPS658621A_VERSIONCRC) {
dev_err(&client->dev, "Unsupported chip ID: %x\n", ret);
return -ENODEV;
}
tps6586x = kzalloc(sizeof(struct tps6586x), GFP_KERNEL);
if (tps6586x == NULL)
return -ENOMEM;
tps6586x->client = client;
tps6586x->dev = &client->dev;
i2c_set_clientdata(client, tps6586x);
mutex_init(&tps6586x->lock);
ret = tps6586x_add_subdevs(tps6586x, pdata);
if (ret) {
dev_err(&client->dev, "add devices failed: %d\n", ret);
goto err_add_devs;
}
tps6586x_gpio_init(tps6586x, pdata->gpio_base);
return 0;
err_add_devs:
kfree(tps6586x);
return ret;
}
static int __devexit tps6586x_i2c_remove(struct i2c_client *client)
{
return 0;
}
static const struct i2c_device_id tps6586x_id_table[] = {
{ "tps6586x", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, tps6586x_id_table);
static struct i2c_driver tps6586x_driver = {
.driver = {
.name = "tps6586x",
.owner = THIS_MODULE,
},
.probe = tps6586x_i2c_probe,
.remove = __devexit_p(tps6586x_i2c_remove),
.id_table = tps6586x_id_table,
};
static int __init tps6586x_init(void)
{
return i2c_add_driver(&tps6586x_driver);
}
subsys_initcall(tps6586x_init);
static void __exit tps6586x_exit(void)
{
i2c_del_driver(&tps6586x_driver);
}
module_exit(tps6586x_exit);
MODULE_DESCRIPTION("TPS6586X core driver");
MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
MODULE_LICENSE("GPL");

163
drivers/mfd/twl6030-pwm.c Normal file
View File

@ -0,0 +1,163 @@
/*
* twl6030_pwm.c
* Driver for PHOENIX (TWL6030) Pulse Width Modulator
*
* Copyright (C) 2010 Texas Instruments
* Author: Hemanth V <hemanthv@ti.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/i2c/twl.h>
#include <linux/slab.h>
#define LED_PWM_CTRL1 0xF4
#define LED_PWM_CTRL2 0xF5
/* Max value for CTRL1 register */
#define PWM_CTRL1_MAX 255
/* Pull down disable */
#define PWM_CTRL2_DIS_PD (1 << 6)
/* Current control 2.5 milli Amps */
#define PWM_CTRL2_CURR_02 (2 << 4)
/* LED supply source */
#define PWM_CTRL2_SRC_VAC (1 << 2)
/* LED modes */
#define PWM_CTRL2_MODE_HW (0 << 0)
#define PWM_CTRL2_MODE_SW (1 << 0)
#define PWM_CTRL2_MODE_DIS (2 << 0)
#define PWM_CTRL2_MODE_MASK 0x3
struct pwm_device {
const char *label;
unsigned int pwm_id;
};
int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
{
u8 duty_cycle;
int ret;
if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
return -EINVAL;
duty_cycle = (duty_ns * PWM_CTRL1_MAX) / period_ns;
ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, duty_cycle, LED_PWM_CTRL1);
if (ret < 0) {
pr_err("%s: Failed to configure PWM, Error %d\n",
pwm->label, ret);
return ret;
}
return 0;
}
EXPORT_SYMBOL(pwm_config);
int pwm_enable(struct pwm_device *pwm)
{
u8 val;
int ret;
ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
if (ret < 0) {
pr_err("%s: Failed to enable PWM, Error %d\n", pwm->label, ret);
return ret;
}
/* Change mode to software control */
val &= ~PWM_CTRL2_MODE_MASK;
val |= PWM_CTRL2_MODE_SW;
ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
if (ret < 0) {
pr_err("%s: Failed to enable PWM, Error %d\n", pwm->label, ret);
return ret;
}
twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
return 0;
}
EXPORT_SYMBOL(pwm_enable);
void pwm_disable(struct pwm_device *pwm)
{
u8 val;
int ret;
ret = twl_i2c_read_u8(TWL6030_MODULE_ID1, &val, LED_PWM_CTRL2);
if (ret < 0) {
pr_err("%s: Failed to disable PWM, Error %d\n",
pwm->label, ret);
return;
}
val &= ~PWM_CTRL2_MODE_MASK;
val |= PWM_CTRL2_MODE_HW;
ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
if (ret < 0) {
pr_err("%s: Failed to disable PWM, Error %d\n",
pwm->label, ret);
return;
}
return;
}
EXPORT_SYMBOL(pwm_disable);
struct pwm_device *pwm_request(int pwm_id, const char *label)
{
u8 val;
int ret;
struct pwm_device *pwm;
pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);
if (pwm == NULL) {
pr_err("%s: failed to allocate memory\n", label);
return NULL;
}
pwm->label = label;
pwm->pwm_id = pwm_id;
/* Configure PWM */
val = PWM_CTRL2_DIS_PD | PWM_CTRL2_CURR_02 | PWM_CTRL2_SRC_VAC |
PWM_CTRL2_MODE_HW;
ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, val, LED_PWM_CTRL2);
if (ret < 0) {
pr_err("%s: Failed to configure PWM, Error %d\n",
pwm->label, ret);
kfree(pwm);
return NULL;
}
return pwm;
}
EXPORT_SYMBOL(pwm_request);
void pwm_free(struct pwm_device *pwm)
{
pwm_disable(pwm);
kfree(pwm);
}
EXPORT_SYMBOL(pwm_free);

View File

@ -114,7 +114,7 @@ static int ucb1400_core_probe(struct device *dev)
err3:
platform_device_put(ucb->ucb1400_ts);
err2:
platform_device_unregister(ucb->ucb1400_gpio);
platform_device_del(ucb->ucb1400_gpio);
err1:
platform_device_put(ucb->ucb1400_gpio);
err0:

View File

@ -95,6 +95,7 @@ enum wm831x_parent {
WM8311 = 0x8311,
WM8312 = 0x8312,
WM8320 = 0x8320,
WM8321 = 0x8321,
};
static int wm831x_reg_locked(struct wm831x *wm831x, unsigned short reg)
@ -1533,6 +1534,12 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
dev_info(wm831x->dev, "WM8320 revision %c\n", 'A' + rev);
break;
case WM8321:
parent = WM8321;
wm831x->num_gpio = 12;
dev_info(wm831x->dev, "WM8321 revision %c\n", 'A' + rev);
break;
default:
dev_err(wm831x->dev, "Unknown WM831x device %04x\n", ret);
ret = -EINVAL;
@ -1607,6 +1614,12 @@ static int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
NULL, 0);
break;
case WM8321:
ret = mfd_add_devices(wm831x->dev, -1,
wm8320_devs, ARRAY_SIZE(wm8320_devs),
NULL, 0);
break;
default:
/* If this happens the bus probe function is buggy */
BUG();
@ -1744,10 +1757,8 @@ static int wm831x_i2c_probe(struct i2c_client *i2c,
struct wm831x *wm831x;
wm831x = kzalloc(sizeof(struct wm831x), GFP_KERNEL);
if (wm831x == NULL) {
kfree(i2c);
if (wm831x == NULL)
return -ENOMEM;
}
i2c_set_clientdata(i2c, wm831x);
wm831x->dev = &i2c->dev;
@ -1779,6 +1790,7 @@ static const struct i2c_device_id wm831x_i2c_id[] = {
{ "wm8311", WM8311 },
{ "wm8312", WM8312 },
{ "wm8320", WM8320 },
{ "wm8321", WM8321 },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm831x_i2c_id);

View File

@ -536,6 +536,7 @@ static int wm8350_create_cache(struct wm8350 *wm8350, int type, int mode)
}
out:
kfree(wm8350->reg_cache);
return ret;
}
@ -700,7 +701,7 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
ret = wm8350_irq_init(wm8350, irq, pdata);
if (ret < 0)
goto err;
goto err_free;
if (wm8350->irq_base) {
ret = request_threaded_irq(wm8350->irq_base +
@ -738,8 +739,9 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
err_irq:
wm8350_irq_exit(wm8350);
err:
err_free:
kfree(wm8350->reg_cache);
err:
return ret;
}
EXPORT_SYMBOL_GPL(wm8350_device_init);

View File

@ -326,8 +326,10 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
ARRAY_SIZE(wm8994_main_supplies),
GFP_KERNEL);
if (!wm8994->supplies)
if (!wm8994->supplies) {
ret = -ENOMEM;
goto err;
}
for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++)
wm8994->supplies[i].supply = wm8994_main_supplies[i];
@ -495,10 +497,8 @@ static int wm8994_i2c_probe(struct i2c_client *i2c,
struct wm8994 *wm8994;
wm8994 = kzalloc(sizeof(struct wm8994), GFP_KERNEL);
if (wm8994 == NULL) {
kfree(i2c);
if (wm8994 == NULL)
return -ENOMEM;
}
i2c_set_clientdata(i2c, wm8994);
wm8994->dev = &i2c->dev;

View File

@ -0,0 +1,32 @@
#ifndef __LINUX_JZ4740_ADC
#define __LINUX_JZ4740_ADC
#include <linux/device.h>
/*
* jz4740_adc_set_config - Configure a JZ4740 adc device
* @dev: Pointer to a jz4740-adc device
* @mask: Mask for the config value to be set
* @val: Value to be set
*
* This function can be used by the JZ4740 ADC mfd cells to configure their
* options in the shared config register.
*/
int jz4740_adc_set_config(struct device *dev, uint32_t mask, uint32_t val);
#define JZ_ADC_CONFIG_SPZZ BIT(31)
#define JZ_ADC_CONFIG_EX_IN BIT(30)
#define JZ_ADC_CONFIG_DNUM_MASK (0x7 << 16)
#define JZ_ADC_CONFIG_DMA_ENABLE BIT(15)
#define JZ_ADC_CONFIG_XYZ_MASK (0x2 << 13)
#define JZ_ADC_CONFIG_SAMPLE_NUM_MASK (0x7 << 10)
#define JZ_ADC_CONFIG_CLKDIV_MASK (0xf << 5)
#define JZ_ADC_CONFIG_BAT_MB BIT(4)
#define JZ_ADC_CONFIG_DNUM(dnum) ((dnum) << 16)
#define JZ_ADC_CONFIG_XYZ_OFFSET(dnum) ((xyz) << 13)
#define JZ_ADC_CONFIG_SAMPLE_NUM(x) ((x) << 10)
#define JZ_ADC_CONFIG_CLKDIV(div) ((div) << 5)
#endif

View File

@ -1,220 +0,0 @@
/*
* Copyright 2009 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
*
* Initial development of this code was funded by
* Phytec Messtechnik GmbH, http://www.phytec.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __LINUX_MFD_MC13783_PRIV_H
#define __LINUX_MFD_MC13783_PRIV_H
#include <linux/platform_device.h>
#include <linux/mfd/mc13783.h>
#include <linux/mutex.h>
#include <linux/interrupt.h>
struct mc13783 {
struct spi_device *spidev;
struct mutex lock;
int irq;
int flags;
irq_handler_t irqhandler[MC13783_NUM_IRQ];
void *irqdata[MC13783_NUM_IRQ];
/* XXX these should go as platformdata to the regulator subdevice */
struct mc13783_regulator_init_data *regulators;
int num_regulators;
};
#define MC13783_REG_INTERRUPT_STATUS_0 0
#define MC13783_REG_INTERRUPT_MASK_0 1
#define MC13783_REG_INTERRUPT_SENSE_0 2
#define MC13783_REG_INTERRUPT_STATUS_1 3
#define MC13783_REG_INTERRUPT_MASK_1 4
#define MC13783_REG_INTERRUPT_SENSE_1 5
#define MC13783_REG_POWER_UP_MODE_SENSE 6
#define MC13783_REG_REVISION 7
#define MC13783_REG_SEMAPHORE 8
#define MC13783_REG_ARBITRATION_PERIPHERAL_AUDIO 9
#define MC13783_REG_ARBITRATION_SWITCHERS 10
#define MC13783_REG_ARBITRATION_REGULATORS_0 11
#define MC13783_REG_ARBITRATION_REGULATORS_1 12
#define MC13783_REG_POWER_CONTROL_0 13
#define MC13783_REG_POWER_CONTROL_1 14
#define MC13783_REG_POWER_CONTROL_2 15
#define MC13783_REG_REGEN_ASSIGNMENT 16
#define MC13783_REG_CONTROL_SPARE 17
#define MC13783_REG_MEMORY_A 18
#define MC13783_REG_MEMORY_B 19
#define MC13783_REG_RTC_TIME 20
#define MC13783_REG_RTC_ALARM 21
#define MC13783_REG_RTC_DAY 22
#define MC13783_REG_RTC_DAY_ALARM 23
#define MC13783_REG_SWITCHERS_0 24
#define MC13783_REG_SWITCHERS_1 25
#define MC13783_REG_SWITCHERS_2 26
#define MC13783_REG_SWITCHERS_3 27
#define MC13783_REG_SWITCHERS_4 28
#define MC13783_REG_SWITCHERS_5 29
#define MC13783_REG_REGULATOR_SETTING_0 30
#define MC13783_REG_REGULATOR_SETTING_1 31
#define MC13783_REG_REGULATOR_MODE_0 32
#define MC13783_REG_REGULATOR_MODE_1 33
#define MC13783_REG_POWER_MISCELLANEOUS 34
#define MC13783_REG_POWER_SPARE 35
#define MC13783_REG_AUDIO_RX_0 36
#define MC13783_REG_AUDIO_RX_1 37
#define MC13783_REG_AUDIO_TX 38
#define MC13783_REG_AUDIO_SSI_NETWORK 39
#define MC13783_REG_AUDIO_CODEC 40
#define MC13783_REG_AUDIO_STEREO_DAC 41
#define MC13783_REG_AUDIO_SPARE 42
#define MC13783_REG_ADC_0 43
#define MC13783_REG_ADC_1 44
#define MC13783_REG_ADC_2 45
#define MC13783_REG_ADC_3 46
#define MC13783_REG_ADC_4 47
#define MC13783_REG_CHARGER 48
#define MC13783_REG_USB 49
#define MC13783_REG_CHARGE_USB_SPARE 50
#define MC13783_REG_LED_CONTROL_0 51
#define MC13783_REG_LED_CONTROL_1 52
#define MC13783_REG_LED_CONTROL_2 53
#define MC13783_REG_LED_CONTROL_3 54
#define MC13783_REG_LED_CONTROL_4 55
#define MC13783_REG_LED_CONTROL_5 56
#define MC13783_REG_SPARE 57
#define MC13783_REG_TRIM_0 58
#define MC13783_REG_TRIM_1 59
#define MC13783_REG_TEST_0 60
#define MC13783_REG_TEST_1 61
#define MC13783_REG_TEST_2 62
#define MC13783_REG_TEST_3 63
#define MC13783_REG_NB 64
/*
* Reg Regulator Mode 0
*/
#define MC13783_REGCTRL_VAUDIO_EN (1 << 0)
#define MC13783_REGCTRL_VAUDIO_STBY (1 << 1)
#define MC13783_REGCTRL_VAUDIO_MODE (1 << 2)
#define MC13783_REGCTRL_VIOHI_EN (1 << 3)
#define MC13783_REGCTRL_VIOHI_STBY (1 << 4)
#define MC13783_REGCTRL_VIOHI_MODE (1 << 5)
#define MC13783_REGCTRL_VIOLO_EN (1 << 6)
#define MC13783_REGCTRL_VIOLO_STBY (1 << 7)
#define MC13783_REGCTRL_VIOLO_MODE (1 << 8)
#define MC13783_REGCTRL_VDIG_EN (1 << 9)
#define MC13783_REGCTRL_VDIG_STBY (1 << 10)
#define MC13783_REGCTRL_VDIG_MODE (1 << 11)
#define MC13783_REGCTRL_VGEN_EN (1 << 12)
#define MC13783_REGCTRL_VGEN_STBY (1 << 13)
#define MC13783_REGCTRL_VGEN_MODE (1 << 14)
#define MC13783_REGCTRL_VRFDIG_EN (1 << 15)
#define MC13783_REGCTRL_VRFDIG_STBY (1 << 16)
#define MC13783_REGCTRL_VRFDIG_MODE (1 << 17)
#define MC13783_REGCTRL_VRFREF_EN (1 << 18)
#define MC13783_REGCTRL_VRFREF_STBY (1 << 19)
#define MC13783_REGCTRL_VRFREF_MODE (1 << 20)
#define MC13783_REGCTRL_VRFCP_EN (1 << 21)
#define MC13783_REGCTRL_VRFCP_STBY (1 << 22)
#define MC13783_REGCTRL_VRFCP_MODE (1 << 23)
/*
* Reg Regulator Mode 1
*/
#define MC13783_REGCTRL_VSIM_EN (1 << 0)
#define MC13783_REGCTRL_VSIM_STBY (1 << 1)
#define MC13783_REGCTRL_VSIM_MODE (1 << 2)
#define MC13783_REGCTRL_VESIM_EN (1 << 3)
#define MC13783_REGCTRL_VESIM_STBY (1 << 4)
#define MC13783_REGCTRL_VESIM_MODE (1 << 5)
#define MC13783_REGCTRL_VCAM_EN (1 << 6)
#define MC13783_REGCTRL_VCAM_STBY (1 << 7)
#define MC13783_REGCTRL_VCAM_MODE (1 << 8)
#define MC13783_REGCTRL_VRFBG_EN (1 << 9)
#define MC13783_REGCTRL_VRFBG_STBY (1 << 10)
#define MC13783_REGCTRL_VVIB_EN (1 << 11)
#define MC13783_REGCTRL_VRF1_EN (1 << 12)
#define MC13783_REGCTRL_VRF1_STBY (1 << 13)
#define MC13783_REGCTRL_VRF1_MODE (1 << 14)
#define MC13783_REGCTRL_VRF2_EN (1 << 15)
#define MC13783_REGCTRL_VRF2_STBY (1 << 16)
#define MC13783_REGCTRL_VRF2_MODE (1 << 17)
#define MC13783_REGCTRL_VMMC1_EN (1 << 18)
#define MC13783_REGCTRL_VMMC1_STBY (1 << 19)
#define MC13783_REGCTRL_VMMC1_MODE (1 << 20)
#define MC13783_REGCTRL_VMMC2_EN (1 << 21)
#define MC13783_REGCTRL_VMMC2_STBY (1 << 22)
#define MC13783_REGCTRL_VMMC2_MODE (1 << 23)
/*
* Reg Regulator Misc.
*/
#define MC13783_REGCTRL_GPO1_EN (1 << 6)
#define MC13783_REGCTRL_GPO2_EN (1 << 8)
#define MC13783_REGCTRL_GPO3_EN (1 << 10)
#define MC13783_REGCTRL_GPO4_EN (1 << 12)
#define MC13783_REGCTRL_VIBPINCTRL (1 << 14)
/*
* Reg Switcher 4
*/
#define MC13783_SWCTRL_SW1A_MODE (1 << 0)
#define MC13783_SWCTRL_SW1A_STBY_MODE (1 << 2)
#define MC13783_SWCTRL_SW1A_DVS_SPEED (1 << 6)
#define MC13783_SWCTRL_SW1A_PANIC_MODE (1 << 8)
#define MC13783_SWCTRL_SW1A_SOFTSTART (1 << 9)
#define MC13783_SWCTRL_SW1B_MODE (1 << 10)
#define MC13783_SWCTRL_SW1B_STBY_MODE (1 << 12)
#define MC13783_SWCTRL_SW1B_DVS_SPEED (1 << 14)
#define MC13783_SWCTRL_SW1B_PANIC_MODE (1 << 16)
#define MC13783_SWCTRL_SW1B_SOFTSTART (1 << 17)
#define MC13783_SWCTRL_PLL_EN (1 << 18)
#define MC13783_SWCTRL_PLL_FACTOR (1 << 19)
/*
* Reg Switcher 5
*/
#define MC13783_SWCTRL_SW2A_MODE (1 << 0)
#define MC13783_SWCTRL_SW2A_STBY_MODE (1 << 2)
#define MC13783_SWCTRL_SW2A_DVS_SPEED (1 << 6)
#define MC13783_SWCTRL_SW2A_PANIC_MODE (1 << 8)
#define MC13783_SWCTRL_SW2A_SOFTSTART (1 << 9)
#define MC13783_SWCTRL_SW2B_MODE (1 << 10)
#define MC13783_SWCTRL_SW2B_STBY_MODE (1 << 12)
#define MC13783_SWCTRL_SW2B_DVS_SPEED (1 << 14)
#define MC13783_SWCTRL_SW2B_PANIC_MODE (1 << 16)
#define MC13783_SWCTRL_SW2B_SOFTSTART (1 << 17)
#define MC13783_SWSET_SW3 (1 << 18)
#define MC13783_SWCTRL_SW3_EN (1 << 20)
#define MC13783_SWCTRL_SW3_STBY (1 << 21)
#define MC13783_SWCTRL_SW3_MODE (1 << 22)
static inline int mc13783_set_bits(struct mc13783 *mc13783, unsigned int offset,
u32 mask, u32 val)
{
int ret;
mc13783_lock(mc13783);
ret = mc13783_reg_rmw(mc13783, offset, mask, val);
mc13783_unlock(mc13783);
return ret;
}
#endif /* __LINUX_MFD_MC13783_PRIV_H */

View File

@ -21,6 +21,8 @@ int mc13783_reg_write(struct mc13783 *mc13783, unsigned int offset, u32 val);
int mc13783_reg_rmw(struct mc13783 *mc13783, unsigned int offset,
u32 mask, u32 val);
int mc13783_get_flags(struct mc13783 *mc13783);
int mc13783_irq_request(struct mc13783 *mc13783, int irq,
irq_handler_t handler, const char *name, void *dev);
int mc13783_irq_request_nounmask(struct mc13783 *mc13783, int irq,

201
include/linux/mfd/stmpe.h Normal file
View File

@ -0,0 +1,201 @@
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License, version 2
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
*/
#ifndef __LINUX_MFD_STMPE_H
#define __LINUX_MFD_STMPE_H
#include <linux/device.h>
enum stmpe_block {
STMPE_BLOCK_GPIO = 1 << 0,
STMPE_BLOCK_KEYPAD = 1 << 1,
STMPE_BLOCK_TOUCHSCREEN = 1 << 2,
STMPE_BLOCK_ADC = 1 << 3,
STMPE_BLOCK_PWM = 1 << 4,
STMPE_BLOCK_ROTATOR = 1 << 5,
};
enum stmpe_partnum {
STMPE811,
STMPE1601,
STMPE2401,
STMPE2403,
};
/*
* For registers whose locations differ on variants, the correct address is
* obtained by indexing stmpe->regs with one of the following.
*/
enum {
STMPE_IDX_CHIP_ID,
STMPE_IDX_ICR_LSB,
STMPE_IDX_IER_LSB,
STMPE_IDX_ISR_MSB,
STMPE_IDX_GPMR_LSB,
STMPE_IDX_GPSR_LSB,
STMPE_IDX_GPCR_LSB,
STMPE_IDX_GPDR_LSB,
STMPE_IDX_GPEDR_MSB,
STMPE_IDX_GPRER_LSB,
STMPE_IDX_GPFER_LSB,
STMPE_IDX_GPAFR_U_MSB,
STMPE_IDX_IEGPIOR_LSB,
STMPE_IDX_ISGPIOR_MSB,
STMPE_IDX_MAX,
};
struct stmpe_variant_info;
/**
* struct stmpe - STMPE MFD structure
* @lock: lock protecting I/O operations
* @irq_lock: IRQ bus lock
* @dev: device, mostly for dev_dbg()
* @i2c: i2c client
* @variant: the detected STMPE model number
* @regs: list of addresses of registers which are at different addresses on
* different variants. Indexed by one of STMPE_IDX_*.
* @irq_base: starting IRQ number for internal IRQs
* @num_gpios: number of gpios, differs for variants
* @ier: cache of IER registers for bus_lock
* @oldier: cache of IER registers for bus_lock
* @pdata: platform data
*/
struct stmpe {
struct mutex lock;
struct mutex irq_lock;
struct device *dev;
struct i2c_client *i2c;
enum stmpe_partnum partnum;
struct stmpe_variant_info *variant;
const u8 *regs;
int irq_base;
int num_gpios;
u8 ier[2];
u8 oldier[2];
struct stmpe_platform_data *pdata;
};
extern int stmpe_reg_write(struct stmpe *stmpe, u8 reg, u8 data);
extern int stmpe_reg_read(struct stmpe *stmpe, u8 reg);
extern int stmpe_block_read(struct stmpe *stmpe, u8 reg, u8 length,
u8 *values);
extern int stmpe_block_write(struct stmpe *stmpe, u8 reg, u8 length,
const u8 *values);
extern int stmpe_set_bits(struct stmpe *stmpe, u8 reg, u8 mask, u8 val);
extern int stmpe_set_altfunc(struct stmpe *stmpe, u32 pins,
enum stmpe_block block);
extern int stmpe_enable(struct stmpe *stmpe, unsigned int blocks);
extern int stmpe_disable(struct stmpe *stmpe, unsigned int blocks);
struct matrix_keymap_data;
/**
* struct stmpe_keypad_platform_data - STMPE keypad platform data
* @keymap_data: key map table and size
* @debounce_ms: debounce interval, in ms. Maximum is
* %STMPE_KEYPAD_MAX_DEBOUNCE.
* @scan_count: number of key scanning cycles to confirm key data.
* Maximum is %STMPE_KEYPAD_MAX_SCAN_COUNT.
* @no_autorepeat: disable key autorepeat
*/
struct stmpe_keypad_platform_data {
struct matrix_keymap_data *keymap_data;
unsigned int debounce_ms;
unsigned int scan_count;
bool no_autorepeat;
};
/**
* struct stmpe_gpio_platform_data - STMPE GPIO platform data
* @gpio_base: first gpio number assigned. A maximum of
* %STMPE_NR_GPIOS GPIOs will be allocated.
*/
struct stmpe_gpio_platform_data {
int gpio_base;
void (*setup)(struct stmpe *stmpe, unsigned gpio_base);
void (*remove)(struct stmpe *stmpe, unsigned gpio_base);
};
/**
* struct stmpe_ts_platform_data - stmpe811 touch screen controller platform
* data
* @sample_time: ADC converstion time in number of clock.
* (0 -> 36 clocks, 1 -> 44 clocks, 2 -> 56 clocks, 3 -> 64 clocks,
* 4 -> 80 clocks, 5 -> 96 clocks, 6 -> 144 clocks),
* recommended is 4.
* @mod_12b: ADC Bit mode (0 -> 10bit ADC, 1 -> 12bit ADC)
* @ref_sel: ADC reference source
* (0 -> internal reference, 1 -> external reference)
* @adc_freq: ADC Clock speed
* (0 -> 1.625 MHz, 1 -> 3.25 MHz, 2 || 3 -> 6.5 MHz)
* @ave_ctrl: Sample average control
* (0 -> 1 sample, 1 -> 2 samples, 2 -> 4 samples, 3 -> 8 samples)
* @touch_det_delay: Touch detect interrupt delay
* (0 -> 10 us, 1 -> 50 us, 2 -> 100 us, 3 -> 500 us,
* 4-> 1 ms, 5 -> 5 ms, 6 -> 10 ms, 7 -> 50 ms)
* recommended is 3
* @settling: Panel driver settling time
* (0 -> 10 us, 1 -> 100 us, 2 -> 500 us, 3 -> 1 ms,
* 4 -> 5 ms, 5 -> 10 ms, 6 for 50 ms, 7 -> 100 ms)
* recommended is 2
* @fraction_z: Length of the fractional part in z
* (fraction_z ([0..7]) = Count of the fractional part)
* recommended is 7
* @i_drive: current limit value of the touchscreen drivers
* (0 -> 20 mA typical 35 mA max, 1 -> 50 mA typical 80 mA max)
*
* */
struct stmpe_ts_platform_data {
u8 sample_time;
u8 mod_12b;
u8 ref_sel;
u8 adc_freq;
u8 ave_ctrl;
u8 touch_det_delay;
u8 settling;
u8 fraction_z;
u8 i_drive;
};
/**
* struct stmpe_platform_data - STMPE platform data
* @id: device id to distinguish between multiple STMPEs on the same board
* @blocks: bitmask of blocks to enable (use STMPE_BLOCK_*)
* @irq_trigger: IRQ trigger to use for the interrupt to the host
* @irq_invert_polarity: IRQ line is connected with reversed polarity
* @autosleep: bool to enable/disable stmpe autosleep
* @autosleep_timeout: inactivity timeout in milliseconds for autosleep
* @irq_base: base IRQ number. %STMPE_NR_IRQS irqs will be used, or
* %STMPE_NR_INTERNAL_IRQS if the GPIO driver is not used.
* @gpio: GPIO-specific platform data
* @keypad: keypad-specific platform data
* @ts: touchscreen-specific platform data
*/
struct stmpe_platform_data {
int id;
unsigned int blocks;
int irq_base;
unsigned int irq_trigger;
bool irq_invert_polarity;
bool autosleep;
int autosleep_timeout;
struct stmpe_gpio_platform_data *gpio;
struct stmpe_keypad_platform_data *keypad;
struct stmpe_ts_platform_data *ts;
};
#define STMPE_NR_INTERNAL_IRQS 9
#define STMPE_INT_GPIO(x) (STMPE_NR_INTERNAL_IRQS + (x))
#define STMPE_NR_GPIOS 24
#define STMPE_NR_IRQS STMPE_INT_GPIO(STMPE_NR_GPIOS)
#endif

View File

@ -0,0 +1,47 @@
#ifndef __LINUX_MFD_TPS6586X_H
#define __LINUX_MFD_TPS6586X_H
enum {
TPS6586X_ID_SM_0,
TPS6586X_ID_SM_1,
TPS6586X_ID_SM_2,
TPS6586X_ID_LDO_0,
TPS6586X_ID_LDO_1,
TPS6586X_ID_LDO_2,
TPS6586X_ID_LDO_3,
TPS6586X_ID_LDO_4,
TPS6586X_ID_LDO_5,
TPS6586X_ID_LDO_6,
TPS6586X_ID_LDO_7,
TPS6586X_ID_LDO_8,
TPS6586X_ID_LDO_9,
TPS6586X_ID_LDO_RTC,
};
struct tps6586x_subdev_info {
int id;
const char *name;
void *platform_data;
};
struct tps6586x_platform_data {
int num_subdevs;
struct tps6586x_subdev_info *subdevs;
int gpio_base;
};
/*
* NOTE: the functions below are not intended for use outside
* of the TPS6586X sub-device drivers
*/
extern int tps6586x_write(struct device *dev, int reg, uint8_t val);
extern int tps6586x_writes(struct device *dev, int reg, int len, uint8_t *val);
extern int tps6586x_read(struct device *dev, int reg, uint8_t *val);
extern int tps6586x_reads(struct device *dev, int reg, int len, uint8_t *val);
extern int tps6586x_set_bits(struct device *dev, int reg, uint8_t bit_mask);
extern int tps6586x_clr_bits(struct device *dev, int reg, uint8_t bit_mask);
extern int tps6586x_update(struct device *dev, int reg, uint8_t val,
uint8_t mask);
#endif /*__LINUX_MFD_TPS6586X_H */

View File

@ -36,6 +36,10 @@
#define WM8994_GP_FN_WSEQ_STATUS 16
#define WM8994_GP_FN_FIFO_ERROR 17
#define WM8994_GP_FN_OPCLK 18
#define WM8994_GP_FN_THW 19
#define WM8994_GP_FN_DCS_DONE 20
#define WM8994_GP_FN_FLL1_OUT 21
#define WM8994_GP_FN_FLL2_OUT 22
#define WM8994_GPN_DIR 0x8000 /* GPN_DIR */
#define WM8994_GPN_DIR_MASK 0x8000 /* GPN_DIR */