On Thu, Dec 04, 2008 at 03:55:06PM +0530, ext [EMAIL PROTECTED] wrote:
> From: Manikandan Pillai <[EMAIL PROTECTED]>
>
> Resending this patch with comments fixed :
> This patch moves the TPS6235x drivers from the drivers/i2c to drivers/
> regulator to put the TPS6235x drivers under the power regulator framework
>
> suffix core_pwr and mpu_pwr has been removed
> I2C bus speeds replaced with numbers again
> Camel case has been removed
> TPS moved into regulator framework and drivers/i2c/chips left untouched.
>
> Not fixed comments:
> Not clear on how to implement runtime check for PR785 and would require some
> inputs on implementing the same.
This patch should be broken into smaller pieces.
The tps driver should come separated, drivers/regulator/core.c should go
to the maintainer in a separate patch, i2c-omap.c adding the i2c4
support, should be in a separate patch and Ccing Ben Dooks and Jean
Delvare.
More comments below.
> Signed-off-by: Manikandan Pillai <[EMAIL PROTECTED]>
> ---
> arch/arm/mach-omap2/board-omap3evm.c | 6 +-
> arch/arm/plat-omap/devices.c | 78 +++++
> arch/arm/plat-omap/i2c.c | 21 +-
> drivers/i2c/busses/i2c-omap.c | 154 +++++++++-
> drivers/i2c/chips/Kconfig | 23 ++
> drivers/regulator/Kconfig | 7 +
> drivers/regulator/Makefile | 1 +
> drivers/regulator/core.c | 27 --
> drivers/regulator/tps6235x-regulator.c | 544
> ++++++++++++++++++++++++++++++++
> include/linux/regulator/driver.h | 23 ++-
> 10 files changed, 848 insertions(+), 36 deletions(-)
> create mode 100644 drivers/regulator/tps6235x-regulator.c
>
> diff --git a/arch/arm/mach-omap2/board-omap3evm.c
> b/arch/arm/mach-omap2/board-omap3evm.c
> index 22ac2e9..ab3070d 100644
> --- a/arch/arm/mach-omap2/board-omap3evm.c
> +++ b/arch/arm/mach-omap2/board-omap3evm.c
> @@ -168,7 +168,7 @@ static struct i2c_board_info __initdata
> tps_6235x_i2c_board_info[] = {
>
> static int __init omap3_evm_i2c_init(void)
> {
> -#if defined(CONFIG_PR785)
> +#if defined(CONFIG_PR785) && defined(CONFIG_TPS6235X_I2C2)
> omap_register_i2c_bus(1, 2600, tps_6235x_i2c_board_info,
> ARRAY_SIZE(tps_6235x_i2c_board_info));
> #endif
> @@ -178,6 +178,10 @@ static int __init omap3_evm_i2c_init(void)
> #endif
> omap_register_i2c_bus(2, 400, NULL, 0);
> omap_register_i2c_bus(3, 400, NULL, 0);
> +#if defined(CONFIG_PR785) && defined(CONFIG_TPS6235X_I2C4)
> + omap_register_i2c_bus(4, 2600, tps_6235x_i2c_board_info,
> + ARRAY_SIZE(tps_6235x_i2c_board_info));
> +#endif
heh, i thought bus4 wasn't sw controllable :-s
> return 0;
> }
>
> diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
> index 25c6d10..4c81eaf 100644
> --- a/arch/arm/plat-omap/devices.c
> +++ b/arch/arm/plat-omap/devices.c
> @@ -27,6 +27,7 @@
> #include <mach/gpio.h>
> #include <mach/dsp_common.h>
> #include <mach/mcbsp.h>
> +#include <linux/regulator/machine.h>
>
> #if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
>
> @@ -350,6 +351,83 @@ static void omap_init_rng(void)
> static inline void omap_init_rng(void) {}
> #endif
>
> +/*-------------------------------------------------------------------------*/
> +#if defined(CONFIG_PR785) || defined(CONFIG_PR785_MODULE)
> +
> +static struct regulator_init_data tps_regulator_data[];
> +
> +static struct resource tps6235x_resources[] = {
> + {
> + .flags = IORESOURCE_MEM,
> + },
> +};
this is not the correct place for it as only one board has this driver.
Move it to the proper board-file.
> +
> +static struct platform_device omap_tps6235x_device[] = {
> + {
> + .name = "tps6235x_reg",
> + .id = 2,
> + .num_resources = ARRAY_SIZE(tps6235x_resources),
> + .resource = tps6235x_resources,
> + .dev = {
> + .platform_data = &tps_regulator_data[0],
> + },
> + },
> + {
> + .name = "tps6235x_reg",
> + .id = 3,
> + .num_resources = ARRAY_SIZE(tps6235x_resources),
> + .resource = tps6235x_resources,
> + .dev = {
> + .platform_data = &tps_regulator_data[1],
> + },
> + },
> +};
> +
> +static struct regulator_consumer_supply tps6235x_consumers[] = {
> + {
> + .dev = &omap_tps6235x_device[0].dev,
> + .supply = "tps62352",
> + },
> + {
> + .dev = &omap_tps6235x_device[1].dev,
> + .supply = "tps62353",
supply should be Vdd, or Vbus or something more useful, not the chip's
name.
> + },
> +};
> +
> +static struct regulator_init_data tps_regulator_data[] = {
> + {
> + .constraints = {
> + .min_uV = 750000,
> + .max_uV = 1537000,
> + .valid_ops_mask = (REGULATOR_CHANGE_VOLTAGE |
> + REGULATOR_CHANGE_STATUS),
> + },
> + .num_consumer_supplies = 1,
> + .consumer_supplies = &tps6235x_consumers[0],
> + },
> + {
> + .constraints = {
> + .min_uV = 750000,
> + .max_uV = 1537000,
> + .valid_ops_mask = (REGULATOR_CHANGE_VOLTAGE |
> + REGULATOR_CHANGE_STATUS),
> + },
> + .num_consumer_supplies = 1,
> + .consumer_supplies = &tps6235x_consumers[1],
> + },
> +
> +};
> +
> +static void omap_init_pr785(void)
> +{
> + (void) platform_device_register(&omap_tps6235x_device[0]);
> + (void) platform_device_register(&omap_tps6235x_device[1]);
> +}
> +#else
> +static inline void omap_init_pr785(void) {}
> +#endif
> +/*-------------------------------------------------------------------------*/
> +
> /*
> * This gets called after board-specific INIT_MACHINE, and initializes most
> * on-chip peripherals accessible on this board (except for few like USB):
> diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c
> index 89a6ab0..e0c763a 100644
> --- a/arch/arm/plat-omap/i2c.c
> +++ b/arch/arm/plat-omap/i2c.c
> @@ -35,6 +35,7 @@
> #define OMAP2_I2C_BASE3 0x48060000
>
> static const char name[] = "i2c_omap";
> +static const char name4[] = "i2c4_omap";
>
> #define I2C_RESOURCE_BUILDER(base, irq) \
> { \
> @@ -54,6 +55,7 @@ static struct resource i2c_resources[][2] = {
> #endif
> #if defined(CONFIG_ARCH_OMAP34XX)
> { I2C_RESOURCE_BUILDER(OMAP2_I2C_BASE3, INT_34XX_I2C3_IRQ) },
> + { I2C_RESOURCE_BUILDER(0x0, 0x0) },
> #endif
> };
>
> @@ -68,6 +70,17 @@ static struct resource i2c_resources[][2] = {
> }, \
> }
>
> +#define I2C_DEV_BUILDER4(bus_id, res, data) \
> + { \
> + .id = (bus_id), \
> + .name = name4, \
> + .num_resources = ARRAY_SIZE(res), \
> + .resource = (res), \
> + .dev = { \
> + .platform_data = (data), \
> + }, \
> + }
> +
> static u32 i2c_rate[ARRAY_SIZE(i2c_resources)];
> static struct platform_device omap_i2c_devices[] = {
> I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_rate[0]),
> @@ -76,6 +89,7 @@ static struct platform_device omap_i2c_devices[] = {
> #endif
> #if defined(CONFIG_ARCH_OMAP34XX)
> I2C_DEV_BUILDER(3, i2c_resources[2], &i2c_rate[2]),
> + I2C_DEV_BUILDER4(4, i2c_resources[3], &i2c_rate[3]),
> #endif
> };
>
> @@ -132,7 +146,8 @@ int __init omap_register_i2c_bus(int bus_id, u32 clkrate,
> else if (cpu_is_omap24xx())
> ports = 2;
> else if (cpu_is_omap34xx())
> - ports = 3;
> + /* There are 4 I2C controller on OMAP3 */
> + ports = 4;
>
> BUG_ON(bus_id < 1 || bus_id > ports);
>
> @@ -141,7 +156,6 @@ int __init omap_register_i2c_bus(int bus_id, u32 clkrate,
> if (err)
> return err;
> }
> -
> pdev = &omap_i2c_devices[bus_id - 1];
> *(u32 *)pdev->dev.platform_data = clkrate;
>
> @@ -159,6 +173,7 @@ int __init omap_register_i2c_bus(int bus_id, u32 clkrate,
> res[1].start = irq;
> }
>
> - omap_i2c_mux_pins(bus_id - 1);
> + if (bus_id != 4)
> + omap_i2c_mux_pins(bus_id - 1);
> return platform_device_register(pdev);
> }
> diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
> index 96f3bed..bf8dd1e 100644
> --- a/drivers/i2c/busses/i2c-omap.c
> +++ b/drivers/i2c/busses/i2c-omap.c
> @@ -157,6 +157,13 @@
> #define SYSC_CLOCKACTIVITY_FCLK 0x2
>
>
> +/* I2C4 Programming interface register address */
> +#define OMAP_I2C4_PRM_VC_BYPASS_VAL (IO_ADDRESS(0x4830723C))
> +#define OMAP_I2C4_PRM_SLAVE_ADDR_MSK (0x7F)
> +#define OMAP_I2C4_PRM_REG_SHIFT (8)
> +#define OMAP_I2C4_PRM_DATA_SHIFT (16)
> +#define OMAP_I2C4_PRM_VALID_MSK (1<<24)
> +
> struct omap_i2c_dev {
> struct device *dev;
> void __iomem *base; /* virtual */
> @@ -524,7 +531,6 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
> return -EIO;
> }
>
> -
> /*
> * Prepare controller for a transaction and call omap_i2c_xfer_msg
> * to do the work during IRQ processing.
> @@ -561,6 +567,70 @@ omap_i2c_func(struct i2c_adapter *adap)
> return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
> }
>
> +/*
> + * I2C4 is a special I2C controller unlike I2C1, I2C2 and I2C3.
> + * Prepare controller for a transaction and write into appropriate
> + * registers for transferring data. Only writes are supported on I2C4.
> + */
> +static int omap_i2c4_xfer_msg(struct i2c_adapter *adap,
> + struct i2c_msg *msg, int stop)
> +{
> + struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
> + unsigned int r;
> + unsigned char *cptr;
> + unsigned char regval, dataval;
> +
> + dev_dbg(dev->dev, "I2C4:addr: 0x%04x, len: %d,flags: 0x%x,stop: %d\n",
> + msg->addr, msg->len, msg->flags, stop);
> +
> + if (msg->len == 0)
> + return -EINVAL;
> +
> + dev->buf_len = msg->len;
> +
> + cptr = msg->buf;
> + regval = *cptr;
> + cptr++;
> + dataval = *cptr;
> +
> + r = (((msg->addr) & OMAP_I2C4_PRM_SLAVE_ADDR_MSK) |
> + (regval << OMAP_I2C4_PRM_REG_SHIFT) |
> + (dataval << OMAP_I2C4_PRM_DATA_SHIFT) |
> + OMAP_I2C4_PRM_VALID_MSK);
> +
> + regval = *(volatile unsigned int *)OMAP_I2C4_PRM_VC_BYPASS_VAL;
> +
> + while (regval & OMAP_I2C4_PRM_VALID_MSK)
> + regval = *(volatile unsigned int *)OMAP_I2C4_PRM_VC_BYPASS_VAL;
> +
> + *(volatile unsigned int *)OMAP_I2C4_PRM_VC_BYPASS_VAL = r;
> + return 0;
> +}
> +
> +/*
> + * I2C4 is a special I2C controller unlike I2C1, I2C2 and I2C3.
> + * Prepare controller for a transaction and call omap_i2c4_xfer_msg
> + * to do the work during IRQ processing.
> + * Only writes are supported on I2C4.
> + */
> +static int
> +omap_i2c4_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
> +{
> + int i;
> + int r;
> +
> + for (i = 0; i < num; i++) {
> + r = omap_i2c4_xfer_msg(adap, &msgs[i], (i == (num - 1)));
> + if (r != 0)
> + break;
> + }
> +
> + if (r == 0)
> + return num;
> + return r;
> +}
> +
> +
> static inline void
> omap_i2c_complete_cmd(struct omap_i2c_dev *dev, u16 err)
> {
> @@ -761,6 +831,11 @@ omap_i2c_isr(int this_irq, void *dev_id)
> return count ? IRQ_HANDLED : IRQ_NONE;
> }
>
> +static const struct i2c_algorithm omap_i2c4_algo = {
> + .master_xfer = omap_i2c4_xfer,
> + .functionality = omap_i2c_func,
> +};
> +
> static const struct i2c_algorithm omap_i2c_algo = {
> .master_xfer = omap_i2c_xfer,
> .functionality = omap_i2c_func,
> @@ -839,8 +914,8 @@ omap_i2c_probe(struct platform_device *pdev)
> */
> dev->fifo_size = (dev->fifo_size / 2);
> dev->b_hw = 1; /* Enable hardware fixes */
> - }
>
> + }
> /* reset ASAP, clearing any IRQs */
> omap_i2c_init(dev);
>
> @@ -856,13 +931,14 @@ omap_i2c_probe(struct platform_device *pdev)
> pdev->id, dev->rev >> 4, dev->rev & 0xf, dev->speed);
>
> omap_i2c_idle(dev);
> -
> adap = &dev->adapter;
> i2c_set_adapdata(adap, dev);
> adap->owner = THIS_MODULE;
> adap->class = I2C_CLASS_HWMON;
> strncpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
> + /* if BusId is 1-3 then algorithm is omap_i2c_algo */
> adap->algo = &omap_i2c_algo;
> +
> adap->dev.parent = &pdev->dev;
>
> /* i2c device drivers may be active on return from add_adapter() */
> @@ -911,6 +987,61 @@ omap_i2c_remove(struct platform_device *pdev)
> return 0;
> }
>
> +static int __init
> +omap_i2c4_probe(struct platform_device *pdev)
> +{
> + struct omap_i2c_dev *dev;
> + struct i2c_adapter *adap;
> + int r = 0;
> + u32 *speed = NULL;
> +
> + dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL);
> + if (!dev)
> + r = -ENOMEM;
> +
> + if (pdev->dev.platform_data != NULL)
> + speed = (u32 *) pdev->dev.platform_data;
> + else
> + *speed = 100; /* Defualt speed */
> +
> + dev->speed = *speed;
> + dev->idle = 1;
> + dev->dev = &pdev->dev;
> +
> + platform_set_drvdata(pdev, dev);
> +
> + r = omap_i2c_get_clocks(dev);
> +
> + adap = &dev->adapter;
> + i2c_set_adapdata(adap, dev);
> + adap->owner = THIS_MODULE;
> + adap->class = I2C_CLASS_HWMON;
> + strncpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
> + /* BusId is 4(I2C4) then algorithm is different */
> + adap->algo = &omap_i2c4_algo;
> +
> + adap->dev.parent = &pdev->dev;
> +
> + /* i2c device drivers may be active on return from add_adapter() */
> + adap->nr = pdev->id;
> + r = i2c_add_numbered_adapter(adap);
> + if (r)
> + dev_err(dev->dev, "failure adding adapter\n");
> +
> + return r;
> +}
> +
> +static int
> +omap_i2c4_remove(struct platform_device *pdev)
> +{
> + struct omap_i2c_dev *dev = platform_get_drvdata(pdev);
> + platform_set_drvdata(pdev, NULL);
> + i2c_del_adapter(&dev->adapter);
> + kfree(dev);
> + return 0;
> +}
> +
> +
> static struct platform_driver omap_i2c_driver = {
> .probe = omap_i2c_probe,
> .remove = omap_i2c_remove,
> @@ -920,17 +1051,32 @@ static struct platform_driver omap_i2c_driver = {
> },
> };
>
> +static struct platform_driver omap_i2c4_driver = {
> + .probe = omap_i2c4_probe,
> + .remove = omap_i2c4_remove,
> + .driver = {
> + .name = "i2c4_omap",
> + .owner = THIS_MODULE,
> + },
> +};
> +
> +
> /* I2C may be needed to bring up other drivers */
> static int __init
> omap_i2c_init_driver(void)
> {
> - return platform_driver_register(&omap_i2c_driver);
> + int ret = 0;
> + ret = platform_driver_register(&omap_i2c_driver);
> + ret = platform_driver_register(&omap_i2c4_driver);
> +
> + return ret;
> }
> subsys_initcall(omap_i2c_init_driver);
>
> static void __exit omap_i2c_exit_driver(void)
> {
> platform_driver_unregister(&omap_i2c_driver);
> + platform_driver_unregister(&omap_i2c4_driver);
> }
> module_exit(omap_i2c_exit_driver);
>
> diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
> index d61589b..5702520 100644
> --- a/drivers/i2c/chips/Kconfig
> +++ b/drivers/i2c/chips/Kconfig
> @@ -194,6 +194,29 @@ config SENSORS_MAX6875
> This driver can also be built as a module. If so, the module
> will be called max6875.
>
> +choice
> + prompt "TPS6235X driver support"
> + depends on I2C=y && PR785=y
> + default n
> + help
> + nothing.
> +
> + config TPS6235X_I2C2
> + bool "TPS6235X_I2C2"
> + help
> + Say yes here if you have TPS6235x devices connected to I2C Bus2
> + on PR785 Power module. Note that while selecting this option,
> + TPS6235X_I2C4 should not be selected.
> +
> + config TPS6235X_I2C4
> + bool "TPS6235X_I2C4"
> + help
> + Say yes here if you have TPS6235x devices connected to I2C Bus4
> + on PR785 Power module. Note that while selecting this option,
> + TPS6235X_I2C2 should not be selected.
> +
> +endchoice
> +
> config SENSORS_TSL2550
> tristate "Taos TSL2550 ambient light sensor"
> depends on EXPERIMENTAL
> diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
> index 0765389..6a827e5 100644
> --- a/drivers/regulator/Kconfig
> +++ b/drivers/regulator/Kconfig
> @@ -80,4 +80,11 @@ config REGULATOR_DA903X
> Say y here to support the BUCKs and LDOs regulators found on
> Dialog Semiconductor DA9030/DA9034 PMIC.
>
> +config REGULATOR_TPS6235X
> + bool "TPS6235X Power regulator for OMAP3EVM"
> + depends on PR785
> + help
> + This driver supports the voltage regulators provided by TPS6235x
> chips.
> + The TPS62352 and TPS62353 are mounted on PR785 Power module card for
> + providing voltage regulator functions.
> endif
> diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
> index 0dacb18..fdc5f5b 100644
> --- a/drivers/regulator/Makefile
> +++ b/drivers/regulator/Makefile
> @@ -12,5 +12,6 @@ obj-$(CONFIG_REGULATOR_TWL4030) += twl4030-regulator.o
> obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
> obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
> obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
> +obj-$(CONFIG_REGULATOR_TPS6235X)+= tps6235x-regulator.o
>
> ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
> diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
> index 02a7744..901f402 100644
> --- a/drivers/regulator/core.c
> +++ b/drivers/regulator/core.c
> @@ -30,33 +30,6 @@ static LIST_HEAD(regulator_list);
> static LIST_HEAD(regulator_map_list);
>
> /**
> - * struct regulator_dev
> - *
> - * Voltage / Current regulator class device. One for each regulator.
> - */
> -struct regulator_dev {
> - struct regulator_desc *desc;
> - int use_count;
> -
> - /* lists we belong to */
> - struct list_head list; /* list of all regulators */
> - struct list_head slist; /* list of supplied regulators */
> -
> - /* lists we own */
> - struct list_head consumer_list; /* consumers we supply */
> - struct list_head supply_list; /* regulators we supply */
> -
> - struct blocking_notifier_head notifier;
> - struct mutex mutex; /* consumer lock */
> - struct module *owner;
> - struct device dev;
> - struct regulation_constraints *constraints;
> - struct regulator_dev *supply; /* for tree */
> -
> - void *reg_data; /* regulator_dev data */
> -};
> -
> -/**
> * struct regulator_map
> *
> * Used to provide symbolic supply names to devices.
> diff --git a/drivers/regulator/tps6235x-regulator.c
> b/drivers/regulator/tps6235x-regulator.c
> new file mode 100644
> index 0000000..8a900db
> --- /dev/null
> +++ b/drivers/regulator/tps6235x-regulator.c
> @@ -0,0 +1,544 @@
> +/*
> + * tps6235x-regulator.c -- support regulators in tps6235x family chips
> + *
> + * Copyright (C) 2008 David Brownell
> + * Author : Manikandan Pillai<[EMAIL PROTECTED]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/err.h>
> +#include <linux/platform_device.h>
> +#include <linux/regulator/driver.h>
> +#include <linux/regulator/machine.h>
> +#include <linux/i2c.h>
> +#include <linux/delay.h>
> +#include <linux/regulator/consumer.h>
> +
> +/* Minimum and Maximum dc-dc voltage supported by the TPS6235x devices
> +All voltages given in millivolts */
> +#define PR785_MIN_CORE_VOLT 750
> +#define PR785_MAX_CORE_VOLT 1537
> +#define PR785_MIN_MPU_VOLT 750
> +#define PR785_MAX_MPU_VOLT 1537
> +
> +/* Maximum number of bytes to be read in a single read */
> +#define PR785_RETRY_COUNT 0x3
> +
> +/* Register bit settings */
> +#define TPS6235X_EN_DCDC (0x1 << 0x7)
> +#define TPS6235X_VSM_MSK (0x3F)
> +#define TPS6235X_EN_SYN_MSK (0x1 << 0x5)
> +#define TPS6235X_SW_VOLT_MSK (0x1 << 0x4)
> +#define TPS6235X_PWR_OK_MSK (0x1 << 0x5)
> +#define TPS6235X_OUT_DIS_MSK (0x1 << 0x6)
> +#define TPS6235X_GO_MSK (0x1 << 0x7)
> +
> +/*
> + * These chips are often used in OMAP-based systems.
> + *
> + * This driver implements software-based resource control for various
> + * voltage regulators. This is usually augmented with state machine
> + * based control.
> + */
> +struct tps_6235x_info {
> + unsigned int state;
> + unsigned int tps_i2c_addr;
> + struct i2c_client *client;
> + struct device *i2c_dev;
> + /* platform data holder */
> + void *pdata;
> +};
> +
> +static struct tps_6235x_info tps_6235x_infodata[2];
> +
> +
> +#ifndef REGULATOR_MODE_OFF
> +#define REGULATOR_MODE_OFF 0
> +#endif
> +
> +
> +/* LDO control registers ... offset is from the base of its register bank.
> + * The first three registers of all power resource banks help hardware to
> + * manage the various resource groups.
> + */
> +
> +#define TPS6235X_REG_VSEL0 0
> +#define TPS6235X_REG_VSEL1 1
> +#define TPS6235X_REG_CTRL1 2
> +#define TPS6235X_REG_CTRL2 3
> +#define TPS6235X_REG_MAX TPS6235X_REG_CTRL2
> +
> +#define MODULE_NAME "tps6235x_power"
> +
> +/* Debug functions */
> +#ifdef DEBUG
> +
> +#define dump_reg(client, reg, val) \
> + do { \
> + tps6235x_read_reg(client, reg, &val); \
> + dev_dbg(&(client)->dev, "Reg(0x%.2X): 0x%.2X\n", reg, val); \
> + } while (0)
> +
> +#endif /* #ifdef DEBUG */
> +
> +/* Device addresses for PR785 card */
> +#define PR785_62352_CORE_ADDR 0x4A
> +#define PR785_62353_MPU_ADDR 0x48
> +
> +/* Minimum and Maximum dc-dc voltage supported by the TPS6235x devices
> +All voltages given in millivolts */
> +#define PR785_MIN_CORE_VOLT 750
> +#define PR785_MAX_CORE_VOLT 1537
> +#define PR785_MIN_MPU_VOLT 750
> +#define PR785_MAX_MPU_VOLT 1537
> +
> +/* Maximum number of bytes to be read in a single read */
> +#define PR785_RETRY_COUNT 0x3
> +
> +/* Register bit settings */
> +#define TPS6235X_EN_DCDC (0x1 << 0x7)
> +#define TPS6235X_VSM_MSK (0x3F)
> +#define TPS6235X_EN_SYN_MSK (0x1 << 0x5)
> +#define TPS6235X_SW_VOLT_MSK (0x1 << 0x4)
> +#define TPS6235X_PWR_OK_MSK (0x1 << 0x5)
> +#define TPS6235X_OUT_DIS_MSK (0x1 << 0x6)
> +#define TPS6235X_GO_MSK (0x1 << 0x7)
> +
> +int pr785_enbl_dcdc(unsigned char tps_mod_type, unsigned int en_flag);
> +int pr785_get_dcdc_volt(unsigned char tps_mod_type, unsigned int
> *millivolts);
> +int pr785_set_dcdc_volt(unsigned char tps_mod_type, unsigned int millivolts);
> +
> +static int tps6235x_dcdc_is_enabled(struct regulator_dev *dev)
> +{
> + struct tps_6235x_info *tps_info =
> + (struct tps_6235x_info *)dev->reg_data;
> + return tps_info->state;
> +}
> +
> +static int tps6235x_dcdc_enable(struct regulator_dev *dev)
> +{
> + struct tps_6235x_info *tps_info =
> + (struct tps_6235x_info *)dev->reg_data;
> +
> + tps_info->state = 1;
> + return pr785_enbl_dcdc(tps_info->tps_i2c_addr, 1);
> +}
> +
> +static int tps6235x_dcdc_disable(struct regulator_dev *dev)
> +{
> + struct tps_6235x_info *tps_info =
> + (struct tps_6235x_info *)dev->reg_data;
> +
> + tps_info->state = 0;
> + return pr785_enbl_dcdc(tps_info->tps_i2c_addr, 0);
> +}
> +
> +static int tps6235x_dcdc_get_voltage(struct regulator_dev *dev)
> +{
> + struct tps_6235x_info *tps_info =
> + (struct tps_6235x_info *)dev->reg_data;
> + unsigned int millivolts;
> +
> + pr785_get_dcdc_volt(tps_info->tps_i2c_addr, &millivolts);
> + return millivolts * 1000;
> +}
> +
> +static int tps6235x_dcdc_set_voltage(struct regulator_dev *dev,
> + int min_uV, int max_uV)
> +{
> + struct tps_6235x_info *tps_info =
> + (struct tps_6235x_info *)dev->reg_data;
> + unsigned int millivolts = max_uV / 1000;
> +
> + return pr785_set_dcdc_volt(tps_info->tps_i2c_addr, millivolts) ;
> +}
> +
> +
> +static struct regulator_ops tps62352_dcdc_ops = {
> + .is_enabled = tps6235x_dcdc_is_enabled,
> + .get_voltage = tps6235x_dcdc_get_voltage,
> + .set_voltage = tps6235x_dcdc_set_voltage,
> +};
> +
> +static struct regulator_ops tps62353_dcdc_ops = {
> + .is_enabled = tps6235x_dcdc_is_enabled,
> + .enable = tps6235x_dcdc_enable,
> + .disable = tps6235x_dcdc_disable,
> + .get_voltage = tps6235x_dcdc_get_voltage,
> + .set_voltage = tps6235x_dcdc_set_voltage,
> +};
> +
> +
> +static struct regulator_desc regulators[] = {
> + {
> + .name = "tps62352",
> + .id = 2,
> + .ops = &tps62352_dcdc_ops,
> + .type = REGULATOR_VOLTAGE,
> + .owner = THIS_MODULE,
> + },
> + {
> + .name = "tps62353",
> + .id = 3,
> + .ops = &tps62353_dcdc_ops,
> + .type = REGULATOR_VOLTAGE,
> + .owner = THIS_MODULE,
> + },
> +};
> +
> +static int tps6235xreg_probe(struct platform_device *pdev)
> +{
> + struct tps_6235x_info *info;
> + struct regulator_dev *rdev = NULL;
> +
> + info = &tps_6235x_infodata[(pdev->id-2)];
> +
> + rdev = regulator_register(®ulators[(pdev->id-2)], &pdev->dev, info);
> + if (rdev == NULL)
> + printk(KERN_ERR "err in regulator registry = %d\n", pdev->id);
> +
> + platform_set_drvdata(pdev, rdev);
> +
> + return 0;
> +}
> +
> +static int __devexit tps6235xreg_remove(struct platform_device *pdev)
> +{
> + regulator_unregister(platform_get_drvdata(pdev));
> + return 0;
> +}
> +
> +MODULE_ALIAS("platform:tps6235x_reg");
> +
> +static struct platform_driver tps6235xreg_driver = {
> + .probe = tps6235xreg_probe,
> + .remove = __devexit_p(tps6235xreg_remove),
> + .driver.name = "tps6235x_reg",
> + .driver.owner = THIS_MODULE,
> +};
> +
> +static int __init tps6235xreg_init(void)
> +{
> + return platform_driver_register(&tps6235xreg_driver);
> +}
> +late_initcall(tps6235xreg_init);
> +
> +static void __exit tps6235xreg_exit(void)
> +{
> + platform_driver_unregister(&tps6235xreg_driver);
> +}
> +module_exit(tps6235xreg_exit)
> +
> +MODULE_DESCRIPTION("TPS6235X regulator driver");
> +MODULE_LICENSE("GPL");
> +
> +
> +/*
> + * Get client pointer for a particular device
> + * Returns zero if successful, or non-zero otherwise.
> + */
> +static struct i2c_client *tps_6235x_get_client(unsigned char tps_i2c_addr)
> +{
> + if (tps_i2c_addr == PR785_62352_CORE_ADDR)
> + return tps_6235x_infodata[0].client;
> + else if (tps_i2c_addr == PR785_62353_MPU_ADDR)
> + return tps_6235x_infodata[1].client;
> + else
> + return NULL;
> +}
> +
> +/*
> + * Read a value from a register in an tps_6235x device.
> + * The value is returned in 'val'.
> + * Returns zero if successful, or non-zero otherwise.
> + */
> +static int tps_6235x_read_reg(struct i2c_client *client, u8 reg, u8 *val)
> +{
> + u8 data;
> +
> + if (!client->adapter)
> + return -ENODEV;
> +
> + data = i2c_smbus_read_byte_data(client, reg);
> + *val = data;
> + return 0;
> +}
> +
> +/*
> + * Write a value to a register in an tps_6235x device.
> + * Returns zero if successful, or non-zero otherwise.
> + */
> +static int tps_6235x_write_reg(struct i2c_client *client, u8 reg, u8 val)
> +{
> + int err;
> + int retry = 0;
> +
> + if (!client->adapter)
> + return -ENODEV;
> +
> +again:
> + err = i2c_smbus_write_byte_data(client, reg, val);
> + if (err >= 0)
> + return 0;
> +
> + dev_err(&client->dev,
> + "wrote 0x%.2x to offset 0x%.2x error %d\n", val, reg, err);
> +
> + if (retry <= PR785_RETRY_COUNT) {
> + dev_info(&client->dev, "retry ... %d\n", retry);
> + retry++;
> + schedule_timeout(msecs_to_jiffies(20));
> + goto again;
> + }
> + return err;
> +}
> +
> +
> +/**
> +* pwr_i2c_read - Allows the caller to read one register from TPS device
> +* based on the address given. For the PR785 it reads
> +* only 1 byte into a specified register
> +* tps_mod_type - Enum for the device to be read
> +* reg - Register to be read from(value has to be between 0-3
> +* val - value read from the reg
> +* Retval - 0 -> Success else non-zero
> +**/
> +int pwr_i2c_read(unsigned char tps_mod_type, u8 reg, u8 *val)
> +{
> + struct i2c_client *client;
> +
> + client = tps_6235x_get_client(tps_mod_type);
> + /* check if register is less than <= 3 Register is 0 -3 */
> + if (reg > TPS6235X_REG_MAX)
> + return -1;
> +
> + return tps_6235x_read_reg(client, reg, val);
> +}
> +EXPORT_SYMBOL(pwr_i2c_read);
> +
> +/**
> +* pwr_i2c_write - Allows the caller to write one register from TPS device
> +* based on the address given. For the PR785 it writes
> +* only 1 byte into a specified register
> +* tps_mod_type - Enum for the device to be written
> +* reg - Register to be written to(value has to be between 0-3
> +* val - value to be written to reg
> +* Retval - 0 -> Success else non-zero
> +**/
> +int pwr_i2c_write(unsigned char tps_mod_type, u8 reg, u8 val)
> +{
> + struct i2c_client *client;
> +
> + client = tps_6235x_get_client(tps_mod_type);
> +
> + /* check if register is less than <= 3 Register is 0 -3 */
> + if (reg > TPS6235X_REG_MAX)
> + return -1;
> +
> + return tps_6235x_write_reg(client, reg, val);
> +}
> +EXPORT_SYMBOL(pwr_i2c_write);
> +
> +
> +/**
> +* TPSPR785 - Specific functions
> +* pr785_enbl_dcdc - Allows the caller to enable or disable the TPS6235x
> device
> +* on the PR785 board. The voltage for PR785 is selected by
> +* VSEL1 register since VSEL pin is kept high
> +*
> +* flag - 1 == enable 0 == disable
> +* Retval - 0 -> Success else non-zero
> +**/
> +int pr785_enbl_dcdc(unsigned char tps_mod_type, unsigned int en_flag)
> +{
> + unsigned char vsel1;
> + int ret;
> +
> + ret = pwr_i2c_read(tps_mod_type, TPS6235X_REG_VSEL1, &vsel1);
> + if (ret == 0) {
> + if (en_flag)
> + vsel1 |= TPS6235X_EN_DCDC;
> + else
> + vsel1 &= ~(TPS6235X_EN_DCDC);
> + ret = pwr_i2c_write(tps_mod_type, TPS6235X_REG_VSEL1, vsel1);
> + }
> + return ret;
> +}
> +EXPORT_SYMBOL(pr785_enbl_dcdc);
> +
> +/**
> +* TPSPR785 - Specific functions
> +* pr785_set_dcdc_volt - Allows the caller to set a particular voltage on
> +* for CORE or MPU
> +*
> +* voltage - voltage to be set in millivolts (75--1537)
> +* Retval - 0 -> Success else non-zero
> +**/
> +int pr785_set_dcdc_volt(unsigned char tps_mod_type, unsigned int millivolts)
> +{
> + unsigned char vsel1;
> + unsigned int volt;
> +
> + /* check if the millivolts is within range */
> + if ((millivolts < PR785_MIN_CORE_VOLT) ||
> + (millivolts > PR785_MAX_CORE_VOLT))
> + return -1;
> +
> + /* Output voltage set is = min_op_volt + ( VSM * 12.5mv) */
> + volt = millivolts - PR785_MIN_CORE_VOLT;
> + volt /= 25;
> + volt *= 2;
> + vsel1 = ((TPS6235X_EN_DCDC) | (volt & TPS6235X_VSM_MSK));
> + return pwr_i2c_write(tps_mod_type, TPS6235X_REG_VSEL1, vsel1);
> +}
> +EXPORT_SYMBOL(pr785_set_dcdc_volt);
> +
> +/**
> +* TPSPR785 - Specific functions
> +* pr785_get_dcdc_volt - Allows the caller to get the set voltage on a
> +* particular TPS 6235x device on PR785 card
> +*
> +* voltage - voltage to be set in millivolts (75--1537)
> +* Retval - 0 -> Success else non-zero
> +**/
> +int pr785_get_dcdc_volt(unsigned char tps_mod_type, unsigned int *millivolts)
> +{
> + unsigned char vsel1;
> + unsigned int volt;
> +
> + /* Read the VSEL1 register to get VSM */
> + pwr_i2c_read(tps_mod_type, TPS6235X_REG_VSEL1, &vsel1);
> + /* Output voltage set is = min_op_volt + ( VSM * 12.5mv) */
> + /* To cut out floating point operation we will multiply by 25
> + divide by 2 */
> + volt = (((vsel1 & TPS6235X_VSM_MSK) * 25) / 2) + PR785_MIN_CORE_VOLT;
> + *millivolts = volt;
> + return 0;
> +}
> +EXPORT_SYMBOL(pr785_get_dcdc_volt);
> +
> +/**
> + * tps_6235x_probe - TPS6235x driver i2c probe handler
> + * @client: i2c driver client device structure
> + *
> + * Register PR785 as an i2c client device driver
> + */
> +static struct i2c_driver tps_6235x_i2c_driver;
> +
> +static
> +int tps_6235x_probe(struct i2c_client *client, const struct i2c_device_id
> *id)
> +{
> + unsigned char reg_val;
> +
> + printk(KERN_INFO "tps_6235x_probe:i2c_addr = %x\n", (int)client->addr);
> +
> + /* Device probed is TPS62352 CORE pwr chip if driver_data = 0
> + Device probed is TPS62353 MPU pwr chip if driver_data = 1 */
> + tps_6235x_infodata[id->driver_data].client = client;
> + tps_6235x_infodata[id->driver_data].tps_i2c_addr = client->addr;
> + tps_6235x_infodata[id->driver_data].state = 1;
> + tps_6235x_infodata[id->driver_data].i2c_dev = &client->dev;
> +
> + tps_6235x_read_reg(client, TPS6235X_REG_CTRL2, ®_val);
> + reg_val |= (TPS6235X_OUT_DIS_MSK | TPS6235X_GO_MSK);
> + tps_6235x_write_reg(client, TPS6235X_REG_CTRL2, reg_val);
> + tps_6235x_read_reg(client, TPS6235X_REG_CTRL2, ®_val);
> +
> + i2c_set_clientdata(client, &tps_6235x_infodata[id->driver_data]);
> +
> + if (reg_val & TPS6235X_PWR_OK_MSK)
> + printk(KERN_INFO "Power is OK %x\n", reg_val);
> + else
> + printk(KERN_INFO "Power not within range = %x\n", reg_val);
> + return 0;
> +}
> +
> +/**
> + * tps_6235x_remove - TPS6235x driver i2c remove handler
> + * @client: i2c driver client device structure
> + *
> + * UnregisterPR785 as an i2c client device driver
> + */
> +static int __exit tps_6235x_remove(struct i2c_client *client)
> +{
> +#ifdef DEBUG
> + printk(KERN_INFO "tps_6235x_remove invoked\n");
> +#endif
> +
> + if (!client->adapter)
> + return -ENODEV; /* our client isn't attached */
> +
> + i2c_set_clientdata(client, NULL);
> +
> + return 0;
> +}
> +
> +
> +static const struct i2c_device_id tps_6235x_id[] = {
> + { "tps62352", 0},
> + { "tps62353", 1},
> + {},
> +};
> +
> +MODULE_DEVICE_TABLE(i2c, tps_6235x_id);
> +
> +static struct i2c_driver tps_6235x_i2c_driver = {
> + .driver = {
> + .name = MODULE_NAME,
> + .owner = THIS_MODULE,
> + },
> + .probe = tps_6235x_probe,
> + .remove = __exit_p(tps_6235x_remove),
> + .id_table = tps_6235x_id,
> +};
> +
> +/**
> + * tps_6235x_init
> + *
> + * Module init function
> + */
> +static int __init tps_6235x_init(void)
> +{
> + int err;
> +
> +#ifdef DEBUG
> + printk(KERN_INFO "tps_6235x_init invoked\n");
> +#endif
> +
> + err = i2c_add_driver(&tps_6235x_i2c_driver);
> + if (err) {
> + printk(KERN_ERR "Failed to register " MODULE_NAME ".\n");
> + return err;
> + } else
> + printk(KERN_INFO "I2c driver registered\n");
> +
> + return 0;
> +}
> +
> +/**
> + * tps_6235x_cleanup
> + *
> + * Module exit function
> + */
> +static void __exit tps_6235x_cleanup(void)
> +{
> +#ifdef DEBUG
> + printk(KERN_INFO "tps_6235x_cleanup invoked\n");
> +#endif
> + i2c_del_driver(&tps_6235x_i2c_driver);
> +}
> +
> +late_initcall(tps_6235x_init);
> +module_exit(tps_6235x_cleanup);
> +
> +MODULE_AUTHOR("Texas Instruments");
> +MODULE_DESCRIPTION("TPS6235x based PR785 linux driver");
> +MODULE_LICENSE("GPL");
> +
> diff --git a/include/linux/regulator/driver.h
> b/include/linux/regulator/driver.h
> index e37d805..9107344 100644
> --- a/include/linux/regulator/driver.h
> +++ b/include/linux/regulator/driver.h
> @@ -18,9 +18,30 @@
> #include <linux/device.h>
> #include <linux/regulator/consumer.h>
>
> -struct regulator_dev;
> struct regulator_init_data;
>
> +struct regulator_dev {
> + struct regulator_desc *desc;
> + int use_count;
> +
> + /* lists we belong to */
> + struct list_head list; /* list of all regulators */
> + struct list_head slist; /* list of supplied regulators */
> +
> + /* lists we own */
> + struct list_head consumer_list; /* consumers we supply */
> + struct list_head supply_list; /* regulators we supply */
> +
> + struct blocking_notifier_head notifier;
> + struct mutex mutex; /* consumer lock */
> + struct module *owner;
> + struct device dev;
> + struct regulation_constraints *constraints;
> + struct regulator_dev *supply; /* for tree */
> +
> + void *reg_data; /* regulator_dev data */
> +};
> +
> /**
> * struct regulator_ops - regulator operations.
> *
> --
> 1.5.6
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to [EMAIL PROTECTED]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
balbi
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html