diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2020-10-30 17:34:01 +0300 |
---|---|---|
committer | Sebastian Reichel <sebastian.reichel@collabora.com> | 2020-11-30 04:18:49 +0300 |
commit | ba940ed83218f034f728184439c7e87795237752 (patch) | |
tree | ced7faf0a94f9b1f11cc90c3ee2f69c99d49709d | |
parent | b2f6cb78eaa1cad57dd3fe11d0458cd4fae9a584 (diff) | |
download | linux-ba940ed83218f034f728184439c7e87795237752.tar.xz |
power: supply: collie_battery: Convert to GPIO descriptors
This converts the Collie battery driver to use GPIO descriptors.
We use a mixture of 3 GPIOs defined in the machine and 3
GPIOs requested directly from the ucb1x00 chip.
Cc: Robert Jarzmik <robert.jarzmik@free.fr>
Cc: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
-rw-r--r-- | arch/arm/mach-sa1100/collie.c | 21 | ||||
-rw-r--r-- | drivers/power/supply/collie_battery.c | 151 |
2 files changed, 130 insertions, 42 deletions
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c index bd3a52fd09ce..d4e89a02c8c8 100644 --- a/arch/arm/mach-sa1100/collie.c +++ b/arch/arm/mach-sa1100/collie.c @@ -98,6 +98,26 @@ static struct mcp_plat_data collie_mcp_data = { .codec_pdata = &collie_ucb1x00_data, }; +/* Battery management GPIOs */ +static struct gpiod_lookup_table collie_battery_gpiod_table = { + /* the MCP codec mcp0 has the ucb1x00 as attached device */ + .dev_id = "ucb1x00", + .table = { + /* This is found on the main GPIO on the SA1100 */ + GPIO_LOOKUP("gpio", COLLIE_GPIO_CO, + "main battery full", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio", COLLIE_GPIO_MAIN_BAT_LOW, + "main battery low", GPIO_ACTIVE_HIGH), + /* + * This is GPIO 0 on the Scoop expander, which is registered + * from common/scoop.c with this gpio chip label. + */ + GPIO_LOOKUP("sharp-scoop", 0, + "main charge on", GPIO_ACTIVE_HIGH), + { }, + }, +}; + static int collie_ir_startup(struct device *dev) { int rc = gpio_request(COLLIE_GPIO_IR_ON, "IrDA"); @@ -395,6 +415,7 @@ static void __init collie_init(void) platform_scoop_config = &collie_pcmcia_config; gpiod_add_lookup_table(&collie_power_gpiod_table); + gpiod_add_lookup_table(&collie_battery_gpiod_table); ret = platform_add_devices(devices, ARRAY_SIZE(devices)); if (ret) { diff --git a/drivers/power/supply/collie_battery.c b/drivers/power/supply/collie_battery.c index cbd588e9e233..7fb9b549f2de 100644 --- a/drivers/power/supply/collie_battery.c +++ b/drivers/power/supply/collie_battery.c @@ -12,7 +12,9 @@ #include <linux/delay.h> #include <linux/spinlock.h> #include <linux/interrupt.h> -#include <linux/gpio.h> +#include <linux/gpio/driver.h> +#include <linux/gpio/machine.h> +#include <linux/gpio/consumer.h> #include <linux/mfd/ucb1x00.h> #include <asm/mach/sharpsl_param.h> @@ -31,18 +33,18 @@ struct collie_bat { struct mutex work_lock; /* protects data */ bool (*is_present)(struct collie_bat *bat); - int gpio_full; - int gpio_charge_on; + struct gpio_desc *gpio_full; + struct gpio_desc *gpio_charge_on; int technology; - int gpio_bat; + struct gpio_desc *gpio_bat; int adc_bat; int adc_bat_divider; int bat_max; int bat_min; - int gpio_temp; + struct gpio_desc *gpio_temp; int adc_temp; int adc_temp_divider; }; @@ -53,15 +55,15 @@ static unsigned long collie_read_bat(struct collie_bat *bat) { unsigned long value = 0; - if (bat->gpio_bat < 0 || bat->adc_bat < 0) + if (!bat->gpio_bat || bat->adc_bat < 0) return 0; mutex_lock(&bat_lock); - gpio_set_value(bat->gpio_bat, 1); + gpiod_set_value(bat->gpio_bat, 1); msleep(5); ucb1x00_adc_enable(ucb); value = ucb1x00_adc_read(ucb, bat->adc_bat, UCB_SYNC); ucb1x00_adc_disable(ucb); - gpio_set_value(bat->gpio_bat, 0); + gpiod_set_value(bat->gpio_bat, 0); mutex_unlock(&bat_lock); value = value * 1000000 / bat->adc_bat_divider; @@ -71,16 +73,16 @@ static unsigned long collie_read_bat(struct collie_bat *bat) static unsigned long collie_read_temp(struct collie_bat *bat) { unsigned long value = 0; - if (bat->gpio_temp < 0 || bat->adc_temp < 0) + if (!bat->gpio_temp || bat->adc_temp < 0) return 0; mutex_lock(&bat_lock); - gpio_set_value(bat->gpio_temp, 1); + gpiod_set_value(bat->gpio_temp, 1); msleep(5); ucb1x00_adc_enable(ucb); value = ucb1x00_adc_read(ucb, bat->adc_temp, UCB_SYNC); ucb1x00_adc_disable(ucb); - gpio_set_value(bat->gpio_temp, 0); + gpiod_set_value(bat->gpio_temp, 0); mutex_unlock(&bat_lock); value = value * 10000 / bat->adc_temp_divider; @@ -162,23 +164,23 @@ static void collie_bat_update(struct collie_bat *bat) bat->full_chrg = -1; } else if (power_supply_am_i_supplied(psy)) { if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING) { - gpio_set_value(bat->gpio_charge_on, 1); + gpiod_set_value(bat->gpio_charge_on, 1); mdelay(15); } - if (gpio_get_value(bat->gpio_full)) { + if (gpiod_get_value(bat->gpio_full)) { if (old == POWER_SUPPLY_STATUS_CHARGING || bat->full_chrg == -1) bat->full_chrg = collie_read_bat(bat); - gpio_set_value(bat->gpio_charge_on, 0); + gpiod_set_value(bat->gpio_charge_on, 0); bat->status = POWER_SUPPLY_STATUS_FULL; } else { - gpio_set_value(bat->gpio_charge_on, 1); + gpiod_set_value(bat->gpio_charge_on, 1); bat->status = POWER_SUPPLY_STATUS_CHARGING; } } else { - gpio_set_value(bat->gpio_charge_on, 0); + gpiod_set_value(bat->gpio_charge_on, 0); bat->status = POWER_SUPPLY_STATUS_DISCHARGING; } @@ -230,18 +232,18 @@ static struct collie_bat collie_bat_main = { .full_chrg = -1, .psy = NULL, - .gpio_full = COLLIE_GPIO_CO, - .gpio_charge_on = COLLIE_GPIO_CHARGE_ON, + .gpio_full = NULL, + .gpio_charge_on = NULL, .technology = POWER_SUPPLY_TECHNOLOGY_LIPO, - .gpio_bat = COLLIE_GPIO_MBAT_ON, + .gpio_bat = NULL, .adc_bat = UCB_ADC_INP_AD1, .adc_bat_divider = 155, .bat_max = 4310000, .bat_min = 1551 * 1000000 / 414, - .gpio_temp = COLLIE_GPIO_TMP_ON, + .gpio_temp = NULL, .adc_temp = UCB_ADC_INP_AD0, .adc_temp_divider = 10000, }; @@ -260,30 +262,24 @@ static struct collie_bat collie_bat_bu = { .full_chrg = -1, .psy = NULL, - .gpio_full = -1, - .gpio_charge_on = -1, + .gpio_full = NULL, + .gpio_charge_on = NULL, .technology = POWER_SUPPLY_TECHNOLOGY_LiMn, - .gpio_bat = COLLIE_GPIO_BBAT_ON, + .gpio_bat = NULL, .adc_bat = UCB_ADC_INP_AD1, .adc_bat_divider = 155, .bat_max = 3000000, .bat_min = 1900000, - .gpio_temp = -1, + .gpio_temp = NULL, .adc_temp = -1, .adc_temp_divider = -1, }; -static struct gpio collie_batt_gpios[] = { - { COLLIE_GPIO_CO, GPIOF_IN, "main battery full" }, - { COLLIE_GPIO_MAIN_BAT_LOW, GPIOF_IN, "main battery low" }, - { COLLIE_GPIO_CHARGE_ON, GPIOF_OUT_INIT_LOW, "main charge on" }, - { COLLIE_GPIO_MBAT_ON, GPIOF_OUT_INIT_LOW, "main battery" }, - { COLLIE_GPIO_TMP_ON, GPIOF_OUT_INIT_LOW, "main battery temp" }, - { COLLIE_GPIO_BBAT_ON, GPIOF_OUT_INIT_LOW, "backup battery" }, -}; +/* Obtained but unused GPIO */ +static struct gpio_desc *collie_mbat_low; #ifdef CONFIG_PM static int wakeup_enabled; @@ -295,7 +291,7 @@ static int collie_bat_suspend(struct ucb1x00_dev *dev) if (device_may_wakeup(&dev->ucb->dev) && collie_bat_main.status == POWER_SUPPLY_STATUS_CHARGING) - wakeup_enabled = !enable_irq_wake(gpio_to_irq(COLLIE_GPIO_CO)); + wakeup_enabled = !enable_irq_wake(gpiod_to_irq(collie_bat_main.gpio_full)); else wakeup_enabled = 0; @@ -305,7 +301,7 @@ static int collie_bat_suspend(struct ucb1x00_dev *dev) static int collie_bat_resume(struct ucb1x00_dev *dev) { if (wakeup_enabled) - disable_irq_wake(gpio_to_irq(COLLIE_GPIO_CO)); + disable_irq_wake(gpiod_to_irq(collie_bat_main.gpio_full)); /* things may have changed while we were away */ schedule_work(&bat_work); @@ -320,16 +316,71 @@ static int collie_bat_probe(struct ucb1x00_dev *dev) { int ret; struct power_supply_config psy_main_cfg = {}, psy_bu_cfg = {}; + struct gpio_chip *gc = &dev->ucb->gpio; if (!machine_is_collie()) return -ENODEV; ucb = dev->ucb; - ret = gpio_request_array(collie_batt_gpios, - ARRAY_SIZE(collie_batt_gpios)); - if (ret) - return ret; + /* Obtain all the main battery GPIOs */ + collie_bat_main.gpio_full = gpiod_get(&dev->ucb->dev, + "main battery full", + GPIOD_IN); + if (IS_ERR(collie_bat_main.gpio_full)) + return PTR_ERR(collie_bat_main.gpio_full); + + collie_mbat_low = gpiod_get(&dev->ucb->dev, + "main battery low", + GPIOD_IN); + if (IS_ERR(collie_mbat_low)) { + ret = PTR_ERR(collie_mbat_low); + goto err_put_gpio_full; + } + + collie_bat_main.gpio_charge_on = gpiod_get(&dev->ucb->dev, + "main charge on", + GPIOD_OUT_LOW); + if (IS_ERR(collie_bat_main.gpio_charge_on)) { + ret = PTR_ERR(collie_bat_main.gpio_charge_on); + goto err_put_mbat_low; + } + + /* COLLIE_GPIO_MBAT_ON = GPIO 7 on the UCB (TC35143) */ + collie_bat_main.gpio_bat = gpiochip_request_own_desc(gc, + 7, + "main battery", + GPIO_ACTIVE_HIGH, + GPIOD_OUT_LOW); + if (IS_ERR(collie_bat_main.gpio_bat)) { + ret = PTR_ERR(collie_bat_main.gpio_bat); + goto err_put_gpio_charge_on; + } + + /* COLLIE_GPIO_TMP_ON = GPIO 9 on the UCB (TC35143) */ + collie_bat_main.gpio_temp = gpiochip_request_own_desc(gc, + 9, + "main battery temp", + GPIO_ACTIVE_HIGH, + GPIOD_OUT_LOW); + if (IS_ERR(collie_bat_main.gpio_temp)) { + ret = PTR_ERR(collie_bat_main.gpio_temp); + goto err_free_gpio_bat; + } + + /* + * Obtain the backup battery COLLIE_GPIO_BBAT_ON which is + * GPIO 8 on the UCB (TC35143) + */ + collie_bat_bu.gpio_bat = gpiochip_request_own_desc(gc, + 8, + "backup battery", + GPIO_ACTIVE_HIGH, + GPIOD_OUT_LOW); + if (IS_ERR(collie_bat_bu.gpio_bat)) { + ret = PTR_ERR(collie_bat_bu.gpio_bat); + goto err_free_gpio_temp; + } mutex_init(&collie_bat_main.work_lock); @@ -370,27 +421,43 @@ err_irq: err_psy_reg_bu: power_supply_unregister(collie_bat_main.psy); err_psy_reg_main: - /* see comment in collie_bat_remove */ cancel_work_sync(&bat_work); - gpio_free_array(collie_batt_gpios, ARRAY_SIZE(collie_batt_gpios)); + gpiochip_free_own_desc(collie_bat_bu.gpio_bat); +err_free_gpio_temp: + gpiochip_free_own_desc(collie_bat_main.gpio_temp); +err_free_gpio_bat: + gpiochip_free_own_desc(collie_bat_main.gpio_bat); +err_put_gpio_charge_on: + gpiod_put(collie_bat_main.gpio_charge_on); +err_put_mbat_low: + gpiod_put(collie_mbat_low); +err_put_gpio_full: + gpiod_put(collie_bat_main.gpio_full); + return ret; } static void collie_bat_remove(struct ucb1x00_dev *dev) { free_irq(gpio_to_irq(COLLIE_GPIO_CO), &collie_bat_main); - power_supply_unregister(collie_bat_bu.psy); power_supply_unregister(collie_bat_main.psy); + /* These are obtained from the machine */ + gpiod_put(collie_bat_main.gpio_full); + gpiod_put(collie_mbat_low); + gpiod_put(collie_bat_main.gpio_charge_on); + /* These are directly from the UCB so let's free them */ + gpiochip_free_own_desc(collie_bat_main.gpio_bat); + gpiochip_free_own_desc(collie_bat_main.gpio_temp); + gpiochip_free_own_desc(collie_bat_bu.gpio_bat); /* * Now cancel the bat_work. We won't get any more schedules, * since all sources (isr and external_power_changed) are * unregistered now. */ cancel_work_sync(&bat_work); - gpio_free_array(collie_batt_gpios, ARRAY_SIZE(collie_batt_gpios)); } static struct ucb1x00_driver collie_bat_driver = { |