2011-03-07 15:55:51

by Haojian Zhuang

[permalink] [raw]
Subject: [PATCH] mfd: adopt mfd_data in 88pm860x backlight

Copy 88pm860x platform data into different mfd_data structure for
backlight driver. So move the identification of device node from
backlight driver to mfd driver.

Signed-off-by: Haojian Zhuang <[email protected]>
---
drivers/mfd/88pm860x-core.c | 96 +++++++++++++++++---------------
drivers/video/backlight/88pm860x_bl.c | 34 +++---------
include/linux/mfd/88pm860x.h | 2 +-
3 files changed, 60 insertions(+), 72 deletions(-)

diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index 793300c..a88967a 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -20,12 +20,19 @@

#define INT_STATUS_NUM 3

-char pm860x_backlight_name[][MFD_NAME_SIZE] = {
- "backlight-0",
- "backlight-1",
- "backlight-2",
+static struct resource bk_resources[] __initdata = {
+ {PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,},
+ {PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,},
+ {PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,},
};
-EXPORT_SYMBOL(pm860x_backlight_name);
+
+static struct mfd_cell bk_devs[] __initdata = {
+ {"88pm860x-backlight", 0,},
+ {"88pm860x-backlight", 1,},
+ {"88pm860x-backlight", 2,},
+};
+
+static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)];

char pm860x_led_name[][MFD_NAME_SIZE] = {
"led0-red",
@@ -37,34 +44,6 @@ char pm860x_led_name[][MFD_NAME_SIZE] = {
};
EXPORT_SYMBOL(pm860x_led_name);

-#define PM8606_BACKLIGHT_RESOURCE(_i, _x) \
-{ \
- .name = pm860x_backlight_name[_i], \
- .start = PM8606_##_x, \
- .end = PM8606_##_x, \
- .flags = IORESOURCE_IO, \
-}
-
-static struct resource backlight_resources[] = {
- PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT1, WLED1A),
- PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT2, WLED2A),
- PM8606_BACKLIGHT_RESOURCE(PM8606_BACKLIGHT3, WLED3A),
-};
-
-#define PM8606_BACKLIGHT_DEVS(_i) \
-{ \
- .name = "88pm860x-backlight", \
- .num_resources = 1, \
- .resources = &backlight_resources[_i], \
- .id = _i, \
-}
-
-static struct mfd_cell backlight_devs[] = {
- PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT1),
- PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT2),
- PM8606_BACKLIGHT_DEVS(PM8606_BACKLIGHT3),
-};
-
#define PM8606_LED_RESOURCE(_i, _x) \
{ \
.name = pm860x_led_name[_i], \
@@ -595,23 +574,49 @@ static void device_irq_exit(struct pm860x_chip *chip)
free_irq(chip->core_irq, chip);
}

