upload tizen1.0 source
[kernel/linux-2.6.36.git] / arch / arm / mach-s5pv310 / charger-q1.c
1 /*
2  * linux/arch/arm/mach-s5pv310/charger-q1.c
3  * COPYRIGHT(C) 2011
4  * MyungJoo Ham <myungjoo.ham@samsung.com>
5  *
6  * U1 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 #if defined(CONFIG_CHARGERCTRL_MAX8922) || defined(CONFIG_SMB328)
43                 .channel        = 7, /* XADCAIN_7 */
44 #elif defined(CONFIG_CHARGERCTRL_MAX8997)
45                 .channel        = 6, /* XADCAIN_6 */
46 #endif
47         };
48
49         return s3c_adc_convert_uV(s3c_adc_get(&req));
50 }
51
52 static struct ntc_thermistor_platform_data ncp15wb473_pdata = {
53         .read_uV        = read_thermistor_uV,
54         .pullup_uV      = 3300000, /* VADC_3.3V_C210 */
55         .pullup_ohm     = 100000, /* R613 in SLP 7 0105 */
56         .pulldown_ohm   = 100000, /* R615 in SLP 7 0105 */
57         .connect        = NTC_CONNECTED_GROUND,
58 };
59
60 struct platform_device q1_ncp15wb473_thermistor;
61 static const char *thermistor_dirent = "temp1_input";
62 static struct device_attribute *thermistor_attr;
63 static int __read_thermistor_mC(void)
64 {
65         int err = 0;
66         int mC = 25000;
67         char buf[32];
68         int count;
69
70         if (thermistor_attr == NULL) {
71                 struct kobject *ntc;
72                 struct sysfs_dirent *ntc_d;
73
74                 ntc = &q1_ncp15wb473_thermistor.dev.kobj;
75                 ntc_d = sysfs_get_dirent(ntc->sd,
76                                         get_ktype(ntc)->namespace(ntc),
77                                         thermistor_dirent);
78                 if (!ntc_d || sysfs_type(ntc_d) != SYSFS_KOBJ_ATTR) {
79                         err = -ENODEV;
80                         dev_err(&q1_ncp15wb473_thermistor.dev, "Cannot init"
81                                         "ialize ncp15wb473's dirent info.\n");
82                         if (ntc_d)
83                                 sysfs_put(ntc_d);
84                         goto out_seterr;
85                 }
86                 thermistor_attr = container_of(ntc_d->s_attr.attr,
87                                                 struct device_attribute, attr);
88
89                 sysfs_put(ntc_d);
90         }
91
92         if (IS_ERR(thermistor_attr)) {
93                 dev_warn(&q1_ncp15wb473_thermistor.dev, "Cannot read.\n");
94                 goto out;
95         }
96
97         count = thermistor_attr->show(&q1_ncp15wb473_thermistor.dev,
98                                         thermistor_attr, buf);
99         WARN_ON(count >= 31);
100         sscanf(buf, "%d", &mC);
101
102         goto out;
103 out_seterr:
104         thermistor_attr = ERR_PTR(err);
105 out:
106         return mC;
107 }
108 #else /* CONFIG_SENSORS_NTC_THERMISTOR */
109 static int __read_thermistor_mC(void)
110 {
111         return 25000; /* 25 mili-Centigrade */
112 }
113 #endif /* CONFIG_SENSORS_NTC_THERMISTOR */
114
115 static bool s3c_wksrc_rtc_alarm(void)
116 {
117         u32 reg = s3c_suspend_wakeup_stat & S5P_WAKEUP_STAT_WKSRC_MASK;
118
119         if ((reg & S5P_WAKEUP_STAT_RTCALARM) &&
120             !(reg & ~S5P_WAKEUP_STAT_RTCALARM))
121                 return true; /* yes, it is */
122
123         return false;
124 }
125
126 enum temp_stat { TEMP_OK = 0, TEMP_HOT = 1, TEMP_COLD = -1 };
127
128 static int q1_thermistor_ck(int *mC)
129 {
130         static enum temp_stat state = TEMP_OK;
131
132         *mC = __read_thermistor_mC();
133         switch (state) {
134         case TEMP_OK:
135                 if (*mC >= SECBATTSPEC_TEMP_HIGH)
136                         state = TEMP_HOT;
137                 else if (*mC <= SECBATTSPEC_TEMP_LOW)
138                         state = TEMP_COLD;
139                 break;
140         case TEMP_HOT:
141                 if (*mC <= SECBATTSPEC_TEMP_LOW)
142                         state = TEMP_COLD;
143                 else if (*mC < SECBATTSPEC_TEMP_HIGH_REC)
144                         state = TEMP_OK;
145                 break;
146         case TEMP_COLD:
147                 if (*mC >= SECBATTSPEC_TEMP_HIGH)
148                         state = TEMP_HOT;
149                 else if (*mC > SECBATTSPEC_TEMP_LOW_REC)
150                         state = TEMP_OK;
151         default:
152                 pr_err("%s has invalid state %d\n", __func__, state);
153         }
154
155         return state;
156 }
157
158 static char *q1_charger_stats[] = {
159 #if defined(CONFIG_SMB328_CHARGER)
160         "smb328-charger",
161 #endif
162 #if defined(CONFIG_CHARGERCTRL_MAX8997)
163         "max8997_pmic",
164 #endif
165         NULL };
166
167 static struct regulator_bulk_data q1_chargers[] = {
168         { .supply = "vinchg2", },
169 };
170 static struct charger_irq q1_chg_irqs[] = {
171         { IRQ_PMIC_BASE + MAX8997_PMICIRQ_TOPOFFR, 0, CM_IRQ_BATT_FULL,
172           true, "Batt Full" },
173         { IRQ_FUEL_BASE + MAX17042_IRQ_Battery_Removed, 0, CM_IRQ_BATT_OUT,
174           true, "Batt Out" },
175         { IRQ_PMIC_BASE + MAX8997_PMICIRQ_CHGRSTF, 0, CM_IRQ_CHG_START_STOP,
176           true, "CHG STOP" },
177         { IRQ_PMIC_BASE + MAX8997_PMICIRQ_MBCHGTMEXPD, 0, CM_IRQ_OTHERS,
178           true, "CHG TIMEOUT" },
179         { IRQ_PMIC_BASE + MAX8997_PMICIRQ_DCINOVP, 0, CM_IRQ_OTHERS,
180           true, "CHG OVERVOLT" },
181         { IRQ_PMIC_BASE + MAX8997_PMICIRQ_CHGINS, 0, CM_IRQ_EXT_PWR_IN_OUT,
182           true, "CHG PWR Insert" },
183         { IRQ_PMIC_BASE + MAX8997_PMICIRQ_CHGRM, 0, CM_IRQ_EXT_PWR_IN_OUT,
184           true, "CHG PWR Remove" },
185         { 0, 0, 0, false, NULL },
186
187 };
188 static struct charger_desc q1_charger_desc = {
189         .psy_name               = "battery",
190         .polling_interval_ms    = 30000,
191         .polling_mode           = CM_POLL_EXTERNAL_POWER_ONLY,
192         .fullbatt_vchkdrop_ms   = 30000,
193         .fullbatt_vchkdrop_uV   = 50000,
194         .fullbatt_uV            = 4200000,
195         .battery_present        = CM_CHARGER_STAT,
196 //      .battery_present        = CM_FUEL_GAUGE,
197         .psy_charger_stat       = q1_charger_stats,
198         .charger_regulators     = q1_chargers,
199         .num_charger_regulators = ARRAY_SIZE(q1_chargers),
200         .psy_fuel_gauge         = "max17042_battery",
201         .irqs                   = q1_chg_irqs,
202
203         .is_temperature_error   = q1_thermistor_ck,
204         .measure_ambient_temp   = true,
205         .measure_battery_temp   = true,
206         .soc_margin             = 0,
207 };
208
209 struct charger_global_desc q1_charger_g_desc = {
210         .rtc = "rtc1",
211         .is_rtc_only_wakeup_reason = s3c_wksrc_rtc_alarm,
212         .assume_timer_stops_in_suspend  = true,
213 };
214
215 #ifdef CONFIG_SENSORS_NTC_THERMISTOR
216 struct platform_device q1_ncp15wb473_thermistor = {
217         .name                   = "ncp15wb473",
218         .dev                    = {
219                 .platform_data = &ncp15wb473_pdata,
220         },
221 };
222 #endif
223
224 struct platform_device q1_charger_manager = {
225         .name                   = "charger-manager",
226         .dev                    = {
227                 .platform_data = &q1_charger_desc,
228         },
229 };