diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig index 5b1edbae6893..4b6a774606cb 100644 --- a/arch/arm/mach-omap1/Kconfig +++ b/arch/arm/mach-omap1/Kconfig @@ -157,6 +157,8 @@ config MACH_AMS_DELTA select FIQ select GPIO_GENERIC_PLATFORM select LEDS_GPIO_REGISTER + select REGULATOR + select REGULATOR_FIXED_VOLTAGE help Support for the Amstrad E3 (codename Delta) videophone. Say Y here if you have such a device. diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c index ce50fe137269..949997c35707 100644 --- a/arch/arm/mach-omap1/board-ams-delta.c +++ b/arch/arm/mach-omap1/board-ams-delta.c @@ -18,7 +18,11 @@ #include #include #include +#include #include +#include +#include +#include #include #include @@ -236,11 +240,6 @@ static const struct gpio latch_gpios[] __initconst = { .flags = GPIOF_OUT_INIT_LOW, .label = "scard_cmdvcc", }, - { - .gpio = AMS_DELTA_GPIO_PIN_MODEM_NRESET, - .flags = GPIOF_OUT_INIT_LOW, - .label = "modem_nreset", - }, { .gpio = AMS_DELTA_GPIO_PIN_MODEM_CODEC, .flags = GPIOF_OUT_INIT_LOW, @@ -258,6 +257,71 @@ static const struct gpio latch_gpios[] __initconst = { }, }; +static struct regulator_consumer_supply modem_nreset_consumers[] = { + REGULATOR_SUPPLY("RESET#", "serial8250.1"), + REGULATOR_SUPPLY("POR", "cx20442-codec"), +}; + +static struct regulator_init_data modem_nreset_data = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(modem_nreset_consumers), + .consumer_supplies = modem_nreset_consumers, +}; + +static struct fixed_voltage_config modem_nreset_config = { + .supply_name = "modem_nreset", + .microvolts = 3300000, + .gpio = AMS_DELTA_GPIO_PIN_MODEM_NRESET, + .startup_delay = 25000, + .enable_high = 1, + .enabled_at_boot = 1, + .init_data = &modem_nreset_data, +}; + +static struct platform_device modem_nreset_device = { + .name = "reg-fixed-voltage", + .id = -1, + .dev = { + .platform_data = &modem_nreset_config, + }, +}; + +struct modem_private_data { + struct regulator *regulator; + struct { + struct mutex lock; + bool enabled; + } consumer; +}; + +static int regulator_toggle(struct modem_private_data *priv, bool enable) +{ + int err = 0; + + mutex_lock(&priv->consumer.lock); + if (IS_ERR(priv->regulator)) { + err = PTR_ERR(priv->regulator); + } else if (enable) { + if (!priv->consumer.enabled) { + err = regulator_enable(priv->regulator); + priv->consumer.enabled = true; + } + } else { + if (priv->consumer.enabled) { + err = regulator_disable(priv->regulator); + priv->consumer.enabled = false; + } + } + mutex_unlock(&priv->consumer.lock); + + return err; +} + +static struct modem_private_data modem_priv; + void ams_delta_latch_write(int base, int ngpio, u16 mask, u16 value) { int bit = 0; @@ -266,7 +330,10 @@ void ams_delta_latch_write(int base, int ngpio, u16 mask, u16 value) for (; bit < ngpio; bit++, bitpos = bitpos << 1) { if (!(mask & bitpos)) continue; - gpio_set_value(base + bit, (value & bitpos) != 0); + else if (base + bit == AMS_DELTA_GPIO_PIN_MODEM_NRESET) + regulator_toggle(&modem_priv, (value & bitpos) != 0); + else + gpio_set_value(base + bit, (value & bitpos) != 0); } } EXPORT_SYMBOL(ams_delta_latch_write); @@ -496,6 +563,12 @@ static int __init late_init(void) platform_add_devices(late_devices, ARRAY_SIZE(late_devices)); + err = platform_device_register(&modem_nreset_device); + if (err) { + pr_err("Couldn't register the modem regulator device\n"); + return err; + } + omap_cfg_reg(M14_1510_GPIO2); ams_delta_modem_ports[0].irq = gpio_to_irq(AMS_DELTA_GPIO_PIN_MODEM_IRQ); @@ -507,6 +580,10 @@ static int __init late_init(void) } gpio_direction_input(AMS_DELTA_GPIO_PIN_MODEM_IRQ); + /* Initialize the modem_nreset regulator consumer before use */ + mutex_init(&modem_priv.consumer.lock); + modem_priv.regulator = ERR_PTR(-ENODEV); + ams_delta_latch2_write( AMS_DELTA_LATCH2_MODEM_NRESET | AMS_DELTA_LATCH2_MODEM_CODEC, AMS_DELTA_LATCH2_MODEM_NRESET | AMS_DELTA_LATCH2_MODEM_CODEC); @@ -514,8 +591,23 @@ static int __init late_init(void) err = platform_device_register(&ams_delta_modem_device); if (err) goto gpio_free; + + /* + * Once the modem device is registered, the modem_nreset + * regulator can be requested on behalf of that device. + * The regulator is used via ams_delta_latch_write() + * by the modem and ASoC drivers until updated. + */ + modem_priv.regulator = regulator_get(&ams_delta_modem_device.dev, + "RESET#"); + if (IS_ERR(modem_priv.regulator)) { + err = PTR_ERR(modem_priv.regulator); + goto unregister; + } return 0; +unregister: + platform_device_unregister(&ams_delta_modem_device); gpio_free: gpio_free(AMS_DELTA_GPIO_PIN_MODEM_IRQ); return err;