+static void __devinit device_bk_init(struct pm860x_chip *chip,
+ struct i2c_client *i2c,
+ struct pm860x_platform_data *pdata)
+{
+ int ret;
+ int i, j, id;
+
+ if ((pdata == NULL) || (pdata->backlight == NULL))
+ return;
+
+ if (pdata->num_backlights > ARRAY_SIZE(bk_devs))
+ pdata->num_backlights = ARRAY_SIZE(bk_devs);
+
+ for (i = 0; i < pdata->num_backlights; i++) {
+ memcpy(&bk_pdata[i], &pdata->backlight[i],
+ sizeof(struct pm860x_backlight_pdata));
+ bk_devs[i].mfd_data = &bk_pdata[i];
+
+ for (j = 0; j < ARRAY_SIZE(bk_devs); j++) {
+ id = bk_resources[j].start;
+ if (bk_pdata[i].flags != id)
+ continue;
+
+ bk_devs[i].num_resources = 1;
+ bk_devs[i].resources = &bk_resources[j];
+ ret = mfd_add_devices(chip->dev, 0,
+ &bk_devs[i], 1,
+ &bk_resources[j], 0);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add "
+ "backlight subdev\n");
+ return;
+ }
+ }
+ }
+}
+
static void __devinit device_8606_init(struct pm860x_chip *chip,
struct i2c_client *i2c,
struct pm860x_platform_data *pdata)
{
int ret;

- if (pdata && pdata->backlight) {
- ret = mfd_add_devices(chip->dev, 0, &backlight_devs[0],
- ARRAY_SIZE(backlight_devs),
- &backlight_resources[0], 0);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to add backlight "
- "subdev\n");
- goto out_dev;
- }
- }
-
if (pdata && pdata->led) {
ret = mfd_add_devices(chip->dev, 0, &led_devs[0],
ARRAY_SIZE(led_devs),
@@ -624,7 +629,6 @@ static void __devinit device_8606_init(struct pm860x_chip *chip,
}
return;
out_dev:
- mfd_remove_devices(chip->dev);
device_irq_exit(chip);
}

@@ -743,6 +747,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,

switch (chip->id) {
case CHIP_PM8606:
+ device_bk_init(chip, chip->client, pdata);
device_8606_init(chip, chip->client, pdata);
break;
case CHIP_PM8607:
@@ -753,6 +758,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
if (chip->companion) {
switch (chip->id) {
case CHIP_PM8607:
+ device_bk_init(chip, chip->companion, pdata);
device_8606_init(chip, chip->companion, pdata);
break;
case CHIP_PM8606:
diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c
index b224396..552825c 100644
--- a/drivers/video/backlight/88pm860x_bl.c
+++ b/drivers/video/backlight/88pm860x_bl.c
@@ -12,11 +12,12 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <linux/fb.h>
#include <linux/i2c.h>
#include <linux/backlight.h>
+#include <linux/mfd/core.h>
#include <linux/mfd/88pm860x.h>
-#include <linux/slab.h>

#define MAX_BRIGHTNESS (0xFF)
#define MIN_BRIGHTNESS (0)
@@ -161,32 +162,13 @@ static const struct backlight_ops pm860x_backlight_ops = {
.get_brightness = pm860x_backlight_get_brightness,
};

-static int __check_device(struct pm860x_backlight_pdata *pdata, char *name)
-{
- struct pm860x_backlight_pdata *p = pdata;
- int ret = -EINVAL;
-
- while (p && p->id) {
- if ((p->id != PM8606_ID_BACKLIGHT) || (p->flags < 0))
- break;
-
- if (!strncmp(name, pm860x_backlight_name[p->flags],
- MFD_NAME_SIZE)) {
- ret = (int)p->flags;
- break;
- }
- p++;
- }
- return ret;
-}
-
static int pm860x_backlight_probe(struct platform_device *pdev)
{
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
- struct pm860x_platform_data *pm860x_pdata;
struct pm860x_backlight_pdata *pdata = NULL;
struct pm860x_backlight_data *data;
struct backlight_device *bl;
+ struct mfd_cell *cell;
struct resource *res;
struct backlight_properties props;
unsigned char value;
@@ -199,10 +181,10 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
return -EINVAL;
}

- if (pdev->dev.parent->platform_data) {
- pm860x_pdata = pdev->dev.parent->platform_data;
- pdata = pm860x_pdata->backlight;
- }
+ cell = pdev->dev.platform_data;
+ if (cell == NULL)
+ return -ENODEV;
+ pdata = cell->mfd_data;
if (pdata == NULL) {
dev_err(&pdev->dev, "platform data isn't assigned to "
"backlight\n");
@@ -219,7 +201,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
data->current_brightness = MAX_BRIGHTNESS;
data->pwm = pdata->pwm;
data->iset = pdata->iset;
- data->port = __check_device(pdata, name);
+ data->port = pdata->flags;
if (data->port < 0) {
dev_err(&pdev->dev, "wrong platform data is assigned");
kfree(data);
diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h
index 4db1fbd..f790d37 100644
--- a/include/linux/mfd/88pm860x.h
+++ b/include/linux/mfd/88pm860x.h
@@ -356,10 +356,10 @@ struct pm860x_platform_data {
int i2c_port; /* Controlled by GI2C or PI2C */
int irq_mode; /* Clear interrupt by read/write(0/1) */
int irq_base; /* IRQ base number of 88pm860x */
+ int num_backlights;
struct regulator_init_data *regulator[PM8607_MAX_REGULATOR];
};

-extern char pm860x_backlight_name[][MFD_NAME_SIZE];
extern char pm860x_led_name[][MFD_NAME_SIZE];

extern int pm860x_reg_read(struct i2c_client *, int);
--
1.5.6.5


2011-03-07 15:55:48

by Haojian Zhuang

[permalink] [raw]
Subject: [PATCH] input: touchscreen: use polling mode in 88pm860x

Measuring point on touchscreen with IRQ mode can only monitor pen-down
event. If finger is moving on touchscreen, it can't be monitored by
IRQ pen-down event. So switch to polling mode after pen-down event.

Signed-off-by: Haojian Zhuang <[email protected]>
---
drivers/input/touchscreen/88pm860x-ts.c | 77 +++++++++++++++++++++++-------
1 files changed, 59 insertions(+), 18 deletions(-)

diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c
index b3aebc2..7d481cc 100644
--- a/drivers/input/touchscreen/88pm860x-ts.c
+++ b/drivers/input/touchscreen/88pm860x-ts.c
@@ -19,6 +19,18 @@
#define MEAS_LEN (8)
#define ACCURATE_BIT (12)

+/*
+ * While 32KHz hardware timer is used for scheduler, we always assign HZ
+ * to 128. It means that 1 tick costs 7.8msec.
+ */
+#define MEASURE_INTERVAL_MS (7)
+
+/* debounce register */
+#define DEBOUNCE (0x0A)
+
+#define PD_DEBOUNCE_0MSEC (0)
+#define PD_DEBOUNCE_MASK (3)
+
/* touch register */
#define MEAS_EN3 (0x52)

@@ -39,22 +51,26 @@
#define MEAS_TSIZ2_EN (1 << 7)

struct pm860x_touch {
- struct input_dev *idev;
- struct i2c_client *i2c;
- struct pm860x_chip *chip;
- int irq;
- int res_x; /* resistor of Xplate */
+ struct input_dev *idev;
+ struct i2c_client *i2c;
+ struct pm860x_chip *chip;
+ struct delayed_work poll_work;
+
+ int irq;
+ int res_x; /* resistor of Xplate */
};

-static irqreturn_t pm860x_touch_handler(int irq, void *data)
+static void pm860x_poll_work(struct work_struct *work)
{
- struct pm860x_touch *touch = data;
+ struct pm860x_touch *touch = container_of(work, struct pm860x_touch,
+ poll_work.work);
struct pm860x_chip *chip = touch->chip;
+ int x, y, z1, z2, rt = 0;
+ int ret, pen_down, interval;
unsigned char buf[MEAS_LEN];
- int x, y, pen_down;
- int z1, z2, rt = 0;
- int ret;
+ struct timeval start, end;

+ do_gettimeofday(&start);
ret = pm860x_bulk_read(touch->i2c, MEAS_TSIX_1, MEAS_LEN, buf);
if (ret < 0)
goto out;
@@ -77,6 +93,15 @@ static irqreturn_t pm860x_touch_handler(int irq, void *data)
input_report_abs(touch->idev, ABS_PRESSURE, rt);
input_report_key(touch->idev, BTN_TOUCH, 1);
dev_dbg(chip->dev, "pen down at [%d, %d].\n", x, y);
+
+ do_gettimeofday(&end);
+ interval = (end.tv_sec - start.tv_sec) * 1000000 +
+ (end.tv_usec - start.tv_usec) / 1000;
+ interval = (interval < MEASURE_INTERVAL_MS)
+ ? (MEASURE_INTERVAL_MS - interval) : 0;
+ queue_delayed_work(touch->chip->monitor_wqueue,
+ &touch->poll_work,
+ msecs_to_jiffies(interval));
} else {
input_report_abs(touch->idev, ABS_PRESSURE, 0);
input_report_key(touch->idev, BTN_TOUCH, 0);
@@ -85,22 +110,36 @@ static irqreturn_t pm860x_touch_handler(int irq, void *data)
input_sync(touch->idev);

out:
+ return;
+}
+
+static irqreturn_t pm860x_touch_handler(int irq, void *data)
+{
+ struct pm860x_touch *touch = data;
+ int ret;
+
+ ret = pm860x_reg_read(touch->i2c, PM8607_STATUS_1);
+ dev_dbg(touch->chip->dev, "pen status:%d\n", (ret & PM8607_STATUS_PEN)
+ ? 1 : 0);
+ if ((ret & PM8607_STATUS_PEN) == 0)
+ return IRQ_HANDLED;
+
+ pm860x_poll_work(&touch->poll_work.work);
return IRQ_HANDLED;
}

static int pm860x_touch_open(struct input_dev *dev)
{
struct pm860x_touch *touch = input_get_drvdata(dev);
- int data, ret;
+ int data;

+ /* set debounce time with 0ms */
+ pm860x_set_bits(touch->i2c, DEBOUNCE, PD_DEBOUNCE_MASK,
+ PD_DEBOUNCE_0MSEC);
data = MEAS_PD_EN | MEAS_TSIX_EN | MEAS_TSIY_EN
| MEAS_TSIZ1_EN | MEAS_TSIZ2_EN;
- ret = pm860x_set_bits(touch->i2c, MEAS_EN3, data, data);
- if (ret < 0)
- goto out;
+ pm860x_set_bits(touch->i2c, MEAS_EN3, data, data);
return 0;
-out:
- return ret;
}

static void pm860x_touch_close(struct input_dev *dev)
@@ -152,14 +191,14 @@ static int __devinit pm860x_touch_probe(struct platform_device *pdev)
}

touch->idev->name = "88pm860x-touch";
- touch->idev->phys = "88pm860x/input0";
+ touch->idev->phys = "88pm860x/input1";
touch->idev->id.bustype = BUS_I2C;
touch->idev->dev.parent = &pdev->dev;
touch->idev->open = pm860x_touch_open;
touch->idev->close = pm860x_touch_close;
touch->chip = chip;
touch->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
- touch->irq = irq + chip->irq_base;
+ touch->irq = irq;
touch->res_x = pdata->res_x;
input_set_drvdata(touch->idev, touch);

@@ -188,6 +227,7 @@ static int __devinit pm860x_touch_probe(struct platform_device *pdev)
}

platform_set_drvdata(pdev, touch);
+ INIT_DELAYED_WORK(&touch->poll_work, pm860x_poll_work);
return 0;
out_rg:
free_irq(touch->irq, touch);
@@ -202,6 +242,7 @@ static int __devexit pm860x_touch_remove(struct platform_device *pdev)
{
struct pm860x_touch *touch = platform_get_drvdata(pdev);

+ flush_workqueue(touch->chip->monitor_wqueue);
input_unregister_device(touch->idev);
free_irq(touch->irq, touch);
platform_set_drvdata(pdev, NULL);
--
1.5.6.5

2011-03-07 15:55:59

by Haojian Zhuang

[permalink] [raw]
Subject: [PATCH] w1: add DS278x slave driver

Append DS278x slave driver.

Signed-off-by: Haojian Zhuang <[email protected]>
---
drivers/w1/slaves/Kconfig | 13 +++
drivers/w1/slaves/Makefile | 1 +
drivers/w1/slaves/w1_ds278x.c | 184 +++++++++++++++++++++++++++++++++++++++++
drivers/w1/w1_family.h | 3 +
4 files changed, 201 insertions(+), 0 deletions(-)
create mode 100644 drivers/w1/slaves/w1_ds278x.c

diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig
index f0c9096..d737aa9 100644
--- a/drivers/w1/slaves/Kconfig
+++ b/drivers/w1/slaves/Kconfig
@@ -61,6 +61,19 @@ config W1_SLAVE_DS2760

If you are unsure, say N.

+config W1_SLAVE_DS278x
+ tristate "Dallas 278x battery monitor chip"
+ depends on W1
+ help
+ If you enable this you will have the DS278x battery monitor
+ chip support.
+
+ The battery monitor chip is used in many batteries/devices
+ as the one who is responsible for charging/discharging/monitoring
+ Li+ batteries.
+
+ If you are unsure, say N.
+
config W1_SLAVE_BQ27000
tristate "BQ27000 slave support"
depends on W1
diff --git a/drivers/w1/slaves/Makefile b/drivers/w1/slaves/Makefile
index 3c76350..bcc134b 100644
--- a/drivers/w1/slaves/Makefile
+++ b/drivers/w1/slaves/Makefile
@@ -8,4 +8,5 @@ obj-$(CONFIG_W1_SLAVE_DS2423) += w1_ds2423.o
obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o
obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o
obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o
+obj-$(CONFIG_W1_SLAVE_DS278x) += w1_ds278x.o
obj-$(CONFIG_W1_SLAVE_BQ27000) += w1_bq27000.o
diff --git a/drivers/w1/slaves/w1_ds278x.c b/drivers/w1/slaves/w1_ds278x.c
new file mode 100644
index 0000000..9da94bb
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds278x.c
@@ -0,0 +1,184 @@
+/*
+ * w1_ds278x.c - w1 family 27 (DS2780/DS2781) driver
+ *
+ * Copyright (c) Intel 2006 Stanley Cai <[email protected]>
+ * Copyright (c) Marvell 2007 Paul Shen <[email protected]>
+ *
+ * Modified from w1_ds2433 driver
+ *
+ * Copyright (c) 2005 Ben Gardner <[email protected]>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+#include "../w1_family.h"
+
+#define W1_REG_SIZE 256
+
+#define W1_F27_READ_REG 0x69
+#define W1_F27_WRITE_REG 0x6C
+#define W1_F27_COPY_REG 0x48
+#define W1_F27_RECALL_REG 0xB8
+#define W1_F27_LOCK_REG 0x6A
+
+struct w1_f27_data {
+ u8 memory[W1_REG_SIZE];
+ u32 validcrc;
+};
+
+/**
+ * Check the file size bounds and adjusts count as needed.
+ * This would not be needed if the file size didn't reset to 0 after a write.
+ */
+static inline size_t w1_f27_fix_count(loff_t off, size_t count,
+ size_t size)
+{
+ if (off > size)
+ return 0;
+
+ if ((off + count) > size)
+ return (size - off);
+
+ return count;
+}
+
+static ssize_t w1_f27_read_bin(struct file *fp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct w1_slave *sl = kobj_to_w1_slave(kobj);
+ u8 wrbuf[2];
+
+ count = w1_f27_fix_count(off, count, W1_REG_SIZE);
+ if (count == 0)
+ return 0;
+
+ atomic_inc(&sl->refcnt);
+ mutex_lock(&sl->master->mutex);
+
+ /* read directly from the REG */
+ if (w1_reset_select_slave(sl)) {
+ count = -EIO;
+ goto out_mutex_unlock;
+ }
+
+ wrbuf[0] = W1_F27_READ_REG;
+ wrbuf[1] = off & 0xff;
+ w1_write_block(sl->master, wrbuf, 2);
+ w1_read_block(sl->master, buf, count);
+
+out_mutex_unlock:
+ mutex_unlock(&sl->master->mutex);
+ atomic_dec(&sl->refcnt);
+
+ return count;
+}
+
+static ssize_t w1_f27_write_bin(struct file *fp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct w1_slave *sl = kobj_to_w1_slave(kobj);
+ char wrbuf[2];
+
+ count = w1_f27_fix_count(off, count, W1_REG_SIZE);
+ if (count == 0)
+ return 0;
+
+ atomic_inc(&sl->refcnt);
+ mutex_lock(&sl->master->mutex);
+
+ if (w1_reset_select_slave(sl)) {
+ count = -EIO;
+ goto out_mutex_unlock;
+ }
+
+ wrbuf[0] = W1_F27_WRITE_REG;
+ wrbuf[1] = off & 0xff;
+ w1_write_block(sl->master, wrbuf, 2);
+ w1_write_block(sl->master, buf, count);
+
+out_mutex_unlock:
+ mutex_unlock(&sl->master->mutex);
+ atomic_dec(&sl->refcnt);
+
+ return count;
+}
+
+static struct bin_attribute w1_f27_bin_attr = {
+ .attr = {
+ .name = "registers",
+ .mode = S_IRUGO | S_IWUSR,
+ },
+ .size = W1_REG_SIZE,
+ .read = w1_f27_read_bin,
+ .write = w1_f27_write_bin,
+};
+
+static int w1_f27_add_slave(struct w1_slave *sl)
+{
+ int err;
+
+ err = sysfs_create_bin_file(&sl->dev.kobj, &w1_f27_bin_attr);
+
+ return err;
+}
+
+static void w1_f27_remove_slave(struct w1_slave *sl)
+{
+ sysfs_remove_bin_file(&sl->dev.kobj, &w1_f27_bin_attr);
+}
+
+static struct w1_family_ops w1_f27_fops = {
+ .add_slave = w1_f27_add_slave,
+ .remove_slave = w1_f27_remove_slave,
+};
+
+static struct w1_family w1_family_2780 = {
+ .fid = W1_BATTMON_DS2780,
+ .fops = &w1_f27_fops,
+};
+
+static struct w1_family w1_family_2781 = {
+ .fid = W1_BATTMON_DS2781,
+ .fops = &w1_f27_fops,
+};
+
+static struct w1_family w1_family_2783 = {
+ .fid = W1_BATTMON_DS2783,
+ .fops = &w1_f27_fops,
+};
+
+
+static int __init w1_f27_init(void)
+{
+ pr_info("1-Wire driver for the DS278x battery monitor...\n");
+ return (w1_register_family(&w1_family_2780) |
+ w1_register_family(&w1_family_2781) |
+ w1_register_family(&w1_family_2783));
+}
+
+static void __exit w1_f27_fini(void)
+{
+ w1_unregister_family(&w1_family_2781);
+ w1_unregister_family(&w1_family_2780);
+ w1_unregister_family(&w1_family_2783);
+}
+
+module_init(w1_f27_init);
+module_exit(w1_f27_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Paul Shen <[email protected]>");
+MODULE_DESCRIPTION("w1 family 27 driver for DS2780 & DS2781,"
+ " Stand-Alone Fuel Gauge IC");
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index f3b636d..0f0b58c 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -36,6 +36,9 @@
#define W1_THERM_DS18B20 0x28
#define W1_EEPROM_DS2431 0x2D
#define W1_FAMILY_DS2760 0x30
+#define W1_BATTMON_DS2780 0x32
+#define W1_BATTMON_DS2781 0x3D
+#define W1_BATTMON_DS2783 0x34

#define MAXNAMELEN 32

--
1.5.6.5

2011-03-07 15:55:45

by Haojian Zhuang

[permalink] [raw]
Subject: [PATCH] input: set the long press detection in 88pm860x onkey

Move the long-press detection from onkey handler to probe function. Avoid
unnecessary I2C operation in onkey handler.

Signed-off-by: Haojian Zhuang <[email protected]>
---
drivers/input/misc/88pm860x_onkey.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/input/misc/88pm860x_onkey.c b/drivers/input/misc/88pm860x_onkey.c
index 3dca3c1..1abc77e 100644
--- a/drivers/input/misc/88pm860x_onkey.c
+++ b/drivers/input/misc/88pm860x_onkey.c
@@ -50,9 +50,6 @@ static irqreturn_t pm860x_onkey_handler(int irq, void *data)
ret &= ONKEY_STATUS;
input_report_key(info->idev, KEY_POWER, ret);
input_sync(info->idev);
-
- /* Enable 8-second long onkey detection */
- pm860x_set_bits(info->i2c, PM8607_WAKEUP, 3, LONG_ONKEY_EN);
return IRQ_HANDLED;
}

@@ -105,6 +102,9 @@ static int __devinit pm860x_onkey_probe(struct platform_device *pdev)
}

platform_set_drvdata(pdev, info);
+
+ /* Enable 8-second long onkey detection */
+ pm860x_set_bits(info->i2c, PM8607_WAKEUP, 3, LONG_ONKEY_EN);
return 0;

out_irq:
--
1.5.6.5

2011-03-07 15:55:53

by Haojian Zhuang

[permalink] [raw]
Subject: [PATCH] mfd: add workqueue thread into 88pm860x

Create workqueue thread in 88pm860x driver since 88pm860x driver
needs to handle event in workqueue.

Avoid to use system workqueue since i2c operation cost a lot of
time. It would impact system performance.

Signed-off-by: Haojian Zhuang <[email protected]>
---
drivers/mfd/88pm860x-core.c | 12 ++++++++++++
include/linux/mfd/88pm860x.h | 1 +
2 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index 9c511c1..42c4fa2 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -766,11 +766,21 @@ static void __devinit device_8607_init(struct pm860x_chip *chip,
if (ret < 0)
goto out;

+ chip->monitor_wqueue = create_singlethread_workqueue("88pm860x");
+ if (!chip->monitor_wqueue) {
+ ret = -ESRCH;
+ goto out_work;
+ }
+
device_regulator_init(chip, i2c, pdata);
device_onkey_init(chip, i2c, pdata);
device_touch_init(chip, i2c, pdata);
device_power_init(chip, i2c, pdata);
device_codec_init(chip, i2c, pdata);
+ return;
+
+out_work:
+ device_irq_exit(chip);
out:
return;
}
@@ -807,6 +817,8 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,

void __devexit pm860x_device_exit(struct pm860x_chip *chip)
{
+ flush_workqueue(chip->monitor_wqueue);
+ destroy_workqueue(chip->monitor_wqueue);
device_irq_exit(chip);
mfd_remove_devices(chip->dev);
}
diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h
index a6f6f81..87df510 100644
--- a/include/linux/mfd/88pm860x.h
+++ b/include/linux/mfd/88pm860x.h
@@ -301,6 +301,7 @@ struct pm860x_chip {
struct mutex irq_lock;
struct i2c_client *client;
struct i2c_client *companion; /* companion chip client */
+ struct workqueue_struct *monitor_wqueue;

int buck3_double; /* DVC ramp slope double */
unsigned short companion_addr;
--
1.5.6.5

2011-03-07 15:55:34

by Haojian Zhuang

[permalink] [raw]
Subject: [PATCH] mfd: adopt mfd_data in 88pm860x

Copy 88pm860x platform data into different mfd_data structure for
onkey/touch/codec/power driver. So move the identification of
device node from those drivers to mfd driver.

Signed-off-by: Haojian Zhuang <[email protected]>
---
drivers/input/misc/88pm860x_onkey.c | 2 +-
drivers/mfd/88pm860x-core.c | 251 ++++++++++++++++++-----------------
2 files changed, 127 insertions(+), 126 deletions(-)

diff --git a/drivers/input/misc/88pm860x_onkey.c b/drivers/input/misc/88pm860x_onkey.c
index 4cc8282..3dca3c1 100644
--- a/drivers/input/misc/88pm860x_onkey.c
+++ b/drivers/input/misc/88pm860x_onkey.c
@@ -74,7 +74,7 @@ static int __devinit pm860x_onkey_probe(struct platform_device *pdev)
info->chip = chip;
info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
info->dev = &pdev->dev;
- info->irq = irq + chip->irq_base;
+ info->irq = irq;

info->idev = input_allocate_device();
if (!info->idev) {
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index 96ea0c6..9c511c1 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -57,6 +57,39 @@ static struct resource regulator_resources[] __initdata = {
{PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,},
};

+static struct resource touch_resources[] __initdata = {
+ {PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,},
+};
+
+static struct resource onkey_resources[] __initdata = {
+ {PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,},
+};
+
+static struct resource codec_resources[] __initdata = {
+ /* Headset microphone insertion or removal */
+ {PM8607_IRQ_MICIN, PM8607_IRQ_MICIN, "micin", IORESOURCE_IRQ,},
+ /* Hook-switch press or release */
+ {PM8607_IRQ_HOOK, PM8607_IRQ_HOOK, "hook", IORESOURCE_IRQ,},
+ /* Headset insertion or removal */
+ {PM8607_IRQ_HEADSET, PM8607_IRQ_HEADSET, "headset", IORESOURCE_IRQ,},
+ /* Audio short */
+ {PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short", IORESOURCE_IRQ,},
+};
+
+static struct resource battery_resources[] __initdata = {
+ {PM8607_IRQ_CC, PM8607_IRQ_CC, "columb counter", IORESOURCE_IRQ,},
+ {PM8607_IRQ_BAT, PM8607_IRQ_BAT, "battery", IORESOURCE_IRQ,},
+};
+
+static struct resource charger_resources[] __initdata = {
+ {PM8607_IRQ_CHG, PM8607_IRQ_CHG, "charger detect", IORESOURCE_IRQ,},
+ {PM8607_IRQ_CHG_DONE, PM8607_IRQ_CHG_DONE, "charging done", IORESOURCE_IRQ,},
+ {PM8607_IRQ_CHG_FAULT, PM8607_IRQ_CHG_FAULT, "charging timeout", IORESOURCE_IRQ,},
+ {PM8607_IRQ_GPADC1, PM8607_IRQ_GPADC1, "battery temperature", IORESOURCE_IRQ,},
+ {PM8607_IRQ_VBAT, PM8607_IRQ_VBAT, "battery voltage", IORESOURCE_IRQ,},
+ {PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage", IORESOURCE_IRQ,},
+};
+
static struct mfd_cell bk_devs[] __initdata = {
{"88pm860x-backlight", 0,},
{"88pm860x-backlight", 1,},
@@ -93,98 +126,28 @@ static struct mfd_cell regulator_devs[] __initdata = {
{"88pm860x-regulator", 17,},
};

-static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)];
-static struct pm860x_led_pdata led_pdata[ARRAY_SIZE(led_devs)];
-static struct regulator_init_data regulator_pdata[ARRAY_SIZE(regulator_devs)];
-
-static struct resource touch_resources[] = {
- {
- .start = PM8607_IRQ_PEN,
- .end = PM8607_IRQ_PEN,
- .flags = IORESOURCE_IRQ,
- },
+static struct mfd_cell touch_devs[] __initdata = {
+ {"88pm860x-touch", -1,},
};

-static struct mfd_cell touch_devs[] = {
- {
- .name = "88pm860x-touch",
- .num_resources = 1,
- .resources = &touch_resources[0],
- },
+static struct mfd_cell onkey_devs[] __initdata = {
+ {"88pm860x-onkey", -1,},
};

-static struct resource power_supply_resources[] = {
- {
- .name = "88pm860x-power",
- .start = PM8607_IRQ_CHG,
- .end = PM8607_IRQ_CHG,
- .flags = IORESOURCE_IRQ,
- },
+static struct mfd_cell codec_devs[] __initdata = {
+ {"88pm860x-codec", -1,},
};

static struct mfd_cell power_devs[] = {
- {
- .name = "88pm860x-power",
- .num_resources = 1,
- .resources = &power_supply_resources[0],
- .id = -1,
- },
-};
-
-static struct resource onkey_resources[] = {
- {
- .name = "88pm860x-onkey",
- .start = PM8607_IRQ_ONKEY,
- .end = PM8607_IRQ_ONKEY,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct mfd_cell onkey_devs[] = {
- {
- .name = "88pm860x-onkey",
- .num_resources = 1,
- .resources = &onkey_resources[0],
- .id = -1,
- },
-};
-
-static struct resource codec_resources[] = {
- {
- /* Headset microphone insertion or removal */
- .name = "micin",
- .start = PM8607_IRQ_MICIN,
- .end = PM8607_IRQ_MICIN,
- .flags = IORESOURCE_IRQ,
- }, {
- /* Hook-switch press or release */
- .name = "hook",
- .start = PM8607_IRQ_HOOK,
- .end = PM8607_IRQ_HOOK,
- .flags = IORESOURCE_IRQ,
- }, {
- /* Headset insertion or removal */
- .name = "headset",
- .start = PM8607_IRQ_HEADSET,
- .end = PM8607_IRQ_HEADSET,
- .flags = IORESOURCE_IRQ,
- }, {
- /* Audio short */
- .name = "audio-short",
- .start = PM8607_IRQ_AUDIO_SHORT,
- .end = PM8607_IRQ_AUDIO_SHORT,
- .flags = IORESOURCE_IRQ,
- },
+ {"88pm860x-battery", -1,},
+ {"88pm860x-charger", -1,},
};

-static struct mfd_cell codec_devs[] = {
- {
- .name = "88pm860x-codec",
- .num_resources = ARRAY_SIZE(codec_resources),
- .resources = &codec_resources[0],
- .id = -1,
- },
-};
+static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)];
+static struct pm860x_led_pdata led_pdata[ARRAY_SIZE(led_devs)];
+static struct regulator_init_data regulator_pdata[ARRAY_SIZE(regulator_devs)];
+static struct pm860x_touch_pdata touch_pdata;
+static struct pm860x_power_pdata power_pdata;

struct pm860x_irq_data {
int reg;
@@ -672,6 +635,82 @@ out:
return;
}

+static void __devinit device_touch_init(struct pm860x_chip *chip,
+ struct i2c_client *i2c,
+ struct pm860x_platform_data *pdata)
+{
+ int ret;
+
+ if ((pdata == NULL) || (pdata->touch == NULL))
+ return;
+
+ memcpy(&touch_pdata, pdata->touch, sizeof(struct pm860x_touch_pdata));
+ touch_devs[0].mfd_data = &touch_pdata;
+ touch_devs[0].num_resources = ARRAY_SIZE(touch_resources);
+ touch_devs[0].resources = &touch_resources[0];
+ ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
+ ARRAY_SIZE(touch_devs), &touch_resources[0],
+ chip->irq_base);
+ if (ret < 0)
+ dev_err(chip->dev, "Failed to add touch subdev\n");
+}
+
+static void __devinit device_power_init(struct pm860x_chip *chip,
+ struct i2c_client *i2c,
+ struct pm860x_platform_data *pdata)
+{
+ int ret;
+
+ if ((pdata == NULL) || (pdata->power == NULL))
+ return;
+
+ memcpy(&power_pdata, pdata->power, sizeof(struct pm860x_power_pdata));
+ power_devs[0].mfd_data = &power_pdata;
+ power_devs[0].num_resources = ARRAY_SIZE(battery_resources);
+ power_devs[0].resources = &battery_resources[0],
+ ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1,
+ &battery_resources[0], chip->irq_base);
+ if (ret < 0)
+ dev_err(chip->dev, "Failed to add battery subdev\n");
+
+ power_devs[1].mfd_data = &power_pdata;
+ power_devs[1].num_resources = ARRAY_SIZE(charger_resources);
+ power_devs[1].resources = &charger_resources[0],
+ ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1,
+ &charger_resources[0], chip->irq_base);
+ if (ret < 0)
+ dev_err(chip->dev, "Failed to add charger subdev\n");
+}
+
+static void __devinit device_onkey_init(struct pm860x_chip *chip,
+ struct i2c_client *i2c,
+ struct pm860x_platform_data *pdata)
+{
+ int ret;
+
+ onkey_devs[0].num_resources = ARRAY_SIZE(onkey_resources);
+ onkey_devs[0].resources = &onkey_resources[0],
+ ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
+ ARRAY_SIZE(onkey_devs), &onkey_resources[0],
+ chip->irq_base);
+ if (ret < 0)
+ dev_err(chip->dev, "Failed to add onkey subdev\n");
+}
+
+static void __devinit device_codec_init(struct pm860x_chip *chip,
+ struct i2c_client *i2c,
+ struct pm860x_platform_data *pdata)
+{
+ int ret;
+
+ codec_devs[0].num_resources = ARRAY_SIZE(codec_resources);
+ codec_devs[0].resources = &codec_resources[0],
+ ret = mfd_add_devices(chip->dev, 0, &codec_devs[0],
+ ARRAY_SIZE(codec_devs), &codec_resources[0], 0);
+ if (ret < 0)
+ dev_err(chip->dev, "Failed to add codec subdev\n");
+}
+
static void __devinit device_8607_init(struct pm860x_chip *chip,
struct i2c_client *i2c,
struct pm860x_platform_data *pdata)
@@ -727,49 +766,11 @@ static void __devinit device_8607_init(struct pm860x_chip *chip,
if (ret < 0)
goto out;

- if (pdata && pdata->touch) {
- ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
- ARRAY_SIZE(touch_devs),
- &touch_resources[0], 0);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to add touch "
- "subdev\n");
- goto out_dev;
- }
- }
-
- if (pdata && pdata->power) {
- ret = mfd_add_devices(chip->dev, 0, &power_devs[0],
- ARRAY_SIZE(power_devs),
- &power_supply_resources[0], 0);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to add power supply "
- "subdev\n");
- goto out_dev;
- }
- }
-
- 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;
- }
-
- ret = mfd_add_devices(chip->dev, 0, &codec_devs[0],
- ARRAY_SIZE(codec_devs),
- &codec_resources[0], 0);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to add codec subdev\n");
- goto out_dev;
- }
-
device_regulator_init(chip, i2c, pdata);
- return;
-out_dev:
- mfd_remove_devices(chip->dev);
- device_irq_exit(chip);
+ device_onkey_init(chip, i2c, pdata);
+ device_touch_init(chip, i2c, pdata);
+ device_power_init(chip, i2c, pdata);
+ device_codec_init(chip, i2c, pdata);
out:
return;
}
--
1.5.6.5

