1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
4 */
5
6 #include <linux/auxiliary_bus.h>
7 #include <linux/bitfield.h>
8 #include <linux/bits.h>
9 #include <linux/cleanup.h>
10 #include <linux/container_of.h>
11 #include <linux/device/devres.h>
12 #include <linux/dev_printk.h>
13 #include <linux/err.h>
14 #include <linux/iio/adc/qcom-adc5-gen3-common.h>
15 #include <linux/interrupt.h>
16 #include <linux/module.h>
17 #include <linux/thermal.h>
18 #include <linux/types.h>
19 #include <linux/unaligned.h>
20
21 #include "../thermal_hwmon.h"
22
23 #define ADC_TM5_GEN3_CONFIG_REGS 12
24
25 struct device;
26 struct adc_tm5_gen3_chip;
27
28 /**
29 * struct adc_tm5_gen3_channel_props - ADC_TM channel structure
30 * @common_props: structure with common ADC channel properties.
31 * @chip: ADC TM device.
32 * @tzd: pointer to thermal device corresponding to TM channel.
33 * @sdam_index: SDAM on which this TM channel lies.
34 * @timer: time period of recurring TM measurement.
35 * @tm_chan_index: TM channel number used.
36 * @high_thr_en: TM high threshold crossing detection enabled.
37 * @low_thr_en: TM low threshold crossing detection enabled.
38 */
39 struct adc_tm5_gen3_channel_props {
40 struct adc5_channel_common_prop common_props;
41 struct adc_tm5_gen3_chip *chip;
42 struct thermal_zone_device *tzd;
43 unsigned int sdam_index;
44 unsigned int timer;
45 unsigned int tm_chan_index;
46 bool high_thr_en;
47 bool low_thr_en;
48 };
49
50 /**
51 * struct adc_tm5_gen3_chip - ADC Thermal Monitoring device structure
52 * @dev_data: Top-level ADC device data.
53 * @chan_props: Array of ADC_TM channel structures.
54 * @dev: SPMI ADC5 Gen3 device.
55 * @nchannels: number of TM channels allocated
56 */
57 struct adc_tm5_gen3_chip {
58 struct adc5_device_data *dev_data;
59 struct adc_tm5_gen3_channel_props *chan_props;
60 struct device *dev;
61 unsigned int nchannels;
62 };
63
64 DEFINE_GUARD(adc5_gen3, struct adc_tm5_gen3_chip *,
65 adc5_gen3_mutex_lock(_T->dev), adc5_gen3_mutex_unlock(_T->dev))
66
get_sdam_from_irq(struct adc_tm5_gen3_chip * adc_tm5,int irq)67 static int get_sdam_from_irq(struct adc_tm5_gen3_chip *adc_tm5, int irq)
68 {
69 for (int i = 0; i < adc_tm5->dev_data->num_sdams; i++) {
70 if (adc_tm5->dev_data->base[i].irq == irq)
71 return i;
72 }
73 return -ENOENT;
74 }
75
adctm5_gen3_isr(int irq,void * dev_id)76 static irqreturn_t adctm5_gen3_isr(int irq, void *dev_id)
77 {
78 struct adc_tm5_gen3_chip *adc_tm5 = dev_id;
79 int ret, sdam_num;
80 u8 tm_status[2];
81 u8 status, val;
82
83 sdam_num = get_sdam_from_irq(adc_tm5, irq);
84 if (sdam_num < 0)
85 return IRQ_NONE;
86
87 ret = adc5_gen3_read(adc_tm5->dev_data, sdam_num, ADC5_GEN3_STATUS1,
88 &status, sizeof(status));
89 if (ret)
90 return IRQ_NONE;
91
92 if (status & ADC5_GEN3_STATUS1_CONV_FAULT) {
93 val = ADC5_GEN3_CONV_ERR_CLR_REQ;
94 adc5_gen3_status_clear(adc_tm5->dev_data, sdam_num,
95 ADC5_GEN3_CONV_ERR_CLR, &val, 1);
96 return IRQ_HANDLED;
97 }
98
99 ret = adc5_gen3_read(adc_tm5->dev_data, sdam_num, ADC5_GEN3_TM_HIGH_STS,
100 tm_status, sizeof(tm_status));
101 if (ret)
102 return IRQ_NONE;
103
104 if (tm_status[0] || tm_status[1])
105 return IRQ_WAKE_THREAD;
106
107 return IRQ_NONE;
108 }
109
adctm5_gen3_isr_thread(int irq,void * dev_id)110 static irqreturn_t adctm5_gen3_isr_thread(int irq, void *dev_id)
111 {
112 struct adc_tm5_gen3_chip *adc_tm5 = dev_id;
113 u8 tm_status[2];
114 int sdam_index;
115
116 sdam_index = get_sdam_from_irq(adc_tm5, irq);
117 if (sdam_index < 0)
118 return IRQ_NONE;
119
120 scoped_guard(adc5_gen3, adc_tm5) {
121 int ret;
122
123 ret = adc5_gen3_read(adc_tm5->dev_data, sdam_index, ADC5_GEN3_TM_HIGH_STS,
124 tm_status, sizeof(tm_status));
125 if (ret)
126 return IRQ_NONE;
127
128 ret = adc5_gen3_status_clear(adc_tm5->dev_data, sdam_index,
129 ADC5_GEN3_TM_HIGH_STS_CLR, tm_status,
130 sizeof(tm_status));
131 if (ret)
132 return IRQ_NONE;
133 }
134
135 for (int i = 0; i < adc_tm5->nchannels; i++) {
136 struct adc_tm5_gen3_channel_props *chan_prop = &adc_tm5->chan_props[i];
137 int offset = chan_prop->tm_chan_index;
138 bool upper_set, lower_set;
139
140 if (chan_prop->sdam_index != sdam_index)
141 continue;
142
143 upper_set = ((tm_status[0] & BIT(offset)) && chan_prop->high_thr_en);
144 lower_set = ((tm_status[1] & BIT(offset)) && chan_prop->low_thr_en);
145
146 if (!(upper_set || lower_set))
147 continue;
148
149 thermal_zone_device_update(chan_prop->tzd, THERMAL_TRIP_VIOLATED);
150 }
151
152 return IRQ_HANDLED;
153 }
154
adc_tm5_gen3_get_temp(struct thermal_zone_device * tz,int * temp)155 static int adc_tm5_gen3_get_temp(struct thermal_zone_device *tz, int *temp)
156 {
157 struct adc_tm5_gen3_channel_props *prop = thermal_zone_device_priv(tz);
158 struct adc_tm5_gen3_chip *adc_tm5;
159
160 if (!prop || !prop->chip)
161 return -EINVAL;
162
163 adc_tm5 = prop->chip;
164
165 return adc5_gen3_get_scaled_reading(adc_tm5->dev, &prop->common_props, temp);
166 }
167
adc_tm5_gen3_disable_channel(struct adc_tm5_gen3_channel_props * prop)168 static int adc_tm5_gen3_disable_channel(struct adc_tm5_gen3_channel_props *prop)
169 {
170 struct adc_tm5_gen3_chip *adc_tm5 = prop->chip;
171 int ret;
172 u8 val;
173
174 prop->high_thr_en = false;
175 prop->low_thr_en = false;
176
177 ret = adc5_gen3_poll_wait_hs(adc_tm5->dev_data, prop->sdam_index);
178 if (ret)
179 return ret;
180
181 val = BIT(prop->tm_chan_index);
182 ret = adc5_gen3_write(adc_tm5->dev_data, prop->sdam_index,
183 ADC5_GEN3_TM_HIGH_STS_CLR, &val, sizeof(val));
184 if (ret)
185 return ret;
186
187 ret = adc5_gen3_write(adc_tm5->dev_data, prop->sdam_index,
188 ADC5_GEN3_TM_LOW_STS_CLR, &val, sizeof(val));
189 if (ret)
190 return ret;
191
192 val = MEAS_INT_DISABLE;
193 ret = adc5_gen3_write(adc_tm5->dev_data, prop->sdam_index,
194 ADC5_GEN3_TIMER_SEL, &val, sizeof(val));
195 if (ret)
196 return ret;
197
198 /* To indicate there is an actual conversion request */
199 val = ADC5_GEN3_CHAN_CONV_REQ | prop->tm_chan_index;
200 ret = adc5_gen3_write(adc_tm5->dev_data, prop->sdam_index,
201 ADC5_GEN3_PERPH_CH, &val, sizeof(val));
202 if (ret)
203 return ret;
204
205 val = ADC5_GEN3_CONV_REQ_REQ;
206 return adc5_gen3_write(adc_tm5->dev_data, prop->sdam_index,
207 ADC5_GEN3_CONV_REQ, &val, sizeof(val));
208 }
209
adc_tm5_gen3_configure(struct adc_tm5_gen3_channel_props * prop,int low_temp,int high_temp)210 static int adc_tm5_gen3_configure(struct adc_tm5_gen3_channel_props *prop,
211 int low_temp, int high_temp)
212 {
213 struct adc_tm5_gen3_chip *adc_tm5 = prop->chip;
214 u8 buf[ADC_TM5_GEN3_CONFIG_REGS];
215 u8 conv_req;
216 u16 adc_code;
217 int ret;
218
219 ret = adc5_gen3_poll_wait_hs(adc_tm5->dev_data, prop->sdam_index);
220 if (ret < 0)
221 return ret;
222
223 ret = adc5_gen3_read(adc_tm5->dev_data, prop->sdam_index,
224 ADC5_GEN3_SID, buf, sizeof(buf));
225 if (ret < 0)
226 return ret;
227
228 /* Write SID */
229 buf[0] = FIELD_PREP(ADC5_GEN3_SID_MASK, prop->common_props.sid);
230
231 /* Select TM channel and indicate there is an actual conversion request */
232 buf[1] = ADC5_GEN3_CHAN_CONV_REQ | prop->tm_chan_index;
233
234 buf[2] = prop->timer;
235
236 /* Digital param selection */
237 adc5_gen3_update_dig_param(&prop->common_props, &buf[3]);
238
239 /* Update fast average sample value */
240 buf[4] = FIELD_PREP(ADC5_GEN3_FAST_AVG_CTL_SAMPLES_MASK,
241 prop->common_props.avg_samples) | ADC5_GEN3_FAST_AVG_CTL_EN;
242
243 /* Select ADC channel */
244 buf[5] = prop->common_props.channel;
245
246 /* Select HW settle delay for channel */
247 buf[6] = FIELD_PREP(ADC5_GEN3_HW_SETTLE_DELAY_MASK,
248 prop->common_props.hw_settle_time_us);
249
250 buf[7] = 0;
251
252 /* High temperature corresponds to low voltage threshold */
253 prop->low_thr_en = (high_temp != INT_MAX);
254 if (prop->low_thr_en) {
255 adc_code = qcom_adc_tm5_gen2_temp_res_scale(high_temp);
256 put_unaligned_le16(adc_code, &buf[8]);
257 buf[7] |= ADC5_GEN3_LOW_THR_INT_EN;
258 }
259
260 /* Low temperature corresponds to high voltage threshold */
261 prop->high_thr_en = (low_temp != -INT_MAX);
262 if (prop->high_thr_en) {
263 adc_code = qcom_adc_tm5_gen2_temp_res_scale(low_temp);
264 put_unaligned_le16(adc_code, &buf[10]);
265 buf[7] |= ADC5_GEN3_HIGH_THR_INT_EN;
266 }
267
268 ret = adc5_gen3_write(adc_tm5->dev_data, prop->sdam_index, ADC5_GEN3_SID,
269 buf, sizeof(buf));
270 if (ret < 0)
271 return ret;
272
273 conv_req = ADC5_GEN3_CONV_REQ_REQ;
274 return adc5_gen3_write(adc_tm5->dev_data, prop->sdam_index,
275 ADC5_GEN3_CONV_REQ, &conv_req, sizeof(conv_req));
276 }
277
adc_tm5_gen3_set_trip_temp(struct thermal_zone_device * tz,int low_temp,int high_temp)278 static int adc_tm5_gen3_set_trip_temp(struct thermal_zone_device *tz,
279 int low_temp, int high_temp)
280 {
281 struct adc_tm5_gen3_channel_props *prop = thermal_zone_device_priv(tz);
282 struct adc_tm5_gen3_chip *adc_tm5;
283
284 if (!prop || !prop->chip)
285 return -EINVAL;
286
287 adc_tm5 = prop->chip;
288
289 dev_dbg(adc_tm5->dev, "channel:%s, low_temp(mdegC):%d, high_temp(mdegC):%d\n",
290 prop->common_props.label, low_temp, high_temp);
291
292 guard(adc5_gen3)(adc_tm5);
293
294 return adc_tm5_gen3_configure(prop, low_temp, high_temp);
295 }
296
297 static const struct thermal_zone_device_ops adc_tm_ops = {
298 .get_temp = adc_tm5_gen3_get_temp,
299 .set_trips = adc_tm5_gen3_set_trip_temp,
300 };
301
adc_tm5_register_tzd(struct adc_tm5_gen3_chip * adc_tm5)302 static int adc_tm5_register_tzd(struct adc_tm5_gen3_chip *adc_tm5)
303 {
304 struct thermal_zone_device *tzd;
305 unsigned int channel;
306 int ret;
307
308 for (int i = 0; i < adc_tm5->nchannels; i++) {
309 channel = ADC5_GEN3_V_CHAN(adc_tm5->chan_props[i].common_props);
310 tzd = devm_thermal_of_zone_register(adc_tm5->dev, channel,
311 &adc_tm5->chan_props[i],
312 &adc_tm_ops);
313 if (IS_ERR(tzd)) {
314 if (PTR_ERR(tzd) == -ENODEV) {
315 dev_dbg(adc_tm5->dev,
316 "thermal sensor on channel %d is not used\n",
317 channel);
318 continue;
319 }
320 return PTR_ERR(tzd);
321 }
322 adc_tm5->chan_props[i].tzd = tzd;
323 ret = devm_thermal_add_hwmon_sysfs(adc_tm5->dev, tzd);
324 if (ret)
325 return ret;
326 }
327
328 return 0;
329 }
330
adc5_gen3_disable(void * data)331 static void adc5_gen3_disable(void *data)
332 {
333 struct adc_tm5_gen3_chip *adc_tm5 = data;
334
335 guard(adc5_gen3)(adc_tm5);
336
337 /* Disable all available TM channels */
338 for (int i = 0; i < adc_tm5->nchannels; i++)
339 adc_tm5_gen3_disable_channel(&adc_tm5->chan_props[i]);
340 }
341
adc_tm5_probe(struct auxiliary_device * aux_dev,const struct auxiliary_device_id * id)342 static int adc_tm5_probe(struct auxiliary_device *aux_dev,
343 const struct auxiliary_device_id *id)
344 {
345 struct adc_tm5_gen3_chip *adc_tm5;
346 struct tm5_aux_dev_wrapper *aux_dev_wrapper;
347 struct device *dev = &aux_dev->dev;
348 int ret;
349
350 adc_tm5 = devm_kzalloc(dev, sizeof(*adc_tm5), GFP_KERNEL);
351 if (!adc_tm5)
352 return -ENOMEM;
353
354 aux_dev_wrapper = container_of(aux_dev, struct tm5_aux_dev_wrapper, aux_dev);
355
356 adc_tm5->dev = dev;
357 adc_tm5->dev_data = aux_dev_wrapper->dev_data;
358 adc_tm5->nchannels = aux_dev_wrapper->n_tm_channels;
359 adc_tm5->chan_props = devm_kcalloc(dev, aux_dev_wrapper->n_tm_channels,
360 sizeof(*adc_tm5->chan_props), GFP_KERNEL);
361 if (!adc_tm5->chan_props)
362 return -ENOMEM;
363
364 for (int i = 0; i < adc_tm5->nchannels; i++) {
365 /*
366 * Since the first channel of the first SDAM is reserved for
367 * immediate ADC conversions, TM channel count must start from
368 * the channel just after it. The variable tm_count is used to
369 * calculate SDAM and TM channel index on that SDAM correctly
370 * for each TM channel.
371 */
372 int tm_count = i + 1;
373
374 adc_tm5->chan_props[i].common_props = aux_dev_wrapper->tm_props[i];
375 adc_tm5->chan_props[i].timer = MEAS_INT_1S;
376 adc_tm5->chan_props[i].sdam_index = tm_count / 8;
377 adc_tm5->chan_props[i].tm_chan_index = tm_count % 8;
378 adc_tm5->chan_props[i].chip = adc_tm5;
379 }
380
381 /*
382 * ADC_TM channels are enabled in the loop in adc_tm5_register_tzd() as
383 * part of the set_trips calls during thermal zone registration. This
384 * action is to disable them all in case of probe failure.
385 */
386 ret = devm_add_action(dev, adc5_gen3_disable, adc_tm5);
387 if (ret)
388 return ret;
389
390 ret = adc_tm5_register_tzd(adc_tm5);
391 if (ret)
392 return ret;
393
394 for (int i = 0; i < adc_tm5->dev_data->num_sdams; i++) {
395 u32 irq_flags = IRQF_ONESHOT;
396
397 /*
398 * First SDAM's interrupt is shared between main ADC driver and
399 * auxiliary TM driver, so its flags must include IRQF_SHARED.
400 * This is not needed for other SDAMs as they will be used only
401 * for TM functionality.
402 */
403 if (i == 0)
404 irq_flags |= IRQF_SHARED;
405
406 ret = devm_request_threaded_irq(dev,
407 adc_tm5->dev_data->base[i].irq,
408 adctm5_gen3_isr,
409 adctm5_gen3_isr_thread,
410 irq_flags,
411 adc_tm5->dev_data->base[i].irq_name,
412 adc_tm5);
413 if (ret < 0)
414 return ret;
415 }
416
417 return 0;
418 }
419
420 static const struct auxiliary_device_id adctm5_auxiliary_id_table[] = {
421 { .name = "qcom_spmi_adc5_gen3.adc5_tm_gen3" },
422 { }
423 };
424 MODULE_DEVICE_TABLE(auxiliary, adctm5_auxiliary_id_table);
425
426 static struct auxiliary_driver adctm5gen3_auxiliary_driver = {
427 .id_table = adctm5_auxiliary_id_table,
428 .probe = adc_tm5_probe,
429 };
430 module_auxiliary_driver(adctm5gen3_auxiliary_driver);
431
432 MODULE_DESCRIPTION("SPMI PMIC Thermal Monitor ADC driver");
433 MODULE_LICENSE("GPL");
434 MODULE_IMPORT_NS("QCOM_SPMI_ADC5_GEN3");
435