blob: cf1801b2009e54a560ad31238a2027469e130f71 [file] [log] [blame]
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
16#include <linux/kernel.h>
17#include <linux/of.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/types.h>
24#include <linux/hwmon.h>
25#include <linux/module.h>
26#include <linux/debugfs.h>
27#include <linux/spmi.h>
28#include <linux/of_irq.h>
29#include <linux/wakelock.h>
30#include <linux/interrupt.h>
31#include <linux/completion.h>
32#include <linux/hwmon-sysfs.h>
33#include <linux/qpnp/qpnp-adc.h>
34#include <linux/thermal.h>
35#include <linux/platform_device.h>
36
37/* QPNP VADC TM register definition */
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -070038#define QPNP_REVISION3 0x2
Siddartha Mohanadossa74b2c72013-04-03 11:12:40 -070039#define QPNP_PERPH_SUBTYPE 0x5
40#define QPNP_PERPH_TYPE2 0x2
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -080041#define QPNP_REVISION_EIGHT_CHANNEL_SUPPORT 2
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -080042#define QPNP_STATUS1 0x8
43#define QPNP_STATUS1_OP_MODE 4
44#define QPNP_STATUS1_MEAS_INTERVAL_EN_STS BIT(2)
45#define QPNP_STATUS1_REQ_STS BIT(1)
46#define QPNP_STATUS1_EOC BIT(0)
47#define QPNP_STATUS2 0x9
48#define QPNP_STATUS2_CONV_SEQ_STATE 6
49#define QPNP_STATUS2_FIFO_NOT_EMPTY_FLAG BIT(1)
50#define QPNP_STATUS2_CONV_SEQ_TIMEOUT_STS BIT(0)
51#define QPNP_CONV_TIMEOUT_ERR 2
52
53#define QPNP_MODE_CTL 0x40
54#define QPNP_OP_MODE_SHIFT 3
55#define QPNP_VREF_XO_THM_FORCE BIT(2)
56#define QPNP_AMUX_TRIM_EN BIT(1)
57#define QPNP_ADC_TRIM_EN BIT(0)
58#define QPNP_EN_CTL1 0x46
59#define QPNP_ADC_TM_EN BIT(7)
60#define QPNP_ADC_CH_SEL_CTL 0x48
61#define QPNP_ADC_DIG_PARAM 0x50
62#define QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT 3
63#define QPNP_HW_SETTLE_DELAY 0x51
64#define QPNP_CONV_REQ 0x52
65#define QPNP_CONV_REQ_SET BIT(7)
66#define QPNP_CONV_SEQ_CTL 0x54
67#define QPNP_CONV_SEQ_HOLDOFF_SHIFT 4
68#define QPNP_CONV_SEQ_TRIG_CTL 0x55
69#define QPNP_ADC_TM_MEAS_INTERVAL_CTL 0x57
70#define QPNP_ADC_TM_MEAS_INTERVAL_TIME_SHIFT 0x3
71#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2 0x58
72#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT 0x4
73#define QPNP_ADC_TM_MEAS_INTERVAL_CTL2_MASK 0xf0
74#define QPNP_ADC_TM_MEAS_INTERVAL_CTL3_MASK 0xf
75
76#define QPNP_ADC_MEAS_INTERVAL_OP_CTL 0x59
77#define QPNP_ADC_MEAS_INTERVAL_OP BIT(7)
78
79#define QPNP_FAST_AVG_CTL 0x5a
80#define QPNP_FAST_AVG_EN 0x5b
81
82#define QPNP_M0_LOW_THR_LSB 0x5c
83#define QPNP_M0_LOW_THR_MSB 0x5d
84#define QPNP_M0_HIGH_THR_LSB 0x5e
85#define QPNP_M0_HIGH_THR_MSB 0x5f
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -080086#define QPNP_M1_ADC_CH_SEL_CTL 0x68
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -080087#define QPNP_M1_LOW_THR_LSB 0x69
88#define QPNP_M1_LOW_THR_MSB 0x6a
89#define QPNP_M1_HIGH_THR_LSB 0x6b
90#define QPNP_M1_HIGH_THR_MSB 0x6c
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -080091#define QPNP_M2_ADC_CH_SEL_CTL 0x70
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -080092#define QPNP_M2_LOW_THR_LSB 0x71
93#define QPNP_M2_LOW_THR_MSB 0x72
Xiaozhe Shi2a503db2013-05-10 17:27:52 -070094#define QPNP_M2_HIGH_THR_LSB 0x73
95#define QPNP_M2_HIGH_THR_MSB 0x74
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -080096#define QPNP_M3_ADC_CH_SEL_CTL 0x78
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -080097#define QPNP_M3_LOW_THR_LSB 0x79
98#define QPNP_M3_LOW_THR_MSB 0x7a
99#define QPNP_M3_HIGH_THR_LSB 0x7b
100#define QPNP_M3_HIGH_THR_MSB 0x7c
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800101#define QPNP_M4_ADC_CH_SEL_CTL 0x80
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800102#define QPNP_M4_LOW_THR_LSB 0x81
103#define QPNP_M4_LOW_THR_MSB 0x82
104#define QPNP_M4_HIGH_THR_LSB 0x83
105#define QPNP_M4_HIGH_THR_MSB 0x84
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800106#define QPNP_M5_ADC_CH_SEL_CTL 0x88
107#define QPNP_M5_LOW_THR_LSB 0x89
108#define QPNP_M5_LOW_THR_MSB 0x8a
109#define QPNP_M5_HIGH_THR_LSB 0x8b
110#define QPNP_M5_HIGH_THR_MSB 0x8c
111#define QPNP_M6_ADC_CH_SEL_CTL 0x90
112#define QPNP_M6_LOW_THR_LSB 0x91
113#define QPNP_M6_LOW_THR_MSB 0x92
114#define QPNP_M6_HIGH_THR_LSB 0x93
115#define QPNP_M6_HIGH_THR_MSB 0x94
116#define QPNP_M7_ADC_CH_SEL_CTL 0x98
117#define QPNP_M7_LOW_THR_LSB 0x99
118#define QPNP_M7_LOW_THR_MSB 0x9a
119#define QPNP_M7_HIGH_THR_LSB 0x9b
120#define QPNP_M7_HIGH_THR_MSB 0x9c
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800121
122#define QPNP_ADC_TM_MULTI_MEAS_EN 0x41
123#define QPNP_ADC_TM_MULTI_MEAS_EN_M0 BIT(0)
124#define QPNP_ADC_TM_MULTI_MEAS_EN_M1 BIT(1)
125#define QPNP_ADC_TM_MULTI_MEAS_EN_M2 BIT(2)
126#define QPNP_ADC_TM_MULTI_MEAS_EN_M3 BIT(3)
127#define QPNP_ADC_TM_MULTI_MEAS_EN_M4 BIT(4)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800128#define QPNP_ADC_TM_MULTI_MEAS_EN_M5 BIT(5)
129#define QPNP_ADC_TM_MULTI_MEAS_EN_M6 BIT(6)
130#define QPNP_ADC_TM_MULTI_MEAS_EN_M7 BIT(7)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800131#define QPNP_ADC_TM_LOW_THR_INT_EN 0x42
132#define QPNP_ADC_TM_LOW_THR_INT_EN_M0 BIT(0)
133#define QPNP_ADC_TM_LOW_THR_INT_EN_M1 BIT(1)
134#define QPNP_ADC_TM_LOW_THR_INT_EN_M2 BIT(2)
135#define QPNP_ADC_TM_LOW_THR_INT_EN_M3 BIT(3)
136#define QPNP_ADC_TM_LOW_THR_INT_EN_M4 BIT(4)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800137#define QPNP_ADC_TM_LOW_THR_INT_EN_M5 BIT(5)
138#define QPNP_ADC_TM_LOW_THR_INT_EN_M6 BIT(6)
139#define QPNP_ADC_TM_LOW_THR_INT_EN_M7 BIT(7)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800140#define QPNP_ADC_TM_HIGH_THR_INT_EN 0x43
141#define QPNP_ADC_TM_HIGH_THR_INT_EN_M0 BIT(0)
142#define QPNP_ADC_TM_HIGH_THR_INT_EN_M1 BIT(1)
143#define QPNP_ADC_TM_HIGH_THR_INT_EN_M2 BIT(2)
144#define QPNP_ADC_TM_HIGH_THR_INT_EN_M3 BIT(3)
145#define QPNP_ADC_TM_HIGH_THR_INT_EN_M4 BIT(4)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800146#define QPNP_ADC_TM_HIGH_THR_INT_EN_M5 BIT(5)
147#define QPNP_ADC_TM_HIGH_THR_INT_EN_M6 BIT(6)
148#define QPNP_ADC_TM_HIGH_THR_INT_EN_M7 BIT(7)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800149
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800150#define QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL 0x59
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800151#define QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL 0x6d
152#define QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL 0x75
153#define QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL 0x7d
154#define QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL 0x85
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800155#define QPNP_ADC_TM_M5_MEAS_INTERVAL_CTL 0x8d
156#define QPNP_ADC_TM_M6_MEAS_INTERVAL_CTL 0x95
157#define QPNP_ADC_TM_M7_MEAS_INTERVAL_CTL 0x9d
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800158#define QPNP_ADC_TM_STATUS1 0x8
159#define QPNP_ADC_TM_STATUS_LOW 0xa
160#define QPNP_ADC_TM_STATUS_HIGH 0xb
161
162#define QPNP_ADC_TM_M0_LOW_THR 0x5d5c
163#define QPNP_ADC_TM_M0_HIGH_THR 0x5f5e
164#define QPNP_ADC_TM_MEAS_INTERVAL 0x0
165
166#define QPNP_ADC_TM_THR_LSB_MASK(val) (val & 0xff)
167#define QPNP_ADC_TM_THR_MSB_MASK(val) ((val & 0xff00) >> 8)
168
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800169#define QPNP_MIN_TIME 2000
170#define QPNP_MAX_TIME 2100
171
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700172struct qpnp_adc_thr_client_info {
173 struct list_head list;
174 struct qpnp_adc_tm_btm_param *btm_param;
175 int32_t low_thr_requested;
176 int32_t high_thr_requested;
177 enum qpnp_state_request state_requested;
178 enum qpnp_state_request state_req_copy;
179 bool low_thr_set;
180 bool high_thr_set;
181 bool notify_low_thr;
182 bool notify_high_thr;
183};
184
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800185struct qpnp_adc_tm_sensor {
186 struct thermal_zone_device *tz_dev;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700187 struct qpnp_adc_tm_chip *chip;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800188 enum thermal_device_mode mode;
189 uint32_t sensor_num;
190 enum qpnp_adc_meas_timer_select timer_select;
191 uint32_t meas_interval;
192 uint32_t low_thr;
193 uint32_t high_thr;
194 uint32_t btm_channel_num;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800195 uint32_t vadc_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800196 struct work_struct work;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800197 bool thermal_node;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700198 uint32_t scale_type;
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700199 struct list_head thr_list;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800200};
201
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700202struct qpnp_adc_tm_chip {
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700203 struct device *dev;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800204 struct qpnp_adc_drv *adc;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700205 struct list_head list;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800206 bool adc_tm_initialized;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800207 int max_channels_available;
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -0700208 struct qpnp_vadc_chip *vadc_dev;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700209 struct work_struct trigger_high_thr_work;
210 struct work_struct trigger_low_thr_work;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800211 struct qpnp_adc_tm_sensor sensor[0];
212};
213
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700214LIST_HEAD(qpnp_adc_tm_device_list);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800215
216struct qpnp_adc_tm_trip_reg_type {
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700217 enum qpnp_adc_tm_channel_select btm_amux_chan;
218 uint16_t low_thr_lsb_addr;
219 uint16_t low_thr_msb_addr;
220 uint16_t high_thr_lsb_addr;
221 uint16_t high_thr_msb_addr;
222 u8 multi_meas_en;
223 u8 low_thr_int_chan_en;
224 u8 high_thr_int_chan_en;
225 u8 meas_interval_ctl;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800226};
227
228static struct qpnp_adc_tm_trip_reg_type adc_tm_data[] = {
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700229 [QPNP_ADC_TM_CHAN0] = {QPNP_ADC_TM_M0_ADC_CH_SEL_CTL,
230 QPNP_M0_LOW_THR_LSB,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800231 QPNP_M0_LOW_THR_MSB, QPNP_M0_HIGH_THR_LSB,
232 QPNP_M0_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M0,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800233 QPNP_ADC_TM_LOW_THR_INT_EN_M0, QPNP_ADC_TM_HIGH_THR_INT_EN_M0,
234 QPNP_ADC_TM_M0_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700235 [QPNP_ADC_TM_CHAN1] = {QPNP_ADC_TM_M1_ADC_CH_SEL_CTL,
236 QPNP_M1_LOW_THR_LSB,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800237 QPNP_M1_LOW_THR_MSB, QPNP_M1_HIGH_THR_LSB,
238 QPNP_M1_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M1,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800239 QPNP_ADC_TM_LOW_THR_INT_EN_M1, QPNP_ADC_TM_HIGH_THR_INT_EN_M1,
240 QPNP_ADC_TM_M1_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700241 [QPNP_ADC_TM_CHAN2] = {QPNP_ADC_TM_M2_ADC_CH_SEL_CTL,
242 QPNP_M2_LOW_THR_LSB,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800243 QPNP_M2_LOW_THR_MSB, QPNP_M2_HIGH_THR_LSB,
244 QPNP_M2_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M2,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800245 QPNP_ADC_TM_LOW_THR_INT_EN_M2, QPNP_ADC_TM_HIGH_THR_INT_EN_M2,
246 QPNP_ADC_TM_M2_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700247 [QPNP_ADC_TM_CHAN3] = {QPNP_ADC_TM_M3_ADC_CH_SEL_CTL,
248 QPNP_M3_LOW_THR_LSB,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800249 QPNP_M3_LOW_THR_MSB, QPNP_M3_HIGH_THR_LSB,
250 QPNP_M3_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M3,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800251 QPNP_ADC_TM_LOW_THR_INT_EN_M3, QPNP_ADC_TM_HIGH_THR_INT_EN_M3,
252 QPNP_ADC_TM_M3_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700253 [QPNP_ADC_TM_CHAN4] = {QPNP_ADC_TM_M4_ADC_CH_SEL_CTL,
254 QPNP_M4_LOW_THR_LSB,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800255 QPNP_M4_LOW_THR_MSB, QPNP_M4_HIGH_THR_LSB,
256 QPNP_M4_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M4,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800257 QPNP_ADC_TM_LOW_THR_INT_EN_M4, QPNP_ADC_TM_HIGH_THR_INT_EN_M4,
258 QPNP_ADC_TM_M4_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700259 [QPNP_ADC_TM_CHAN5] = {QPNP_ADC_TM_M5_ADC_CH_SEL_CTL,
260 QPNP_M5_LOW_THR_LSB,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800261 QPNP_M5_LOW_THR_MSB, QPNP_M5_HIGH_THR_LSB,
262 QPNP_M5_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M5,
263 QPNP_ADC_TM_LOW_THR_INT_EN_M5, QPNP_ADC_TM_HIGH_THR_INT_EN_M5,
264 QPNP_ADC_TM_M5_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700265 [QPNP_ADC_TM_CHAN6] = {QPNP_ADC_TM_M6_ADC_CH_SEL_CTL,
266 QPNP_M6_LOW_THR_LSB,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800267 QPNP_M6_LOW_THR_MSB, QPNP_M6_HIGH_THR_LSB,
268 QPNP_M6_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M6,
269 QPNP_ADC_TM_LOW_THR_INT_EN_M6, QPNP_ADC_TM_HIGH_THR_INT_EN_M6,
270 QPNP_ADC_TM_M6_MEAS_INTERVAL_CTL},
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700271 [QPNP_ADC_TM_CHAN7] = {QPNP_ADC_TM_M7_ADC_CH_SEL_CTL,
272 QPNP_M7_LOW_THR_LSB,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800273 QPNP_M7_LOW_THR_MSB, QPNP_M7_HIGH_THR_LSB,
274 QPNP_M7_HIGH_THR_MSB, QPNP_ADC_TM_MULTI_MEAS_EN_M7,
275 QPNP_ADC_TM_LOW_THR_INT_EN_M7, QPNP_ADC_TM_HIGH_THR_INT_EN_M7,
276 QPNP_ADC_TM_M7_MEAS_INTERVAL_CTL},
277};
278
279static struct qpnp_adc_tm_reverse_scale_fn adc_tm_rscale_fn[] = {
280 [SCALE_R_VBATT] = {qpnp_adc_vbatt_rscaler},
281 [SCALE_RBATT_THERM] = {qpnp_adc_btm_scaler},
282 [SCALE_R_USB_ID] = {qpnp_adc_usb_scaler},
283 [SCALE_RPMIC_THERM] = {qpnp_adc_scale_millidegc_pmic_voltage_thr},
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800284};
285
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700286static int32_t qpnp_adc_tm_read_reg(struct qpnp_adc_tm_chip *chip,
287 int16_t reg, u8 *data)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800288{
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800289 int rc = 0;
290
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700291 rc = spmi_ext_register_readl(chip->adc->spmi->ctrl,
292 chip->adc->slave, (chip->adc->offset + reg), data, 1);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800293 if (rc < 0)
294 pr_err("adc-tm read reg %d failed with %d\n", reg, rc);
295
296 return rc;
297}
298
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700299static int32_t qpnp_adc_tm_write_reg(struct qpnp_adc_tm_chip *chip,
300 int16_t reg, u8 data)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800301{
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800302 int rc = 0;
303 u8 *buf;
304
305 buf = &data;
306
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700307 rc = spmi_ext_register_writel(chip->adc->spmi->ctrl,
308 chip->adc->slave, (chip->adc->offset + reg), buf, 1);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800309 if (rc < 0)
310 pr_err("adc-tm write reg %d failed with %d\n", reg, rc);
311
312 return rc;
313}
314
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700315static int32_t qpnp_adc_tm_enable(struct qpnp_adc_tm_chip *chip)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800316{
317 int rc = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800318 u8 data = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800319
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800320 data = QPNP_ADC_TM_EN;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700321 rc = qpnp_adc_tm_write_reg(chip, QPNP_EN_CTL1, data);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800322 if (rc < 0)
323 pr_err("adc-tm enable failed\n");
324
325 return rc;
326}
327
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700328static int32_t qpnp_adc_tm_disable(struct qpnp_adc_tm_chip *chip)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800329{
330 u8 data = 0;
331 int rc = 0;
332
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700333 rc = qpnp_adc_tm_write_reg(chip, QPNP_EN_CTL1, data);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800334 if (rc < 0)
335 pr_err("adc-tm disable failed\n");
336
337 return rc;
338}
339
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700340static int qpnp_adc_tm_is_valid(struct qpnp_adc_tm_chip *chip)
341{
342 struct qpnp_adc_tm_chip *adc_tm_chip = NULL;
343
344 list_for_each_entry(adc_tm_chip, &qpnp_adc_tm_device_list, list)
345 if (chip == adc_tm_chip)
346 return 0;
347
348 return -EINVAL;
349}
350
351static int32_t qpnp_adc_tm_enable_if_channel_meas(
352 struct qpnp_adc_tm_chip *chip)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800353{
354 u8 adc_tm_meas_en = 0;
355 int rc = 0;
356
357 /* Check if a measurement request is still required */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700358 rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800359 &adc_tm_meas_en);
360 if (rc) {
361 pr_err("adc-tm-tm read status high failed with %d\n", rc);
362 return rc;
363 }
364
365 /* Enable only if there are pending measurement requests */
366 if (adc_tm_meas_en) {
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700367 qpnp_adc_tm_enable(chip);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800368
369 /* Request conversion */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700370 rc = qpnp_adc_tm_write_reg(chip, QPNP_CONV_REQ,
371 QPNP_CONV_REQ_SET);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800372 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800373 pr_err("adc-tm request conversion failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800374 return rc;
375 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800376 }
377
378 return rc;
379}
380
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700381static int32_t qpnp_adc_tm_req_sts_check(struct qpnp_adc_tm_chip *chip)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800382{
383 u8 status1;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800384 int rc, count = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800385
386 /* The VADC_TM bank needs to be disabled for new conversion request */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700387 rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800388 if (rc) {
389 pr_err("adc-tm read status1 failed\n");
390 return rc;
391 }
392
393 /* Disable the bank if a conversion is occuring */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800394 while ((status1 & QPNP_STATUS1_REQ_STS) && (count < 5)) {
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700395 rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS1, &status1);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800396 if (rc < 0)
397 pr_err("adc-tm disable failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800398 /* Wait time is based on the optimum sampling rate
399 * and adding enough time buffer to account for ADC conversions
400 * occuring on different peripheral banks */
401 usleep_range(QPNP_MIN_TIME, QPNP_MAX_TIME);
402 count++;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800403 }
404
405 return rc;
406}
407
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700408static int32_t qpnp_adc_tm_get_btm_idx(uint32_t btm_chan,
409 uint32_t *btm_chan_idx)
410{
411 int rc = 0, i;
412 bool chan_found = false;
413
414 for (i = 0; i < QPNP_ADC_TM_CHAN_NONE; i++) {
415 if (adc_tm_data[i].btm_amux_chan == btm_chan) {
416 *btm_chan_idx = i;
417 chan_found = true;
418 }
419 }
420
421 if (!chan_found)
422 return -EINVAL;
423
424 return rc;
425}
426
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700427static int32_t qpnp_adc_tm_check_revision(struct qpnp_adc_tm_chip *chip,
428 uint32_t btm_chan_num)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800429{
Siddartha Mohanadossa74b2c72013-04-03 11:12:40 -0700430 u8 rev, perph_subtype;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800431 int rc = 0;
432
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700433 rc = qpnp_adc_tm_read_reg(chip, QPNP_REVISION3, &rev);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800434 if (rc) {
435 pr_err("adc-tm revision read failed\n");
436 return rc;
437 }
438
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700439 rc = qpnp_adc_tm_read_reg(chip, QPNP_PERPH_SUBTYPE, &perph_subtype);
Siddartha Mohanadossa74b2c72013-04-03 11:12:40 -0700440 if (rc) {
441 pr_err("adc-tm perph_subtype read failed\n");
442 return rc;
443 }
444
445 if (perph_subtype == QPNP_PERPH_TYPE2) {
446 if ((rev < QPNP_REVISION_EIGHT_CHANNEL_SUPPORT) &&
447 (btm_chan_num > QPNP_ADC_TM_M4_ADC_CH_SEL_CTL)) {
448 pr_debug("Version does not support more than 5 channels\n");
449 return -EINVAL;
450 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800451 }
452
453 return rc;
454}
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700455static int32_t qpnp_adc_tm_mode_select(struct qpnp_adc_tm_chip *chip,
456 u8 mode_ctl)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800457{
458 int rc;
459
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800460 mode_ctl |= (QPNP_ADC_TRIM_EN | QPNP_AMUX_TRIM_EN);
461
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800462 /* VADC_BTM current sets mode to recurring measurements */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700463 rc = qpnp_adc_tm_write_reg(chip, QPNP_MODE_CTL, mode_ctl);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800464 if (rc < 0)
465 pr_err("adc-tm write mode selection err\n");
466
467 return rc;
468}
469
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700470static int32_t qpnp_adc_tm_timer_interval_select(
471 struct qpnp_adc_tm_chip *chip, uint32_t btm_chan,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800472 struct qpnp_vadc_chan_properties *chan_prop)
473{
474 int rc;
475 u8 meas_interval_timer2 = 0;
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700476 uint32_t btm_chan_idx = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800477
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800478 /* Configure kernel clients to timer1 */
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800479 switch (chan_prop->timer_select) {
480 case ADC_MEAS_TIMER_SELECT1:
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700481 rc = qpnp_adc_tm_write_reg(chip,
482 QPNP_ADC_TM_MEAS_INTERVAL_CTL,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800483 chan_prop->meas_interval1);
484 if (rc < 0) {
485 pr_err("timer1 configure failed\n");
486 return rc;
487 }
488 break;
489 case ADC_MEAS_TIMER_SELECT2:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800490 /* Thermal channels uses timer2, default to 1 second */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700491 rc = qpnp_adc_tm_read_reg(chip,
492 QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800493 &meas_interval_timer2);
494 if (rc < 0) {
495 pr_err("timer2 configure read failed\n");
496 return rc;
497 }
498 meas_interval_timer2 |=
499 (chan_prop->meas_interval2 <<
500 QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700501 rc = qpnp_adc_tm_write_reg(chip,
502 QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800503 meas_interval_timer2);
504 if (rc < 0) {
505 pr_err("timer2 configure failed\n");
506 return rc;
507 }
508 break;
509 case ADC_MEAS_TIMER_SELECT3:
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700510 rc = qpnp_adc_tm_read_reg(chip,
511 QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800512 &meas_interval_timer2);
513 if (rc < 0) {
514 pr_err("timer3 read failed\n");
515 return rc;
516 }
517 chan_prop->meas_interval2 = ADC_MEAS3_INTERVAL_1S;
518 meas_interval_timer2 |= chan_prop->meas_interval2;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700519 rc = qpnp_adc_tm_write_reg(chip,
520 QPNP_ADC_TM_MEAS_INTERVAL_CTL2,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800521 meas_interval_timer2);
522 if (rc < 0) {
523 pr_err("timer3 configure failed\n");
524 return rc;
525 }
526 break;
527 default:
528 pr_err("Invalid timer selection\n");
529 return -EINVAL;
530 }
531
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800532 /* Select the timer to use for the corresponding channel */
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700533 rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
534 if (rc < 0) {
535 pr_err("Invalid btm channel idx\n");
536 return rc;
537 }
538 adc_tm_data[btm_chan_idx].meas_interval_ctl = chan_prop->timer_select;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800539
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800540 return rc;
541}
542
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700543static int32_t qpnp_adc_tm_add_to_list(struct qpnp_adc_tm_chip *chip,
544 uint32_t dt_index,
545 struct qpnp_adc_tm_btm_param *param,
546 struct qpnp_vadc_chan_properties *chan_prop)
547{
548 struct qpnp_adc_thr_client_info *client_info = NULL;
549 bool client_info_exists = false;
550
551 list_for_each_entry(client_info,
552 &chip->sensor[dt_index].thr_list, list) {
553 if (client_info->btm_param == param) {
554 client_info->low_thr_requested = chan_prop->low_thr;
555 client_info->high_thr_requested = chan_prop->high_thr;
556 client_info->state_requested = param->state_request;
557 client_info->state_req_copy = param->state_request;
558 client_info->notify_low_thr = false;
559 client_info->notify_high_thr = false;
560 client_info_exists = true;
561 pr_debug("client found\n");
562 }
563 }
564
565 if (!client_info_exists) {
566 client_info = devm_kzalloc(chip->dev,
567 sizeof(struct qpnp_adc_thr_client_info), GFP_KERNEL);
568 if (!client_info) {
569 pr_err("%s: kzalloc() failed.\n", __func__);
570 return -ENOMEM;
571 }
572
573 pr_debug("new client\n");
574 client_info->btm_param = param;
575 client_info->low_thr_requested = chan_prop->low_thr;
576 client_info->high_thr_requested = chan_prop->high_thr;
577 client_info->state_requested = param->state_request;
578 client_info->state_req_copy = param->state_request;
579
580 list_add_tail(&client_info->list,
581 &chip->sensor[dt_index].thr_list);
582 }
583
584 return 0;
585}
586
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700587static int32_t qpnp_adc_tm_reg_update(struct qpnp_adc_tm_chip *chip,
588 uint16_t addr, u8 mask, bool state)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800589{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800590 u8 reg_value = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800591 int rc = 0;
592
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700593 rc = qpnp_adc_tm_read_reg(chip, addr, &reg_value);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800594 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800595 pr_err("read failed for addr:0x%x\n", addr);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800596 return rc;
597 }
598
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800599 reg_value = reg_value & ~mask;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800600 if (state)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800601 reg_value |= mask;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800602
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800603 pr_debug("state:%d, reg:0x%x with bits:0x%x and mask:0x%x\n",
604 state, addr, reg_value, ~mask);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700605 rc = qpnp_adc_tm_write_reg(chip, addr, reg_value);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800606 if (rc < 0) {
607 pr_err("write failed for addr:%x\n", addr);
608 return rc;
609 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800610
611 return rc;
612}
613
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700614static int32_t qpnp_adc_tm_thr_update(struct qpnp_adc_tm_chip *chip,
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700615 uint32_t btm_chan, int32_t high_thr, int32_t low_thr)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800616{
617 int rc = 0;
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700618 uint32_t btm_chan_idx = 0;
619
620 rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
621 if (rc < 0) {
622 pr_err("Invalid btm channel idx\n");
623 return rc;
624 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800625
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700626 rc = qpnp_adc_tm_write_reg(chip,
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700627 adc_tm_data[btm_chan_idx].low_thr_lsb_addr,
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700628 QPNP_ADC_TM_THR_LSB_MASK(low_thr));
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800629 if (rc < 0) {
630 pr_err("low threshold lsb setting failed\n");
631 return rc;
632 }
633
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700634 rc = qpnp_adc_tm_write_reg(chip,
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700635 adc_tm_data[btm_chan_idx].low_thr_msb_addr,
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700636 QPNP_ADC_TM_THR_MSB_MASK(low_thr));
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800637 if (rc < 0) {
638 pr_err("low threshold msb setting failed\n");
639 return rc;
640 }
641
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700642 rc = qpnp_adc_tm_write_reg(chip,
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700643 adc_tm_data[btm_chan_idx].high_thr_lsb_addr,
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700644 QPNP_ADC_TM_THR_LSB_MASK(high_thr));
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800645 if (rc < 0) {
646 pr_err("high threshold lsb setting failed\n");
647 return rc;
648 }
649
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700650 rc = qpnp_adc_tm_write_reg(chip,
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -0700651 adc_tm_data[btm_chan_idx].high_thr_msb_addr,
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700652 QPNP_ADC_TM_THR_MSB_MASK(high_thr));
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800653 if (rc < 0)
654 pr_err("high threshold msb setting failed\n");
655
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700656 pr_debug("client requested high:%d and low:%d\n",
657 high_thr, low_thr);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800658
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800659 return rc;
660}
661
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700662static int32_t qpnp_adc_tm_manage_thresholds(struct qpnp_adc_tm_chip *chip,
663 uint32_t dt_index, uint32_t btm_chan)
664{
665 struct qpnp_adc_thr_client_info *client_info = NULL;
666 struct list_head *thr_list;
667 int high_thr = 0, low_thr = 0, rc = 0;
668
669
670 /* high_thr/low_thr starting point and reset the high_thr_set and
671 low_thr_set back to reset since the thresholds will be
672 recomputed */
673 list_for_each(thr_list,
674 &chip->sensor[dt_index].thr_list) {
675 client_info = list_entry(thr_list,
676 struct qpnp_adc_thr_client_info, list);
677 high_thr = client_info->high_thr_requested;
678 low_thr = client_info->low_thr_requested;
679 client_info->high_thr_set = false;
680 client_info->low_thr_set = false;
681 }
682
683 pr_debug("init threshold is high:%d and low:%d\n", high_thr, low_thr);
684
685 /* Find the min of high_thr and max of low_thr */
686 list_for_each(thr_list,
687 &chip->sensor[dt_index].thr_list) {
688 client_info = list_entry(thr_list,
689 struct qpnp_adc_thr_client_info, list);
690 if ((client_info->state_req_copy == ADC_TM_HIGH_THR_ENABLE) ||
691 (client_info->state_req_copy ==
692 ADC_TM_HIGH_LOW_THR_ENABLE))
693 if (client_info->high_thr_requested < high_thr)
694 high_thr = client_info->high_thr_requested;
695
696 if ((client_info->state_req_copy == ADC_TM_LOW_THR_ENABLE) ||
697 (client_info->state_req_copy ==
698 ADC_TM_HIGH_LOW_THR_ENABLE))
699 if (client_info->low_thr_requested > low_thr)
700 low_thr = client_info->low_thr_requested;
701
702 pr_debug("threshold compared is high:%d and low:%d\n",
703 client_info->high_thr_requested,
704 client_info->low_thr_requested);
705 pr_debug("current threshold is high:%d and low:%d\n",
706 high_thr, low_thr);
707 }
708
709 /* Check which of the high_thr and low_thr got set */
710 list_for_each(thr_list,
711 &chip->sensor[dt_index].thr_list) {
712 client_info = list_entry(thr_list,
713 struct qpnp_adc_thr_client_info, list);
714 if ((client_info->state_req_copy == ADC_TM_HIGH_THR_ENABLE) ||
715 (client_info->state_req_copy ==
716 ADC_TM_HIGH_LOW_THR_ENABLE))
717 if (high_thr == client_info->high_thr_requested)
718 client_info->high_thr_set = true;
719
720 if ((client_info->state_req_copy == ADC_TM_LOW_THR_ENABLE) ||
721 (client_info->state_req_copy ==
722 ADC_TM_HIGH_LOW_THR_ENABLE))
723 if (low_thr == client_info->low_thr_requested)
724 client_info->low_thr_set = true;
725 }
726
727 rc = qpnp_adc_tm_thr_update(chip, btm_chan, high_thr, low_thr);
728 if (rc < 0)
729 pr_err("setting chan:%d threshold failed\n", btm_chan);
730
731 pr_debug("threshold written is high:%d and low:%d\n",
732 high_thr, low_thr);
733
734 return 0;
735}
736
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700737static int32_t qpnp_adc_tm_channel_configure(struct qpnp_adc_tm_chip *chip,
738 uint32_t btm_chan,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800739 struct qpnp_vadc_chan_properties *chan_prop,
740 uint32_t amux_channel)
741{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800742 int rc = 0, i = 0, chan_idx = 0;
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700743 bool chan_found = false, high_thr_set = false, low_thr_set = false;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800744 u8 sensor_mask = 0;
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700745 struct qpnp_adc_thr_client_info *client_info = NULL;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800746
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700747 while (i < chip->max_channels_available) {
748 if (chip->sensor[i].btm_channel_num == btm_chan) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800749 chan_idx = i;
750 chan_found = true;
751 i++;
752 } else
753 i++;
754 }
755
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -0700756 if (!chan_found) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800757 pr_err("Channel not found\n");
758 return -EINVAL;
759 }
760
761 sensor_mask = 1 << chan_idx;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700762 if (!chip->sensor[chan_idx].thermal_node) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800763 /* Update low and high notification thresholds */
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700764 rc = qpnp_adc_tm_manage_thresholds(chip, chan_idx,
765 btm_chan);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800766 if (rc < 0) {
767 pr_err("setting chan:%d threshold failed\n", btm_chan);
768 return rc;
769 }
770
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700771 list_for_each_entry(client_info,
772 &chip->sensor[chan_idx].thr_list, list) {
773 if (client_info->high_thr_set == true)
774 high_thr_set = true;
775 if (client_info->low_thr_set == true)
776 low_thr_set = true;
777 }
778
779 if (low_thr_set) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800780 pr_debug("low sensor mask:%x with state:%d\n",
781 sensor_mask, chan_prop->state_request);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800782 /* Enable low threshold's interrupt */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700783 rc = qpnp_adc_tm_reg_update(chip,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800784 QPNP_ADC_TM_LOW_THR_INT_EN, sensor_mask, true);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800785 if (rc < 0) {
786 pr_err("low thr enable err:%d\n", btm_chan);
787 return rc;
788 }
789 }
790
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700791 if (high_thr_set) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800792 /* Enable high threshold's interrupt */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800793 pr_debug("high sensor mask:%x\n", sensor_mask);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700794 rc = qpnp_adc_tm_reg_update(chip,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800795 QPNP_ADC_TM_HIGH_THR_INT_EN, sensor_mask, true);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800796 if (rc < 0) {
797 pr_err("high thr enable err:%d\n", btm_chan);
798 return rc;
799 }
800 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800801 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800802
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800803 /* Enable corresponding BTM channel measurement */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700804 rc = qpnp_adc_tm_reg_update(chip,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800805 QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, true);
806 if (rc < 0) {
807 pr_err("multi measurement en failed\n");
808 return rc;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800809 }
810
811 return rc;
812}
813
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700814static int32_t qpnp_adc_tm_configure(struct qpnp_adc_tm_chip *chip,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800815 struct qpnp_adc_amux_properties *chan_prop)
816{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800817 u8 decimation = 0, op_cntrl = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800818 int rc = 0;
819 uint32_t btm_chan = 0;
820
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800821 /* Disable bank */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700822 rc = qpnp_adc_tm_disable(chip);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800823 if (rc)
824 return rc;
825
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800826 /* Check if a conversion is in progress */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700827 rc = qpnp_adc_tm_req_sts_check(chip);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800828 if (rc < 0) {
829 pr_err("adc-tm req_sts check failed\n");
830 return rc;
831 }
832
833 /* Set measurement in recurring mode */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700834 rc = qpnp_adc_tm_mode_select(chip, chan_prop->mode_sel);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800835 if (rc < 0) {
836 pr_err("adc-tm mode select failed\n");
837 return rc;
838 }
839
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800840 /* Configure AMUX channel select for the corresponding BTM channel*/
841 btm_chan = chan_prop->chan_prop->tm_channel_select;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700842 rc = qpnp_adc_tm_write_reg(chip, btm_chan, chan_prop->amux_channel);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800843 if (rc < 0) {
844 pr_err("adc-tm channel selection err\n");
845 return rc;
846 }
847
848 /* Digital paramater setup */
849 decimation |= chan_prop->decimation <<
850 QPNP_ADC_DIG_DEC_RATIO_SEL_SHIFT;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700851 rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_DIG_PARAM, decimation);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800852 if (rc < 0) {
853 pr_err("adc-tm digital parameter setup err\n");
854 return rc;
855 }
856
857 /* Hardware setting time */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700858 rc = qpnp_adc_tm_write_reg(chip, QPNP_HW_SETTLE_DELAY,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800859 chan_prop->hw_settle_time);
860 if (rc < 0) {
861 pr_err("adc-tm hw settling time setup err\n");
862 return rc;
863 }
864
865 /* Fast averaging setup */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700866 rc = qpnp_adc_tm_write_reg(chip, QPNP_FAST_AVG_CTL,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800867 chan_prop->fast_avg_setup);
868 if (rc < 0) {
869 pr_err("adc-tm fast-avg setup err\n");
870 return rc;
871 }
872
873 /* Measurement interval setup */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700874 rc = qpnp_adc_tm_timer_interval_select(chip, btm_chan,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800875 chan_prop->chan_prop);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800876 if (rc < 0) {
877 pr_err("adc-tm timer select failed\n");
878 return rc;
879 }
880
881 /* Channel configuration setup */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700882 rc = qpnp_adc_tm_channel_configure(chip, btm_chan,
883 chan_prop->chan_prop, chan_prop->amux_channel);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800884 if (rc < 0) {
885 pr_err("adc-tm channel configure failed\n");
886 return rc;
887 }
888
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800889 /* Recurring interval measurement enable */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700890 rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_MEAS_INTERVAL_OP_CTL,
891 &op_cntrl);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800892 op_cntrl |= QPNP_ADC_MEAS_INTERVAL_OP;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700893 rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_MEAS_INTERVAL_OP_CTL,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800894 op_cntrl, true);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800895 if (rc < 0) {
896 pr_err("adc-tm meas interval op configure failed\n");
897 return rc;
898 }
899
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800900 /* Enable bank */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700901 rc = qpnp_adc_tm_enable(chip);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800902 if (rc)
903 return rc;
904
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800905 /* Request conversion */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700906 rc = qpnp_adc_tm_write_reg(chip, QPNP_CONV_REQ, QPNP_CONV_REQ_SET);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800907 if (rc < 0) {
908 pr_err("adc-tm request conversion failed\n");
909 return rc;
910 }
911
912 return 0;
913}
914
915static int qpnp_adc_tm_get_mode(struct thermal_zone_device *thermal,
916 enum thermal_device_mode *mode)
917{
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700918 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800919
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700920 if ((IS_ERR(adc_tm)) || qpnp_adc_tm_check_revision(
921 adc_tm->chip, adc_tm->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800922 return -EINVAL;
923
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700924 *mode = adc_tm->mode;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800925
926 return 0;
927}
928
929static int qpnp_adc_tm_set_mode(struct thermal_zone_device *thermal,
930 enum thermal_device_mode mode)
931{
932 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700933 struct qpnp_adc_tm_chip *chip = adc_tm->chip;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800934 int rc = 0, channel;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800935 u8 sensor_mask = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800936
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700937 if (qpnp_adc_tm_is_valid(chip)) {
938 pr_err("invalid device\n");
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700939 return -ENODEV;
Siddartha Mohanadossbb315992013-09-11 13:28:51 -0700940 }
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700941
942 if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800943 return -EINVAL;
944
945 if (mode == THERMAL_DEVICE_ENABLED) {
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700946 chip->adc->amux_prop->amux_channel =
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800947 adc_tm->vadc_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800948 channel = adc_tm->sensor_num;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700949 chip->adc->amux_prop->decimation =
950 chip->adc->adc_channels[channel].adc_decimation;
951 chip->adc->amux_prop->hw_settle_time =
952 chip->adc->adc_channels[channel].hw_settle_time;
953 chip->adc->amux_prop->fast_avg_setup =
954 chip->adc->adc_channels[channel].fast_avg_setup;
955 chip->adc->amux_prop->mode_sel =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800956 ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700957 chip->adc->amux_prop->chan_prop->timer_select =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800958 ADC_MEAS_TIMER_SELECT1;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700959 chip->adc->amux_prop->chan_prop->meas_interval1 =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800960 ADC_MEAS1_INTERVAL_1S;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700961 chip->adc->amux_prop->chan_prop->low_thr = adc_tm->low_thr;
962 chip->adc->amux_prop->chan_prop->high_thr = adc_tm->high_thr;
963 chip->adc->amux_prop->chan_prop->tm_channel_select =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800964 adc_tm->btm_channel_num;
965
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700966 rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800967 if (rc) {
968 pr_err("adc-tm tm configure failed with %d\n", rc);
969 return -EINVAL;
970 }
971 } else if (mode == THERMAL_DEVICE_DISABLED) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800972 sensor_mask = 1 << adc_tm->sensor_num;
973 /* Disable bank */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700974 rc = qpnp_adc_tm_disable(chip);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800975 if (rc < 0) {
976 pr_err("adc-tm disable failed\n");
977 return rc;
978 }
979
980 /* Check if a conversion is in progress */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700981 rc = qpnp_adc_tm_req_sts_check(chip);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800982 if (rc < 0) {
983 pr_err("adc-tm req_sts check failed\n");
984 return rc;
985 }
986
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700987 rc = qpnp_adc_tm_reg_update(chip,
988 QPNP_ADC_TM_MULTI_MEAS_EN, sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800989 if (rc < 0) {
990 pr_err("multi measurement update failed\n");
991 return rc;
992 }
993
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -0700994 rc = qpnp_adc_tm_enable_if_channel_meas(chip);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800995 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800996 pr_err("re-enabling measurement failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800997 return rc;
998 }
999 }
1000
1001 adc_tm->mode = mode;
1002
1003 return 0;
1004}
1005
1006static int qpnp_adc_tm_get_trip_type(struct thermal_zone_device *thermal,
1007 int trip, enum thermal_trip_type *type)
1008{
1009 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001010 struct qpnp_adc_tm_chip *chip = adc_tm->chip;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001011
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001012 if (qpnp_adc_tm_is_valid(chip))
1013 return -ENODEV;
1014
1015 if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001016 return -EINVAL;
1017
1018 switch (trip) {
1019 case ADC_TM_TRIP_HIGH_WARM:
1020 *type = THERMAL_TRIP_CONFIGURABLE_HI;
1021 break;
1022 case ADC_TM_TRIP_LOW_COOL:
1023 *type = THERMAL_TRIP_CONFIGURABLE_LOW;
1024 break;
1025 default:
1026 return -EINVAL;
1027 }
1028
1029 return 0;
1030}
1031
1032static int qpnp_adc_tm_get_trip_temp(struct thermal_zone_device *thermal,
1033 int trip, unsigned long *temp)
1034{
1035 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001036 struct qpnp_adc_tm_chip *chip = adc_tm_sensor->chip;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001037 int64_t result = 0;
1038 u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001039 unsigned int reg, rc = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001040 uint16_t reg_low_thr_lsb, reg_low_thr_msb;
1041 uint16_t reg_high_thr_lsb, reg_high_thr_msb;
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001042 uint32_t btm_chan_idx = 0, btm_chan = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001043
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001044 if (qpnp_adc_tm_is_valid(chip))
1045 return -ENODEV;
1046
1047 if (qpnp_adc_tm_check_revision(chip, adc_tm_sensor->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001048 return -EINVAL;
1049
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001050 btm_chan = adc_tm_sensor->btm_channel_num;
1051 rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
1052 if (rc < 0) {
1053 pr_err("Invalid btm channel idx\n");
1054 return rc;
1055 }
1056
1057 reg_low_thr_lsb = adc_tm_data[btm_chan_idx].low_thr_lsb_addr;
1058 reg_low_thr_msb = adc_tm_data[btm_chan_idx].low_thr_msb_addr;
1059 reg_high_thr_lsb = adc_tm_data[btm_chan_idx].high_thr_lsb_addr;
1060 reg_high_thr_msb = adc_tm_data[btm_chan_idx].high_thr_msb_addr;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001061
1062 switch (trip) {
1063 case ADC_TM_TRIP_HIGH_WARM:
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001064 rc = qpnp_adc_tm_read_reg(chip, reg_low_thr_lsb,
1065 &trip_warm_thr0);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001066 if (rc) {
1067 pr_err("adc-tm low_thr_lsb err\n");
1068 return rc;
1069 }
1070
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001071 rc = qpnp_adc_tm_read_reg(chip, reg_low_thr_msb,
1072 &trip_warm_thr1);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001073 if (rc) {
1074 pr_err("adc-tm low_thr_msb err\n");
1075 return rc;
1076 }
1077 reg = (trip_warm_thr1 << 8) | trip_warm_thr0;
1078 break;
1079 case ADC_TM_TRIP_LOW_COOL:
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001080 rc = qpnp_adc_tm_read_reg(chip, reg_high_thr_lsb,
1081 &trip_cool_thr0);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001082 if (rc) {
1083 pr_err("adc-tm_tm high_thr_lsb err\n");
1084 return rc;
1085 }
1086
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001087 rc = qpnp_adc_tm_read_reg(chip, reg_high_thr_msb,
1088 &trip_cool_thr1);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001089 if (rc) {
1090 pr_err("adc-tm_tm high_thr_lsb err\n");
1091 return rc;
1092 }
1093 reg = (trip_cool_thr1 << 8) | trip_cool_thr0;
1094 break;
1095 default:
1096 return -EINVAL;
1097 }
1098
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001099 rc = qpnp_adc_tm_scale_voltage_therm_pu2(chip->vadc_dev, reg,
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001100 &result);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001101 if (rc < 0) {
1102 pr_err("Failed to lookup the therm thresholds\n");
1103 return rc;
1104 }
1105
1106 *temp = result;
1107
1108 return 0;
1109}
1110
1111static int qpnp_adc_tm_set_trip_temp(struct thermal_zone_device *thermal,
1112 int trip, long temp)
1113{
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001114 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
1115 struct qpnp_adc_tm_chip *chip = adc_tm->chip;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001116 struct qpnp_adc_tm_config tm_config;
1117 u8 trip_cool_thr0, trip_cool_thr1, trip_warm_thr0, trip_warm_thr1;
1118 uint16_t reg_low_thr_lsb, reg_low_thr_msb;
1119 uint16_t reg_high_thr_lsb, reg_high_thr_msb;
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001120 int rc = 0;
1121 uint32_t btm_chan = 0, btm_chan_idx = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001122
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001123 if (qpnp_adc_tm_is_valid(chip))
1124 return -ENODEV;
1125
1126 if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001127 return -EINVAL;
1128
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001129 tm_config.channel = adc_tm->vadc_channel_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001130 switch (trip) {
1131 case ADC_TM_TRIP_HIGH_WARM:
1132 tm_config.high_thr_temp = temp;
1133 break;
1134 case ADC_TM_TRIP_LOW_COOL:
1135 tm_config.low_thr_temp = temp;
1136 break;
1137 default:
1138 return -EINVAL;
1139 }
1140
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001141 pr_debug("requested a high - %d and low - %d with trip - %d\n",
1142 tm_config.high_thr_temp, tm_config.low_thr_temp, trip);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001143 rc = qpnp_adc_tm_scale_therm_voltage_pu2(chip->vadc_dev, &tm_config);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001144 if (rc < 0) {
1145 pr_err("Failed to lookup the adc-tm thresholds\n");
1146 return rc;
1147 }
1148
1149 trip_warm_thr0 = ((tm_config.low_thr_voltage << 24) >> 24);
1150 trip_warm_thr1 = ((tm_config.low_thr_voltage << 16) >> 24);
1151 trip_cool_thr0 = ((tm_config.high_thr_voltage << 24) >> 24);
1152 trip_cool_thr1 = ((tm_config.high_thr_voltage << 16) >> 24);
1153
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001154 btm_chan = adc_tm->btm_channel_num;
1155 rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
1156 if (rc < 0) {
1157 pr_err("Invalid btm channel idx\n");
1158 return rc;
1159 }
1160
1161 reg_low_thr_lsb = adc_tm_data[btm_chan_idx].low_thr_lsb_addr;
1162 reg_low_thr_msb = adc_tm_data[btm_chan_idx].low_thr_msb_addr;
1163 reg_high_thr_lsb = adc_tm_data[btm_chan_idx].high_thr_lsb_addr;
1164 reg_high_thr_msb = adc_tm_data[btm_chan_idx].high_thr_msb_addr;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001165
1166 switch (trip) {
1167 case ADC_TM_TRIP_HIGH_WARM:
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001168 rc = qpnp_adc_tm_write_reg(chip, reg_low_thr_lsb,
1169 trip_cool_thr0);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001170 if (rc) {
1171 pr_err("adc-tm_tm read threshold err\n");
1172 return rc;
1173 }
1174
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001175 rc = qpnp_adc_tm_write_reg(chip, reg_low_thr_msb,
1176 trip_cool_thr1);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001177 if (rc) {
1178 pr_err("adc-tm_tm read threshold err\n");
1179 return rc;
1180 }
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001181 adc_tm->low_thr = tm_config.high_thr_voltage;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001182 break;
1183 case ADC_TM_TRIP_LOW_COOL:
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001184 rc = qpnp_adc_tm_write_reg(chip, reg_high_thr_lsb,
1185 trip_warm_thr0);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001186 if (rc) {
1187 pr_err("adc-tm_tm read threshold err\n");
1188 return rc;
1189 }
1190
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001191 rc = qpnp_adc_tm_write_reg(chip, reg_high_thr_msb,
1192 trip_warm_thr1);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001193 if (rc) {
1194 pr_err("adc-tm_tm read threshold err\n");
1195 return rc;
1196 }
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001197 adc_tm->high_thr = tm_config.low_thr_voltage;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001198 break;
1199 default:
1200 return -EINVAL;
1201 }
1202
1203 return 0;
1204}
1205
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001206static void notify_battery_therm(struct qpnp_adc_tm_sensor *adc_tm)
1207{
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001208 struct qpnp_adc_thr_client_info *client_info = NULL;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001209
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001210 list_for_each_entry(client_info,
1211 &adc_tm->thr_list, list) {
1212 /* Batt therm's warm temperature translates to low voltage */
1213 if (client_info->notify_low_thr) {
1214 /* HIGH_STATE = WARM_TEMP for battery client */
1215 client_info->btm_param->threshold_notification(
1216 ADC_TM_WARM_STATE, client_info->btm_param->btm_ctx);
1217 client_info->notify_low_thr = false;
1218 }
1219
1220 /* Batt therm's cool temperature translates to high voltage */
1221 if (client_info->notify_high_thr) {
1222 /* LOW_STATE = COOL_TEMP for battery client */
1223 client_info->btm_param->threshold_notification(
1224 ADC_TM_COOL_STATE, client_info->btm_param->btm_ctx);
1225 client_info->notify_high_thr = false;
1226 }
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001227 }
1228
1229 return;
1230}
1231
1232static void notify_clients(struct qpnp_adc_tm_sensor *adc_tm)
1233{
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001234 struct qpnp_adc_thr_client_info *client_info = NULL;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001235
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001236 list_for_each_entry(client_info,
1237 &adc_tm->thr_list, list) {
1238 /* For non batt therm clients */
1239 if (client_info->notify_low_thr) {
1240 if (client_info->btm_param->threshold_notification
1241 != NULL) {
1242 pr_debug("notify kernel with low state\n");
1243 client_info->btm_param->threshold_notification(
1244 ADC_TM_LOW_STATE,
1245 client_info->btm_param->btm_ctx);
1246 client_info->notify_low_thr = false;
1247 }
1248 }
1249
1250 if (client_info->notify_high_thr) {
1251 if (client_info->btm_param->threshold_notification
1252 != NULL) {
1253 pr_debug("notify kernel with high state\n");
1254 client_info->btm_param->threshold_notification(
1255 ADC_TM_HIGH_STATE,
1256 client_info->btm_param->btm_ctx);
1257 client_info->notify_high_thr = false;
1258 }
1259 }
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001260 }
1261
1262 return;
1263}
1264
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001265static void notify_adc_tm_fn(struct work_struct *work)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001266{
1267 struct qpnp_adc_tm_sensor *adc_tm = container_of(work,
1268 struct qpnp_adc_tm_sensor, work);
1269
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001270 if (adc_tm->thermal_node) {
1271 sysfs_notify(&adc_tm->tz_dev->device.kobj,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001272 NULL, "btm");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001273 pr_debug("notifying uspace client\n");
1274 } else {
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001275 if (adc_tm->scale_type == SCALE_RBATT_THERM)
1276 notify_battery_therm(adc_tm);
1277 else
1278 notify_clients(adc_tm);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001279 }
1280
1281 return;
1282}
1283
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001284static int qpnp_adc_tm_activate_trip_type(struct thermal_zone_device *thermal,
1285 int trip, enum thermal_trip_activation_mode mode)
1286{
1287 struct qpnp_adc_tm_sensor *adc_tm = thermal->devdata;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001288 struct qpnp_adc_tm_chip *chip = adc_tm->chip;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001289 int rc = 0, sensor_mask = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001290 u8 thr_int_en = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001291 bool state = false;
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001292 uint32_t btm_chan_idx = 0, btm_chan = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001293
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001294 if (qpnp_adc_tm_is_valid(chip))
1295 return -ENODEV;
1296
1297 if (qpnp_adc_tm_check_revision(chip, adc_tm->btm_channel_num))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001298 return -EINVAL;
1299
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001300 if (mode == THERMAL_TRIP_ACTIVATION_ENABLED)
1301 state = true;
1302
1303 sensor_mask = 1 << adc_tm->sensor_num;
1304
1305 pr_debug("Sensor number:%x with state:%d\n", adc_tm->sensor_num, state);
1306
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001307 btm_chan = adc_tm->btm_channel_num;
1308 rc = qpnp_adc_tm_get_btm_idx(btm_chan, &btm_chan_idx);
1309 if (rc < 0) {
1310 pr_err("Invalid btm channel idx\n");
1311 return rc;
1312 }
1313
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001314 switch (trip) {
1315 case ADC_TM_TRIP_HIGH_WARM:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001316 /* low_thr (lower voltage) for higher temp */
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001317 thr_int_en = adc_tm_data[btm_chan_idx].low_thr_int_chan_en;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001318 rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001319 sensor_mask, state);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001320 if (rc)
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001321 pr_err("channel:%x failed\n", btm_chan);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001322 break;
1323 case ADC_TM_TRIP_LOW_COOL:
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001324 /* high_thr (higher voltage) for cooler temp */
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001325 thr_int_en = adc_tm_data[btm_chan_idx].high_thr_int_chan_en;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001326 rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001327 sensor_mask, state);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001328 if (rc)
Siddartha Mohanadoss71a83442013-08-29 11:43:24 -07001329 pr_err("channel:%x failed\n", btm_chan);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001330 break;
1331 default:
1332 return -EINVAL;
1333 }
1334
1335 return rc;
1336}
1337
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001338static int qpnp_adc_tm_read_status(struct qpnp_adc_tm_chip *chip)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001339{
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001340 u8 status_low = 0, status_high = 0, qpnp_adc_tm_meas_en = 0;
1341 u8 adc_tm_low_enable = 0, adc_tm_high_enable = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001342 u8 sensor_mask = 0;
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001343 int rc = 0, sensor_notify_num = 0, i = 0, sensor_num = 0;
1344 uint32_t btm_chan_num = 0;
1345 struct qpnp_adc_thr_client_info *client_info = NULL;
1346 struct list_head *thr_list;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001347
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001348 if (qpnp_adc_tm_is_valid(chip))
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001349 return -ENODEV;
1350
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001351 mutex_lock(&chip->adc->adc_lock);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001352
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001353 rc = qpnp_adc_tm_req_sts_check(chip);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001354 if (rc) {
1355 pr_err("adc-tm-tm req sts check failed with %d\n", rc);
1356 goto fail;
1357 }
1358
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001359 rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS_LOW, &status_low);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001360 if (rc) {
1361 pr_err("adc-tm-tm read status low failed with %d\n", rc);
1362 goto fail;
1363 }
1364
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001365 rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_STATUS_HIGH, &status_high);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001366 if (rc) {
1367 pr_err("adc-tm-tm read status high failed with %d\n", rc);
1368 goto fail;
1369 }
1370
1371 /* Check which interrupt threshold is lower and measure against the
1372 * enabled channel */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001373 rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001374 &qpnp_adc_tm_meas_en);
1375 if (rc) {
1376 pr_err("adc-tm-tm read status high failed with %d\n", rc);
1377 goto fail;
1378 }
1379
1380 adc_tm_low_enable = qpnp_adc_tm_meas_en & status_low;
1381 adc_tm_high_enable = qpnp_adc_tm_meas_en & status_high;
1382
1383 if (adc_tm_high_enable) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001384 sensor_notify_num = adc_tm_high_enable;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001385 while (i < chip->max_channels_available) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001386 if ((sensor_notify_num & 0x1) == 1)
1387 sensor_num = i;
1388 sensor_notify_num >>= 1;
1389 i++;
1390 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001391
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001392 btm_chan_num = chip->sensor[sensor_num].btm_channel_num;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001393 pr_debug("high:sen:%d, hs:0x%x, ls:0x%x, meas_en:0x%x\n",
1394 sensor_num, adc_tm_high_enable, adc_tm_low_enable,
1395 qpnp_adc_tm_meas_en);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001396 if (!chip->sensor[sensor_num].thermal_node) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001397 /* For non thermal registered clients
1398 such as usb_id, vbatt, pmic_therm */
1399 sensor_mask = 1 << sensor_num;
1400 pr_debug("non thermal node - mask:%x\n", sensor_mask);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001401 rc = qpnp_adc_tm_reg_update(chip,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001402 QPNP_ADC_TM_HIGH_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001403 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001404 if (rc < 0) {
1405 pr_err("high threshold int read failed\n");
1406 goto fail;
1407 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001408 } else {
1409 /* Uses the thermal sysfs registered device to disable
1410 the corresponding high voltage threshold which
1411 is triggered by low temp */
1412 pr_debug("thermal node with mask:%x\n", sensor_mask);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001413 rc = qpnp_adc_tm_activate_trip_type(
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001414 chip->sensor[sensor_num].tz_dev,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001415 ADC_TM_TRIP_LOW_COOL,
1416 THERMAL_TRIP_ACTIVATION_DISABLED);
1417 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001418 pr_err("notify error:%d\n", sensor_num);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001419 goto fail;
1420 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001421 }
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001422 list_for_each(thr_list, &chip->sensor[sensor_num].thr_list) {
1423 client_info = list_entry(thr_list,
1424 struct qpnp_adc_thr_client_info, list);
1425 if (client_info->high_thr_set) {
1426 client_info->high_thr_set = false;
1427 client_info->notify_high_thr = true;
1428 if (client_info->state_req_copy ==
1429 ADC_TM_HIGH_LOW_THR_ENABLE)
1430 client_info->state_req_copy =
1431 ADC_TM_LOW_THR_ENABLE;
1432 else
1433 client_info->state_req_copy =
1434 ADC_TM_HIGH_THR_DISABLE;
1435 }
1436 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001437 }
1438
1439 if (adc_tm_low_enable) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001440 sensor_notify_num = adc_tm_low_enable;
1441 i = 0;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001442 while (i < chip->max_channels_available) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001443 if ((sensor_notify_num & 0x1) == 1)
1444 sensor_num = i;
1445 sensor_notify_num >>= 1;
1446 i++;
1447 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001448
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001449 btm_chan_num = chip->sensor[sensor_num].btm_channel_num;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001450 pr_debug("low:sen:%d, hs:0x%x, ls:0x%x, meas_en:0x%x\n",
1451 sensor_num, adc_tm_high_enable, adc_tm_low_enable,
1452 qpnp_adc_tm_meas_en);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001453 if (!chip->sensor[sensor_num].thermal_node) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001454 /* For non thermal registered clients
1455 such as usb_id, vbatt, pmic_therm */
1456 pr_debug("non thermal node - mask:%x\n", sensor_mask);
1457 sensor_mask = 1 << sensor_num;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001458 rc = qpnp_adc_tm_reg_update(chip,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001459 QPNP_ADC_TM_LOW_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001460 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001461 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001462 pr_err("low threshold int read failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001463 goto fail;
1464 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001465 } else {
1466 /* Uses the thermal sysfs registered device to disable
1467 the corresponding low voltage threshold which
1468 is triggered by high temp */
1469 pr_debug("thermal node with mask:%x\n", sensor_mask);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001470 rc = qpnp_adc_tm_activate_trip_type(
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001471 chip->sensor[sensor_num].tz_dev,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001472 ADC_TM_TRIP_HIGH_WARM,
1473 THERMAL_TRIP_ACTIVATION_DISABLED);
1474 if (rc < 0) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001475 pr_err("notify error:%d\n", sensor_num);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001476 goto fail;
1477 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001478 }
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001479 list_for_each(thr_list, &chip->sensor[sensor_num].thr_list) {
1480 client_info = list_entry(thr_list,
1481 struct qpnp_adc_thr_client_info, list);
1482 if (client_info->low_thr_set) {
1483 /* mark the corresponding clients threshold
1484 as not set */
1485 client_info->low_thr_set = false;
1486 client_info->notify_low_thr = true;
1487 if (client_info->state_req_copy ==
1488 ADC_TM_HIGH_LOW_THR_ENABLE)
1489 client_info->state_req_copy =
1490 ADC_TM_HIGH_THR_ENABLE;
1491 else
1492 client_info->state_req_copy =
1493 ADC_TM_LOW_THR_DISABLE;
1494 }
1495 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001496 }
1497
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001498 qpnp_adc_tm_manage_thresholds(chip, sensor_num, btm_chan_num);
1499
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -07001500 if (adc_tm_high_enable || adc_tm_low_enable) {
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001501 rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -07001502 sensor_mask, false);
1503 if (rc < 0) {
1504 pr_err("multi meas disable for channel failed\n");
1505 goto fail;
1506 }
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -07001507
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001508 rc = qpnp_adc_tm_enable_if_channel_meas(chip);
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -07001509 if (rc < 0) {
1510 pr_err("re-enabling measurement failed\n");
1511 return rc;
1512 }
1513 } else
1514 pr_debug("No threshold status enable %d for high/low??\n",
1515 sensor_mask);
1516
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001517fail:
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001518 mutex_unlock(&chip->adc->adc_lock);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001519
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -07001520 if (adc_tm_high_enable || adc_tm_low_enable)
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001521 schedule_work(&chip->sensor[sensor_num].work);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001522
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001523 return rc;
1524}
1525
1526static void qpnp_adc_tm_high_thr_work(struct work_struct *work)
1527{
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001528 struct qpnp_adc_tm_chip *chip = container_of(work,
1529 struct qpnp_adc_tm_chip, trigger_high_thr_work);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001530 int rc;
1531
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001532 rc = qpnp_adc_tm_read_status(chip);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001533 if (rc < 0)
1534 pr_err("adc-tm high thr work failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001535
1536 return;
1537}
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001538
1539static irqreturn_t qpnp_adc_tm_high_thr_isr(int irq, void *data)
1540{
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001541 struct qpnp_adc_tm_chip *chip = data;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001542
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001543 qpnp_adc_tm_disable(chip);
1544
1545 schedule_work(&chip->trigger_high_thr_work);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001546
1547 return IRQ_HANDLED;
1548}
1549
1550static void qpnp_adc_tm_low_thr_work(struct work_struct *work)
1551{
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001552 struct qpnp_adc_tm_chip *chip = container_of(work,
1553 struct qpnp_adc_tm_chip, trigger_low_thr_work);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001554 int rc;
1555
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001556 rc = qpnp_adc_tm_read_status(chip);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001557 if (rc < 0)
1558 pr_err("adc-tm low thr work failed\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001559
1560 return;
1561}
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001562
1563static irqreturn_t qpnp_adc_tm_low_thr_isr(int irq, void *data)
1564{
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001565 struct qpnp_adc_tm_chip *chip = data;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001566
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001567 qpnp_adc_tm_disable(chip);
1568
1569 schedule_work(&chip->trigger_low_thr_work);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001570
1571 return IRQ_HANDLED;
1572}
1573
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001574static int qpnp_adc_read_temp(struct thermal_zone_device *thermal,
1575 unsigned long *temp)
1576{
1577 struct qpnp_adc_tm_sensor *adc_tm_sensor = thermal->devdata;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001578 struct qpnp_adc_tm_chip *chip = adc_tm_sensor->chip;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001579 struct qpnp_vadc_result result;
1580 int rc = 0;
1581
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001582 rc = qpnp_vadc_read(chip->vadc_dev,
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001583 adc_tm_sensor->vadc_channel_num, &result);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001584 if (rc)
1585 return rc;
1586
1587 *temp = result.physical;
1588
1589 return rc;
1590}
1591
1592static struct thermal_zone_device_ops qpnp_adc_tm_thermal_ops = {
1593 .get_temp = qpnp_adc_read_temp,
1594 .get_mode = qpnp_adc_tm_get_mode,
1595 .set_mode = qpnp_adc_tm_set_mode,
1596 .get_trip_type = qpnp_adc_tm_get_trip_type,
1597 .activate_trip_type = qpnp_adc_tm_activate_trip_type,
1598 .get_trip_temp = qpnp_adc_tm_get_trip_temp,
1599 .set_trip_temp = qpnp_adc_tm_set_trip_temp,
1600};
1601
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001602int32_t qpnp_adc_tm_channel_measure(struct qpnp_adc_tm_chip *chip,
1603 struct qpnp_adc_tm_btm_param *param)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001604{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001605 uint32_t channel, dt_index = 0, scale_type = 0;
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -07001606 int rc = 0, i = 0;
1607 bool chan_found = false;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001608
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001609 if (qpnp_adc_tm_is_valid(chip)) {
1610 pr_err("chip not valid\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001611 return -ENODEV;
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001612 }
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001613
1614 if (param->threshold_notification == NULL) {
Siddartha Mohanadoss8707b512013-07-16 18:43:41 -07001615 pr_debug("No notification for high/low temp??\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001616 return -EINVAL;
1617 }
1618
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001619 mutex_lock(&chip->adc->adc_lock);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001620
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001621 channel = param->channel;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001622 while (i < chip->max_channels_available) {
1623 if (chip->adc->adc_channels[i].channel_num ==
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -07001624 channel) {
1625 dt_index = i;
1626 chan_found = true;
1627 i++;
1628 } else
1629 i++;
1630 }
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001631
Siddartha Mohanadossb60744d2013-03-28 14:14:26 -07001632 if (!chan_found) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001633 pr_err("not a valid ADC_TM channel\n");
1634 rc = -EINVAL;
1635 goto fail_unlock;
1636 }
1637
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001638 rc = qpnp_adc_tm_check_revision(chip,
1639 chip->sensor[dt_index].btm_channel_num);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001640 if (rc < 0)
1641 goto fail_unlock;
1642
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001643 scale_type = chip->adc->adc_channels[dt_index].adc_scale_fn;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001644 if (scale_type >= SCALE_RSCALE_NONE) {
1645 rc = -EBADF;
1646 goto fail_unlock;
1647 }
1648
1649 pr_debug("channel:%d, scale_type:%d, dt_idx:%d",
1650 channel, scale_type, dt_index);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001651 chip->adc->amux_prop->amux_channel = channel;
1652 chip->adc->amux_prop->decimation =
1653 chip->adc->adc_channels[dt_index].adc_decimation;
1654 chip->adc->amux_prop->hw_settle_time =
1655 chip->adc->adc_channels[dt_index].hw_settle_time;
1656 chip->adc->amux_prop->fast_avg_setup =
1657 chip->adc->adc_channels[dt_index].fast_avg_setup;
1658 chip->adc->amux_prop->mode_sel =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001659 ADC_OP_MEASUREMENT_INTERVAL << QPNP_OP_MODE_SHIFT;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001660 chip->adc->amux_prop->chan_prop->meas_interval1 =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001661 ADC_MEAS1_INTERVAL_1S;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001662 adc_tm_rscale_fn[scale_type].chan(chip->vadc_dev, param,
1663 &chip->adc->amux_prop->chan_prop->low_thr,
1664 &chip->adc->amux_prop->chan_prop->high_thr);
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001665 qpnp_adc_tm_add_to_list(chip, dt_index, param,
1666 chip->adc->amux_prop->chan_prop);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001667 chip->adc->amux_prop->chan_prop->tm_channel_select =
1668 chip->sensor[dt_index].btm_channel_num;
1669 chip->adc->amux_prop->chan_prop->timer_select =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001670 ADC_MEAS_TIMER_SELECT1;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001671 chip->adc->amux_prop->chan_prop->state_request =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001672 param->state_request;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001673 rc = qpnp_adc_tm_configure(chip, chip->adc->amux_prop);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001674 if (rc) {
1675 pr_err("adc-tm configure failed with %d\n", rc);
1676 goto fail_unlock;
1677 }
1678
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001679 chip->sensor[dt_index].scale_type = scale_type;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001680
1681fail_unlock:
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001682 mutex_unlock(&chip->adc->adc_lock);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001683
1684 return rc;
1685}
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001686EXPORT_SYMBOL(qpnp_adc_tm_channel_measure);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001687
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001688int32_t qpnp_adc_tm_disable_chan_meas(struct qpnp_adc_tm_chip *chip,
1689 struct qpnp_adc_tm_btm_param *param)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001690{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001691 uint32_t channel, dt_index = 0, btm_chan_num;
1692 u8 sensor_mask = 0;
1693 int rc = 0;
1694
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001695 if (qpnp_adc_tm_is_valid(chip))
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001696 return -ENODEV;
1697
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001698 mutex_lock(&chip->adc->adc_lock);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001699
1700 /* Disable bank */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001701 rc = qpnp_adc_tm_disable(chip);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001702 if (rc < 0) {
1703 pr_err("adc-tm disable failed\n");
1704 goto fail;
1705 }
1706
1707 /* Check if a conversion is in progress */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001708 rc = qpnp_adc_tm_req_sts_check(chip);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001709 if (rc < 0) {
1710 pr_err("adc-tm req_sts check failed\n");
1711 goto fail;
1712 }
1713
1714 channel = param->channel;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001715 while ((chip->adc->adc_channels[dt_index].channel_num
1716 != channel) && (dt_index < chip->max_channels_available))
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001717 dt_index++;
1718
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001719 if (dt_index >= chip->max_channels_available) {
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001720 pr_err("not a valid ADC_TMN channel\n");
1721 rc = -EINVAL;
1722 goto fail;
1723 }
1724
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001725 btm_chan_num = chip->sensor[dt_index].btm_channel_num;
1726 sensor_mask = 1 << chip->sensor[dt_index].sensor_num;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001727
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001728 rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001729 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001730 if (rc < 0) {
1731 pr_err("low threshold int write failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001732 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001733 }
1734
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001735 rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001736 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001737 if (rc < 0) {
1738 pr_err("high threshold int enable failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001739 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001740 }
1741
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001742 rc = qpnp_adc_tm_reg_update(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001743 sensor_mask, false);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001744 if (rc < 0) {
1745 pr_err("multi measurement en failed\n");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001746 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001747 }
1748
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001749 rc = qpnp_adc_tm_enable_if_channel_meas(chip);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001750 if (rc < 0)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001751 pr_err("re-enabling measurement failed\n");
1752
1753fail:
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001754 mutex_unlock(&chip->adc->adc_lock);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001755
1756 return rc;
1757}
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001758EXPORT_SYMBOL(qpnp_adc_tm_disable_chan_meas);
1759
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001760int32_t qpnp_adc_tm_usbid_configure(struct qpnp_adc_tm_chip *chip,
1761 struct qpnp_adc_tm_btm_param *param)
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001762{
1763 param->channel = LR_MUX10_PU2_AMUX_USB_ID_LV;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001764 return qpnp_adc_tm_channel_measure(chip, param);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001765}
1766EXPORT_SYMBOL(qpnp_adc_tm_usbid_configure);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001767
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001768int32_t qpnp_adc_tm_usbid_end(struct qpnp_adc_tm_chip *chip)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001769{
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001770 struct qpnp_adc_tm_btm_param param;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001771
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001772 return qpnp_adc_tm_disable_chan_meas(chip, &param);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001773}
1774EXPORT_SYMBOL(qpnp_adc_tm_usbid_end);
1775
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001776struct qpnp_adc_tm_chip *qpnp_get_adc_tm(struct device *dev, const char *name)
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001777{
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001778 struct qpnp_adc_tm_chip *chip;
1779 struct device_node *node = NULL;
1780 char prop_name[QPNP_MAX_PROP_NAME_LEN];
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001781
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001782 snprintf(prop_name, QPNP_MAX_PROP_NAME_LEN, "qcom,%s-adc_tm", name);
1783
1784 node = of_parse_phandle(dev->of_node, prop_name, 0);
1785 if (node == NULL)
1786 return ERR_PTR(-ENODEV);
1787
1788 list_for_each_entry(chip, &qpnp_adc_tm_device_list, list)
1789 if (chip->adc->spmi->dev.of_node == node)
1790 return chip;
1791
1792 return ERR_PTR(-EPROBE_DEFER);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001793}
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001794EXPORT_SYMBOL(qpnp_get_adc_tm);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001795
1796static int __devinit qpnp_adc_tm_probe(struct spmi_device *spmi)
1797{
1798 struct device_node *node = spmi->dev.of_node, *child;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001799 struct qpnp_adc_tm_chip *chip;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001800 struct qpnp_adc_drv *adc_qpnp;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001801 int32_t count_adc_channel_list = 0, rc, sen_idx = 0, i = 0;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001802 u8 thr_init = 0;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001803 bool thermal_node = false;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001804
1805 for_each_child_of_node(node, child)
1806 count_adc_channel_list++;
1807
1808 if (!count_adc_channel_list) {
1809 pr_err("No channel listing\n");
1810 return -EINVAL;
1811 }
1812
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001813 chip = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_tm_chip) +
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001814 (count_adc_channel_list *
1815 sizeof(struct qpnp_adc_tm_sensor)),
1816 GFP_KERNEL);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001817 if (!chip) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001818 dev_err(&spmi->dev, "Unable to allocate memory\n");
1819 return -ENOMEM;
1820 }
1821
1822 adc_qpnp = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_drv),
1823 GFP_KERNEL);
1824 if (!adc_qpnp) {
1825 dev_err(&spmi->dev, "Unable to allocate memory\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001826 rc = -ENOMEM;
1827 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001828 }
1829
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001830 chip->dev = &(spmi->dev);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001831 chip->adc = adc_qpnp;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001832
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001833 rc = qpnp_adc_get_devicetree_data(spmi, chip->adc);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001834 if (rc) {
1835 dev_err(&spmi->dev, "failed to read device tree\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001836 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001837 }
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001838 mutex_init(&chip->adc->adc_lock);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001839
1840 /* Register the ADC peripheral interrupt */
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001841 chip->adc->adc_high_thr_irq = spmi_get_irq_byname(spmi,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001842 NULL, "high-thr-en-set");
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001843 if (chip->adc->adc_high_thr_irq < 0) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001844 pr_err("Invalid irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001845 rc = -ENXIO;
1846 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001847 }
1848
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001849 chip->adc->adc_low_thr_irq = spmi_get_irq_byname(spmi,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001850 NULL, "low-thr-en-set");
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001851 if (chip->adc->adc_low_thr_irq < 0) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001852 pr_err("Invalid irq\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001853 rc = -ENXIO;
1854 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001855 }
1856
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001857 chip->vadc_dev = qpnp_get_vadc(&spmi->dev, "adc_tm");
1858 if (IS_ERR(chip->vadc_dev)) {
1859 rc = PTR_ERR(chip->vadc_dev);
Siddartha Mohanadoss3cb2b6b2013-06-21 12:07:05 -07001860 if (rc != -EPROBE_DEFER)
1861 pr_err("vadc property missing, rc=%d\n", rc);
1862 goto fail;
1863 }
1864
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001865 for_each_child_of_node(node, child) {
1866 char name[25];
1867 int btm_channel_num;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001868
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001869 rc = of_property_read_u32(child,
1870 "qcom,btm-channel-number", &btm_channel_num);
1871 if (rc) {
1872 pr_err("Invalid btm channel number\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001873 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001874 }
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001875 chip->sensor[sen_idx].btm_channel_num = btm_channel_num;
1876 chip->sensor[sen_idx].vadc_channel_num =
1877 chip->adc->adc_channels[sen_idx].channel_num;
1878 chip->sensor[sen_idx].sensor_num = sen_idx;
1879 chip->sensor[sen_idx].chip = chip;
Siddartha Mohanadossb2795e42013-03-22 09:00:28 -07001880 pr_debug("btm_chan:%x, vadc_chan:%x\n", btm_channel_num,
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001881 chip->adc->adc_channels[sen_idx].channel_num);
Siddartha Mohanadossea65d9e2013-04-16 18:26:39 -07001882 thermal_node = of_property_read_bool(child,
1883 "qcom,thermal-node");
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001884 if (thermal_node) {
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001885 /* Register with the thermal zone */
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001886 pr_debug("thermal node%x\n", btm_channel_num);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001887 chip->sensor[sen_idx].mode = THERMAL_DEVICE_DISABLED;
1888 chip->sensor[sen_idx].thermal_node = true;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001889 snprintf(name, sizeof(name),
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001890 chip->adc->adc_channels[sen_idx].name);
1891 chip->sensor[sen_idx].meas_interval =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001892 QPNP_ADC_TM_MEAS_INTERVAL;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001893 chip->sensor[sen_idx].low_thr =
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001894 QPNP_ADC_TM_M0_LOW_THR;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001895 chip->sensor[sen_idx].high_thr =
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001896 QPNP_ADC_TM_M0_HIGH_THR;
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001897 chip->sensor[sen_idx].tz_dev =
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001898 thermal_zone_device_register(name,
1899 ADC_TM_TRIP_NUM,
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001900 &chip->sensor[sen_idx],
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001901 &qpnp_adc_tm_thermal_ops, 0, 0, 0, 0);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001902 if (IS_ERR(chip->sensor[sen_idx].tz_dev))
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001903 pr_err("thermal device register failed.\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001904 }
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001905 INIT_WORK(&chip->sensor[sen_idx].work, notify_adc_tm_fn);
Siddartha Mohanadossbb315992013-09-11 13:28:51 -07001906 INIT_LIST_HEAD(&chip->sensor[sen_idx].thr_list);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001907 sen_idx++;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001908 }
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001909 chip->max_channels_available = count_adc_channel_list;
1910 INIT_WORK(&chip->trigger_high_thr_work, qpnp_adc_tm_high_thr_work);
1911 INIT_WORK(&chip->trigger_low_thr_work, qpnp_adc_tm_low_thr_work);
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001912
1913 rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_HIGH_THR_INT_EN,
1914 thr_init);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001915 if (rc < 0) {
1916 pr_err("high thr init failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001917 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001918 }
1919
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001920 rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_LOW_THR_INT_EN,
1921 thr_init);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001922 if (rc < 0) {
1923 pr_err("low thr init failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001924 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001925 }
1926
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001927 rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_MULTI_MEAS_EN,
1928 thr_init);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001929 if (rc < 0) {
1930 pr_err("multi meas en failed\n");
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001931 goto fail;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001932 }
1933
Siddartha Mohanadoss73fb1512013-08-08 22:38:13 -07001934 rc = devm_request_irq(&spmi->dev, chip->adc->adc_high_thr_irq,
1935 qpnp_adc_tm_high_thr_isr,
1936 IRQF_TRIGGER_RISING, "qpnp_adc_tm_high_interrupt", chip);
1937 if (rc) {
1938 dev_err(&spmi->dev, "failed to request adc irq\n");
1939 goto fail;
1940 } else {
1941 enable_irq_wake(chip->adc->adc_high_thr_irq);
1942 }
1943
1944 rc = devm_request_irq(&spmi->dev, chip->adc->adc_low_thr_irq,
1945 qpnp_adc_tm_low_thr_isr,
1946 IRQF_TRIGGER_RISING, "qpnp_adc_tm_low_interrupt", chip);
1947 if (rc) {
1948 dev_err(&spmi->dev, "failed to request adc irq\n");
1949 goto fail;
1950 } else {
1951 enable_irq_wake(chip->adc->adc_low_thr_irq);
1952 }
1953
1954 dev_set_drvdata(&spmi->dev, chip);
1955 list_add(&chip->list, &qpnp_adc_tm_device_list);
1956
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001957 pr_debug("OK\n");
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001958 return 0;
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001959fail:
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001960 for_each_child_of_node(node, child) {
1961 thermal_node = of_property_read_bool(child,
1962 "qcom,thermal-node");
1963 if (thermal_node)
1964 thermal_zone_device_unregister(chip->sensor[i].tz_dev);
1965 i++;
1966 }
1967 dev_set_drvdata(&spmi->dev, NULL);
Siddartha Mohanadossb60f6462012-11-20 18:06:51 -08001968 return rc;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001969}
1970
1971static int __devexit qpnp_adc_tm_remove(struct spmi_device *spmi)
1972{
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001973 struct qpnp_adc_tm_chip *chip = dev_get_drvdata(&spmi->dev);
1974 struct device_node *node = spmi->dev.of_node, *child;
1975 bool thermal_node = false;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001976 int i = 0;
1977
1978 for_each_child_of_node(node, child) {
Siddartha Mohanadoss88a3fde2013-06-24 16:18:52 -07001979 thermal_node = of_property_read_bool(child,
1980 "qcom,thermal-node");
1981 if (thermal_node)
1982 thermal_zone_device_unregister(chip->sensor[i].tz_dev);
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001983 i++;
1984 }
1985
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -08001986 dev_set_drvdata(&spmi->dev, NULL);
1987
1988 return 0;
1989}
1990
1991static const struct of_device_id qpnp_adc_tm_match_table[] = {
1992 { .compatible = "qcom,qpnp-adc-tm" },
1993 {}
1994};
1995
1996static struct spmi_driver qpnp_adc_tm_driver = {
1997 .driver = {
1998 .name = "qcom,qpnp-adc-tm",
1999 .of_match_table = qpnp_adc_tm_match_table,
2000 },
2001 .probe = qpnp_adc_tm_probe,
2002 .remove = qpnp_adc_tm_remove,
2003};
2004
2005static int __init qpnp_adc_tm_init(void)
2006{
2007 return spmi_driver_register(&qpnp_adc_tm_driver);
2008}
2009module_init(qpnp_adc_tm_init);
2010
2011static void __exit qpnp_adc_tm_exit(void)
2012{
2013 spmi_driver_unregister(&qpnp_adc_tm_driver);
2014}
2015module_exit(qpnp_adc_tm_exit);
2016
2017MODULE_DESCRIPTION("QPNP PMIC ADC Threshold Monitoring driver");
2018MODULE_LICENSE("GPL v2");