2011-03-07 15:55:41

by Haojian Zhuang

[permalink] [raw]
Subject: [PATCH] mfd: append additional read write on 88pm860x

Append the additional read/write operation on 88pm860x for accessing
test page in 88PM860x.

Signed-off-by: Haojian Zhuang <[email protected]>
---
drivers/mfd/88pm860x-i2c.c | 103 ++++++++++++++++++++++++++++++++++++++++++
include/linux/mfd/88pm860x.h | 8 +++
2 files changed, 111 insertions(+), 0 deletions(-)

diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c
index bc02e6b..e017dc8 100644
--- a/drivers/mfd/88pm860x-i2c.c
+++ b/drivers/mfd/88pm860x-i2c.c
@@ -126,6 +126,109 @@ out:
}
EXPORT_SYMBOL(pm860x_set_bits);

+int pm860x_page_reg_read(struct i2c_client *i2c, int reg)
+{
+ struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+ unsigned char zero = 0;
+ unsigned char data;
+ int ret;
+
+ mutex_lock(&chip->io_lock);
+ pm860x_write_device(i2c, 0xFA, 0, &zero);
+ pm860x_write_device(i2c, 0xFB, 0, &zero);
+ pm860x_write_device(i2c, 0xFF, 0, &zero);
+ ret = pm860x_read_device(i2c, reg, 1, &data);
+ if (ret >= 0)
+ ret = (int)data;
+ pm860x_write_device(i2c, 0xFE, 0, &zero);
+ pm860x_write_device(i2c, 0xFC, 0, &zero);
+ mutex_unlock(&chip->io_lock);
+ return ret;
+}
+EXPORT_SYMBOL(pm860x_page_reg_read);
+
+int pm860x_page_reg_write(struct i2c_client *i2c, int reg,
+ unsigned char data)
+{
+ struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+ unsigned char zero;
+ int ret;
+
+ mutex_lock(&chip->io_lock);
+ pm860x_write_device(i2c, 0xFA, 0, &zero);
+ pm860x_write_device(i2c, 0xFB, 0, &zero);
+ pm860x_write_device(i2c, 0xFF, 0, &zero);
+ ret = pm860x_write_device(i2c, reg, 1, &data);
+ pm860x_write_device(i2c, 0xFE, 0, &zero);
+ pm860x_write_device(i2c, 0xFC, 0, &zero);
+ mutex_unlock(&chip->io_lock);
+ return ret;
+}
+EXPORT_SYMBOL(pm860x_page_reg_write);
+
+int pm860x_page_bulk_read(struct i2c_client *i2c, int reg,
+ int count, unsigned char *buf)
+{
+ struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+ unsigned char zero = 0;
+ int ret;
+
+ mutex_lock(&chip->io_lock);
+ pm860x_write_device(i2c, 0xFA, 0, &zero);
+ pm860x_write_device(i2c, 0xFB, 0, &zero);
+ pm860x_write_device(i2c, 0xFF, 0, &zero);
+ ret = pm860x_read_device(i2c, reg, count, buf);
+ pm860x_write_device(i2c, 0xFE, 0, &zero);
+ pm860x_write_device(i2c, 0xFC, 0, &zero);
+ mutex_unlock(&chip->io_lock);
+ return ret;
+}
+EXPORT_SYMBOL(pm860x_page_bulk_read);
+
+int pm860x_page_bulk_write(struct i2c_client *i2c, int reg,
+ int count, unsigned char *buf)
+{
+ struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+ unsigned char zero = 0;
+ int ret;
+
+ mutex_lock(&chip->io_lock);
+ pm860x_write_device(i2c, 0xFA, 0, &zero);
+ pm860x_write_device(i2c, 0xFB, 0, &zero);
+ pm860x_write_device(i2c, 0xFF, 0, &zero);
+ ret = pm860x_write_device(i2c, reg, count, buf);
+ pm860x_write_device(i2c, 0xFE, 0, &zero);
+ pm860x_write_device(i2c, 0xFC, 0, &zero);
+ mutex_unlock(&chip->io_lock);
+ return ret;
+}
+EXPORT_SYMBOL(pm860x_page_bulk_write);
+
+int pm860x_page_set_bits(struct i2c_client *i2c, int reg,
+ unsigned char mask, unsigned char data)
+{
+ struct pm860x_chip *chip = i2c_get_clientdata(i2c);
+ unsigned char zero;
+ unsigned char value;
+ int ret;
+
+ mutex_lock(&chip->io_lock);
+ pm860x_write_device(i2c, 0xFA, 0, &zero);
+ pm860x_write_device(i2c, 0xFB, 0, &zero);
+ pm860x_write_device(i2c, 0xFF, 0, &zero);
+ ret = pm860x_read_device(i2c, reg, 1, &value);
+ if (ret < 0)
+ goto out;
+ value &= ~mask;
+ value |= data;
+ ret = pm860x_write_device(i2c, reg, 1, &value);
+out:
+ pm860x_write_device(i2c, 0xFE, 0, &zero);
+ pm860x_write_device(i2c, 0xFC, 0, &zero);
+ mutex_unlock(&chip->io_lock);
+ return ret;
+}
+EXPORT_SYMBOL(pm860x_page_set_bits);

