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
43 changed files with 3933 additions and 339 deletions
+7
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
+1
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
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>");
+32
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,
};
+13 -4
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);
+10
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
+1
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
+386
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>");
+10
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
+1
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
+397
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);
+38 -46
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;
}
+64 -1
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"
+4
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
+8 -8
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;
}
+12 -11
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;
+6 -1
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;
}
+1 -1
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;
}
+4 -2
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;
+1
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>

Some files were not shown because too many files have changed in this diff Show More