blob: 1a163a48150cbbe8476b712c589dcc8a9e91974b [file] [log] [blame]
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001/*
Dipen Parmar4ceb5c72013-01-02 12:09:42 +05302 * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
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 * Qualcomm's PM8921/PM8018 ADC Arbiter driver
14 */
15#define pr_fmt(fmt) "%s: " fmt, __func__
16
17#include <linux/kernel.h>
18#include <linux/err.h>
19#include <linux/init.h>
20#include <linux/slab.h>
21#include <linux/delay.h>
22#include <linux/mutex.h>
23#include <linux/hwmon.h>
24#include <linux/module.h>
25#include <linux/debugfs.h>
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -070026#include <linux/interrupt.h>
27#include <linux/completion.h>
28#include <linux/hwmon-sysfs.h>
29#include <linux/mfd/pm8xxx/mpp.h>
30#include <linux/platform_device.h>
31#include <linux/mfd/pm8xxx/core.h>
32#include <linux/regulator/consumer.h>
33#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
Siddartha Mohanadossf9dfe1b2012-08-14 15:15:42 -070034#include <mach/msm_xo.h>
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -070035
36/* User Bank register set */
37#define PM8XXX_ADC_ARB_USRP_CNTRL1 0x197
38#define PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB BIT(0)
39#define PM8XXX_ADC_ARB_USRP_CNTRL1_RSV1 BIT(1)
40#define PM8XXX_ADC_ARB_USRP_CNTRL1_RSV2 BIT(2)
41#define PM8XXX_ADC_ARB_USRP_CNTRL1_RSV3 BIT(3)
42#define PM8XXX_ADC_ARB_USRP_CNTRL1_RSV4 BIT(4)
43#define PM8XXX_ADC_ARB_USRP_CNTRL1_RSV5 BIT(5)
44#define PM8XXX_ADC_ARB_USRP_CNTRL1_EOC BIT(6)
45#define PM8XXX_ADC_ARB_USRP_CNTRL1_REQ BIT(7)
46
47#define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL 0x198
48#define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_RSV0 BIT(0)
49#define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_RSV1 BIT(1)
50#define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_PREMUX0 BIT(2)
51#define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_PREMUX1 BIT(3)
52#define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_SEL0 BIT(4)
53#define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_SEL1 BIT(5)
54#define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_SEL2 BIT(6)
55#define PM8XXX_ADC_ARB_USRP_AMUX_CNTRL_SEL3 BIT(7)
56
57#define PM8XXX_ADC_ARB_USRP_ANA_PARAM 0x199
58#define PM8XXX_ADC_ARB_USRP_DIG_PARAM 0x19A
59#define PM8XXX_ADC_ARB_USRP_DIG_PARAM_SEL_SHIFT0 BIT(0)
60#define PM8XXX_ADC_ARB_USRP_DIG_PARAM_SEL_SHIFT1 BIT(1)
61#define PM8XXX_ADC_ARB_USRP_DIG_PARAM_CLK_RATE0 BIT(2)
62#define PM8XXX_ADC_ARB_USRP_DIG_PARAM_CLK_RATE1 BIT(3)
63#define PM8XXX_ADC_ARB_USRP_DIG_PARAM_EOC BIT(4)
64#define PM8XXX_ADC_ARB_USRP_DIG_PARAM_DEC_RATE0 BIT(5)
65#define PM8XXX_ADC_ARB_USRP_DIG_PARAM_DEC_RATE1 BIT(6)
66#define PM8XXX_ADC_ARB_USRP_DIG_PARAM_EN BIT(7)
67
68#define PM8XXX_ADC_ARB_USRP_RSV 0x19B
69#define PM8XXX_ADC_ARB_USRP_RSV_RST BIT(0)
70#define PM8XXX_ADC_ARB_USRP_RSV_DTEST0 BIT(1)
71#define PM8XXX_ADC_ARB_USRP_RSV_DTEST1 BIT(2)
72#define PM8XXX_ADC_ARB_USRP_RSV_OP BIT(3)
73#define PM8XXX_ADC_ARB_USRP_RSV_IP_SEL0 BIT(4)
74#define PM8XXX_ADC_ARB_USRP_RSV_IP_SEL1 BIT(5)
75#define PM8XXX_ADC_ARB_USRP_RSV_IP_SEL2 BIT(6)
76#define PM8XXX_ADC_ARB_USRP_RSV_TRM BIT(7)
77
78#define PM8XXX_ADC_ARB_USRP_DATA0 0x19D
79#define PM8XXX_ADC_ARB_USRP_DATA1 0x19C
80
81#define PM8XXX_ADC_ARB_BTM_CNTRL1 0x17e
82#define PM8XXX_ADC_ARB_BTM_CNTRL1_EN_BTM BIT(0)
83#define PM8XXX_ADC_ARB_BTM_CNTRL1_SEL_OP_MODE BIT(1)
84#define PM8XXX_ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL1 BIT(2)
85#define PM8XXX_ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL2 BIT(3)
86#define PM8XXX_ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL3 BIT(4)
87#define PM8XXX_ADC_ARB_BTM_CNTRL1_MEAS_INTERVAL4 BIT(5)
88#define PM8XXX_ADC_ARB_BTM_CNTRL1_EOC BIT(6)
89#define PM8XXX_ADC_ARB_BTM_CNTRL1_REQ BIT(7)
90
91#define PM8XXX_ADC_ARB_BTM_CNTRL2 0x18c
92#define PM8XXX_ADC_ARB_BTM_AMUX_CNTRL 0x17f
93#define PM8XXX_ADC_ARB_BTM_ANA_PARAM 0x180
94#define PM8XXX_ADC_ARB_BTM_DIG_PARAM 0x181
95#define PM8XXX_ADC_ARB_BTM_RSV 0x182
96#define PM8XXX_ADC_ARB_BTM_DATA1 0x183
97#define PM8XXX_ADC_ARB_BTM_DATA0 0x184
98#define PM8XXX_ADC_ARB_BTM_BAT_COOL_THR1 0x185
99#define PM8XXX_ADC_ARB_BTM_BAT_COOL_THR0 0x186
100#define PM8XXX_ADC_ARB_BTM_BAT_WARM_THR1 0x187
101#define PM8XXX_ADC_ARB_BTM_BAT_WARM_THR0 0x188
102
103#define PM8XXX_ADC_ARB_ANA_DIG 0xa0
104#define PM8XXX_ADC_BTM_RSV 0x10
105#define PM8XXX_ADC_AMUX_MPP_SEL 2
106#define PM8XXX_ADC_AMUX_SEL 4
107#define PM8XXX_ADC_RSV_IP_SEL 4
108#define PM8XXX_ADC_BTM_CHANNEL_SEL 4
109#define PM8XXX_MAX_CHANNEL_PROPERTIES 2
110#define PM8XXX_ADC_IRQ_0 0
111#define PM8XXX_ADC_IRQ_1 1
112#define PM8XXX_ADC_IRQ_2 2
113#define PM8XXX_ADC_BTM_INTERVAL_SEL_MASK 0xF
114#define PM8XXX_ADC_BTM_INTERVAL_SEL_SHIFT 2
115#define PM8XXX_ADC_BTM_DECIMATION_SEL 5
116#define PM8XXX_ADC_MUL 10
117#define PM8XXX_ADC_CONV_TIME_MIN 2000
118#define PM8XXX_ADC_CONV_TIME_MAX 2100
119#define PM8XXX_ADC_MPP_SETTLE_TIME_MIN 200
120#define PM8XXX_ADC_MPP_SETTLE_TIME_MAX 200
121#define PM8XXX_ADC_PA_THERM_VREG_UV_MIN 1800000
122#define PM8XXX_ADC_PA_THERM_VREG_UV_MAX 1800000
123#define PM8XXX_ADC_PA_THERM_VREG_UA_LOAD 100000
Siddartha Mohanadossae39c902011-11-09 17:54:31 -0800124#define PM8XXX_ADC_HWMON_NAME_LENGTH 32
Siddartha Mohanadoss68ceac12011-12-09 16:04:41 -0800125#define PM8XXX_ADC_BTM_INTERVAL_MAX 0x14
Siddartha Mohanadoss96ab7812012-07-24 22:19:48 -0700126#define PM8XXX_ADC_COMPLETION_TIMEOUT (2 * HZ)
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700127
128struct pm8xxx_adc {
129 struct device *dev;
130 struct pm8xxx_adc_properties *adc_prop;
131 int adc_irq;
132 struct mutex adc_lock;
133 struct mutex mpp_adc_lock;
134 spinlock_t btm_lock;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700135 uint32_t adc_num_board_channel;
136 struct completion adc_rslt_completion;
137 struct pm8xxx_adc_amux *adc_channel;
138 int btm_warm_irq;
139 int btm_cool_irq;
140 struct dentry *dent;
141 struct work_struct warm_work;
142 struct work_struct cool_work;
143 uint32_t mpp_base;
144 struct device *hwmon;
Siddartha Mohanadossf9dfe1b2012-08-14 15:15:42 -0700145 struct msm_xo_voter *adc_voter;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700146 int msm_suspend_check;
147 struct pm8xxx_adc_amux_properties *conv;
Siddartha Mohanadoss402673e2012-01-06 16:31:44 -0800148 struct pm8xxx_adc_arb_btm_param batt;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700149 struct sensor_device_attribute sens_attr[0];
150};
151
152struct pm8xxx_adc_amux_properties {
153 uint32_t amux_channel;
154 uint32_t decimation;
155 uint32_t amux_ip_rsv;
156 uint32_t amux_mpp_channel;
157 struct pm8xxx_adc_chan_properties chan_prop[0];
158};
159
160static const struct pm8xxx_adc_scaling_ratio pm8xxx_amux_scaling_ratio[] = {
161 {1, 1},
162 {1, 3},
163 {1, 4},
164 {1, 6}
165};
166
167static struct pm8xxx_adc *pmic_adc;
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -0800168static struct regulator *pa_therm;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700169
170static struct pm8xxx_adc_scale_fn adc_scale_fn[] = {
171 [ADC_SCALE_DEFAULT] = {pm8xxx_adc_scale_default},
172 [ADC_SCALE_BATT_THERM] = {pm8xxx_adc_scale_batt_therm},
173 [ADC_SCALE_PA_THERM] = {pm8xxx_adc_scale_pa_therm},
174 [ADC_SCALE_PMIC_THERM] = {pm8xxx_adc_scale_pmic_therm},
175 [ADC_SCALE_XOTHERM] = {pm8xxx_adc_tdkntcg_therm},
176};
177
178/* On PM8921 ADC the MPP needs to first be configured
179as an analog input to the AMUX pre-mux channel before
180issuing a read request. PM8921 MPP 8 is mapped to AMUX8
181and is common between remote processor's.
182On PM8018 ADC the MPP is directly connected to the AMUX
183pre-mux. Therefore clients of the PM8018 MPP do not need
184to configure the MPP as an analog input to the pre-mux.
185Clients can directly issue request on the pre-mux AMUX
186channel to read the ADC on the MPP */
187static struct pm8xxx_mpp_config_data pm8xxx_adc_mpp_config = {
188 .type = PM8XXX_MPP_TYPE_A_INPUT,
189 /* AMUX6 is dedicated to be used for apps processor */
190 .level = PM8XXX_MPP_AIN_AMUX_CH6,
191 .control = PM8XXX_MPP_AOUT_CTRL_DISABLE,
192};
193
194/* MPP Configuration for default settings */
195static struct pm8xxx_mpp_config_data pm8xxx_adc_mpp_unconfig = {
196 .type = PM8XXX_MPP_TYPE_SINK,
197 .level = PM8XXX_MPP_AIN_AMUX_CH5,
198 .control = PM8XXX_MPP_AOUT_CTRL_DISABLE,
199};
200
201static bool pm8xxx_adc_calib_first_adc;
202static bool pm8xxx_adc_initialized, pm8xxx_adc_calib_device_init;
203
Siddartha Mohanadosscb6d3002012-03-15 10:44:11 -0700204static int32_t pm8xxx_adc_check_channel_valid(uint32_t channel)
205{
206 if (channel < CHANNEL_VCOIN ||
207 (channel > CHANNEL_MUXOFF && channel < ADC_MPP_1_ATEST_8) ||
208 (channel > ADC_MPP_1_ATEST_7 && channel < ADC_MPP_2_ATEST_8)
209 || (channel >= ADC_CHANNEL_MAX_NUM))
210 return -EBADF;
211 else
212 return 0;
213}
214
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700215static int32_t pm8xxx_adc_arb_cntrl(uint32_t arb_cntrl,
216 uint32_t channel)
217{
218 struct pm8xxx_adc *adc_pmic = pmic_adc;
219 int i, rc;
220 u8 data_arb_cntrl = 0;
221
222 if (arb_cntrl) {
223 if (adc_pmic->msm_suspend_check)
224 pr_err("PM8xxx ADC request made after suspend_noirq "
225 "with channel: %d\n", channel);
226 data_arb_cntrl |= PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700227 }
228
229 /* Write twice to the CNTRL register for the arbiter settings
230 to take into effect */
231 for (i = 0; i < 2; i++) {
232 rc = pm8xxx_writeb(adc_pmic->dev->parent,
233 PM8XXX_ADC_ARB_USRP_CNTRL1, data_arb_cntrl);
234 if (rc < 0) {
235 pr_err("PM8xxx arb cntrl write failed with %d\n", rc);
236 return rc;
237 }
238 }
239
240 if (arb_cntrl) {
241 data_arb_cntrl |= PM8XXX_ADC_ARB_USRP_CNTRL1_REQ;
Abhijeet Dharmapurikarf5285a22012-04-10 23:42:45 -0700242 INIT_COMPLETION(adc_pmic->adc_rslt_completion);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700243 rc = pm8xxx_writeb(adc_pmic->dev->parent,
244 PM8XXX_ADC_ARB_USRP_CNTRL1, data_arb_cntrl);
Siddartha Mohanadoss96ab7812012-07-24 22:19:48 -0700245 }
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700246
247 return 0;
248}
249
250static int32_t pm8xxx_adc_patherm_power(bool on)
251{
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700252 int rc = 0;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700253
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -0800254 if (!pa_therm) {
255 pr_err("pm8xxx adc pa_therm not valid\n");
256 return -EINVAL;
257 }
258
259 if (on) {
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700260 rc = regulator_set_voltage(pa_therm,
261 PM8XXX_ADC_PA_THERM_VREG_UV_MIN,
262 PM8XXX_ADC_PA_THERM_VREG_UV_MAX);
263 if (rc < 0) {
264 pr_err("failed to set the voltage for "
265 "pa_therm with error %d\n", rc);
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -0800266 return rc;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700267 }
268
269 rc = regulator_set_optimum_mode(pa_therm,
270 PM8XXX_ADC_PA_THERM_VREG_UA_LOAD);
271 if (rc < 0) {
272 pr_err("failed to set optimum mode for "
273 "pa_therm with error %d\n", rc);
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -0800274 return rc;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700275 }
276
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -0800277 rc = regulator_enable(pa_therm);
278 if (rc < 0) {
279 pr_err("failed to enable pa_therm vreg "
280 "with error %d\n", rc);
281 return rc;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700282 }
283 } else {
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -0800284 rc = regulator_disable(pa_therm);
285 if (rc < 0) {
286 pr_err("failed to disable pa_therm vreg "
287 "with error %d\n", rc);
288 return rc;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700289 }
290 }
291
292 return rc;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700293}
294
Siddartha Mohanadossf9dfe1b2012-08-14 15:15:42 -0700295static int32_t pm8xxx_adc_xo_vote(bool on)
296{
297 struct pm8xxx_adc *adc_pmic = pmic_adc;
298
299 if (on)
300 msm_xo_mode_vote(adc_pmic->adc_voter, MSM_XO_MODE_ON);
301 else
302 msm_xo_mode_vote(adc_pmic->adc_voter, MSM_XO_MODE_OFF);
303
304 return 0;
305}
306
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700307static int32_t pm8xxx_adc_channel_power_enable(uint32_t channel,
308 bool power_cntrl)
309{
310 int rc = 0;
311
Siddartha Mohanadossf9dfe1b2012-08-14 15:15:42 -0700312 switch (channel) {
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700313 case ADC_MPP_1_AMUX8:
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -0800314 rc = pm8xxx_adc_patherm_power(power_cntrl);
Siddartha Mohanadossf9dfe1b2012-08-14 15:15:42 -0700315 break;
316 case CHANNEL_DIE_TEMP:
317 case CHANNEL_MUXOFF:
318 rc = pm8xxx_adc_xo_vote(power_cntrl);
319 break;
320 default:
321 break;
322 }
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700323
324 return rc;
325}
326
327
328static uint32_t pm8xxx_adc_read_reg(uint32_t reg, u8 *data)
329{
330 struct pm8xxx_adc *adc_pmic = pmic_adc;
331 int rc;
332
333 rc = pm8xxx_readb(adc_pmic->dev->parent, reg, data);
334 if (rc < 0) {
335 pr_err("PM8xxx adc read reg %d failed with %d\n", reg, rc);
336 return rc;
337 }
338
339 return 0;
340}
341
342static uint32_t pm8xxx_adc_write_reg(uint32_t reg, u8 data)
343{
344 struct pm8xxx_adc *adc_pmic = pmic_adc;
345 int rc;
346
347 rc = pm8xxx_writeb(adc_pmic->dev->parent, reg, data);
348 if (rc < 0) {
349 pr_err("PM8xxx adc write reg %d failed with %d\n", reg, rc);
350 return rc;
351 }
352
353 return 0;
354}
355
356static int32_t pm8xxx_adc_configure(
357 struct pm8xxx_adc_amux_properties *chan_prop)
358{
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700359 u8 data_amux_chan = 0, data_arb_rsv = 0, data_dig_param = 0;
360 int rc;
361
362 data_amux_chan |= chan_prop->amux_channel << PM8XXX_ADC_AMUX_SEL;
363
364 if (chan_prop->amux_mpp_channel)
365 data_amux_chan |= chan_prop->amux_mpp_channel <<
366 PM8XXX_ADC_AMUX_MPP_SEL;
367
368 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_USRP_AMUX_CNTRL,
369 data_amux_chan);
370 if (rc < 0)
371 return rc;
372
Siddartha Mohanadoss866fe9f2011-12-13 23:01:40 -0800373 rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_RSV, &data_arb_rsv);
374 if (rc < 0)
375 return rc;
376
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700377 data_arb_rsv &= (PM8XXX_ADC_ARB_USRP_RSV_RST |
378 PM8XXX_ADC_ARB_USRP_RSV_DTEST0 |
379 PM8XXX_ADC_ARB_USRP_RSV_DTEST1 |
Siddartha Mohanadoss866fe9f2011-12-13 23:01:40 -0800380 PM8XXX_ADC_ARB_USRP_RSV_OP);
381 data_arb_rsv |= (chan_prop->amux_ip_rsv << PM8XXX_ADC_RSV_IP_SEL |
382 PM8XXX_ADC_ARB_USRP_RSV_TRM);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700383
384 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_USRP_RSV, data_arb_rsv);
385 if (rc < 0)
386 return rc;
387
388 rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_DIG_PARAM,
389 &data_dig_param);
390 if (rc < 0)
391 return rc;
392
393 /* Default 2.4Mhz clock rate */
394 /* Client chooses the decimation */
395 switch (chan_prop->decimation) {
396 case ADC_DECIMATION_TYPE1:
397 data_dig_param |= PM8XXX_ADC_ARB_USRP_DIG_PARAM_DEC_RATE0;
398 break;
399 case ADC_DECIMATION_TYPE2:
400 data_dig_param |= (PM8XXX_ADC_ARB_USRP_DIG_PARAM_DEC_RATE0
401 | PM8XXX_ADC_ARB_USRP_DIG_PARAM_DEC_RATE1);
402 break;
403 default:
404 data_dig_param |= PM8XXX_ADC_ARB_USRP_DIG_PARAM_DEC_RATE0;
405 break;
406 }
407 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_USRP_DIG_PARAM,
408 PM8XXX_ADC_ARB_ANA_DIG);
409 if (rc < 0)
410 return rc;
411
412 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_USRP_ANA_PARAM,
413 PM8XXX_ADC_ARB_ANA_DIG);
414 if (rc < 0)
415 return rc;
416
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700417 rc = pm8xxx_adc_arb_cntrl(1, data_amux_chan);
418 if (rc < 0) {
419 pr_err("Configuring ADC Arbiter"
420 "enable failed with %d\n", rc);
421 return rc;
422 }
423
424 return 0;
425}
426
427static uint32_t pm8xxx_adc_read_adc_code(int32_t *data)
428{
429 struct pm8xxx_adc *adc_pmic = pmic_adc;
430 uint8_t rslt_lsb, rslt_msb;
431 int32_t rc, max_ideal_adc_code = 1 << adc_pmic->adc_prop->bitresolution;
432
433 rc = pm8xxx_readb(adc_pmic->dev->parent,
434 PM8XXX_ADC_ARB_USRP_DATA0, &rslt_lsb);
435 if (rc < 0) {
436 pr_err("PM8xxx adc result read failed with %d\n", rc);
437 return rc;
438 }
439
440 rc = pm8xxx_readb(adc_pmic->dev->parent,
441 PM8XXX_ADC_ARB_USRP_DATA1, &rslt_msb);
442 if (rc < 0) {
443 pr_err("PM8xxx adc result read failed with %d\n", rc);
444 return rc;
445 }
446
447 *data = (rslt_msb << 8) | rslt_lsb;
448
449 /* Use the midpoint to determine underflow or overflow */
450 if (*data > max_ideal_adc_code + (max_ideal_adc_code >> 1))
451 *data |= ((1 << (8 * sizeof(*data) -
452 adc_pmic->adc_prop->bitresolution)) - 1) <<
453 adc_pmic->adc_prop->bitresolution;
454
455 /* Default value for switching off the arbiter after reading
456 the ADC value. Bit 0 set to 0. */
457 rc = pm8xxx_adc_arb_cntrl(0, CHANNEL_NONE);
458 if (rc < 0) {
459 pr_err("%s: Configuring ADC Arbiter disable"
460 "failed\n", __func__);
461 return rc;
462 }
463
464 return 0;
465}
466
467static void pm8xxx_adc_btm_warm_scheduler_fn(struct work_struct *work)
468{
469 struct pm8xxx_adc *adc_pmic = container_of(work, struct pm8xxx_adc,
470 warm_work);
471 unsigned long flags = 0;
472 bool warm_status;
473
474 spin_lock_irqsave(&adc_pmic->btm_lock, flags);
475 warm_status = irq_read_line(adc_pmic->btm_warm_irq);
Siddartha Mohanadoss402673e2012-01-06 16:31:44 -0800476 if (adc_pmic->batt.btm_warm_fn != NULL)
477 adc_pmic->batt.btm_warm_fn(warm_status);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700478 spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
479}
480
481static void pm8xxx_adc_btm_cool_scheduler_fn(struct work_struct *work)
482{
483 struct pm8xxx_adc *adc_pmic = container_of(work, struct pm8xxx_adc,
484 cool_work);
485 unsigned long flags = 0;
486 bool cool_status;
487
488 spin_lock_irqsave(&adc_pmic->btm_lock, flags);
489 cool_status = irq_read_line(adc_pmic->btm_cool_irq);
Siddartha Mohanadoss402673e2012-01-06 16:31:44 -0800490 if (adc_pmic->batt.btm_cool_fn != NULL)
491 adc_pmic->batt.btm_cool_fn(cool_status);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700492 spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
493}
494
Abhijeet Dharmapurikarf5285a22012-04-10 23:42:45 -0700495void trigger_completion(struct work_struct *work)
496{
497 struct pm8xxx_adc *adc_8xxx = pmic_adc;
498
499 complete(&adc_8xxx->adc_rslt_completion);
500}
501DECLARE_WORK(trigger_completion_work, trigger_completion);
502
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700503static irqreturn_t pm8xxx_adc_isr(int irq, void *dev_id)
504{
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700505
506 if (pm8xxx_adc_calib_first_adc)
507 return IRQ_HANDLED;
Abhijeet Dharmapurikarf5285a22012-04-10 23:42:45 -0700508
509 schedule_work(&trigger_completion_work);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700510
511 return IRQ_HANDLED;
512}
513
514static irqreturn_t pm8xxx_btm_warm_isr(int irq, void *dev_id)
515{
516 struct pm8xxx_adc *btm_8xxx = dev_id;
517
518 schedule_work(&btm_8xxx->warm_work);
519
520 return IRQ_HANDLED;
521}
522
523static irqreturn_t pm8xxx_btm_cool_isr(int irq, void *dev_id)
524{
525 struct pm8xxx_adc *btm_8xxx = dev_id;
526
527 schedule_work(&btm_8xxx->cool_work);
528
529 return IRQ_HANDLED;
530}
531
532static uint32_t pm8xxx_adc_calib_device(void)
533{
534 struct pm8xxx_adc *adc_pmic = pmic_adc;
535 struct pm8xxx_adc_amux_properties conv;
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800536 int rc, calib_read_1, calib_read_2;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700537 u8 data_arb_usrp_cntrl1 = 0;
538
539 conv.amux_channel = CHANNEL_125V;
540 conv.decimation = ADC_DECIMATION_TYPE2;
541 conv.amux_ip_rsv = AMUX_RSV1;
542 conv.amux_mpp_channel = PREMUX_MPP_SCALE_0;
543 pm8xxx_adc_calib_first_adc = true;
544 rc = pm8xxx_adc_configure(&conv);
545 if (rc) {
546 pr_err("pm8xxx_adc configure failed with %d\n", rc);
547 goto calib_fail;
548 }
549
550 while (data_arb_usrp_cntrl1 != (PM8XXX_ADC_ARB_USRP_CNTRL1_EOC |
551 PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB)) {
552 rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_CNTRL1,
553 &data_arb_usrp_cntrl1);
554 if (rc < 0)
555 return rc;
556 usleep_range(PM8XXX_ADC_CONV_TIME_MIN,
557 PM8XXX_ADC_CONV_TIME_MAX);
558 }
559 data_arb_usrp_cntrl1 = 0;
560
561 rc = pm8xxx_adc_read_adc_code(&calib_read_1);
562 if (rc) {
563 pr_err("pm8xxx_adc read adc failed with %d\n", rc);
564 pm8xxx_adc_calib_first_adc = false;
565 goto calib_fail;
566 }
567 pm8xxx_adc_calib_first_adc = false;
568
569 conv.amux_channel = CHANNEL_625MV;
570 conv.decimation = ADC_DECIMATION_TYPE2;
571 conv.amux_ip_rsv = AMUX_RSV1;
572 conv.amux_mpp_channel = PREMUX_MPP_SCALE_0;
573 pm8xxx_adc_calib_first_adc = true;
574 rc = pm8xxx_adc_configure(&conv);
575 if (rc) {
576 pr_err("pm8xxx_adc configure failed with %d\n", rc);
577 goto calib_fail;
578 }
579
580 while (data_arb_usrp_cntrl1 != (PM8XXX_ADC_ARB_USRP_CNTRL1_EOC |
581 PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB)) {
582 rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_CNTRL1,
583 &data_arb_usrp_cntrl1);
584 if (rc < 0)
585 return rc;
586 usleep_range(PM8XXX_ADC_CONV_TIME_MIN,
587 PM8XXX_ADC_CONV_TIME_MAX);
588 }
589 data_arb_usrp_cntrl1 = 0;
590
591 rc = pm8xxx_adc_read_adc_code(&calib_read_2);
592 if (rc) {
593 pr_err("pm8xxx_adc read adc failed with %d\n", rc);
594 pm8xxx_adc_calib_first_adc = false;
595 goto calib_fail;
596 }
597 pm8xxx_adc_calib_first_adc = false;
598
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700599 adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_ABSOLUTE].dy =
600 (calib_read_1 - calib_read_2);
601 adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_ABSOLUTE].dx
Siddartha Mohanadoss37e6fc02011-11-16 16:57:03 -0800602 = PM8XXX_CHANNEL_ADC_625_UV;
603 adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_ABSOLUTE].adc_vref =
604 calib_read_1;
605 adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_ABSOLUTE].adc_gnd =
606 calib_read_2;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700607 rc = pm8xxx_adc_arb_cntrl(0, CHANNEL_NONE);
608 if (rc < 0) {
609 pr_err("%s: Configuring ADC Arbiter disable"
610 "failed\n", __func__);
611 return rc;
612 }
613 /* Ratiometric Calibration */
614 conv.amux_channel = CHANNEL_MUXOFF;
615 conv.decimation = ADC_DECIMATION_TYPE2;
616 conv.amux_ip_rsv = AMUX_RSV5;
617 conv.amux_mpp_channel = PREMUX_MPP_SCALE_0;
618 pm8xxx_adc_calib_first_adc = true;
619 rc = pm8xxx_adc_configure(&conv);
620 if (rc) {
621 pr_err("pm8xxx_adc configure failed with %d\n", rc);
622 goto calib_fail;
623 }
624
625 while (data_arb_usrp_cntrl1 != (PM8XXX_ADC_ARB_USRP_CNTRL1_EOC |
626 PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB)) {
627 rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_CNTRL1,
628 &data_arb_usrp_cntrl1);
629 if (rc < 0)
630 return rc;
631 usleep_range(PM8XXX_ADC_CONV_TIME_MIN,
632 PM8XXX_ADC_CONV_TIME_MAX);
633 }
634 data_arb_usrp_cntrl1 = 0;
635
636 rc = pm8xxx_adc_read_adc_code(&calib_read_1);
637 if (rc) {
638 pr_err("pm8xxx_adc read adc failed with %d\n", rc);
639 pm8xxx_adc_calib_first_adc = false;
640 goto calib_fail;
641 }
642 pm8xxx_adc_calib_first_adc = false;
643
644 conv.amux_channel = CHANNEL_MUXOFF;
645 conv.decimation = ADC_DECIMATION_TYPE2;
646 conv.amux_ip_rsv = AMUX_RSV4;
647 conv.amux_mpp_channel = PREMUX_MPP_SCALE_0;
648 pm8xxx_adc_calib_first_adc = true;
649 rc = pm8xxx_adc_configure(&conv);
650 if (rc) {
651 pr_err("pm8xxx_adc configure failed with %d\n", rc);
652 goto calib_fail;
653 }
654
655 while (data_arb_usrp_cntrl1 != (PM8XXX_ADC_ARB_USRP_CNTRL1_EOC |
656 PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB)) {
657 rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_CNTRL1,
658 &data_arb_usrp_cntrl1);
659 if (rc < 0)
660 return rc;
661 usleep_range(PM8XXX_ADC_CONV_TIME_MIN,
662 PM8XXX_ADC_CONV_TIME_MAX);
663 }
664 data_arb_usrp_cntrl1 = 0;
665
666 rc = pm8xxx_adc_read_adc_code(&calib_read_2);
667 if (rc) {
668 pr_err("pm8xxx_adc read adc failed with %d\n", rc);
669 pm8xxx_adc_calib_first_adc = false;
670 goto calib_fail;
671 }
672 pm8xxx_adc_calib_first_adc = false;
673
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700674 adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_RATIOMETRIC].dy =
675 (calib_read_1 - calib_read_2);
676 adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_RATIOMETRIC].dx =
677 adc_pmic->adc_prop->adc_vdd_reference;
Siddartha Mohanadossae39c902011-11-09 17:54:31 -0800678 adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_RATIOMETRIC].adc_vref =
679 calib_read_1;
680 adc_pmic->conv->chan_prop->adc_graph[ADC_CALIB_RATIOMETRIC].adc_gnd =
681 calib_read_2;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700682calib_fail:
683 rc = pm8xxx_adc_arb_cntrl(0, CHANNEL_NONE);
684 if (rc < 0) {
685 pr_err("%s: Configuring ADC Arbiter disable"
686 "failed\n", __func__);
687 }
688
689 return rc;
690}
691
692uint32_t pm8xxx_adc_read(enum pm8xxx_adc_channels channel,
693 struct pm8xxx_adc_chan_result *result)
694{
695 struct pm8xxx_adc *adc_pmic = pmic_adc;
696 int i = 0, rc = 0, rc_fail, amux_prescaling, scale_type;
697 enum pm8xxx_adc_premux_mpp_scale_type mpp_scale;
698
699 if (!pm8xxx_adc_initialized)
700 return -ENODEV;
701
702 if (!pm8xxx_adc_calib_device_init) {
703 if (pm8xxx_adc_calib_device() == 0)
704 pm8xxx_adc_calib_device_init = true;
705 }
706
707 mutex_lock(&adc_pmic->adc_lock);
708
Siddartha Mohanadosscb6d3002012-03-15 10:44:11 -0700709 for (i = 0; i < adc_pmic->adc_num_board_channel; i++) {
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700710 if (channel == adc_pmic->adc_channel[i].channel_name)
711 break;
712 }
713
Siddartha Mohanadosscb6d3002012-03-15 10:44:11 -0700714 if (i == adc_pmic->adc_num_board_channel ||
715 (pm8xxx_adc_check_channel_valid(channel) != 0)) {
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700716 rc = -EBADF;
717 goto fail_unlock;
718 }
719
720 if (channel < PM8XXX_CHANNEL_MPP_SCALE1_IDX) {
721 mpp_scale = PREMUX_MPP_SCALE_0;
722 adc_pmic->conv->amux_channel = channel;
Siddartha Mohanadossae39c902011-11-09 17:54:31 -0800723 } else if (channel >= PM8XXX_CHANNEL_MPP_SCALE1_IDX &&
724 channel < PM8XXX_CHANNEL_MPP_SCALE3_IDX) {
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700725 mpp_scale = PREMUX_MPP_SCALE_1;
726 adc_pmic->conv->amux_channel = channel %
727 PM8XXX_CHANNEL_MPP_SCALE1_IDX;
Siddartha Mohanadossae39c902011-11-09 17:54:31 -0800728 } else {
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700729 mpp_scale = PREMUX_MPP_SCALE_1_DIV3;
730 adc_pmic->conv->amux_channel = channel %
731 PM8XXX_CHANNEL_MPP_SCALE3_IDX;
732 }
733
734 adc_pmic->conv->amux_mpp_channel = mpp_scale;
735 adc_pmic->conv->amux_ip_rsv = adc_pmic->adc_channel[i].adc_rsv;
736 adc_pmic->conv->decimation = adc_pmic->adc_channel[i].adc_decimation;
737 amux_prescaling = adc_pmic->adc_channel[i].chan_path_prescaling;
738
739 adc_pmic->conv->chan_prop->offset_gain_numerator =
740 pm8xxx_amux_scaling_ratio[amux_prescaling].num;
741 adc_pmic->conv->chan_prop->offset_gain_denominator =
742 pm8xxx_amux_scaling_ratio[amux_prescaling].den;
743
744 rc = pm8xxx_adc_channel_power_enable(channel, true);
745 if (rc) {
746 rc = -EINVAL;
747 goto fail_unlock;
748 }
749
750 rc = pm8xxx_adc_configure(adc_pmic->conv);
751 if (rc) {
752 rc = -EINVAL;
753 goto fail;
754 }
755
Siddartha Mohanadoss96ab7812012-07-24 22:19:48 -0700756 rc = wait_for_completion_timeout(&adc_pmic->adc_rslt_completion,
757 PM8XXX_ADC_COMPLETION_TIMEOUT);
758 if (!rc) {
759 u8 data_arb_usrp_cntrl1 = 0;
760 rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_USRP_CNTRL1,
761 &data_arb_usrp_cntrl1);
762 if (rc < 0)
763 goto fail;
764 if (data_arb_usrp_cntrl1 == (PM8XXX_ADC_ARB_USRP_CNTRL1_EOC |
765 PM8XXX_ADC_ARB_USRP_CNTRL1_EN_ARB))
766 pr_debug("End of conversion status set\n");
767 else {
768 pr_err("EOC interrupt not received\n");
769 rc = -EINVAL;
770 goto fail;
771 }
772 }
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700773
774 rc = pm8xxx_adc_read_adc_code(&result->adc_code);
775 if (rc) {
776 rc = -EINVAL;
777 goto fail;
778 }
779
780 scale_type = adc_pmic->adc_channel[i].adc_scale_fn;
781 if (scale_type >= ADC_SCALE_NONE) {
782 rc = -EBADF;
783 goto fail;
784 }
785
786 adc_scale_fn[scale_type].chan(result->adc_code,
787 adc_pmic->adc_prop, adc_pmic->conv->chan_prop, result);
788
789 rc = pm8xxx_adc_channel_power_enable(channel, false);
790 if (rc) {
791 rc = -EINVAL;
792 goto fail_unlock;
793 }
794
795 mutex_unlock(&adc_pmic->adc_lock);
796
797 return 0;
798fail:
799 rc_fail = pm8xxx_adc_channel_power_enable(channel, false);
800 if (rc_fail)
801 pr_err("pm8xxx adc power disable failed\n");
802fail_unlock:
803 mutex_unlock(&adc_pmic->adc_lock);
804 pr_err("pm8xxx adc error with %d\n", rc);
805 return rc;
806}
807EXPORT_SYMBOL_GPL(pm8xxx_adc_read);
808
809uint32_t pm8xxx_adc_mpp_config_read(uint32_t mpp_num,
810 enum pm8xxx_adc_channels channel,
811 struct pm8xxx_adc_chan_result *result)
812{
813 struct pm8xxx_adc *adc_pmic = pmic_adc;
814 int rc = 0;
815
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -0800816 if (!pm8xxx_adc_initialized)
817 return -ENODEV;
818
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700819 if (!adc_pmic->mpp_base) {
820 rc = -EINVAL;
821 pr_info("PM8xxx MPP base invalid with error %d\n", rc);
822 return rc;
823 }
824
825 if (mpp_num == PM8XXX_AMUX_MPP_8) {
826 rc = -EINVAL;
827 pr_info("PM8xxx MPP8 is already configured "
828 "to AMUX8. Use pm8xxx_adc_read() instead.\n");
829 return rc;
830 }
831
832 mutex_lock(&adc_pmic->mpp_adc_lock);
833
834 rc = pm8xxx_mpp_config(((mpp_num - 1) + adc_pmic->mpp_base),
835 &pm8xxx_adc_mpp_config);
836 if (rc < 0) {
837 pr_err("pm8xxx adc mpp config error with %d\n", rc);
838 goto fail;
839 }
840
841 usleep_range(PM8XXX_ADC_MPP_SETTLE_TIME_MIN,
842 PM8XXX_ADC_MPP_SETTLE_TIME_MAX);
843
844 rc = pm8xxx_adc_read(channel, result);
845 if (rc < 0)
846 pr_err("pm8xxx adc read error with %d\n", rc);
847
848 rc = pm8xxx_mpp_config(((mpp_num - 1) + adc_pmic->mpp_base),
849 &pm8xxx_adc_mpp_unconfig);
850 if (rc < 0)
851 pr_err("pm8xxx adc mpp config error with %d\n", rc);
852fail:
853 mutex_unlock(&adc_pmic->mpp_adc_lock);
854
855 return rc;
856}
857EXPORT_SYMBOL_GPL(pm8xxx_adc_mpp_config_read);
858
859uint32_t pm8xxx_adc_btm_configure(struct pm8xxx_adc_arb_btm_param *btm_param)
860{
861 struct pm8xxx_adc *adc_pmic = pmic_adc;
862 u8 data_btm_cool_thr0, data_btm_cool_thr1;
863 u8 data_btm_warm_thr0, data_btm_warm_thr1;
864 u8 arb_btm_cntrl1;
865 unsigned long flags = 0;
866 int rc;
867
868 if (adc_pmic == NULL) {
869 pr_err("PMIC ADC not valid\n");
870 return -EINVAL;
871 }
872
873 if ((btm_param->btm_cool_fn == NULL) &&
874 (btm_param->btm_warm_fn == NULL)) {
875 pr_err("No BTM warm/cool notification??\n");
876 return -EINVAL;
877 }
878
Siddartha Mohanadossae39c902011-11-09 17:54:31 -0800879 rc = pm8xxx_adc_batt_scaler(btm_param, adc_pmic->adc_prop,
880 adc_pmic->conv->chan_prop);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700881 if (rc < 0) {
882 pr_err("Failed to lookup the BTM thresholds\n");
883 return rc;
884 }
885
Siddartha Mohanadoss68ceac12011-12-09 16:04:41 -0800886 if (btm_param->interval > PM8XXX_ADC_BTM_INTERVAL_MAX) {
887 pr_info("Bug in PMIC BTM interval time and cannot set"
888 " a value greater than 0x14 %x\n", btm_param->interval);
889 btm_param->interval = PM8XXX_ADC_BTM_INTERVAL_MAX;
890 }
891
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700892 spin_lock_irqsave(&adc_pmic->btm_lock, flags);
893
894 data_btm_cool_thr0 = ((btm_param->low_thr_voltage << 24) >> 24);
895 data_btm_cool_thr1 = ((btm_param->low_thr_voltage << 16) >> 24);
896 data_btm_warm_thr0 = ((btm_param->high_thr_voltage << 24) >> 24);
897 data_btm_warm_thr1 = ((btm_param->high_thr_voltage << 16) >> 24);
898
899 if (btm_param->btm_cool_fn != NULL) {
900 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_BAT_COOL_THR0,
901 data_btm_cool_thr0);
902 if (rc < 0)
903 goto write_err;
904
905 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_BAT_COOL_THR1,
906 data_btm_cool_thr1);
907 if (rc < 0)
908 goto write_err;
909
Siddartha Mohanadoss402673e2012-01-06 16:31:44 -0800910 adc_pmic->batt.btm_cool_fn = btm_param->btm_cool_fn;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700911 }
912
913 if (btm_param->btm_warm_fn != NULL) {
914 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_BAT_WARM_THR0,
915 data_btm_warm_thr0);
916 if (rc < 0)
917 goto write_err;
918
919 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_BAT_WARM_THR1,
920 data_btm_warm_thr1);
921 if (rc < 0)
922 goto write_err;
923
Siddartha Mohanadoss402673e2012-01-06 16:31:44 -0800924 adc_pmic->batt.btm_warm_fn = btm_param->btm_warm_fn;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700925 }
926
927 rc = pm8xxx_adc_read_reg(PM8XXX_ADC_ARB_BTM_CNTRL1, &arb_btm_cntrl1);
928 if (rc < 0)
929 goto bail_out;
930
931 btm_param->interval &= PM8XXX_ADC_BTM_INTERVAL_SEL_MASK;
932 arb_btm_cntrl1 |=
933 btm_param->interval << PM8XXX_ADC_BTM_INTERVAL_SEL_SHIFT;
934
935 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_CNTRL1, arb_btm_cntrl1);
936 if (rc < 0)
937 goto write_err;
938
939 spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
940
941 return rc;
942bail_out:
943write_err:
944 spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
945 pr_debug("%s: with error code %d\n", __func__, rc);
946 return rc;
947}
948EXPORT_SYMBOL_GPL(pm8xxx_adc_btm_configure);
949
950static uint32_t pm8xxx_adc_btm_read(uint32_t channel)
951{
952 struct pm8xxx_adc *adc_pmic = pmic_adc;
953 int rc, i;
954 u8 arb_btm_dig_param, arb_btm_ana_param, arb_btm_rsv;
955 u8 arb_btm_amux_cntrl, data_arb_btm_cntrl = 0;
956 unsigned long flags;
957
958 arb_btm_amux_cntrl = channel << PM8XXX_ADC_BTM_CHANNEL_SEL;
959 arb_btm_rsv = adc_pmic->adc_channel[channel].adc_rsv;
960 arb_btm_dig_param = arb_btm_ana_param = PM8XXX_ADC_ARB_ANA_DIG;
961
962 spin_lock_irqsave(&adc_pmic->btm_lock, flags);
963
964 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_AMUX_CNTRL,
965 arb_btm_amux_cntrl);
966 if (rc < 0)
967 goto write_err;
968
969 arb_btm_rsv = PM8XXX_ADC_BTM_RSV;
970
971 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_RSV, arb_btm_rsv);
972 if (rc < 0)
973 goto write_err;
974
975 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_DIG_PARAM,
976 arb_btm_dig_param);
977 if (rc < 0)
978 goto write_err;
979
980 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_ANA_PARAM,
981 arb_btm_ana_param);
982 if (rc < 0)
983 goto write_err;
984
985 data_arb_btm_cntrl |= PM8XXX_ADC_ARB_BTM_CNTRL1_EN_BTM;
986
987 for (i = 0; i < 2; i++) {
988 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_CNTRL1,
989 data_arb_btm_cntrl);
990 if (rc < 0)
991 goto write_err;
992 }
993
994 data_arb_btm_cntrl |= PM8XXX_ADC_ARB_BTM_CNTRL1_REQ
995 | PM8XXX_ADC_ARB_BTM_CNTRL1_SEL_OP_MODE;
996
997 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_CNTRL1,
998 data_arb_btm_cntrl);
999 if (rc < 0)
1000 goto write_err;
1001
Siddartha Mohanadoss402673e2012-01-06 16:31:44 -08001002 if (pmic_adc->batt.btm_warm_fn != NULL)
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001003 enable_irq(adc_pmic->btm_warm_irq);
1004
Siddartha Mohanadoss402673e2012-01-06 16:31:44 -08001005 if (pmic_adc->batt.btm_cool_fn != NULL)
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001006 enable_irq(adc_pmic->btm_cool_irq);
1007
1008write_err:
1009 spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
1010 return rc;
1011}
1012
1013uint32_t pm8xxx_adc_btm_start(void)
1014{
1015 return pm8xxx_adc_btm_read(CHANNEL_BATT_THERM);
1016}
1017EXPORT_SYMBOL_GPL(pm8xxx_adc_btm_start);
1018
1019uint32_t pm8xxx_adc_btm_end(void)
1020{
1021 struct pm8xxx_adc *adc_pmic = pmic_adc;
1022 int i, rc;
Siddartha Mohanadoss6217da02011-12-13 20:23:05 -08001023 u8 data_arb_btm_cntrl = 0;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001024 unsigned long flags;
1025
1026 disable_irq_nosync(adc_pmic->btm_warm_irq);
1027 disable_irq_nosync(adc_pmic->btm_cool_irq);
1028
1029 spin_lock_irqsave(&adc_pmic->btm_lock, flags);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001030
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001031 /* Write twice to the CNTRL register for the arbiter settings
1032 to take into effect */
1033 for (i = 0; i < 2; i++) {
1034 rc = pm8xxx_adc_write_reg(PM8XXX_ADC_ARB_BTM_CNTRL1,
1035 data_arb_btm_cntrl);
1036 if (rc < 0) {
1037 spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
1038 return rc;
1039 }
1040 }
1041
1042 spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
1043
1044 return rc;
1045}
1046EXPORT_SYMBOL_GPL(pm8xxx_adc_btm_end);
1047
1048static ssize_t pm8xxx_adc_show(struct device *dev,
1049 struct device_attribute *devattr, char *buf)
1050{
1051 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001052 struct pm8xxx_adc_chan_result result;
1053 int rc = -1;
1054
Siddartha Mohanadosscb6d3002012-03-15 10:44:11 -07001055 rc = pm8xxx_adc_read(attr->index, &result);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001056
1057 if (rc)
1058 return 0;
1059
Siddartha Mohanadossae39c902011-11-09 17:54:31 -08001060 return snprintf(buf, PM8XXX_ADC_HWMON_NAME_LENGTH,
1061 "Result:%lld Raw:%d\n", result.physical, result.adc_code);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001062}
1063
1064static int get_adc(void *data, u64 *val)
1065{
1066 struct pm8xxx_adc_chan_result result;
1067 int i = (int)data;
1068 int rc;
1069
1070 rc = pm8xxx_adc_read(i, &result);
1071 if (!rc)
1072 pr_info("ADC value raw:%x physical:%lld\n",
1073 result.adc_code, result.physical);
1074 *val = result.physical;
1075
1076 return 0;
1077}
Dipen Parmar4ceb5c72013-01-02 12:09:42 +05301078DEFINE_SIMPLE_ATTRIBUTE(reg_fops, get_adc, NULL, "%lld\n");
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001079
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001080#ifdef CONFIG_DEBUG_FS
1081static void create_debugfs_entries(void)
1082{
1083 int i = 0;
1084 pmic_adc->dent = debugfs_create_dir("pm8xxx_adc", NULL);
1085
1086 if (IS_ERR(pmic_adc->dent)) {
1087 pr_err("pmic adc debugfs dir not created\n");
1088 return;
1089 }
1090
1091 for (i = 0; i < pmic_adc->adc_num_board_channel; i++)
1092 debugfs_create_file(pmic_adc->adc_channel[i].name,
1093 0644, pmic_adc->dent,
1094 (void *)pmic_adc->adc_channel[i].channel_name,
1095 &reg_fops);
1096}
1097#else
1098static inline void create_debugfs_entries(void)
1099{
1100}
1101#endif
1102static struct sensor_device_attribute pm8xxx_adc_attr =
1103 SENSOR_ATTR(NULL, S_IRUGO, pm8xxx_adc_show, NULL, 0);
1104
1105static int32_t pm8xxx_adc_init_hwmon(struct platform_device *pdev)
1106{
1107 struct pm8xxx_adc *adc_pmic = pmic_adc;
Siddartha Mohanadosscb6d3002012-03-15 10:44:11 -07001108 int rc = 0, i, channel;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001109
1110 for (i = 0; i < pmic_adc->adc_num_board_channel; i++) {
Siddartha Mohanadosscb6d3002012-03-15 10:44:11 -07001111 channel = adc_pmic->adc_channel[i].channel_name;
1112 if (pm8xxx_adc_check_channel_valid(channel)) {
1113 pr_err("Invalid ADC init HWMON channel: %d\n", channel);
1114 continue;
1115 }
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001116 pm8xxx_adc_attr.index = adc_pmic->adc_channel[i].channel_name;
1117 pm8xxx_adc_attr.dev_attr.attr.name =
1118 adc_pmic->adc_channel[i].name;
1119 memcpy(&adc_pmic->sens_attr[i], &pm8xxx_adc_attr,
1120 sizeof(pm8xxx_adc_attr));
Stephen Boyd388d5cf2012-07-03 14:33:25 -07001121 sysfs_attr_init(&adc_pmic->sens_attr[i].dev_attr.attr);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001122 rc = device_create_file(&pdev->dev,
1123 &adc_pmic->sens_attr[i].dev_attr);
1124 if (rc) {
1125 dev_err(&pdev->dev, "device_create_file failed for "
1126 "dev %s\n",
1127 adc_pmic->adc_channel[i].name);
1128 goto hwmon_err_sens;
1129 }
1130 }
1131
1132 return 0;
1133hwmon_err_sens:
1134 pr_info("Init HWMON failed for pm8xxx_adc with %d\n", rc);
1135 return rc;
1136}
1137
1138#ifdef CONFIG_PM
1139static int pm8xxx_adc_suspend_noirq(struct device *dev)
1140{
1141 struct pm8xxx_adc *adc_pmic = pmic_adc;
1142
1143 adc_pmic->msm_suspend_check = 1;
1144
1145 return 0;
1146}
1147
1148static int pm8xxx_adc_resume_noirq(struct device *dev)
1149{
1150 struct pm8xxx_adc *adc_pmic = pmic_adc;
1151
1152 adc_pmic->msm_suspend_check = 0;
1153
1154 return 0;
1155}
1156
1157static const struct dev_pm_ops pm8xxx_adc_dev_pm_ops = {
1158 .suspend_noirq = pm8xxx_adc_suspend_noirq,
1159 .resume_noirq = pm8xxx_adc_resume_noirq,
1160};
1161
1162#define PM8XXX_ADC_DEV_PM_OPS (&pm8xxx_adc_dev_pm_ops)
1163#else
1164#define PM8XXX_ADC_DEV_PM_OPS NULL
1165#endif
1166
1167static int __devexit pm8xxx_adc_teardown(struct platform_device *pdev)
1168{
1169 struct pm8xxx_adc *adc_pmic = pmic_adc;
1170 int i;
1171
Siddartha Mohanadossf9dfe1b2012-08-14 15:15:42 -07001172 msm_xo_put(adc_pmic->adc_voter);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001173 platform_set_drvdata(pdev, NULL);
1174 pmic_adc = NULL;
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -08001175 if (!pa_therm) {
1176 regulator_put(pa_therm);
1177 pa_therm = NULL;
1178 }
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001179 for (i = 0; i < adc_pmic->adc_num_board_channel; i++)
1180 device_remove_file(adc_pmic->dev,
1181 &adc_pmic->sens_attr[i].dev_attr);
1182 pm8xxx_adc_initialized = false;
1183
1184 return 0;
1185}
1186
1187static int __devinit pm8xxx_adc_probe(struct platform_device *pdev)
1188{
1189 const struct pm8xxx_adc_platform_data *pdata = pdev->dev.platform_data;
1190 struct pm8xxx_adc *adc_pmic;
1191 struct pm8xxx_adc_amux_properties *adc_amux_prop;
1192 int rc = 0;
1193
1194 if (!pdata) {
1195 dev_err(&pdev->dev, "no platform data?\n");
1196 return -EINVAL;
1197 }
1198
1199 adc_pmic = devm_kzalloc(&pdev->dev, sizeof(struct pm8xxx_adc) +
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001200 (sizeof(struct sensor_device_attribute) *
1201 pdata->adc_num_board_channel), GFP_KERNEL);
1202 if (!adc_pmic) {
1203 dev_err(&pdev->dev, "Unable to allocate memory\n");
1204 return -ENOMEM;
1205 }
1206
1207 adc_amux_prop = devm_kzalloc(&pdev->dev,
1208 sizeof(struct pm8xxx_adc_amux_properties) +
1209 sizeof(struct pm8xxx_adc_chan_properties)
1210 , GFP_KERNEL);
1211 if (!adc_amux_prop) {
1212 dev_err(&pdev->dev, "Unable to allocate memory\n");
1213 return -ENOMEM;
1214 }
1215
1216 adc_pmic->dev = &pdev->dev;
1217 adc_pmic->adc_prop = pdata->adc_prop;
1218 adc_pmic->conv = adc_amux_prop;
1219 init_completion(&adc_pmic->adc_rslt_completion);
1220 adc_pmic->adc_channel = pdata->adc_channel;
1221 adc_pmic->adc_num_board_channel = pdata->adc_num_board_channel;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001222 adc_pmic->mpp_base = pdata->adc_mpp_base;
1223
1224 mutex_init(&adc_pmic->adc_lock);
1225 mutex_init(&adc_pmic->mpp_adc_lock);
1226 spin_lock_init(&adc_pmic->btm_lock);
1227
1228 adc_pmic->adc_irq = platform_get_irq(pdev, PM8XXX_ADC_IRQ_0);
1229 if (adc_pmic->adc_irq < 0)
1230 return adc_pmic->adc_irq;
1231
1232 rc = devm_request_irq(&pdev->dev, adc_pmic->adc_irq,
1233 pm8xxx_adc_isr,
1234 IRQF_TRIGGER_RISING, "pm8xxx_adc_interrupt", adc_pmic);
1235 if (rc) {
1236 dev_err(&pdev->dev, "failed to request adc irq "
1237 "with error %d\n", rc);
Abhijeet Dharmapurikarf5285a22012-04-10 23:42:45 -07001238 } else {
1239 enable_irq_wake(adc_pmic->adc_irq);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001240 }
1241
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001242 adc_pmic->btm_warm_irq = platform_get_irq(pdev, PM8XXX_ADC_IRQ_1);
1243 if (adc_pmic->btm_warm_irq < 0)
1244 return adc_pmic->btm_warm_irq;
1245
1246 rc = devm_request_irq(&pdev->dev, adc_pmic->btm_warm_irq,
1247 pm8xxx_btm_warm_isr,
1248 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
1249 "pm8xxx_btm_warm_interrupt", adc_pmic);
1250 if (rc) {
1251 pr_err("btm warm irq failed %d with interrupt number %d\n",
1252 rc, adc_pmic->btm_warm_irq);
1253 dev_err(&pdev->dev, "failed to request btm irq\n");
1254 }
1255
1256 disable_irq_nosync(adc_pmic->btm_warm_irq);
1257
1258 adc_pmic->btm_cool_irq = platform_get_irq(pdev, PM8XXX_ADC_IRQ_2);
1259 if (adc_pmic->btm_cool_irq < 0)
1260 return adc_pmic->btm_cool_irq;
1261
1262 rc = devm_request_irq(&pdev->dev, adc_pmic->btm_cool_irq,
1263 pm8xxx_btm_cool_isr,
1264 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
1265 "pm8xxx_btm_cool_interrupt", adc_pmic);
1266 if (rc) {
1267 pr_err("btm cool irq failed with return %d and number %d\n",
1268 rc, adc_pmic->btm_cool_irq);
1269 dev_err(&pdev->dev, "failed to request btm irq\n");
1270 }
1271
1272 disable_irq_nosync(adc_pmic->btm_cool_irq);
1273 platform_set_drvdata(pdev, adc_pmic);
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001274 adc_pmic->msm_suspend_check = 0;
1275 pmic_adc = adc_pmic;
1276
1277 INIT_WORK(&adc_pmic->warm_work, pm8xxx_adc_btm_warm_scheduler_fn);
1278 INIT_WORK(&adc_pmic->cool_work, pm8xxx_adc_btm_cool_scheduler_fn);
1279 create_debugfs_entries();
1280 pm8xxx_adc_calib_first_adc = false;
1281 pm8xxx_adc_calib_device_init = false;
1282 pm8xxx_adc_initialized = true;
1283
1284 rc = pm8xxx_adc_init_hwmon(pdev);
1285 if (rc) {
1286 pr_err("pm8xxx adc init hwmon failed with %d\n", rc);
1287 dev_err(&pdev->dev, "failed to initialize pm8xxx hwmon adc\n");
1288 }
1289 adc_pmic->hwmon = hwmon_device_register(adc_pmic->dev);
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -08001290
Siddartha Mohanadossf9dfe1b2012-08-14 15:15:42 -07001291 if (adc_pmic->adc_voter == NULL) {
1292 adc_pmic->adc_voter = msm_xo_get(MSM_XO_TCXO_D0, "pmic_xoadc");
1293 if (IS_ERR(adc_pmic->adc_voter)) {
1294 dev_err(&pdev->dev, "Failed to get XO vote\n");
1295 return PTR_ERR(adc_pmic->adc_voter);
1296 }
1297 }
1298
Siddartha Mohanadoss2c546d32012-02-21 23:01:08 -08001299 pa_therm = regulator_get(adc_pmic->dev, "pa_therm");
1300 if (IS_ERR(pa_therm)) {
1301 rc = PTR_ERR(pa_therm);
1302 pr_err("failed to request pa_therm vreg with error %d\n", rc);
1303 pa_therm = NULL;
1304 }
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001305 return 0;
1306}
1307
1308static struct platform_driver pm8xxx_adc_driver = {
1309 .probe = pm8xxx_adc_probe,
1310 .remove = __devexit_p(pm8xxx_adc_teardown),
1311 .driver = {
1312 .name = PM8XXX_ADC_DEV_NAME,
1313 .owner = THIS_MODULE,
1314 .pm = PM8XXX_ADC_DEV_PM_OPS,
1315 },
1316};
1317
1318static int __init pm8xxx_adc_init(void)
1319{
1320 return platform_driver_register(&pm8xxx_adc_driver);
1321}
1322module_init(pm8xxx_adc_init);
1323
1324static void __exit pm8xxx_adc_exit(void)
1325{
1326 platform_driver_unregister(&pm8xxx_adc_driver);
1327}
1328module_exit(pm8xxx_adc_exit);
1329
1330MODULE_ALIAS("platform:" PM8XXX_ADC_DEV_NAME);
1331MODULE_DESCRIPTION("PMIC8921/8018 ADC driver");
1332MODULE_LICENSE("GPL v2");