From eb8956074e7652e802be5f078080c704c2c87104 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 6 Apr 2011 16:52:52 +0200 Subject: mfd: Add platform data pointer back Now that we have a way to pass MFD cells down to the sub drivers, we can gradually get rid of mfd_data by putting the platform pointer back in place. Signed-off-by: Samuel Ortiz --- drivers/mfd/mfd-core.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index f4c8c844b913..0902523af62d 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -88,6 +88,13 @@ static int mfd_add_device(struct device *parent, int id, pdev->dev.parent = parent; + if (cell->pdata_size) { + ret = platform_device_add_data(pdev, + cell->platform_data, cell->pdata_size); + if (ret) + goto fail_res; + } + ret = mfd_platform_add_cell(pdev, cell); if (ret) goto fail_res; -- cgit v1.2.3 From 1f235a3785dbcfb324ff228048b859a3bd1e1a59 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 6 Apr 2011 00:20:24 +0200 Subject: mfd: Use mfd cell platform_data for ab3550 cells platform bits With the addition of a platform device mfd_cell pointer, MFD drivers can go back to passing platform data back to their sub drivers. This allows for an mfd_cell->mfd_data removal and thus keep the sub drivers MFD agnostic. This is mostly needed for non MFD aware sub drivers. Acked-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab3550-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab3550-core.c b/drivers/mfd/ab3550-core.c index ff86acf3e6bd..3d7dce671b93 100644 --- a/drivers/mfd/ab3550-core.c +++ b/drivers/mfd/ab3550-core.c @@ -1320,8 +1320,10 @@ static int __init ab3550_probe(struct i2c_client *client, goto exit_no_ops; /* Set up and register the platform devices. */ - for (i = 0; i < AB3550_NUM_DEVICES; i++) - ab3550_devs[i].mfd_data = ab3550_plf_data->dev_data[i]; + for (i = 0; i < AB3550_NUM_DEVICES; i++) { + ab3550_devs[i].platform_data = ab3550_plf_data->dev_data[i]; + ab3550_devs[i].pdata_size = ab3550_plf_data->dev_data_sz[i]; + } err = mfd_add_devices(&client->dev, 0, ab3550_devs, ARRAY_SIZE(ab3550_devs), NULL, -- cgit v1.2.3 From a771e36e16e9fdacb2bb8d3b9be50be68f211b82 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 6 Apr 2011 00:41:43 +0200 Subject: mfd: Use mfd cell platform_data for ab3100 cells platform bits With the addition of a platform device mfd_cell pointer, MFD drivers can go back to passing platform data back to their sub drivers. This allows for an mfd_cell->mfd_data removal and thus keep the sub drivers MFD agnostic. This is mostly needed for non MFD aware sub drivers. Acked-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab3100-core.c | 6 ++++-- drivers/regulator/ab3100.c | 3 +-- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index a751927047ac..a20e1c41bed2 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -949,8 +949,10 @@ static int __devinit ab3100_probe(struct i2c_client *client, goto exit_no_ops; /* Set up and register the platform devices. */ - for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) - ab3100_devs[i].mfd_data = ab3100_plf_data; + for (i = 0; i < ARRAY_SIZE(ab3100_devs); i++) { + ab3100_devs[i].platform_data = ab3100_plf_data; + ab3100_devs[i].pdata_size = sizeof(struct ab3100_platform_data); + } err = mfd_add_devices(&client->dev, 0, ab3100_devs, ARRAY_SIZE(ab3100_devs), NULL, 0); diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index b1d77946e9c6..585e4946fe0a 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c @@ -17,7 +17,6 @@ #include #include #include -#include /* LDO registers and some handy masking definitions for AB3100 */ #define AB3100_LDO_A 0x40 @@ -582,7 +581,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = { static int __devinit ab3100_regulators_probe(struct platform_device *pdev) { - struct ab3100_platform_data *plfdata = mfd_get_data(pdev); + struct ab3100_platform_data *plfdata = pdev->dev.platform_data; int err = 0; u8 data; int i; -- cgit v1.2.3 From ec71974f2a3ae052cdbb57a92ce3c3b34ebd7b5d Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 6 Apr 2011 11:38:14 +0200 Subject: mmc: Use device platform_data to retrieve tmio_mmc platform bits With the addition of the platform device mfd_cell pointer, we can now cleanly pass the sub device drivers platform data pointers through the regular device platform_data one, and get rid of mfd_get_data() Cc: Ian Molton Cc: Guennadi Liakhovetski Cc: Philipp Zabel Acked-by: Dmitry Eremin-Solenikov Signed-off-by: Samuel Ortiz --- drivers/mfd/asic3.c | 3 ++- drivers/mfd/t7l66xb.c | 3 ++- drivers/mfd/tc6387xb.c | 3 ++- drivers/mfd/tc6393xb.c | 3 ++- drivers/mmc/host/tmio_mmc.c | 2 +- 5 files changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 0b4d5b23bec9..a26280240bb9 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -777,7 +777,8 @@ static struct mfd_cell asic3_cell_mmc = { .name = "tmio-mmc", .enable = asic3_mmc_enable, .disable = asic3_mmc_disable, - .mfd_data = &asic3_mmc_data, + .platform_data = &asic3_mmc_data, + .pdata_size = sizeof(asic3_mmc_data), .num_resources = ARRAY_SIZE(asic3_mmc_resources), .resources = asic3_mmc_resources, }; diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index 42830e692964..5ef0b8fba107 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -170,7 +170,8 @@ static struct mfd_cell t7l66xb_cells[] = { .name = "tmio-mmc", .enable = t7l66xb_mmc_enable, .disable = t7l66xb_mmc_disable, - .mfd_data = &t7166xb_mmc_data, + .platform_data = &t7166xb_mmc_data, + .pdata_size = sizeof(t7166xb_mmc_data), .num_resources = ARRAY_SIZE(t7l66xb_mmc_resources), .resources = t7l66xb_mmc_resources, }, diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c index b006f7cee952..ad715bf49cac 100644 --- a/drivers/mfd/tc6387xb.c +++ b/drivers/mfd/tc6387xb.c @@ -131,7 +131,8 @@ static struct mfd_cell tc6387xb_cells[] = { .name = "tmio-mmc", .enable = tc6387xb_mmc_enable, .disable = tc6387xb_mmc_disable, - .mfd_data = &tc6387xb_mmc_data, + .platform_data = &tc6387xb_mmc_data, + .pdata_size = sizeof(tc6387xb_mmc_data), .num_resources = ARRAY_SIZE(tc6387xb_mmc_resources), .resources = tc6387xb_mmc_resources, }, diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index fc53ce287601..8e9b1b765f1a 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -393,7 +393,8 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = { .name = "tmio-mmc", .enable = tc6393xb_mmc_enable, .resume = tc6393xb_mmc_resume, - .mfd_data = &tc6393xb_mmc_data, + .platform_data = &tc6393xb_mmc_data, + .pdata_size = sizeof(tc6393xb_mmc_data), .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources), .resources = tc6393xb_mmc_resources, }, diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c index 14479f9ef53f..8d185de90d20 100644 --- a/drivers/mmc/host/tmio_mmc.c +++ b/drivers/mmc/host/tmio_mmc.c @@ -69,7 +69,7 @@ static int __devinit tmio_mmc_probe(struct platform_device *pdev) if (pdev->num_resources != 2) goto out; - pdata = mfd_get_data(pdev); + pdata = pdev->dev.platform_data; if (!pdata || !pdata->hclk) goto out; -- cgit v1.2.3 From 121ea573aeb7e9b1d79effa8ef7970031aebda12 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 6 Apr 2011 11:41:03 +0200 Subject: w1: Use device platform_data to retrieve ds1wm platform bits With the addition of the platform device mfd_cell pointer, we can now cleanly pass the sub device drivers platform data pointers through the regular device platform_data one, and get rid of mfd_get_data(). Cc: Matt Reimer Cc: Philipp Zabel Signed-off-by: Samuel Ortiz --- drivers/mfd/asic3.c | 3 ++- drivers/mfd/htc-pasic3.c | 3 ++- drivers/w1/masters/ds1wm.c | 12 ++++++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index a26280240bb9..77a3971e00bd 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -676,7 +676,8 @@ static struct mfd_cell asic3_cell_ds1wm = { .name = "ds1wm", .enable = ds1wm_enable, .disable = ds1wm_disable, - .mfd_data = &ds1wm_pdata, + .platform_data = &ds1wm_pdata, + .pdata_size = sizeof(ds1wm_pdata), .num_resources = ARRAY_SIZE(ds1wm_resources), .resources = ds1wm_resources, }; diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c index fb9770b39a32..95a4ff48b282 100644 --- a/drivers/mfd/htc-pasic3.c +++ b/drivers/mfd/htc-pasic3.c @@ -117,7 +117,8 @@ static struct mfd_cell ds1wm_cell __initdata = { .name = "ds1wm", .enable = ds1wm_enable, .disable = ds1wm_disable, - .mfd_data = &ds1wm_pdata, + .platform_data = &ds1wm_pdata, + .pdata_size = sizeof(ds1wm_pdata), .num_resources = 2, .resources = ds1wm_resources, }; diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c index 2f4fa02744a5..0855d6cce3c1 100644 --- a/drivers/w1/masters/ds1wm.c +++ b/drivers/w1/masters/ds1wm.c @@ -216,7 +216,7 @@ static int ds1wm_find_divisor(int gclk) static void ds1wm_up(struct ds1wm_data *ds1wm_data) { int divisor; - struct ds1wm_driver_data *plat = mfd_get_data(ds1wm_data->pdev); + struct ds1wm_driver_data *plat = ds1wm_data->pdev->dev.platform_data; if (ds1wm_data->cell->enable) ds1wm_data->cell->enable(ds1wm_data->pdev); @@ -351,13 +351,21 @@ static int ds1wm_probe(struct platform_device *pdev) ret = -ENOMEM; goto err0; } - plat = mfd_get_data(pdev); /* calculate bus shift from mem resource */ ds1wm_data->bus_shift = resource_size(res) >> 3; ds1wm_data->pdev = pdev; ds1wm_data->cell = mfd_get_cell(pdev); + if (!ds1wm_data->cell) { + ret = -ENODEV; + goto err1; + } + plat = pdev->dev.platform_data; + if (!plat) { + ret = -ENODEV; + goto err1; + } res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { -- cgit v1.2.3 From 8ac93beaab97d56b6e702cc625438f533e361ea5 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 6 Apr 2011 11:48:53 +0200 Subject: mfd: Pass htc-pasic3 led platform data through the cell platform_data Cc: Philipp Zabel Signed-off-by: Samuel Ortiz --- drivers/mfd/htc-pasic3.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c index 95a4ff48b282..2808bd125d13 100644 --- a/drivers/mfd/htc-pasic3.c +++ b/drivers/mfd/htc-pasic3.c @@ -173,6 +173,8 @@ static int __init pasic3_probe(struct platform_device *pdev) } if (pdata && pdata->led_pdata) { + led_cell.platform_data = pdata->led_pdata; + led_cell.pdata_size = sizeof(struct pasic3_leds_machinfo); ret = mfd_add_devices(&pdev->dev, pdev->id, &led_cell, 1, r, 0); if (ret < 0) dev_warn(dev, "failed to register LED device\n"); -- cgit v1.2.3 From 9e554696c03e04c51d095c1c451e26a8cb6a84fa Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 6 Apr 2011 11:56:04 +0200 Subject: mfd: Use mfd cell platform_data for wl1273 cells platform bits With the addition of a platform device mfd_cell pointer, MFD drivers can go back to passing platform data back to their sub drivers. This allows for an mfd_cell->mfd_data removal and thus keep the sub drivers MFD agnostic. This is mostly needed for non MFD aware sub drivers. Cc: Matti Aaltonen Signed-off-by: Samuel Ortiz --- drivers/media/radio/radio-wl1273.c | 2 +- drivers/mfd/wl1273-core.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index e2550dc2944f..46cacf845049 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -1990,7 +1990,7 @@ static int wl1273_fm_radio_remove(struct platform_device *pdev) static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev) { - struct wl1273_core **core = mfd_get_data(pdev); + struct wl1273_core **core = pdev->dev.platform_data; struct wl1273_device *radio; struct v4l2_ctrl *ctrl; int r = 0; diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c index 04914f2836c0..63d250d9a366 100644 --- a/drivers/mfd/wl1273-core.c +++ b/drivers/mfd/wl1273-core.c @@ -217,7 +217,8 @@ static int __devinit wl1273_core_probe(struct i2c_client *client, cell = &core->cells[children]; cell->name = "wl1273_fm_radio"; - cell->mfd_data = &core; + cell->platform_data = &core; + cell->pdata_size = sizeof(core); children++; core->read = wl1273_fm_read_reg; @@ -231,7 +232,8 @@ static int __devinit wl1273_core_probe(struct i2c_client *client, dev_dbg(&client->dev, "%s: Have codec.\n", __func__); cell->name = "wl1273-codec"; - cell->mfd_data = &core; + cell->platform_data = &core; + cell->pdata_size = sizeof(core); children++; } -- cgit v1.2.3 From 1f8c666caddb4cd0c547bbedbc9f98c7bf51e176 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 6 Apr 2011 12:13:25 +0200 Subject: fb: Use platform_data to retrieve tmiofb platform bits With the addition of the platform device mfd_cell pointer, we can now cleanly pass the sub device drivers platform data pointers through the regular device platform_data one, and get rid of mfd_get_data(). Cc: Ian Molton Cc: Paul Mundt Acked-by: Dmitry Eremin-Solenikov Signed-off-by: Samuel Ortiz --- drivers/mfd/tc6393xb.c | 3 ++- drivers/video/tmiofb.c | 12 +++++------- 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 8e9b1b765f1a..b3d5852b0698 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -694,7 +694,8 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) } tc6393xb_cells[TC6393XB_CELL_NAND].mfd_data = tcpd->nand_data; - tc6393xb_cells[TC6393XB_CELL_FB].mfd_data = tcpd->fb_data; + tc6393xb_cells[TC6393XB_CELL_FB].platform_data = tcpd->fb_data; + tc6393xb_cells[TC6393XB_CELL_FB].pdata_size = sizeof(*tcpd->fb_data); ret = mfd_add_devices(&dev->dev, dev->id, tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells), diff --git a/drivers/video/tmiofb.c b/drivers/video/tmiofb.c index 0c341d739604..cd1c4dcef8fd 100644 --- a/drivers/video/tmiofb.c +++ b/drivers/video/tmiofb.c @@ -250,7 +250,7 @@ static irqreturn_t tmiofb_irq(int irq, void *__info) */ static int tmiofb_hw_stop(struct platform_device *dev) { - struct tmio_fb_data *data = mfd_get_data(dev); + struct tmio_fb_data *data = dev->dev.platform_data; struct fb_info *info = platform_get_drvdata(dev); struct tmiofb_par *par = info->par; @@ -311,7 +311,7 @@ static int tmiofb_hw_init(struct platform_device *dev) */ static void tmiofb_hw_mode(struct platform_device *dev) { - struct tmio_fb_data *data = mfd_get_data(dev); + struct tmio_fb_data *data = dev->dev.platform_data; struct fb_info *info = platform_get_drvdata(dev); struct fb_videomode *mode = info->mode; struct tmiofb_par *par = info->par; @@ -557,8 +557,7 @@ static int tmiofb_ioctl(struct fb_info *fbi, static struct fb_videomode * tmiofb_find_mode(struct fb_info *info, struct fb_var_screeninfo *var) { - struct tmio_fb_data *data = - mfd_get_data(to_platform_device(info->device)); + struct tmio_fb_data *data = info->device->platform_data; struct fb_videomode *best = NULL; int i; @@ -578,8 +577,7 @@ static int tmiofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct fb_videomode *mode; - struct tmio_fb_data *data = - mfd_get_data(to_platform_device(info->device)); + struct tmio_fb_data *data = info->device->platform_data; mode = tmiofb_find_mode(info, var); if (!mode || var->bits_per_pixel > 16) @@ -680,7 +678,7 @@ static struct fb_ops tmiofb_ops = { static int __devinit tmiofb_probe(struct platform_device *dev) { const struct mfd_cell *cell = mfd_get_cell(dev); - struct tmio_fb_data *data = mfd_get_data(dev); + struct tmio_fb_data *data = dev->dev.platform_data; struct resource *ccr = platform_get_resource(dev, IORESOURCE_MEM, 1); struct resource *lcr = platform_get_resource(dev, IORESOURCE_MEM, 0); struct resource *vram = platform_get_resource(dev, IORESOURCE_MEM, 2); -- cgit v1.2.3 From 7dc00a0d14992d0083fefccad7839ac837ea55bc Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 6 Apr 2011 12:20:49 +0200 Subject: mtd: Use platform_data to retrieve tmio_nand platform bits With the addition of the platform device mfd_cell pointer, we can now cleanly pass the sub device drivers platform data pointers through the regular device platform_data one, and get rid of mfd_get_data(). Cc: Ian Molton Cc: Artem Bityutskiy Acked-by: Dmitry Eremin-Solenikov Signed-off-by: Samuel Ortiz --- drivers/mfd/t7l66xb.c | 3 ++- drivers/mfd/tc6393xb.c | 4 +++- drivers/mtd/nand/tmio_nand.c | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index 5ef0b8fba107..91ad21ef7721 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -383,7 +383,8 @@ static int t7l66xb_probe(struct platform_device *dev) t7l66xb_attach_irq(dev); - t7l66xb_cells[T7L66XB_CELL_NAND].mfd_data = pdata->nand_data; + t7l66xb_cells[T7L66XB_CELL_NAND].platform_data = pdata->nand_data; + t7l66xb_cells[T7L66XB_CELL_NAND].pdata_size = sizeof(*pdata->nand_data); ret = mfd_add_devices(&dev->dev, dev->id, t7l66xb_cells, ARRAY_SIZE(t7l66xb_cells), diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index b3d5852b0698..9612264f0e6d 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -693,7 +693,9 @@ static int __devinit tc6393xb_probe(struct platform_device *dev) goto err_setup; } - tc6393xb_cells[TC6393XB_CELL_NAND].mfd_data = tcpd->nand_data; + tc6393xb_cells[TC6393XB_CELL_NAND].platform_data = tcpd->nand_data; + tc6393xb_cells[TC6393XB_CELL_NAND].pdata_size = + sizeof(*tcpd->nand_data); tc6393xb_cells[TC6393XB_CELL_FB].platform_data = tcpd->fb_data; tc6393xb_cells[TC6393XB_CELL_FB].pdata_size = sizeof(*tcpd->fb_data); diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index 14c578707824..c004e474631b 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -372,7 +372,7 @@ static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio) static int tmio_probe(struct platform_device *dev) { - struct tmio_nand_data *data = mfd_get_data(dev); + struct tmio_nand_data *data = dev->dev.platform_data; struct resource *fcr = platform_get_resource(dev, IORESOURCE_MEM, 0); struct resource *ccr = platform_get_resource(dev, -- cgit v1.2.3 From 3271d382c3ffe61ef3d059ef47e635dbe031030e Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 8 Apr 2011 01:23:57 +0200 Subject: mfd: Use mfd cell platform_data for timberdale cells platform bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the addition of a device platform mfd_cell pointer, MFD drivers can go back to passing platform data back to their sub drivers. This allows for an mfd_cell->mfd_data removal and thus keep the sub drivers MFD agnostic. This is mostly needed for non MFD aware sub drivers. Acked-by: Richard Röjfors Signed-off-by: Samuel Ortiz --- drivers/dma/timb_dma.c | 3 +- drivers/gpio/timbgpio.c | 6 +-- drivers/i2c/busses/i2c-ocores.c | 3 +- drivers/i2c/busses/i2c-xiic.c | 3 +- drivers/media/radio/radio-timb.c | 3 +- drivers/media/video/timblogiw.c | 3 +- drivers/mfd/timberdale.c | 81 ++++++++++++++++++++++++++-------------- drivers/net/ks8842.c | 3 +- drivers/spi/xilinx_spi.c | 3 +- 9 files changed, 64 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c index d2c75feff7df..f69f90a61873 100644 --- a/drivers/dma/timb_dma.c +++ b/drivers/dma/timb_dma.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -685,7 +684,7 @@ static irqreturn_t td_irq(int irq, void *devid) static int __devinit td_probe(struct platform_device *pdev) { - struct timb_dma_platform_data *pdata = mfd_get_data(pdev); + struct timb_dma_platform_data *pdata = pdev->dev.platform_data; struct timb_dma *td; struct resource *iomem; int irq; diff --git a/drivers/gpio/timbgpio.c b/drivers/gpio/timbgpio.c index edbe1eae531f..0265872e57d1 100644 --- a/drivers/gpio/timbgpio.c +++ b/drivers/gpio/timbgpio.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -229,7 +228,7 @@ static int __devinit timbgpio_probe(struct platform_device *pdev) struct gpio_chip *gc; struct timbgpio *tgpio; struct resource *iomem; - struct timbgpio_platform_data *pdata = mfd_get_data(pdev); + struct timbgpio_platform_data *pdata = pdev->dev.platform_data; int irq = platform_get_irq(pdev, 0); if (!pdata || pdata->nr_pins > 32) { @@ -320,13 +319,14 @@ err_mem: static int __devexit timbgpio_remove(struct platform_device *pdev) { int err; + struct timbgpio_platform_data *pdata = pdev->dev.platform_data; struct timbgpio *tgpio = platform_get_drvdata(pdev); struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); int irq = platform_get_irq(pdev, 0); if (irq >= 0 && tgpio->irq_base > 0) { int i; - for (i = 0; i < tgpio->gpio.ngpio; i++) { + for (i = 0; i < pdata->nr_pins; i++) { irq_set_chip(tgpio->irq_base + i, NULL); irq_set_chip_data(tgpio->irq_base + i, NULL); } diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index fee1a2613861..1b46a9d9f907 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -49,7 +49,6 @@ #include #include #include -#include #include #include #include @@ -306,7 +305,7 @@ static int __devinit ocores_i2c_probe(struct platform_device *pdev) return -EIO; } - pdata = mfd_get_data(pdev); + pdata = pdev->dev.platform_data; if (pdata) { i2c->regstep = pdata->regstep; i2c->clock_khz = pdata->clock_khz; diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index e9d5ff4d1496..4bb68f35caf2 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -705,7 +704,7 @@ static int __devinit xiic_i2c_probe(struct platform_device *pdev) if (irq < 0) goto resource_missing; - pdata = mfd_get_data(pdev); + pdata = (struct xiic_i2c_platform_data *) pdev->dev.platform_data; if (!pdata) return -EINVAL; diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c index 1e3a8dd820a4..a185610b376b 100644 --- a/drivers/media/radio/radio-timb.c +++ b/drivers/media/radio/radio-timb.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -149,7 +148,7 @@ static const struct v4l2_file_operations timbradio_fops = { static int __devinit timbradio_probe(struct platform_device *pdev) { - struct timb_radio_platform_data *pdata = mfd_get_data(pdev); + struct timb_radio_platform_data *pdata = pdev->dev.platform_data; struct timbradio *tr; int err; diff --git a/drivers/media/video/timblogiw.c b/drivers/media/video/timblogiw.c index 84d4c7c83435..fc611ebeb82c 100644 --- a/drivers/media/video/timblogiw.c +++ b/drivers/media/video/timblogiw.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -791,7 +790,7 @@ static int __devinit timblogiw_probe(struct platform_device *pdev) { int err; struct timblogiw *lw = NULL; - struct timb_video_platform_data *pdata = mfd_get_data(pdev); + struct timb_video_platform_data *pdata = pdev->dev.platform_data; if (!pdata) { dev_err(&pdev->dev, "No platform data\n"); diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c index 94c6c8afad12..69272e4e3459 100644 --- a/drivers/mfd/timberdale.c +++ b/drivers/mfd/timberdale.c @@ -384,7 +384,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = { .name = "timb-dma", .num_resources = ARRAY_SIZE(timberdale_dma_resources), .resources = timberdale_dma_resources, - .mfd_data = &timb_dma_platform_data, + .platform_data = &timb_dma_platform_data, + .pdata_size = sizeof(timb_dma_platform_data), }, { .name = "timb-uart", @@ -395,37 +396,43 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = { .name = "xiic-i2c", .num_resources = ARRAY_SIZE(timberdale_xiic_resources), .resources = timberdale_xiic_resources, - .mfd_data = &timberdale_xiic_platform_data, + .platform_data = &timberdale_xiic_platform_data, + .pdata_size = sizeof(timberdale_xiic_platform_data), }, { .name = "timb-gpio", .num_resources = ARRAY_SIZE(timberdale_gpio_resources), .resources = timberdale_gpio_resources, - .mfd_data = &timberdale_gpio_platform_data, + .platform_data = &timberdale_gpio_platform_data, + .pdata_size = sizeof(timberdale_gpio_platform_data), }, { .name = "timb-video", .num_resources = ARRAY_SIZE(timberdale_video_resources), .resources = timberdale_video_resources, - .mfd_data = &timberdale_video_platform_data, + .platform_data = &timberdale_video_platform_data, + .pdata_size = sizeof(timberdale_video_platform_data), }, { .name = "timb-radio", .num_resources = ARRAY_SIZE(timberdale_radio_resources), .resources = timberdale_radio_resources, - .mfd_data = &timberdale_radio_platform_data, + .platform_data = &timberdale_radio_platform_data, + .pdata_size = sizeof(timberdale_radio_platform_data), }, { .name = "xilinx_spi", .num_resources = ARRAY_SIZE(timberdale_spi_resources), .resources = timberdale_spi_resources, - .mfd_data = &timberdale_xspi_platform_data, + .platform_data = &timberdale_xspi_platform_data, + .pdata_size = sizeof(timberdale_xspi_platform_data), }, { .name = "ks8842", .num_resources = ARRAY_SIZE(timberdale_eth_resources), .resources = timberdale_eth_resources, - .mfd_data = &timberdale_ks8842_platform_data, + .platform_data = &timberdale_ks8842_platform_data, + .pdata_size = sizeof(timberdale_ks8842_platform_data), }, }; @@ -434,7 +441,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { .name = "timb-dma", .num_resources = ARRAY_SIZE(timberdale_dma_resources), .resources = timberdale_dma_resources, - .mfd_data = &timb_dma_platform_data, + .platform_data = &timb_dma_platform_data, + .pdata_size = sizeof(timb_dma_platform_data), }, { .name = "timb-uart", @@ -450,13 +458,15 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { .name = "xiic-i2c", .num_resources = ARRAY_SIZE(timberdale_xiic_resources), .resources = timberdale_xiic_resources, - .mfd_data = &timberdale_xiic_platform_data, + .platform_data = &timberdale_xiic_platform_data, + .pdata_size = sizeof(timberdale_xiic_platform_data), }, { .name = "timb-gpio", .num_resources = ARRAY_SIZE(timberdale_gpio_resources), .resources = timberdale_gpio_resources, - .mfd_data = &timberdale_gpio_platform_data, + .platform_data = &timberdale_gpio_platform_data, + .pdata_size = sizeof(timberdale_gpio_platform_data), }, { .name = "timb-mlogicore", @@ -467,25 +477,29 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = { .name = "timb-video", .num_resources = ARRAY_SIZE(timberdale_video_resources), .resources = timberdale_video_resources, - .mfd_data = &timberdale_video_platform_data, + .platform_data = &timberdale_video_platform_data, + .pdata_size = sizeof(timberdale_video_platform_data), }, { .name = "timb-radio", .num_resources = ARRAY_SIZE(timberdale_radio_resources), .resources = timberdale_radio_resources, - .mfd_data = &timberdale_radio_platform_data, + .platform_data = &timberdale_radio_platform_data, + .pdata_size = sizeof(timberdale_radio_platform_data), }, { .name = "xilinx_spi", .num_resources = ARRAY_SIZE(timberdale_spi_resources), .resources = timberdale_spi_resources, - .mfd_data = &timberdale_xspi_platform_data, + .platform_data = &timberdale_xspi_platform_data, + .pdata_size = sizeof(timberdale_xspi_platform_data), }, { .name = "ks8842", .num_resources = ARRAY_SIZE(timberdale_eth_resources), .resources = timberdale_eth_resources, - .mfd_data = &timberdale_ks8842_platform_data, + .platform_data = &timberdale_ks8842_platform_data, + .pdata_size = sizeof(timberdale_ks8842_platform_data), }, }; @@ -494,7 +508,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = { .name = "timb-dma", .num_resources = ARRAY_SIZE(timberdale_dma_resources), .resources = timberdale_dma_resources, - .mfd_data = &timb_dma_platform_data, + .platform_data = &timb_dma_platform_data, + .pdata_size = sizeof(timb_dma_platform_data), }, { .name = "timb-uart", @@ -505,31 +520,36 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = { .name = "xiic-i2c", .num_resources = ARRAY_SIZE(timberdale_xiic_resources), .resources = timberdale_xiic_resources, - .mfd_data = &timberdale_xiic_platform_data, + .platform_data = &timberdale_xiic_platform_data, + .pdata_size = sizeof(timberdale_xiic_platform_data), }, { .name = "timb-gpio", .num_resources = ARRAY_SIZE(timberdale_gpio_resources), .resources = timberdale_gpio_resources, - .mfd_data = &timberdale_gpio_platform_data, + .platform_data = &timberdale_gpio_platform_data, + .pdata_size = sizeof(timberdale_gpio_platform_data), }, { .name = "timb-video", .num_resources = ARRAY_SIZE(timberdale_video_resources), .resources = timberdale_video_resources, - .mfd_data = &timberdale_video_platform_data, + .platform_data = &timberdale_video_platform_data, + .pdata_size = sizeof(timberdale_video_platform_data), }, { .name = "timb-radio", .num_resources = ARRAY_SIZE(timberdale_radio_resources), .resources = timberdale_radio_resources, - .mfd_data = &timberdale_radio_platform_data, + .platform_data = &timberdale_radio_platform_data, + .pdata_size = sizeof(timberdale_radio_platform_data), }, { .name = "xilinx_spi", .num_resources = ARRAY_SIZE(timberdale_spi_resources), .resources = timberdale_spi_resources, - .mfd_data = &timberdale_xspi_platform_data, + .platform_data = &timberdale_xspi_platform_data, + .pdata_size = sizeof(timberdale_xspi_platform_data), }, }; @@ -538,7 +558,8 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = { .name = "timb-dma", .num_resources = ARRAY_SIZE(timberdale_dma_resources), .resources = timberdale_dma_resources, - .mfd_data = &timb_dma_platform_data, + .platform_data = &timb_dma_platform_data, + .pdata_size = sizeof(timb_dma_platform_data), }, { .name = "timb-uart", @@ -549,37 +570,43 @@ static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = { .name = "ocores-i2c", .num_resources = ARRAY_SIZE(timberdale_ocores_resources), .resources = timberdale_ocores_resources, - .mfd_data = &timberdale_ocores_platform_data, + .platform_data = &timberdale_ocores_platform_data, + .pdata_size = sizeof(timberdale_ocores_platform_data), }, { .name = "timb-gpio", .num_resources = ARRAY_SIZE(timberdale_gpio_resources), .resources = timberdale_gpio_resources, - .mfd_data = &timberdale_gpio_platform_data, + .platform_data = &timberdale_gpio_platform_data, + .pdata_size = sizeof(timberdale_gpio_platform_data), }, { .name = "timb-video", .num_resources = ARRAY_SIZE(timberdale_video_resources), .resources = timberdale_video_resources, - .mfd_data = &timberdale_video_platform_data, + .platform_data = &timberdale_video_platform_data, + .pdata_size = sizeof(timberdale_video_platform_data), }, { .name = "timb-radio", .num_resources = ARRAY_SIZE(timberdale_radio_resources), .resources = timberdale_radio_resources, - .mfd_data = &timberdale_radio_platform_data, + .platform_data = &timberdale_radio_platform_data, + .pdata_size = sizeof(timberdale_radio_platform_data), }, { .name = "xilinx_spi", .num_resources = ARRAY_SIZE(timberdale_spi_resources), .resources = timberdale_spi_resources, - .mfd_data = &timberdale_xspi_platform_data, + .platform_data = &timberdale_xspi_platform_data, + .pdata_size = sizeof(timberdale_xspi_platform_data), }, { .name = "ks8842", .num_resources = ARRAY_SIZE(timberdale_eth_resources), .resources = timberdale_eth_resources, - .mfd_data = &timberdale_ks8842_platform_data, + .platform_data = &timberdale_ks8842_platform_data, + .pdata_size = sizeof(timberdale_ks8842_platform_data), }, }; diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c index f0d8346d0fa5..4d40626b3bfa 100644 --- a/drivers/net/ks8842.c +++ b/drivers/net/ks8842.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -1146,7 +1145,7 @@ static int __devinit ks8842_probe(struct platform_device *pdev) struct resource *iomem; struct net_device *netdev; struct ks8842_adapter *adapter; - struct ks8842_platform_data *pdata = mfd_get_data(pdev); + struct ks8842_platform_data *pdata = pdev->dev.platform_data; u16 id; unsigned i; diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c index c69c6f2c2c5c..4d2c75df886c 100644 --- a/drivers/spi/xilinx_spi.c +++ b/drivers/spi/xilinx_spi.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -471,7 +470,7 @@ static int __devinit xilinx_spi_probe(struct platform_device *dev) struct spi_master *master; u8 i; - pdata = mfd_get_data(dev); + pdata = dev->dev.platform_data; if (pdata) { num_cs = pdata->num_chipselect; little_endian = pdata->little_endian; -- cgit v1.2.3 From 9abd768a8d470d58071e30c57d1fa4a7090518bc Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 6 Apr 2011 13:21:01 +0200 Subject: mfd: Use mfd cell platform_data for rdc321x cells platform bits With the addition of a platform device mfd_cell pointer, MFD drivers can go back to passing platform data back to their sub drivers. This allows for an mfd_cell->mfd_data removal and thus keep the sub drivers MFD agnostic. This is mostly needed for non MFD aware sub drivers. Cc: Grant Likely Cc: Wim Van Sebroeck Cc: Florian Fainelli Signed-off-by: Samuel Ortiz --- drivers/gpio/rdc321x-gpio.c | 3 +-- drivers/mfd/rdc321x-southbridge.c | 6 ++++-- drivers/watchdog/rdc321x_wdt.c | 3 +-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/rdc321x-gpio.c b/drivers/gpio/rdc321x-gpio.c index a9bda881935a..2762698e0204 100644 --- a/drivers/gpio/rdc321x-gpio.c +++ b/drivers/gpio/rdc321x-gpio.c @@ -27,7 +27,6 @@ #include #include #include -#include #include struct rdc321x_gpio { @@ -136,7 +135,7 @@ static int __devinit rdc321x_gpio_probe(struct platform_device *pdev) struct rdc321x_gpio *rdc321x_gpio_dev; struct rdc321x_gpio_pdata *pdata; - pdata = mfd_get_data(pdev); + pdata = pdev->dev.platform_data; if (!pdata) { dev_err(&pdev->dev, "no platform data supplied\n"); return -ENODEV; diff --git a/drivers/mfd/rdc321x-southbridge.c b/drivers/mfd/rdc321x-southbridge.c index 10dbe6374a89..809bd4a61089 100644 --- a/drivers/mfd/rdc321x-southbridge.c +++ b/drivers/mfd/rdc321x-southbridge.c @@ -61,12 +61,14 @@ static struct mfd_cell rdc321x_sb_cells[] = { .name = "rdc321x-wdt", .resources = rdc321x_wdt_resource, .num_resources = ARRAY_SIZE(rdc321x_wdt_resource), - .mfd_data = &rdc321x_wdt_pdata, + .platform_data = &rdc321x_wdt_pdata, + .pdata_size = sizeof(rdc321x_wdt_pdata), }, { .name = "rdc321x-gpio", .resources = rdc321x_gpio_resources, .num_resources = ARRAY_SIZE(rdc321x_gpio_resources), - .mfd_data = &rdc321x_gpio_pdata, + .platform_data = &rdc321x_gpio_pdata, + .pdata_size = sizeof(rdc321x_gpio_pdata), }, }; diff --git a/drivers/watchdog/rdc321x_wdt.c b/drivers/watchdog/rdc321x_wdt.c index d8e725082fdc..428f8a1583e8 100644 --- a/drivers/watchdog/rdc321x_wdt.c +++ b/drivers/watchdog/rdc321x_wdt.c @@ -37,7 +37,6 @@ #include #include #include -#include #define RDC_WDT_MASK 0x80000000 /* Mask */ #define RDC_WDT_EN 0x00800000 /* Enable bit */ @@ -232,7 +231,7 @@ static int __devinit rdc321x_wdt_probe(struct platform_device *pdev) struct resource *r; struct rdc321x_wdt_pdata *pdata; - pdata = mfd_get_data(pdev); + pdata = pdev->dev.platform_data; if (!pdata) { dev_err(&pdev->dev, "no platform data supplied\n"); return -ENODEV; -- cgit v1.2.3 From c8a03c96b61bd03a3603bfe5381848c0b40e99be Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Fri, 8 Apr 2011 01:55:01 +0200 Subject: mfd: Use mfd cell platform_data for mc13xxx cells platform bits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the addition of a platform device mfd_cell pointer, MFD drivers can go back to passing platform data back to their sub drivers. This allows for an mfd_cell->mfd_data removal and thus keep the sub drivers MFD agnostic. This is mostly needed for non MFD aware sub drivers. Cc: Mark Brown Cc: Liam Girdwood Acked-by: Uwe Kleine-König Signed-off-by: Samuel Ortiz --- drivers/leds/leds-mc13783.c | 7 +++---- drivers/mfd/mc13xxx-core.c | 12 +++++++----- drivers/regulator/mc13783-regulator.c | 7 ++++--- drivers/regulator/mc13892-regulator.c | 7 ++++--- 4 files changed, 18 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c index 126ca7955f6e..f369e56d6547 100644 --- a/drivers/leds/leds-mc13783.c +++ b/drivers/leds/leds-mc13783.c @@ -22,7 +22,6 @@ #include #include #include -#include #include struct mc13783_led { @@ -184,7 +183,7 @@ static int __devinit mc13783_led_setup(struct mc13783_led *led, int max_current) static int __devinit mc13783_leds_prepare(struct platform_device *pdev) { - struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev); + struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent); int ret = 0; int reg = 0; @@ -265,7 +264,7 @@ out: static int __devinit mc13783_led_probe(struct platform_device *pdev) { - struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev); + struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); struct mc13783_led_platform_data *led_cur; struct mc13783_led *led, *led_dat; int ret, i; @@ -352,7 +351,7 @@ err_free: static int __devexit mc13783_led_remove(struct platform_device *pdev) { - struct mc13783_leds_platform_data *pdata = mfd_get_data(pdev); + struct mc13783_leds_platform_data *pdata = dev_get_platdata(&pdev->dev); struct mc13783_led *led = platform_get_drvdata(pdev); struct mc13783 *dev = dev_get_drvdata(pdev->dev.parent); int i; diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c index 668634e89e81..7e4d44bf92ab 100644 --- a/drivers/mfd/mc13xxx-core.c +++ b/drivers/mfd/mc13xxx-core.c @@ -683,13 +683,14 @@ out: EXPORT_SYMBOL_GPL(mc13783_adc_do_conversion); static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, - const char *format, void *pdata) + const char *format, void *pdata, size_t pdata_size) { char buf[30]; const char *name = mc13xxx_get_chipname(mc13xxx); struct mfd_cell cell = { - .mfd_data = pdata, + .platform_data = pdata, + .pdata_size = pdata_size, }; /* there is no asnprintf in the kernel :-( */ @@ -705,7 +706,7 @@ static int mc13xxx_add_subdevice_pdata(struct mc13xxx *mc13xxx, static int mc13xxx_add_subdevice(struct mc13xxx *mc13xxx, const char *format) { - return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL); + return mc13xxx_add_subdevice_pdata(mc13xxx, format, NULL, 0); } static int mc13xxx_probe(struct spi_device *spi) @@ -764,7 +765,7 @@ err_revision: if (pdata->flags & MC13XXX_USE_REGULATOR) { mc13xxx_add_subdevice_pdata(mc13xxx, "%s-regulator", - &pdata->regulators); + &pdata->regulators, sizeof(pdata->regulators)); } if (pdata->flags & MC13XXX_USE_RTC) @@ -774,7 +775,8 @@ err_revision: mc13xxx_add_subdevice(mc13xxx, "%s-ts"); if (pdata->flags & MC13XXX_USE_LED) - mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", pdata->leds); + mc13xxx_add_subdevice_pdata(mc13xxx, "%s-led", + pdata->leds, sizeof(*pdata->leds)); return 0; } diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index b8a00c7fa441..730f43ad415b 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -337,7 +336,8 @@ static int __devinit mc13783_regulator_probe(struct platform_device *pdev) { struct mc13xxx_regulator_priv *priv; struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent); - struct mc13783_regulator_platform_data *pdata = mfd_get_data(pdev); + struct mc13783_regulator_platform_data *pdata = + dev_get_platdata(&pdev->dev); struct mc13783_regulator_init_data *init_data; int i, ret; @@ -381,7 +381,8 @@ err: static int __devexit mc13783_regulator_remove(struct platform_device *pdev) { struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); - struct mc13783_regulator_platform_data *pdata = mfd_get_data(pdev); + struct mc13783_regulator_platform_data *pdata = + dev_get_platdata(&pdev->dev); int i; platform_set_drvdata(pdev, NULL); diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index 6f15168e5ed4..1b8f7398a4a8 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -521,7 +520,8 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev) { struct mc13xxx_regulator_priv *priv; struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent); - struct mc13xxx_regulator_platform_data *pdata = mfd_get_data(pdev); + struct mc13xxx_regulator_platform_data *pdata = + dev_get_platdata(&pdev->dev); struct mc13xxx_regulator_init_data *init_data; int i, ret; u32 val; @@ -595,7 +595,8 @@ err_free: static int __devexit mc13892_regulator_remove(struct platform_device *pdev) { struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); - struct mc13xxx_regulator_platform_data *pdata = mfd_get_data(pdev); + struct mc13xxx_regulator_platform_data *pdata = + dev_get_platdata(&pdev->dev); int i; platform_set_drvdata(pdev, NULL); -- cgit v1.2.3 From 3d2bdf759f48f9b0a0ffcd798f3e9a3228d6455d Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 6 Apr 2011 16:02:25 +0200 Subject: mfd: Use mfd cell platform_data for janz cells platform bits With the addition of a platform device mfd_cell pointer, MFD drivers can go back to passing platform data back to their sub drivers. This allows for an mfd_cell->mfd_data removal and thus keep the sub drivers MFD agnostic. This is mostly needed for non MFD aware sub drivers. Cc: Ira W. Snyder Cc: Wolfgang Grandegger Cc: Grant Likely Signed-off-by: Samuel Ortiz --- drivers/gpio/janz-ttl.c | 3 +-- drivers/mfd/janz-cmodio.c | 3 ++- drivers/net/can/janz-ican3.c | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/janz-ttl.c b/drivers/gpio/janz-ttl.c index 2514fb075f4a..813ac077e5d7 100644 --- a/drivers/gpio/janz-ttl.c +++ b/drivers/gpio/janz-ttl.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -150,7 +149,7 @@ static int __devinit ttl_probe(struct platform_device *pdev) struct resource *res; int ret; - pdata = mfd_get_data(pdev); + pdata = pdev->dev.platform_data; if (!pdata) { dev_err(dev, "no platform data\n"); ret = -ENXIO; diff --git a/drivers/mfd/janz-cmodio.c b/drivers/mfd/janz-cmodio.c index fc4191137e90..5c2a06acb77f 100644 --- a/drivers/mfd/janz-cmodio.c +++ b/drivers/mfd/janz-cmodio.c @@ -86,7 +86,8 @@ static int __devinit cmodio_setup_subdevice(struct cmodio_device *priv, /* Add platform data */ pdata->modno = modno; - cell->mfd_data = pdata; + cell->platform_data = pdata; + cell->pdata_size = sizeof(*pdata); /* MODULbus registers -- PCI BAR3 is big-endian MODULbus access */ res->flags = IORESOURCE_MEM; diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index 587fba48cdd9..f1942cab35f6 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -1644,7 +1643,7 @@ static int __devinit ican3_probe(struct platform_device *pdev) struct device *dev; int ret; - pdata = mfd_get_data(pdev); + pdata = pdev->dev.platform_data; if (!pdata) return -ENXIO; -- cgit v1.2.3 From a4579ad2bb6557834ebfafc8d2942891516fb4ad Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 6 Apr 2011 15:57:17 +0200 Subject: mfd: Use mfd cell platform_data for twl4030 codec cells platform bits With the addition of a platform device mfd_cell pointer, MFD drivers can go back to passing platform data back to their sub drivers. This allows for an mfd_cell->mfd_data removal and thus keep the sub drivers MFD agnostic. This is mostly needed for non MFD aware sub drivers. Cc: Peter Ujfalusi Cc: Mark Brown Cc: Liam Girdwood Cc: Dmitry Torokhov Signed-off-by: Samuel Ortiz --- drivers/input/misc/twl4030-vibra.c | 3 +-- drivers/mfd/twl4030-codec.c | 6 ++++-- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c index 6a11694e3fc7..014dd4ad0d4f 100644 --- a/drivers/input/misc/twl4030-vibra.c +++ b/drivers/input/misc/twl4030-vibra.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include @@ -197,7 +196,7 @@ static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops, static int __devinit twl4030_vibra_probe(struct platform_device *pdev) { - struct twl4030_codec_vibra_data *pdata = mfd_get_data(pdev); + struct twl4030_codec_vibra_data *pdata = pdev->dev.platform_data; struct vibra_info *info; int ret; diff --git a/drivers/mfd/twl4030-codec.c b/drivers/mfd/twl4030-codec.c index c02fded316c9..315b5ead8437 100644 --- a/drivers/mfd/twl4030-codec.c +++ b/drivers/mfd/twl4030-codec.c @@ -208,13 +208,15 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev) if (pdata->audio) { cell = &codec->cells[childs]; cell->name = "twl4030-codec"; - cell->mfd_data = pdata->audio; + cell->platform_data = pdata->audio; + cell->pdata_size = sizeof(*pdata->audio); childs++; } if (pdata->vibra) { cell = &codec->cells[childs]; cell->name = "twl4030-vibra"; - cell->mfd_data = pdata->vibra; + cell->platform_data = pdata->vibra; + cell->pdata_size = sizeof(*pdata->vibra); childs++; } -- cgit v1.2.3 From a7c98ce25cfa600bd614134a82d22bcb7bcb9d65 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 11 May 2011 10:33:25 +0200 Subject: mfd: Use mfd cell platform_data for tps6105x cells platform bits With the addition of a platform device mfd_cell pointer, MFD drivers can go back to passing platform data back to their sub drivers. This allows for an mfd_cell->mfd_data removal and thus keep the sub drivers MFD agnostic. This is mostly needed for non MFD aware sub drivers. Cc: Mark Brown Cc: Liam Girdwood Cc: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/tps6105x.c | 3 ++- drivers/regulator/tps6105x-regulator.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/tps6105x.c b/drivers/mfd/tps6105x.c index 46d8205646b6..a293b978e27c 100644 --- a/drivers/mfd/tps6105x.c +++ b/drivers/mfd/tps6105x.c @@ -183,7 +183,8 @@ static int __devinit tps6105x_probe(struct i2c_client *client, /* Set up and register the platform devices. */ for (i = 0; i < ARRAY_SIZE(tps6105x_cells); i++) { /* One state holder for all drivers, this is simple */ - tps6105x_cells[i].mfd_data = tps6105x; + tps6105x_cells[i].platform_data = tps6105x; + tps6105x_cells[i].pdata_size = sizeof(*tps6105x); } ret = mfd_add_devices(&client->dev, 0, tps6105x_cells, diff --git a/drivers/regulator/tps6105x-regulator.c b/drivers/regulator/tps6105x-regulator.c index 1661499feda4..a4d7f4540c18 100644 --- a/drivers/regulator/tps6105x-regulator.c +++ b/drivers/regulator/tps6105x-regulator.c @@ -137,7 +137,7 @@ static struct regulator_desc tps6105x_regulator_desc = { */ static int __devinit tps6105x_regulator_probe(struct platform_device *pdev) { - struct tps6105x *tps6105x = mfd_get_data(pdev); + struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev); struct tps6105x_platform_data *pdata = tps6105x->pdata; int ret; @@ -164,7 +164,7 @@ static int __devinit tps6105x_regulator_probe(struct platform_device *pdev) static int __devexit tps6105x_regulator_remove(struct platform_device *pdev) { - struct tps6105x *tps6105x = platform_get_drvdata(pdev); + struct tps6105x *tps6105x = dev_get_platdata(&pdev->dev); regulator_unregister(tps6105x->regulator); return 0; } -- cgit v1.2.3 From 07259a7092e47b9fbb5c8bfdad45fa4c7dbbc051 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 6 Apr 2011 16:26:56 +0200 Subject: mfd: Use mfd cell platform_data for 88pm860x cells platform bits With the addition of a platform device mfd_cell pointer, MFD drivers can go back to passing platform back to their sub drivers. This allows for an mfd_cell->mfd_data removal and thus keep the sub drivers MFD agnostic. This is mostly needed for non MFD aware sub drivers. Cc: Mark Brown Cc: Liam Girdwood Cc: Richard Purdie Acked-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/leds/leds-88pm860x.c | 7 +------ drivers/mfd/88pm860x-core.c | 18 ++++++++++++------ drivers/regulator/88pm8607.c | 7 +------ drivers/video/backlight/88pm860x_bl.c | 7 +------ 4 files changed, 15 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c index 416def84d045..0d4c16678ace 100644 --- a/drivers/leds/leds-88pm860x.c +++ b/drivers/leds/leds-88pm860x.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #define LED_PWM_SHIFT (3) @@ -171,7 +170,6 @@ static int pm860x_led_probe(struct platform_device *pdev) struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); struct pm860x_led_pdata *pdata; struct pm860x_led *data; - struct mfd_cell *cell; struct resource *res; int ret; @@ -181,10 +179,7 @@ static int pm860x_led_probe(struct platform_device *pdev) return -EINVAL; } - cell = pdev->dev.platform_data; - if (cell == NULL) - return -ENODEV; - pdata = cell->mfd_data; + pdata = pdev->dev.platform_data; if (pdata == NULL) { dev_err(&pdev->dev, "No platform data!\n"); return -EINVAL; diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 011cb6ce861b..801aff7c8bab 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -516,7 +516,8 @@ static void __devinit device_bk_init(struct pm860x_chip *chip, 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]; + bk_devs[i].platform_data = &bk_pdata[i]; + bk_devs[i].pdata_size = sizeof(bk_pdata[i]); for (j = 0; j < ARRAY_SIZE(bk_devs); j++) { id = bk_resources[j].start; @@ -553,7 +554,8 @@ static void __devinit device_led_init(struct pm860x_chip *chip, 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]; + led_devs[i].platform_data = &led_pdata[i]; + led_devs[i].pdata_size = sizeof(led_pdata[i]); for (j = 0; j < ARRAY_SIZE(led_devs); j++) { id = led_resources[j].start; @@ -617,7 +619,8 @@ static void __devinit device_regulator_init(struct pm860x_chip *chip, } memcpy(®ulator_pdata[i], &pdata->regulator[i], sizeof(struct regulator_init_data)); - regulator_devs[i].mfd_data = ®ulator_pdata[i]; + regulator_devs[i].platform_data = ®ulator_pdata[i]; + regulator_devs[i].pdata_size = sizeof(regulator_pdata[i]); regulator_devs[i].num_resources = 1; regulator_devs[i].resources = ®ulator_resources[j]; @@ -642,7 +645,8 @@ static void __devinit device_touch_init(struct pm860x_chip *chip, return; memcpy(&touch_pdata, pdata->touch, sizeof(struct pm860x_touch_pdata)); - touch_devs[0].mfd_data = &touch_pdata; + touch_devs[0].platform_data = &touch_pdata; + touch_devs[0].pdata_size = sizeof(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], @@ -662,7 +666,8 @@ static void __devinit device_power_init(struct pm860x_chip *chip, return; memcpy(&power_pdata, pdata->power, sizeof(struct pm860x_power_pdata)); - power_devs[0].mfd_data = &power_pdata; + power_devs[0].platform_data = &power_pdata; + power_devs[0].pdata_size = sizeof(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, @@ -670,7 +675,8 @@ static void __devinit device_power_init(struct pm860x_chip *chip, if (ret < 0) dev_err(chip->dev, "Failed to add battery subdev\n"); - power_devs[1].mfd_data = &power_pdata; + power_devs[1].platform_data = &power_pdata; + power_devs[0].pdata_size = sizeof(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, diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index 859251250b55..784ea7724c7a 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -15,7 +15,6 @@ #include #include #include -#include #include struct pm8607_regulator_info { @@ -400,13 +399,9 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) 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; + pdata = pdev->dev.platform_data; if (pdata == NULL) return -EINVAL; diff --git a/drivers/video/backlight/88pm860x_bl.c b/drivers/video/backlight/88pm860x_bl.c index c8b520e9a11a..c04b94da81f7 100644 --- a/drivers/video/backlight/88pm860x_bl.c +++ b/drivers/video/backlight/88pm860x_bl.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #define MAX_BRIGHTNESS (0xFF) @@ -168,7 +167,6 @@ static int pm860x_backlight_probe(struct platform_device *pdev) 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; @@ -181,10 +179,7 @@ static int pm860x_backlight_probe(struct platform_device *pdev) return -EINVAL; } - cell = pdev->dev.platform_data; - if (cell == NULL) - return -ENODEV; - pdata = cell->mfd_data; + pdata = pdev->dev.platform_data; if (pdata == NULL) { dev_err(&pdev->dev, "platform data isn't assigned to " "backlight\n"); -- cgit v1.2.3 From cb5811cf325f44eb0630b55a6416311e4ba661ee Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 6 Apr 2011 16:39:45 +0200 Subject: mfd: Use mfd cell platform_data for davinci cells platform bits With the addition of a platform device mfd_cell pointer, MFD drivers can go back to passing platform back to their sub drivers. This allows for an mfd_cell->mfd_data removal and thus keep the sub drivers MFD agnostic. This is mostly needed for non MFD aware sub drivers. Cc: Miguel Aguilar Cc: Mark Brown Cc: Liam Girdwood Signed-off-by: Samuel Ortiz --- drivers/mfd/davinci_voicecodec.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c index 414783b04849..4e2af2cb2d26 100644 --- a/drivers/mfd/davinci_voicecodec.c +++ b/drivers/mfd/davinci_voicecodec.c @@ -119,12 +119,14 @@ static int __init davinci_vc_probe(struct platform_device *pdev) /* Voice codec interface client */ cell = &davinci_vc->cells[DAVINCI_VC_VCIF_CELL]; cell->name = "davinci-vcif"; - cell->mfd_data = davinci_vc; + cell->platform_data = davinci_vc; + cell->pdata_size = sizeof(*davinci_vc); /* Voice codec CQ93VC client */ cell = &davinci_vc->cells[DAVINCI_VC_CQ93VC_CELL]; cell->name = "cq93vc-codec"; - cell->mfd_data = davinci_vc; + cell->platform_data = davinci_vc; + cell->pdata_size = sizeof(*davinci_vc); ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells, DAVINCI_VC_CELLS, NULL, 0); -- cgit v1.2.3 From e45be4b5fcccb241101ad1aa1e15581ad2071393 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Wed, 11 May 2011 10:44:36 +0200 Subject: mfd: Use mfd cell platform_data for wm8400 cells platform bits With the addition of a platform device mfd_cell pointer, MFD drivers can go back to passing platform data back to their sub drivers. This allows for an mfd_cell->mfd_data removal and thus keep the sub drivers MFD agnostic. This is mostly needed for non MFD aware sub drivers. Reviewed-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm8400-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c index 3a6e78cb0384..597f82edacaa 100644 --- a/drivers/mfd/wm8400-core.c +++ b/drivers/mfd/wm8400-core.c @@ -245,7 +245,8 @@ static int wm8400_register_codec(struct wm8400 *wm8400) { struct mfd_cell cell = { .name = "wm8400-codec", - .mfd_data = wm8400, + .platform_data = wm8400, + .pdata_size = sizeof(*wm8400), }; return mfd_add_devices(wm8400->dev, -1, &cell, 1, NULL, 0); -- cgit v1.2.3 From 17cf8b429341869c154268f9d92d32a74295a29a Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 26 May 2011 10:06:31 +0200 Subject: regulator: Use device platform_data to retrieve db8500 platform bits With the addition of a platform device mfd_cell pointer, MFD drivers can go back to passing platform data back to their sub drivers. This allows for an mfd_cell->mfd_data removal and thus keep the sub drivers MFD agnostic. This is mostly needed for non MFD aware sub drivers. Acked-by: Linus Walleij Acked-by: Liam Girdwood Signed-off-by: Samuel Ortiz --- drivers/regulator/db8500-prcmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c index 1089a961616e..e5f7b8fe51f4 100644 --- a/drivers/regulator/db8500-prcmu.c +++ b/drivers/regulator/db8500-prcmu.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -471,7 +470,8 @@ static struct db8500_regulator_info static int __devinit db8500_regulator_probe(struct platform_device *pdev) { - struct regulator_init_data *db8500_init_data = mfd_get_data(pdev); + struct regulator_init_data *db8500_init_data = + dev_get_platdata(&pdev->dev); int i, err; /* register all regulators */ -- cgit v1.2.3 From 0b14c22ea1e0226d894df76176971d06e8886aa7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 4 Apr 2011 11:04:42 +0900 Subject: mfd: Provide platform data for WM831x GPIO configuration Allow the GPIO mode of WM831x devices to be configured using platform data. Users may provide a table of GPIO register values in gpio_defaults[]. In order to allow 0 to be set explicitly out of range values are accepted and masked off, with a WM831X_GPIO_CONFIGURE define provided to set an out of range value. This can be used to configure higher numbered GPIOs or override values set in OTP for GPIOs configured using OTP. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-core.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/wm831x-core.c b/drivers/mfd/wm831x-core.c index 3fe9a58fe6c7..265f75fc6a25 100644 --- a/drivers/mfd/wm831x-core.c +++ b/drivers/mfd/wm831x-core.c @@ -1442,7 +1442,7 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) struct wm831x_pdata *pdata = wm831x->dev->platform_data; int rev; enum wm831x_parent parent; - int ret; + int ret, i; mutex_init(&wm831x->io_lock); mutex_init(&wm831x->key_lock); @@ -1581,6 +1581,17 @@ int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq) } } + if (pdata) { + for (i = 0; i < ARRAY_SIZE(pdata->gpio_defaults); i++) { + if (!pdata->gpio_defaults[i]) + continue; + + wm831x_reg_write(wm831x, + WM831X_GPIO1_CONTROL + i, + pdata->gpio_defaults[i] & 0xffff); + } + } + ret = wm831x_irq_init(wm831x, irq); if (ret != 0) goto err; -- cgit v1.2.3 From bc86fcee373f27bffc9ed0c0a734e40ec084aef5 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 4 Apr 2011 11:59:57 +0900 Subject: mfd: Continue with IRQ setup even if we don't have PMIC main IRQ The fact that we can't actually raise any interrupts doesn't stop us setting up the IRQs we're exporting. While this isn't actually going to do anything it allows us to proceed further through device setup during board bringup and avoids issues with the MFD core not letting us suppress the configuration of IRQ resources. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/wm831x-irq.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index 23e66af89dea..42b928ec891e 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c @@ -515,12 +515,6 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) 0xffff); } - if (!irq) { - dev_warn(wm831x->dev, - "No interrupt specified - functionality limited\n"); - return 0; - } - if (!pdata || !pdata->irq_base) { dev_err(wm831x->dev, "No interrupt base specified, no interrupts\n"); @@ -567,15 +561,22 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) #endif } - ret = request_threaded_irq(irq, NULL, wm831x_irq_thread, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, - "wm831x", wm831x); - if (ret != 0) { - dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n", - irq, ret); - return ret; + if (irq) { + ret = request_threaded_irq(irq, NULL, wm831x_irq_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "wm831x", wm831x); + if (ret != 0) { + dev_err(wm831x->dev, "Failed to request IRQ %d: %d\n", + irq, ret); + return ret; + } + } else { + dev_warn(wm831x->dev, + "No interrupt specified - functionality limited\n"); } + + /* Enable top level interrupts, we mask at secondary level */ wm831x_reg_write(wm831x, WM831X_SYSTEM_INTERRUPTS_MASK, 0); -- cgit v1.2.3 From 5d76ca3baaf5504779a59b2ad73b609b92e7e8dc Mon Sep 17 00:00:00 2001 From: Wanlong Gao Date: Sun, 10 Apr 2011 22:10:26 +0800 Subject: mfd: Fix wl1273 warning Remove the unused variable "u16 val" of wl1273-core.c. Signed-off-by: Wanlong Gao Signed-off-by: Samuel Ortiz --- drivers/mfd/wl1273-core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c index 63d250d9a366..d97a86945174 100644 --- a/drivers/mfd/wl1273-core.c +++ b/drivers/mfd/wl1273-core.c @@ -153,7 +153,6 @@ out: */ static int wl1273_fm_set_volume(struct wl1273_core *core, unsigned int volume) { - u16 val; int r; if (volume > WL1273_MAX_VOLUME) -- cgit v1.2.3 From a5156f1adeeb0be7f8370c1d2e111bd1b082b578 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Tue, 26 Apr 2011 11:06:22 +0200 Subject: mfd: Fix build warning on 88pm860x WARNING: vmlinux.o(.devinit.text+0x6c4): Section mismatch in reference from the function device_onkey_init() to the (unknown reference) .init.data:(unknown) The function __devinit device_onkey_init() references a (unknown reference) __initdata (unknown). If (unknown) is only used by device_onkey_init then annotate (unknown) with a matching annotation. It's caused by using __initdata on mfd cell resources. Replace __initdata with __devinitdata. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-core.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 801aff7c8bab..7ba4aafb051d 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -21,13 +21,13 @@ #define INT_STATUS_NUM 3 -static struct resource bk_resources[] __initdata = { +static struct resource bk_resources[] __devinitdata = { {PM8606_BACKLIGHT1, PM8606_BACKLIGHT1, "backlight-0", IORESOURCE_IO,}, {PM8606_BACKLIGHT2, PM8606_BACKLIGHT2, "backlight-1", IORESOURCE_IO,}, {PM8606_BACKLIGHT3, PM8606_BACKLIGHT3, "backlight-2", IORESOURCE_IO,}, }; -static struct resource led_resources[] __initdata = { +static struct resource led_resources[] __devinitdata = { {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,}, @@ -36,7 +36,7 @@ static struct resource led_resources[] __initdata = { {PM8606_LED2_BLUE, PM8606_LED2_BLUE, "led1-blue", IORESOURCE_IO,}, }; -static struct resource regulator_resources[] __initdata = { +static struct resource regulator_resources[] __devinitdata = { {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,}, @@ -57,15 +57,15 @@ static struct resource regulator_resources[] __initdata = { {PM8607_ID_LDO15, PM8607_ID_LDO15, "ldo-15", IORESOURCE_IO,}, }; -static struct resource touch_resources[] __initdata = { +static struct resource touch_resources[] __devinitdata = { {PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,}, }; -static struct resource onkey_resources[] __initdata = { +static struct resource onkey_resources[] __devinitdata = { {PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,}, }; -static struct resource codec_resources[] __initdata = { +static struct resource codec_resources[] __devinitdata = { /* Headset microphone insertion or removal */ {PM8607_IRQ_MICIN, PM8607_IRQ_MICIN, "micin", IORESOURCE_IRQ,}, /* Hook-switch press or release */ @@ -76,12 +76,12 @@ static struct resource codec_resources[] __initdata = { {PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short", IORESOURCE_IRQ,}, }; -static struct resource battery_resources[] __initdata = { +static struct resource battery_resources[] __devinitdata = { {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 = { +static struct resource charger_resources[] __devinitdata = { {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,}, @@ -90,13 +90,13 @@ static struct resource charger_resources[] __initdata = { {PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage", IORESOURCE_IRQ,}, }; -static struct mfd_cell bk_devs[] __initdata = { +static struct mfd_cell bk_devs[] = { {"88pm860x-backlight", 0,}, {"88pm860x-backlight", 1,}, {"88pm860x-backlight", 2,}, }; -static struct mfd_cell led_devs[] __initdata = { +static struct mfd_cell led_devs[] = { {"88pm860x-led", 0,}, {"88pm860x-led", 1,}, {"88pm860x-led", 2,}, @@ -105,7 +105,7 @@ static struct mfd_cell led_devs[] __initdata = { {"88pm860x-led", 5,}, }; -static struct mfd_cell regulator_devs[] __initdata = { +static struct mfd_cell regulator_devs[] = { {"88pm860x-regulator", 0,}, {"88pm860x-regulator", 1,}, {"88pm860x-regulator", 2,}, @@ -126,15 +126,15 @@ static struct mfd_cell regulator_devs[] __initdata = { {"88pm860x-regulator", 17,}, }; -static struct mfd_cell touch_devs[] __initdata = { +static struct mfd_cell touch_devs[] = { {"88pm860x-touch", -1,}, }; -static struct mfd_cell onkey_devs[] __initdata = { +static struct mfd_cell onkey_devs[] = { {"88pm860x-onkey", -1,}, }; -static struct mfd_cell codec_devs[] __initdata = { +static struct mfd_cell codec_devs[] = { {"88pm860x-codec", -1,}, }; -- cgit v1.2.3 From 1f968ff61f2987f500832e93b9b704f26adadea6 Mon Sep 17 00:00:00 2001 From: Lesly A M Date: Thu, 14 Apr 2011 17:57:50 +0530 Subject: mfd: Correct the twl4030-power warning print during script loading Correcting the if condition check for printing the warning, if wakeup script is not updated before updating the sleep script. Since the flag 'order' is set to '1' while updating the wakeup script for P1P2, the condition checking for printing the warning should be if(!order) (ie: print the warning if wakeup script is not updated before updating the sleep script) Signed-off-by: Lesly A M Cc: Nishanth Menon Cc: David Derrick Signed-off-by: Samuel Ortiz --- drivers/mfd/twl4030-power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index 2c0d4d16491a..8373d79323cc 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -448,7 +448,7 @@ static int __init load_twl4030_script(struct twl4030_script *tscript, goto out; } if (tscript->flags & TWL4030_SLEEP_SCRIPT) { - if (order) + if (!order) pr_warning("TWL4030: Bad order of scripts (sleep "\ "script before wakeup) Leads to boot"\ "failure on some boards\n"); -- cgit v1.2.3 From d7ac829fa30d44d6553a0ead41f47bb92ee4d73e Mon Sep 17 00:00:00 2001 From: Lesly A M Date: Thu, 14 Apr 2011 17:57:51 +0530 Subject: mfd: Modifying the twl4030-power macro name Main_Ref to all caps Modifying the macro name Main_Ref to all caps(MAIN_REF). Suggested by Nishanth Menon Signed-off-by: Lesly A M Cc: Nishanth Menon Cc: David Derrick Signed-off-by: Samuel Ortiz --- drivers/mfd/twl4030-power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index 8373d79323cc..8162e435c9ff 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -120,7 +120,7 @@ static u8 res_config_addrs[] = { [RES_HFCLKOUT] = 0x8b, [RES_32KCLKOUT] = 0x8e, [RES_RESET] = 0x91, - [RES_Main_Ref] = 0x94, + [RES_MAIN_REF] = 0x94, }; static int __init twl4030_write_script_byte(u8 address, u8 byte) -- cgit v1.2.3 From ca972d13382436530896e90591e2793e7a9e7eba Mon Sep 17 00:00:00 2001 From: Lesly A M Date: Thu, 14 Apr 2011 17:57:53 +0530 Subject: mfd: TWL5030 version checking in twl-core Added API to get the TWL5030 Si version from the IDCODE register. It is used for enabling the workaround for TWL erratum 27. Signed-off-by: Lesly A M Cc: Nishanth Menon Cc: David Derrick Signed-off-by: Samuel Ortiz --- drivers/mfd/twl-core.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 960b5bed7f52..2bd9e0676bc2 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -229,6 +229,9 @@ /* is driver active, bound to a chip? */ static bool inuse; +/* TWL IDCODE Register value */ +static u32 twl_idcode; + static unsigned int twl_id; unsigned int twl_rev(void) { @@ -487,6 +490,58 @@ EXPORT_SYMBOL(twl_i2c_read_u8); /*----------------------------------------------------------------------*/ +/** + * twl_read_idcode_register - API to read the IDCODE register. + * + * Unlocks the IDCODE register and read the 32 bit value. + */ +static int twl_read_idcode_register(void) +{ + int err; + + err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, TWL_EEPROM_R_UNLOCK, + REG_UNLOCK_TEST_REG); + if (err) { + pr_err("TWL4030 Unable to unlock IDCODE registers -%d\n", err); + goto fail; + } + + err = twl_i2c_read(TWL4030_MODULE_INTBR, (u8 *)(&twl_idcode), + REG_IDCODE_7_0, 4); + if (err) { + pr_err("TWL4030: unable to read IDCODE -%d\n", err); + goto fail; + } + + err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, 0x0, REG_UNLOCK_TEST_REG); + if (err) + pr_err("TWL4030 Unable to relock IDCODE registers -%d\n", err); +fail: + return err; +} + +/** + * twl_get_type - API to get TWL Si type. + * + * Api to get the TWL Si type from IDCODE value. + */ +int twl_get_type(void) +{ + return TWL_SIL_TYPE(twl_idcode); +} +EXPORT_SYMBOL_GPL(twl_get_type); + +/** + * twl_get_version - API to get TWL Si version. + * + * Api to get the TWL Si version from IDCODE value. + */ +int twl_get_version(void) +{ + return TWL_SIL_REV(twl_idcode); +} +EXPORT_SYMBOL_GPL(twl_get_version); + static struct device * add_numbered_child(unsigned chip, const char *name, int num, void *pdata, unsigned pdata_len, @@ -1014,6 +1069,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) unsigned i; struct twl4030_platform_data *pdata = client->dev.platform_data; u8 temp; + int ret = 0; if (!pdata) { dev_dbg(&client->dev, "no platform data?\n"); @@ -1060,6 +1116,12 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) /* setup clock framework */ clocks_init(&client->dev, pdata->clock); + /* read TWL IDCODE Register */ + if (twl_id == TWL4030_CLASS_ID) { + ret = twl_read_idcode_register(); + WARN(ret < 0, "Error: reading twl_idcode register value\n"); + } + /* load power event scripts */ if (twl_has_power() && pdata->power) twl4030_power_init(pdata->power); -- cgit v1.2.3 From 37df003c85efd40b20c6d54695d4f03e6e75ebe6 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 15 Apr 2011 20:04:45 +0800 Subject: mfd: Group TPSxxxxx power management chips together Group TPSxxxxx power management chips together and sort in alphabetical order. This change makes it easier for users to find config options. Signed-off-by: Axel Lin Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 481770ab2716..66db02cee2ad 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -157,6 +157,20 @@ config TPS6507X This driver can also be built as a module. If so, the module will be called tps6507x. +config MFD_TPS6586X + bool "TPS6586x Power Management chips" + depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS + 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. + config MENELAUS bool "Texas Instruments TWL92330/Menelaus PM chip" depends on I2C=y && ARCH_OMAP2 @@ -649,20 +663,6 @@ config MFD_JZ4740_ADC 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 - bool "TPS6586x Power Management chips" - depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS - 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. - config MFD_VX855 tristate "Support for VIA VX855/VX875 integrated south bridge" depends on PCI -- cgit v1.2.3 From 1305134e8246fb4e86b93d5b6a21caa0e07a8ecf Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 15 Apr 2011 20:06:37 +0800 Subject: mfd: Group NXP PCF50633* drivers together PCF50633_ADC and PCF50633_GPIO depends on MFD_PCF50633. Thus group NXP PCF50633* drivers together. Signed-off-by: Axel Lin Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 66db02cee2ad..ec2da8392466 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -469,6 +469,20 @@ config MFD_PCF50633 facilities, and registers devices for the various functions so that function-specific drivers can bind to them. +config PCF50633_ADC + tristate "Support for NXP PCF50633 ADC" + depends on MFD_PCF50633 + help + Say yes here if you want to include support for ADC in the + NXP PCF50633 chip. + +config PCF50633_GPIO + tristate "Support for NXP PCF50633 GPIO" + depends on MFD_PCF50633 + help + Say yes here if you want to include support GPIO for pins on + the PCF50633 chip. + config MFD_MC13783 tristate @@ -484,20 +498,6 @@ config MFD_MC13XXX additional drivers must be enabled in order to use the functionality of the device. -config PCF50633_ADC - tristate "Support for NXP PCF50633 ADC" - depends on MFD_PCF50633 - help - Say yes here if you want to include support for ADC in the - NXP PCF50633 chip. - -config PCF50633_GPIO - tristate "Support for NXP PCF50633 GPIO" - depends on MFD_PCF50633 - help - Say yes here if you want to include support GPIO for pins on - the PCF50633 chip. - config ABX500_CORE bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" default y if ARCH_U300 || ARCH_U8500 -- cgit v1.2.3 From cbdb53e1f33baf60ded045dc79cd0dd4e9705fa5 Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Tue, 5 Apr 2011 14:40:52 -0700 Subject: mfd: Add Qualcomm PMIC 8921 core driver Add support for the Qualcomm PM8921 PMIC chip. The core driver will communicate with the PMIC chip via the MSM SSBI bus. Signed-off-by: Abhijeet Dharmapurikar Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 18 ++++++ drivers/mfd/Makefile | 1 + drivers/mfd/pm8921-core.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 177 insertions(+) create mode 100644 drivers/mfd/pm8921-core.c (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index ec2da8392466..d42328873dc9 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -691,6 +691,24 @@ config MFD_OMAP_USB_HOST This MFD driver does the required setup functionalities for OMAP USB Host drivers. +config MFD_PM8XXX + tristate + +config MFD_PM8921_CORE + tristate "Qualcomm PM8921 PMIC chip" + depends on MSM_SSBI + select MFD_CORE + select MFD_PM8XXX + help + If you say yes to this option, support will be included for the + built-in PM8921 PMIC chip. + + This is required if your board has a PM8921 and uses its features, + such as: MPPs, GPIOs, regulators, interrupts, and PWM. + + Say M here if you want to include support for PM8921 chip as a module. + This will build a module called "pm8921-core". + endif # MFD_SUPPORT menu "Multimedia Capabilities Port drivers" diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 24aa44448daf..d32a7b8f57f7 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -91,3 +91,4 @@ obj-$(CONFIG_MFD_VX855) += vx855.o obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o +obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c new file mode 100644 index 000000000000..a2ecd3233b1b --- /dev/null +++ b/drivers/mfd/pm8921-core.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2011, Code Aurora Forum. 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 version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include + +#define REG_HWREV 0x002 /* PMIC4 revision */ +#define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */ + +struct pm8921 { + struct device *dev; +}; + +static int pm8921_readb(const struct device *dev, u16 addr, u8 *val) +{ + const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); + const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data; + + return msm_ssbi_read(pmic->dev->parent, addr, val, 1); +} + +static int pm8921_writeb(const struct device *dev, u16 addr, u8 val) +{ + const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); + const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data; + + return msm_ssbi_write(pmic->dev->parent, addr, &val, 1); +} + +static int pm8921_read_buf(const struct device *dev, u16 addr, u8 *buf, + int cnt) +{ + const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); + const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data; + + return msm_ssbi_read(pmic->dev->parent, addr, buf, cnt); +} + +static int pm8921_write_buf(const struct device *dev, u16 addr, u8 *buf, + int cnt) +{ + const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); + const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data; + + return msm_ssbi_write(pmic->dev->parent, addr, buf, cnt); +} + +static struct pm8xxx_drvdata pm8921_drvdata = { + .pmic_readb = pm8921_readb, + .pmic_writeb = pm8921_writeb, + .pmic_read_buf = pm8921_read_buf, + .pmic_write_buf = pm8921_write_buf, +}; + +static int __devinit pm8921_probe(struct platform_device *pdev) +{ + const struct pm8921_platform_data *pdata = pdev->dev.platform_data; + struct pm8921 *pmic; + int rc; + u8 val; + + if (!pdata) { + pr_err("missing platform data\n"); + return -EINVAL; + } + + pmic = kzalloc(sizeof(struct pm8921), GFP_KERNEL); + if (!pmic) { + pr_err("Cannot alloc pm8921 struct\n"); + return -ENOMEM; + } + + /* Read PMIC chip revision */ + rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val)); + if (rc) { + pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc); + goto err_read_rev; + } + pr_info("PMIC revision 1: %02X\n", val); + + /* Read PMIC chip revision 2 */ + rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val)); + if (rc) { + pr_err("Failed to read hw rev 2 reg %d:rc=%d\n", + REG_HWREV_2, rc); + goto err_read_rev; + } + pr_info("PMIC revision 2: %02X\n", val); + + pmic->dev = &pdev->dev; + pm8921_drvdata.pm_chip_data = pmic; + platform_set_drvdata(pdev, &pm8921_drvdata); + + return 0; + +err_read_rev: + kfree(pmic); + return rc; +} + +static int __devexit pm8921_remove(struct platform_device *pdev) +{ + struct pm8xxx_drvdata *drvdata; + struct pm8921 *pmic = NULL; + + drvdata = platform_get_drvdata(pdev); + if (drvdata) + pmic = drvdata->pm_chip_data; + if (pmic) + mfd_remove_devices(pmic->dev); + platform_set_drvdata(pdev, NULL); + kfree(pmic); + + return 0; +} + +static struct platform_driver pm8921_driver = { + .probe = pm8921_probe, + .remove = __devexit_p(pm8921_remove), + .driver = { + .name = "pm8921-core", + .owner = THIS_MODULE, + }, +}; + +static int __init pm8921_init(void) +{ + return platform_driver_register(&pm8921_driver); +} +subsys_initcall(pm8921_init); + +static void __exit pm8921_exit(void) +{ + platform_driver_unregister(&pm8921_driver); +} +module_exit(pm8921_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("PMIC 8921 core driver"); +MODULE_VERSION("1.0"); +MODULE_ALIAS("platform:pm8921-core"); -- cgit v1.2.3 From c013f0a56c56b88ac63c4037f2dfaaf2422fa863 Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Tue, 5 Apr 2011 14:40:53 -0700 Subject: mfd: Add pm8xxx irq support Add support for the irq controller in Qualcomm 8xxx pmic. The 8xxx interrupt controller provides control for gpio and mpp configured as interrupts in addition to other subdevice interrupts. The interrupt controller also provides a way to read the real time status of an interrupt. This real time status is the only way one can get the input values of gpio and mpp lines. Signed-off-by: Abhijeet Dharmapurikar Signed-off-by: Samuel Ortiz --- drivers/mfd/Kconfig | 10 ++ drivers/mfd/Makefile | 1 + drivers/mfd/pm8921-core.c | 54 +++++++ drivers/mfd/pm8xxx-irq.c | 371 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 436 insertions(+) create mode 100644 drivers/mfd/pm8xxx-irq.c (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d42328873dc9..8344fc0ab858 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -709,6 +709,16 @@ config MFD_PM8921_CORE Say M here if you want to include support for PM8921 chip as a module. This will build a module called "pm8921-core". +config MFD_PM8XXX_IRQ + bool "Support for Qualcomm PM8xxx IRQ features" + depends on MFD_PM8XXX + default y if MFD_PM8XXX + help + This is the IRQ driver for Qualcomm PM 8xxx PMIC chips. + + This is required to use certain other PM 8xxx features, such as GPIO + and MPP. + endif # MFD_SUPPORT menu "Multimedia Capabilities Port drivers" diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index d32a7b8f57f7..1acb8f29a96c 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -92,3 +92,4 @@ obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o +obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c index a2ecd3233b1b..e873b15753d8 100644 --- a/drivers/mfd/pm8921-core.c +++ b/drivers/mfd/pm8921-core.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -26,6 +27,7 @@ struct pm8921 { struct device *dev; + struct pm_irq_chip *irq_chip; }; static int pm8921_readb(const struct device *dev, u16 addr, u8 *val) @@ -62,19 +64,53 @@ static int pm8921_write_buf(const struct device *dev, u16 addr, u8 *buf, return msm_ssbi_write(pmic->dev->parent, addr, buf, cnt); } +static int pm8921_read_irq_stat(const struct device *dev, int irq) +{ + const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); + const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data; + + return pm8xxx_get_irq_stat(pmic->irq_chip, irq); +} + static struct pm8xxx_drvdata pm8921_drvdata = { .pmic_readb = pm8921_readb, .pmic_writeb = pm8921_writeb, .pmic_read_buf = pm8921_read_buf, .pmic_write_buf = pm8921_write_buf, + .pmic_read_irq_stat = pm8921_read_irq_stat, }; +static int __devinit pm8921_add_subdevices(const struct pm8921_platform_data + *pdata, + struct pm8921 *pmic, + u32 rev) +{ + int ret = 0, irq_base = 0; + struct pm_irq_chip *irq_chip; + + if (pdata->irq_pdata) { + pdata->irq_pdata->irq_cdata.nirqs = PM8921_NR_IRQS; + pdata->irq_pdata->irq_cdata.rev = rev; + irq_base = pdata->irq_pdata->irq_base; + irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata); + + if (IS_ERR(irq_chip)) { + pr_err("Failed to init interrupts ret=%ld\n", + PTR_ERR(irq_chip)); + return PTR_ERR(irq_chip); + } + pmic->irq_chip = irq_chip; + } + return ret; +} + static int __devinit pm8921_probe(struct platform_device *pdev) { const struct pm8921_platform_data *pdata = pdev->dev.platform_data; struct pm8921 *pmic; int rc; u8 val; + u32 rev; if (!pdata) { pr_err("missing platform data\n"); @@ -94,6 +130,7 @@ static int __devinit pm8921_probe(struct platform_device *pdev) goto err_read_rev; } pr_info("PMIC revision 1: %02X\n", val); + rev = val; /* Read PMIC chip revision 2 */ rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val)); @@ -103,13 +140,26 @@ static int __devinit pm8921_probe(struct platform_device *pdev) goto err_read_rev; } pr_info("PMIC revision 2: %02X\n", val); + rev |= val << BITS_PER_BYTE; pmic->dev = &pdev->dev; pm8921_drvdata.pm_chip_data = pmic; platform_set_drvdata(pdev, &pm8921_drvdata); + rc = pm8921_add_subdevices(pdata, pmic, rev); + if (rc) { + pr_err("Cannot add subdevices rc=%d\n", rc); + goto err; + } + + /* gpio might not work if no irq device is found */ + WARN_ON(pmic->irq_chip == NULL); + return 0; +err: + mfd_remove_devices(pmic->dev); + platform_set_drvdata(pdev, NULL); err_read_rev: kfree(pmic); return rc; @@ -125,6 +175,10 @@ static int __devexit pm8921_remove(struct platform_device *pdev) pmic = drvdata->pm_chip_data; if (pmic) mfd_remove_devices(pmic->dev); + if (pmic->irq_chip) { + pm8xxx_irq_exit(pmic->irq_chip); + pmic->irq_chip = NULL; + } platform_set_drvdata(pdev, NULL); kfree(pmic); diff --git a/drivers/mfd/pm8xxx-irq.c b/drivers/mfd/pm8xxx-irq.c new file mode 100644 index 000000000000..d452dd013081 --- /dev/null +++ b/drivers/mfd/pm8xxx-irq.c @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2011, Code Aurora Forum. 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 version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* PMIC8xxx IRQ */ + +#define SSBI_REG_ADDR_IRQ_BASE 0x1BB + +#define SSBI_REG_ADDR_IRQ_ROOT (SSBI_REG_ADDR_IRQ_BASE + 0) +#define SSBI_REG_ADDR_IRQ_M_STATUS1 (SSBI_REG_ADDR_IRQ_BASE + 1) +#define SSBI_REG_ADDR_IRQ_M_STATUS2 (SSBI_REG_ADDR_IRQ_BASE + 2) +#define SSBI_REG_ADDR_IRQ_M_STATUS3 (SSBI_REG_ADDR_IRQ_BASE + 3) +#define SSBI_REG_ADDR_IRQ_M_STATUS4 (SSBI_REG_ADDR_IRQ_BASE + 4) +#define SSBI_REG_ADDR_IRQ_BLK_SEL (SSBI_REG_ADDR_IRQ_BASE + 5) +#define SSBI_REG_ADDR_IRQ_IT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 6) +#define SSBI_REG_ADDR_IRQ_CONFIG (SSBI_REG_ADDR_IRQ_BASE + 7) +#define SSBI_REG_ADDR_IRQ_RT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 8) + +#define PM_IRQF_LVL_SEL 0x01 /* level select */ +#define PM_IRQF_MASK_FE 0x02 /* mask falling edge */ +#define PM_IRQF_MASK_RE 0x04 /* mask rising edge */ +#define PM_IRQF_CLR 0x08 /* clear interrupt */ +#define PM_IRQF_BITS_MASK 0x70 +#define PM_IRQF_BITS_SHIFT 4 +#define PM_IRQF_WRITE 0x80 + +#define PM_IRQF_MASK_ALL (PM_IRQF_MASK_FE | \ + PM_IRQF_MASK_RE) + +struct pm_irq_chip { + struct device *dev; + spinlock_t pm_irq_lock; + unsigned int devirq; + unsigned int irq_base; + unsigned int num_irqs; + unsigned int num_blocks; + unsigned int num_masters; + u8 config[0]; +}; + +static int pm8xxx_read_root_irq(const struct pm_irq_chip *chip, u8 *rp) +{ + return pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_ROOT, rp); +} + +static int pm8xxx_read_master_irq(const struct pm_irq_chip *chip, u8 m, u8 *bp) +{ + return pm8xxx_readb(chip->dev, + SSBI_REG_ADDR_IRQ_M_STATUS1 + m, bp); +} + +static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, u8 bp, u8 *ip) +{ + int rc; + + spin_lock(&chip->pm_irq_lock); + rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp); + if (rc) { + pr_err("Failed Selecting Block %d rc=%d\n", bp, rc); + goto bail; + } + + rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_IT_STATUS, ip); + if (rc) + pr_err("Failed Reading Status rc=%d\n", rc); +bail: + spin_unlock(&chip->pm_irq_lock); + return rc; +} + +static int pm8xxx_config_irq(struct pm_irq_chip *chip, u8 bp, u8 cp) +{ + int rc; + + spin_lock(&chip->pm_irq_lock); + rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp); + if (rc) { + pr_err("Failed Selecting Block %d rc=%d\n", bp, rc); + goto bail; + } + + cp |= PM_IRQF_WRITE; + rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_CONFIG, cp); + if (rc) + pr_err("Failed Configuring IRQ rc=%d\n", rc); +bail: + spin_unlock(&chip->pm_irq_lock); + return rc; +} + +static int pm8xxx_irq_block_handler(struct pm_irq_chip *chip, int block) +{ + int pmirq, irq, i, ret = 0; + u8 bits; + + ret = pm8xxx_read_block_irq(chip, block, &bits); + if (ret) { + pr_err("Failed reading %d block ret=%d", block, ret); + return ret; + } + if (!bits) { + pr_err("block bit set in master but no irqs: %d", block); + return 0; + } + + /* Check IRQ bits */ + for (i = 0; i < 8; i++) { + if (bits & (1 << i)) { + pmirq = block * 8 + i; + irq = pmirq + chip->irq_base; + generic_handle_irq(irq); + } + } + return 0; +} + +static int pm8xxx_irq_master_handler(struct pm_irq_chip *chip, int master) +{ + u8 blockbits; + int block_number, i, ret = 0; + + ret = pm8xxx_read_master_irq(chip, master, &blockbits); + if (ret) { + pr_err("Failed to read master %d ret=%d\n", master, ret); + return ret; + } + if (!blockbits) { + pr_err("master bit set in root but no blocks: %d", master); + return 0; + } + + for (i = 0; i < 8; i++) + if (blockbits & (1 << i)) { + block_number = master * 8 + i; /* block # */ + ret |= pm8xxx_irq_block_handler(chip, block_number); + } + return ret; +} + +static void pm8xxx_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + struct pm_irq_chip *chip = irq_desc_get_handler_data(desc); + struct irq_chip *irq_chip = irq_desc_get_chip(desc); + u8 root; + int i, ret, masters = 0; + + ret = pm8xxx_read_root_irq(chip, &root); + if (ret) { + pr_err("Can't read root status ret=%d\n", ret); + return; + } + + /* on pm8xxx series masters start from bit 1 of the root */ + masters = root >> 1; + + /* Read allowed masters for blocks. */ + for (i = 0; i < chip->num_masters; i++) + if (masters & (1 << i)) + pm8xxx_irq_master_handler(chip, i); + + irq_chip->irq_ack(&desc->irq_data); +} + +static void pm8xxx_irq_mask_ack(struct irq_data *d) +{ + struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d); + unsigned int pmirq = d->irq - chip->irq_base; + int master, irq_bit; + u8 block, config; + + block = pmirq / 8; + master = block / 8; + irq_bit = pmirq % 8; + + config = chip->config[pmirq] | PM_IRQF_MASK_ALL | PM_IRQF_CLR; + pm8xxx_config_irq(chip, block, config); +} + +static void pm8xxx_irq_unmask(struct irq_data *d) +{ + struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d); + unsigned int pmirq = d->irq - chip->irq_base; + int master, irq_bit; + u8 block, config; + + block = pmirq / 8; + master = block / 8; + irq_bit = pmirq % 8; + + config = chip->config[pmirq]; + pm8xxx_config_irq(chip, block, config); +} + +static int pm8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type) +{ + struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d); + unsigned int pmirq = d->irq - chip->irq_base; + int master, irq_bit; + u8 block, config; + + block = pmirq / 8; + master = block / 8; + irq_bit = pmirq % 8; + + chip->config[pmirq] = (irq_bit << PM_IRQF_BITS_SHIFT) + | PM_IRQF_MASK_ALL; + if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { + if (flow_type & IRQF_TRIGGER_RISING) + chip->config[pmirq] &= ~PM_IRQF_MASK_RE; + if (flow_type & IRQF_TRIGGER_FALLING) + chip->config[pmirq] &= ~PM_IRQF_MASK_FE; + } else { + chip->config[pmirq] |= PM_IRQF_LVL_SEL; + + if (flow_type & IRQF_TRIGGER_HIGH) + chip->config[pmirq] &= ~PM_IRQF_MASK_RE; + else + chip->config[pmirq] &= ~PM_IRQF_MASK_FE; + } + + config = chip->config[pmirq] | PM_IRQF_CLR; + return pm8xxx_config_irq(chip, block, config); +} + +static int pm8xxx_irq_set_wake(struct irq_data *d, unsigned int on) +{ + return 0; +} + +static struct irq_chip pm8xxx_irq_chip = { + .name = "pm8xxx", + .irq_mask_ack = pm8xxx_irq_mask_ack, + .irq_unmask = pm8xxx_irq_unmask, + .irq_set_type = pm8xxx_irq_set_type, + .irq_set_wake = pm8xxx_irq_set_wake, + .flags = IRQCHIP_MASK_ON_SUSPEND, +}; + +/** + * pm8xxx_get_irq_stat - get the status of the irq line + * @chip: pointer to identify a pmic irq controller + * @irq: the irq number + * + * The pm8xxx gpio and mpp rely on the interrupt block to read + * the values on their pins. This function is to facilitate reading + * the status of a gpio or an mpp line. The caller has to convert the + * gpio number to irq number. + * + * RETURNS: + * an int indicating the value read on that line + */ +int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq) +{ + int pmirq, rc; + u8 block, bits, bit; + unsigned long flags; + + if (chip == NULL || irq < chip->irq_base || + irq >= chip->irq_base + chip->num_irqs) + return -EINVAL; + + pmirq = irq - chip->irq_base; + + block = pmirq / 8; + bit = pmirq % 8; + + spin_lock_irqsave(&chip->pm_irq_lock, flags); + + rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, block); + if (rc) { + pr_err("Failed Selecting block irq=%d pmirq=%d blk=%d rc=%d\n", + irq, pmirq, block, rc); + goto bail_out; + } + + rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_RT_STATUS, &bits); + if (rc) { + pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n", + irq, pmirq, block, rc); + goto bail_out; + } + + rc = (bits & (1 << bit)) ? 1 : 0; + +bail_out: + spin_unlock_irqrestore(&chip->pm_irq_lock, flags); + + return rc; +} +EXPORT_SYMBOL_GPL(pm8xxx_get_irq_stat); + +struct pm_irq_chip * __devinit pm8xxx_irq_init(struct device *dev, + const struct pm8xxx_irq_platform_data *pdata) +{ + struct pm_irq_chip *chip; + int devirq, rc; + unsigned int pmirq; + + if (!pdata) { + pr_err("No platform data\n"); + return ERR_PTR(-EINVAL); + } + + devirq = pdata->devirq; + if (devirq < 0) { + pr_err("missing devirq\n"); + rc = devirq; + return ERR_PTR(-EINVAL); + } + + chip = kzalloc(sizeof(struct pm_irq_chip) + + sizeof(u8) * pdata->irq_cdata.nirqs, GFP_KERNEL); + if (!chip) { + pr_err("Cannot alloc pm_irq_chip struct\n"); + return ERR_PTR(-EINVAL); + } + + chip->dev = dev; + chip->devirq = devirq; + chip->irq_base = pdata->irq_base; + chip->num_irqs = pdata->irq_cdata.nirqs; + chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8); + chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8); + spin_lock_init(&chip->pm_irq_lock); + + for (pmirq = 0; pmirq < chip->num_irqs; pmirq++) { + irq_set_chip_and_handler(chip->irq_base + pmirq, + &pm8xxx_irq_chip, + handle_level_irq); + irq_set_chip_data(chip->irq_base + pmirq, chip); +#ifdef CONFIG_ARM + set_irq_flags(chip->irq_base + pmirq, IRQF_VALID); +#else + irq_set_noprobe(chip->irq_base + pmirq); +#endif + } + + irq_set_irq_type(devirq, pdata->irq_trigger_flag); + irq_set_handler_data(devirq, chip); + irq_set_chained_handler(devirq, pm8xxx_irq_handler); + set_irq_wake(devirq, 1); + + return chip; +} + +int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip) +{ + irq_set_chained_handler(chip->devirq, NULL); + kfree(chip); + return 0; +} -- cgit v1.2.3 From e6f1945b9e71cbc8498e5fbf8d5352331ac5da14 Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Tue, 12 Apr 2011 10:55:58 -0400 Subject: mfd: Fix tps6586x GPIO value setting In the current code, every time we set a TPS6586x GPIO pin, the tps6586x_gpio_set function is resetting all other GPIO pins. We need to update the right GPIOxOUT bit of the GPIOSET2 register instead of overriding the full value. Tested by setting sequentially GPIO2 and GPIO3 and verifying the pins voltage. Change-Id: I560edde146c5425cce37432c4ee91569eea5adcf Signed-off-by: Vincent Palatin Signed-off-by: Samuel Ortiz --- drivers/mfd/tps6586x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index b600808690c1..bba26d96c240 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -270,8 +270,8 @@ static void tps6586x_gpio_set(struct gpio_chip *chip, unsigned offset, { struct tps6586x *tps6586x = container_of(chip, struct tps6586x, gpio); - __tps6586x_write(tps6586x->client, TPS6586X_GPIOSET2, - value << offset); + tps6586x_update(tps6586x->dev, TPS6586X_GPIOSET2, + value << offset, 1 << offset); } static int tps6586x_gpio_output(struct gpio_chip *gc, unsigned offset, -- cgit v1.2.3 From 2402ca5e300db0d88fce9e0b3a5218863c71b694 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 18 Apr 2011 22:04:08 +0800 Subject: power_supply: Use max8925 platform_data from cell Avoid to get platform_data from parent device. Get it from mfd cell device instead. Signed-off-by: Haojian Zhuang Acked-by: Anton Vorontsov Cc: David Woodhouse Signed-off-by: Samuel Ortiz --- drivers/power/max8925_power.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/power/max8925_power.c b/drivers/power/max8925_power.c index 8e5aec260866..a70e16d3a3dc 100644 --- a/drivers/power/max8925_power.c +++ b/drivers/power/max8925_power.c @@ -425,16 +425,11 @@ static __devexit int max8925_deinit_charger(struct max8925_power_info *info) static __devinit int max8925_power_probe(struct platform_device *pdev) { struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct max8925_platform_data *max8925_pdata; struct max8925_power_pdata *pdata = NULL; struct max8925_power_info *info; int ret; - if (pdev->dev.parent->platform_data) { - max8925_pdata = pdev->dev.parent->platform_data; - pdata = max8925_pdata->power; - } - + pdata = pdev->dev.platform_data; if (!pdata) { dev_err(&pdev->dev, "platform data isn't assigned to " "power supply\n"); @@ -447,6 +442,7 @@ static __devinit int max8925_power_probe(struct platform_device *pdev) info->chip = chip; info->gpm = chip->i2c; info->adc = chip->adc; + platform_set_drvdata(pdev, info); info->ac.name = "max8925-ac"; info->ac.type = POWER_SUPPLY_TYPE_MAINS; @@ -482,8 +478,6 @@ static __devinit int max8925_power_probe(struct platform_device *pdev) info->topoff_threshold = pdata->topoff_threshold; info->fast_charge = pdata->fast_charge; info->set_charger = pdata->set_charger; - dev_set_drvdata(&pdev->dev, info); - platform_set_drvdata(pdev, info); max8925_init_charger(chip, info); return 0; -- cgit v1.2.3 From db13c04002e0d896f89657f9b2837a8ecfbb19b6 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Mon, 18 Apr 2011 22:04:09 +0800 Subject: regulator: Enable max8925 i2c sequence for control Force to enable i2c as power up/down sequence. Otherwise, SD/LDO can't be enabled or disabled via accessing i2c bus. Signed-off-by: Haojian Zhuang Cc: Liam Girdwood Acked-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/regulator/max8925-regulator.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index 8ae147549c6a..e4dbd667c043 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -23,6 +23,10 @@ #define SD1_DVM_SHIFT 5 /* SDCTL1 bit5 */ #define SD1_DVM_EN 6 /* SDV1 bit 6 */ +/* bit definitions in SD & LDO control registers */ +#define OUT_ENABLE 0x1f /* Power U/D sequence as I2C */ +#define OUT_DISABLE 0x1e /* Power U/D sequence as I2C */ + struct max8925_regulator_info { struct regulator_desc desc; struct regulator_dev *regulator; @@ -93,8 +97,8 @@ static int max8925_enable(struct regulator_dev *rdev) struct max8925_regulator_info *info = rdev_get_drvdata(rdev); return max8925_set_bits(info->i2c, info->enable_reg, - 1 << info->enable_bit, - 1 << info->enable_bit); + OUT_ENABLE << info->enable_bit, + OUT_ENABLE << info->enable_bit); } static int max8925_disable(struct regulator_dev *rdev) @@ -102,7 +106,8 @@ static int max8925_disable(struct regulator_dev *rdev) struct max8925_regulator_info *info = rdev_get_drvdata(rdev); return max8925_set_bits(info->i2c, info->enable_reg, - 1 << info->enable_bit, 0); + OUT_ENABLE << info->enable_bit, + OUT_DISABLE << info->enable_bit); } static int max8925_is_enabled(struct regulator_dev *rdev) -- cgit v1.2.3 From 008b30408c40ede5985397e7daac45d30b375a01 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Fri, 6 May 2011 17:21:20 +0800 Subject: mfd: Add rtc support to 88pm860x Enable rtc function in 88pm860x PMIC. Signed-off-by: Haojian Zhuang Cc: Alessandro Zummo Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-core.c | 29 +++ drivers/rtc/Kconfig | 10 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-88pm860x.c | 427 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 467 insertions(+) create mode 100644 drivers/rtc/rtc-88pm860x.c (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 7ba4aafb051d..f2cac9287756 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -90,6 +90,10 @@ static struct resource charger_resources[] __devinitdata = { {PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage", IORESOURCE_IRQ,}, }; +static struct resource rtc_resources[] __devinitdata = { + {PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,}, +}; + static struct mfd_cell bk_devs[] = { {"88pm860x-backlight", 0,}, {"88pm860x-backlight", 1,}, @@ -143,6 +147,10 @@ static struct mfd_cell power_devs[] = { {"88pm860x-charger", -1,}, }; +static struct mfd_cell rtc_devs[] = { + {"88pm860x-rtc", -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)]; @@ -635,6 +643,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)) + return; + + rtc_devs[0].platform_data = pdata->rtc; + rtc_devs[0].pdata_size = sizeof(struct pm860x_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) @@ -770,6 +798,7 @@ static void __devinit device_8607_init(struct pm860x_chip *chip, goto out; 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 b8f4e9e66cd5..8e437e2f6281 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -125,6 +125,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 9574748d1c73..612f5a88a8ee 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -15,6 +15,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/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c new file mode 100644 index 000000000000..64b847b7f970 --- /dev/null +++ b/drivers/rtc/rtc-88pm860x.c @@ -0,0 +1,427 @@ +/* + * Real Time Clock driver for Marvell 88PM860x PMIC + * + * Copyright (c) 2010 Marvell International Ltd. + * Author: Haojian Zhuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VRTC_CALIBRATION + +struct pm860x_rtc_info { + struct pm860x_chip *chip; + struct i2c_client *i2c; + struct rtc_device *rtc_dev; + struct device *dev; + struct delayed_work calib_work; + + int irq; + int vrtc; + int (*sync)(unsigned int ticks); +}; + +#define REG_VRTC_MEAS1 0x7D + +#define REG0_ADDR 0xB0 +#define REG1_ADDR 0xB2 +#define REG2_ADDR 0xB4 +#define REG3_ADDR 0xB6 + +#define REG0_DATA 0xB1 +#define REG1_DATA 0xB3 +#define REG2_DATA 0xB5 +#define REG3_DATA 0xB7 + +/* bit definitions of Measurement Enable Register 2 (0x51) */ +#define MEAS2_VRTC (1 << 0) + +/* bit definitions of RTC Register 1 (0xA0) */ +#define ALARM_EN (1 << 3) +#define ALARM_WAKEUP (1 << 4) +#define ALARM (1 << 5) +#define RTC1_USE_XO (1 << 7) + +#define VRTC_CALIB_INTERVAL (HZ * 60 * 10) /* 10 minutes */ + +static irqreturn_t rtc_update_handler(int irq, void *data) +{ + struct pm860x_rtc_info *info = (struct pm860x_rtc_info *)data; + int mask; + + mask = ALARM | ALARM_WAKEUP; + pm860x_set_bits(info->i2c, PM8607_RTC1, mask | ALARM_EN, mask); + rtc_update_irq(info->rtc_dev, 1, RTC_AF); + return IRQ_HANDLED; +} + +static int pm860x_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct pm860x_rtc_info *info = dev_get_drvdata(dev); + + if (enabled) + pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, ALARM); + else + pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, 0); + return 0; +} + +/* + * Calculate the next alarm time given the requested alarm time mask + * and the current time. + */ +static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, + struct rtc_time *alrm) +{ + unsigned long next_time; + unsigned long now_time; + + next->tm_year = now->tm_year; + next->tm_mon = now->tm_mon; + next->tm_mday = now->tm_mday; + next->tm_hour = alrm->tm_hour; + next->tm_min = alrm->tm_min; + next->tm_sec = alrm->tm_sec; + + rtc_tm_to_time(now, &now_time); + rtc_tm_to_time(next, &next_time); + + if (next_time < now_time) { + /* Advance one day */ + next_time += 60 * 60 * 24; + rtc_time_to_tm(next_time, next); + } +} + +static int pm860x_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct pm860x_rtc_info *info = dev_get_drvdata(dev); + unsigned char buf[8]; + unsigned long ticks, base, data; + + pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf); + dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1], + buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); + base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7]; + + /* load 32-bit read-only counter */ + pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf); + data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + ticks = base + data; + dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", + base, data, ticks); + + rtc_time_to_tm(ticks, tm); + + return 0; +} + +static int pm860x_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct pm860x_rtc_info *info = dev_get_drvdata(dev); + unsigned char buf[4]; + unsigned long ticks, base, data; + + if ((tm->tm_year < 70) || (tm->tm_year > 138)) { + dev_dbg(info->dev, "Set time %d out of range. " + "Please set time between 1970 to 2038.\n", + 1900 + tm->tm_year); + return -EINVAL; + } + rtc_tm_to_time(tm, &ticks); + + /* load 32-bit read-only counter */ + pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf); + data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + base = ticks - data; + dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", + base, data, ticks); + + pm860x_page_reg_write(info->i2c, REG0_DATA, (base >> 24) & 0xFF); + pm860x_page_reg_write(info->i2c, REG1_DATA, (base >> 16) & 0xFF); + pm860x_page_reg_write(info->i2c, REG2_DATA, (base >> 8) & 0xFF); + pm860x_page_reg_write(info->i2c, REG3_DATA, base & 0xFF); + + if (info->sync) + info->sync(ticks); + return 0; +} + +static int pm860x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct pm860x_rtc_info *info = dev_get_drvdata(dev); + unsigned char buf[8]; + unsigned long ticks, base, data; + int ret; + + pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf); + dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1], + buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); + base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7]; + + pm860x_bulk_read(info->i2c, PM8607_RTC_EXPIRE1, 4, buf); + data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + ticks = base + data; + dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", + base, data, ticks); + + rtc_time_to_tm(ticks, &alrm->time); + ret = pm860x_reg_read(info->i2c, PM8607_RTC1); + alrm->enabled = (ret & ALARM_EN) ? 1 : 0; + alrm->pending = (ret & (ALARM | ALARM_WAKEUP)) ? 1 : 0; + return 0; +} + +static int pm860x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct pm860x_rtc_info *info = dev_get_drvdata(dev); + struct rtc_time now_tm, alarm_tm; + unsigned long ticks, base, data; + unsigned char buf[8]; + int mask; + + pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM_EN, 0); + + pm860x_page_bulk_read(info->i2c, REG0_ADDR, 8, buf); + dev_dbg(info->dev, "%x-%x-%x-%x-%x-%x-%x-%x\n", buf[0], buf[1], + buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); + base = (buf[1] << 24) | (buf[3] << 16) | (buf[5] << 8) | buf[7]; + + /* load 32-bit read-only counter */ + pm860x_bulk_read(info->i2c, PM8607_RTC_COUNTER1, 4, buf); + data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; + ticks = base + data; + dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", + base, data, ticks); + + rtc_time_to_tm(ticks, &now_tm); + rtc_next_alarm_time(&alarm_tm, &now_tm, &alrm->time); + /* get new ticks for alarm in 24 hours */ + rtc_tm_to_time(&alarm_tm, &ticks); + data = ticks - base; + + buf[0] = data & 0xff; + buf[1] = (data >> 8) & 0xff; + buf[2] = (data >> 16) & 0xff; + buf[3] = (data >> 24) & 0xff; + pm860x_bulk_write(info->i2c, PM8607_RTC_EXPIRE1, 4, buf); + if (alrm->enabled) { + mask = ALARM | ALARM_WAKEUP | ALARM_EN; + pm860x_set_bits(info->i2c, PM8607_RTC1, mask, mask); + } else { + mask = ALARM | ALARM_WAKEUP | ALARM_EN; + pm860x_set_bits(info->i2c, PM8607_RTC1, mask, + ALARM | ALARM_WAKEUP); + } + return 0; +} + +static const struct rtc_class_ops pm860x_rtc_ops = { + .read_time = pm860x_rtc_read_time, + .set_time = pm860x_rtc_set_time, + .read_alarm = pm860x_rtc_read_alarm, + .set_alarm = pm860x_rtc_set_alarm, + .alarm_irq_enable = pm860x_rtc_alarm_irq_enable, +}; + +#ifdef VRTC_CALIBRATION +static void calibrate_vrtc_work(struct work_struct *work) +{ + struct pm860x_rtc_info *info = container_of(work, + struct pm860x_rtc_info, calib_work.work); + unsigned char buf[2]; + unsigned int sum, data, mean, vrtc_set; + int i; + + for (i = 0, sum = 0; i < 16; i++) { + msleep(100); + pm860x_bulk_read(info->i2c, REG_VRTC_MEAS1, 2, buf); + data = (buf[0] << 4) | buf[1]; + data = (data * 5400) >> 12; /* convert to mv */ + sum += data; + } + mean = sum >> 4; + vrtc_set = 2700 + (info->vrtc & 0x3) * 200; + dev_dbg(info->dev, "mean:%d, vrtc_set:%d\n", mean, vrtc_set); + + sum = pm860x_reg_read(info->i2c, PM8607_RTC_MISC1); + data = sum & 0x3; + if ((mean + 200) < vrtc_set) { + /* try higher voltage */ + if (++data == 4) + goto out; + data = (sum & 0xf8) | (data & 0x3); + pm860x_reg_write(info->i2c, PM8607_RTC_MISC1, data); + } else if ((mean - 200) > vrtc_set) { + /* try lower voltage */ + if (data-- == 0) + goto out; + data = (sum & 0xf8) | (data & 0x3); + pm860x_reg_write(info->i2c, PM8607_RTC_MISC1, data); + } else + goto out; + dev_dbg(info->dev, "set 0x%x to RTC_MISC1\n", data); + /* trigger next calibration since VRTC is updated */ + schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL); + return; +out: + /* disable measurement */ + pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0); + dev_dbg(info->dev, "finish VRTC calibration\n"); + return; +} +#endif + +static int __devinit pm860x_rtc_probe(struct platform_device *pdev) +{ + struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); + struct pm860x_rtc_pdata *pdata = NULL; + struct pm860x_rtc_info *info; + struct rtc_time tm; + unsigned long ticks = 0; + int ret; + + pdata = pdev->dev.platform_data; + if (pdata == NULL) + dev_warn(&pdev->dev, "No platform data!\n"); + + info = kzalloc(sizeof(struct pm860x_rtc_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + info->irq = platform_get_irq(pdev, 0); + if (info->irq < 0) { + dev_err(&pdev->dev, "No IRQ resource!\n"); + ret = -EINVAL; + goto out; + } + + info->chip = chip; + info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; + info->dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, info); + + ret = request_threaded_irq(info->irq, NULL, rtc_update_handler, + IRQF_ONESHOT, "rtc", info); + if (ret < 0) { + dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", + info->irq, ret); + goto out; + } + + /* set addresses of 32-bit base value for RTC time */ + pm860x_page_reg_write(info->i2c, REG0_ADDR, REG0_DATA); + pm860x_page_reg_write(info->i2c, REG1_ADDR, REG1_DATA); + pm860x_page_reg_write(info->i2c, REG2_ADDR, REG2_DATA); + pm860x_page_reg_write(info->i2c, REG3_ADDR, REG3_DATA); + + ret = pm860x_rtc_read_time(&pdev->dev, &tm); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to read initial time.\n"); + goto out_rtc; + } + if ((tm.tm_year < 70) || (tm.tm_year > 138)) { + tm.tm_year = 70; + tm.tm_mon = 0; + tm.tm_mday = 1; + tm.tm_hour = 0; + tm.tm_min = 0; + tm.tm_sec = 0; + ret = pm860x_rtc_set_time(&pdev->dev, &tm); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to set initial time.\n"); + goto out_rtc; + } + } + rtc_tm_to_time(&tm, &ticks); + if (pdata && pdata->sync) { + pdata->sync(ticks); + info->sync = pdata->sync; + } + + info->rtc_dev = rtc_device_register("88pm860x-rtc", &pdev->dev, + &pm860x_rtc_ops, THIS_MODULE); + ret = PTR_ERR(info->rtc_dev); + if (IS_ERR(info->rtc_dev)) { + dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); + goto out_rtc; + } + + /* + * enable internal XO instead of internal 3.25MHz clock since it can + * free running in PMIC power-down state. + */ + pm860x_set_bits(info->i2c, PM8607_RTC1, RTC1_USE_XO, RTC1_USE_XO); + +#ifdef VRTC_CALIBRATION + /* <00> -- 2.7V, <01> -- 2.9V, <10> -- 3.1V, <11> -- 3.3V */ + if (pdata && pdata->vrtc) + info->vrtc = pdata->vrtc & 0x3; + else + info->vrtc = 1; + pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, MEAS2_VRTC); + + /* calibrate VRTC */ + INIT_DELAYED_WORK(&info->calib_work, calibrate_vrtc_work); + schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL); +#endif /* VRTC_CALIBRATION */ + return 0; +out_rtc: + free_irq(info->irq, info); +out: + kfree(info); + return ret; +} + +static int __devexit pm860x_rtc_remove(struct platform_device *pdev) +{ + struct pm860x_rtc_info *info = platform_get_drvdata(pdev); + +#ifdef VRTC_CALIBRATION + flush_scheduled_work(); + /* disable measurement */ + pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0); +#endif /* VRTC_CALIBRATION */ + + platform_set_drvdata(pdev, NULL); + rtc_device_unregister(info->rtc_dev); + free_irq(info->irq, info); + kfree(info); + return 0; +} + +static struct platform_driver pm860x_rtc_driver = { + .driver = { + .name = "88pm860x-rtc", + .owner = THIS_MODULE, + }, + .probe = pm860x_rtc_probe, + .remove = __devexit_p(pm860x_rtc_remove), +}; + +static int __init pm860x_rtc_init(void) +{ + return platform_driver_register(&pm860x_rtc_driver); +} +module_init(pm860x_rtc_init); + +static void __exit pm860x_rtc_exit(void) +{ + platform_driver_unregister(&pm860x_rtc_driver); +} +module_exit(pm860x_rtc_exit); + +MODULE_DESCRIPTION("Marvell 88PM860x RTC driver"); +MODULE_AUTHOR("Haojian Zhuang "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From f5fb758de6d2ddae572ee39de54d60bf5593652a Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Fri, 6 May 2011 17:21:21 +0800 Subject: mfd: Avoid to allocate 88pm860x static platform data Maybe multiple PMIC devices are installed into one board. Static variable can only make driver logic mess. So remove these variable, and use platform data from platform driver instead. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-core.c | 45 ++++++++++++++++----------------------------- 1 file changed, 16 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index f2cac9287756..04ab50c1a6d4 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -151,11 +151,6 @@ static struct mfd_cell rtc_devs[] = { {"88pm860x-rtc", -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; @@ -522,14 +517,12 @@ static void __devinit device_bk_init(struct pm860x_chip *chip, 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].platform_data = &bk_pdata[i]; - bk_devs[i].pdata_size = sizeof(bk_pdata[i]); + bk_devs[i].platform_data = &pdata->backlight[i]; + bk_devs[i].pdata_size = sizeof(struct pm860x_backlight_pdata); for (j = 0; j < ARRAY_SIZE(bk_devs); j++) { id = bk_resources[j].start; - if (bk_pdata[i].flags != id) + if (pdata->backlight[i].flags != id) continue; bk_devs[i].num_resources = 1; @@ -560,14 +553,12 @@ static void __devinit device_led_init(struct pm860x_chip *chip, 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].platform_data = &led_pdata[i]; - led_devs[i].pdata_size = sizeof(led_pdata[i]); + led_devs[i].platform_data = &pdata->led[i]; + led_devs[i].pdata_size = sizeof(struct pm860x_led_pdata); for (j = 0; j < ARRAY_SIZE(led_devs); j++) { id = led_resources[j].start; - if (led_pdata[i].flags != id) + if (pdata->led[i].flags != id) continue; led_devs[i].num_resources = 1; @@ -625,10 +616,8 @@ static void __devinit device_regulator_init(struct pm860x_chip *chip, initdata->constraints.name); goto out; } - memcpy(®ulator_pdata[i], &pdata->regulator[i], - sizeof(struct regulator_init_data)); - regulator_devs[i].platform_data = ®ulator_pdata[i]; - regulator_devs[i].pdata_size = sizeof(regulator_pdata[i]); + regulator_devs[i].platform_data = &pdata->regulator[i]; + regulator_devs[i].pdata_size = sizeof(struct regulator_init_data); regulator_devs[i].num_resources = 1; regulator_devs[i].resources = ®ulator_resources[j]; @@ -669,12 +658,11 @@ static void __devinit device_touch_init(struct pm860x_chip *chip, { int ret; - if ((pdata == NULL) || (pdata->touch == NULL)) + if (pdata == NULL) return; - memcpy(&touch_pdata, pdata->touch, sizeof(struct pm860x_touch_pdata)); - touch_devs[0].platform_data = &touch_pdata; - touch_devs[0].pdata_size = sizeof(touch_pdata); + touch_devs[0].platform_data = pdata->touch; + touch_devs[0].pdata_size = sizeof(struct pm860x_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], @@ -690,12 +678,11 @@ static void __devinit device_power_init(struct pm860x_chip *chip, { int ret; - if ((pdata == NULL) || (pdata->power == NULL)) + if (pdata == NULL) return; - memcpy(&power_pdata, pdata->power, sizeof(struct pm860x_power_pdata)); - power_devs[0].platform_data = &power_pdata; - power_devs[0].pdata_size = sizeof(power_pdata); + power_devs[0].platform_data = pdata->power; + power_devs[0].pdata_size = sizeof(struct pm860x_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, @@ -703,8 +690,8 @@ static void __devinit device_power_init(struct pm860x_chip *chip, if (ret < 0) dev_err(chip->dev, "Failed to add battery subdev\n"); - power_devs[1].platform_data = &power_pdata; - power_devs[0].pdata_size = sizeof(power_pdata); + power_devs[1].platform_data = pdata->power; + power_devs[1].pdata_size = sizeof(struct pm860x_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, -- cgit v1.2.3 From cea438dda618797922d0bfc4814e832bab19ac19 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Fri, 6 May 2011 17:21:24 +0800 Subject: mfd: Remove unused parameter from 88pm860x API i2c_client parameter isn't used in some functions. Just remove it. Signed-off-by: Haojian Zhuang Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-core.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 04ab50c1a6d4..91962ef38c08 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -504,7 +504,6 @@ static void device_irq_exit(struct pm860x_chip *chip) } static void __devinit device_bk_init(struct pm860x_chip *chip, - struct i2c_client *i2c, struct pm860x_platform_data *pdata) { int ret; @@ -540,7 +539,6 @@ static void __devinit device_bk_init(struct pm860x_chip *chip, } static void __devinit device_led_init(struct pm860x_chip *chip, - struct i2c_client *i2c, struct pm860x_platform_data *pdata) { int ret; @@ -576,7 +574,6 @@ 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; @@ -633,7 +630,6 @@ out: } static void __devinit device_rtc_init(struct pm860x_chip *chip, - struct i2c_client *i2c, struct pm860x_platform_data *pdata) { int ret; @@ -653,7 +649,6 @@ static void __devinit device_rtc_init(struct pm860x_chip *chip, } static void __devinit device_touch_init(struct pm860x_chip *chip, - struct i2c_client *i2c, struct pm860x_platform_data *pdata) { int ret; @@ -673,7 +668,6 @@ static void __devinit device_touch_init(struct pm860x_chip *chip, } static void __devinit device_power_init(struct pm860x_chip *chip, - struct i2c_client *i2c, struct pm860x_platform_data *pdata) { int ret; @@ -701,7 +695,6 @@ static void __devinit device_power_init(struct pm860x_chip *chip, } static void __devinit device_onkey_init(struct pm860x_chip *chip, - struct i2c_client *i2c, struct pm860x_platform_data *pdata) { int ret; @@ -716,7 +709,6 @@ static void __devinit device_onkey_init(struct pm860x_chip *chip, } static void __devinit device_codec_init(struct pm860x_chip *chip, - struct i2c_client *i2c, struct pm860x_platform_data *pdata) { int ret; @@ -784,12 +776,12 @@ static void __devinit device_8607_init(struct pm860x_chip *chip, if (ret < 0) goto out; - 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); - device_codec_init(chip, i2c, pdata); + device_regulator_init(chip, pdata); + device_rtc_init(chip, pdata); + device_onkey_init(chip, pdata); + device_touch_init(chip, pdata); + device_power_init(chip, pdata); + device_codec_init(chip, pdata); out: return; } @@ -801,8 +793,8 @@ int __devinit pm860x_device_init(struct pm860x_chip *chip, switch (chip->id) { case CHIP_PM8606: - device_bk_init(chip, chip->client, pdata); - device_led_init(chip, chip->client, pdata); + device_bk_init(chip, pdata); + device_led_init(chip, pdata); break; case CHIP_PM8607: device_8607_init(chip, chip->client, pdata); @@ -812,8 +804,8 @@ 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_led_init(chip, chip->companion, pdata); + device_bk_init(chip, pdata); + device_led_init(chip, pdata); break; case CHIP_PM8606: device_8607_init(chip, chip->companion, pdata); -- cgit v1.2.3 From ebf9988ecad6727e5ae950fc2c72b963a1bfc0fe Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Fri, 6 May 2011 17:21:25 +0800 Subject: mfd: Remove checking on max8925 regulator[0] Since regulator[0] is always checking in mfd driver, it results in registration failure without regulator[0]. Signed-off-by: Haojian Zhuang Reviewed-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/max8925-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index 58cc5fdde016..e1e59c92f758 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -627,7 +627,7 @@ int __devinit max8925_device_init(struct max8925_chip *chip, goto out_dev; } - if (pdata && pdata->regulator[0]) { + if (pdata) { ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[0], ARRAY_SIZE(regulator_devs), ®ulator_resources[0], 0); -- cgit v1.2.3 From 586e1a1763d34bd256f3f1e77293d8386e4871d2 Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Fri, 6 May 2011 17:21:23 +0800 Subject: mfd: Avoid to use constraint name in 88pm860x regulator driver Avoid to use constraint name in regulator driver. So use regulator id is used instead in platform driver. Signed-off-by: Haojian Zhuang Cc: Liam Girdwood Acked-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/88pm860x-core.c | 35 ++++++++--------------------------- drivers/regulator/88pm8607.c | 25 +++++++++++++------------ 2 files changed, 21 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 91962ef38c08..17dfe9bb6d27 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -578,7 +578,7 @@ static void __devinit device_regulator_init(struct pm860x_chip *chip, { struct regulator_init_data *initdata; int ret; - int i, j; + int i, seq; if ((pdata == NULL) || (pdata->regulator == NULL)) return; @@ -586,40 +586,21 @@ static void __devinit device_regulator_init(struct pm860x_chip *chip, 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++) { + for (i = 0, seq = -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); + seq = *(unsigned int *)initdata->driver_data; + if ((seq < 0) || (seq > PM8607_ID_RG_MAX)) { + dev_err(chip->dev, "Wrong ID(%d) on regulator(%s)\n", + seq, initdata->constraints.name); goto out; } regulator_devs[i].platform_data = &pdata->regulator[i]; regulator_devs[i].pdata_size = sizeof(struct regulator_init_data); regulator_devs[i].num_resources = 1; - regulator_devs[i].resources = ®ulator_resources[j]; + regulator_devs[i].resources = ®ulator_resources[seq]; ret = mfd_add_devices(chip->dev, 0, ®ulator_devs[i], 1, - ®ulator_resources[j], 0); + ®ulator_resources[seq], 0); if (ret < 0) { dev_err(chip->dev, "Failed to add regulator subdev\n"); goto out; diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index 784ea7724c7a..1904be9149af 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -398,32 +398,33 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) { struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent); struct pm8607_regulator_info *info = NULL; - struct regulator_init_data *pdata; + struct regulator_init_data *pdata = pdev->dev.platform_data; + struct resource *res; int i; - pdata = pdev->dev.platform_data; - if (pdata == NULL) + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (res == NULL) { + dev_err(&pdev->dev, "No I/O resource!\n"); return -EINVAL; - + } for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) { info = &pm8607_regulator_info[i]; - if (!strcmp(info->desc.name, pdata->constraints.name)) + if (info->desc.id == res->start) break; } - if (i > ARRAY_SIZE(pm8607_regulator_info)) { - dev_err(&pdev->dev, "Failed to find regulator %s\n", - pdata->constraints.name); + if ((i < 0) || (i > PM8607_ID_RG_MAX)) { + dev_err(&pdev->dev, "Failed to find regulator %d\n", + res->start); 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; + if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double) + info->slope_double = 1; + /* replace driver_data with info */ info->regulator = regulator_register(&info->desc, &pdev->dev, pdata, info); if (IS_ERR(info->regulator)) { -- cgit v1.2.3 From 521d8ec3f0d8069bea3b3afa70f487cdb5118018 Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Thu, 12 May 2011 14:27:55 +0100 Subject: mfd: Add phoenix lite (twl6025) support to twl6030 Phoenix Lite is based on the twl6030 family of PMICs. It has mostly the same feature set of twl6030 but with small changes. The codec block has also been removed. It also has a new charger block and new features in its ADC block. VUSB handling also differs. Signed-off-by: Graeme Gregory Reviewed-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/mfd/twl-core.c | 190 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 153 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 2bd9e0676bc2..b8f2a4e7f6e7 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -198,6 +198,7 @@ #define TWL6030_BASEADD_GASGAUGE 0x00C0 #define TWL6030_BASEADD_PIH 0x00D0 #define TWL6030_BASEADD_CHARGER 0x00E0 +#define TWL6025_BASEADD_CHARGER 0x00DA /* subchip/slave 2 0x4A - DFT */ #define TWL6030_BASEADD_DIEID 0x00C0 @@ -331,6 +332,7 @@ static struct twl_mapping twl6030_map[] = { { SUB_CHIP_ID0, TWL6030_BASEADD_RTC }, { SUB_CHIP_ID0, TWL6030_BASEADD_MEM }, + { SUB_CHIP_ID1, TWL6025_BASEADD_CHARGER }, }; /*----------------------------------------------------------------------*/ @@ -604,7 +606,7 @@ static inline struct device *add_child(unsigned chip, const char *name, static struct device * add_regulator_linked(int num, struct regulator_init_data *pdata, struct regulator_consumer_supply *consumers, - unsigned num_consumers) + unsigned num_consumers, unsigned long features) { unsigned sub_chip_id; /* regulator framework demands init_data ... */ @@ -616,6 +618,8 @@ add_regulator_linked(int num, struct regulator_init_data *pdata, pdata->num_consumer_supplies = num_consumers; } + pdata->driver_data = (void *)features; + /* NOTE: we currently ignore regulator IRQs, e.g. for short circuits */ sub_chip_id = twl_map[TWL_MODULE_PM_MASTER].sid; return add_numbered_child(sub_chip_id, "twl_reg", num, @@ -623,9 +627,10 @@ add_regulator_linked(int num, struct regulator_init_data *pdata, } static struct device * -add_regulator(int num, struct regulator_init_data *pdata) +add_regulator(int num, struct regulator_init_data *pdata, + unsigned long features) { - return add_regulator_linked(num, pdata, NULL, 0); + return add_regulator_linked(num, pdata, NULL, 0, features); } /* @@ -705,17 +710,20 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) }; child = add_regulator_linked(TWL4030_REG_VUSB1V5, - &usb_fixed, &usb1v5, 1); + &usb_fixed, &usb1v5, 1, + features); if (IS_ERR(child)) return PTR_ERR(child); child = add_regulator_linked(TWL4030_REG_VUSB1V8, - &usb_fixed, &usb1v8, 1); + &usb_fixed, &usb1v8, 1, + features); if (IS_ERR(child)) return PTR_ERR(child); child = add_regulator_linked(TWL4030_REG_VUSB3V1, - &usb_fixed, &usb3v1, 1); + &usb_fixed, &usb3v1, 1, + features); if (IS_ERR(child)) return PTR_ERR(child); @@ -740,9 +748,8 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) } if (twl_has_usb() && pdata->usb && twl_class_is_6030()) { - static struct regulator_consumer_supply usb3v3 = { - .supply = "vusb", - }; + static struct regulator_consumer_supply usb3v3; + int regulator; if (twl_has_regulator()) { /* this is a template that gets copied */ @@ -755,12 +762,22 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) | REGULATOR_CHANGE_STATUS, }; - child = add_regulator_linked(TWL6030_REG_VUSB, - &usb_fixed, &usb3v3, 1); + if (features & TWL6025_SUBCLASS) { + usb3v3.supply = "ldousb"; + regulator = TWL6025_REG_LDOUSB; + } else { + usb3v3.supply = "vusb"; + regulator = TWL6030_REG_VUSB; + } + child = add_regulator_linked(regulator, &usb_fixed, + &usb3v3, 1, + features); if (IS_ERR(child)) return PTR_ERR(child); } + pdata->usb->features = features; + child = add_child(0, "twl6030_usb", pdata->usb, sizeof(*pdata->usb), true, @@ -773,7 +790,16 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) /* we need to connect regulators to this transceiver */ if (twl_has_regulator() && child) usb3v3.dev = child; + } else if (twl_has_regulator() && twl_class_is_6030()) { + if (features & TWL6025_SUBCLASS) + child = add_regulator(TWL6025_REG_LDOUSB, + pdata->ldousb, features); + else + child = add_regulator(TWL6030_REG_VUSB, + pdata->vusb, features); + if (IS_ERR(child)) + return PTR_ERR(child); } if (twl_has_watchdog() && twl_class_is_4030()) { @@ -810,46 +836,55 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) /* twl4030 regulators */ if (twl_has_regulator() && twl_class_is_4030()) { - child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1); + child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL4030_REG_VIO, pdata->vio); + child = add_regulator(TWL4030_REG_VIO, pdata->vio, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1); + child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2); + child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1); + child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL4030_REG_VDAC, pdata->vdac); + child = add_regulator(TWL4030_REG_VDAC, pdata->vdac, + features); if (IS_ERR(child)) return PTR_ERR(child); child = add_regulator((features & TWL4030_VAUX2) ? TWL4030_REG_VAUX2_4030 : TWL4030_REG_VAUX2, - pdata->vaux2); + pdata->vaux2, features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1); + child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2); + child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig); + child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig, + features); if (IS_ERR(child)) return PTR_ERR(child); } @@ -857,72 +892,152 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features) /* maybe add LDOs that are omitted on cost-reduced parts */ if (twl_has_regulator() && !(features & TPS_SUBSET) && twl_class_is_4030()) { - child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2); + child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2); + child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL4030_REG_VSIM, pdata->vsim); + child = add_regulator(TWL4030_REG_VSIM, pdata->vsim, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1); + child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3); + child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4); + child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4, + features); if (IS_ERR(child)) return PTR_ERR(child); } /* twl6030 regulators */ + if (twl_has_regulator() && twl_class_is_6030() && + !(features & TWL6025_SUBCLASS)) { + child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + + child = add_regulator(TWL6030_REG_VPP, pdata->vpp, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + + child = add_regulator(TWL6030_REG_VUSIM, pdata->vusim, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + + child = add_regulator(TWL6030_REG_VCXIO, pdata->vcxio, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + + child = add_regulator(TWL6030_REG_VDAC, pdata->vdac, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + + child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + + child = add_regulator(TWL6030_REG_VAUX2_6030, pdata->vaux2, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + + child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + + child = add_regulator(TWL6030_REG_CLK32KG, pdata->clk32kg, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + } + + /* 6030 and 6025 share this regulator */ if (twl_has_regulator() && twl_class_is_6030()) { - child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc); + child = add_regulator(TWL6030_REG_VANA, pdata->vana, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + } + + /* twl6025 regulators */ + if (twl_has_regulator() && twl_class_is_6030() && + (features & TWL6025_SUBCLASS)) { + child = add_regulator(TWL6025_REG_LDO5, pdata->ldo5, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL6030_REG_VPP, pdata->vpp); + child = add_regulator(TWL6025_REG_LDO1, pdata->ldo1, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL6030_REG_VUSIM, pdata->vusim); + child = add_regulator(TWL6025_REG_LDO7, pdata->ldo7, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL6030_REG_VANA, pdata->vana); + child = add_regulator(TWL6025_REG_LDO6, pdata->ldo6, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL6030_REG_VCXIO, pdata->vcxio); + child = add_regulator(TWL6025_REG_LDOLN, pdata->ldoln, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL6030_REG_VDAC, pdata->vdac); + child = add_regulator(TWL6025_REG_LDO2, pdata->ldo2, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1); + child = add_regulator(TWL6025_REG_LDO4, pdata->ldo4, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL6030_REG_VAUX2_6030, pdata->vaux2); + child = add_regulator(TWL6025_REG_LDO3, pdata->ldo3, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3); + child = add_regulator(TWL6025_REG_SMPS3, pdata->smps3, + features); if (IS_ERR(child)) return PTR_ERR(child); - child = add_regulator(TWL6030_REG_CLK32KG, pdata->clk32kg); + child = add_regulator(TWL6025_REG_SMPS4, pdata->smps4, + features); if (IS_ERR(child)) return PTR_ERR(child); + + child = add_regulator(TWL6025_REG_VIO, pdata->vio6025, + features); + if (IS_ERR(child)) + return PTR_ERR(child); + } if (twl_has_bci() && pdata->bci && @@ -1170,6 +1285,7 @@ static const struct i2c_device_id twl_ids[] = { { "tps65930", TPS_SUBSET }, /* fewer LDOs and DACs; no charger */ { "tps65920", TPS_SUBSET }, /* fewer LDOs; no codec or charger */ { "twl6030", TWL6030_CLASS }, /* "Phoenix power chip" */ + { "twl6025", TWL6030_CLASS | TWL6025_SUBCLASS }, /* "Phoenix lite" */ { /* end of list */ }, }; MODULE_DEVICE_TABLE(i2c, twl_ids); -- cgit v1.2.3 From 6523b148b44be38d89c2ee9865d34da30d9f5f1c Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Thu, 12 May 2011 14:27:56 +0100 Subject: mfd: Fix twl6030 irq definitions The charger fault IRQs from the twl will in future patches be handled by a seperate IRQ handler in the charger driver than the general charger IRQ. Give them different IRQ numbers now to allow the charger driver to be merged in the future. Signed-off-by: Graeme Gregory Signed-off-by: Samuel Ortiz --- drivers/mfd/twl6030-irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index dfbae34e1804..eb3b5f88e566 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -76,8 +76,8 @@ static int twl6030_interrupt_mapping[24] = { USBOTG_INTR_OFFSET, /* Bit 18 ID */ USB_PRES_INTR_OFFSET, /* Bit 19 VBUS */ CHARGER_INTR_OFFSET, /* Bit 20 CHRG_CTRL */ - CHARGER_INTR_OFFSET, /* Bit 21 EXT_CHRG */ - CHARGER_INTR_OFFSET, /* Bit 22 INT_CHRG */ + CHARGERFAULT_INTR_OFFSET, /* Bit 21 EXT_CHRG */ + CHARGERFAULT_INTR_OFFSET, /* Bit 22 INT_CHRG */ RSV_INTR_OFFSET, /* Bit 23 Reserved */ }; /*----------------------------------------------------------------------*/ -- cgit v1.2.3 From eac78a21017f5beefa75f88b966950cd89caac37 Mon Sep 17 00:00:00 2001 From: Lesly A M Date: Wed, 4 May 2011 17:38:53 +0530 Subject: mfd: Check twl4030-power remove script error condition after i2cwrite Fixing the error condition check in twl4030 remove script function. Due to some typo in commit ID: 11a441ce82d6ffecfd39b324024de0cd630b36c1 Signed-off-by: Lesly A M Signed-off-by: Samuel Ortiz --- drivers/mfd/twl4030-power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c index 8162e435c9ff..a764676f0922 100644 --- a/drivers/mfd/twl4030-power.c +++ b/drivers/mfd/twl4030-power.c @@ -485,9 +485,9 @@ int twl4030_remove_script(u8 flags) return err; } if (flags & TWL4030_WAKEUP12_SCRIPT) { - if (err) err = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, END_OF_SCRIPT, R_SEQ_ADD_S2A12); + if (err) return err; } if (flags & TWL4030_WAKEUP3_SCRIPT) { -- cgit v1.2.3 From 863dde5bfa3c48f459c6302daf64f94a11c7c1e5 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 8 May 2011 00:54:45 +0200 Subject: mfd: Provide ab8500-core enumerators for chip cuts Since functionality in MFD cells may need to be adjusted according to chip revision, let's enumerate them and keep track of them. Signed-off-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-core.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 67d01c938284..fc0c1af1566e 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -254,8 +254,9 @@ static void ab8500_irq_sync_unlock(struct irq_data *data) if (new == old) continue; - /* Interrupt register 12 does'nt exist prior to version 0x20 */ - if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20) + /* Interrupt register 12 doesn't exist prior to version 2.0 */ + if (ab8500_irq_regoffset[i] == 11 && + ab8500->chip_id < AB8500_CUT2P0) continue; ab8500->oldmask[i] = new; @@ -307,8 +308,8 @@ static irqreturn_t ab8500_irq(int irq, void *dev) int status; u8 value; - /* Interrupt register 12 does'nt exist prior to version 0x20 */ - if (regoffset == 11 && ab8500->chip_id < 0x20) + /* Interrupt register 12 doesn't exist prior to version 2.0 */ + if (regoffset == 11 && ab8500->chip_id < AB8500_CUT2P0) continue; status = get_register_interruptible(ab8500, AB8500_INTERRUPT, @@ -724,17 +725,15 @@ int __devinit ab8500_init(struct ab8500 *ab8500) if (ret < 0) return ret; - /* - * 0x0 - Early Drop - * 0x10 - Cut 1.0 - * 0x11 - Cut 1.1 - * 0x20 - Cut 2.0 - * 0x30 - Cut 3.0 - */ - if (value == 0x0 || value == 0x10 || value == 0x11 || value == 0x20 || - value == 0x30) { + switch (value) { + case AB8500_CUTEARLY: + case AB8500_CUT1P0: + case AB8500_CUT1P1: + case AB8500_CUT2P0: + case AB8500_CUT3P0: dev_info(ab8500->dev, "detected chip, revision: %#x\n", value); - } else { + break; + default: dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value); return -EINVAL; } @@ -763,8 +762,9 @@ int __devinit ab8500_init(struct ab8500 *ab8500) /* Clear and mask all interrupts */ for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) { - /* Interrupt register 12 does'nt exist prior to version 0x20 */ - if (ab8500_irq_regoffset[i] == 11 && ab8500->chip_id < 0x20) + /* Interrupt register 12 doesn't exist prior to version 2.0 */ + if (ab8500_irq_regoffset[i] == 11 && + ab8500->chip_id < AB8500_CUT2P0) continue; get_register_interruptible(ab8500, AB8500_INTERRUPT, -- cgit v1.2.3 From c9c9513fd08d1e0548003e86d70a211c2e456d49 Mon Sep 17 00:00:00 2001 From: Karl Komierowski Date: Sun, 8 May 2011 00:55:31 +0200 Subject: mfd: Add manual ab8500-gpadc batt temp activation for AB8500 3.0 In AB8500 3.0 the pull-up supplying the NTC must be manually activated. Add enumerators to chip version detection logic. Signed-off-by: Kalle Komierowski Reviewed-by: Johan Palsson Reviewed-by: Daniel Willerud Reviewed-by: Jonas Aberg Signed-off-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-gpadc.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index 6421ad1160de..82708c1f316d 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c @@ -57,6 +57,7 @@ #define SW_AVG_16 0x60 #define ADC_SW_CONV 0x04 #define EN_ICHAR 0x80 +#define BATTEMP_PULLUP 0x04 #define EN_BUF 0x40 #define DIS_ZERO 0x00 #define GPADC_BUSY 0x01 @@ -101,6 +102,7 @@ struct adc_cal_data { /** * struct ab8500_gpadc - AB8500 GPADC device information + * @chip_id ABB chip id * @dev: pointer to the struct device * @node: a list of AB8500 GPADCs, hence prepared for reentrance @@ -112,6 +114,7 @@ struct adc_cal_data { * @cal_data array of ADC calibration data structs */ struct ab8500_gpadc { + u8 chip_id; struct device *dev; struct list_head node; struct completion ab8500_gpadc_complete; @@ -274,6 +277,7 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input) dev_err(gpadc->dev, "gpadc_conversion: enable gpadc failed\n"); goto out; } + /* Select the input source and set average samples to 16 */ ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC, AB8500_GPADC_CTRL2_REG, (input | SW_AVG_16)); @@ -282,9 +286,11 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input) "gpadc_conversion: set avg samples failed\n"); goto out; } + /* * Enable ADC, buffering, select rising edge and enable ADC path - * charging current sense if it needed + * charging current sense if it needed, ABB 3.0 needs some special + * treatment too. */ switch (input) { case MAIN_CHARGER_C: @@ -294,6 +300,23 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input) EN_BUF | EN_ICHAR, EN_BUF | EN_ICHAR); break; + case BTEMP_BALL: + if (gpadc->chip_id >= AB8500_CUT3P0) { + /* Turn on btemp pull-up on ABB 3.0 */ + ret = abx500_mask_and_set_register_interruptible( + gpadc->dev, + AB8500_GPADC, AB8500_GPADC_CTRL1_REG, + EN_BUF | BATTEMP_PULLUP, + EN_BUF | BATTEMP_PULLUP); + + /* + * Delay might be needed for ABB8500 cut 3.0, if not, remove + * when hardware will be availible + */ + msleep(1); + break; + } + /* Intentional fallthrough */ default: ret = abx500_mask_and_set_register_interruptible(gpadc->dev, AB8500_GPADC, AB8500_GPADC_CTRL1_REG, EN_BUF, EN_BUF); @@ -304,6 +327,7 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input) "gpadc_conversion: select falling edge failed\n"); goto out; } + ret = abx500_mask_and_set_register_interruptible(gpadc->dev, AB8500_GPADC, AB8500_GPADC_CTRL1_REG, ADC_SW_CONV, ADC_SW_CONV); if (ret < 0) { @@ -552,6 +576,14 @@ static int __devinit ab8500_gpadc_probe(struct platform_device *pdev) goto fail; } + /* Get Chip ID of the ABB ASIC */ + ret = abx500_get_chip_id(gpadc->dev); + if (ret < 0) { + dev_err(gpadc->dev, "failed to get chip ID\n"); + goto fail_irq; + } + gpadc->chip_id = (u8) ret; + /* VTVout LDO used to power up ab8500-GPADC */ gpadc->regu = regulator_get(&pdev->dev, "vddadc"); if (IS_ERR(gpadc->regu)) { -- cgit v1.2.3 From ed13941643a437cf48f24ed53bdae79457628105 Mon Sep 17 00:00:00 2001 From: Johan Palsson Date: Sun, 8 May 2011 00:55:43 +0200 Subject: mfd: Correct the name and bitmask for ab8500-gpadc BTempPullUp The bitmask for enabling the BatTemp pull-up was wrong and is corrected. The name is also changed to be inline with the AB8500 register description Signed-off-by: Johan Palsson Reviewed-by: Mattias Wallin Signed-off-by: Linus Walleij Signed-off-by: Samuel Ortiz --- drivers/mfd/ab8500-gpadc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index 82708c1f316d..f16afb234ff9 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c @@ -57,7 +57,7 @@ #define SW_AVG_16 0x60 #define ADC_SW_CONV 0x04 #define EN_ICHAR 0x80 -#define BATTEMP_PULLUP 0x04 +#define BTEMP_PULL_UP 0x08 #define EN_BUF 0x40 #define DIS_ZERO 0x00 #define GPADC_BUSY 0x01 @@ -306,8 +306,8 @@ int ab8500_gpadc_convert(struct ab8500_gpadc *gpadc, u8 input) ret = abx500_mask_and_set_register_interruptible( gpadc->dev, AB8500_GPADC, AB8500_GPADC_CTRL1_REG, - EN_BUF | BATTEMP_PULLUP, - EN_BUF | BATTEMP_PULLUP); + EN_BUF | BTEMP_PULL_UP, + EN_BUF | BTEMP_PULL_UP); /* * Delay might be needed for ABB8500 cut 3.0, if not, remove -- cgit v1.2.3 From 4a7c00cd94d4ca7061c481fe823a256e37436044 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 10 May 2011 08:59:23 +0300 Subject: mfd: Update twl4030-code maintainer e-mail address Signed-off-by: Peter Ujfalusi Signed-off-by: Samuel Ortiz --- drivers/mfd/twl4030-codec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/twl4030-codec.c b/drivers/mfd/twl4030-codec.c index 315b5ead8437..2bf4136464c1 100644 --- a/drivers/mfd/twl4030-codec.c +++ b/drivers/mfd/twl4030-codec.c @@ -1,7 +1,7 @@ /* * MFD driver for twl4030 codec submodule * - * Author: Peter Ujfalusi + * Author: Peter Ujfalusi * * Copyright: (C) 2009 Nokia Corporation * @@ -272,6 +272,6 @@ static void __devexit twl4030_codec_exit(void) } module_exit(twl4030_codec_exit); -MODULE_AUTHOR("Peter Ujfalusi "); +MODULE_AUTHOR("Peter Ujfalusi "); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 7d9e7e9fbd3041a0596394579d800788bbf94939 Mon Sep 17 00:00:00 2001 From: Paul Parsons Date: Fri, 13 May 2011 18:52:56 +0000 Subject: leds: Add ASIC3 LED support Add LED support for the HTC ASIC3. Underlying support is provided by the mfd/asic3 and leds/leds-asic3 drivers. An example configuration is provided by the pxa/hx4700 platform. Signed-off-by: Paul Parsons Signed-off-by: Samuel Ortiz --- drivers/leds/Kconfig | 10 +++ drivers/leds/Makefile | 1 + drivers/leds/leds-asic3.c | 165 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 drivers/leds/leds-asic3.c (limited to 'drivers') diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 1d027b475b22..23f0d5e99f35 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -389,6 +389,16 @@ config LEDS_NETXBIG and 5Big Network v2 boards. The LEDs are wired to a CPLD and are controlled through a GPIO extension bus. +config LEDS_ASIC3 + bool "LED support for the HTC ASIC3" + depends on MFD_ASIC3 + default y + help + This option enables support for the LEDs on the HTC ASIC3. The HTC + ASIC3 LED GPIOs are inputs, not outputs, thus the leds-gpio driver + cannot be used. This driver supports hardware blinking with an on+off + period from 62ms to 125s. Say Y to enable LEDs on the HP iPAQ hx4700. + config LEDS_TRIGGERS bool "LED Trigger support" depends on LEDS_CLASS diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index bccb96c9bb45..bbfd2e367dc0 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_LEDS_DELL_NETBOOKS) += dell-led.o obj-$(CONFIG_LEDS_MC13783) += leds-mc13783.o obj-$(CONFIG_LEDS_NS2) += leds-ns2.o obj-$(CONFIG_LEDS_NETXBIG) += leds-netxbig.o +obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o # LED SPI Drivers obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o diff --git a/drivers/leds/leds-asic3.c b/drivers/leds/leds-asic3.c new file mode 100644 index 000000000000..22f847c890c9 --- /dev/null +++ b/drivers/leds/leds-asic3.c @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2011 Paul Parsons + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include +#include + +/* + * The HTC ASIC3 LED GPIOs are inputs, not outputs. + * Hence we turn the LEDs on/off via the TimeBase register. + */ + +/* + * When TimeBase is 4 the clock resolution is about 32Hz. + * This driver supports hardware blinking with an on+off + * period from 62ms (2 clocks) to 125s (4000 clocks). + */ +#define MS_TO_CLK(ms) DIV_ROUND_CLOSEST(((ms)*1024), 32000) +#define CLK_TO_MS(clk) (((clk)*32000)/1024) +#define MAX_CLK 4000 /* Fits into 12-bit Time registers */ +#define MAX_MS CLK_TO_MS(MAX_CLK) + +static const unsigned int led_n_base[ASIC3_NUM_LEDS] = { + [0] = ASIC3_LED_0_Base, + [1] = ASIC3_LED_1_Base, + [2] = ASIC3_LED_2_Base, +}; + +static void brightness_set(struct led_classdev *cdev, + enum led_brightness value) +{ + struct platform_device *pdev = to_platform_device(cdev->dev->parent); + const struct mfd_cell *cell = mfd_get_cell(pdev); + struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); + u32 timebase; + unsigned int base; + + timebase = (value == LED_OFF) ? 0 : (LED_EN|0x4); + + base = led_n_base[cell->id]; + asic3_write_register(asic, (base + ASIC3_LED_PeriodTime), 32); + asic3_write_register(asic, (base + ASIC3_LED_DutyTime), 32); + asic3_write_register(asic, (base + ASIC3_LED_AutoStopCount), 0); + asic3_write_register(asic, (base + ASIC3_LED_TimeBase), timebase); +} + +static int blink_set(struct led_classdev *cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct platform_device *pdev = to_platform_device(cdev->dev->parent); + const struct mfd_cell *cell = mfd_get_cell(pdev); + struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); + u32 on; + u32 off; + unsigned int base; + + if (*delay_on > MAX_MS || *delay_off > MAX_MS) + return -EINVAL; + + if (*delay_on == 0 && *delay_off == 0) { + /* If both are zero then a sensible default should be chosen */ + on = MS_TO_CLK(500); + off = MS_TO_CLK(500); + } else { + on = MS_TO_CLK(*delay_on); + off = MS_TO_CLK(*delay_off); + if ((on + off) > MAX_CLK) + return -EINVAL; + } + + base = led_n_base[cell->id]; + asic3_write_register(asic, (base + ASIC3_LED_PeriodTime), (on + off)); + asic3_write_register(asic, (base + ASIC3_LED_DutyTime), on); + asic3_write_register(asic, (base + ASIC3_LED_AutoStopCount), 0); + asic3_write_register(asic, (base + ASIC3_LED_TimeBase), (LED_EN|0x4)); + + *delay_on = CLK_TO_MS(on); + *delay_off = CLK_TO_MS(off); + + return 0; +} + +static int __devinit asic3_led_probe(struct platform_device *pdev) +{ + struct asic3_led *led = pdev->dev.platform_data; + int ret; + + ret = mfd_cell_enable(pdev); + if (ret < 0) + goto ret0; + + led->cdev = kzalloc(sizeof(struct led_classdev), GFP_KERNEL); + if (!led->cdev) { + ret = -ENOMEM; + goto ret1; + } + + led->cdev->name = led->name; + led->cdev->default_trigger = led->default_trigger; + led->cdev->brightness_set = brightness_set; + led->cdev->blink_set = blink_set; + + ret = led_classdev_register(&pdev->dev, led->cdev); + if (ret < 0) + goto ret2; + + return 0; + +ret2: + kfree(led->cdev); +ret1: + (void) mfd_cell_disable(pdev); +ret0: + return ret; +} + +static int __devexit asic3_led_remove(struct platform_device *pdev) +{ + struct asic3_led *led = pdev->dev.platform_data; + + led_classdev_unregister(led->cdev); + + kfree(led->cdev); + + return mfd_cell_disable(pdev); +} + +static struct platform_driver asic3_led_driver = { + .probe = asic3_led_probe, + .remove = __devexit_p(asic3_led_remove), + .driver = { + .name = "leds-asic3", + .owner = THIS_MODULE, + }, +}; + +MODULE_ALIAS("platform:leds-asic3"); + +static int __init asic3_led_init(void) +{ + return platform_driver_register(&asic3_led_driver); +} + +static void __exit asic3_led_exit(void) +{ + platform_driver_unregister(&asic3_led_driver); +} + +module_init(asic3_led_init); +module_exit(asic3_led_exit); + +MODULE_AUTHOR("Paul Parsons "); +MODULE_DESCRIPTION("HTC ASIC3 LED driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 13ca4f66108188231f9ef0358449f4543a0b84a1 Mon Sep 17 00:00:00 2001 From: Paul Parsons Date: Fri, 13 May 2011 18:53:03 +0000 Subject: mfd: Add ASIC3 LED support Add LED support for the HTC ASIC3. Underlying support is provided by the mfd/asic3 and leds/leds-asic3 drivers. An example configuration is provided by the pxa/hx4700 platform. Signed-off-by: Paul Parsons Signed-off-by: Samuel Ortiz --- drivers/mfd/asic3.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 77a3971e00bd..52e56ea43a85 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -88,19 +88,19 @@ struct asic3 { static int asic3_gpio_get(struct gpio_chip *chip, unsigned offset); -static inline void asic3_write_register(struct asic3 *asic, - unsigned int reg, u32 value) +void asic3_write_register(struct asic3 *asic, unsigned int reg, u32 value) { iowrite16(value, asic->mapping + (reg >> asic->bus_shift)); } +EXPORT_SYMBOL_GPL(asic3_write_register); -static inline u32 asic3_read_register(struct asic3 *asic, - unsigned int reg) +u32 asic3_read_register(struct asic3 *asic, unsigned int reg) { return ioread16(asic->mapping + (reg >> asic->bus_shift)); } +EXPORT_SYMBOL_GPL(asic3_read_register); static void asic3_set_register(struct asic3 *asic, u32 reg, u32 bits, bool set) { @@ -784,7 +784,55 @@ static struct mfd_cell asic3_cell_mmc = { .resources = asic3_mmc_resources, }; +static const int clock_ledn[ASIC3_NUM_LEDS] = { + [0] = ASIC3_CLOCK_LED0, + [1] = ASIC3_CLOCK_LED1, + [2] = ASIC3_CLOCK_LED2, +}; + +static int asic3_leds_enable(struct platform_device *pdev) +{ + const struct mfd_cell *cell = mfd_get_cell(pdev); + struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); + + asic3_clk_enable(asic, &asic->clocks[clock_ledn[cell->id]]); + + return 0; +} + +static int asic3_leds_disable(struct platform_device *pdev) +{ + const struct mfd_cell *cell = mfd_get_cell(pdev); + struct asic3 *asic = dev_get_drvdata(pdev->dev.parent); + + asic3_clk_disable(asic, &asic->clocks[clock_ledn[cell->id]]); + + return 0; +} + +static struct mfd_cell asic3_cell_leds[ASIC3_NUM_LEDS] = { + [0] = { + .name = "leds-asic3", + .id = 0, + .enable = asic3_leds_enable, + .disable = asic3_leds_disable, + }, + [1] = { + .name = "leds-asic3", + .id = 1, + .enable = asic3_leds_enable, + .disable = asic3_leds_disable, + }, + [2] = { + .name = "leds-asic3", + .id = 2, + .enable = asic3_leds_enable, + .disable = asic3_leds_disable, + }, +}; + static int __init asic3_mfd_probe(struct platform_device *pdev, + struct asic3_platform_data *pdata, struct resource *mem) { struct asic3 *asic = platform_get_drvdata(pdev); @@ -822,9 +870,23 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, if (ret < 0) goto out; - if (mem_sdio && (irq >= 0)) + if (mem_sdio && (irq >= 0)) { ret = mfd_add_devices(&pdev->dev, pdev->id, &asic3_cell_mmc, 1, mem_sdio, irq); + if (ret < 0) + goto out; + } + + if (pdata->leds) { + int i; + + for (i = 0; i < ASIC3_NUM_LEDS; ++i) { + asic3_cell_leds[i].platform_data = &pdata->leds[i]; + asic3_cell_leds[i].pdata_size = sizeof(pdata->leds[i]); + } + ret = mfd_add_devices(&pdev->dev, 0, + asic3_cell_leds, ASIC3_NUM_LEDS, NULL, 0); + } out: return ret; @@ -905,7 +967,7 @@ static int __init asic3_probe(struct platform_device *pdev) */ memcpy(asic->clocks, asic3_clk_init, sizeof(asic3_clk_init)); - asic3_mfd_probe(pdev, mem); + asic3_mfd_probe(pdev, pdata, mem); dev_info(asic->dev, "ASIC3 Core driver\n"); -- cgit v1.2.3 From 6eb6fbbf3eca6dfba73e72de5ab2eeb52ae41f7a Mon Sep 17 00:00:00 2001 From: Keshava Munegowda Date: Mon, 16 May 2011 14:24:58 +0530 Subject: mfd: Fix omap usbhs crash when rmmoding ehci or ohci The disabling of clocks and freeing GPIO are changed to fix the occurrence of the crash of rmmod of ehci and ohci drivers. The GPIOs should be freed after the spin locks are unlocked. Signed-off-by: Keshava Munegowda Acked-by: Felipe Balbi Cc: stable@kernel.org Signed-off-by: Samuel Ortiz --- drivers/mfd/omap-usb-host.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 3ab9ffa00aad..55c5d4732f5f 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -994,22 +994,33 @@ static void usbhs_disable(struct device *dev) dev_dbg(dev, "operation timed out\n"); } - if (pdata->ehci_data->phy_reset) { - if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) - gpio_free(pdata->ehci_data->reset_gpio_port[0]); - - if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) - gpio_free(pdata->ehci_data->reset_gpio_port[1]); + if (is_omap_usbhs_rev2(omap)) { + if (is_ehci_tll_mode(pdata->port_mode[0])) + clk_enable(omap->usbtll_p1_fck); + if (is_ehci_tll_mode(pdata->port_mode[1])) + clk_enable(omap->usbtll_p2_fck); + clk_disable(omap->utmi_p2_fck); + clk_disable(omap->utmi_p1_fck); } - clk_disable(omap->utmi_p2_fck); - clk_disable(omap->utmi_p1_fck); clk_disable(omap->usbtll_ick); clk_disable(omap->usbtll_fck); clk_disable(omap->usbhost_fs_fck); clk_disable(omap->usbhost_hs_fck); clk_disable(omap->usbhost_ick); + /* The gpio_free migh sleep; so unlock the spinlock */ + spin_unlock_irqrestore(&omap->lock, flags); + + if (pdata->ehci_data->phy_reset) { + if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) + gpio_free(pdata->ehci_data->reset_gpio_port[0]); + + if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) + gpio_free(pdata->ehci_data->reset_gpio_port[1]); + } + return; + end_disble: spin_unlock_irqrestore(&omap->lock, flags); } -- cgit v1.2.3 From d910774f13678caf68fc9cbbef325f08f7f951a3 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 14 May 2011 14:15:36 +0800 Subject: mfd: Fix omap_usbhs_alloc_children error handling 1. Return proper error if omap_usbhs_alloc_child fails 2. In the case of goto err_ehci, we should call platform_device_unregister(ehci) instead of platform_device_put(ehci) because we have already added the platform device to device hierarchy. Signed-off-by: Axel Lin Signed-off-by: Axel Lin Tested-by: Keshava Munegowda Acked-by: Felipe Balbi Signed-off-by: Samuel Ortiz --- drivers/mfd/omap-usb-host.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 55c5d4732f5f..1717144fe7f4 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -281,6 +281,7 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev) if (!ehci) { dev_err(dev, "omap_usbhs_alloc_child failed\n"); + ret = -ENOMEM; goto err_end; } @@ -304,13 +305,14 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev) sizeof(*ohci_data), dev); if (!ohci) { dev_err(dev, "omap_usbhs_alloc_child failed\n"); + ret = -ENOMEM; goto err_ehci; } return 0; err_ehci: - platform_device_put(ehci); + platform_device_unregister(ehci); err_end: return ret; -- cgit v1.2.3 From 74e32d1b68f177f9c998041d789253df9c7f3575 Mon Sep 17 00:00:00 2001 From: Paul Parsons Date: Sun, 15 May 2011 14:13:11 +0000 Subject: mfd: Fix ASIC3 SD Host Controller Configuration size The size of the TC6380AF SD Host Controller Configuration area is 0x200 bytes (assuming registers are aligned on 32-bit boundaries), not 0x400 bytes. Source: Toshiba TC6380AF Specification sections 4.2 and 4.3.1 Signed-off-by: Paul Parsons Signed-off-by: Samuel Ortiz --- drivers/mfd/asic3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 52e56ea43a85..c27fd1fc3b86 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -856,7 +856,8 @@ static int __init asic3_mfd_probe(struct platform_device *pdev, /* MMC */ asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) + - mem_sdio->start, 0x400 >> asic->bus_shift); + mem_sdio->start, + ASIC3_SD_CONFIG_SIZE >> asic->bus_shift); if (!asic->tmio_cnf) { ret = -ENOMEM; dev_dbg(asic->dev, "Couldn't ioremap SD_CONFIG\n"); -- cgit v1.2.3 From 7e6502d577106fb5b202bbaac64c5f1b065e6daa Mon Sep 17 00:00:00 2001 From: Keshava Munegowda Date: Sun, 22 May 2011 22:51:26 +0200 Subject: mfd: Add omap-usbhs runtime PM support The usbhs core driver does not enable/disable the interface and functional clocks; These clocks are handled by hwmod and runtime pm, hence insted of the clock enable/disable, the runtime pm APIS are used. however,the port clocks and tll clocks are handled by the usbhs core. Signed-off-by: Keshava Munegowda Signed-off-by: Samuel Ortiz --- drivers/mfd/omap-usb-host.c | 131 +++----------------------------------------- 1 file changed, 9 insertions(+), 122 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index 1717144fe7f4..855219526ccb 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -26,6 +26,7 @@ #include #include #include +#include #define USBHS_DRIVER_NAME "usbhs-omap" #define OMAP_EHCI_DEVICE "ehci-omap" @@ -146,9 +147,6 @@ struct usbhs_hcd_omap { - struct clk *usbhost_ick; - struct clk *usbhost_hs_fck; - struct clk *usbhost_fs_fck; struct clk *xclk60mhsp1_ck; struct clk *xclk60mhsp2_ck; struct clk *utmi_p1_fck; @@ -158,8 +156,6 @@ struct usbhs_hcd_omap { struct clk *usbhost_p2_fck; struct clk *usbtll_p2_fck; struct clk *init_60m_fclk; - struct clk *usbtll_fck; - struct clk *usbtll_ick; void __iomem *uhh_base; void __iomem *tll_base; @@ -353,46 +349,13 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev) omap->platdata.ehci_data = pdata->ehci_data; omap->platdata.ohci_data = pdata->ohci_data; - omap->usbhost_ick = clk_get(dev, "usbhost_ick"); - if (IS_ERR(omap->usbhost_ick)) { - ret = PTR_ERR(omap->usbhost_ick); - dev_err(dev, "usbhost_ick failed error:%d\n", ret); - goto err_end; - } - - omap->usbhost_hs_fck = clk_get(dev, "hs_fck"); - if (IS_ERR(omap->usbhost_hs_fck)) { - ret = PTR_ERR(omap->usbhost_hs_fck); - dev_err(dev, "usbhost_hs_fck failed error:%d\n", ret); - goto err_usbhost_ick; - } - - omap->usbhost_fs_fck = clk_get(dev, "fs_fck"); - if (IS_ERR(omap->usbhost_fs_fck)) { - ret = PTR_ERR(omap->usbhost_fs_fck); - dev_err(dev, "usbhost_fs_fck failed error:%d\n", ret); - goto err_usbhost_hs_fck; - } - - omap->usbtll_fck = clk_get(dev, "usbtll_fck"); - if (IS_ERR(omap->usbtll_fck)) { - ret = PTR_ERR(omap->usbtll_fck); - dev_err(dev, "usbtll_fck failed error:%d\n", ret); - goto err_usbhost_fs_fck; - } - - omap->usbtll_ick = clk_get(dev, "usbtll_ick"); - if (IS_ERR(omap->usbtll_ick)) { - ret = PTR_ERR(omap->usbtll_ick); - dev_err(dev, "usbtll_ick failed error:%d\n", ret); - goto err_usbtll_fck; - } + pm_runtime_enable(&pdev->dev); omap->utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk"); if (IS_ERR(omap->utmi_p1_fck)) { ret = PTR_ERR(omap->utmi_p1_fck); dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret); - goto err_usbtll_ick; + goto err_end; } omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck"); @@ -522,22 +485,8 @@ err_xclk60mhsp1_ck: err_utmi_p1_fck: clk_put(omap->utmi_p1_fck); -err_usbtll_ick: - clk_put(omap->usbtll_ick); - -err_usbtll_fck: - clk_put(omap->usbtll_fck); - -err_usbhost_fs_fck: - clk_put(omap->usbhost_fs_fck); - -err_usbhost_hs_fck: - clk_put(omap->usbhost_hs_fck); - -err_usbhost_ick: - clk_put(omap->usbhost_ick); - err_end: + pm_runtime_disable(&pdev->dev); kfree(omap); end_probe: @@ -571,11 +520,7 @@ static int __devexit usbhs_omap_remove(struct platform_device *pdev) clk_put(omap->utmi_p2_fck); clk_put(omap->xclk60mhsp1_ck); clk_put(omap->utmi_p1_fck); - clk_put(omap->usbtll_ick); - clk_put(omap->usbtll_fck); - clk_put(omap->usbhost_fs_fck); - clk_put(omap->usbhost_hs_fck); - clk_put(omap->usbhost_ick); + pm_runtime_disable(&pdev->dev); kfree(omap); return 0; @@ -695,7 +640,6 @@ static int usbhs_enable(struct device *dev) struct usbhs_omap_platform_data *pdata = &omap->platdata; unsigned long flags = 0; int ret = 0; - unsigned long timeout; unsigned reg; dev_dbg(dev, "starting TI HSUSB Controller\n"); @@ -708,11 +652,7 @@ static int usbhs_enable(struct device *dev) if (omap->count > 0) goto end_count; - clk_enable(omap->usbhost_ick); - clk_enable(omap->usbhost_hs_fck); - clk_enable(omap->usbhost_fs_fck); - clk_enable(omap->usbtll_fck); - clk_enable(omap->usbtll_ick); + pm_runtime_get_sync(dev); if (pdata->ehci_data->phy_reset) { if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) { @@ -736,50 +676,6 @@ static int usbhs_enable(struct device *dev) omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); - /* perform TLL soft reset, and wait until reset is complete */ - usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, - OMAP_USBTLL_SYSCONFIG_SOFTRESET); - - /* Wait for TLL reset to complete */ - timeout = jiffies + msecs_to_jiffies(1000); - while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS) - & OMAP_USBTLL_SYSSTATUS_RESETDONE)) { - cpu_relax(); - - if (time_after(jiffies, timeout)) { - dev_dbg(dev, "operation timed out\n"); - ret = -EINVAL; - goto err_tll; - } - } - - dev_dbg(dev, "TLL RESET DONE\n"); - - /* (1<<3) = no idle mode only for initial debugging */ - usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, - OMAP_USBTLL_SYSCONFIG_ENAWAKEUP | - OMAP_USBTLL_SYSCONFIG_SIDLEMODE | - OMAP_USBTLL_SYSCONFIG_AUTOIDLE); - - /* Put UHH in NoIdle/NoStandby mode */ - reg = usbhs_read(omap->uhh_base, OMAP_UHH_SYSCONFIG); - if (is_omap_usbhs_rev1(omap)) { - reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP - | OMAP_UHH_SYSCONFIG_SIDLEMODE - | OMAP_UHH_SYSCONFIG_CACTIVITY - | OMAP_UHH_SYSCONFIG_MIDLEMODE); - reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE; - - - } else if (is_omap_usbhs_rev2(omap)) { - reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR; - reg |= OMAP4_UHH_SYSCONFIG_NOIDLE; - reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR; - reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY; - } - - usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); - reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG); /* setup ULPI bypass and burst configurations */ reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN @@ -919,6 +815,8 @@ end_count: return 0; err_tll: + pm_runtime_put_sync(dev); + spin_unlock_irqrestore(&omap->lock, flags); if (pdata->ehci_data->phy_reset) { if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) gpio_free(pdata->ehci_data->reset_gpio_port[0]); @@ -926,13 +824,6 @@ err_tll: if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) gpio_free(pdata->ehci_data->reset_gpio_port[1]); } - - clk_disable(omap->usbtll_ick); - clk_disable(omap->usbtll_fck); - clk_disable(omap->usbhost_fs_fck); - clk_disable(omap->usbhost_hs_fck); - clk_disable(omap->usbhost_ick); - spin_unlock_irqrestore(&omap->lock, flags); return ret; } @@ -1005,11 +896,7 @@ static void usbhs_disable(struct device *dev) clk_disable(omap->utmi_p1_fck); } - clk_disable(omap->usbtll_ick); - clk_disable(omap->usbtll_fck); - clk_disable(omap->usbhost_fs_fck); - clk_disable(omap->usbhost_hs_fck); - clk_disable(omap->usbhost_ick); + pm_runtime_put_sync(dev); /* The gpio_free migh sleep; so unlock the spinlock */ spin_unlock_irqrestore(&omap->lock, flags); -- cgit v1.2.3 From 39325b59d88b42ba2ccf2e62c234059e9941a47c Mon Sep 17 00:00:00 2001 From: Trilok Soni Date: Thu, 19 May 2011 10:54:04 +0530 Subject: input: Add Qualcomm pm8xxx keypad controller driver Add Qualcomm PMIC8XXX based keypad controller driver supporting upto 18x8 matrix configuration. Acked-by: Dmitry Torokhov Signed-off-by: Trilok Soni Signed-off-by: Anirudh Ghayal Signed-off-by: Samuel Ortiz --- drivers/input/keyboard/Kconfig | 11 + drivers/input/keyboard/Makefile | 1 + drivers/input/keyboard/pmic8xxx-keypad.c | 799 +++++++++++++++++++++++++++++++ 3 files changed, 811 insertions(+) create mode 100644 drivers/input/keyboard/pmic8xxx-keypad.c (limited to 'drivers') diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 69badb4e06aa..b4dee9d5a055 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -412,6 +412,17 @@ config KEYBOARD_PXA930_ROTARY To compile this driver as a module, choose M here: the module will be called pxa930_rotary. +config KEYBOARD_PMIC8XXX + tristate "Qualcomm PMIC8XXX keypad support" + depends on MFD_PM8XXX + help + Say Y here if you want to enable the driver for the PMIC8XXX + keypad provided as a reference design from Qualcomm. This is intended + to support upto 18x8 matrix based keypad design. + + To compile this driver as a module, choose M here: the module will + be called pmic8xxx-keypad. + config KEYBOARD_SAMSUNG tristate "Samsung keypad support" depends on SAMSUNG_DEV_KEYPAD diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index c49cf8e04cd7..ddde0fd476f7 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o +obj-$(CONFIG_KEYBOARD_PMIC8XXX) += pmic8xxx-keypad.o obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c new file mode 100644 index 000000000000..40b02ae96f86 --- /dev/null +++ b/drivers/input/keyboard/pmic8xxx-keypad.c @@ -0,0 +1,799 @@ +/* Copyright (c) 2009-2011, Code Aurora Forum. 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 version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define PM8XXX_MAX_ROWS 18 +#define PM8XXX_MAX_COLS 8 +#define PM8XXX_ROW_SHIFT 3 +#define PM8XXX_MATRIX_MAX_SIZE (PM8XXX_MAX_ROWS * PM8XXX_MAX_COLS) + +#define PM8XXX_MIN_ROWS 5 +#define PM8XXX_MIN_COLS 5 + +#define MAX_SCAN_DELAY 128 +#define MIN_SCAN_DELAY 1 + +/* in nanoseconds */ +#define MAX_ROW_HOLD_DELAY 122000 +#define MIN_ROW_HOLD_DELAY 30500 + +#define MAX_DEBOUNCE_TIME 20 +#define MIN_DEBOUNCE_TIME 5 + +#define KEYP_CTRL 0x148 + +#define KEYP_CTRL_EVNTS BIT(0) +#define KEYP_CTRL_EVNTS_MASK 0x3 + +#define KEYP_CTRL_SCAN_COLS_SHIFT 5 +#define KEYP_CTRL_SCAN_COLS_MIN 5 +#define KEYP_CTRL_SCAN_COLS_BITS 0x3 + +#define KEYP_CTRL_SCAN_ROWS_SHIFT 2 +#define KEYP_CTRL_SCAN_ROWS_MIN 5 +#define KEYP_CTRL_SCAN_ROWS_BITS 0x7 + +#define KEYP_CTRL_KEYP_EN BIT(7) + +#define KEYP_SCAN 0x149 + +#define KEYP_SCAN_READ_STATE BIT(0) +#define KEYP_SCAN_DBOUNCE_SHIFT 1 +#define KEYP_SCAN_PAUSE_SHIFT 3 +#define KEYP_SCAN_ROW_HOLD_SHIFT 6 + +#define KEYP_TEST 0x14A + +#define KEYP_TEST_CLEAR_RECENT_SCAN BIT(6) +#define KEYP_TEST_CLEAR_OLD_SCAN BIT(5) +#define KEYP_TEST_READ_RESET BIT(4) +#define KEYP_TEST_DTEST_EN BIT(3) +#define KEYP_TEST_ABORT_READ BIT(0) + +#define KEYP_TEST_DBG_SELECT_SHIFT 1 + +/* bits of these registers represent + * '0' for key press + * '1' for key release + */ +#define KEYP_RECENT_DATA 0x14B +#define KEYP_OLD_DATA 0x14C + +#define KEYP_CLOCK_FREQ 32768 + +/** + * struct pmic8xxx_kp - internal keypad data structure + * @pdata - keypad platform data pointer + * @input - input device pointer for keypad + * @key_sense_irq - key press/release irq number + * @key_stuck_irq - key stuck notification irq number + * @keycodes - array to hold the key codes + * @dev - parent device pointer + * @keystate - present key press/release state + * @stuckstate - present state when key stuck irq + * @ctrl_reg - control register value + */ +struct pmic8xxx_kp { + const struct pm8xxx_keypad_platform_data *pdata; + struct input_dev *input; + int key_sense_irq; + int key_stuck_irq; + + unsigned short keycodes[PM8XXX_MATRIX_MAX_SIZE]; + + struct device *dev; + u16 keystate[PM8XXX_MAX_ROWS]; + u16 stuckstate[PM8XXX_MAX_ROWS]; + + u8 ctrl_reg; +}; + +static int pmic8xxx_kp_write_u8(struct pmic8xxx_kp *kp, + u8 data, u16 reg) +{ + int rc; + + rc = pm8xxx_writeb(kp->dev->parent, reg, data); + return rc; +} + +static int pmic8xxx_kp_read(struct pmic8xxx_kp *kp, + u8 *data, u16 reg, unsigned num_bytes) +{ + int rc; + + rc = pm8xxx_read_buf(kp->dev->parent, reg, data, num_bytes); + return rc; +} + +static int pmic8xxx_kp_read_u8(struct pmic8xxx_kp *kp, + u8 *data, u16 reg) +{ + int rc; + + rc = pmic8xxx_kp_read(kp, data, reg, 1); + return rc; +} + +static u8 pmic8xxx_col_state(struct pmic8xxx_kp *kp, u8 col) +{ + /* all keys pressed on that particular row? */ + if (col == 0x00) + return 1 << kp->pdata->num_cols; + else + return col & ((1 << kp->pdata->num_cols) - 1); +} + +/* + * Synchronous read protocol for RevB0 onwards: + * + * 1. Write '1' to ReadState bit in KEYP_SCAN register + * 2. Wait 2*32KHz clocks, so that HW can successfully enter read mode + * synchronously + * 3. Read rows in old array first if events are more than one + * 4. Read rows in recent array + * 5. Wait 4*32KHz clocks + * 6. Write '0' to ReadState bit of KEYP_SCAN register so that hw can + * synchronously exit read mode. + */ +static int pmic8xxx_chk_sync_read(struct pmic8xxx_kp *kp) +{ + int rc; + u8 scan_val; + + rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN); + if (rc < 0) { + dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc); + return rc; + } + + scan_val |= 0x1; + + rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN); + if (rc < 0) { + dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc); + return rc; + } + + /* 2 * 32KHz clocks */ + udelay((2 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1); + + return rc; +} + +static int pmic8xxx_kp_read_data(struct pmic8xxx_kp *kp, u16 *state, + u16 data_reg, int read_rows) +{ + int rc, row; + u8 new_data[PM8XXX_MAX_ROWS]; + + rc = pmic8xxx_kp_read(kp, new_data, data_reg, read_rows); + if (rc) + return rc; + + for (row = 0; row < kp->pdata->num_rows; row++) { + dev_dbg(kp->dev, "new_data[%d] = %d\n", row, + new_data[row]); + state[row] = pmic8xxx_col_state(kp, new_data[row]); + } + + return rc; +} + +static int pmic8xxx_kp_read_matrix(struct pmic8xxx_kp *kp, u16 *new_state, + u16 *old_state) +{ + int rc, read_rows; + u8 scan_val; + + if (kp->pdata->num_rows < PM8XXX_MIN_ROWS) + read_rows = PM8XXX_MIN_ROWS; + else + read_rows = kp->pdata->num_rows; + + pmic8xxx_chk_sync_read(kp); + + if (old_state) { + rc = pmic8xxx_kp_read_data(kp, old_state, KEYP_OLD_DATA, + read_rows); + if (rc < 0) { + dev_err(kp->dev, + "Error reading KEYP_OLD_DATA, rc=%d\n", rc); + return rc; + } + } + + rc = pmic8xxx_kp_read_data(kp, new_state, KEYP_RECENT_DATA, + read_rows); + if (rc < 0) { + dev_err(kp->dev, + "Error reading KEYP_RECENT_DATA, rc=%d\n", rc); + return rc; + } + + /* 4 * 32KHz clocks */ + udelay((4 * DIV_ROUND_UP(USEC_PER_SEC, KEYP_CLOCK_FREQ)) + 1); + + rc = pmic8xxx_kp_read_u8(kp, &scan_val, KEYP_SCAN); + if (rc < 0) { + dev_err(kp->dev, "Error reading KEYP_SCAN reg, rc=%d\n", rc); + return rc; + } + + scan_val &= 0xFE; + rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN); + if (rc < 0) + dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc); + + return rc; +} + +static void __pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, u16 *new_state, + u16 *old_state) +{ + int row, col, code; + + for (row = 0; row < kp->pdata->num_rows; row++) { + int bits_changed = new_state[row] ^ old_state[row]; + + if (!bits_changed) + continue; + + for (col = 0; col < kp->pdata->num_cols; col++) { + if (!(bits_changed & (1 << col))) + continue; + + dev_dbg(kp->dev, "key [%d:%d] %s\n", row, col, + !(new_state[row] & (1 << col)) ? + "pressed" : "released"); + + code = MATRIX_SCAN_CODE(row, col, PM8XXX_ROW_SHIFT); + + input_event(kp->input, EV_MSC, MSC_SCAN, code); + input_report_key(kp->input, + kp->keycodes[code], + !(new_state[row] & (1 << col))); + + input_sync(kp->input); + } + } +} + +static bool pmic8xxx_detect_ghost_keys(struct pmic8xxx_kp *kp, u16 *new_state) +{ + int row, found_first = -1; + u16 check, row_state; + + check = 0; + for (row = 0; row < kp->pdata->num_rows; row++) { + row_state = (~new_state[row]) & + ((1 << kp->pdata->num_cols) - 1); + + if (hweight16(row_state) > 1) { + if (found_first == -1) + found_first = row; + if (check & row_state) { + dev_dbg(kp->dev, "detected ghost key on row[%d]" + " and row[%d]\n", found_first, row); + return true; + } + } + check |= row_state; + } + return false; +} + +static int pmic8xxx_kp_scan_matrix(struct pmic8xxx_kp *kp, unsigned int events) +{ + u16 new_state[PM8XXX_MAX_ROWS]; + u16 old_state[PM8XXX_MAX_ROWS]; + int rc; + + switch (events) { + case 0x1: + rc = pmic8xxx_kp_read_matrix(kp, new_state, NULL); + if (rc < 0) + return rc; + + /* detecting ghost key is not an error */ + if (pmic8xxx_detect_ghost_keys(kp, new_state)) + return 0; + __pmic8xxx_kp_scan_matrix(kp, new_state, kp->keystate); + memcpy(kp->keystate, new_state, sizeof(new_state)); + break; + case 0x3: /* two events - eventcounter is gray-coded */ + rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state); + if (rc < 0) + return rc; + + __pmic8xxx_kp_scan_matrix(kp, old_state, kp->keystate); + __pmic8xxx_kp_scan_matrix(kp, new_state, old_state); + memcpy(kp->keystate, new_state, sizeof(new_state)); + break; + case 0x2: + dev_dbg(kp->dev, "Some key events were lost\n"); + rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state); + if (rc < 0) + return rc; + __pmic8xxx_kp_scan_matrix(kp, old_state, kp->keystate); + __pmic8xxx_kp_scan_matrix(kp, new_state, old_state); + memcpy(kp->keystate, new_state, sizeof(new_state)); + break; + default: + rc = -EINVAL; + } + return rc; +} + +/* + * NOTE: We are reading recent and old data registers blindly + * whenever key-stuck interrupt happens, because events counter doesn't + * get updated when this interrupt happens due to key stuck doesn't get + * considered as key state change. + * + * We are not using old data register contents after they are being read + * because it might report the key which was pressed before the key being stuck + * as stuck key because it's pressed status is stored in the old data + * register. + */ +static irqreturn_t pmic8xxx_kp_stuck_irq(int irq, void *data) +{ + u16 new_state[PM8XXX_MAX_ROWS]; + u16 old_state[PM8XXX_MAX_ROWS]; + int rc; + struct pmic8xxx_kp *kp = data; + + rc = pmic8xxx_kp_read_matrix(kp, new_state, old_state); + if (rc < 0) { + dev_err(kp->dev, "failed to read keypad matrix\n"); + return IRQ_HANDLED; + } + + __pmic8xxx_kp_scan_matrix(kp, new_state, kp->stuckstate); + + return IRQ_HANDLED; +} + +static irqreturn_t pmic8xxx_kp_irq(int irq, void *data) +{ + struct pmic8xxx_kp *kp = data; + u8 ctrl_val, events; + int rc; + + rc = pmic8xxx_kp_read(kp, &ctrl_val, KEYP_CTRL, 1); + if (rc < 0) { + dev_err(kp->dev, "failed to read keyp_ctrl register\n"); + return IRQ_HANDLED; + } + + events = ctrl_val & KEYP_CTRL_EVNTS_MASK; + + rc = pmic8xxx_kp_scan_matrix(kp, events); + if (rc < 0) + dev_err(kp->dev, "failed to scan matrix\n"); + + return IRQ_HANDLED; +} + +static int __devinit pmic8xxx_kpd_init(struct pmic8xxx_kp *kp) +{ + int bits, rc, cycles; + u8 scan_val = 0, ctrl_val = 0; + static const u8 row_bits[] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, + }; + + /* Find column bits */ + if (kp->pdata->num_cols < KEYP_CTRL_SCAN_COLS_MIN) + bits = 0; + else + bits = kp->pdata->num_cols - KEYP_CTRL_SCAN_COLS_MIN; + ctrl_val = (bits & KEYP_CTRL_SCAN_COLS_BITS) << + KEYP_CTRL_SCAN_COLS_SHIFT; + + /* Find row bits */ + if (kp->pdata->num_rows < KEYP_CTRL_SCAN_ROWS_MIN) + bits = 0; + else + bits = row_bits[kp->pdata->num_rows - KEYP_CTRL_SCAN_ROWS_MIN]; + + ctrl_val |= (bits << KEYP_CTRL_SCAN_ROWS_SHIFT); + + rc = pmic8xxx_kp_write_u8(kp, ctrl_val, KEYP_CTRL); + if (rc < 0) { + dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc); + return rc; + } + + bits = (kp->pdata->debounce_ms / 5) - 1; + + scan_val |= (bits << KEYP_SCAN_DBOUNCE_SHIFT); + + bits = fls(kp->pdata->scan_delay_ms) - 1; + scan_val |= (bits << KEYP_SCAN_PAUSE_SHIFT); + + /* Row hold time is a multiple of 32KHz cycles. */ + cycles = (kp->pdata->row_hold_ns * KEYP_CLOCK_FREQ) / NSEC_PER_SEC; + + scan_val |= (cycles << KEYP_SCAN_ROW_HOLD_SHIFT); + + rc = pmic8xxx_kp_write_u8(kp, scan_val, KEYP_SCAN); + if (rc) + dev_err(kp->dev, "Error writing KEYP_SCAN reg, rc=%d\n", rc); + + return rc; + +} + +static int __devinit pmic8xxx_kp_config_gpio(int gpio_start, int num_gpios, + struct pmic8xxx_kp *kp, struct pm_gpio *gpio_config) +{ + int rc, i; + + if (gpio_start < 0 || num_gpios < 0) + return -EINVAL; + + for (i = 0; i < num_gpios; i++) { + rc = pm8xxx_gpio_config(gpio_start + i, gpio_config); + if (rc) { + dev_err(kp->dev, "%s: FAIL pm8xxx_gpio_config():" + "for PM GPIO [%d] rc=%d.\n", + __func__, gpio_start + i, rc); + return rc; + } + } + + return 0; +} + +static int pmic8xxx_kp_enable(struct pmic8xxx_kp *kp) +{ + int rc; + + kp->ctrl_reg |= KEYP_CTRL_KEYP_EN; + + rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL); + if (rc < 0) + dev_err(kp->dev, "Error writing KEYP_CTRL reg, rc=%d\n", rc); + + return rc; +} + +static int pmic8xxx_kp_disable(struct pmic8xxx_kp *kp) +{ + int rc; + + kp->ctrl_reg &= ~KEYP_CTRL_KEYP_EN; + + rc = pmic8xxx_kp_write_u8(kp, kp->ctrl_reg, KEYP_CTRL); + if (rc < 0) + return rc; + + return rc; +} + +static int pmic8xxx_kp_open(struct input_dev *dev) +{ + struct pmic8xxx_kp *kp = input_get_drvdata(dev); + + return pmic8xxx_kp_enable(kp); +} + +static void pmic8xxx_kp_close(struct input_dev *dev) +{ + struct pmic8xxx_kp *kp = input_get_drvdata(dev); + + pmic8xxx_kp_disable(kp); +} + +/* + * keypad controller should be initialized in the following sequence + * only, otherwise it might get into FSM stuck state. + * + * - Initialize keypad control parameters, like no. of rows, columns, + * timing values etc., + * - configure rows and column gpios pull up/down. + * - set irq edge type. + * - enable the keypad controller. + */ +static int __devinit pmic8xxx_kp_probe(struct platform_device *pdev) +{ + const struct pm8xxx_keypad_platform_data *pdata = mfd_get_data(pdev); + const struct matrix_keymap_data *keymap_data; + struct pmic8xxx_kp *kp; + int rc; + u8 ctrl_val; + + struct pm_gpio kypd_drv = { + .direction = PM_GPIO_DIR_OUT, + .output_buffer = PM_GPIO_OUT_BUF_OPEN_DRAIN, + .output_value = 0, + .pull = PM_GPIO_PULL_NO, + .vin_sel = PM_GPIO_VIN_S3, + .out_strength = PM_GPIO_STRENGTH_LOW, + .function = PM_GPIO_FUNC_1, + .inv_int_pol = 1, + }; + + struct pm_gpio kypd_sns = { + .direction = PM_GPIO_DIR_IN, + .pull = PM_GPIO_PULL_UP_31P5, + .vin_sel = PM_GPIO_VIN_S3, + .out_strength = PM_GPIO_STRENGTH_NO, + .function = PM_GPIO_FUNC_NORMAL, + .inv_int_pol = 1, + }; + + + if (!pdata || !pdata->num_cols || !pdata->num_rows || + pdata->num_cols > PM8XXX_MAX_COLS || + pdata->num_rows > PM8XXX_MAX_ROWS || + pdata->num_cols < PM8XXX_MIN_COLS) { + dev_err(&pdev->dev, "invalid platform data\n"); + return -EINVAL; + } + + if (!pdata->scan_delay_ms || + pdata->scan_delay_ms > MAX_SCAN_DELAY || + pdata->scan_delay_ms < MIN_SCAN_DELAY || + !is_power_of_2(pdata->scan_delay_ms)) { + dev_err(&pdev->dev, "invalid keypad scan time supplied\n"); + return -EINVAL; + } + + if (!pdata->row_hold_ns || + pdata->row_hold_ns > MAX_ROW_HOLD_DELAY || + pdata->row_hold_ns < MIN_ROW_HOLD_DELAY || + ((pdata->row_hold_ns % MIN_ROW_HOLD_DELAY) != 0)) { + dev_err(&pdev->dev, "invalid keypad row hold time supplied\n"); + return -EINVAL; + } + + if (!pdata->debounce_ms || + ((pdata->debounce_ms % 5) != 0) || + pdata->debounce_ms > MAX_DEBOUNCE_TIME || + pdata->debounce_ms < MIN_DEBOUNCE_TIME) { + dev_err(&pdev->dev, "invalid debounce time supplied\n"); + return -EINVAL; + } + + keymap_data = pdata->keymap_data; + if (!keymap_data) { + dev_err(&pdev->dev, "no keymap data supplied\n"); + return -EINVAL; + } + + kp = kzalloc(sizeof(*kp), GFP_KERNEL); + if (!kp) + return -ENOMEM; + + platform_set_drvdata(pdev, kp); + + kp->pdata = pdata; + kp->dev = &pdev->dev; + + kp->input = input_allocate_device(); + if (!kp->input) { + dev_err(&pdev->dev, "unable to allocate input device\n"); + rc = -ENOMEM; + goto err_alloc_device; + } + + kp->key_sense_irq = platform_get_irq(pdev, 0); + if (kp->key_sense_irq < 0) { + dev_err(&pdev->dev, "unable to get keypad sense irq\n"); + rc = -ENXIO; + goto err_get_irq; + } + + kp->key_stuck_irq = platform_get_irq(pdev, 1); + if (kp->key_stuck_irq < 0) { + dev_err(&pdev->dev, "unable to get keypad stuck irq\n"); + rc = -ENXIO; + goto err_get_irq; + } + + kp->input->name = pdata->input_name ? : "PMIC8XXX keypad"; + kp->input->phys = pdata->input_phys_device ? : "pmic8xxx_keypad/input0"; + + kp->input->dev.parent = &pdev->dev; + + kp->input->id.bustype = BUS_I2C; + kp->input->id.version = 0x0001; + kp->input->id.product = 0x0001; + kp->input->id.vendor = 0x0001; + + kp->input->evbit[0] = BIT_MASK(EV_KEY); + + if (pdata->rep) + __set_bit(EV_REP, kp->input->evbit); + + kp->input->keycode = kp->keycodes; + kp->input->keycodemax = PM8XXX_MATRIX_MAX_SIZE; + kp->input->keycodesize = sizeof(kp->keycodes); + kp->input->open = pmic8xxx_kp_open; + kp->input->close = pmic8xxx_kp_close; + + matrix_keypad_build_keymap(keymap_data, PM8XXX_ROW_SHIFT, + kp->input->keycode, kp->input->keybit); + + input_set_capability(kp->input, EV_MSC, MSC_SCAN); + input_set_drvdata(kp->input, kp); + + /* initialize keypad state */ + memset(kp->keystate, 0xff, sizeof(kp->keystate)); + memset(kp->stuckstate, 0xff, sizeof(kp->stuckstate)); + + rc = pmic8xxx_kpd_init(kp); + if (rc < 0) { + dev_err(&pdev->dev, "unable to initialize keypad controller\n"); + goto err_get_irq; + } + + rc = pmic8xxx_kp_config_gpio(pdata->cols_gpio_start, + pdata->num_cols, kp, &kypd_sns); + if (rc < 0) { + dev_err(&pdev->dev, "unable to configure keypad sense lines\n"); + goto err_gpio_config; + } + + rc = pmic8xxx_kp_config_gpio(pdata->rows_gpio_start, + pdata->num_rows, kp, &kypd_drv); + if (rc < 0) { + dev_err(&pdev->dev, "unable to configure keypad drive lines\n"); + goto err_gpio_config; + } + + rc = request_any_context_irq(kp->key_sense_irq, pmic8xxx_kp_irq, + IRQF_TRIGGER_RISING, "pmic-keypad", kp); + if (rc < 0) { + dev_err(&pdev->dev, "failed to request keypad sense irq\n"); + goto err_get_irq; + } + + rc = request_any_context_irq(kp->key_stuck_irq, pmic8xxx_kp_stuck_irq, + IRQF_TRIGGER_RISING, "pmic-keypad-stuck", kp); + if (rc < 0) { + dev_err(&pdev->dev, "failed to request keypad stuck irq\n"); + goto err_req_stuck_irq; + } + + rc = pmic8xxx_kp_read_u8(kp, &ctrl_val, KEYP_CTRL); + if (rc < 0) { + dev_err(&pdev->dev, "failed to read KEYP_CTRL register\n"); + goto err_pmic_reg_read; + } + + kp->ctrl_reg = ctrl_val; + + rc = input_register_device(kp->input); + if (rc < 0) { + dev_err(&pdev->dev, "unable to register keypad input device\n"); + goto err_pmic_reg_read; + } + + device_init_wakeup(&pdev->dev, pdata->wakeup); + + return 0; + +err_pmic_reg_read: + free_irq(kp->key_stuck_irq, NULL); +err_req_stuck_irq: + free_irq(kp->key_sense_irq, NULL); +err_gpio_config: +err_get_irq: + input_free_device(kp->input); +err_alloc_device: + platform_set_drvdata(pdev, NULL); + kfree(kp); + return rc; +} + +static int __devexit pmic8xxx_kp_remove(struct platform_device *pdev) +{ + struct pmic8xxx_kp *kp = platform_get_drvdata(pdev); + + device_init_wakeup(&pdev->dev, 0); + free_irq(kp->key_stuck_irq, NULL); + free_irq(kp->key_sense_irq, NULL); + input_unregister_device(kp->input); + kfree(kp); + + platform_set_drvdata(pdev, NULL); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int pmic8xxx_kp_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct pmic8xxx_kp *kp = platform_get_drvdata(pdev); + struct input_dev *input_dev = kp->input; + + if (device_may_wakeup(dev)) { + enable_irq_wake(kp->key_sense_irq); + } else { + mutex_lock(&input_dev->mutex); + + if (input_dev->users) + pmic8xxx_kp_disable(kp); + + mutex_unlock(&input_dev->mutex); + } + + return 0; +} + +static int pmic8xxx_kp_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct pmic8xxx_kp *kp = platform_get_drvdata(pdev); + struct input_dev *input_dev = kp->input; + + if (device_may_wakeup(dev)) { + disable_irq_wake(kp->key_sense_irq); + } else { + mutex_lock(&input_dev->mutex); + + if (input_dev->users) + pmic8xxx_kp_enable(kp); + + mutex_unlock(&input_dev->mutex); + } + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(pm8xxx_kp_pm_ops, + pmic8xxx_kp_suspend, pmic8xxx_kp_resume); + +static struct platform_driver pmic8xxx_kp_driver = { + .probe = pmic8xxx_kp_probe, + .remove = __devexit_p(pmic8xxx_kp_remove), + .driver = { + .name = PM8XXX_KEYPAD_DEV_NAME, + .owner = THIS_MODULE, + .pm = &pm8xxx_kp_pm_ops, + }, +}; + +static int __init pmic8xxx_kp_init(void) +{ + return platform_driver_register(&pmic8xxx_kp_driver); +} +module_init(pmic8xxx_kp_init); + +static void __exit pmic8xxx_kp_exit(void) +{ + platform_driver_unregister(&pmic8xxx_kp_driver); +} +module_exit(pmic8xxx_kp_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("PMIC8XXX keypad driver"); +MODULE_VERSION("1.0"); +MODULE_ALIAS("platform:pmic8xxx_keypad"); +MODULE_AUTHOR("Trilok Soni "); -- cgit v1.2.3 From 92d57a73e41047bff7d0812e06f893567876d455 Mon Sep 17 00:00:00 2001 From: Trilok Soni Date: Fri, 13 May 2011 15:17:51 +0530 Subject: input: Add support for Qualcomm PMIC8XXX power key Add support for PMIC8XXX power key driven over dedicated KYPD_PWR_N pin. Acked-by: Dmitry Torokhov Signed-off-by: Trilok Soni Signed-off-by: Anirudh Ghayal Signed-off-by: Samuel Ortiz --- drivers/input/misc/Kconfig | 11 ++ drivers/input/misc/Makefile | 1 + drivers/input/misc/pmic8xxx-pwrkey.c | 231 +++++++++++++++++++++++++++++++++++ 3 files changed, 243 insertions(+) create mode 100644 drivers/input/misc/pmic8xxx-pwrkey.c (limited to 'drivers') diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index f9cf0881b0e3..45dc6aa62ba4 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -330,6 +330,17 @@ config INPUT_PWM_BEEPER To compile this driver as a module, choose M here: the module will be called pwm-beeper. +config INPUT_PMIC8XXX_PWRKEY + tristate "PMIC8XXX power key support" + depends on MFD_PM8XXX + help + Say Y here if you want support for the PMIC8XXX power key. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called pmic8xxx-pwrkey. + config INPUT_GPIO_ROTARY_ENCODER tristate "Rotary encoders connected to GPIO pins" depends on GPIOLIB && GENERIC_GPIO diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index e3f7984e6274..38efb2cb182b 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o obj-$(CONFIG_INPUT_POWERMATE) += powermate.o obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o +obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c new file mode 100644 index 000000000000..97e07e786e41 --- /dev/null +++ b/drivers/input/misc/pmic8xxx-pwrkey.c @@ -0,0 +1,231 @@ +/* Copyright (c) 2010-2011, Code Aurora Forum. 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 version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define PON_CNTL_1 0x1C +#define PON_CNTL_PULL_UP BIT(7) +#define PON_CNTL_TRIG_DELAY_MASK (0x7) + +/** + * struct pmic8xxx_pwrkey - pmic8xxx pwrkey information + * @key_press_irq: key press irq number + */ +struct pmic8xxx_pwrkey { + struct input_dev *pwr; + int key_press_irq; +}; + +static irqreturn_t pwrkey_press_irq(int irq, void *_pwrkey) +{ + struct pmic8xxx_pwrkey *pwrkey = _pwrkey; + + input_report_key(pwrkey->pwr, KEY_POWER, 1); + input_sync(pwrkey->pwr); + + return IRQ_HANDLED; +} + +static irqreturn_t pwrkey_release_irq(int irq, void *_pwrkey) +{ + struct pmic8xxx_pwrkey *pwrkey = _pwrkey; + + input_report_key(pwrkey->pwr, KEY_POWER, 0); + input_sync(pwrkey->pwr); + + return IRQ_HANDLED; +} + +#ifdef CONFIG_PM_SLEEP +static int pmic8xxx_pwrkey_suspend(struct device *dev) +{ + struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(pwrkey->key_press_irq); + + return 0; +} + +static int pmic8xxx_pwrkey_resume(struct device *dev) +{ + struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(pwrkey->key_press_irq); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops, + pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume); + +static int __devinit pmic8xxx_pwrkey_probe(struct platform_device *pdev) +{ + struct input_dev *pwr; + int key_release_irq = platform_get_irq(pdev, 0); + int key_press_irq = platform_get_irq(pdev, 1); + int err; + unsigned int delay; + u8 pon_cntl; + struct pmic8xxx_pwrkey *pwrkey; + const struct pm8xxx_pwrkey_platform_data *pdata = mfd_get_data(pdev); + + if (!pdata) { + dev_err(&pdev->dev, "power key platform data not supplied\n"); + return -EINVAL; + } + + if (pdata->kpd_trigger_delay_us > 62500) { + dev_err(&pdev->dev, "invalid power key trigger delay\n"); + return -EINVAL; + } + + pwrkey = kzalloc(sizeof(*pwrkey), GFP_KERNEL); + if (!pwrkey) + return -ENOMEM; + + pwr = input_allocate_device(); + if (!pwr) { + dev_dbg(&pdev->dev, "Can't allocate power button\n"); + err = -ENOMEM; + goto free_pwrkey; + } + + input_set_capability(pwr, EV_KEY, KEY_POWER); + + pwr->name = "pmic8xxx_pwrkey"; + pwr->phys = "pmic8xxx_pwrkey/input0"; + pwr->dev.parent = &pdev->dev; + + delay = (pdata->kpd_trigger_delay_us << 10) / USEC_PER_SEC; + delay = 1 + ilog2(delay); + + err = pm8xxx_readb(pdev->dev.parent, PON_CNTL_1, &pon_cntl); + if (err < 0) { + dev_err(&pdev->dev, "failed reading PON_CNTL_1 err=%d\n", err); + goto free_input_dev; + } + + pon_cntl &= ~PON_CNTL_TRIG_DELAY_MASK; + pon_cntl |= (delay & PON_CNTL_TRIG_DELAY_MASK); + if (pdata->pull_up) + pon_cntl |= PON_CNTL_PULL_UP; + else + pon_cntl &= ~PON_CNTL_PULL_UP; + + err = pm8xxx_writeb(pdev->dev.parent, PON_CNTL_1, pon_cntl); + if (err < 0) { + dev_err(&pdev->dev, "failed writing PON_CNTL_1 err=%d\n", err); + goto free_input_dev; + } + + err = input_register_device(pwr); + if (err) { + dev_dbg(&pdev->dev, "Can't register power key: %d\n", err); + goto free_input_dev; + } + + pwrkey->key_press_irq = key_press_irq; + pwrkey->pwr = pwr; + + platform_set_drvdata(pdev, pwrkey); + + err = request_irq(key_press_irq, pwrkey_press_irq, + IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_press", pwrkey); + if (err < 0) { + dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n", + key_press_irq, err); + goto unreg_input_dev; + } + + err = request_irq(key_release_irq, pwrkey_release_irq, + IRQF_TRIGGER_RISING, "pmic8xxx_pwrkey_release", pwrkey); + if (err < 0) { + dev_dbg(&pdev->dev, "Can't get %d IRQ for pwrkey: %d\n", + key_release_irq, err); + + goto free_press_irq; + } + + device_init_wakeup(&pdev->dev, pdata->wakeup); + + return 0; + +free_press_irq: + free_irq(key_press_irq, NULL); +unreg_input_dev: + platform_set_drvdata(pdev, NULL); + input_unregister_device(pwr); + pwr = NULL; +free_input_dev: + input_free_device(pwr); +free_pwrkey: + kfree(pwrkey); + return err; +} + +static int __devexit pmic8xxx_pwrkey_remove(struct platform_device *pdev) +{ + struct pmic8xxx_pwrkey *pwrkey = platform_get_drvdata(pdev); + int key_release_irq = platform_get_irq(pdev, 0); + int key_press_irq = platform_get_irq(pdev, 1); + + device_init_wakeup(&pdev->dev, 0); + + free_irq(key_press_irq, pwrkey); + free_irq(key_release_irq, pwrkey); + input_unregister_device(pwrkey->pwr); + platform_set_drvdata(pdev, NULL); + kfree(pwrkey); + + return 0; +} + +static struct platform_driver pmic8xxx_pwrkey_driver = { + .probe = pmic8xxx_pwrkey_probe, + .remove = __devexit_p(pmic8xxx_pwrkey_remove), + .driver = { + .name = PM8XXX_PWRKEY_DEV_NAME, + .owner = THIS_MODULE, + .pm = &pm8xxx_pwr_key_pm_ops, + }, +}; + +static int __init pmic8xxx_pwrkey_init(void) +{ + return platform_driver_register(&pmic8xxx_pwrkey_driver); +} +module_init(pmic8xxx_pwrkey_init); + +static void __exit pmic8xxx_pwrkey_exit(void) +{ + platform_driver_unregister(&pmic8xxx_pwrkey_driver); +} +module_exit(pmic8xxx_pwrkey_exit); + +MODULE_ALIAS("platform:pmic8xxx_pwrkey"); +MODULE_DESCRIPTION("PMIC8XXX Power Key driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Trilok Soni "); -- cgit v1.2.3 From 099691081df40d8863cb2fb01ee64039633892dd Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 26 May 2011 10:16:15 -0700 Subject: regulator: Fix 88pm8607.c printk format warning Fix printk format warning (seen on x86_64) and change to unsigned output format: drivers/regulator/88pm8607.c:417: warning: format '%d' expects type 'int', but argument 3 has type 'resource_size_t' Signed-off-by: Randy Dunlap Acked-by: Mark Brown Signed-off-by: Samuel Ortiz --- drivers/regulator/88pm8607.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index 1904be9149af..d63fddb0fbb0 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -413,8 +413,8 @@ static int __devinit pm8607_regulator_probe(struct platform_device *pdev) break; } if ((i < 0) || (i > PM8607_ID_RG_MAX)) { - dev_err(&pdev->dev, "Failed to find regulator %d\n", - res->start); + dev_err(&pdev->dev, "Failed to find regulator %llu\n", + (unsigned long long)res->start); return -EINVAL; } info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion; -- cgit v1.2.3