EDP: adding power-supply depletion driver
[linux-2.6.git] / drivers / edp / psy_depletion.c
1 /*
2  * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16
17 #include <linux/edp.h>
18 #include <linux/edpdev.h>
19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/platform_device.h>
22 #include <linux/power_supply.h>
23 #include <linux/slab.h>
24 #include <linux/workqueue.h>
25
26 #define DEPL_INTERVAL   60000
27
28 struct depl_driver {
29         struct edp_client client;
30         struct psy_depletion_platform_data *pdata;
31         struct delayed_work work;
32         struct edp_manager *manager;
33         struct power_supply *psy;
34 };
35
36 static int depl_psy_get_property(struct depl_driver *drv,
37                 enum power_supply_property psp, int *val)
38 {
39         union power_supply_propval pv;
40
41         if (drv->psy->get_property(drv->psy, psp, &pv))
42                 return -EFAULT;
43         *val = pv.intval;
44         return 0;
45 }
46
47 static int depl_psy_ocv(struct depl_driver *drv)
48 {
49         int val;
50         if (depl_psy_get_property(drv, POWER_SUPPLY_PROP_VOLTAGE_OCV, &val))
51                 return drv->pdata->vsys_min;
52         return val;
53 }
54
55 static int depl_psy_capacity(struct depl_driver *drv)
56 {
57         int val;
58         if (depl_psy_get_property(drv, POWER_SUPPLY_PROP_CAPACITY, &val))
59                 return 0;
60         return val;
61 }
62
63 static unsigned int depl_psy_temp(struct depl_driver *drv)
64 {
65         int val;
66         if (depl_psy_get_property(drv, POWER_SUPPLY_PROP_TEMP, &val))
67                 return 25;
68         return max(0, val);
69 }
70
71 static inline unsigned int depl_maximum(struct depl_driver *drv)
72 {
73         return drv->client.states[0];
74 }
75
76 /* Given two points (x1, y1) and (x2, y2), find the y coord of x */
77 static int depl_interpolate(int x, int x1, int y1, int x2, int y2)
78 {
79         if (x1 == x2)
80                 return y1;
81         return (y2 * (x - x1) - y1 * (x - x2)) / (x2 - x1);
82 }
83
84 /* Calc RBAT for current capacity (SOC) */
85 static int depl_rbat(struct depl_driver *drv)
86 {
87         struct psy_depletion_rbat_lut *p;
88         struct psy_depletion_rbat_lut *q;
89         unsigned int capacity;
90         int rbat;
91
92         capacity = depl_psy_capacity(drv);
93         p = drv->pdata->rbat_lut;
94
95         while (p->capacity > capacity)
96                 p++;
97
98         if (p == drv->pdata->rbat_lut)
99                 return p->rbat;
100
101         q = p - 1;
102
103         rbat = depl_interpolate(capacity, p->capacity, p->rbat,
104                         q->capacity, q->rbat);
105         rbat += drv->pdata->r_const;
106
107         pr_debug("capacity : %u\n", capacity);
108         pr_debug("rbat     : %d\n", rbat);
109
110         return rbat;
111 }
112
113 static s64 depl_ibat_possible(struct depl_driver *drv, s64 ocv, s64 rbat)
114 {
115         return div64_s64(1000 * (ocv - drv->pdata->vsys_min), rbat);
116 }
117
118 /* Calc IBAT for a given temperature */
119 static int depl_ibat(struct depl_driver *drv, unsigned int temp)
120 {
121         struct psy_depletion_ibat_lut *p;
122         struct psy_depletion_ibat_lut *q;
123         int ibat;
124
125         p = drv->pdata->ibat_lut;
126         while (p->ibat && p->temp > temp)
127                 p++;
128
129         if (p == drv->pdata->ibat_lut || !p->ibat)
130                 return p->ibat;
131
132         q = p - 1;
133         ibat = depl_interpolate(temp, p->temp, p->ibat, q->temp, q->ibat);
134
135         pr_debug("temp     : %d\n", temp);
136         pr_debug("ibat     : %d\n", ibat);
137
138         return ibat;
139 }
140
141 static s64 depl_pbat(s64 ocv, s64 ibat, s64 rbat)
142 {
143         s64 pbat;
144         pbat = ocv - div64_s64(ibat * rbat, 1000);
145         pbat = div64_s64(pbat * ibat, 1000000);
146         return pbat;
147 }
148
149 static unsigned int depl_calc(struct depl_driver *drv)
150 {
151         s64 ocv;
152         s64 rbat;
153         s64 ibat_pos;
154         s64 ibat_tbat;
155         s64 ibat_lcm;
156         s64 pbat_lcm;
157         s64 pbat_nom;
158         s64 pbat_gain;
159         s64 depl;
160
161         ocv = depl_psy_ocv(drv);
162         rbat = depl_rbat(drv);
163
164         ibat_pos = depl_ibat_possible(drv, ocv, rbat);
165         ibat_tbat = depl_ibat(drv, depl_psy_temp(drv));
166         ibat_lcm = min(ibat_pos, ibat_tbat);
167
168         pbat_lcm = depl_pbat(ocv, ibat_lcm, rbat);
169         pbat_nom = depl_pbat(drv->pdata->vcharge, drv->pdata->ibat_nom, rbat);
170         pbat_gain = div64_s64(drv->manager->max * 1000, pbat_nom);
171
172         depl = drv->manager->max - div64_s64(pbat_gain * pbat_lcm, 1000);
173
174         pr_debug("ocv      : %lld\n", ocv);
175         pr_debug("ibat_pos : %lld\n", ibat_pos);
176         pr_debug("ibat_tbat: %lld\n", ibat_tbat);
177         pr_debug("ibat_lcm : %lld\n", ibat_lcm);
178         pr_debug("pbat_lcm : %lld\n", pbat_lcm);
179         pr_debug("pbat_nom : %lld\n", pbat_nom);
180         pr_debug("pbat_gain: %lld\n", pbat_gain);
181         pr_debug("depletion: %lld\n", depl);
182
183         depl = clamp_t(s64, depl, 0, depl_maximum(drv));
184         return depl;
185 }
186
187 static void depl_update(struct work_struct *work)
188 {
189         struct depl_driver *drv;
190         struct edp_client *c;
191         unsigned int depl;
192         unsigned int i;
193
194         drv = container_of(work, struct depl_driver, work.work);
195         c = &drv->client;
196         depl = depl_calc(drv);
197
198         i = c->num_states - 1;
199         while (i && c->states[i] < depl)
200                 i--;
201
202         edp_update_client_request(c, i, NULL);
203
204         schedule_delayed_work(to_delayed_work(work),
205                         msecs_to_jiffies(DEPL_INTERVAL));
206 }
207
208 /* Nothing to do */
209 static void depl_edp_callback(unsigned int new_state, void *priv_data)
210 {
211 }
212
213 static void depl_shutdown(struct platform_device *pdev)
214 {
215         struct depl_driver *drv = platform_get_drvdata(pdev);
216         cancel_delayed_work_sync(&drv->work);
217 }
218
219 static int depl_suspend(struct platform_device *pdev, pm_message_t state)
220 {
221         depl_shutdown(pdev);
222         return 0;
223 }
224
225 static int depl_resume(struct platform_device *pdev)
226 {
227         struct depl_driver *drv = platform_get_drvdata(pdev);
228         schedule_delayed_work(&drv->work, 0);
229         return 0;
230 }
231
232 static __devinit int depl_probe(struct platform_device *pdev)
233 {
234         struct depl_driver *drv;
235         struct edp_manager *m;
236         struct edp_client *c;
237         int r = -EFAULT;
238
239         if (!pdev->dev.platform_data)
240                 return -EINVAL;
241
242         m = edp_get_manager("battery");
243         if (!m) {
244                 dev_err(&pdev->dev, "could not get EDP manager\n");
245                 return -ENODEV;
246         }
247
248         drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
249         if (!drv)
250                 return -ENOMEM;
251
252         drv->pdata = pdev->dev.platform_data;
253         drv->manager = m;
254         drv->psy = power_supply_get_by_name(drv->pdata->power_supply);
255         if (!drv->psy)
256                 goto fail;
257
258         c = &drv->client;
259         strncpy(c->name, "depletion", EDP_NAME_LEN - 1);
260         c->name[EDP_NAME_LEN - 1] = 0;
261         c->priority = EDP_MAX_PRIO;
262         c->throttle = depl_edp_callback;
263         c->notify_promotion = depl_edp_callback;
264         c->states = drv->pdata->states;
265         c->num_states = drv->pdata->num_states;
266         c->e0_index = drv->pdata->e0_index;
267
268         r = edp_register_client(m, c);
269         if (r) {
270                 dev_err(&pdev->dev, "failed to register: %d\n", r);
271                 goto fail;
272         }
273
274         platform_set_drvdata(pdev, drv);
275         INIT_DELAYED_WORK_DEFERRABLE(&drv->work, depl_update);
276         schedule_delayed_work(&drv->work, 0);
277         return 0;
278
279 fail:
280         devm_kfree(&pdev->dev, drv);
281         return r;
282 }
283
284 static struct platform_driver depl_driver = {
285         .probe = depl_probe,
286         .shutdown = depl_shutdown,
287         .suspend = depl_suspend,
288         .resume = depl_resume,
289         .driver = {
290                 .name = "psy_depletion",
291                 .owner = THIS_MODULE
292         }
293 };
294
295 static __init int depl_init(void)
296 {
297         return platform_driver_register(&depl_driver);
298 }
299 late_initcall(depl_init);