power: supply: collie_battery: Convert to GPIO descriptors
authorLinus Walleij <linus.walleij@linaro.org>
Fri, 30 Oct 2020 14:34:01 +0000 (15:34 +0100)
committerSebastian Reichel <sebastian.reichel@collabora.com>
Mon, 30 Nov 2020 01:18:49 +0000 (02:18 +0100)
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>
arch/arm/mach-sa1100/collie.c
drivers/power/supply/collie_battery.c

index bd3a52f..d4e89a0 100644 (file)
@@ -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) {
index cbd588e..7fb9b54 100644 (file)
@@ -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 = {