Hi, Few comments below. * Manikandan Pillai <mani.pillai@xxxxxx> [090113 09:42]: > TPS6235x chip based PR785 power modules are from Texas Instruments > for OMAP3 EVM boards. This patch supports the PR785 card > and provides the driver support for the TPS devices. > > For compilation, the LCD and MMC drivers are modified and will not > work. Further patches will be provided for support of LCD and MMC > with PR785 boards. > > Signed-off-by: Manikandan Pillai <mani.pillai@xxxxxx> > --- > arch/arm/mach-omap2/Kconfig | 11 +++ > arch/arm/mach-omap2/board-omap3evm.c | 137 ++++++++++++++++++++++++++++++++++ > arch/arm/mach-omap2/mmc-twl4030.c | 4 +- > arch/arm/plat-omap/i2c.c | 69 +++++++++++++++++- > drivers/video/omap/lcd_omap3evm.c | 6 ++ > 5 files changed, 225 insertions(+), 2 deletions(-) > > diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig > index 0a86a88..91890be 100644 > --- a/arch/arm/mach-omap2/Kconfig > +++ b/arch/arm/mach-omap2/Kconfig > @@ -121,6 +121,17 @@ config MACH_OMAP3EVM > bool "OMAP 3530 EVM board" > depends on ARCH_OMAP3 && ARCH_OMAP34XX > > +menu "PR785 Power board selection for OMAP3 EVM" > +config OMAP3EVM_PR785 > + bool "Power board for OMAP3 EVM" > + depends on I2C=y && ARCH_OMAP34XX > + help > + Say yes here if you are using the TPS6235x based PR785 Power Module > + for the EVM boards. This core driver provides register access and IRQ > + handling facilities, and registers devices for the various functions > + so that function-specific drivers can bind to them. > +endmenu > + > config MACH_OMAP3_BEAGLE > bool "OMAP3 BEAGLE board" > depends on ARCH_OMAP3 && ARCH_OMAP34XX > diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c > index e4e60e2..60d2d22 100644 > --- a/arch/arm/mach-omap2/board-omap3evm.c > +++ b/arch/arm/mach-omap2/board-omap3evm.c > @@ -36,12 +36,19 @@ > #include <mach/usb-ehci.h> > #include <mach/common.h> > #include <mach/mcspi.h> > +#include <mach/mux.h> > > #include "sdram-micron-mt46h32m32lf-6.h" > #include "twl4030-generic-scripts.h" > #include "mmc-twl4030.h" > +#include <linux/regulator/machine.h> > +#include <linux/regulator/driver.h> > > +#define TPS6235X_REG_MAX 3 > > +#if defined(CONFIG_OMAP3EVM_PR785) && defined(CONFIG_TWL4030_CORE) > +#error config err : only one of OMAP3EVM_PR785 or TWL4030_CORE can be defined > +#endif > static struct resource omap3evm_smc911x_resources[] = { > [0] = { > .start = OMAP3EVM_ETHR_START, > @@ -89,6 +96,7 @@ static struct omap_uart_config omap3_evm_uart_config __initdata = { > .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), > }; > > +#if defined(CONFIG_TWL4030_CORE) > static struct twl4030_gpio_platform_data omap3evm_gpio_data = { > .gpio_base = OMAP_MAX_GPIO_LINES, > .irq_base = TWL4030_GPIO_IRQ_BASE, > @@ -150,16 +158,125 @@ static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = { > .platform_data = &omap3evm_twldata, > }, > }; > +#endif > + > +#if defined(CONFIG_OMAP3EVM_PR785) > +/* CORE voltage regulator */ > +struct regulator_consumer_supply tps62352_core_consumers = { > + .supply = "vdd2", > +}; > + > +/* MPU voltage regulator */ > +struct regulator_consumer_supply tps62352_mpu_consumers = { > + .supply = "vdd1", > +}; > + > +struct regulator_init_data vdd2_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 = &tps62352_core_consumers, > +}; > + > +struct regulator_init_data vdd1_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 = &tps62352_mpu_consumers, > +}; > + > +static struct i2c_board_info __initdata tps_6235x_i2c_board_info[] = { > + { > + I2C_BOARD_INFO("tps62352", 0x4A), > + .flags = I2C_CLIENT_WAKE, > + .platform_data = &vdd2_tps_regulator_data, > + }, > + { > + I2C_BOARD_INFO("tps62353", 0x48), > + .flags = I2C_CLIENT_WAKE, > + .platform_data = &vdd1_tps_regulator_data, > + }, > +}; > +#endif > > static int __init omap3_evm_i2c_init(void) > { > +#if defined(CONFIG_OMAP3EVM_PR785) > + omap_register_i2c_bus(1, 2600, tps_6235x_i2c_board_info, > + ARRAY_SIZE(tps_6235x_i2c_board_info)); > +#endif > +#if defined(CONFIG_TWL4030_CORE) > omap_register_i2c_bus(1, 2600, omap3evm_i2c_boardinfo, > ARRAY_SIZE(omap3evm_i2c_boardinfo)); > +#endif > omap_register_i2c_bus(2, 400, NULL, 0); > omap_register_i2c_bus(3, 400, NULL, 0); > return 0; > } > > +/* > + * 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. > + */ > +int tps_6235x_read_reg(struct i2c_client *client, u8 reg, u8 *val) > +{ > + u8 data; > + > + if (!client->adapter) > + return -ENODEV; > + > + if (reg > TPS6235X_REG_MAX) > + return -1; > + > + 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. > + */ > +int tps_6235x_write_reg(struct i2c_client *client, u8 reg, u8 val) > +{ > + int err; > + int retry = 0; > + > + if (!client->adapter) > + return -ENODEV; > + > + if (reg > TPS6235X_REG_MAX) > + return -1; > + > +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); > + > + /* Try 3 times */ > + if (retry <= 3) { > + dev_info(&client->dev, "retry ... %d\n", retry); > + retry++; > + schedule_timeout(msecs_to_jiffies(20)); > + goto again; > + } > + return err; > +} > + > +/*-------------------------------------------------------------------*/ > + The the read/write_reg should be in drivers/mfd somewhere. > static struct platform_device omap3_evm_lcd_device = { > .name = "omap3evm_lcd", > .id = -1, > @@ -233,6 +350,7 @@ static struct platform_device *omap3_evm_devices[] __initdata = { > &omap3evm_smc911x_device, > }; > > +#if defined(CONFIG_TWL4030_CORE) > static struct twl4030_hsmmc_info mmc[] __initdata = { > { > .mmc = 1, > @@ -242,6 +360,20 @@ static struct twl4030_hsmmc_info mmc[] __initdata = { > }, > {} /* Terminator */ > }; > +#endif > + > +static void omap_init_pr785(void) > +{ > + /* Initialize the mux settings for PR785 power module board */ > + if (cpu_is_omap343x()) { > + omap_cfg_reg(AF26_34XX_GPIO0); > + omap_cfg_reg(AF22_34XX_GPIO9); > + omap_cfg_reg(AF6_34XX_GPIO140_UP); > + omap_cfg_reg(AE6_34XX_GPIO141); > + omap_cfg_reg(AF5_34XX_GPIO142); > + omap_cfg_reg(AE5_34XX_GPIO143); > + } > +} > > static void __init omap3_evm_init(void) > { > @@ -255,7 +387,12 @@ static void __init omap3_evm_init(void) > ARRAY_SIZE(omap3evm_spi_board_info)); > > omap_serial_init(); > +#if defined(CONFIG_TWL4030_CORE) > twl4030_mmc_init(mmc); > +#endif > +#if defined(CONFIG_OMAP3EVM_PR785) > + omap_init_pr785(); > +#endif > usb_musb_init(); > usb_ehci_init(); > omap3evm_flash_init(); > diff --git a/arch/arm/mach-omap2/mmc-twl4030.c b/arch/arm/mach-omap2/mmc-twl4030.c > index 437f520..d907889 100644 > --- a/arch/arm/mach-omap2/mmc-twl4030.c > +++ b/arch/arm/mach-omap2/mmc-twl4030.c > @@ -168,7 +168,7 @@ static int twl_mmc_resume(struct device *dev, int slot) > */ > static int twl_mmc_set_voltage(struct twl_mmc_controller *c, int vdd) > { > - int ret; > + int ret = 0; > u8 vmmc, dev_grp_val; > > switch (1 << vdd) { > @@ -223,6 +223,7 @@ static int twl_mmc_set_voltage(struct twl_mmc_controller *c, int vdd) > else > dev_grp_val = LDO_CLR; /* Power down */ > > +#if defined(CONFIG_TWL4030_CORE) > ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, > dev_grp_val, c->twl_vmmc_dev_grp); > if (ret) > @@ -231,6 +232,7 @@ static int twl_mmc_set_voltage(struct twl_mmc_controller *c, int vdd) > ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, > vmmc, c->twl_mmc_dedicated); > > +#endif > return ret; > } > > diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c > index 89a6ab0..3bc21bb 100644 > --- a/arch/arm/plat-omap/i2c.c > +++ b/arch/arm/plat-omap/i2c.c > @@ -27,6 +27,8 @@ > #include <linux/platform_device.h> > #include <linux/i2c.h> > #include <mach/mux.h> > +#include <linux/string.h> > +#include <linux/regulator/machine.h> > > #define OMAP_I2C_SIZE 0x3f > #define OMAP1_I2C_BASE 0xfffb3800 > @@ -97,6 +99,15 @@ static const int omap34xx_pins[][2] = { > static const int omap34xx_pins[][2] = {}; > #endif > > +#if defined(CONFIG_OMAP3EVM_PR785) > +struct platform_device *vdd2_platform_device; > +struct platform_device *vdd1_platform_device; > +extern struct regulator_init_data vdd2_tps_regulator_data; > +extern struct regulator_init_data vdd1_tps_regulator_data; > +extern struct regulator_consumer_supply tps62352_core_consumers; > +extern struct regulator_consumer_supply tps62352_mpu_consumers; > +#endif > + > static void __init omap_i2c_mux_pins(int bus) > { > int scl, sda; > @@ -118,6 +129,53 @@ static void __init omap_i2c_mux_pins(int bus) > omap_cfg_reg(scl); > } > > +#if defined(CONFIG_OMAP3EVM_PR785) > +/* This is the callback function used to find the correct > + * i2c platform child for the regulator consumer > +*/ > +int omap_i2c_match_child(struct device *dev, void *data) > +{ > + struct regulator_init_data *reg_init_data = dev->platform_data; > + char *name = data; > + > + /* Child does not match */ > + if (strcmp(name, reg_init_data->consumer_supplies->supply)) > + return 0; > + else > + return 1; > +} > + > +int omap_i2c_register_child(struct platform_device *pdev_parent, > + const char *name, struct platform_device **pdev) > +{ > + int ret = 0; > + > + *pdev = platform_device_alloc(name, -1); > + if (pdev == NULL) { > + dev_err(&(*pdev)->dev, "Failed to alloc i2c-child %s\n", name); > + return -1; > + } > + > + (*pdev)->dev.parent = &pdev_parent->dev; > + if (strcmp(name, "vdd2_consumer") == 0) { > + tps62352_core_consumers.dev = &(*pdev)->dev; > + (*pdev)->dev.platform_data = &vdd2_tps_regulator_data; > + } else if (strcmp(name, "vdd1_consumer") == 0) { > + tps62352_mpu_consumers.dev = &(*pdev)->dev; > + (*pdev)->dev.platform_data = &vdd1_tps_regulator_data; > + } > + > + ret = platform_device_add(*pdev); > + if (ret != 0) { > + dev_err(&(*pdev)->dev, "Failed to register %s: %d\n", > + name, ret); > + platform_device_put(*pdev); > + *pdev = NULL; > + } > + return ret; > +} > +#endif > + > int __init omap_register_i2c_bus(int bus_id, u32 clkrate, > struct i2c_board_info const *info, > unsigned len) > @@ -160,5 +218,14 @@ int __init omap_register_i2c_bus(int bus_id, u32 clkrate, > } > > omap_i2c_mux_pins(bus_id - 1); > - return platform_device_register(pdev); > + platform_device_register(pdev); > +#if defined(CONFIG_OMAP3EVM_PR785) > + if (bus_id == 1) { > + omap_i2c_register_child(pdev, "vdd2_consumer", \ > + &vdd2_platform_device); > + omap_i2c_register_child(pdev, "vdd1_consumer", \ > + &vdd1_platform_device); > + } > +#endif > + return 0; > } Argh, i2c-omap.c is the _bus_ driver, not i2c device! Please move the above code to drivers/mfd somewhere. How different tps6235 is from the twl4030? Maybe you can just add functionality to the existing drivers/mfd/twl4030-core.c. > diff --git a/drivers/video/omap/lcd_omap3evm.c b/drivers/video/omap/lcd_omap3evm.c > index 1c3d814..4f373b2 100644 > --- a/drivers/video/omap/lcd_omap3evm.c > +++ b/drivers/video/omap/lcd_omap3evm.c > @@ -66,9 +66,11 @@ static int omap3evm_panel_init(struct lcd_panel *panel, > gpio_direction_output(LCD_PANEL_LR, 1); > gpio_direction_output(LCD_PANEL_UD, 1); > > +#if defined(CONFIG_TWL4030_CORE) > twl4030_i2c_write_u8(TWL4030_MODULE_LED, 0x11, TWL_LED_LEDEN); > twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x01, TWL_PWMA_PWMAON); > twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x02, TWL_PWMA_PWMAOFF); > +#endif > bklight_level = 100; > > return 0; > @@ -97,6 +99,7 @@ static unsigned long omap3evm_panel_get_caps(struct lcd_panel *panel) > static int omap3evm_bklight_setlevel(struct lcd_panel *panel, > unsigned int level) > { > +#if defined(CONFIG_TWL4030_CORE) > u8 c; > if ((level >= 0) && (level <= 100)) { > c = (125 * (100 - level)) / 100 + 2; > @@ -104,6 +107,9 @@ static int omap3evm_bklight_setlevel(struct lcd_panel *panel, > bklight_level = level; > } > return 0; > +#endif > + /* Fix this once patch fix is sent out for TPS-boards */ > + return -1; > } > > static unsigned int omap3evm_bklight_getlevel(struct lcd_panel *panel) Looks like the above needs some more work too. Tony -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html