static const struct i2c_device_id pm860x_id_table[] = {
{ "88PM860x", 0 },
diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h
index 87df510..05f8677 100644
--- a/include/linux/mfd/88pm860x.h
+++ b/include/linux/mfd/88pm860x.h
@@ -369,6 +369,14 @@ extern int pm860x_bulk_read(struct i2c_client *, int, int, unsigned char *);
extern int pm860x_bulk_write(struct i2c_client *, int, int, unsigned char *);
extern int pm860x_set_bits(struct i2c_client *, int, unsigned char,
unsigned char);
+extern int pm860x_page_reg_read(struct i2c_client *, int);
+extern int pm860x_page_reg_write(struct i2c_client *, int, unsigned char);
+extern int pm860x_page_bulk_read(struct i2c_client *, int, int,
+ unsigned char *);
+extern int pm860x_page_bulk_write(struct i2c_client *, int, int,
+ unsigned char *);
+extern int pm860x_page_set_bits(struct i2c_client *, int, unsigned char,
+ unsigned char);

extern int pm860x_device_init(struct pm860x_chip *chip,
struct pm860x_platform_data *pdata) __devinit ;
--
1.5.6.5

2011-03-07 15:55:56

by Haojian Zhuang

[permalink] [raw]
Subject: [PATCH] rtc: add 88pm860x rtc

Support RTC component in 88PM860x. Also support synchronize time
88PM860x RTC to another RTC device. It should be implemented in
sync callback API.

While 88PM860x RTC is enabled, it can do RTC calibration to gurantee
enough power is supplied on VRTC domain of 88PM860x.

Signed-off-by: Haojian Zhuang <[email protected]>
---
drivers/mfd/88pm860x-core.c | 30 ++++++++++++++++++++++++++++++
drivers/rtc/Kconfig | 10 ++++++++++
drivers/rtc/Makefile | 1 +
include/linux/mfd/88pm860x.h | 6 ++++++
4 files changed, 47 insertions(+), 0 deletions(-)

diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index 7879569..864e6a3 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -57,6 +57,10 @@ static struct resource regulator_resources[] __initdata = {
{PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,},
};

+static struct resource rtc_resources[] __initdata = {
+ {PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,},
+};
+
static struct resource touch_resources[] __initdata = {
{PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,},
};
@@ -126,6 +130,10 @@ static struct mfd_cell regulator_devs[] __initdata = {
{"88pm860x-regulator", 17,},
};

+static struct mfd_cell rtc_devs[] __initdata = {
+ {"88pm860x-rtc", -1,},
+};
+
static struct mfd_cell touch_devs[] __initdata = {
{"88pm860x-touch", -1,},
};
@@ -148,6 +156,7 @@ static struct pm860x_led_pdata led_pdata[ARRAY_SIZE(led_devs)];
static struct regulator_init_data regulator_pdata[ARRAY_SIZE(regulator_devs)];
static struct pm860x_touch_pdata touch_pdata;
static struct pm860x_power_pdata power_pdata;
+static struct pm860x_rtc_pdata rtc_pdata;

struct pm860x_irq_data {
int reg;
@@ -588,6 +597,26 @@ out:
return;
}

+static void __devinit device_rtc_init(struct pm860x_chip *chip,
+ struct i2c_client *i2c,
+ struct pm860x_platform_data *pdata)
+{
+ int ret;
+
+ if ((pdata == NULL) || (pdata->rtc == NULL))
+ return;
+
+ memcpy(&rtc_pdata, pdata->rtc, sizeof(struct pm860x_rtc_pdata));
+ rtc_devs[0].mfd_data = &rtc_pdata;
+ rtc_devs[0].num_resources = ARRAY_SIZE(rtc_resources);
+ rtc_devs[0].resources = &rtc_resources[0];
+ ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
+ ARRAY_SIZE(rtc_devs), &rtc_resources[0],
+ chip->irq_base);
+ if (ret < 0)
+ dev_err(chip->dev, "Failed to add rtc subdev\n");
+}
+
static void __devinit device_touch_init(struct pm860x_chip *chip,
struct i2c_client *i2c,
struct pm860x_platform_data *pdata)
@@ -722,6 +751,7 @@ static void __devinit device_8607_init(struct pm860x_chip *chip,
}

device_regulator_init(chip, i2c, pdata);
+ device_rtc_init(chip, i2c, pdata);
device_onkey_init(chip, i2c, pdata);
device_touch_init(chip, i2c, pdata);
device_power_init(chip, i2c, pdata);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 4941cad..4f7b9f4 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -128,6 +128,16 @@ comment "I2C RTC drivers"

if I2C

+config RTC_DRV_88PM860X
+ tristate "Marvell 88PM860x"
+ depends on RTC_CLASS && I2C && MFD_88PM860X
+ help
+ If you say yes here you get support for RTC function in Marvell
+ 88PM860x chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-88pm860x.
+
config RTC_DRV_DS1307
tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025"
help
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 2afdaf3..edc9325 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -17,6 +17,7 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o

# Keep the list ordered.

+obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-88pm860x.o
obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o
obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o
obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h
index 05f8677..318aba8 100644
--- a/include/linux/mfd/88pm860x.h
+++ b/include/linux/mfd/88pm860x.h
@@ -331,6 +331,11 @@ struct pm860x_led_pdata {
unsigned long flags;
};

+struct pm860x_rtc_pdata {
+ int (*sync)(unsigned int ticks);
+ int vrtc;
+};
+
struct pm860x_touch_pdata {
int gpadc_prebias;
int slot_cycle;
@@ -350,6 +355,7 @@ struct pm860x_power_pdata {
struct pm860x_platform_data {
struct pm860x_backlight_pdata *backlight;
struct pm860x_led_pdata *led;
+ struct pm860x_rtc_pdata *rtc;
struct pm860x_touch_pdata *touch;
struct pm860x_power_pdata *power;
struct regulator_init_data *regulator;
--
1.5.6.5

2011-03-07 15:56:04

by Haojian Zhuang

[permalink] [raw]
Subject: [PATCH] mfd: adopt mfd_data in 88pm860x led

Copy 88pm860x platform data into different mfd_data structure for
led driver. So move the identification of device node from led
driver to mfd driver.

Signed-off-by: Haojian Zhuang <[email protected]>
---
drivers/leds/leds-88pm860x.c | 60 +++++++++++------------
drivers/mfd/88pm860x-core.c | 109 +++++++++++++++++++-----------------------
include/linux/mfd/88pm860x.h | 3 +-
3 files changed, 79 insertions(+), 93 deletions(-)

diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c
index e672b44..416def8 100644
--- a/drivers/leds/leds-88pm860x.c
+++ b/drivers/leds/leds-88pm860x.c
@@ -17,6 +17,7 @@
#include <linux/leds.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
+#include <linux/mfd/core.h>
#include <linux/mfd/88pm860x.h>

#define LED_PWM_SHIFT (3)
@@ -118,7 +119,8 @@ static void pm860x_led_work(struct work_struct *work)

struct pm860x_led *led;
struct pm860x_chip *chip;
- int mask;
+ unsigned char buf[3];
+ int mask, ret;

led = container_of(work, struct pm860x_led, work);
chip = led->chip;
@@ -128,16 +130,27 @@ static void pm860x_led_work(struct work_struct *work)
pm860x_set_bits(led->i2c, __led_off(led->port),
LED_CURRENT_MASK, led->iset);
}
+ pm860x_set_bits(led->i2c, __blink_off(led->port),
+ LED_BLINK_MASK, LED_ON_CONTINUOUS);
mask = __blink_ctl_mask(led->port);
pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, mask);
- } else if (led->brightness == 0) {
- pm860x_set_bits(led->i2c, __led_off(led->port),
- LED_CURRENT_MASK, 0);
- mask = __blink_ctl_mask(led->port);
- pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0);
}
pm860x_set_bits(led->i2c, __led_off(led->port), LED_PWM_MASK,
led->brightness);
+
+ if (led->brightness == 0) {
+ pm860x_bulk_read(led->i2c, __led_off(led->port), 3, buf);
+ ret = buf[0] & LED_PWM_MASK;
+ ret |= buf[1] & LED_PWM_MASK;
+ ret |= buf[2] & LED_PWM_MASK;
+ if (ret == 0) {
+ /* unset current since no led is lighting */
+ pm860x_set_bits(led->i2c, __led_off(led->port),
+ LED_CURRENT_MASK, 0);
+ mask = __blink_ctl_mask(led->port);
+ pm860x_set_bits(led->i2c, PM8606_WLED3B, mask, 0);
+ }
+ }
led->current_brightness = led->brightness;
dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n",
__led_off(led->port), led->brightness);
@@ -153,31 +166,12 @@ static void pm860x_led_set(struct led_classdev *cdev,
schedule_work(&data->work);
}

-static int __check_device(struct pm860x_led_pdata *pdata, char *name)
-{
- struct pm860x_led_pdata *p = pdata;
- int ret = -EINVAL;
-
- while (p && p->id) {
- if ((p->id != PM8606_ID_LED) || (p->flags < 0))
- break;
-
- if (!strncmp(name, pm860x_led_name[p->flags],
- MFD_NAME_SIZE)) {
- ret = (int)p->flags;
- break;
- }
- p++;
- }
- return ret;
-}
-
static int pm860x_led_probe(struct platform_device *pdev)
{
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
- struct pm860x_platform_data *pm860x_pdata;
struct pm860x_led_pdata *pdata;
struct pm860x_led *data;
+ struct mfd_cell *cell;
struct resource *res;
int ret;

@@ -187,10 +181,11 @@ static int pm860x_led_probe(struct platform_device *pdev)
return -EINVAL;
}

