s3c24xx: iPAQ rx1950 series
Subsystems (3)
cover s3c24xx: iPAQ rx1950 series
This patch series adds more support for iPAQ rx1950 PDA to linux:
1. LEDs driver -- it controls blue, green and red LEDs on rx1950
2. Battery driver -- adds ability to monitor and charge battery. This driver is suitable for H1940 PDA aswell (just need to write some machine specific callbacks and get voltage LUTs)
PATCH 1/3 rx1950: add rx1950 LEDs driver
--- arch/arm/mach-s3c2440/mach-rx1950.c | 6 + drivers/leds/Kconfig | 6 + drivers/leds/Makefile | 1 + drivers/leds/leds-rx1950.c | 206 +++++++++++++++++++++++++++++++++++ 4 files changed, 219 insertions(+), 0 deletions(-) create mode 100644 drivers/leds/leds-rx1950.c
arch/arm/mach-s3c2440/mach-rx1950.c +6 -0
@@ -126,6 +126,11 @@ static struct s3c2410fb_display rx1950_display = { }; +static struct platform_device rx1950_device_leds = { + .name ="rx1950-leds" , + .id =-1 , +}; +static struct s3c2410fb_mach_info rx1950_lcd_cfg = { .displays = &rx1950_display, .num_displays =1 ,
@@ -502,6 +507,7 @@ static struct platform_device *rx1950_devices[] __initdata = { &s3c_device_timer[1 ], &rx1950_backlight, &rx1950_device_gpiokeys, + &rx1950_device_leds, }; static struct clk *rx1950_clocks[] __initdata = {
drivers/leds/Kconfig +6 -0
@@ -102,6 +102,12 @@ config LEDS_H1940 help This option enables support for the LEDs on the h1940. +config LEDS_RX1950 + tristate "LED Support for iPAQ RX1950 device" + depends on MACH_RX1950 + help + This option enables support for the LEDs on the rx1950. + config LEDS_COBALT_QUBE tristate "LED Support for the Cobalt Qube series front LED" depends on MIPS_COBALT
drivers/leds/Makefile +1 -0
@@ -17,6 +17,7 @@ obj-$(CONFIG_LEDS_NET5501) += leds-net5501.o obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o obj-$(CONFIG_LEDS_ALIX2) += leds-alix2.o obj-$(CONFIG_LEDS_H1940) += leds-h1940.o +obj-$(CONFIG_LEDS_RX1950) += leds-rx1950.o obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o
drivers/leds/leds-rx1950.c new file +206 -0
206 lines not on this page · raw message
Signature · 1 line
1.7.1
PATCH 2/3 Add s3c-adc-battery driver
In reply to Vasily Khoruzhicks3c-adc-battery is driver for monitoring
and charging battery on iPAQ H1930/H1940/RX1950.
It depends on s3c-adc driver to get battery voltage and current.
--- drivers/power/Kconfig | 6 + drivers/power/Makefile | 1 + drivers/power/s3c_adc_battery.c | 518 +++++++++++++++++++++++++++++++++++++++ include/linux/s3c_adc_battery.h | 37 +++ 4 files changed, 562 insertions(+), 0 deletions(-) create mode 100644 drivers/power/s3c_adc_battery.c create mode 100644 include/linux/s3c_adc_battery.h
drivers/power/Kconfig +6 -0
@@ -136,6 +136,12 @@ config BATTERY_Z2 help Say Y to include support for the battery on the Zipit Z2. +config BATTERY_S3C_ADC + tristate "Battery driver for Samsung ADC based monitoring" + depends on S3C_ADC + help + Say Y here to enable support for iPAQ h1930/h1940/rx1950 battery + config CHARGER_PCF50633 tristate "NXP PCF50633 MBC" depends on MFD_PCF50633
drivers/power/Makefile +1 -0
@@ -33,4 +33,5 @@ obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o obj-$(CONFIG_BATTERY_Z2) += z2_battery.o +obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
drivers/power/s3c_adc_battery.c new file +518 -0
518 lines not on this page · raw message
include/linux/s3c_adc_battery.h new file +37 -0
@@ -0,0 +1,37 @@ +#ifndef _S3C_ADC_BATTERY_H +#define _S3C_ADC_BATTERY_H + +struct s3c_adc_batt_thresh { +int volt;/* mV */ +int cur;/* mA */ +int level;/* percent */ +}; + +struct s3c_adc_batt_pdata { +int (*init)(void ); +void (*exit)(void ); +void (*enable_charger)(void ); +void (*disable_charger)(void ); + +unsigned int gpio_cable_plugged; +unsigned int gpio_charge_finished; + +const struct s3c_adc_batt_thresh *lut_noac; +unsigned int lut_noac_cnt; +const struct s3c_adc_batt_thresh *lut_acin; +unsigned int lut_acin_cnt; + +const unsigned int volt_channel; +const unsigned int current_channel; +const unsigned int backup_volt_channel; + +const unsigned int volt_mult; +const unsigned int current_mult; +const unsigned int backup_volt_mult; +const unsigned int internal_impedance; + +const unsigned int backup_volt_max; +const unsigned int backup_volt_min; +}; + +#endif
Signature · 1 line
1.7.1
PATCH 2/3 Add s3c-adc-battery driver
Quoted 5 lines · Vasily Khoruzhick
s3c-adc-battery is driver for monitoring
and charging battery on iPAQ H1930/H1940/RX1950.
It depends on s3c-adc driver to get battery voltage and current.Signed-off-by Vasily Khoruzhick <[email protected]>
Thanks for the driver!
Please Cc me on driver/power/* patches, it's pure luck that I noticed this patch.
drivers/power/s3c_adc_battery.c line 2
Quoted 8 lines
drivers/power/s3c_adc_battery.c new file +2
-0@@ -0,0 +1,518 @@ +/* +* drivers/power/s3c_adc_battery.c
This line isn't needed. You'd better move the
"iPAQ h1930/h1940/rx1950 battery controler driver" line here.
drivers/power/s3c_adc_battery.c line 11
Quoted 9 lines
drivers/power/s3c_adc_battery.c new file +9
-0+* Copyright (c) Vasily Khoruzhick +* Based on h1940_battery.c by Arnaud Patard +* +* This file is subject to the terms and conditions of the GNU General Public +* License. See the file COPYING in the main directory of this archive for +* more details. +* +* iPAQ h1930/h1940/rx1950 battery controler driver +*/
#include <linux/init.h> for __init
#include <linux/errno.h> for E-codes
drivers/power/s3c_adc_battery.c line 19
Quoted 7 lines
drivers/power/s3c_adc_battery.c new file +7
-0+#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/power_supply.h> +#include <linux/leds.h> +#include <linux/gpio.h> +#include <linux/err.h> +#include <linux/io.h>
Do you really need io.h?
drivers/power/s3c_adc_battery.c line 24
Quoted 5 lines
drivers/power/s3c_adc_battery.c new file +5
-0+#include <linux/timer.h> +#include <linux/jiffies.h> +#include <linux/s3c_adc_battery.h> + +#include <asm/irq.h>
Is this really needed?
drivers/power/s3c_adc_battery.c line 26
Quoted 2 lines
drivers/power/s3c_adc_battery.c new file +2
-0+#include <mach/regs-gpio.h> +#include <mach/regs-gpioj.h>
Not linux/gpio.h?
Quoted 9 lines
drivers/power/s3c_adc_battery.c new file +9
-0+ +#include <plat/adc.h> + +#define BAT_POLL_INTERVAL 10000/* ms */ +#define JITTER_DELAY 500/* ms */ + +struct s3c_adc_bat { +struct power_supply psy; +struct s3c_adc_client *client;
drivers/power/s3c_adc_battery.c line 45
Quoted 10 lines
drivers/power/s3c_adc_battery.c new file +10
-0+struct s3c_adc_batt_pdata *pdata; +}; + +#ifdef CONFIG_LEDS_CLASS +DEFINE_LED_TRIGGER (charger_led_trigger); +#endif + +static int s3c_adc_ac_get_property (struct power_supply *psy, +enum power_supply_property psp, +union power_supply_propval *val);
Please avoid forward declarations where possible.
Quoted 7 lines
drivers/power/s3c_adc_battery.c new file +7
-0+static char *s3c_adc_supplied_to[] = { +"main-battery" , +}; + +static enum power_supply_property s3c_adc_ac_props[] = { +POWER_SUPPLY_PROP_ONLINE , +};
drivers/power/s3c_adc_battery.c line 63
Quoted 10 lines
drivers/power/s3c_adc_battery.c new file +10
-0+ +static struct power_supply s3c_adc_ac = { + .name ="ac" , + .type =POWER_SUPPLY_TYPE_MAINS , + .supplied_to = s3c_adc_supplied_to, + .num_supplicants =ARRAY_SIZE (s3c_adc_supplied_to), + .properties = s3c_adc_ac_props, + .num_properties =ARRAY_SIZE (s3c_adc_ac_props), + .get_property = s3c_adc_ac_get_property, +};
You really shouldn't create yet another "ac" power supply instance. You can use drivers/power/pda_power.c for this.
Quoted 46 lines
drivers/power/s3c_adc_battery.c new file +46
-0+ +static enum power_supply_property s3c_adc_backup_bat_props[] = { +POWER_SUPPLY_PROP_VOLTAGE_NOW , +POWER_SUPPLY_PROP_VOLTAGE_MIN , +POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN , +}; + +static int s3c_adc_backup_bat_get_property (struct power_supply *psy, +enum power_supply_property psp, +union power_supply_propval *val); + +static struct s3c_adc_bat backup_bat = { + .psy = { + .name ="backup-battery" , + .type =POWER_SUPPLY_TYPE_BATTERY , + .properties = s3c_adc_backup_bat_props, + .num_properties =ARRAY_SIZE (s3c_adc_backup_bat_props), + .get_property = s3c_adc_backup_bat_get_property, + .use_for_apm =1 , + }, +}; + +static enum power_supply_property s3c_adc_main_bat_props[] = { +POWER_SUPPLY_PROP_STATUS , +POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN , +POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN , +POWER_SUPPLY_PROP_CHARGE_NOW , +POWER_SUPPLY_PROP_VOLTAGE_NOW , +POWER_SUPPLY_PROP_CURRENT_NOW , +}; + +static int s3c_adc_bat_get_property (struct power_supply *psy, +enum power_supply_property psp, +union power_supply_propval *val); + +static struct s3c_adc_bat main_bat = { + .psy = { + .name ="main-battery" , + .type =POWER_SUPPLY_TYPE_BATTERY , + .properties = s3c_adc_main_bat_props, + .num_properties =ARRAY_SIZE (s3c_adc_main_bat_props), + .get_property = s3c_adc_bat_get_property, + .use_for_apm =1 , + }, +}; +
drivers/power/s3c_adc_battery.c line 119
Quoted 10 lines
drivers/power/s3c_adc_battery.c new file +10
-0+static int s3c_adc_ac_get_property (struct power_supply *psy, +enum power_supply_property psp, +union power_supply_propval *val) +{ +int ret =0 ; + +switch (psp) { +case POWER_SUPPLY_PROP_ONLINE : + val->intval = + !gpio_get_value (main_bat.pdata->gpio_cable_plugged);
Yep, it's duplication of pda_power.c functionality.
So, you probably want to register S3C ADC battery and pda-power platform devices. And S3C ADC battery driver would only do battery stuff, and pda-power would do the AC stuff.
Quoted 8 lines
drivers/power/s3c_adc_battery.c new file +8
-0+break ; +default : + ret = -EINVAL ; +break ; + } +return ret; +} +
drivers/power/s3c_adc_battery.c line 137
Quoted 10 lines
drivers/power/s3c_adc_battery.c new file +10
-0+static int s3c_adc_backup_bat_get_property (struct power_supply *psy, +enum power_supply_property psp, +union power_supply_propval *val) +{ + struct s3c_adc_bat *bat = container_of(psy, struct s3c_adc_bat, psy); +static int volt_value =-1 ; +static unsigned int timestamp; + +if (!bat) { +printk (KERN_ERR "%s: no battery infos ?!\n" , __func__);
dev_err()
Quoted 26 lines
drivers/power/s3c_adc_battery.c new file +26
-0+return -EINVAL ; + } + +if (volt_value <0 || +jiffies_to_msecs (jiffies - timestamp) >BAT_POLL_INTERVAL ) { + volt_value =s3c_adc_read (bat->client, + bat->pdata->backup_volt_channel); + volt_value *= bat->pdata->backup_volt_mult; + timestamp = jiffies; + } + +switch (psp) { +case POWER_SUPPLY_PROP_VOLTAGE_NOW : + val->intval = volt_value; +return 0 ; +case POWER_SUPPLY_PROP_VOLTAGE_MIN : + val->intval = bat->pdata->backup_volt_min; +return 0 ; +case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN : + val->intval = bat->pdata->backup_volt_max; +return 0 ; +default : +return -EINVAL ; + } +} +
drivers/power/s3c_adc_battery.c line 173
Quoted 10 lines
drivers/power/s3c_adc_battery.c new file +10
-0+static void cable_plugged_handler (unsigned long data) +{ +static int old_status; +int is_plugged = !gpio_get_value (main_bat.pdata->gpio_cable_plugged); + +if (old_status == is_plugged) +return ; + +printk (KERN_INFO "Power cable %s\n" ,\ + is_plugged ?"plugged" :"unplugged" );
dev_info()
drivers/power/s3c_adc_battery.c line 183
Quoted 10 lines
drivers/power/s3c_adc_battery.c new file +10
-0+if (is_plugged) { + main_bat.pdata->enable_charger (); +#ifdef CONFIG_LEDS_CLASS +led_trigger_event (charger_led_trigger,LED_HALF ); +#endif + }else { + main_bat.pdata->disable_charger (); +#ifdef CONFIG_LEDS_CLASS +led_trigger_event (charger_led_trigger,LED_OFF ); +#endif
?
We have a generic charge triggers, see drivers/power/power_supply_leds.c, so you probably don't need this.
Quoted 53 lines
drivers/power/s3c_adc_battery.c new file +53
-0+ } + + old_status = is_plugged; +power_supply_changed (&s3c_adc_ac); +} + +static void charge_finished_handler (unsigned long data) +{ +static int old_status; +int is_plugged = !gpio_get_value (main_bat.pdata->gpio_cable_plugged); +int is_charged =gpio_get_value (main_bat.pdata->gpio_charge_finished); + +if (old_status == is_charged) +return ; + +if (!is_plugged) +return ; + +if (is_charged) { +#ifdef CONFIG_LEDS_CLASS +led_trigger_event (charger_led_trigger,LED_FULL ); +#endif + main_bat.pdata->disable_charger (); + }else { +#ifdef CONFIG_LEDS_CLASS +led_trigger_event (charger_led_trigger,LED_HALF ); +#endif + main_bat.pdata->enable_charger (); + } + + old_status = is_charged; +power_supply_changed (&main_bat.psy); +} + +static DEFINE_TIMER(cable_plugged_timer, cable_plugged_handler, 0, 0); +static DEFINE_TIMER(charge_finished_timer, charge_finished_handler, 0, 0); + +static irqreturn_t s3c_adc_batt_cable (int irq,void *dev_id) +{ +mod_timer (&cable_plugged_timer, + jiffies +msecs_to_jiffies (JITTER_DELAY )); +return IRQ_HANDLED ; +} + +static irqreturn_t s3c_adc_batt_charged (int irq,void *dev_id) +{ +mod_timer (&charge_finished_timer, + jiffies +msecs_to_jiffies (JITTER_DELAY )); +return IRQ_HANDLED ; +} + +static int calc_full_volt (int volt_val,int cur_val) +{
drivers/power/s3c_adc_battery.c line 246
Quoted 10 lines
drivers/power/s3c_adc_battery.c new file +10
-0+return volt_val + + cur_val * main_bat.pdata->internal_impedance /1000 ; +} + +static int s3c_adc_bat_get_property (struct power_supply *psy, +enum power_supply_property psp, +union power_supply_propval *val) +{ + struct s3c_adc_bat *bat = container_of(psy, struct s3c_adc_bat, psy); +static int volt_value =-1 , cur_value =-1 ;
I don't think that using static variables here is safe. Why you need them? There must be a better way.
drivers/power/s3c_adc_battery.c line 249
Quoted 3 lines
drivers/power/s3c_adc_battery.c new file +3
-0+static unsigned int timestamp; +static int level =1000000 ; +
No need for this empty line.
drivers/power/s3c_adc_battery.c line 250
Quoted 1 line
drivers/power/s3c_adc_battery.c new file +1
-0+int status =POWER_SUPPLY_STATUS_DISCHARGING , new_level, full_volt;
Each declaration on it own line please, e.g.
int status = ...;
int new_level;
int full_volt;
drivers/power/s3c_adc_battery.c line 255
Quoted 5 lines
drivers/power/s3c_adc_battery.c new file +5
-0+const struct s3c_adc_batt_thresh *lut = bat->pdata->lut_noac; +unsigned int lut_size = bat->pdata->lut_noac_cnt; + +if (!bat) { +printk (KERN_ERR "%s: no battery infos ?!\n" , __func__);
dev_err() please.
Quoted 19 lines
drivers/power/s3c_adc_battery.c new file +19
-0+return -EINVAL ; + } + +if (volt_value <0 || cur_value <0 || +jiffies_to_msecs (jiffies - timestamp) >BAT_POLL_INTERVAL ) { + volt_value =s3c_adc_read (bat->client, + bat->pdata->volt_channel) * bat->pdata->volt_mult; + cur_value =s3c_adc_read (bat->client, + bat->pdata->current_channel) * bat->pdata->current_mult; + timestamp = jiffies; + } + +if (!gpio_get_value (bat->pdata->gpio_cable_plugged)) { +if (gpio_get_value (bat->pdata->gpio_charge_finished)) + status =POWER_SUPPLY_STATUS_FULL ; +else { + status =POWER_SUPPLY_STATUS_CHARGING ; + lut = bat->pdata->lut_acin; + lut_size = bat->pdata->lut_acin_cnt;
drivers/power/s3c_adc_battery.c line 284
Quoted 10 lines
drivers/power/s3c_adc_battery.c new file +10
-0+ } + } + + new_level =100000 ; + full_volt =calc_full_volt ((volt_value /1000 ), (cur_value /1000 )); + +if (full_volt <calc_full_volt (lut->volt, lut->cur)) { + lut_size--; +while (lut_size--) { +int lut_volt1, lut_volt2;
int lut_volt1;
int lut_volt2;
<empty line>
...
drivers/power/s3c_adc_battery.c line 297
Quoted 13 lines
drivers/power/s3c_adc_battery.c new file +13
-0+ lut_volt1 =calc_full_volt (lut[0 ].volt, lut[0 ].cur); + lut_volt2 =calc_full_volt (lut[1 ].volt, lut[1 ].cur); +if (full_volt < lut_volt1 && full_volt >= lut_volt2) { + new_level = (lut[1 ].level + + (lut[0 ].level - lut[1 ].level) * + (full_volt - lut_volt2) / + (lut_volt1 - lut_volt2)) *1000 ; +break ; + } + new_level = lut[1 ].level *1000 ; + lut++; + } + }
Cool!
drivers/power/s3c_adc_battery.c line 299
Quoted 1 line
drivers/power/s3c_adc_battery.c new file +1
-0+#if 0
Do you really need this dead code?
Quoted 57 lines
drivers/power/s3c_adc_battery.c new file +57
-0+/* Battery level can't go up during discharging, and +* can't go down during charging +*/ +if ((status ==POWER_SUPPLY_STATUS_DISCHARGING && new_level < level) || + (status ==POWER_SUPPLY_STATUS_CHARGING && new_level > level) || + status ==POWER_SUPPLY_STATUS_FULL ) + level = new_level; +#else + level = new_level; +#endif + +switch (psp) { +case POWER_SUPPLY_PROP_STATUS : + val->intval = status; +return 0 ; +case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN : + val->intval =100000 ; +return 0 ; +case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN : + val->intval =0 ; +return 0 ; +case POWER_SUPPLY_PROP_CHARGE_NOW : + val->intval = level; +return 0 ; +case POWER_SUPPLY_PROP_VOLTAGE_NOW : + val->intval = volt_value; +return 0 ; +case POWER_SUPPLY_PROP_CURRENT_NOW : + val->intval = cur_value; +return 0 ; +default : +return -EINVAL ; + } +} + +static int __init s3c_adc_batt_probe (struct platform_device *pdev) +{ +struct s3c_adc_client *client; +struct s3c_adc_batt_pdata *pdata = pdev->dev.platform_data; +int ret; + + client =s3c_adc_register (pdev,NULL ,NULL ,0 ); +if (IS_ERR (client)) { +dev_err (&pdev->dev,"cannot register adc\n" ); +return PTR_ERR (client); + } + +platform_set_drvdata (pdev, client); + + main_bat.client = client; + main_bat.pdata = pdev->dev.platform_data; + + ret =power_supply_register (&pdev->dev, &main_bat.psy); +if (ret) + goto err_reg_main; +if (pdata->backup_volt_mult) { + backup_bat.client = client;
drivers/power/s3c_adc_battery.c line 366
Quoted 10 lines
drivers/power/s3c_adc_battery.c new file +10
-0+ backup_bat.pdata = pdev->dev.platform_data; + ret =power_supply_register (&pdev->dev, &backup_bat.psy); +if (ret) + goto err_reg_backup; + } + ret =power_supply_register (&pdev->dev, &s3c_adc_ac); +if (ret) + goto err_reg_ac; + +
One empty line is enough.
Quoted 20 lines
drivers/power/s3c_adc_battery.c new file +20
-0+ ret =gpio_request (main_bat.pdata->gpio_cable_plugged,"batcable" ); +if (ret) + goto err_gpio1; + + ret =request_irq (gpio_to_irq (main_bat.pdata->gpio_cable_plugged), + s3c_adc_batt_cable, +IRQF_TRIGGER_RISING |IRQF_TRIGGER_FALLING , + pdev->name,NULL ); +if (ret) + goto err_irq1; + + ret =gpio_request (main_bat.pdata->gpio_charge_finished,"charged" ); +if (ret) + goto err_gpio2; + + ret =request_irq (gpio_to_irq (main_bat.pdata->gpio_charge_finished), + s3c_adc_batt_charged, +IRQF_TRIGGER_RISING |IRQF_TRIGGER_FALLING , + pdev->name,NULL ); +if (ret)
drivers/power/s3c_adc_battery.c line 396
Quoted 10 lines
drivers/power/s3c_adc_battery.c new file +10
-0+ goto err_irq2; + + ret = pdata->init (); +if (ret) + goto err_platform; + +#ifdef CONFIG_LEDS_CLASS +led_trigger_register_simple ("s3c-adc-charger" , &charger_led_trigger); +#endif +printk (KERN_INFO "s3c-adc-batt successfully loaded\n" );
dev_info().
drivers/power/s3c_adc_battery.c line 402
Quoted 6 lines
drivers/power/s3c_adc_battery.c new file +6
-0+ +device_init_wakeup (&pdev->dev,1 ); + +/* Schedule timer to check current status */ +mod_timer (&cable_plugged_timer, + jiffies +msecs_to_jiffies (JITTER_DELAY ));
You probably don't need a timer for this.
Use schedule_work() instead.
Thanks,
Signature · 3 lines
Anton Vorontsov email: cbouatmailru at gmail.com irc://irc.freenode.net/bd2
PATCH 2/3 Add s3c-adc-battery driver
? ????????? ?? 9 ???? 2010 15:57:01 ????? Anton Vorontsov ???????:
Quoted 2 lines
Please Cc me on driver/power/* patches, it's pure luck that I noticed this patch.
Ok, I'll do :)
Quoted 4 lines
Quoted 1 line
+ *
drivers/power/s3c_adc_battery.cThis line isn't needed. You'd better move the
"iPAQ h1930/h1940/rx1950 battery controler driver" line here.
Ok
Quoted 2 lines
#include <
linux/init.h> for__init
#include <linux/errno.h> for E-codes
init is not necessary, but errno is, I'm using some error codes (-EINVAL) in driver
Quoted 9 lines
drivers/power/s3c_adc_battery.c line 19
Quoted 7 lines
drivers/power/s3c_adc_battery.c new file +7
-0+#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/power_supply.h> +#include <linux/leds.h> +#include <linux/gpio.h> +#include <linux/err.h> +#include <linux/io.h> Do you really need
io.h?
Will check.
Quoted 7 lines
drivers/power/s3c_adc_battery.c line 24
Quoted 5 lines
drivers/power/s3c_adc_battery.c new file +5
-0+#include <linux/timer.h> +#include <linux/jiffies.h> +#include <linux/s3c_adc_battery.h> + +#include <asm/irq.h> Is this really needed?
asm/irq.h is not necessary
Quoted 4 lines
drivers/power/s3c_adc_battery.c line 26
Quoted 2 lines
drivers/power/s3c_adc_battery.c new file +2
-0+#include <mach/regs-gpio.h> +#include <mach/regs-gpioj.h> Not
linux/gpio.h?
Will remove it
Quoted 5 lines
drivers/power/s3c_adc_battery.c line 45
Quoted 3 lines
drivers/power/s3c_adc_battery.c new file +3
-0+static int s3c_adc_ac_get_property (struct power_supply *psy, +enum power_supply_property psp, +union power_supply_propval *val);Please avoid forward declarations where possible.
Ok
Quoted 21 lines
Quoted 7 lines
drivers/power/s3c_adc_battery.c new file +7
-0+static char *s3c_adc_supplied_to[] = { +"main-battery" , +}; + +static enum power_supply_property s3c_adc_ac_props[] = { +POWER_SUPPLY_PROP_ONLINE , +};drivers/power/s3c_adc_battery.c line 63
Quoted 10 lines
drivers/power/s3c_adc_battery.c new file +10
-0+ +static struct power_supply s3c_adc_ac = { + .name ="ac" , + .type =POWER_SUPPLY_TYPE_MAINS , + .supplied_to = s3c_adc_supplied_to, + .num_supplicants =ARRAY_SIZE (s3c_adc_supplied_to), + .properties = s3c_adc_ac_props, + .num_properties =ARRAY_SIZE (s3c_adc_ac_props), + .get_property = s3c_adc_ac_get_property, +};You really shouldn't create yet another "ac" power supply instance. You can use
drivers/power/pda_power.cfor this.
Quoted 5 lines
Yep, it's duplication of
pda_power.cfunctionality.So, you probably want to register S3C ADC battery and pda-power platform devices. And S3C ADC battery driver would only do battery stuff, and pda-power would do the AC stuff.
Nope, I can't use pda_power here, as it can't control whether battery is already charged (it's separate gpio pin, and I need to disable charger in this case)
Quoted 4 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ if (!bat) { + printk(KERN_ERR "%s: no battery infos ?!\n", __func__);
dev_err()
Ok
Quoted 4 lines
drivers/power/s3c_adc_battery.c line 173
Quoted 2 lines
drivers/power/s3c_adc_battery.c new file +2
-0+printk (KERN_INFO "Power cable %s\n" ,\ + is_plugged ?"plugged" :"unplugged" );
dev_info()
Ok
Quoted 4 lines
?
We have a generic charge triggers, see
drivers/power/power_supply_leds.c, so you probably don't need this.
Ok
Quoted 9 lines
drivers/power/s3c_adc_battery.c line 246
Quoted 6 lines
drivers/power/s3c_adc_battery.c new file +6
-0+static int s3c_adc_bat_get_property (struct power_supply *psy, +enum power_supply_property psp, +union power_supply_propval *val) +{ + struct s3c_adc_bat *bat = container_of(psy, struct s3c_adc_bat, psy); +static int volt_value =-1 , cur_value =-1 ;I don't think that using static variables here is safe. Why you need them? There must be a better way.
Need them to cache voltage and current values (to prevent spamming adc), however I should move them to s3c_adc_bat struct.
Quoted 6 lines
drivers/power/s3c_adc_battery.c line 249
Quoted 3 lines
drivers/power/s3c_adc_battery.c new file +3
-0+static unsigned int timestamp; +static int level =1000000 ; +No need for this empty line.
Ok
Quoted 7 lines
drivers/power/s3c_adc_battery.c line 250
Quoted 1 line
drivers/power/s3c_adc_battery.c new file +1
-0+int status =POWER_SUPPLY_STATUS_DISCHARGING , new_level, full_volt;Each declaration on it own line please, e.g.
int status = ...;
intnew_level;
intfull_volt;
Ok
Quoted 7 lines
Quoted 7 lines
drivers/power/s3c_adc_battery.c new file +7
-0+ lut_volt1 =calc_full_volt (lut[0 ].volt, lut[0 ].cur); + lut_volt2 =calc_full_volt (lut[1 ].volt, lut[1 ].cur); +if (full_volt < lut_volt1 && full_volt >= lut_volt2) { + new_level = (lut[1 ].level + + (lut[0 ].level - lut[1 ].level) * + (full_volt - lut_volt2) / + (lut_volt1 - lut_volt2)) *1000 ;
Quoted 8 lines
drivers/power/s3c_adc_battery.c line 297
Quoted 6 lines
drivers/power/s3c_adc_battery.c new file +6
-0+break ; + } + new_level = lut[1 ].level *1000 ; + lut++; + } + }Cool!
Is it some kind of sarcasm? :)
Quoted 3 lines
Quoted 1 line
+#if 0
Do you really need this dead code?
Nope, I'll remove it.
Quoted 3 lines
You probably don't need a timer for this.
Useschedule_work()instead.
Timer's used to prevet jitter on gpio pins, and here it's used to check pins state on startup. I don't see any reason to replace it with delayed work.
Thanks for review!
Regards
Vasily
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100709/34e2210c/attachment.sig>
PATCH 2/3 Add s3c-adc-battery driver
On Fri, Jul 09, 2010 at 04:19:14PM +0300, Vasily Khoruzhick wrote:
[...]
Quoted 8 lines
Quoted 8 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ .get_property = s3c_adc_ac_get_property, +};You really shouldn't create yet another "ac" power supply instance. You can use
drivers/power/pda_power.cfor this.Yep, it's duplication of
pda_power.cfunctionality.
Quoted 7 lines
Quoted 3 lines
So, you probably want to register S3C ADC battery and pda-power platform devices. And S3C ADC battery driver would only do battery stuff, and pda-power would do the AC stuff.
Nope, I can't use
pda_powerhere, as it can't control whether battery is already charged (it's separate gpio pin, and I need to disable charger in this case)
I guess you can remove all the cable_plugged handling from s3c battery driver, and then use power_supply.external_power_changed callback to get cable_plugged notification (you should fill pda_power.supplied_to properly to make it work).
See drivers/power/ds2760_battery.c and arch/arm/mach-pxa/hx4700.c as an example.
You probably will need to change .external_power_changed() hook to accept 'pst' argument (the supply that caused the change), so that you could write something like this:
s3c_external_power_changed(struct power_supply *psy,
struct power_supply *ext)
{
...
ext->get_property(ext, ONLINE, &val);
s3c->is_plugged = val.intval;
s3c_kick_cable_plugged_handler(s3c);
}Or, instead of ext->get_property() you could just use power_supply_is_system_supplied(). Not very elegant, but should work.
[...]
Quoted 16 lines
Quoted 7 lines
Quoted 7 lines
drivers/power/s3c_adc_battery.c new file +7
-0+ lut_volt1 =calc_full_volt (lut[0 ].volt, lut[0 ].cur); + lut_volt2 =calc_full_volt (lut[1 ].volt, lut[1 ].cur); +if (full_volt < lut_volt1 && full_volt >= lut_volt2) { + new_level = (lut[1 ].level + + (lut[0 ].level - lut[1 ].level) * + (full_volt - lut_volt2) / + (lut_volt1 - lut_volt2)) *1000 ;Quoted 8 lines
drivers/power/s3c_adc_battery.c line 297
Quoted 6 lines
drivers/power/s3c_adc_battery.c new file +6
-0+break ; + } + new_level = lut[1 ].level *1000 ; + lut++; + } + }Cool!
Quoted 1 line
Is it some kind of sarcasm? :)
Nope. ;-)
[...]
Quoted 5 lines
Quoted 2 lines
You probably don't need a timer for this.
Useschedule_work()instead.Timer's used to prevet jitter on gpio pins, and here it's used to check pins state on startup. I don't see any reason to replace it with delayed work.
Timer is a softirq, atomic context. It adds latency to your embedded, underpowered device. Plus with timer you can't use sleepable GPIOs (we should change it for pda_power too, btw).
Jitter filtering isn't urgent task for the kernel (or user) needs, right? So it's fine to postpone it for non-atomic context.
Thanks,
Signature · 3 lines
Anton Vorontsov email: cbouatmailru at gmail.com irc://irc.freenode.net/bd2
PATCH 2/3 Add s3c-adc-battery driver
? ????????? ?? 9 ???? 2010 16:53:45 ????? Anton Vorontsov ???????:
Quoted 23 lines
I guess you can remove all the
cable_pluggedhandling from s3c battery driver, and then use power_supply.external_power_changed callback to getcable_pluggednotification (you should fill pda_power.supplied_to properly to make it work).See
drivers/power/ds2760_battery.candarch/arm/mach-pxa/hx4700.cas an example.You probably will need to change .external_power_changed() hook to accept 'pst' argument (the supply that caused the change), so that you could write something like this:
s3c_external_power_changed(struct
power_supply*psy,
structpower_supply*ext){ ... ext->get_property(ext, ONLINE, &val); s3c->is_plugged = val.intval; s3c_kick_cable_plugged_handler(s3c); }
Quoted 3 lines
Or, instead of
ext->get_property()you could just usepower_supply_is_system_supplied(). Not very elegant, but should work.
You didn't get the point. Here's workflow:
cable plugged -> GPF2 goes to 0, irq is generated
cable plugged irq handler -> cable_plugged ? enable_charger : disable_charger charging....
battery is charged, GPF3 goes to 0, irq is generated
battery charged irq handler -> disable_charger
cable unplugged -> GPF2 goest to 1, irq is generated
pda_power driver does not support 'battery_charged' pin handling, but I need to handle this pin (and IRQ from it) to prevent battery overcharge
Quoted 7 lines
Timer is a softirq, atomic context. It adds latency to your embedded, underpowered device. Plus with timer you can't use sleepable GPIOs (we should change it for
pda_powertoo, btw).Jitter filtering isn't urgent task for the kernel (or user) needs, right? So it's fine to postpone it for non-atomic context.
Ok, will replace timer with delayed works
Regards
Vasily
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100709/0dfa45f9/attachment.sig>
PATCH 2/3 Add s3c-adc-battery driver
Quoted 28 lines · Vasily Khoruzhick
? ????????? ?? 9 ???? 2010 16:53:45 ????? Anton Vorontsov ???????:
Quoted 26 lines
I guess you can remove all the
cable_pluggedhandling from s3c battery driver, and then use power_supply.external_power_changed callback to getcable_pluggednotification (you should fill pda_power.supplied_to properly to make it work).See
drivers/power/ds2760_battery.candarch/arm/mach-pxa/hx4700.cas an example.You probably will need to change .external_power_changed() hook to accept 'pst' argument (the supply that caused the change), so that you could write something like this:
s3c_external_power_changed(struct
power_supply*psy,
structpower_supply*ext){ ... ext->get_property(ext, ONLINE, &val); s3c->is_plugged = val.intval; s3c_kick_cable_plugged_handler(s3c); }Or, instead of
ext->get_property()you could just usepower_supply_is_system_supplied(). Not very elegant, but should work.
[...reordered...]
Quoted 2 lines
pda_powerdriver does not support 'battery_charged' pin handling, but I need to handle this pin (and IRQ from it) to prevent battery overcharge
And I was not talking about 'battery_charged' pin handling. :-) Sure, battery_charged handling should be in the battery driver.
I was talking about 'cable_plugged' handling, it is the only thing that s3c_adc_ac_get_property() is using, see the driver you've just posted:
+static int s3c_adc_ac_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ int ret = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval =
+ !gpio_get_value(main_bat.pdata->gpio_cable_plugged);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
And cable_plugged_handler() stays in the battery driver, but it will be called by the pda_power driver via external_power_changed callback.
Quoted 2 lines
You didn't get the point. Here's workflow:
cable plugged -> GPF2 goes to 0, irq is generated
Handled by the pda_power driver.
Quoted 1 line
cable plugged irq handler ->
cable_plugged?enable_charger:disable_charger
pda_power driver calls power_supply_changed(), which calls s3c battery.external_power_changed/cable_plugged_handler, which starts charging (sets is_plugged if power_supply_is_system_supplied() returns true).
Quoted 2 lines
charging....
battery is charged, GPF3 goes to 0, irq is generated
Yep, this is handled by the s3c driver.
Quoted 1 line
battery charged irq handler ->
disable_charger
This is still s3c driver's job.
Quoted 1 line
cable unplugged -> GPF2 goest to 1, irq is generated
Handled by the pda_power driver, it again sends the 'changed' event to s3c battery driver, and the battery driver clears is_plugged if power_supply_is_system_supplied() returns false.
Still think this wont work?
Signature · 3 lines
Anton Vorontsov email: cbouatmailru at gmail.com irc://irc.freenode.net/bd2
PATCH 2/3 Add s3c-adc-battery driver
? ????????? ?? 9 ???? 2010 18:15:35 ????? Anton Vorontsov ???????:
Quoted 1 line
Still think this wont work?
Ok, one more question: pda_power requests irq with cleared TRIGGER flags, but
I need TRIGGER_RISING | TRIGGER_FALLING, how can I add my custom irq flags topda_power driver? :)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100709/1d9bbe63/attachment.sig>
PATCH 2/3 Add s3c-adc-battery driver
? ????????? ?? 9 ???? 2010 18:32:02 ????? Vasily Khoruzhick ???????:
Quoted 3 lines
Ok, one more question:
pda_powerrequests irq with cleared TRIGGER flags, but I needTRIGGER_RISING|TRIGGER_FALLING, how can I add my custom irq flags topda_powerdriver? :)
Oops, sorry, they aren't cleared :) Sorry for the noise
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100709/130da2b9/attachment.sig>
PATCH 3/3 rx1950: add battery device
In reply to Vasily Khoruzhick--- arch/arm/mach-s3c2440/Kconfig | 2 + arch/arm/mach-s3c2440/mach-rx1950.c | 111 +++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 0 deletions(-)
arch/arm/mach-s3c2440/Kconfig +2 -0
@@ -198,6 +198,8 @@ config MACH_RX1950 select S3C_DEV_NAND select S3C2410_IOTIMING if S3C2440_CPUFREQ select S3C2440_XTAL_16934400 + select S3C_ADC + select BATTERY_S3C_ADC help Say Y here if you're using HP iPAQ rx1950
arch/arm/mach-s3c2440/mach-rx1950.c +111 -0
129 lines not on this page · raw message
Signature · 1 line
1.7.1