Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 367490
b: refs/heads/master
c: 4d3b4aa
h: refs/heads/master
v: v3
  • Loading branch information
Lee Jones committed Mar 7, 2013
1 parent 9f08d65 commit dd07a9c
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 77 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9b7f50e3ea9a98f518fc4077f8bebc96717acff5
refs/heads/master: 4d3b4aa58ac9e18029c4d0259630414cffd3ba76
231 changes: 155 additions & 76 deletions trunk/drivers/power/abx500_chargalg.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
/* Plus margin for the low battery threshold */
#define BAT_PLUS_MARGIN (100)

#define CHARGALG_CURR_STEP_LOW 0
#define CHARGALG_CURR_STEP_HIGH 100

#define to_abx500_chargalg_device_info(x) container_of((x), \
struct abx500_chargalg, chargalg_psy);

Expand Down Expand Up @@ -80,6 +83,11 @@ struct abx500_chargalg_suspension_status {
bool usb_suspended;
};

struct abx500_chargalg_current_step_status {
bool curr_step_change;
int curr_step;
};

struct abx500_chargalg_battery_data {
int temp;
int volt;
Expand Down Expand Up @@ -220,6 +228,7 @@ enum maxim_ret {
* @batt_data: data of the battery
* @susp_status: current charger suspension status
* @bm: Platform specific battery management information
* @curr_status: Current step status for over-current protection
* @parent: pointer to the struct abx500
* @chargalg_psy: structure that holds the battery properties exposed by
* the charging algorithm
Expand All @@ -245,6 +254,7 @@ struct abx500_chargalg {
struct abx500_chargalg_battery_data batt_data;
struct abx500_chargalg_suspension_status susp_status;
struct ab8500 *parent;
struct abx500_chargalg_current_step_status curr_status;
struct abx500_bm_data *bm;
struct power_supply chargalg_psy;
struct ux500_charger *ac_chg;
Expand All @@ -268,6 +278,12 @@ static enum power_supply_property abx500_chargalg_props[] = {
POWER_SUPPLY_PROP_HEALTH,
};

struct abx500_chargalg_sysfs_entry {
struct attribute attr;
ssize_t (*show)(struct abx500_chargalg *, char *);
ssize_t (*store)(struct abx500_chargalg *, const char *, size_t);
};

/**
* abx500_chargalg_safety_timer_expired() - Expiration of the safety timer
* @timer: pointer to the hrtimer structure
Expand Down Expand Up @@ -401,6 +417,22 @@ static int abx500_chargalg_check_charger_connection(struct abx500_chargalg *di)
return di->chg_info.conn_chg;
}

/**
* abx500_chargalg_check_current_step_status() - Check charging current
* step status.
* @di: pointer to the abx500_chargalg structure
*
* This function will check if there is a change in the charging current step
* and change charge state accordingly.
*/
static void abx500_chargalg_check_current_step_status
(struct abx500_chargalg *di)
{
if (di->curr_status.curr_step_change)
abx500_chargalg_state_to(di, STATE_NORMAL_INIT);
di->curr_status.curr_step_change = false;
}

/**
* abx500_chargalg_start_safety_timer() - Start charging safety timer
* @di: pointer to the abx500_chargalg structure
Expand Down Expand Up @@ -1300,6 +1332,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
{
int charger_status;
int ret;
int curr_step_lvl;

/* Collect data from all power_supply class devices */
class_for_each_device(power_supply_class, NULL,
Expand All @@ -1310,6 +1343,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
abx500_chargalg_check_charger_voltage(di);

charger_status = abx500_chargalg_check_charger_connection(di);
abx500_chargalg_check_current_step_status(di);

if (is_ab8500(di->parent)) {
ret = abx500_chargalg_check_charger_enable(di);
Expand Down Expand Up @@ -1523,9 +1557,18 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
}
}

abx500_chargalg_start_charging(di,
di->bm->bat_type[di->bm->batt_id].normal_vol_lvl,
di->bm->bat_type[di->bm->batt_id].normal_cur_lvl);
if (di->curr_status.curr_step == CHARGALG_CURR_STEP_LOW)
abx500_chargalg_stop_charging(di);
else {
curr_step_lvl = di->bm->bat_type[
di->bm->batt_id].normal_cur_lvl
* di->curr_status.curr_step
/ CHARGALG_CURR_STEP_HIGH;
abx500_chargalg_start_charging(di,
di->bm->bat_type[di->bm->batt_id]
.normal_vol_lvl, curr_step_lvl);
}

abx500_chargalg_state_to(di, STATE_NORMAL);
abx500_chargalg_start_safety_timer(di);
abx500_chargalg_stop_maintenance_timer(di);
Expand Down Expand Up @@ -1767,99 +1810,134 @@ static int abx500_chargalg_get_property(struct power_supply *psy,

/* Exposure to the sysfs interface */

/**
* abx500_chargalg_sysfs_show() - sysfs show operations
* @kobj: pointer to the struct kobject
* @attr: pointer to the struct attribute
* @buf: buffer that holds the parameter to send to userspace
*
* Returns a buffer to be displayed in user space
*/
static ssize_t abx500_chargalg_sysfs_show(struct kobject *kobj,
struct attribute *attr, char *buf)
static ssize_t abx500_chargalg_curr_step_show(struct abx500_chargalg *di,
char *buf)
{
struct abx500_chargalg *di = container_of(kobj,
struct abx500_chargalg, chargalg_kobject);
return sprintf(buf, "%d\n", di->curr_status.curr_step);
}

static ssize_t abx500_chargalg_curr_step_store(struct abx500_chargalg *di,
const char *buf, size_t length)
{
long int param;
int ret;

ret = kstrtol(buf, 10, &param);
if (ret < 0)
return ret;

di->curr_status.curr_step = param;
if (di->curr_status.curr_step >= CHARGALG_CURR_STEP_LOW &&
di->curr_status.curr_step <= CHARGALG_CURR_STEP_HIGH) {
di->curr_status.curr_step_change = true;
queue_work(di->chargalg_wq, &di->chargalg_work);
} else
dev_info(di->dev, "Wrong current step\n"
"Enter 0. Disable AC/USB Charging\n"
"1--100. Set AC/USB charging current step\n"
"100. Enable AC/USB Charging\n");

return strlen(buf);
}


static ssize_t abx500_chargalg_en_show(struct abx500_chargalg *di,
char *buf)
{
return sprintf(buf, "%d\n",
di->susp_status.ac_suspended &&
di->susp_status.usb_suspended);
}

/**
* abx500_chargalg_sysfs_charger() - sysfs store operations
* @kobj: pointer to the struct kobject
* @attr: pointer to the struct attribute
* @buf: buffer that holds the parameter passed from userspace
* @length: length of the parameter passed
*
* Returns length of the buffer(input taken from user space) on success
* else error code on failure
* The operation to be performed on passing the parameters from the user space.
*/
static ssize_t abx500_chargalg_sysfs_charger(struct kobject *kobj,
struct attribute *attr, const char *buf, size_t length)
static ssize_t abx500_chargalg_en_store(struct abx500_chargalg *di,
const char *buf, size_t length)
{
struct abx500_chargalg *di = container_of(kobj,
struct abx500_chargalg, chargalg_kobject);
long int param;
int ac_usb;
int ret;
char entry = *attr->name;

switch (entry) {
case 'c':
ret = strict_strtol(buf, 10, &param);
if (ret < 0)
return ret;

ac_usb = param;
switch (ac_usb) {
case 0:
/* Disable charging */
di->susp_status.ac_suspended = true;
di->susp_status.usb_suspended = true;
di->susp_status.suspended_change = true;
/* Trigger a state change */
queue_work(di->chargalg_wq,
&di->chargalg_work);
break;
case 1:
/* Enable AC Charging */
di->susp_status.ac_suspended = false;
di->susp_status.suspended_change = true;
/* Trigger a state change */
queue_work(di->chargalg_wq,
&di->chargalg_work);
break;
case 2:
/* Enable USB charging */
di->susp_status.usb_suspended = false;
di->susp_status.suspended_change = true;
/* Trigger a state change */
queue_work(di->chargalg_wq,
&di->chargalg_work);
break;
default:
dev_info(di->dev, "Wrong input\n"
"Enter 0. Disable AC/USB Charging\n"
"1. Enable AC charging\n"
"2. Enable USB Charging\n");
};
ret = kstrtol(buf, 10, &param);
if (ret < 0)
return ret;

ac_usb = param;
switch (ac_usb) {
case 0:
/* Disable charging */
di->susp_status.ac_suspended = true;
di->susp_status.usb_suspended = true;
di->susp_status.suspended_change = true;
/* Trigger a state change */
queue_work(di->chargalg_wq,
&di->chargalg_work);
break;
case 1:
/* Enable AC Charging */
di->susp_status.ac_suspended = false;
di->susp_status.suspended_change = true;
/* Trigger a state change */
queue_work(di->chargalg_wq,
&di->chargalg_work);
break;
case 2:
/* Enable USB charging */
di->susp_status.usb_suspended = false;
di->susp_status.suspended_change = true;
/* Trigger a state change */
queue_work(di->chargalg_wq,
&di->chargalg_work);
break;
default:
dev_info(di->dev, "Wrong input\n"
"Enter 0. Disable AC/USB Charging\n"
"1. Enable AC charging\n"
"2. Enable USB Charging\n");
};
return strlen(buf);
}

static struct attribute abx500_chargalg_en_charger = \
static struct abx500_chargalg_sysfs_entry abx500_chargalg_en_charger =
__ATTR(chargalg, 0644, abx500_chargalg_en_show,
abx500_chargalg_en_store);

static struct abx500_chargalg_sysfs_entry abx500_chargalg_curr_step =
__ATTR(chargalg_curr_step, 0644, abx500_chargalg_curr_step_show,
abx500_chargalg_curr_step_store);

static ssize_t abx500_chargalg_sysfs_show(struct kobject *kobj,
struct attribute *attr, char *buf)
{
struct abx500_chargalg_sysfs_entry *entry = container_of(attr,
struct abx500_chargalg_sysfs_entry, attr);

struct abx500_chargalg *di = container_of(kobj,
struct abx500_chargalg, chargalg_kobject);

if (!entry->show)
return -EIO;

return entry->show(di, buf);
}

static ssize_t abx500_chargalg_sysfs_charger(struct kobject *kobj,
struct attribute *attr, const char *buf, size_t length)
{
.name = "chargalg",
.mode = S_IRUGO | S_IWUSR,
};
struct abx500_chargalg_sysfs_entry *entry = container_of(attr,
struct abx500_chargalg_sysfs_entry, attr);

struct abx500_chargalg *di = container_of(kobj,
struct abx500_chargalg, chargalg_kobject);

if (!entry->store)
return -EIO;

return entry->store(di, buf, length);
}

static struct attribute *abx500_chargalg_chg[] = {
&abx500_chargalg_en_charger,
NULL
&abx500_chargalg_en_charger.attr,
&abx500_chargalg_curr_step.attr,
NULL,
};

static const struct sysfs_ops abx500_chargalg_sysfs_ops = {
Expand Down Expand Up @@ -2052,6 +2130,7 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
dev_err(di->dev, "failed to create sysfs entry\n");
goto free_psy;
}
di->curr_status.curr_step = CHARGALG_CURR_STEP_HIGH;

/* Run the charging algorithm */
queue_delayed_work(di->chargalg_wq, &di->chargalg_periodic_work, 0);
Expand Down

0 comments on commit dd07a9c

Please sign in to comment.