aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power
diff options
context:
space:
mode:
authorLee Jones <lee.jones@linaro.org>2013-02-15 05:58:58 -0500
committerLee Jones <lee.jones@linaro.org>2013-03-06 23:35:58 -0500
commit4d3b4aa58ac9e18029c4d0259630414cffd3ba76 (patch)
treebdf4b1ede008d25d894f54c6d74486d394096d9a /drivers/power
parent9b7f50e3ea9a98f518fc4077f8bebc96717acff5 (diff)
abx500-chargalg: Add charging current step interface
To prevent overheating, provide differnt steps of charging current interface to allow thermal mitigation. This will provide possibility to reduce gradually the charging current. Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/abx500_chargalg.c231
1 files changed, 155 insertions, 76 deletions
diff --git a/drivers/power/abx500_chargalg.c b/drivers/power/abx500_chargalg.c
index 7e4bc011dd8f..9863e423602c 100644
--- a/drivers/power/abx500_chargalg.c
+++ b/drivers/power/abx500_chargalg.c
@@ -47,6 +47,9 @@
47/* Plus margin for the low battery threshold */ 47/* Plus margin for the low battery threshold */
48#define BAT_PLUS_MARGIN (100) 48#define BAT_PLUS_MARGIN (100)
49 49
50#define CHARGALG_CURR_STEP_LOW 0
51#define CHARGALG_CURR_STEP_HIGH 100
52
50#define to_abx500_chargalg_device_info(x) container_of((x), \ 53#define to_abx500_chargalg_device_info(x) container_of((x), \
51 struct abx500_chargalg, chargalg_psy); 54 struct abx500_chargalg, chargalg_psy);
52 55
@@ -80,6 +83,11 @@ struct abx500_chargalg_suspension_status {
80 bool usb_suspended; 83 bool usb_suspended;
81}; 84};
82 85
86struct abx500_chargalg_current_step_status {
87 bool curr_step_change;
88 int curr_step;
89};
90
83struct abx500_chargalg_battery_data { 91struct abx500_chargalg_battery_data {
84 int temp; 92 int temp;
85 int volt; 93 int volt;
@@ -220,6 +228,7 @@ enum maxim_ret {
220 * @batt_data: data of the battery 228 * @batt_data: data of the battery
221 * @susp_status: current charger suspension status 229 * @susp_status: current charger suspension status
222 * @bm: Platform specific battery management information 230 * @bm: Platform specific battery management information
231 * @curr_status: Current step status for over-current protection
223 * @parent: pointer to the struct abx500 232 * @parent: pointer to the struct abx500
224 * @chargalg_psy: structure that holds the battery properties exposed by 233 * @chargalg_psy: structure that holds the battery properties exposed by
225 * the charging algorithm 234 * the charging algorithm
@@ -245,6 +254,7 @@ struct abx500_chargalg {
245 struct abx500_chargalg_battery_data batt_data; 254 struct abx500_chargalg_battery_data batt_data;
246 struct abx500_chargalg_suspension_status susp_status; 255 struct abx500_chargalg_suspension_status susp_status;
247 struct ab8500 *parent; 256 struct ab8500 *parent;
257 struct abx500_chargalg_current_step_status curr_status;
248 struct abx500_bm_data *bm; 258 struct abx500_bm_data *bm;
249 struct power_supply chargalg_psy; 259 struct power_supply chargalg_psy;
250 struct ux500_charger *ac_chg; 260 struct ux500_charger *ac_chg;
@@ -268,6 +278,12 @@ static enum power_supply_property abx500_chargalg_props[] = {
268 POWER_SUPPLY_PROP_HEALTH, 278 POWER_SUPPLY_PROP_HEALTH,
269}; 279};
270 280
281struct abx500_chargalg_sysfs_entry {
282 struct attribute attr;
283 ssize_t (*show)(struct abx500_chargalg *, char *);
284 ssize_t (*store)(struct abx500_chargalg *, const char *, size_t);
285};
286
271/** 287/**
272 * abx500_chargalg_safety_timer_expired() - Expiration of the safety timer 288 * abx500_chargalg_safety_timer_expired() - Expiration of the safety timer
273 * @timer: pointer to the hrtimer structure 289 * @timer: pointer to the hrtimer structure
@@ -402,6 +418,22 @@ static int abx500_chargalg_check_charger_connection(struct abx500_chargalg *di)
402} 418}
403 419
404/** 420/**
421 * abx500_chargalg_check_current_step_status() - Check charging current
422 * step status.
423 * @di: pointer to the abx500_chargalg structure
424 *
425 * This function will check if there is a change in the charging current step
426 * and change charge state accordingly.
427 */
428static void abx500_chargalg_check_current_step_status
429 (struct abx500_chargalg *di)
430{
431 if (di->curr_status.curr_step_change)
432 abx500_chargalg_state_to(di, STATE_NORMAL_INIT);
433 di->curr_status.curr_step_change = false;
434}
435
436/**
405 * abx500_chargalg_start_safety_timer() - Start charging safety timer 437 * abx500_chargalg_start_safety_timer() - Start charging safety timer
406 * @di: pointer to the abx500_chargalg structure 438 * @di: pointer to the abx500_chargalg structure
407 * 439 *
@@ -1300,6 +1332,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
1300{ 1332{
1301 int charger_status; 1333 int charger_status;
1302 int ret; 1334 int ret;
1335 int curr_step_lvl;
1303 1336
1304 /* Collect data from all power_supply class devices */ 1337 /* Collect data from all power_supply class devices */
1305 class_for_each_device(power_supply_class, NULL, 1338 class_for_each_device(power_supply_class, NULL,
@@ -1310,6 +1343,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
1310 abx500_chargalg_check_charger_voltage(di); 1343 abx500_chargalg_check_charger_voltage(di);
1311 1344
1312 charger_status = abx500_chargalg_check_charger_connection(di); 1345 charger_status = abx500_chargalg_check_charger_connection(di);
1346 abx500_chargalg_check_current_step_status(di);
1313 1347
1314 if (is_ab8500(di->parent)) { 1348 if (is_ab8500(di->parent)) {
1315 ret = abx500_chargalg_check_charger_enable(di); 1349 ret = abx500_chargalg_check_charger_enable(di);
@@ -1523,9 +1557,18 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di)
1523 } 1557 }
1524 } 1558 }
1525 1559
1526 abx500_chargalg_start_charging(di, 1560 if (di->curr_status.curr_step == CHARGALG_CURR_STEP_LOW)
1527 di->bm->bat_type[di->bm->batt_id].normal_vol_lvl, 1561 abx500_chargalg_stop_charging(di);
1528 di->bm->bat_type[di->bm->batt_id].normal_cur_lvl); 1562 else {
1563 curr_step_lvl = di->bm->bat_type[
1564 di->bm->batt_id].normal_cur_lvl
1565 * di->curr_status.curr_step
1566 / CHARGALG_CURR_STEP_HIGH;
1567 abx500_chargalg_start_charging(di,
1568 di->bm->bat_type[di->bm->batt_id]
1569 .normal_vol_lvl, curr_step_lvl);
1570 }
1571
1529 abx500_chargalg_state_to(di, STATE_NORMAL); 1572 abx500_chargalg_state_to(di, STATE_NORMAL);
1530 abx500_chargalg_start_safety_timer(di); 1573 abx500_chargalg_start_safety_timer(di);
1531 abx500_chargalg_stop_maintenance_timer(di); 1574 abx500_chargalg_stop_maintenance_timer(di);
@@ -1767,99 +1810,134 @@ static int abx500_chargalg_get_property(struct power_supply *psy,
1767 1810
1768/* Exposure to the sysfs interface */ 1811/* Exposure to the sysfs interface */
1769 1812
1770/** 1813static ssize_t abx500_chargalg_curr_step_show(struct abx500_chargalg *di,
1771 * abx500_chargalg_sysfs_show() - sysfs show operations 1814 char *buf)
1772 * @kobj: pointer to the struct kobject
1773 * @attr: pointer to the struct attribute
1774 * @buf: buffer that holds the parameter to send to userspace
1775 *
1776 * Returns a buffer to be displayed in user space
1777 */
1778static ssize_t abx500_chargalg_sysfs_show(struct kobject *kobj,
1779 struct attribute *attr, char *buf)
1780{ 1815{
1781 struct abx500_chargalg *di = container_of(kobj, 1816 return sprintf(buf, "%d\n", di->curr_status.curr_step);
1782 struct abx500_chargalg, chargalg_kobject); 1817}
1818
1819static ssize_t abx500_chargalg_curr_step_store(struct abx500_chargalg *di,
1820 const char *buf, size_t length)
1821{
1822 long int param;
1823 int ret;
1824
1825 ret = kstrtol(buf, 10, &param);
1826 if (ret < 0)
1827 return ret;
1783 1828
1829 di->curr_status.curr_step = param;
1830 if (di->curr_status.curr_step >= CHARGALG_CURR_STEP_LOW &&
1831 di->curr_status.curr_step <= CHARGALG_CURR_STEP_HIGH) {
1832 di->curr_status.curr_step_change = true;
1833 queue_work(di->chargalg_wq, &di->chargalg_work);
1834 } else
1835 dev_info(di->dev, "Wrong current step\n"
1836 "Enter 0. Disable AC/USB Charging\n"
1837 "1--100. Set AC/USB charging current step\n"
1838 "100. Enable AC/USB Charging\n");
1839
1840 return strlen(buf);
1841}
1842
1843
1844static ssize_t abx500_chargalg_en_show(struct abx500_chargalg *di,
1845 char *buf)
1846{
1784 return sprintf(buf, "%d\n", 1847 return sprintf(buf, "%d\n",
1785 di->susp_status.ac_suspended && 1848 di->susp_status.ac_suspended &&
1786 di->susp_status.usb_suspended); 1849 di->susp_status.usb_suspended);
1787} 1850}
1788 1851
1789/** 1852static ssize_t abx500_chargalg_en_store(struct abx500_chargalg *di,
1790 * abx500_chargalg_sysfs_charger() - sysfs store operations 1853 const char *buf, size_t length)
1791 * @kobj: pointer to the struct kobject
1792 * @attr: pointer to the struct attribute
1793 * @buf: buffer that holds the parameter passed from userspace
1794 * @length: length of the parameter passed
1795 *
1796 * Returns length of the buffer(input taken from user space) on success
1797 * else error code on failure
1798 * The operation to be performed on passing the parameters from the user space.
1799 */
1800static ssize_t abx500_chargalg_sysfs_charger(struct kobject *kobj,
1801 struct attribute *attr, const char *buf, size_t length)
1802{ 1854{
1803 struct abx500_chargalg *di = container_of(kobj,
1804 struct abx500_chargalg, chargalg_kobject);
1805 long int param; 1855 long int param;
1806 int ac_usb; 1856 int ac_usb;
1807 int ret; 1857 int ret;
1808 char entry = *attr->name;
1809 1858
1810 switch (entry) { 1859 ret = kstrtol(buf, 10, &param);
1811 case 'c': 1860 if (ret < 0)
1812 ret = strict_strtol(buf, 10, &param); 1861 return ret;
1813 if (ret < 0) 1862
1814 return ret; 1863 ac_usb = param;
1815 1864 switch (ac_usb) {
1816 ac_usb = param; 1865 case 0:
1817 switch (ac_usb) { 1866 /* Disable charging */
1818 case 0: 1867 di->susp_status.ac_suspended = true;
1819 /* Disable charging */ 1868 di->susp_status.usb_suspended = true;
1820 di->susp_status.ac_suspended = true; 1869 di->susp_status.suspended_change = true;
1821 di->susp_status.usb_suspended = true; 1870 /* Trigger a state change */
1822 di->susp_status.suspended_change = true; 1871 queue_work(di->chargalg_wq,
1823 /* Trigger a state change */ 1872 &di->chargalg_work);
1824 queue_work(di->chargalg_wq, 1873 break;
1825 &di->chargalg_work); 1874 case 1:
1826 break; 1875 /* Enable AC Charging */
1827 case 1: 1876 di->susp_status.ac_suspended = false;
1828 /* Enable AC Charging */ 1877 di->susp_status.suspended_change = true;
1829 di->susp_status.ac_suspended = false; 1878 /* Trigger a state change */
1830 di->susp_status.suspended_change = true; 1879 queue_work(di->chargalg_wq,
1831 /* Trigger a state change */ 1880 &di->chargalg_work);
1832 queue_work(di->chargalg_wq,
1833 &di->chargalg_work);
1834 break;
1835 case 2:
1836 /* Enable USB charging */
1837 di->susp_status.usb_suspended = false;
1838 di->susp_status.suspended_change = true;
1839 /* Trigger a state change */
1840 queue_work(di->chargalg_wq,
1841 &di->chargalg_work);
1842 break;
1843 default:
1844 dev_info(di->dev, "Wrong input\n"
1845 "Enter 0. Disable AC/USB Charging\n"
1846 "1. Enable AC charging\n"
1847 "2. Enable USB Charging\n");
1848 };
1849 break; 1881 break;
1882 case 2:
1883 /* Enable USB charging */
1884 di->susp_status.usb_suspended = false;
1885 di->susp_status.suspended_change = true;
1886 /* Trigger a state change */
1887 queue_work(di->chargalg_wq,
1888 &di->chargalg_work);
1889 break;
1890 default:
1891 dev_info(di->dev, "Wrong input\n"
1892 "Enter 0. Disable AC/USB Charging\n"
1893 "1. Enable AC charging\n"
1894 "2. Enable USB Charging\n");
1850 }; 1895 };
1851 return strlen(buf); 1896 return strlen(buf);
1852} 1897}
1853 1898
1854static struct attribute abx500_chargalg_en_charger = \ 1899static struct abx500_chargalg_sysfs_entry abx500_chargalg_en_charger =
1900 __ATTR(chargalg, 0644, abx500_chargalg_en_show,
1901 abx500_chargalg_en_store);
1902
1903static struct abx500_chargalg_sysfs_entry abx500_chargalg_curr_step =
1904 __ATTR(chargalg_curr_step, 0644, abx500_chargalg_curr_step_show,
1905 abx500_chargalg_curr_step_store);
1906
1907static ssize_t abx500_chargalg_sysfs_show(struct kobject *kobj,
1908 struct attribute *attr, char *buf)
1909{
1910 struct abx500_chargalg_sysfs_entry *entry = container_of(attr,
1911 struct abx500_chargalg_sysfs_entry, attr);
1912
1913 struct abx500_chargalg *di = container_of(kobj,
1914 struct abx500_chargalg, chargalg_kobject);
1915
1916 if (!entry->show)
1917 return -EIO;
1918
1919 return entry->show(di, buf);
1920}
1921
1922static ssize_t abx500_chargalg_sysfs_charger(struct kobject *kobj,
1923 struct attribute *attr, const char *buf, size_t length)
1855{ 1924{
1856 .name = "chargalg", 1925 struct abx500_chargalg_sysfs_entry *entry = container_of(attr,
1857 .mode = S_IRUGO | S_IWUSR, 1926 struct abx500_chargalg_sysfs_entry, attr);
1858}; 1927
1928 struct abx500_chargalg *di = container_of(kobj,
1929 struct abx500_chargalg, chargalg_kobject);
1930
1931 if (!entry->store)
1932 return -EIO;
1933
1934 return entry->store(di, buf, length);
1935}
1859 1936
1860static struct attribute *abx500_chargalg_chg[] = { 1937static struct attribute *abx500_chargalg_chg[] = {
1861 &abx500_chargalg_en_charger, 1938 &abx500_chargalg_en_charger.attr,
1862 NULL 1939 &abx500_chargalg_curr_step.attr,
1940 NULL,
1863}; 1941};
1864 1942
1865static const struct sysfs_ops abx500_chargalg_sysfs_ops = { 1943static const struct sysfs_ops abx500_chargalg_sysfs_ops = {
@@ -2052,6 +2130,7 @@ static int abx500_chargalg_probe(struct platform_device *pdev)
2052 dev_err(di->dev, "failed to create sysfs entry\n"); 2130 dev_err(di->dev, "failed to create sysfs entry\n");
2053 goto free_psy; 2131 goto free_psy;
2054 } 2132 }
2133 di->curr_status.curr_step = CHARGALG_CURR_STEP_HIGH;
2055 2134
2056 /* Run the charging algorithm */ 2135 /* Run the charging algorithm */
2057 queue_delayed_work(di->chargalg_wq, &di->chargalg_periodic_work, 0); 2136 queue_delayed_work(di->chargalg_wq, &di->chargalg_periodic_work, 0);