mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
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>
This commit is contained in:
parent
b2f6cb78ea
commit
ba940ed832
@ -98,6 +98,26 @@ static struct mcp_plat_data collie_mcp_data = {
|
|||||||
.codec_pdata = &collie_ucb1x00_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)
|
static int collie_ir_startup(struct device *dev)
|
||||||
{
|
{
|
||||||
int rc = gpio_request(COLLIE_GPIO_IR_ON, "IrDA");
|
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;
|
platform_scoop_config = &collie_pcmcia_config;
|
||||||
|
|
||||||
gpiod_add_lookup_table(&collie_power_gpiod_table);
|
gpiod_add_lookup_table(&collie_power_gpiod_table);
|
||||||
|
gpiod_add_lookup_table(&collie_battery_gpiod_table);
|
||||||
|
|
||||||
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
|
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -12,7 +12,9 @@
|
|||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/interrupt.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 <linux/mfd/ucb1x00.h>
|
||||||
|
|
||||||
#include <asm/mach/sharpsl_param.h>
|
#include <asm/mach/sharpsl_param.h>
|
||||||
@ -31,18 +33,18 @@ struct collie_bat {
|
|||||||
struct mutex work_lock; /* protects data */
|
struct mutex work_lock; /* protects data */
|
||||||
|
|
||||||
bool (*is_present)(struct collie_bat *bat);
|
bool (*is_present)(struct collie_bat *bat);
|
||||||
int gpio_full;
|
struct gpio_desc *gpio_full;
|
||||||
int gpio_charge_on;
|
struct gpio_desc *gpio_charge_on;
|
||||||
|
|
||||||
int technology;
|
int technology;
|
||||||
|
|
||||||
int gpio_bat;
|
struct gpio_desc *gpio_bat;
|
||||||
int adc_bat;
|
int adc_bat;
|
||||||
int adc_bat_divider;
|
int adc_bat_divider;
|
||||||
int bat_max;
|
int bat_max;
|
||||||
int bat_min;
|
int bat_min;
|
||||||
|
|
||||||
int gpio_temp;
|
struct gpio_desc *gpio_temp;
|
||||||
int adc_temp;
|
int adc_temp;
|
||||||
int adc_temp_divider;
|
int adc_temp_divider;
|
||||||
};
|
};
|
||||||
@ -53,15 +55,15 @@ static unsigned long collie_read_bat(struct collie_bat *bat)
|
|||||||
{
|
{
|
||||||
unsigned long value = 0;
|
unsigned long value = 0;
|
||||||
|
|
||||||
if (bat->gpio_bat < 0 || bat->adc_bat < 0)
|
if (!bat->gpio_bat || bat->adc_bat < 0)
|
||||||
return 0;
|
return 0;
|
||||||
mutex_lock(&bat_lock);
|
mutex_lock(&bat_lock);
|
||||||
gpio_set_value(bat->gpio_bat, 1);
|
gpiod_set_value(bat->gpio_bat, 1);
|
||||||
msleep(5);
|
msleep(5);
|
||||||
ucb1x00_adc_enable(ucb);
|
ucb1x00_adc_enable(ucb);
|
||||||
value = ucb1x00_adc_read(ucb, bat->adc_bat, UCB_SYNC);
|
value = ucb1x00_adc_read(ucb, bat->adc_bat, UCB_SYNC);
|
||||||
ucb1x00_adc_disable(ucb);
|
ucb1x00_adc_disable(ucb);
|
||||||
gpio_set_value(bat->gpio_bat, 0);
|
gpiod_set_value(bat->gpio_bat, 0);
|
||||||
mutex_unlock(&bat_lock);
|
mutex_unlock(&bat_lock);
|
||||||
value = value * 1000000 / bat->adc_bat_divider;
|
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)
|
static unsigned long collie_read_temp(struct collie_bat *bat)
|
||||||
{
|
{
|
||||||
unsigned long value = 0;
|
unsigned long value = 0;
|
||||||
if (bat->gpio_temp < 0 || bat->adc_temp < 0)
|
if (!bat->gpio_temp || bat->adc_temp < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
mutex_lock(&bat_lock);
|
mutex_lock(&bat_lock);
|
||||||
gpio_set_value(bat->gpio_temp, 1);
|
gpiod_set_value(bat->gpio_temp, 1);
|
||||||
msleep(5);
|
msleep(5);
|
||||||
ucb1x00_adc_enable(ucb);
|
ucb1x00_adc_enable(ucb);
|
||||||
value = ucb1x00_adc_read(ucb, bat->adc_temp, UCB_SYNC);
|
value = ucb1x00_adc_read(ucb, bat->adc_temp, UCB_SYNC);
|
||||||
ucb1x00_adc_disable(ucb);
|
ucb1x00_adc_disable(ucb);
|
||||||
gpio_set_value(bat->gpio_temp, 0);
|
gpiod_set_value(bat->gpio_temp, 0);
|
||||||
mutex_unlock(&bat_lock);
|
mutex_unlock(&bat_lock);
|
||||||
|
|
||||||
value = value * 10000 / bat->adc_temp_divider;
|
value = value * 10000 / bat->adc_temp_divider;
|
||||||
@ -162,23 +164,23 @@ static void collie_bat_update(struct collie_bat *bat)
|
|||||||
bat->full_chrg = -1;
|
bat->full_chrg = -1;
|
||||||
} else if (power_supply_am_i_supplied(psy)) {
|
} else if (power_supply_am_i_supplied(psy)) {
|
||||||
if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING) {
|
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);
|
mdelay(15);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gpio_get_value(bat->gpio_full)) {
|
if (gpiod_get_value(bat->gpio_full)) {
|
||||||
if (old == POWER_SUPPLY_STATUS_CHARGING ||
|
if (old == POWER_SUPPLY_STATUS_CHARGING ||
|
||||||
bat->full_chrg == -1)
|
bat->full_chrg == -1)
|
||||||
bat->full_chrg = collie_read_bat(bat);
|
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;
|
bat->status = POWER_SUPPLY_STATUS_FULL;
|
||||||
} else {
|
} else {
|
||||||
gpio_set_value(bat->gpio_charge_on, 1);
|
gpiod_set_value(bat->gpio_charge_on, 1);
|
||||||
bat->status = POWER_SUPPLY_STATUS_CHARGING;
|
bat->status = POWER_SUPPLY_STATUS_CHARGING;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gpio_set_value(bat->gpio_charge_on, 0);
|
gpiod_set_value(bat->gpio_charge_on, 0);
|
||||||
bat->status = POWER_SUPPLY_STATUS_DISCHARGING;
|
bat->status = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,18 +232,18 @@ static struct collie_bat collie_bat_main = {
|
|||||||
.full_chrg = -1,
|
.full_chrg = -1,
|
||||||
.psy = NULL,
|
.psy = NULL,
|
||||||
|
|
||||||
.gpio_full = COLLIE_GPIO_CO,
|
.gpio_full = NULL,
|
||||||
.gpio_charge_on = COLLIE_GPIO_CHARGE_ON,
|
.gpio_charge_on = NULL,
|
||||||
|
|
||||||
.technology = POWER_SUPPLY_TECHNOLOGY_LIPO,
|
.technology = POWER_SUPPLY_TECHNOLOGY_LIPO,
|
||||||
|
|
||||||
.gpio_bat = COLLIE_GPIO_MBAT_ON,
|
.gpio_bat = NULL,
|
||||||
.adc_bat = UCB_ADC_INP_AD1,
|
.adc_bat = UCB_ADC_INP_AD1,
|
||||||
.adc_bat_divider = 155,
|
.adc_bat_divider = 155,
|
||||||
.bat_max = 4310000,
|
.bat_max = 4310000,
|
||||||
.bat_min = 1551 * 1000000 / 414,
|
.bat_min = 1551 * 1000000 / 414,
|
||||||
|
|
||||||
.gpio_temp = COLLIE_GPIO_TMP_ON,
|
.gpio_temp = NULL,
|
||||||
.adc_temp = UCB_ADC_INP_AD0,
|
.adc_temp = UCB_ADC_INP_AD0,
|
||||||
.adc_temp_divider = 10000,
|
.adc_temp_divider = 10000,
|
||||||
};
|
};
|
||||||
@ -260,30 +262,24 @@ static struct collie_bat collie_bat_bu = {
|
|||||||
.full_chrg = -1,
|
.full_chrg = -1,
|
||||||
.psy = NULL,
|
.psy = NULL,
|
||||||
|
|
||||||
.gpio_full = -1,
|
.gpio_full = NULL,
|
||||||
.gpio_charge_on = -1,
|
.gpio_charge_on = NULL,
|
||||||
|
|
||||||
.technology = POWER_SUPPLY_TECHNOLOGY_LiMn,
|
.technology = POWER_SUPPLY_TECHNOLOGY_LiMn,
|
||||||
|
|
||||||
.gpio_bat = COLLIE_GPIO_BBAT_ON,
|
.gpio_bat = NULL,
|
||||||
.adc_bat = UCB_ADC_INP_AD1,
|
.adc_bat = UCB_ADC_INP_AD1,
|
||||||
.adc_bat_divider = 155,
|
.adc_bat_divider = 155,
|
||||||
.bat_max = 3000000,
|
.bat_max = 3000000,
|
||||||
.bat_min = 1900000,
|
.bat_min = 1900000,
|
||||||
|
|
||||||
.gpio_temp = -1,
|
.gpio_temp = NULL,
|
||||||
.adc_temp = -1,
|
.adc_temp = -1,
|
||||||
.adc_temp_divider = -1,
|
.adc_temp_divider = -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct gpio collie_batt_gpios[] = {
|
/* Obtained but unused GPIO */
|
||||||
{ COLLIE_GPIO_CO, GPIOF_IN, "main battery full" },
|
static struct gpio_desc *collie_mbat_low;
|
||||||
{ 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" },
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
static int wakeup_enabled;
|
static int wakeup_enabled;
|
||||||
@ -295,7 +291,7 @@ static int collie_bat_suspend(struct ucb1x00_dev *dev)
|
|||||||
|
|
||||||
if (device_may_wakeup(&dev->ucb->dev) &&
|
if (device_may_wakeup(&dev->ucb->dev) &&
|
||||||
collie_bat_main.status == POWER_SUPPLY_STATUS_CHARGING)
|
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
|
else
|
||||||
wakeup_enabled = 0;
|
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)
|
static int collie_bat_resume(struct ucb1x00_dev *dev)
|
||||||
{
|
{
|
||||||
if (wakeup_enabled)
|
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 */
|
/* things may have changed while we were away */
|
||||||
schedule_work(&bat_work);
|
schedule_work(&bat_work);
|
||||||
@ -320,16 +316,71 @@ static int collie_bat_probe(struct ucb1x00_dev *dev)
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct power_supply_config psy_main_cfg = {}, psy_bu_cfg = {};
|
struct power_supply_config psy_main_cfg = {}, psy_bu_cfg = {};
|
||||||
|
struct gpio_chip *gc = &dev->ucb->gpio;
|
||||||
|
|
||||||
if (!machine_is_collie())
|
if (!machine_is_collie())
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
ucb = dev->ucb;
|
ucb = dev->ucb;
|
||||||
|
|
||||||
ret = gpio_request_array(collie_batt_gpios,
|
/* Obtain all the main battery GPIOs */
|
||||||
ARRAY_SIZE(collie_batt_gpios));
|
collie_bat_main.gpio_full = gpiod_get(&dev->ucb->dev,
|
||||||
if (ret)
|
"main battery full",
|
||||||
return ret;
|
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);
|
mutex_init(&collie_bat_main.work_lock);
|
||||||
|
|
||||||
@ -370,27 +421,43 @@ err_irq:
|
|||||||
err_psy_reg_bu:
|
err_psy_reg_bu:
|
||||||
power_supply_unregister(collie_bat_main.psy);
|
power_supply_unregister(collie_bat_main.psy);
|
||||||
err_psy_reg_main:
|
err_psy_reg_main:
|
||||||
|
|
||||||
/* see comment in collie_bat_remove */
|
/* see comment in collie_bat_remove */
|
||||||
cancel_work_sync(&bat_work);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void collie_bat_remove(struct ucb1x00_dev *dev)
|
static void collie_bat_remove(struct ucb1x00_dev *dev)
|
||||||
{
|
{
|
||||||
free_irq(gpio_to_irq(COLLIE_GPIO_CO), &collie_bat_main);
|
free_irq(gpio_to_irq(COLLIE_GPIO_CO), &collie_bat_main);
|
||||||
|
|
||||||
power_supply_unregister(collie_bat_bu.psy);
|
power_supply_unregister(collie_bat_bu.psy);
|
||||||
power_supply_unregister(collie_bat_main.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,
|
* Now cancel the bat_work. We won't get any more schedules,
|
||||||
* since all sources (isr and external_power_changed) are
|
* since all sources (isr and external_power_changed) are
|
||||||
* unregistered now.
|
* unregistered now.
|
||||||
*/
|
*/
|
||||||
cancel_work_sync(&bat_work);
|
cancel_work_sync(&bat_work);
|
||||||
gpio_free_array(collie_batt_gpios, ARRAY_SIZE(collie_batt_gpios));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ucb1x00_driver collie_bat_driver = {
|
static struct ucb1x00_driver collie_bat_driver = {
|
||||||
|
Loading…
Reference in New Issue
Block a user