- if (pdev->dev.parent->platform_data) {
- pm860x_pdata = pdev->dev.parent->platform_data;
- pdata = pm860x_pdata->led;
- } else {
+ cell = pdev->dev.platform_data;
+ if (cell == NULL)
+ return -ENODEV;
+ pdata = cell->mfd_data;
+ if (pdata == NULL) {
dev_err(&pdev->dev, "No platform data!\n");
return -EINVAL;
}
@@ -198,12 +193,12 @@ static int pm860x_led_probe(struct platform_device *pdev)
data = kzalloc(sizeof(struct pm860x_led), GFP_KERNEL);
if (data == NULL)
return -ENOMEM;
- strncpy(data->name, res->name, MFD_NAME_SIZE);
+ strncpy(data->name, res->name, MFD_NAME_SIZE - 1);
dev_set_drvdata(&pdev->dev, data);
data->chip = chip;
data->i2c = (chip->id == CHIP_PM8606) ? chip->client : chip->companion;
data->iset = pdata->iset;
- data->port = __check_device(pdata, data->name);
+ data->port = pdata->flags;
if (data->port < 0) {
dev_err(&pdev->dev, "check device failed\n");
kfree(data);
@@ -221,6 +216,7 @@ static int pm860x_led_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Failed to register LED: %d\n", ret);
goto out;
}
+ pm860x_led_set(&data->cdev, 0);
return 0;
out:
kfree(data);
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index a88967a..cec375c 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -26,57 +26,32 @@ static struct resource bk_resources[] __initdata = {
{PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,},
};

+static struct resource led_resources[] __initdata = {
+ {PM8606_LED1_RED, PM8606_LED1_RED, "led0-red", IORESOURCE_IO,},
+ {PM8606_LED1_GREEN, PM8606_LED1_GREEN, "led0-green", IORESOURCE_IO,},
+ {PM8606_LED1_BLUE, PM8606_LED1_BLUE, "led0-blue", IORESOURCE_IO,},
+ {PM8606_LED2_RED, PM8606_LED2_RED, "led1-red", IORESOURCE_IO,},
+ {PM8606_LED2_GREEN, PM8606_LED2_GREEN, "led1-green", IORESOURCE_IO,},
+ {PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_IO,},
+};
+
static struct mfd_cell bk_devs[] __initdata = {
{"88pm860x-backlight", 0,},
{"88pm860x-backlight", 1,},
{"88pm860x-backlight", 2,},
};

-static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)];
-
-char pm860x_led_name[][MFD_NAME_SIZE] = {
- "led0-red",
- "led0-green",
- "led0-blue",
- "led1-red",
- "led1-green",
- "led1-blue",
-};
-EXPORT_SYMBOL(pm860x_led_name);
-
-#define PM8606_LED_RESOURCE(_i, _x) \
-{ \
- .name = pm860x_led_name[_i], \
- .start = PM8606_##_x, \
- .end = PM8606_##_x, \
- .flags = IORESOURCE_IO, \
-}
-
-static struct resource led_resources[] = {
- 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),
+static struct mfd_cell led_devs[] __initdata = {
+ {"88pm860x-led", 0,},
+ {"88pm860x-led", 1,},
+ {"88pm860x-led", 2,},
+ {"88pm860x-led", 3,},
+ {"88pm860x-led", 4,},
+ {"88pm860x-led", 5,},
};

-#define PM8606_LED_DEVS(_i) \
-{ \
- .name = "88pm860x-led", \
- .num_resources = 1, \
- .resources = &led_resources[_i], \
- .id = _i, \
-}
-
-static struct mfd_cell led_devs[] = {
- PM8606_LED_DEVS(PM8606_LED1_RED),
- PM8606_LED_DEVS(PM8606_LED1_GREEN),
- PM8606_LED_DEVS(PM8606_LED1_BLUE),
- PM8606_LED_DEVS(PM8606_LED2_RED),
- PM8606_LED_DEVS(PM8606_LED2_GREEN),
- PM8606_LED_DEVS(PM8606_LED2_BLUE),
-};
+static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)];
+static struct pm860x_led_pdata led_pdata[ARRAY_SIZE(led_devs)];

static struct resource touch_resources[] = {
{
@@ -611,25 +586,41 @@ static void __devinit device_bk_init(struct pm860x_chip *chip,
}
}

-static void __devinit device_8606_init(struct pm860x_chip *chip,
- struct i2c_client *i2c,
- struct pm860x_platform_data *pdata)
+static void __devinit device_led_init(struct pm860x_chip *chip,
+ struct i2c_client *i2c,
+ struct pm860x_platform_data *pdata)
{
int ret;
+ int i, j, id;

- if (pdata && pdata->led) {
- ret = mfd_add_devices(chip->dev, 0, &led_devs[0],
- ARRAY_SIZE(led_devs),
- &led_resources[0], 0);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to add led "
- "subdev\n");
- goto out_dev;
+ if ((pdata == NULL) || (pdata->led == NULL))
+ return;
+
+ if (pdata->num_leds > ARRAY_SIZE(led_devs))
+ pdata->num_leds = ARRAY_SIZE(led_devs);
+
+ for (i = 0; i < pdata->num_leds; i++) {
+ memcpy(&led_pdata[i], &pdata->led[i],
+ sizeof(struct pm860x_led_pdata));
+ led_devs[i].mfd_data = &led_pdata[i];
+
+ for (j = 0; j < ARRAY_SIZE(led_devs); j++) {
+ id = led_resources[j].start;
+ if (led_pdata[i].flags != id)
+ continue;
+
+ led_devs[i].num_resources = 1;
+ led_devs[i].resources = &led_resources[j],
+ ret = mfd_add_devices(chip->dev, 0,
+ &led_devs[i], 1,
+ &led_resources[j], 0);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add "
+ "led subdev\n");
+ return;
+ }
}
}
- return;
-out_dev:
- device_irq_exit(chip);
}

