upload tizen1.0 source
[kernel/linux-2.6.36.git] / arch / arm / mach-s5pv310 / charger-p8.c
1 /*
2  * linux/arch/arm/mach-s5pv310/charger-p8.c
3  * COPYRIGHT(C) 2011
4  * MyungJoo Ham <myungjoo.ham@samsung.com>
5  *
6  * P8 Board Charger Support with Charger-Manager Framework
7  *
8  */
9
10 #include <asm/io.h>
11
12 #include <linux/err.h>
13 #include <linux/platform_device.h>
14 #include <linux/ntc.h>
15 #include <linux/rtc/rtc-s3c.h>
16 #include <linux/regulator/consumer.h>
17 #include <linux/power/charger-manager.h>
18 #include <linux/power/max17042_battery.h>
19 #include <linux/mfd/max8997.h>
20
21 #include <plat/adc.h>
22 #include <plat/pm.h>
23
24 #include <mach/regs-pmu.h>
25 #include <mach/irqs.h>
26
27 #include "../../../fs/sysfs/sysfs.h"
28
29 /* Temperatures in milli-centigrade */
30 #define SECBATTSPEC_TEMP_HIGH           (63 * 1000)
31 #define SECBATTSPEC_TEMP_HIGH_REC       (58 * 1000)
32 #define SECBATTSPEC_TEMP_LOW            (-5 * 1000)
33 #define SECBATTSPEC_TEMP_LOW_REC        (0 * 1000)
34
35 #ifdef CONFIG_SENSORS_NTC_THERMISTOR
36 static unsigned int read_thermistor_uV(void)
37 {
38         struct s3c_adc_request req = {
39                 .list           = NULL,
40                 .callback       = NULL,
41                 .param          = 0,
42                 .channel        = 7, /* XADCAIN_7 */
43         };
44
45         return s3c_adc_convert_uV(s3c_adc_get(&req));
46 }
47
48 static struct ntc_thermistor_platform_data ncp15wb473_pdata = {
49         .read_uV        = read_thermistor_uV,
50         .pullup_uV      = 3300000, /* VADC_3.3V_C210 */
51         .pullup_ohm     = 100000,
52         .pulldown_ohm   = 100000,
53         .connect        = NTC_CONNECTED_GROUND,
54 };
55
56 struct platform_device p8_ncp15wb473_thermistor;
57 static const char *thermistor_dirent = "temp1_input";
58 static struct device_attribute *thermistor_attr;
59 static int __read_thermistor_mC(void)
60 {
61         int err = 0;
62         int mC = 25000;
63         char buf[32];
64         int count;
65
66         if (thermistor_attr == NULL) {
67                 struct kobject *ntc;
68                 struct sysfs_dirent *ntc_d;
69
70                 ntc = &p8_ncp15wb473_thermistor.dev.kobj;
71                 ntc_d = sysfs_get_dirent(ntc->sd,
72                                         get_ktype(ntc)->namespace(ntc),
73                                         thermistor_dirent);
74                 if (!ntc_d || sysfs_type(ntc_d) != SYSFS_KOBJ_ATTR) {
75                         err = -ENODEV;
76                         dev_err(&p8_ncp15wb473_thermistor.dev, "Cannot init"
77                                         "ialize ncp15wb473's dirent info.\n");
78                         if (ntc_d)
79                                 sysfs_put(ntc_d);
80                         goto out_seterr;
81                 }
82                 thermistor_attr = container_of(ntc_d->s_attr.attr,
83                                                 struct device_attribute, attr);
84
85                 sysfs_put(ntc_d);
86         }
87
88         if (IS_ERR(thermistor_attr)) {
89                 dev_warn(&p8_ncp15wb473_thermistor.dev, "Cannot read.\n");
90                 goto out;
91         }
92
93         count = thermistor_attr->show(&p8_ncp15wb473_thermistor.dev,
94                                         thermistor_attr, buf);
95         WARN_ON(count >= 31);
96         sscanf(buf, "%d", &mC);
97
98         goto out;
99 out_seterr:
100         thermistor_attr = ERR_PTR(err);
101 out:
102         return mC;
103 }
104 #else /* CONFIG_SENSORS_NTC_THERMISTOR */
105 static int __read_thermistor_mC(void)
106 {
107         return 25000; /* 25 mili-Centigrade */
108 }
109 #endif /* CONFIG_SENSORS_NTC_THERMISTOR */
110
111 static bool s3c_wksrc_rtc_alarm(void)
112 {
113         u32 reg = s3c_suspend_wakeup_stat & S5P_WAKEUP_STAT_WKSRC_MASK;
114
115         if ((reg & S5P_WAKEUP_STAT_RTCALARM) &&
116             !(reg & ~S5P_WAKEUP_STAT_RTCALARM))
117                 return true; /* yes, it is */
118
119         return false;
120 }
121
122 enum temp_stat { TEMP_OK = 0, TEMP_HOT = 1, TEMP_COLD = -1 };
123
124 static int p8_thermistor_ck(int *mC)
125 {
126         static enum temp_stat state = TEMP_OK;
127
128         *mC = __read_thermistor_mC();
129         switch (state) {
130         case TEMP_OK:
131                 if (*mC >= SECBATTSPEC_TEMP_HIGH)
132                         state = TEMP_HOT;
133                 else if (*mC <= SECBATTSPEC_TEMP_LOW)
134                         state = TEMP_COLD;
135                 break;
136         case TEMP_HOT:
137                 if (*mC <= SECBATTSPEC_TEMP_LOW)
138                         state = TEMP_COLD;
139                 else if (*mC < SECBATTSPEC_TEMP_HIGH_REC)
140                         state = TEMP_OK;
141                 break;
142         case TEMP_COLD:
143                 if (*mC >= SECBATTSPEC_TEMP_HIGH)
144                         state = TEMP_HOT;
145                 else if (*mC > SECBATTSPEC_TEMP_LOW_REC)
146                         state = TEMP_OK;
147         default:
148                 pr_err("%s has invalid state %d\n", __func__, state);
149         }
150
151         return state;
152 }
153
154 static char *p8_charger_stats[] = { "max8997_pmic", "max8903_charger", NULL };
155 static struct regulator_bulk_data p8_chargers[] = {
156         { .supply = "vinchg1", },
157         { .supply = "vinchg2", },
158 };
159 static struct charger_irq p8_chg_irqs[] = {
160         { IRQ_PMIC_BASE + MAX8997_PMICIRQ_TOPOFFR, 0, CM_IRQ_BATT_FULL,
161           true, "Batt Full" },
162         { IRQ_FUEL_BASE + MAX17042_IRQ_Battery_Removed, 0, CM_IRQ_BATT_OUT,
163           true, "Batt Out" },
164         { IRQ_PMIC_BASE + MAX8997_PMICIRQ_CHGRSTF, 0, CM_IRQ_CHG_START_STOP,
165           true, "CHG STOP" },
166         { IRQ_PMIC_BASE + MAX8997_PMICIRQ_MBCHGTMEXPD, 0, CM_IRQ_OTHERS,
167           true, "CHG TIMEOUT" },
168         { IRQ_PMIC_BASE + MAX8997_PMICIRQ_DCINOVP, 0, CM_IRQ_OTHERS,
169           true, "CHG OVERVOLT" },
170         { IRQ_PMIC_BASE + MAX8997_PMICIRQ_CHGINS, 0, CM_IRQ_EXT_PWR_IN_OUT,
171           true, "CHG PWR Insert" },
172         { IRQ_PMIC_BASE + MAX8997_PMICIRQ_CHGRM, 0, CM_IRQ_EXT_PWR_IN_OUT,
173           true, "CHG PWR Remove" },
174         { 0, 0, 0, false, NULL },
175 };
176 static struct charger_desc p8_charger_desc = {
177         .psy_name               = "battery",
178         .polling_interval_ms    = 30000,
179         .polling_mode           = CM_POLL_CHARGING_ONLY,
180         .fullbatt_vchkdrop_ms   = 30000,
181         .fullbatt_vchkdrop_uV   = 100000,
182         .fullbatt_uV            = 4200000,
183         .battery_present        = CM_FUEL_GAUGE,
184         .psy_charger_stat       = p8_charger_stats,
185         .charger_regulators     = p8_chargers,
186         .num_charger_regulators = ARRAY_SIZE(p8_chargers),
187         .psy_fuel_gauge         = "max17042_battery",
188         .irqs                   = p8_chg_irqs,
189
190         .is_temperature_error   = p8_thermistor_ck,
191         .measure_ambient_temp   = true,
192         .measure_battery_temp   = false,
193 };
194
195 struct charger_global_desc p8_charger_g_desc = {
196         .rtc = "rtc1",
197         .is_rtc_only_wakeup_reason = s3c_wksrc_rtc_alarm,
198         .assume_timer_stops_in_suspend  = true,
199 };
200
201 #ifdef CONFIG_SENSORS_NTC_THERMISTOR
202 struct platform_device p8_ncp15wb473_thermistor = {
203         .name                   = "ncp15wb473",
204         .dev                    = {
205                 .platform_data = &ncp15wb473_pdata,
206         },
207 };
208 #endif
209
210 struct platform_device p8_charger_manager = {
211         .name                   = "charger-manager",
212         .dev                    = {
213                 .platform_data = &p8_charger_desc,
214         },
215 };