drm/prime: add return check for dma_buf_fd
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / battery / sprd27x3_fuelgauge4samsung.c
1 /*
2  * Copyright (C) 2013 Spreadtrum Communications Inc.
3  *
4  * This software is licensed under the terms of the GNU General Public
5  * License version 2, as published by the Free Software Foundation, and
6  * may be copied, distributed, and modified under those terms.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  */
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/interrupt.h>
16 #include <linux/err.h>
17 #include <soc/sprd/hardware.h>
18 #include <soc/sprd/sci.h>
19 #include <soc/sprd/sci_glb_regs.h>
20 #include <linux/io.h>
21 #include <soc/sprd/adi.h>
22 #include <linux/wakelock.h>
23 #include <linux/hrtimer.h>
24 #include <linux/delay.h>
25 #include <linux/device.h>
26 #include <linux/platform_device.h>
27 #include <linux/power_supply.h>
28 #include <linux/battery/sec_fuelgauge.h>
29 #include <linux/sprd_battery_common.h>
30
31 #define SPRDFGU_TEMP_COMP_SOC
32 int sprdbat_interpolate(int x, int n, struct sprdbat_table_data *tab)
33 {
34         int index;
35         int y;
36
37         if (x >= tab[0].x)
38                 y = tab[0].y;
39         else if (x <= tab[n - 1].x)
40                 y = tab[n - 1].y;
41         else {
42                 /*  find interval */
43                 for (index = 1; index < n; index++)
44                         if (x > tab[index].x)
45                                 break;
46                 /*  interpolate */
47                 y = (tab[index - 1].y - tab[index].y) * (x - tab[index].x)
48                     * 2 / (tab[index - 1].x - tab[index].x);
49                 y = (y + 1) / 2;
50                 y += tab[index].y;
51         }
52         return y;
53 }
54 static void print_pdata(struct sprd_battery_platform_data *pdata)
55 {
56 #define PDATA_LOG(format, arg...) printk("sprdbat pdata: " format, ## arg)
57         int i;
58
59
60         PDATA_LOG("chg_bat_safety_vol:%d\n", pdata->chg_bat_safety_vol);
61
62         PDATA_LOG("irq_fgu:%d\n", pdata->irq_fgu);
63         PDATA_LOG("fgu_mode:%d\n", pdata->fgu_mode);
64         PDATA_LOG("alm_soc:%d\n", pdata->alm_soc);
65         PDATA_LOG("alm_vol:%d\n", pdata->alm_vol);
66         PDATA_LOG("soft_vbat_uvlo:%d\n", pdata->soft_vbat_uvlo);
67         PDATA_LOG("soft_vbat_ovp:%d\n", pdata->soft_vbat_ovp);
68         PDATA_LOG("rint:%d\n", pdata->rint);
69         PDATA_LOG("cnom:%d\n", pdata->cnom);
70         PDATA_LOG("rsense_real:%d\n", pdata->rsense_real);
71         PDATA_LOG("rsense_spec:%d\n", pdata->rsense_spec);
72         PDATA_LOG("relax_current:%d\n", pdata->relax_current);
73         PDATA_LOG("fgu_cal_ajust:%d\n", pdata->fgu_cal_ajust);
74         PDATA_LOG("qmax_update_period:%d\n", pdata->qmax_update_period);
75         PDATA_LOG("ocv_tab_size:%d\n", pdata->ocv_tab_size);
76         for (i = 0; i < pdata->ocv_tab_size; i++) {
77                 PDATA_LOG("ocv_tab i=%d x:%d,y:%d\n", i, pdata->ocv_tab[i].x,
78                           pdata->ocv_tab[i].y);
79         }
80         for (i = 0; i < pdata->temp_tab_size; i++) {
81                 PDATA_LOG("temp_tab_size i=%d x:%d,y:%d\n", i,
82                           pdata->temp_tab[i].x, pdata->temp_tab[i].y);
83         }
84         for (i = 0; i < pdata->cnom_temp_tab_size; i++) {
85                 PDATA_LOG("cnom_temp_tab i=%d x:%d,y:%d\n", i, pdata->cnom_temp_tab[i].x,
86                           pdata->cnom_temp_tab[i].y);
87         }
88         for (i = 0; i < pdata->rint_temp_tab_size; i++) {
89                 PDATA_LOG("rint_temp_tab i=%d x:%d,y:%d\n", i, pdata->rint_temp_tab[i].x,
90                           pdata->rint_temp_tab[i].y);
91         }
92
93 }
94
95 static uint32_t init_flag = 0;
96 static uint32_t init_temp_flag = 0;
97
98 #define SPRDBAT_ONE_PERCENT_TIME   (40)
99 #define SPRDBAT_AVOID_JUMPING_TEMI  (SPRDBAT_ONE_PERCENT_TIME)
100
101 static unsigned long sprdbat_update_capacity_time;
102 static uint32_t update_capacity;
103
104 static unsigned long sprdbat_last_query_time;
105 struct sprd_battery_platform_data *bat_pdata;
106
107 bool sec_hal_fg_init(fuelgauge_variable_t * fg_var)
108 {
109         struct sprd_battery_platform_data *pdata = (&get_battery_data(fg_var))->pdata ;
110         bat_pdata = pdata;
111         pr_info("register sec_hal_fg_init\n");
112         print_pdata(pdata); //debug
113         sprdfgu_init(pdata);
114         {
115                 struct timespec cur_time;
116                 get_monotonic_boottime(&cur_time);
117                 sprdbat_update_capacity_time = cur_time.tv_sec;
118                 update_capacity = sprdfgu_poweron_capacity();
119         }
120         init_flag = 1;
121         return true;
122 }
123
124 static uint32_t sprdbat_update_capacty(void)
125 {
126         uint32_t fgu_capacity = sprdfgu_read_capacity();
127         uint32_t flush_time = 0;
128         uint32_t period_time = 0;
129         struct timespec cur_time;
130         union power_supply_propval value;
131         int temp_degree;
132         union power_supply_propval temp_value;
133
134         psy_do_property("battery", get, POWER_SUPPLY_PROP_TEMP, temp_value);
135         temp_degree = temp_value.intval / 10;
136
137         psy_do_property("battery", get, POWER_SUPPLY_PROP_STATUS, value);
138
139         get_monotonic_boottime(&cur_time);
140         flush_time = cur_time.tv_sec - sprdbat_update_capacity_time;
141         period_time = cur_time.tv_sec - sprdbat_last_query_time;
142         sprdbat_last_query_time = cur_time.tv_sec;
143
144         pr_info("fgu_capacity: = %d,flush_time: = %d,period_time:=%d\n",
145                       fgu_capacity, flush_time, period_time);
146         if ((!init_temp_flag) && (temp_degree < 16)) {
147           pr_info("temp init skip\n");
148           init_temp_flag = 1;
149          } else {
150
151         switch (value.intval) {
152         case POWER_SUPPLY_STATUS_CHARGING:
153 #ifdef SPRDFGU_TEMP_COMP_SOC
154                 if ((fgu_capacity < update_capacity) && ((temp_degree > 15) || \
155                         (update_capacity >= 2))) {
156 #else
157                 if (fgu_capacity < update_capacity) {
158 #endif
159                         if (sprdfgu_read_batcurrent() > 0) {
160                                 pr_info("avoid vol jumping\n");
161                         fgu_capacity = update_capacity;
162                 } else {
163                                 if (period_time <= SPRDBAT_AVOID_JUMPING_TEMI) {
164                                         fgu_capacity =update_capacity - 1;
165                                         pr_info("avoid jumping! fgu_capacity: = %d\n", fgu_capacity);
166                                 }
167                                 if ((update_capacity - fgu_capacity) >=
168                                     (flush_time / SPRDBAT_ONE_PERCENT_TIME)) {
169                                         fgu_capacity =
170                                             update_capacity -
171                                             flush_time / SPRDBAT_ONE_PERCENT_TIME;
172                                 }
173                         }
174                 } else if (fgu_capacity > update_capacity) {
175                         if (period_time <= SPRDBAT_AVOID_JUMPING_TEMI) {
176                                 fgu_capacity =
177                                         update_capacity + 1;
178                                 pr_info("avoid  jumping! fgu_capacity: = %d\n",fgu_capacity);
179                         }
180                         if ((fgu_capacity - update_capacity) >=
181                             (flush_time / SPRDBAT_ONE_PERCENT_TIME)) {
182                                 fgu_capacity =
183                                     update_capacity +
184                                     flush_time / SPRDBAT_ONE_PERCENT_TIME;
185                         }
186                 }
187                 /*when soc=100 and adp plugin occur, keep on 100, */
188                 if (100 == update_capacity) {
189                         sprdbat_update_capacity_time = cur_time.tv_sec;
190                         fgu_capacity = 100;
191                 }
192 #if 0
193         /* skip this code to avoid not full in charger when current comsuption is high */
194                 else {
195                         if (fgu_capacity >= 100) {
196                                 fgu_capacity = 99;
197                         }
198                 }
199 #endif
200
201                 break;
202         case POWER_SUPPLY_STATUS_NOT_CHARGING:
203         case POWER_SUPPLY_STATUS_DISCHARGING:
204                 if (fgu_capacity >= update_capacity) {
205                         fgu_capacity = update_capacity;
206                 } else {
207                         if (period_time <= SPRDBAT_AVOID_JUMPING_TEMI) {
208                                 fgu_capacity =
209                                     update_capacity - 1;
210                                 pr_info
211                                     ("avoid jumping! fgu_capacity: = %d\n",
212                                      fgu_capacity);
213                         }
214                         if ((update_capacity - fgu_capacity) >=
215                             (flush_time / SPRDBAT_ONE_PERCENT_TIME)) {
216                                 fgu_capacity =
217                                     update_capacity -
218                                     flush_time / SPRDBAT_ONE_PERCENT_TIME;
219                         }
220                 }
221
222                 if (sprdfgu_read_vbat_vol() < bat_pdata->soft_vbat_uvlo) {
223                         pr_info("soft uvlo vol 0...\n");
224                         fgu_capacity = 0;
225                 }
226
227                 break;
228         case POWER_SUPPLY_STATUS_FULL:
229                 sprdbat_update_capacity_time = cur_time.tv_sec;
230                 if (fgu_capacity != 100) {
231                         fgu_capacity = 100;
232                 }
233                 break;
234         default:
235                 break;
236         }
237                 }
238         if (fgu_capacity != update_capacity) {
239                 update_capacity = fgu_capacity;
240                 sprdbat_update_capacity_time = cur_time.tv_sec;
241         }
242         sprdfgu_record_cap(update_capacity);
243         return update_capacity;
244
245 }
246
247 bool sec_hal_fg_reset(fuelgauge_variable_t * fg_var)
248 {
249         msleep(1000);  //wait a moment,insure voltage REG of FG is updated after power supply voltage be changed
250         sprdfgu_reset();
251         {
252                 struct timespec cur_time;
253                 get_monotonic_boottime(&cur_time);
254                 sprdbat_update_capacity_time = cur_time.tv_sec; //time need to be updated,too.
255                 update_capacity = sprdfgu_poweron_capacity(); //same as your change
256         }
257         return true;
258 }
259 bool sec_hal_fg_suspend(fuelgauge_variable_t * fg_var)
260 {
261         sprdfgu_pm_op(1);
262         return true;
263 }
264
265 bool sec_hal_fg_resume(fuelgauge_variable_t * fg_var)
266 {
267         sprdfgu_pm_op(0);
268         return true;
269 }
270 bool sec_hal_fg_fuelalert_init(fuelgauge_variable_t * fg_var , int val)
271 {
272         return true;
273 }
274 bool sec_hal_fg_is_fuelalerted(fuelgauge_variable_t * fg_var)
275 {
276         return false;
277 }
278 bool sec_hal_fg_full_charged(fuelgauge_variable_t * fg_var)
279 {
280         return true;
281 }
282
283 bool sec_hal_fg_fuelalert_process(void *irq_data, bool is_fuel_alerted)
284 {
285         return true;
286 }
287
288 bool sec_hal_fg_get_property(fuelgauge_variable_t * fg_var,
289                                enum power_supply_property psp,
290                                union power_supply_propval *val)
291 {
292
293         switch (psp) {
294
295         /* Cell voltage (VCELL, mV) */
296         case POWER_SUPPLY_PROP_VOLTAGE_NOW:
297                 val->intval = sprdfgu_read_vbat_vol();
298                 break;
299
300         /* Additional Voltage Information (mV) */
301         case POWER_SUPPLY_PROP_VOLTAGE_AVG:
302                 switch (val->intval) {
303                 case SEC_BATTEY_VOLTAGE_AVERAGE:
304                         val->intval = sprdfgu_read_vbat_vol();
305                         break;
306                 case SEC_BATTEY_VOLTAGE_OCV:
307                         val->intval = sprdfgu_read_vbat_ocv();
308                         break;
309                 }
310                 break;
311
312         /* Current (mA) */
313         case POWER_SUPPLY_PROP_CURRENT_NOW:
314                 val->intval = sprdfgu_read_batcurrent();
315                 break;
316
317         /* Average Current (mA) */
318         case POWER_SUPPLY_PROP_CURRENT_AVG:
319                 val->intval = sprdfgu_read_batcurrent();
320                 break;
321
322         /* SOC (%) */
323         case POWER_SUPPLY_PROP_CAPACITY:
324                 if (init_flag) {
325 #if 0
326                         int cap = sprdfgu_read_capacity();
327                         if (100 == cap) {
328                                 union power_supply_propval value;
329                                 psy_do_property("battery", get,
330                                                 POWER_SUPPLY_PROP_STATUS,
331                                                 value);
332                                 if (POWER_SUPPLY_STATUS_CHARGING ==
333                                     value.intval) {
334                                         pr_info
335                                             ("sec_hal_fg_get_property soc == 100, but is charging\n",
336                                              psp);
337                                         cap = 99;
338                                 }
339                         }
340 #else
341                         int cap = sprdbat_update_capacty();
342 #endif
343                         val->intval = cap * 10;
344                 } else {
345                         val->intval = 500;
346                 }
347                 break;
348
349         case POWER_SUPPLY_PROP_PRESENT:
350                 /* TODO */
351                 break;
352
353         case POWER_SUPPLY_PROP_ENERGY_NOW:
354                 /* TODO */
355                 break;
356
357         /* Battery Temperature */
358         case POWER_SUPPLY_PROP_TEMP:
359                 /* TODO */
360                 break;
361
362         /* Target Temperature */
363         case POWER_SUPPLY_PROP_TEMP_AMBIENT:
364                 /* TODO */
365                 break;
366
367         default:
368                 return false;
369         }
370         pr_debug("sec_hal_fg_get_property-%d,val->intval = %d\n", psp,
371                 val->intval);
372         return true;
373 }
374
375 bool sec_hal_fg_set_property(fuelgauge_variable_t * fg_var,
376                                enum power_supply_property psp,
377                                const union power_supply_propval *val)
378 {
379         switch (psp) {
380
381         case POWER_SUPPLY_PROP_ONLINE:
382                 if (val->intval == POWER_SUPPLY_TYPE_BATTERY) {
383                         sprdfgu_adp_status_set(0);
384                 } else {
385                         sprdfgu_adp_status_set(1);
386                 }
387                 break;
388         /* Battery Temperature */
389         case POWER_SUPPLY_PROP_TEMP:
390
391         /* Target Temperature */
392         case POWER_SUPPLY_PROP_TEMP_AMBIENT:
393                 break;
394         default:
395                 return false;
396         }
397         return true;
398 }
399