static void __devinit device_8607_init(struct pm860x_chip *chip,
@@ -748,7 +739,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
switch (chip->id) {
case CHIP_PM8606:
device_bk_init(chip, chip->client, pdata);
- device_8606_init(chip, chip->client, pdata);
+ device_led_init(chip, chip->client, pdata);
break;
case CHIP_PM8607:
device_8607_init(chip, chip->client, pdata);
@@ -759,7 +750,7 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip,
switch (chip->id) {
case CHIP_PM8607:
device_bk_init(chip, chip->companion, pdata);
- device_8606_init(chip, chip->companion, pdata);
+ device_led_init(chip, chip->companion, pdata);
break;
case CHIP_PM8606:
device_8607_init(chip, chip->companion, pdata);
diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h
index f790d37..ff60614 100644
--- a/include/linux/mfd/88pm860x.h
+++ b/include/linux/mfd/88pm860x.h
@@ -356,12 +356,11 @@ struct pm860x_platform_data {
int i2c_port; /* Controlled by GI2C or PI2C */
int irq_mode; /* Clear interrupt by read/write(0/1) */
int irq_base; /* IRQ base number of 88pm860x */
+ int num_leds;
int num_backlights;
struct regulator_init_data *regulator[PM8607_MAX_REGULATOR];
};

-extern char pm860x_led_name[][MFD_NAME_SIZE];
-
extern int pm860x_reg_read(struct i2c_client *, int);
extern int pm860x_reg_write(struct i2c_client *, int, unsigned char);
extern int pm860x_bulk_read(struct i2c_client *, int, int, unsigned char *);
--
1.5.6.5

2011-03-07 15:56:07

by Haojian Zhuang

[permalink] [raw]
Subject: [PATCH] mfd: adopt mfd_data in 88pm860x regulator

Copy 88pm860x platform data into different mfd_data structure for
regulator driver. So move the identification of device node from
regulator driver to mfd driver.

Signed-off-by: Haojian Zhuang <[email protected]>
---
drivers/mfd/88pm860x-core.c | 165 ++++++++++++++++++++++++++----------------
drivers/regulator/88pm8607.c | 46 ++++++------
include/linux/mfd/88pm860x.h | 7 +-
3 files changed, 132 insertions(+), 86 deletions(-)

diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index cec375c..96ea0c6 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -17,6 +17,7 @@
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
#include <linux/mfd/88pm860x.h>
+#include <linux/regulator/machine.h>

#define INT_STATUS_NUM 3

@@ -35,6 +36,27 @@ static struct resource led_resources[] __initdata = {
{PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_IO,},
};

+static struct resource regulator_resources[] __initdata = {
+ {PM8607_ID_BUCK1, PM8607_ID_BUCK1, "buck-1", IORESOURCE_IO,},
+ {PM8607_ID_BUCK2, PM8607_ID_BUCK2, "buck-2", IORESOURCE_IO,},
+ {PM8607_ID_BUCK3, PM8607_ID_BUCK3, "buck-3", IORESOURCE_IO,},
+ {PM8607_ID_LDO1, PM8607_ID_LDO1, "ldo-01", IORESOURCE_IO,},
+ {PM8607_ID_LDO2, PM8607_ID_LDO2, "ldo-02", IORESOURCE_IO,},
+ {PM8607_ID_LDO3, PM8607_ID_LDO3, "ldo-03", IORESOURCE_IO,},
+ {PM8607_ID_LDO4, PM8607_ID_LDO4, "ldo-04", IORESOURCE_IO,},
+ {PM8607_ID_LDO5, PM8607_ID_LDO5, "ldo-05", IORESOURCE_IO,},
+ {PM8607_ID_LDO6, PM8607_ID_LDO6, "ldo-06", IORESOURCE_IO,},
+ {PM8607_ID_LDO7, PM8607_ID_LDO7, "ldo-07", IORESOURCE_IO,},
+ {PM8607_ID_LDO8, PM8607_ID_LDO8, "ldo-08", IORESOURCE_IO,},
+ {PM8607_ID_LDO9, PM8607_ID_LDO9, "ldo-09", IORESOURCE_IO,},
+ {PM8607_ID_LDO10, PM8607_ID_LDO10, "ldo-10", IORESOURCE_IO,},
+ {PM8607_ID_LDO11, PM8607_ID_LDO11, "ldo-11", IORESOURCE_IO,},
+ {PM8607_ID_LDO12, PM8607_ID_LDO12, "ldo-12", IORESOURCE_IO,},
+ {PM8607_ID_LDO13, PM8607_ID_LDO13, "ldo-13", IORESOURCE_IO,},
+ {PM8607_ID_LDO14, PM8607_ID_LDO14, "ldo-14", IORESOURCE_IO,},
+ {PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,},
+};
+
static struct mfd_cell bk_devs[] __initdata = {
{"88pm860x-backlight", 0,},
{"88pm860x-backlight", 1,},
@@ -50,8 +72,30 @@ static struct mfd_cell led_devs[] __initdata = {
{"88pm860x-led", 5,},
};

+static struct mfd_cell regulator_devs[] __initdata = {
+ {"88pm860x-regulator", 0,},
+ {"88pm860x-regulator", 1,},
+ {"88pm860x-regulator", 2,},
+ {"88pm860x-regulator", 3,},
+ {"88pm860x-regulator", 4,},
+ {"88pm860x-regulator", 5,},
+ {"88pm860x-regulator", 6,},
+ {"88pm860x-regulator", 7,},
+ {"88pm860x-regulator", 8,},
+ {"88pm860x-regulator", 9,},
+ {"88pm860x-regulator", 10,},
+ {"88pm860x-regulator", 11,},
+ {"88pm860x-regulator", 12,},
+ {"88pm860x-regulator", 13,},
+ {"88pm860x-regulator", 14,},
+ {"88pm860x-regulator", 15,},
+ {"88pm860x-regulator", 16,},
+ {"88pm860x-regulator", 17,},
+};
+
static struct pm860x_backlight_pdata bk_pdata[ARRAY_SIZE(bk_devs)];
static struct pm860x_led_pdata led_pdata[ARRAY_SIZE(led_devs)];
+static struct regulator_init_data regulator_pdata[ARRAY_SIZE(regulator_devs)];

static struct resource touch_resources[] = {
{
@@ -69,13 +113,6 @@ static struct mfd_cell touch_devs[] = {
},
};

-#define PM8607_REG_RESOURCE(_start, _end) \
-{ \
- .start = PM8607_##_start, \
- .end = PM8607_##_end, \
- .flags = IORESOURCE_IO, \
-}
-
static struct resource power_supply_resources[] = {
{
.name = "88pm860x-power",
@@ -149,52 +186,6 @@ static struct mfd_cell codec_devs[] = {
},
};

-static struct resource regulator_resources[] = {
- PM8607_REG_RESOURCE(BUCK1, BUCK1),
- PM8607_REG_RESOURCE(BUCK2, BUCK2),
- PM8607_REG_RESOURCE(BUCK3, BUCK3),
- PM8607_REG_RESOURCE(LDO1, LDO1),
- PM8607_REG_RESOURCE(LDO2, LDO2),
- PM8607_REG_RESOURCE(LDO3, LDO3),
- PM8607_REG_RESOURCE(LDO4, LDO4),
- PM8607_REG_RESOURCE(LDO5, LDO5),
- PM8607_REG_RESOURCE(LDO6, LDO6),
- PM8607_REG_RESOURCE(LDO7, LDO7),
- PM8607_REG_RESOURCE(LDO8, LDO8),
- PM8607_REG_RESOURCE(LDO9, LDO9),
- PM8607_REG_RESOURCE(LDO10, LDO10),
- PM8607_REG_RESOURCE(LDO12, LDO12),
- PM8607_REG_RESOURCE(VIBRATOR_SET, VIBRATOR_SET),
- PM8607_REG_RESOURCE(LDO14, LDO14),
-};
-
-#define PM8607_REG_DEVS(_id) \
-{ \
- .name = "88pm860x-regulator", \
- .num_resources = 1, \
- .resources = &regulator_resources[PM8607_ID_##_id], \
- .id = PM8607_ID_##_id, \
-}
-
-static struct mfd_cell regulator_devs[] = {
- PM8607_REG_DEVS(BUCK1),
- PM8607_REG_DEVS(BUCK2),
- PM8607_REG_DEVS(BUCK3),
- PM8607_REG_DEVS(LDO1),
- PM8607_REG_DEVS(LDO2),
- PM8607_REG_DEVS(LDO3),
- PM8607_REG_DEVS(LDO4),
- PM8607_REG_DEVS(LDO5),
- PM8607_REG_DEVS(LDO6),
- PM8607_REG_DEVS(LDO7),
- PM8607_REG_DEVS(LDO8),
- PM8607_REG_DEVS(LDO9),
- PM8607_REG_DEVS(LDO10),
- PM8607_REG_DEVS(LDO12),
- PM8607_REG_DEVS(LDO13),
- PM8607_REG_DEVS(LDO14),
-};
-
struct pm860x_irq_data {
int reg;
int mask_reg;
@@ -623,6 +614,64 @@ static void __devinit device_led_init(struct pm860x_chip *chip,
}
}

+static void __devinit device_regulator_init(struct pm860x_chip *chip,
+ struct i2c_client *i2c,
+ struct pm860x_platform_data *pdata)
+{
+ struct regulator_init_data *initdata;
+ int ret;
+ int i, j;
+
+ if ((pdata == NULL) || (pdata->regulator == NULL))
+ return;
+
+ if (pdata->num_regulators > ARRAY_SIZE(regulator_devs))
+ pdata->num_regulators = ARRAY_SIZE(regulator_devs);
+
+ for (i = 0, j = -1; i < pdata->num_regulators; i++) {
+ initdata = &pdata->regulator[i];
+ if (strstr(initdata->constraints.name, "BUCK")) {
+ sscanf(initdata->constraints.name, "BUCK%d", &j);
+ /* BUCK1 ~ BUCK3 */
+ if ((j < 1) || (j > 3)) {
+ dev_err(chip->dev, "Failed to add constraint "
+ "(%s)\n", initdata->constraints.name);
+ goto out;
+ }
+ j = (j - 1) + PM8607_ID_BUCK1;
+ }
+ if (strstr(initdata->constraints.name, "LDO")) {
+ sscanf(initdata->constraints.name, "LDO%d", &j);
+ /* LDO1 ~ LDO15 */
+ if ((j < 1) || (j > 15)) {
+ dev_err(chip->dev, "Failed to add constraint "
+ "(%s)\n", initdata->constraints.name);
+ goto out;
+ }
+ j = (j - 1) + PM8607_ID_LDO1;
+ }
+ if (j == -1) {
+ dev_err(chip->dev, "Failed to add constraint (%s)\n",
+ initdata->constraints.name);
+ goto out;
+ }
+ memcpy(&regulator_pdata[i], &pdata->regulator[i],
+ sizeof(struct regulator_init_data));
+ regulator_devs[i].mfd_data = &regulator_pdata[i];
+ regulator_devs[i].num_resources = 1;
+ regulator_devs[i].resources = &regulator_resources[j];
+
+ ret = mfd_add_devices(chip->dev, 0, &regulator_devs[i], 1,
+ &regulator_resources[j], 0);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to add regulator subdev\n");
+ goto out;
+ }
+ }
+out:
+ return;
+}
+
static void __devinit device_8607_init(struct pm860x_chip *chip,
struct i2c_client *i2c,
struct pm860x_platform_data *pdata)
@@ -678,14 +727,6 @@ static void __devinit device_8607_init(struct pm860x_chip *chip,
if (ret < 0)
goto out;

- ret = mfd_add_devices(chip->dev, 0, &regulator_devs[0],
- ARRAY_SIZE(regulator_devs),
- &regulator_resources[0], 0);
- if (ret < 0) {
- dev_err(chip->dev, "Failed to add regulator subdev\n");
- goto out_dev;
- }
-
if (pdata && pdata->touch) {
ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
ARRAY_SIZE(touch_devs),
@@ -723,6 +764,8 @@ static void __devinit device_8607_init(struct pm860x_chip *chip,
dev_err(chip->dev, "Failed to add codec subdev\n");
goto out_dev;
}
+
+ device_regulator_init(chip, i2c, pdata);
return;
out_dev:
mfd_remove_devices(chip->dev);
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c
index dd63084..8592512 100644
--- a/drivers/regulator/88pm8607.c
+++ b/drivers/regulator/88pm8607.c
@@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
+#include <linux/mfd/core.h>
#include <linux/mfd/88pm860x.h>

struct pm8607_regulator_info {
@@ -394,47 +395,48 @@ static struct pm8607_regulator_info pm8607_regulator_info[] = {
PM8607_LDO(14, LDO14, 0, 4, SUPPLIES_EN12, 6),
};

-static inline struct pm8607_regulator_info *find_regulator_info(int id)
+static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
{
- struct pm8607_regulator_info *info;
+ struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct pm8607_regulator_info *info = NULL;
+ struct regulator_init_data *pdata;
+ struct mfd_cell *cell;
int i;

+ cell = pdev->dev.platform_data;
+ if (cell == NULL)
+ return -ENODEV;
+ pdata = cell->mfd_data;
+ if (pdata == NULL)
+ return -EINVAL;
+
for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
info = &pm8607_regulator_info[i];
- if (info->desc.id == id)
- return info;
+ if (!strcmp(info->desc.name, pdata->constraints.name))
+ break;
}
- return NULL;
-}
-
-static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
-{
- struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
- struct pm860x_platform_data *pdata = chip->dev->platform_data;
- struct pm8607_regulator_info *info = NULL;
-
- info = find_regulator_info(pdev->id);
- if (info == NULL) {
- dev_err(&pdev->dev, "invalid regulator ID specified\n");
+ if (i > ARRAY_SIZE(pm8607_regulator_info)) {
+ dev_err(&pdev->dev, "Failed to find regulator %s\n",
+ pdata->constraints.name);
return -EINVAL;
}

info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
info->chip = chip;

+ /* check DVC ramp slope double */
+ if (!strcmp(info->desc.name, "BUCK3"))
+ if (info->chip->buck3_double)
+ info->slope_double = 1;
+
info->regulator = regulator_register(&info->desc, &pdev->dev,
- pdata->regulator[pdev->id], info);
+ pdata, info);
if (IS_ERR(info->regulator)) {
dev_err(&pdev->dev, "failed to register regulator %s\n",
info->desc.name);
return PTR_ERR(info->regulator);
}

- /* check DVC ramp slope double */
- if (info->desc.id == PM8607_ID_BUCK3)
- if (info->chip->buck3_double)
- info->slope_double = 1;
-
platform_set_drvdata(pdev, info);
return 0;
}
diff --git a/include/linux/mfd/88pm860x.h b/include/linux/mfd/88pm860x.h
index ff60614..a6f6f81 100644
--- a/include/linux/mfd/88pm860x.h
+++ b/include/linux/mfd/88pm860x.h
@@ -131,9 +131,11 @@ enum {
PM8607_ID_LDO8,
PM8607_ID_LDO9,
PM8607_ID_LDO10,
+ PM8607_ID_LDO11,
PM8607_ID_LDO12,
PM8607_ID_LDO13,
PM8607_ID_LDO14,
+ PM8607_ID_LDO15,

PM8607_ID_RG_MAX,
};
@@ -310,8 +312,6 @@ struct pm860x_chip {

};

-#define PM8607_MAX_REGULATOR PM8607_ID_RG_MAX /* 3 Bucks, 13 LDOs */
-
enum {
GI2C_PORT = 0,
PI2C_PORT,
@@ -351,6 +351,7 @@ struct pm860x_platform_data {
struct pm860x_led_pdata *led;
struct pm860x_touch_pdata *touch;
struct pm860x_power_pdata *power;
+ struct regulator_init_data *regulator;

unsigned short companion_addr; /* I2C address of companion chip */
int i2c_port; /* Controlled by GI2C or PI2C */
@@ -358,7 +359,7 @@ struct pm860x_platform_data {
int irq_base; /* IRQ base number of 88pm860x */
int num_leds;
int num_backlights;
- struct regulator_init_data *regulator[PM8607_MAX_REGULATOR];
+ int num_regulators;
};

extern int pm860x_reg_read(struct i2c_client *, int);
--
1.5.6.5

2011-03-07 15:56:10

by Haojian Zhuang

[permalink] [raw]
Subject: [PATCH] mfd: pxa-w1: MFD driver for PXA 1wire control + DS1WM chip

This driver provides registers and IRQ of PXA3xx chips to the ds1wm driver.

Signed-off-by: Haojian Zhuang <[email protected]>
---
drivers/mfd/Kconfig | 7 ++
drivers/mfd/Makefile | 1 +
drivers/mfd/pxa-w1.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 157 insertions(+), 0 deletions(-)
create mode 100644 drivers/mfd/pxa-w1.c

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 5309534..1bb0ebd 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -34,6 +34,13 @@ config MFD_88PM860X
select individual components like voltage regulators, RTC and
battery-charger under the corresponding menus.

+config MFD_PXA_DS1WM
+ tristate "Support DS1WM chip on Marvell silicons"
+ select MFD_CORE
+ help
+ This core driver provides register access for PXA_DS1WM.
+ Actual functionality is handled by the ds1wm drivers.
+
config MFD_SM501
tristate "Support for Silicon Motion SM501"
---help---
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index c7e99df..3d1648f 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -4,6 +4,7 @@

88pm860x-objs := 88pm860x-core.o 88pm860x-i2c.o
obj-$(CONFIG_MFD_88PM860X) += 88pm860x.o
+obj-$(CONFIG_MFD_PXA_DS1WM) += pxa-w1.o
obj-$(CONFIG_MFD_SM501) += sm501.o
obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o
obj-$(CONFIG_MFD_SH_MOBILE_SDHI) += sh_mobile_sdhi.o
diff --git a/drivers/mfd/pxa-w1.c b/drivers/mfd/pxa-w1.c
new file mode 100644
index 0000000..1fb380f
--- /dev/null
+++ b/drivers/mfd/pxa-w1.c
@@ -0,0 +1,149 @@
+/*
+ * Core driver for PXA DS1WM chip.
+ *
+ * Copyright (C) 2010 Marvell <[email protected]>
+ *
+ * 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; version 2 of the License.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/ds1wm.h>
+
+struct pxa_w1_info {
+ struct clk *clk;
+};
+
+static int ds1wm_enable(struct platform_device *pdev)
+{
+ struct device *dev = pdev->dev.parent;
+ struct pxa_w1_info *info = dev_get_drvdata(dev);
+
+ clk_enable(info->clk);
+ dev_dbg(dev, "pxa DS1WM clk (active)\n");
+ return 0;
+}
+
+static int ds1wm_disable(struct platform_device *pdev)
+{
+ struct device *dev = pdev->dev.parent;
+ struct pxa_w1_info *info = dev_get_drvdata(dev);
+
+ clk_disable(info->clk);
+ dev_dbg(dev, "pxa DS1WM clk (in-active)\n");
+ return 0;
+}
+
+static struct resource ds1wm_resources[] __initdata = {
+ {0, 0, "ds1wm-mem", IORESOURCE_MEM,},
+ {0, 0, "ds1wm-irq", IORESOURCE_IRQ,},
+};
+
+static struct ds1wm_driver_data ds1wm_pdata;
+
+static struct mfd_cell ds1wm_cell __initdata = {
+ .name = "ds1wm",
+ .enable = ds1wm_enable,
+ .disable = ds1wm_disable,
+ .mfd_data = &ds1wm_pdata,
+ .num_resources = ARRAY_SIZE(ds1wm_resources),
+ .resources = ds1wm_resources,
+};
+
+static int __devinit pxa_w1_probe(struct platform_device *pdev)
+{
+ struct ds1wm_driver_data *pdata = pdev->dev.platform_data;
+ struct pxa_w1_info *info;
+ struct resource *r;
+ int ret, irq;
+
+ info = kzalloc(sizeof(struct pxa_w1_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (r == NULL) {
+ ret = -ENXIO;
+ goto out;
+ }
+ irq = r->start;
+ if (pdata)
+ ds1wm_pdata.active_high = pdata->active_high;
+ if (ds1wm_pdata.active_high)
+ ds1wm_resources[1].flags |= IORESOURCE_IRQ_HIGHEDGE;
+ else
+ ds1wm_resources[1].flags |= IORESOURCE_IRQ_LOWEDGE;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (r == NULL) {
+ ret = -ENXIO;
+ goto out;
+ }
+ ds1wm_resources[0].end = resource_size(r) - 1;
+
+ info->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(info->clk)) {
+ ret = PTR_ERR(info->clk);
+ goto out;
+ }
+ platform_set_drvdata(pdev, info);
+
+ ds1wm_pdata.clock_rate = clk_get_rate(info->clk);
+ ret = mfd_add_devices(&pdev->dev, pdev->id, &ds1wm_cell, 1, r, irq);
+ if (ret < 0)
+ dev_err(&pdev->dev, "failed to register pxa DS1WM\n");
+
+ return 0;
+out:
+ kfree(info);
+ return ret;
+}
+
+static int __devexit pxa_w1_remove(struct platform_device *pdev)
+{
+ struct pxa_w1_info *info = platform_get_drvdata(pdev);
+
+ mfd_remove_devices(&pdev->dev);
+ clk_put(info->clk);
+ kfree(info);
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+static struct platform_driver pxa_w1_driver = {
+ .driver = {
+ .name = "pxa3xx-w1",
+ .owner = THIS_MODULE,
+ },
+ .probe = pxa_w1_probe,
+ .remove = __devexit_p(pxa_w1_remove),
+};
+
+static int __init pxa_w1_base_init(void)
+{
+ return platform_driver_register(&pxa_w1_driver);
+}
+
+static void __exit pxa_w1_base_exit(void)
+{
+ platform_driver_unregister(&pxa_w1_driver);
+}
+
+module_init(pxa_w1_base_init);
+module_exit(pxa_w1_base_exit);
+
+MODULE_AUTHOR("Jett Zhou <[email protected]>");
+MODULE_DESCRIPTION("one wire driver for PXA");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa-w1");
--
1.5.6.5

2011-03-07 15:55:38

by Haojian Zhuang

[permalink] [raw]
Subject: [PATCH] input: touchscreen: move initialization in 88pm860x

Move the GPADC initialization code from mfd driver to touch driver.

Signed-off-by: Haojian Zhuang <[email protected]>
---
drivers/input/touchscreen/88pm860x-ts.c | 50 ++++++++++++++++++++++++------
drivers/mfd/88pm860x-core.c | 51 -------------------------------
2 files changed, 40 insertions(+), 61 deletions(-)

diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c
index 7d481cc..aa8fe1a 100644
--- a/drivers/input/touchscreen/88pm860x-ts.c
+++ b/drivers/input/touchscreen/88pm860x-ts.c
@@ -11,10 +11,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/input.h>
+#include <linux/mfd/core.h>
#include <linux/mfd/88pm860x.h>
-#include <linux/slab.h>

#define MEAS_LEN (8)
#define ACCURATE_BIT (12)
@@ -152,13 +153,43 @@ static void pm860x_touch_close(struct input_dev *dev)
pm860x_set_bits(touch->i2c, MEAS_EN3, data, 0);
}

+static void __devinit pm860x_gpadc_init(struct i2c_client *i2c,
+ struct pm860x_touch_pdata *pdata)
+{
+ int data;
+
+ /* set GPADC MISC1 register */
+ data = 0;
+ data |= (pdata->gpadc_prebias << 1) & PM8607_GPADC_PREBIAS_MASK;
+ data |= (pdata->slot_cycle << 3) & PM8607_GPADC_SLOT_CYCLE_MASK;
+ data |= (pdata->off_scale << 5) & PM8607_GPADC_OFF_SCALE_MASK;
+ data |= (pdata->sw_cal << 7) & PM8607_GPADC_SW_CAL_MASK;
+ if (data)
+ pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data);
+
+ /* set tsi prebias time */
+ if (pdata->tsi_prebias) {
+ data = pdata->tsi_prebias;
+ pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data);
+ }
+
+ /* set prebias & prechg time of pen detect */
+ data = 0;
+ data |= pdata->pen_prebias & PM8607_PD_PREBIAS_MASK;
+ data |= (pdata->pen_prechg << 5) & PM8607_PD_PRECHG_MASK;
+ if (data)
+ pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data);
+
+ pm860x_set_bits(i2c, PM8607_GPADC_MISC1,
+ PM8607_GPADC_EN, PM8607_GPADC_EN);
+}
+
static int __devinit pm860x_touch_probe(struct platform_device *pdev)
{
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
- struct pm860x_platform_data *pm860x_pdata = \
- pdev->dev.parent->platform_data;
struct pm860x_touch_pdata *pdata = NULL;
struct pm860x_touch *touch;
+ struct mfd_cell *cell;
int irq, ret;

irq = platform_get_irq(pdev, 0);
@@ -167,13 +198,11 @@ static int __devinit pm860x_touch_probe(struct platform_device *pdev)
return -EINVAL;
}

- if (!pm860x_pdata) {
- dev_err(&pdev->dev, "platform data is missing\n");
- return -EINVAL;
- }
-
- pdata = pm860x_pdata->touch;
- if (!pdata) {
+ cell = pdev->dev.platform_data;
+ if (cell == NULL)
+ return -ENODEV;
+ pdata = cell->mfd_data;
+ if (pdata == NULL) {
dev_err(&pdev->dev, "touchscreen data is missing\n");
return -EINVAL;
}
@@ -226,6 +255,7 @@ static int __devinit pm860x_touch_probe(struct platform_device *pdev)
goto out_rg;
}

+ pm860x_gpadc_init(touch->i2c, pdata);
platform_set_drvdata(pdev, touch);
INIT_DELAYED_WORK(&touch->poll_work, pm860x_poll_work);
return 0;
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index 42c4fa2..7879569 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -362,53 +362,6 @@ static struct irq_chip pm860x_irq_chip = {
.irq_disable = pm860x_irq_disable,
};

-static int __devinit device_gpadc_init(struct pm860x_chip *chip,
- struct pm860x_platform_data *pdata)
-{
- struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
- : chip->companion;
- int data;
- int ret;
-
- /* initialize GPADC without activating it */
-
- if (!pdata || !pdata->touch)
- return -EINVAL;
-
- /* 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;
- }
-
- ret = pm860x_set_bits(i2c, PM8607_GPADC_MISC1,
- PM8607_GPADC_EN, PM8607_GPADC_EN);
-out:
- return ret;
-}
-
static int __devinit device_irq_init(struct pm860x_chip *chip,
struct pm860x_platform_data *pdata)
{
@@ -758,10 +711,6 @@ static void __devinit device_8607_init(struct pm860x_chip *chip,
goto out;
}

- ret = device_gpadc_init(chip, pdata);
- if (ret < 0)
- goto out;
-
ret = device_irq_init(chip, pdata);
if (ret < 0)
goto out;
--
1.5.6.5

2011-03-08 23:24:01

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH] mfd: adopt mfd_data in 88pm860x regulator

On Mon, Mar 07, 2011 at 11:43:11PM +0800, Haojian Zhuang wrote:
> Copy 88pm860x platform data into different mfd_data structure for
> regulator driver. So move the identification of device node from
> regulator driver to mfd driver.
>
> Signed-off-by: Haojian Zhuang <[email protected]>

Acked-by: Mark Brown <[email protected]>

but if there's any in-tree users of the device I'd expect they need
their platform data updated?

2011-03-13 06:38:45

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: [PATCH] mfd: add workqueue thread into 88pm860x

On Mon, Mar 07, 2011 at 11:43:13PM +0800, Haojian Zhuang wrote:
> Create workqueue thread in 88pm860x driver since 88pm860x driver
> needs to handle event in workqueue.
>
> Avoid to use system workqueue since i2c operation cost a lot of
> time. It would impact system performance.

No, not anymore - the concurrency managed workqueues implemented by
Tejun allow scheduling longer-running jobs on the system workqueue
without impacting other users.

Thanks.

--
Dmitry

2011-03-13 06:44:33

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: [PATCH] input: touchscreen: use polling mode in 88pm860x

On Mon, Mar 07, 2011 at 11:43:14PM +0800, Haojian Zhuang wrote:
> Measuring point on touchscreen with IRQ mode can only monitor pen-down
> event. If finger is moving on touchscreen, it can't be monitored by
> IRQ pen-down event. So switch to polling mode after pen-down event.
>

Instead of scheduling work you could stay in the interrupt handler
(which is a separate thread) and poll from it. Or is it a nested
interrupt and it is sharing the interrupt thread?

Thanks.

--
Dmitry

2011-03-13 06:45:15

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: [PATCH] input: set the long press detection in 88pm860x onkey

On Mon, Mar 07, 2011 at 11:43:18PM +0800, Haojian Zhuang wrote:
> Move the long-press detection from onkey handler to probe function. Avoid
> unnecessary I2C operation in onkey handler.
>
> Signed-off-by: Haojian Zhuang <[email protected]>

Acked-by: Dmitry Torokhov <[email protected]>

> ---
> drivers/input/misc/88pm860x_onkey.c | 6 +++---
> 1 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/input/misc/88pm860x_onkey.c b/drivers/input/misc/88pm860x_onkey.c
> index 3dca3c1..1abc77e 100644
> --- a/drivers/input/misc/88pm860x_onkey.c
> +++ b/drivers/input/misc/88pm860x_onkey.c
> @@ -50,9 +50,6 @@ static irqreturn_t pm860x_onkey_handler(int irq, void *data)
> ret &= ONKEY_STATUS;
> input_report_key(info->idev, KEY_POWER, ret);
> input_sync(info->idev);
> -
> - /* Enable 8-second long onkey detection */
> - pm860x_set_bits(info->i2c, PM8607_WAKEUP, 3, LONG_ONKEY_EN);
> return IRQ_HANDLED;
> }
>
> @@ -105,6 +102,9 @@ static int __devinit pm860x_onkey_probe(struct platform_device *pdev)
> }
>
> platform_set_drvdata(pdev, info);
> +
> + /* Enable 8-second long onkey detection */
> + pm860x_set_bits(info->i2c, PM8607_WAKEUP, 3, LONG_ONKEY_EN);
> return 0;
>
> out_irq:
> --
> 1.5.6.5
>

--
Dmitry

2011-03-14 10:51:24

by Samuel Ortiz

[permalink] [raw]
Subject: Re: [PATCH] rtc: add 88pm860x rtc

Hi Haojian,

On Mon, Mar 07, 2011 at 11:43:17PM +0800, Haojian Zhuang wrote:
> Support RTC component in 88PM860x. Also support synchronize time
> 88PM860x RTC to another RTC device. It should be implemented in
> sync callback API.
>
> While 88PM860x RTC is enabled, it can do RTC calibration to gurantee
> enough power is supplied on VRTC domain of 88PM860x.
>
> Signed-off-by: Haojian Zhuang <[email protected]>
> ---
> drivers/mfd/88pm860x-core.c | 30 ++++++++++++++++++++++++++++++
> drivers/rtc/Kconfig | 10 ++++++++++
> drivers/rtc/Makefile | 1 +
> include/linux/mfd/88pm860x.h | 6 ++++++
rtc-88pm860x.c is missing from this patch.

Cheers,
Samuel.

--
Intel Open Source Technology Centre
http://oss.intel.com/

2011-03-14 10:56:43

by Samuel Ortiz

[permalink] [raw]
Subject: Re: [PATCH] mfd: adopt mfd_data in 88pm860x backlight

Hi Haojian,

On Mon, Mar 07, 2011 at 11:43:09PM +0800, Haojian Zhuang wrote:
> Copy 88pm860x platform data into different mfd_data structure for
> backlight driver. So move the identification of device node from
> backlight driver to mfd driver.
Patch applied, thanks.

Cheers,
Samuel.

--
Intel Open Source Technology Centre
http://oss.intel.com/

2011-03-14 11:23:22

by Samuel Ortiz

[permalink] [raw]
Subject: Re: [PATCH] mfd: adopt mfd_data in 88pm860x led

Hi Haojian,

On Mon, Mar 07, 2011 at 11:43:10PM +0800, Haojian Zhuang wrote:
> Copy 88pm860x platform data into different mfd_data structure for
> led driver. So move the identification of device node from led
> driver to mfd driver.
Patch applied, thanks.

Cheers,
Samuel.

--
Intel Open Source Technology Centre
http://oss.intel.com/

2011-03-14 11:23:44

by Samuel Ortiz

[permalink] [raw]
Subject: Re: [PATCH] mfd: adopt mfd_data in 88pm860x regulator

Hi Haojian,

On Mon, Mar 07, 2011 at 11:43:11PM +0800, Haojian Zhuang wrote:
> Copy 88pm860x platform data into different mfd_data structure for
> regulator driver. So move the identification of device node from
> regulator driver to mfd driver.
Patch applied as well, thanks.

Cheers,
Samuel.

--
Intel Open Source Technology Centre
http://oss.intel.com/

2011-03-14 11:24:25

by Samuel Ortiz

[permalink] [raw]
Subject: Re: [PATCH] mfd: adopt mfd_data in 88pm860x

Hi Haojian,

On Mon, Mar 07, 2011 at 11:43:12PM +0800, Haojian Zhuang wrote:
> Copy 88pm860x platform data into different mfd_data structure for
> onkey/touch/codec/power driver. So move the identification of
> device node from those drivers to mfd driver.
I applied this patch too.

Cheers,
Samuel.

--
Intel Open Source Technology Centre
http://oss.intel.com/

2011-03-14 11:25:08

by Samuel Ortiz

[permalink] [raw]
Subject: Re: [PATCH] mfd: append additional read write on 88pm860x

Hi Haojian,

On Mon, Mar 07, 2011 at 11:43:16PM +0800, Haojian Zhuang wrote:
> Append the additional read/write operation on 88pm860x for accessing
> test page in 88PM860x.
Patch applied, thanks.

Cheers,
Samuel.

--
Intel Open Source Technology Centre
http://oss.intel.com/

2011-03-14 11:28:46

by Samuel Ortiz

[permalink] [raw]
Subject: Re: [PATCH] mfd: pxa-w1: MFD driver for PXA 1wire control + DS1WM chip

Hi Haojian,

On Mon, Mar 07, 2011 at 11:43:20PM +0800, Haojian Zhuang wrote:
> This driver provides registers and IRQ of PXA3xx chips to the ds1wm driver.
Why is this an MFD driver ?

Cheers,
Samuel.

--
Intel Open Source Technology Centre
http://oss.intel.com/

2011-03-14 12:35:09

by Haojian Zhuang

[permalink] [raw]
Subject: RE: [PATCH] mfd: pxa-w1: MFD driver for PXA 1wire control + DS1WM chip



>-----Original Message-----
>From: Samuel Ortiz [mailto:[email protected]]
>Sent: 2011??3??14?? 7:29 PM
>To: Haojian Zhuang
>Cc: [email protected]; [email protected]; [email protected];
>[email protected]; [email protected];
>[email protected]; [email protected]; [email protected]
>Subject: Re: [PATCH] mfd: pxa-w1: MFD driver for PXA 1wire control +
>DS1WM chip
>
>Hi Haojian,
>
>On Mon, Mar 07, 2011 at 11:43:20PM +0800, Haojian Zhuang wrote:
>> This driver provides registers and IRQ of PXA3xx chips to the ds1wm
>driver.
>Why is this an MFD driver ?
>
>Cheers,
>Samuel.
>
>--
>Intel Open Source Technology Centre
>http://oss.intel.com/

Hi Samuel,

Because there's already a DS1WM driver in drivers/w1/masters/ds1wm.c. In PXA silicons, W1 controler is compatible with this driver. So we implement it as MFD driver, like htc-pasic3.c.

Best Regards
Haojian
????{.n?+???????+%?????ݶ??w??{.n?+????{??G?????{ay?ʇڙ?,j??f???h?????????z_??(?階?ݢj"???m??????G????????????&???~???iO???z??v?^?m???? ????????I?

2011-03-14 12:41:56

by Haojian Zhuang

[permalink] [raw]
Subject: RE: [PATCH] input: touchscreen: use polling mode in 88pm860x



>-----Original Message-----
>From: Dmitry Torokhov [mailto:[email protected]]
>Sent: 2011??3??13?? 2:44 PM
>To: Haojian Zhuang
>Cc: [email protected]; [email protected]; [email protected];
>[email protected]; [email protected];
>[email protected]; [email protected]
>Subject: Re: [PATCH] input: touchscreen: use polling mode in 88pm860x
>
>On Mon, Mar 07, 2011 at 11:43:14PM +0800, Haojian Zhuang wrote:
>> Measuring point on touchscreen with IRQ mode can only monitor pen-down
>> event. If finger is moving on touchscreen, it can't be monitored by
>> IRQ pen-down event. So switch to polling mode after pen-down event.
>>
>
>Instead of scheduling work you could stay in the interrupt handler
>(which is a separate thread) and poll from it. Or is it a nested
>interrupt and it is sharing the interrupt thread?
>
>Thanks.
>
>--
>Dmitry

I'm using a nested interrupt. Do you mean that I should keep polling in the nested interrupt handler?

Thanks
Haojian
????{.n?+???????+%?????ݶ??w??{.n?+????{??G?????{ay?ʇڙ?,j??f???h?????????z_??(?階?ݢj"???m??????G????????????&???~???iO???z??v?^?m???? ????????I?

2011-03-14 13:09:41

by Haojian Zhuang

[permalink] [raw]
Subject: RE: [PATCH] rtc: add 88pm860x rtc



>-----Original Message-----
>From: Samuel Ortiz [mailto:[email protected]]
>Sent: 2011??3??14?? 6:51 PM
>To: Haojian Zhuang
>Cc: [email protected]; [email protected]; [email protected];
>[email protected]; [email protected];
>[email protected]; [email protected]; [email protected]
>Subject: Re: [PATCH] rtc: add 88pm860x rtc
>
>Hi Haojian,
>
>On Mon, Mar 07, 2011 at 11:43:17PM +0800, Haojian Zhuang wrote:
>> Support RTC component in 88PM860x. Also support synchronize time
>> 88PM860x RTC to another RTC device. It should be implemented in
>> sync callback API.
>>
>> While 88PM860x RTC is enabled, it can do RTC calibration to gurantee
>> enough power is supplied on VRTC domain of 88PM860x.
>>
>> Signed-off-by: Haojian Zhuang <[email protected]>
>> ---
>> drivers/mfd/88pm860x-core.c | 30 ++++++++++++++++++++++++++++++
>> drivers/rtc/Kconfig | 10 ++++++++++
>> drivers/rtc/Makefile | 1 +
>> include/linux/mfd/88pm860x.h | 6 ++++++
>rtc-88pm860x.c is missing from this patch.
>
>Cheers,
>Samuel.
>
>--
>Intel Open Source Technology Centre
>http://oss.intel.com/

Hi Samuel,

I'm sorry on missing the rtc file. Now I attach it in mail. I'm sorry on inconvient.

Thanks
Haojian


Attachments:
0001-rtc-add-88pm860x-rtc.patch (17.28 kB)
0001-rtc-add-88pm860x-rtc.patch

2011-03-14 19:55:53

by Jean-François Dagenais

[permalink] [raw]
Subject: Re: [PATCH] mfd: pxa-w1: MFD driver for PXA 1wire control + DS1WM chip


On Mar 14, 2011, at 8:34, Haojian Zhuang wrote:

>
>
>> -----Original Message-----
>> From: Samuel Ortiz [mailto:[email protected]]
>> Sent: 2011年3月14日 7:29 PM
>> To: Haojian Zhuang
>> Cc: [email protected]; [email protected]; [email protected];
>> [email protected]; [email protected];
>> [email protected]; [email protected]; [email protected]
>> Subject: Re: [PATCH] mfd: pxa-w1: MFD driver for PXA 1wire control +
>> DS1WM chip
>>
>> Hi Haojian,
>>
>> On Mon, Mar 07, 2011 at 11:43:20PM +0800, Haojian Zhuang wrote:
>>> This driver provides registers and IRQ of PXA3xx chips to the ds1wm
>> driver.
>> Why is this an MFD driver ?
>>
>> Cheers,
>> Samuel.
>>
>> --
>> Intel Open Source Technology Centre
>> http://oss.intel.com/
>
> Hi Samuel,
>
> Because there's already a DS1WM driver in drivers/w1/masters/ds1wm.c. In PXA silicons, W1 controler is compatible with this driver. So we implement it as MFD driver, like htc-pasic3.c.
>
> Best Regards
> Haojian--
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>
I successfully made this driver work with a ds1wm core inside a virtex5 interfaced through PCI express. The base address of the ds1wm is at a certain offset in the BAR0 of the virtex5. We used a shared interrupt for the ds1wm and the other function our virtex5 does. This is on a x86 platform. I posted a couple of patches last week which added multi-slave search support to the existing ds1wm driver.

look for [w1 PATCHES 3/3] Complete the 1-wire (w1) ds1wm driver search algo

I declare the presence of the ds1wm from my pci_probe of the FPGA device.

static int ds1wm_enable(struct platform_device *pdev)
{
struct MYSTRUCT* pMyDevStruct = dev_get_drvdata(pdev->dev.parent);
u32* address = pHudDev->bar0KernAddr + REG_OFFSET_RESET;
... custom stuff you need to do to make the ds1wm power up
return 0;
}

static int ds1wm_disable(struct platform_device *pdev)
{
... undo what you did in enable.
return 0;
}
#define REG_1_WIRE_BASE 0xXX
static struct ds1wm_driver_data ds1wm_pdata = {
.active_high = 1,
.clock_rate = 125000000 // PCIe transaction clock
};


static struct resource ds1wm_resources[] = {
[0] = {
.start = REG_1_WIRE_BASE,
.end = REG_1_WIRE_BASE + (5*sizeof(int)), // that's 5 registers each on a 32 bit address, we omit the 6th one, i.e. control reg
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 0, // cell define as offset from parent base resource, i.e. 0 means same
.end = 0,
.flags = IORESOURCE_IRQ,
},
};

static struct mfd_cell ds1wm_cell = {
.name = "ds1wm",
.enable = ds1wm_enable,
.disable = ds1wm_disable,
.driver_data = &ds1wm_pdata,
.num_resources = 2,
.resources = ds1wm_resources,
};

[...] in my pci_probe() [...]
ds1wm_cell.platform_data = &ds1wm_cell;
ds1wm_cell.data_size = sizeof(ds1wm_cell);
PDEBUG( "adding ds1wm core in mfd subsys, irq: %d\n", pPciDev->irq);
if(0 > mfd_add_devices(&pPciDev->dev, 0, &ds1wm_cell, 1, &pPciDev->resource[0], pPciDev->irq))
{
printk(KERN_CRIT PRINTK_ID "%s failed to add ds1wm \n", pHudDev->hwDeviceName);
goto cancel_and_exit;
}
PDEBUG( "ds1wm core added to mfd subsys\n");

GOOD LUCK!

FYI, here's the intro I had for these patches:
===================

The first patch add generic functionnality to w1_io for Resume Command [A5h]
lots of slaves support. I found it useful for multi-commands/reset workflows
with the same slave on a multi-slave bus.

This DS2408 w1 slave driver is not complete for all the
features of the chip, but its sufficient if you use it as
a simple IO expander. Enjoy!

The ds1wm had Kconfig dependencies towards ARM && HAVE_CLK. I took them
out since I was using the ds1wm on an x86_64 platform (ds1wm in a FPGA through
pcie) and found them irrelevant.

The clock freq/divisors at the top of ds1wm.c did not have the MSB set to 1.
This bit is CLK_EN which turns the whole prescaler and dividers on. The driver
never mentionned this bit either, so I just included this bit right in the table
entries. I also took the liberty to add a couple of entries to the table. The
spec doesn't explicitely mentions these possibilities but the description and
examination of the core shows the prescalers & dividers can be used for more
than the table explicitely shows. The table I enlarged still doesn't cover all
possibilities, but it's a good start.

I also made a few tweaks to a couple of the read and write algorithms which
made sense while I had my head very deep in the ds1wm documentation. We stressed
it a lot with 10+ slaves on the bus, many ds2408, ds2431 and ds2433 at the same
time doing extensive interaction. It proved quite stable in our production
environment.-

2011-03-15 05:02:18

by Dmitry Torokhov

[permalink] [raw]
Subject: Re: [PATCH] input: touchscreen: use polling mode in 88pm860x

On Mon, Mar 14, 2011 at 05:41:35AM -0700, Haojian Zhuang wrote:
>
>
> >-----Original Message-----
> >From: Dmitry Torokhov [mailto:[email protected]]
> >Sent: 2011年3月13日 2:44 PM
> >To: Haojian Zhuang
> >Cc: [email protected]; [email protected]; [email protected];
> >[email protected]; [email protected];
> >[email protected]; [email protected]
> >Subject: Re: [PATCH] input: touchscreen: use polling mode in 88pm860x
> >
> >On Mon, Mar 07, 2011 at 11:43:14PM +0800, Haojian Zhuang wrote:
> >> Measuring point on touchscreen with IRQ mode can only monitor pen-down
> >> event. If finger is moving on touchscreen, it can't be monitored by
> >> IRQ pen-down event. So switch to polling mode after pen-down event.
> >>
> >
> >Instead of scheduling work you could stay in the interrupt handler
> >(which is a separate thread) and poll from it. Or is it a nested
> >interrupt and it is sharing the interrupt thread?
> >
> >Thanks.
> >
> >--
> >Dmitry
>
> I'm using a nested interrupt. Do you mean that I should keep polling in the nested interrupt handler?
>

No, I do not believe you can poll from the nested handler since I
believe it shares the thread with other interrupts. In non-nested case
you could though.

Thanks.

--
Dmitry