drm/prime: add return check for dma_buf_fd
[profile/mobile/platform/kernel/linux-3.10-sc7730.git] / drivers / battery / sec_fuelgauge.c
1 /*
2  *  sec_fuelgauge.c
3  *  Samsung Mobile Fuel Gauge Driver
4  *
5  *  Copyright (C) 2012 Samsung Electronics
6  *
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12 #define DEBUG
13 #include <linux/battery/sec_fuelgauge.h>
14 #include <linux/of_gpio.h>
15 int sec_fg_dt_init(struct device_node *np,
16                          struct device *dev,
17                          sec_battery_platform_data_t *pdata);
18 static struct device_attribute sec_fg_attrs[] = {
19         SEC_FG_ATTR(reg),
20         SEC_FG_ATTR(data),
21         SEC_FG_ATTR(regs),
22 };
23
24 static enum power_supply_property sec_fuelgauge_props[] = {
25         POWER_SUPPLY_PROP_STATUS,
26         POWER_SUPPLY_PROP_VOLTAGE_NOW,
27         POWER_SUPPLY_PROP_VOLTAGE_AVG,
28         POWER_SUPPLY_PROP_CURRENT_NOW,
29         POWER_SUPPLY_PROP_CURRENT_AVG,
30         POWER_SUPPLY_PROP_CHARGE_FULL,
31         POWER_SUPPLY_PROP_PRESENT,
32         POWER_SUPPLY_PROP_ENERGY_NOW,
33         POWER_SUPPLY_PROP_CAPACITY,
34         POWER_SUPPLY_PROP_TEMP,
35         POWER_SUPPLY_PROP_TEMP_AMBIENT,
36 };
37 #ifdef CONFIG_FUELGAUGE_SPRD4SAMSUNG27X3
38 #undef dev_dbg
39 #undef dev_err
40 #undef dev_info
41
42 #define dev_dbg(dev, format, arg...)   pr_info(format, ##arg)
43 #define dev_err(dev, format, arg...)   pr_info(format, ##arg)
44 #define dev_info(dev, format, arg...)  pr_info(format, ##arg)
45 #endif
46
47 /* capacity is  0.1% unit */
48 static void sec_fg_get_scaled_capacity(
49                                 struct sec_fuelgauge_info *fuelgauge,
50                                 union power_supply_propval *val)
51 {
52         val->intval = (val->intval < fuelgauge->pdata->capacity_min) ?
53                 0 : ((val->intval - fuelgauge->pdata->capacity_min) * 1000 /
54                 (fuelgauge->capacity_max - fuelgauge->pdata->capacity_min));
55
56         dev_dbg(&fuelgauge->client->dev,
57                 "%s: scaled capacity (%d.%d)\n",
58                 __func__, val->intval/10, val->intval%10);
59 }
60
61 /* capacity is integer */
62 static void sec_fg_get_atomic_capacity(
63                                 struct sec_fuelgauge_info *fuelgauge,
64                                 union power_supply_propval *val)
65 {
66         if (fuelgauge->pdata->capacity_calculation_type &
67                 SEC_FUELGAUGE_CAPACITY_TYPE_ATOMIC) {
68                 if (fuelgauge->capacity_old < val->intval)
69                         val->intval = fuelgauge->capacity_old + 1;
70                 else if (fuelgauge->capacity_old > val->intval)
71                         val->intval = fuelgauge->capacity_old - 1;
72         }
73
74         /* keep SOC stable in abnormal status */
75         if (fuelgauge->pdata->capacity_calculation_type &
76                 SEC_FUELGAUGE_CAPACITY_TYPE_SKIP_ABNORMAL) {
77                 if ((fuelgauge->is_charging &&
78                         fuelgauge->capacity_old > val->intval) ||
79                         (!fuelgauge->is_charging &&
80                         fuelgauge->capacity_old < val->intval)) {
81                         dev_err(&fuelgauge->client->dev,
82                                 "%s: abnormal capacity (old %d : new %d)\n",
83                                 __func__, fuelgauge->capacity_old, val->intval);
84                         val->intval = fuelgauge->capacity_old;
85                 }
86         }
87
88         /* updated old capacity */
89         fuelgauge->capacity_old = val->intval;
90 }
91
92 static int sec_fg_get_property(struct power_supply *psy,
93                             enum power_supply_property psp,
94                             union power_supply_propval *val)
95 {
96         struct sec_fuelgauge_info *fuelgauge =
97                 container_of(psy, struct sec_fuelgauge_info, psy_fg);
98         int soc_type = val->intval;
99
100         switch (psp) {
101         case POWER_SUPPLY_PROP_VOLTAGE_NOW:
102         case POWER_SUPPLY_PROP_VOLTAGE_AVG:
103         case POWER_SUPPLY_PROP_CURRENT_NOW:
104         case POWER_SUPPLY_PROP_CURRENT_AVG:
105         case POWER_SUPPLY_PROP_ENERGY_NOW:
106         case POWER_SUPPLY_PROP_CAPACITY:
107         case POWER_SUPPLY_PROP_TEMP:
108         case POWER_SUPPLY_PROP_TEMP_AMBIENT:
109         case POWER_SUPPLY_PROP_PRESENT:
110                 if (!sec_hal_fg_get_property(fuelgauge_variable, psp, val))
111                         return -EINVAL;
112                 if (psp == POWER_SUPPLY_PROP_CAPACITY) {
113                         if (soc_type == SEC_FUELGAUGE_CAPACITY_TYPE_RAW)
114                                 break;
115
116                         if (fuelgauge->pdata->capacity_calculation_type &
117                                 (SEC_FUELGAUGE_CAPACITY_TYPE_SCALE |
118                                  SEC_FUELGAUGE_CAPACITY_TYPE_DYNAMIC_SCALE))
119                                 sec_fg_get_scaled_capacity(fuelgauge, val);
120
121                         /* capacity should be between 0% and 100%
122                          * (0.1% degree)
123                          */
124                         if (val->intval > 1000)
125                                 val->intval = 1000;
126                         if (val->intval < 0)
127                                 val->intval = 0;
128
129                         /* get only integer part */
130                         val->intval /= 10;
131
132                         /* check whether doing the wake_unlock */
133                         if ((val->intval > fuelgauge->pdata->fuel_alert_soc) &&
134                                 fuelgauge->is_fuel_alerted) {
135                                 wake_unlock(&fuelgauge->fuel_alert_wake_lock);
136                                 sec_hal_fg_fuelalert_init(fuelgauge_variable,
137                                         fuelgauge->pdata->fuel_alert_soc);
138                         }
139
140                         /* (Only for atomic capacity)
141                          * In initial time, capacity_old is 0.
142                          * and in resume from sleep,
143                          * capacity_old is too different from actual soc.
144                          * should update capacity_old
145                          * by val->intval in booting or resume.
146                          */
147                         if (fuelgauge->initial_update_of_soc) {
148                                 /* updated old capacity */
149                                 fuelgauge->capacity_old = val->intval;
150                                 fuelgauge->initial_update_of_soc = false;
151                                 break;
152                         }
153
154                         if (fuelgauge->pdata->capacity_calculation_type &
155                                 (SEC_FUELGAUGE_CAPACITY_TYPE_ATOMIC |
156                                  SEC_FUELGAUGE_CAPACITY_TYPE_SKIP_ABNORMAL))
157                                 sec_fg_get_atomic_capacity(fuelgauge, val);
158                 }
159                 break;
160         case POWER_SUPPLY_PROP_STATUS:
161                 /* TODO */
162                 val->intval = 0;
163                 break;
164         case POWER_SUPPLY_PROP_CHARGE_FULL:
165                 /* TODO */
166                 val->intval = 0;
167                 break;
168         default:
169                 return -EINVAL;
170         }
171         return 0;
172 }
173
174 static int sec_fg_calculate_dynamic_scale(
175                                 struct sec_fuelgauge_info *fuelgauge)
176 {
177         union power_supply_propval raw_soc_val;
178
179         raw_soc_val.intval = SEC_FUELGAUGE_CAPACITY_TYPE_RAW;
180         if (!sec_hal_fg_get_property(fuelgauge_variable,
181                 POWER_SUPPLY_PROP_CAPACITY,
182                 &raw_soc_val))
183                 return -EINVAL;
184         raw_soc_val.intval /= 10;
185
186         if (raw_soc_val.intval <
187                 fuelgauge->pdata->capacity_max -
188                 fuelgauge->pdata->capacity_max_margin) {
189                 fuelgauge->capacity_max =
190                         fuelgauge->pdata->capacity_max -
191                         fuelgauge->pdata->capacity_max_margin;
192                 dev_dbg(&fuelgauge->client->dev, "%s: capacity_max (%d)",
193                         __func__, fuelgauge->capacity_max);
194         } else {
195                 fuelgauge->capacity_max =
196                         (raw_soc_val.intval >
197                         fuelgauge->pdata->capacity_max +
198                         fuelgauge->pdata->capacity_max_margin) ?
199                         (fuelgauge->pdata->capacity_max +
200                         fuelgauge->pdata->capacity_max_margin) :
201                         raw_soc_val.intval;
202                 dev_dbg(&fuelgauge->client->dev, "%s: raw soc (%d)",
203                         __func__, fuelgauge->capacity_max);
204         }
205
206         fuelgauge->capacity_max =
207                 (fuelgauge->capacity_max * 99 / 100);
208
209         dev_info(&fuelgauge->client->dev, "%s: %d is used for capacity_max\n",
210                 __func__, fuelgauge->capacity_max);
211
212         return fuelgauge->capacity_max;
213 }
214
215 static int sec_fg_set_property(struct power_supply *psy,
216                             enum power_supply_property psp,
217                             const union power_supply_propval *val)
218 {
219         struct sec_fuelgauge_info *fuelgauge =
220                 container_of(psy, struct sec_fuelgauge_info, psy_fg);
221
222         switch (psp) {
223         case POWER_SUPPLY_PROP_STATUS:
224                 if (val->intval == POWER_SUPPLY_STATUS_FULL)
225                         sec_hal_fg_full_charged(fuelgauge_variable);
226                 break;
227         case POWER_SUPPLY_PROP_CHARGE_FULL:
228                 if (val->intval == POWER_SUPPLY_TYPE_BATTERY) {
229                         if (fuelgauge->pdata->capacity_calculation_type &
230                                 SEC_FUELGAUGE_CAPACITY_TYPE_DYNAMIC_SCALE)
231                                 sec_fg_calculate_dynamic_scale(fuelgauge);
232                 }
233                 break;
234         case POWER_SUPPLY_PROP_ONLINE:
235                 fuelgauge->cable_type = val->intval;
236                 if (val->intval == POWER_SUPPLY_TYPE_BATTERY)
237                         fuelgauge->is_charging = false;
238                 else
239                         fuelgauge->is_charging = true;
240                 break;
241         case POWER_SUPPLY_PROP_CAPACITY:
242                 if (val->intval == SEC_FUELGAUGE_CAPACITY_TYPE_RESET) {
243                         if (!sec_hal_fg_reset(fuelgauge_variable))
244                                 return -EINVAL;
245                         else
246                                 break;
247                 }
248         case POWER_SUPPLY_PROP_TEMP:
249         case POWER_SUPPLY_PROP_TEMP_AMBIENT:
250                 if (!sec_hal_fg_set_property(fuelgauge_variable, psp, val))
251                         return -EINVAL;
252                 break;
253         default:
254                 return -EINVAL;
255         }
256         return 0;
257 }
258
259 static void sec_fg_isr_work(struct work_struct *work)
260 {
261         struct sec_fuelgauge_info *fuelgauge =
262                 container_of(work, struct sec_fuelgauge_info, isr_work.work);
263
264         /* process for fuel gauge chip */
265         sec_hal_fg_fuelalert_process(fuelgauge, fuelgauge->is_fuel_alerted);
266
267         /* process for others */
268         if (fuelgauge->pdata->fuelalert_process != NULL)
269                 fuelgauge->pdata->fuelalert_process(fuelgauge->is_fuel_alerted);
270 }
271
272 static irqreturn_t sec_fg_irq_thread(int irq, void *irq_data)
273 {
274         struct sec_fuelgauge_info *fuelgauge = irq_data;
275         bool fuel_alerted;
276
277         if (fuelgauge->pdata->fuel_alert_soc >= 0) {
278                 fuel_alerted =
279                         sec_hal_fg_is_fuelalerted(fuelgauge_variable);
280
281                 dev_info(&fuelgauge->client->dev,
282                         "%s: Fuel-alert %salerted!\n",
283                         __func__, fuel_alerted ? "" : "NOT ");
284
285                 if (fuel_alerted == fuelgauge->is_fuel_alerted) {
286                         if (!fuelgauge->pdata->repeated_fuelalert) {
287                                 dev_dbg(&fuelgauge->client->dev,
288                                         "%s: Fuel-alert Repeated (%d)\n",
289                                         __func__, fuelgauge->is_fuel_alerted);
290                                 return IRQ_HANDLED;
291                         }
292                 }
293
294                 if (fuel_alerted)
295                         wake_lock(&fuelgauge->fuel_alert_wake_lock);
296                 else
297                         wake_unlock(&fuelgauge->fuel_alert_wake_lock);
298
299                 schedule_delayed_work(&fuelgauge->isr_work, 0);
300
301                 fuelgauge->is_fuel_alerted = fuel_alerted;
302         }
303
304         return IRQ_HANDLED;
305 }
306
307 static int sec_fg_create_attrs(struct device *dev)
308 {
309         int i, rc;
310
311         for (i = 0; i < ARRAY_SIZE(sec_fg_attrs); i++) {
312                 rc = device_create_file(dev, &sec_fg_attrs[i]);
313                 if (rc)
314                         goto create_attrs_failed;
315         }
316         goto create_attrs_succeed;
317
318 create_attrs_failed:
319         dev_err(dev, "%s: failed (%d)\n", __func__, rc);
320         while (i--)
321                 device_remove_file(dev, &sec_fg_attrs[i]);
322 create_attrs_succeed:
323         return rc;
324 }
325
326 ssize_t sec_fg_show_attrs(struct device *dev,
327                                 struct device_attribute *attr, char *buf)
328 {
329         const ptrdiff_t offset = attr - sec_fg_attrs;
330         int i = 0;
331
332         switch (offset) {
333         case FG_REG:
334         case FG_DATA:
335         case FG_REGS:
336 //              i = sec_hal_fg_show_attrs(dev, offset, buf);
337                 break;
338         default:
339                 i = -EINVAL;
340                 break;
341         }
342
343         return i;
344 }
345
346 ssize_t sec_fg_store_attrs(struct device *dev,
347                                 struct device_attribute *attr,
348                                 const char *buf, size_t count)
349 {
350         const ptrdiff_t offset = attr - sec_fg_attrs;
351         int ret = 0;
352
353         switch (offset) {
354         case FG_REG:
355         case FG_DATA:
356 //              ret = sec_hal_fg_store_attrs(dev, offset, buf, count);
357                 break;
358         default:
359                 ret = -EINVAL;
360                 break;
361         }
362         return ret;
363 }
364
365 #if defined(CONFIG_FUELGAUGE_MFD) || defined(CONFIG_FUELGAUGE_SPRD4SAMSUNG27X3)
366 static int sec_fuelgauge_probe(struct platform_device *pdev)
367 {
368         struct sec_fuelgauge_info *fuelgauge;
369 #ifndef CONFIG_FUELGAUGE_SPRD4SAMSUNG27X3
370         sec_fuelgauge_dev_t *mfd_dev = dev_get_drvdata(pdev->dev.parent);
371         sec_fuelgauge_pdata_t *pdata = dev_get_platdata(mfd_dev->dev);
372 #else
373        sec_battery_platform_data_t *pdata = dev_get_platdata(&pdev->dev);
374 #endif
375         int ret = 0;
376         bool fuelalert_init_ret = false;
377         union power_supply_propval raw_soc_val;
378
379         dev_info(&pdev->dev,
380                 "%s: SEC Fuelgauge Driver Loading\n", __func__);
381
382         fuelgauge = kzalloc(sizeof(*fuelgauge), GFP_KERNEL);
383         if (!fuelgauge)
384                 return -ENOMEM;
385
386         platform_set_drvdata(pdev, fuelgauge);
387 #ifndef CONFIG_FUELGAUGE_SPRD4SAMSUNG27X3
388         fuelgauge->client = mfd_dev->i2c;
389         fuelgauge->pdata = pdata->fuelgauge_data;
390 #else
391         fuelgauge->pdata = pdata;
392 #endif
393
394         mutex_init(&fuelgauge->fg_lock);
395
396         if (pdev->dev.of_node) {
397                 pdata = devm_kzalloc(&pdev->dev,
398                                 sizeof(sec_battery_platform_data_t),
399                                 GFP_KERNEL);
400                 if (!pdata) {
401                         dev_err(&pdev->dev, "Failed to allocate memory\n");
402                         ret = -ENOMEM;
403                         goto err_free;
404                 }
405
406                 fuelgauge->pdata = pdata;
407 #ifdef CONFIG_OF
408                 if (sec_fg_dt_init(pdev->dev.of_node, &pdev->dev, fuelgauge->pdata))
409                         dev_err(&pdev->dev,
410                                 "%s: Failed to get fuel_int\n", __func__);
411 #endif
412         }
413
414         fuelgauge->psy_fg.name          = "sec-fuelgauge";
415         fuelgauge->psy_fg.type          = POWER_SUPPLY_TYPE_UNKNOWN;
416         fuelgauge->psy_fg.get_property  = sec_fg_get_property;
417         fuelgauge->psy_fg.set_property  = sec_fg_set_property;
418         fuelgauge->psy_fg.properties    = sec_fuelgauge_props;
419         fuelgauge->psy_fg.num_properties =
420                 ARRAY_SIZE(sec_fuelgauge_props);
421         fuelgauge->capacity_max = fuelgauge->pdata->capacity_max;
422         raw_soc_val.intval = SEC_FUELGAUGE_CAPACITY_TYPE_RAW;
423         sec_hal_fg_get_property(fuelgauge,
424                         POWER_SUPPLY_PROP_CAPACITY, &raw_soc_val);
425         raw_soc_val.intval /= 10;
426         if(raw_soc_val.intval > fuelgauge->pdata->capacity_max)
427                 sec_fg_calculate_dynamic_scale(fuelgauge);
428
429         if (!fuelgauge->pdata->fg_gpio_init()) {
430                 dev_err(&pdev->dev,
431                         "%s: Failed to Initialize GPIO\n", __func__);
432                 goto err_free;
433         }
434
435         if (!sec_hal_fg_init(fuelgauge)) {
436                 dev_err(&pdev->dev,
437                         "%s: Failed to Initialize Fuelgauge\n", __func__);
438                 goto err_free;
439         }
440
441         ret = power_supply_register(&pdev->dev, &fuelgauge->psy_fg);
442         if (ret) {
443                 dev_err(&pdev->dev,
444                         "%s: Failed to Register psy_fg\n", __func__);
445                 goto err_free;
446         }
447
448         fuelgauge->is_fuel_alerted = false;
449         if (fuelgauge->pdata->fuel_alert_soc >= 0) {
450                 fuelalert_init_ret =
451                         sec_hal_fg_fuelalert_init(fuelgauge,
452                                         fuelgauge->pdata->fuel_alert_soc);
453                 if (fuelalert_init_ret)
454                         wake_lock_init(&fuelgauge->fuel_alert_wake_lock,
455                                 WAKE_LOCK_SUSPEND, "fuel_alerted");
456                 else {
457                         dev_err(&pdev->dev,
458                                 "%s: Failed to Initialize Fuel-alert\n",
459                                 __func__);
460                         goto err_irq;
461                 }
462         }
463 #ifndef CONFIG_FUELGAUGE_SPRD4SAMSUNG27X3
464         if (fuelgauge->pdata->fg_irq) {
465                 INIT_DELAYED_WORK_DEFERRABLE(
466                         &fuelgauge->isr_work, sec_fg_isr_work);
467
468                 fuelgauge->fg_irq = gpio_to_irq(fuelgauge->pdata->fg_irq);
469
470                 ret = request_threaded_irq(fuelgauge->fg_irq,
471                                 NULL, sec_fg_irq_thread,
472                                 fuelgauge->pdata->fg_irq_attr,
473                                 "fuelgauge-irq", fuelgauge);
474                 if (ret) {
475                         dev_err(&pdev->dev,
476                                 "%s: Failed to Reqeust IRQ\n", __func__);
477                         goto err_supply_unreg;
478                 }
479
480                 ret = enable_irq_wake(fuelgauge->pdata->fg_irq);
481                 if (ret < 0)
482                         dev_err(&pdev->dev,
483                                 "%s: Failed to Enable Wakeup Source(%d)\n",
484                                 __func__, ret);
485         }
486 #endif
487         fuelgauge->initial_update_of_soc = true;
488
489         ret = sec_fg_create_attrs(fuelgauge->psy_fg.dev);
490         if (ret) {
491                 dev_err(&pdev->dev,
492                         "%s : Failed to create_attrs\n", __func__);
493                 goto err_irq;
494         }
495
496         dev_info(&pdev->dev,
497                 "%s: SEC Fuelgauge Driver Loaded\n", __func__);
498         return 0;
499
500 err_irq:
501         if (fuelgauge->pdata->fg_irq)
502                 free_irq(fuelgauge->pdata->fg_irq, fuelgauge);
503         if (fuelalert_init_ret)
504         wake_lock_destroy(&fuelgauge->fuel_alert_wake_lock);
505 err_supply_unreg:
506         power_supply_unregister(&fuelgauge->psy_fg);
507 err_free:
508         mutex_destroy(&fuelgauge->fg_lock);
509         kfree(fuelgauge);
510
511         return ret;
512 }
513
514 static int sec_fuelgauge_remove(struct platform_device *pdev)
515 {
516         return 0;
517 }
518
519 static int sec_fuelgauge_suspend(struct device *dev)
520 {
521         struct sec_fuelgauge_info *fuelgauge = dev_get_drvdata(dev);
522
523         if (!sec_hal_fg_suspend(fuelgauge))
524                 dev_err(dev,
525                         "%s: Failed to Suspend Fuelgauge\n", __func__);
526
527         return 0;
528 }
529
530 static int sec_fuelgauge_resume(struct device *dev)
531 {
532         struct sec_fuelgauge_info *fuelgauge = dev_get_drvdata(dev);
533
534         if (!sec_hal_fg_resume(fuelgauge))
535                 dev_err(dev,
536                         "%s: Failed to Resume Fuelgauge\n", __func__);
537
538         if (fuelgauge->pdata->capacity_calculation_type &
539                 SEC_FUELGAUGE_CAPACITY_TYPE_ATOMIC)
540                 fuelgauge->initial_update_of_soc = true;
541
542         return 0;
543 }
544
545 static void sec_fuelgauge_shutdown(struct device *dev)
546 {
547 }
548
549 static const struct dev_pm_ops sec_fuelgauge_pm_ops = {
550         .suspend = sec_fuelgauge_suspend,
551         .resume = sec_fuelgauge_resume,
552 };
553
554 #ifdef CONFIG_OF
555 static struct of_device_id sec_fuelgauge_dt_ids[] = {
556         { .compatible = "samsung,sec-fuelgauge" },
557         { }
558 };
559 MODULE_DEVICE_TABLE(of, sec_fuelgauge_dt_ids);
560 #endif /* CONFIG_OF */
561
562 static struct platform_driver sec_fuelgauge_driver = {
563         .driver = {
564                 .name = "sec-fuelgauge",
565                 .pm = &sec_fuelgauge_pm_ops,
566                 .shutdown = sec_fuelgauge_shutdown,
567 #ifdef CONFIG_OF
568                 .of_match_table = sec_fuelgauge_dt_ids,
569 #endif
570         },
571         .probe  = sec_fuelgauge_probe,
572         .remove = sec_fuelgauge_remove,
573 };
574
575 static int __init sec_fuelgauge_init(void)
576 {
577         pr_info("[%s] start !!!!! \n", __func__);
578         return platform_driver_register(&sec_fuelgauge_driver);
579 }
580
581 static void __exit sec_fuelgauge_exit(void)
582 {
583         platform_driver_unregister(&sec_fuelgauge_driver);
584 }
585
586 #else
587 static int sec_fuelgauge_probe(struct i2c_client *client,
588                                                 const struct i2c_device_id *id)
589 {
590         struct sec_fuelgauge_info *fuelgauge;
591         struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
592         int ret = 0;
593         bool fuelalert_init_ret = false;
594         union power_supply_propval raw_soc_val;
595
596         dev_dbg(&client->dev,
597                 "%s: SEC Fuelgauge Driver Loading\n", __func__);
598
599         if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
600                 return -EIO;
601
602         fuelgauge = kzalloc(sizeof(*fuelgauge), GFP_KERNEL);
603         if (!fuelgauge)
604                 return -ENOMEM;
605
606         mutex_init(&fuelgauge->fg_lock);
607
608         fuelgauge->client = client;
609         fuelgauge->pdata = client->dev.platform_data;
610
611         i2c_set_clientdata(client, fuelgauge);
612
613         fuelgauge->psy_fg.name          = "sec-fuelgauge";
614         fuelgauge->psy_fg.type          = POWER_SUPPLY_TYPE_UNKNOWN;
615         fuelgauge->psy_fg.get_property  = sec_fg_get_property;
616         fuelgauge->psy_fg.set_property  = sec_fg_set_property;
617         fuelgauge->psy_fg.properties    = sec_fuelgauge_props;
618         fuelgauge->psy_fg.num_properties =
619                 ARRAY_SIZE(sec_fuelgauge_props);
620         fuelgauge->capacity_max = fuelgauge->pdata->capacity_max;
621         raw_soc_val.intval = SEC_FUELGAUGE_CAPACITY_TYPE_RAW;
622         sec_hal_fg_get_property(fuelgauge->client,
623                         POWER_SUPPLY_PROP_CAPACITY, &raw_soc_val);
624         raw_soc_val.intval /= 10;
625         if(raw_soc_val.intval > fuelgauge->pdata->capacity_max)
626                 sec_fg_calculate_dynamic_scale(fuelgauge);
627
628         if (!fuelgauge->pdata->fg_gpio_init()) {
629                 dev_err(&client->dev,
630                         "%s: Failed to Initialize GPIO\n", __func__);
631                 goto err_free;
632         }
633
634         if (!sec_hal_fg_init(fuelgauge->client)) {
635                 dev_err(&client->dev,
636                         "%s: Failed to Initialize Fuelgauge\n", __func__);
637                 goto err_free;
638         }
639
640         ret = power_supply_register(&client->dev, &fuelgauge->psy_fg);
641         if (ret) {
642                 dev_err(&client->dev,
643                         "%s: Failed to Register psy_fg\n", __func__);
644                 goto err_free;
645         }
646 #if 0
647         fuelgauge->is_fuel_alerted = false;
648         if (fuelgauge->pdata->fuel_alert_soc >= 0) {
649                 fuelalert_init_ret =
650                         sec_hal_fg_fuelalert_init(fuelgauge->client,
651                                         fuelgauge->pdata->fuel_alert_soc);
652                 if (fuelalert_init_ret)
653                         wake_lock_init(&fuelgauge->fuel_alert_wake_lock,
654                                 WAKE_LOCK_SUSPEND, "fuel_alerted");
655                 else {
656                         dev_err(&client->dev,
657                                 "%s: Failed to Initialize Fuel-alert\n",
658                                 __func__);
659                         goto err_irq;
660                 }
661         }
662
663         if (fuelgauge->pdata->fg_irq) {
664                 INIT_DELAYED_WORK(&fuelgauge->isr_work, sec_fg_isr_work);
665
666                 ret = request_threaded_irq(fuelgauge->pdata->fg_irq,
667                                 NULL, sec_fg_irq_thread,
668                                 fuelgauge->pdata->fg_irq_attr,
669                                 "fuelgauge-irq", fuelgauge);
670                 if (ret) {
671                         dev_err(&client->dev,
672                                 "%s: Failed to Reqeust IRQ\n", __func__);
673                         goto err_supply_unreg;
674                 }
675
676                 ret = enable_irq_wake(fuelgauge->pdata->fg_irq);
677                 if (ret < 0)
678                         dev_err(&client->dev,
679                                 "%s: Failed to Enable Wakeup Source(%d)\n",
680                                 __func__, ret);
681         }
682 #endif
683         fuelgauge->initial_update_of_soc = true;
684
685         ret = sec_fg_create_attrs(fuelgauge->psy_fg.dev);
686         if (ret) {
687                 dev_err(&client->dev,
688                         "%s : Failed to create_attrs\n", __func__);
689                 goto err_irq;
690         }
691
692         dev_dbg(&client->dev,
693                 "%s: SEC Fuelgauge Driver Loaded\n", __func__);
694         return 0;
695
696 err_irq:
697         if (fuelgauge->pdata->fg_irq)
698                 free_irq(fuelgauge->pdata->fg_irq, fuelgauge);
699 err_supply_unreg:
700         power_supply_unregister(&fuelgauge->psy_fg);
701 err_free:
702         mutex_destroy(&fuelgauge->fg_lock);
703         kfree(fuelgauge);
704
705         return ret;
706 }
707
708 static int sec_fuelgauge_remove(struct i2c_client *client)
709 {
710         struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client);
711
712         if (fuelgauge->pdata->fuel_alert_soc >= 0)
713                 wake_lock_destroy(&fuelgauge->fuel_alert_wake_lock);
714
715         return 0;
716 }
717
718 static int sec_fuelgauge_suspend(struct device *dev)
719 {
720         struct i2c_client *client =
721                 container_of(dev, struct i2c_client, dev);
722
723         if (!sec_hal_fg_suspend(client))
724                 dev_err(dev, "%s: Failed to Suspend Fuelgauge\n", __func__);
725
726         return 0;
727 }
728
729 static int sec_fuelgauge_resume(struct device *dev)
730 {
731         struct i2c_client *client =
732                 container_of(dev, struct i2c_client, dev);
733         struct sec_fuelgauge_info *fuelgauge = i2c_get_clientdata(client);
734
735         if (!sec_hal_fg_resume(client))
736                 dev_err(dev, "%s: Failed to Resume Fuelgauge\n", __func__);
737
738         if (fuelgauge->pdata->capacity_calculation_type &
739                 SEC_FUELGAUGE_CAPACITY_TYPE_ATOMIC)
740                 fuelgauge->initial_update_of_soc = true;
741
742         return 0;
743 }
744
745 static void sec_fuelgauge_shutdown(struct device *dev)
746 {
747 }
748
749 static const struct i2c_device_id sec_fuelgauge_id[] = {
750         {"sec-fuelgauge", 0},
751         {}
752 };
753
754 MODULE_DEVICE_TABLE(i2c, sec_fuelgauge_id);
755
756 static const struct dev_pm_ops sec_fuelgauge_pm_ops = {
757         .suspend = sec_fuelgauge_suspend,
758         .resume = sec_fuelgauge_resume,
759 };
760
761 static struct i2c_driver sec_fuelgauge_driver = {
762         .driver = {
763                    .name = "sec-fuelgauge",
764                    .owner = THIS_MODULE,
765                    .pm = &sec_fuelgauge_pm_ops,
766                    .shutdown = sec_fuelgauge_shutdown,
767                    },
768         .probe  = sec_fuelgauge_probe,
769         .remove = sec_fuelgauge_remove,
770         .id_table   = sec_fuelgauge_id,
771 };
772
773 static int __init sec_fuelgauge_init(void)
774 {
775         return i2c_add_driver(&sec_fuelgauge_driver);
776 }
777
778 static void __exit sec_fuelgauge_exit(void)
779 {
780         i2c_del_driver(&sec_fuelgauge_driver);
781 }
782 #endif
783
784 module_init(sec_fuelgauge_init);
785 module_exit(sec_fuelgauge_exit);
786
787 MODULE_DESCRIPTION("Samsung Fuel Gauge Driver");
788 MODULE_AUTHOR("Samsung Electronics");
789 MODULE_LICENSE("GPL");