12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2e41f6432SAshish Jangam /*
3e41f6432SAshish Jangam * HWMON Driver for Dialog DA9052
4e41f6432SAshish Jangam *
5e41f6432SAshish Jangam * Copyright(c) 2012 Dialog Semiconductor Ltd.
6e41f6432SAshish Jangam *
7e41f6432SAshish Jangam * Author: David Dajun Chen <dchen@diasemi.com>
8e41f6432SAshish Jangam */
9e41f6432SAshish Jangam
10e41f6432SAshish Jangam #include <linux/err.h>
11e41f6432SAshish Jangam #include <linux/hwmon.h>
12e41f6432SAshish Jangam #include <linux/hwmon-sysfs.h>
13e41f6432SAshish Jangam #include <linux/init.h>
14e41f6432SAshish Jangam #include <linux/kernel.h>
15e41f6432SAshish Jangam #include <linux/module.h>
16e41f6432SAshish Jangam #include <linux/slab.h>
17e41f6432SAshish Jangam #include <linux/platform_device.h>
184f16cab1SSebastian Reichel #include <linux/property.h>
19e41f6432SAshish Jangam
20e41f6432SAshish Jangam #include <linux/mfd/da9052/da9052.h>
21e41f6432SAshish Jangam #include <linux/mfd/da9052/reg.h>
224f16cab1SSebastian Reichel #include <linux/regulator/consumer.h>
23e41f6432SAshish Jangam
24e41f6432SAshish Jangam struct da9052_hwmon {
25e41f6432SAshish Jangam struct da9052 *da9052;
26e41f6432SAshish Jangam struct mutex hwmon_lock;
274f16cab1SSebastian Reichel bool tsi_as_adc;
284f16cab1SSebastian Reichel int tsiref_mv;
294f16cab1SSebastian Reichel struct regulator *tsiref;
304f16cab1SSebastian Reichel struct completion tsidone;
31e41f6432SAshish Jangam };
32e41f6432SAshish Jangam
33e41f6432SAshish Jangam static const char * const input_names[] = {
34e41f6432SAshish Jangam [DA9052_ADC_VDDOUT] = "VDDOUT",
35e41f6432SAshish Jangam [DA9052_ADC_ICH] = "CHARGING CURRENT",
36e41f6432SAshish Jangam [DA9052_ADC_TBAT] = "BATTERY TEMP",
37e41f6432SAshish Jangam [DA9052_ADC_VBAT] = "BATTERY VOLTAGE",
38e41f6432SAshish Jangam [DA9052_ADC_IN4] = "ADC IN4",
39e41f6432SAshish Jangam [DA9052_ADC_IN5] = "ADC IN5",
40e41f6432SAshish Jangam [DA9052_ADC_IN6] = "ADC IN6",
414f16cab1SSebastian Reichel [DA9052_ADC_TSI_XP] = "ADC TS X+",
424f16cab1SSebastian Reichel [DA9052_ADC_TSI_YP] = "ADC TS Y+",
434f16cab1SSebastian Reichel [DA9052_ADC_TSI_XN] = "ADC TS X-",
444f16cab1SSebastian Reichel [DA9052_ADC_TSI_YN] = "ADC TS Y-",
45e41f6432SAshish Jangam [DA9052_ADC_TJUNC] = "BATTERY JUNCTION TEMP",
46e41f6432SAshish Jangam [DA9052_ADC_VBBAT] = "BACK-UP BATTERY VOLTAGE",
47e41f6432SAshish Jangam };
48e41f6432SAshish Jangam
49e41f6432SAshish Jangam /* Conversion function for VDDOUT and VBAT */
volt_reg_to_mv(int value)50088ce2acSGuenter Roeck static inline int volt_reg_to_mv(int value)
51e41f6432SAshish Jangam {
52c09088d9SAnthony Olech return DIV_ROUND_CLOSEST(value * 2000, 1023) + 2500;
53e41f6432SAshish Jangam }
54e41f6432SAshish Jangam
55e41f6432SAshish Jangam /* Conversion function for ADC channels 4, 5 and 6 */
input_reg_to_mv(int value)56088ce2acSGuenter Roeck static inline int input_reg_to_mv(int value)
57e41f6432SAshish Jangam {
58e41f6432SAshish Jangam return DIV_ROUND_CLOSEST(value * 2500, 1023);
59e41f6432SAshish Jangam }
60e41f6432SAshish Jangam
61e41f6432SAshish Jangam /* Conversion function for VBBAT */
vbbat_reg_to_mv(int value)62088ce2acSGuenter Roeck static inline int vbbat_reg_to_mv(int value)
63e41f6432SAshish Jangam {
64c09088d9SAnthony Olech return DIV_ROUND_CLOSEST(value * 5000, 1023);
65e41f6432SAshish Jangam }
66e41f6432SAshish Jangam
input_tsireg_to_mv(struct da9052_hwmon * hwmon,int value)674f16cab1SSebastian Reichel static inline int input_tsireg_to_mv(struct da9052_hwmon *hwmon, int value)
684f16cab1SSebastian Reichel {
694f16cab1SSebastian Reichel return DIV_ROUND_CLOSEST(value * hwmon->tsiref_mv, 1023);
704f16cab1SSebastian Reichel }
714f16cab1SSebastian Reichel
da9052_enable_vddout_channel(struct da9052 * da9052)72d9b24e37SAxel Lin static inline int da9052_enable_vddout_channel(struct da9052 *da9052)
73e41f6432SAshish Jangam {
74d9b24e37SAxel Lin return da9052_reg_update(da9052, DA9052_ADC_CONT_REG,
75d9b24e37SAxel Lin DA9052_ADCCONT_AUTOVDDEN,
76d9b24e37SAxel Lin DA9052_ADCCONT_AUTOVDDEN);
77e41f6432SAshish Jangam }
78e41f6432SAshish Jangam
da9052_disable_vddout_channel(struct da9052 * da9052)79d9b24e37SAxel Lin static inline int da9052_disable_vddout_channel(struct da9052 *da9052)
80e41f6432SAshish Jangam {
81d9b24e37SAxel Lin return da9052_reg_update(da9052, DA9052_ADC_CONT_REG,
82d9b24e37SAxel Lin DA9052_ADCCONT_AUTOVDDEN, 0);
83e41f6432SAshish Jangam }
84e41f6432SAshish Jangam
da9052_vddout_show(struct device * dev,struct device_attribute * devattr,char * buf)856db587b7SGuenter Roeck static ssize_t da9052_vddout_show(struct device *dev,
86e41f6432SAshish Jangam struct device_attribute *devattr, char *buf)
87e41f6432SAshish Jangam {
88e41f6432SAshish Jangam struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
89e41f6432SAshish Jangam int ret, vdd;
90e41f6432SAshish Jangam
91e41f6432SAshish Jangam mutex_lock(&hwmon->hwmon_lock);
92e41f6432SAshish Jangam
93e41f6432SAshish Jangam ret = da9052_enable_vddout_channel(hwmon->da9052);
94e41f6432SAshish Jangam if (ret < 0)
95e41f6432SAshish Jangam goto hwmon_err;
96e41f6432SAshish Jangam
97e41f6432SAshish Jangam vdd = da9052_reg_read(hwmon->da9052, DA9052_VDD_RES_REG);
98e41f6432SAshish Jangam if (vdd < 0) {
99e41f6432SAshish Jangam ret = vdd;
100e41f6432SAshish Jangam goto hwmon_err_release;
101e41f6432SAshish Jangam }
102e41f6432SAshish Jangam
103e41f6432SAshish Jangam ret = da9052_disable_vddout_channel(hwmon->da9052);
104e41f6432SAshish Jangam if (ret < 0)
105e41f6432SAshish Jangam goto hwmon_err;
106e41f6432SAshish Jangam
107e41f6432SAshish Jangam mutex_unlock(&hwmon->hwmon_lock);
108088ce2acSGuenter Roeck return sprintf(buf, "%d\n", volt_reg_to_mv(vdd));
109e41f6432SAshish Jangam
110e41f6432SAshish Jangam hwmon_err_release:
111e41f6432SAshish Jangam da9052_disable_vddout_channel(hwmon->da9052);
112e41f6432SAshish Jangam hwmon_err:
113e41f6432SAshish Jangam mutex_unlock(&hwmon->hwmon_lock);
114e41f6432SAshish Jangam return ret;
115e41f6432SAshish Jangam }
116e41f6432SAshish Jangam
da9052_ich_show(struct device * dev,struct device_attribute * devattr,char * buf)1176db587b7SGuenter Roeck static ssize_t da9052_ich_show(struct device *dev,
118e41f6432SAshish Jangam struct device_attribute *devattr, char *buf)
119e41f6432SAshish Jangam {
120e41f6432SAshish Jangam struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
121e41f6432SAshish Jangam int ret;
122e41f6432SAshish Jangam
123e41f6432SAshish Jangam ret = da9052_reg_read(hwmon->da9052, DA9052_ICHG_AV_REG);
124e41f6432SAshish Jangam if (ret < 0)
125e41f6432SAshish Jangam return ret;
126e41f6432SAshish Jangam
127e41f6432SAshish Jangam /* Equivalent to 3.9mA/bit in register ICHG_AV */
128e41f6432SAshish Jangam return sprintf(buf, "%d\n", DIV_ROUND_CLOSEST(ret * 39, 10));
129e41f6432SAshish Jangam }
130e41f6432SAshish Jangam
da9052_tbat_show(struct device * dev,struct device_attribute * devattr,char * buf)1316db587b7SGuenter Roeck static ssize_t da9052_tbat_show(struct device *dev,
132e41f6432SAshish Jangam struct device_attribute *devattr, char *buf)
133e41f6432SAshish Jangam {
134e41f6432SAshish Jangam struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
135e41f6432SAshish Jangam
136e41f6432SAshish Jangam return sprintf(buf, "%d\n", da9052_adc_read_temp(hwmon->da9052));
137e41f6432SAshish Jangam }
138e41f6432SAshish Jangam
da9052_vbat_show(struct device * dev,struct device_attribute * devattr,char * buf)1396db587b7SGuenter Roeck static ssize_t da9052_vbat_show(struct device *dev,
140e41f6432SAshish Jangam struct device_attribute *devattr, char *buf)
141e41f6432SAshish Jangam {
142e41f6432SAshish Jangam struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
143e41f6432SAshish Jangam int ret;
144e41f6432SAshish Jangam
145e41f6432SAshish Jangam ret = da9052_adc_manual_read(hwmon->da9052, DA9052_ADC_VBAT);
146e41f6432SAshish Jangam if (ret < 0)
147e41f6432SAshish Jangam return ret;
148e41f6432SAshish Jangam
149088ce2acSGuenter Roeck return sprintf(buf, "%d\n", volt_reg_to_mv(ret));
150e41f6432SAshish Jangam }
151e41f6432SAshish Jangam
da9052_misc_channel_show(struct device * dev,struct device_attribute * devattr,char * buf)1526db587b7SGuenter Roeck static ssize_t da9052_misc_channel_show(struct device *dev,
153e41f6432SAshish Jangam struct device_attribute *devattr,
154e41f6432SAshish Jangam char *buf)
155e41f6432SAshish Jangam {
156e41f6432SAshish Jangam struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
157e41f6432SAshish Jangam int channel = to_sensor_dev_attr(devattr)->index;
158e41f6432SAshish Jangam int ret;
159e41f6432SAshish Jangam
160e41f6432SAshish Jangam ret = da9052_adc_manual_read(hwmon->da9052, channel);
161e41f6432SAshish Jangam if (ret < 0)
162e41f6432SAshish Jangam return ret;
163e41f6432SAshish Jangam
164088ce2acSGuenter Roeck return sprintf(buf, "%d\n", input_reg_to_mv(ret));
165e41f6432SAshish Jangam }
166e41f6432SAshish Jangam
da9052_request_tsi_read(struct da9052_hwmon * hwmon,int channel)1674f16cab1SSebastian Reichel static int da9052_request_tsi_read(struct da9052_hwmon *hwmon, int channel)
1684f16cab1SSebastian Reichel {
1694f16cab1SSebastian Reichel u8 val = DA9052_TSICONTB_TSIMAN;
1704f16cab1SSebastian Reichel
1714f16cab1SSebastian Reichel switch (channel) {
1724f16cab1SSebastian Reichel case DA9052_ADC_TSI_XP:
1734f16cab1SSebastian Reichel val |= DA9052_TSICONTB_TSIMUX_XP;
1744f16cab1SSebastian Reichel break;
1754f16cab1SSebastian Reichel case DA9052_ADC_TSI_YP:
1764f16cab1SSebastian Reichel val |= DA9052_TSICONTB_TSIMUX_YP;
1774f16cab1SSebastian Reichel break;
1784f16cab1SSebastian Reichel case DA9052_ADC_TSI_XN:
1794f16cab1SSebastian Reichel val |= DA9052_TSICONTB_TSIMUX_XN;
1804f16cab1SSebastian Reichel break;
1814f16cab1SSebastian Reichel case DA9052_ADC_TSI_YN:
1824f16cab1SSebastian Reichel val |= DA9052_TSICONTB_TSIMUX_YN;
1834f16cab1SSebastian Reichel break;
1844f16cab1SSebastian Reichel }
1854f16cab1SSebastian Reichel
1864f16cab1SSebastian Reichel return da9052_reg_write(hwmon->da9052, DA9052_TSI_CONT_B_REG, val);
1874f16cab1SSebastian Reichel }
1884f16cab1SSebastian Reichel
da9052_get_tsi_result(struct da9052_hwmon * hwmon,int channel)1894f16cab1SSebastian Reichel static int da9052_get_tsi_result(struct da9052_hwmon *hwmon, int channel)
1904f16cab1SSebastian Reichel {
1914f16cab1SSebastian Reichel u8 regs[3];
1924f16cab1SSebastian Reichel int msb, lsb, err;
1934f16cab1SSebastian Reichel
1944f16cab1SSebastian Reichel /* block read to avoid separation of MSB and LSB */
1954f16cab1SSebastian Reichel err = da9052_group_read(hwmon->da9052, DA9052_TSI_X_MSB_REG,
1964f16cab1SSebastian Reichel ARRAY_SIZE(regs), regs);
1974f16cab1SSebastian Reichel if (err)
1984f16cab1SSebastian Reichel return err;
1994f16cab1SSebastian Reichel
2004f16cab1SSebastian Reichel switch (channel) {
2014f16cab1SSebastian Reichel case DA9052_ADC_TSI_XP:
2024f16cab1SSebastian Reichel case DA9052_ADC_TSI_XN:
2034f16cab1SSebastian Reichel msb = regs[0] << DA9052_TSILSB_TSIXL_BITS;
2044f16cab1SSebastian Reichel lsb = regs[2] & DA9052_TSILSB_TSIXL;
2054f16cab1SSebastian Reichel lsb >>= DA9052_TSILSB_TSIXL_SHIFT;
2064f16cab1SSebastian Reichel break;
2074f16cab1SSebastian Reichel case DA9052_ADC_TSI_YP:
2084f16cab1SSebastian Reichel case DA9052_ADC_TSI_YN:
2094f16cab1SSebastian Reichel msb = regs[1] << DA9052_TSILSB_TSIYL_BITS;
2104f16cab1SSebastian Reichel lsb = regs[2] & DA9052_TSILSB_TSIYL;
2114f16cab1SSebastian Reichel lsb >>= DA9052_TSILSB_TSIYL_SHIFT;
2124f16cab1SSebastian Reichel break;
2134f16cab1SSebastian Reichel default:
2144f16cab1SSebastian Reichel return -EINVAL;
2154f16cab1SSebastian Reichel }
2164f16cab1SSebastian Reichel
2174f16cab1SSebastian Reichel return msb | lsb;
2184f16cab1SSebastian Reichel }
2194f16cab1SSebastian Reichel
2204f16cab1SSebastian Reichel
__da9052_read_tsi(struct device * dev,int channel)2214f16cab1SSebastian Reichel static ssize_t __da9052_read_tsi(struct device *dev, int channel)
2224f16cab1SSebastian Reichel {
2234f16cab1SSebastian Reichel struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
2244f16cab1SSebastian Reichel int ret;
2254f16cab1SSebastian Reichel
2264f16cab1SSebastian Reichel reinit_completion(&hwmon->tsidone);
2274f16cab1SSebastian Reichel
2284f16cab1SSebastian Reichel ret = da9052_request_tsi_read(hwmon, channel);
2294f16cab1SSebastian Reichel if (ret < 0)
2304f16cab1SSebastian Reichel return ret;
2314f16cab1SSebastian Reichel
2324f16cab1SSebastian Reichel /* Wait for an conversion done interrupt */
2334f16cab1SSebastian Reichel if (!wait_for_completion_timeout(&hwmon->tsidone,
2344f16cab1SSebastian Reichel msecs_to_jiffies(500)))
2354f16cab1SSebastian Reichel return -ETIMEDOUT;
2364f16cab1SSebastian Reichel
2374f16cab1SSebastian Reichel return da9052_get_tsi_result(hwmon, channel);
2384f16cab1SSebastian Reichel }
2394f16cab1SSebastian Reichel
da9052_tsi_show(struct device * dev,struct device_attribute * devattr,char * buf)2406db587b7SGuenter Roeck static ssize_t da9052_tsi_show(struct device *dev,
2416db587b7SGuenter Roeck struct device_attribute *devattr, char *buf)
2424f16cab1SSebastian Reichel {
2434f16cab1SSebastian Reichel struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
2444f16cab1SSebastian Reichel int channel = to_sensor_dev_attr(devattr)->index;
2454f16cab1SSebastian Reichel int ret;
2464f16cab1SSebastian Reichel
247333e22dbSSamu Nuutamo mutex_lock(&hwmon->da9052->auxadc_lock);
2484f16cab1SSebastian Reichel ret = __da9052_read_tsi(dev, channel);
249333e22dbSSamu Nuutamo mutex_unlock(&hwmon->da9052->auxadc_lock);
2504f16cab1SSebastian Reichel
2514f16cab1SSebastian Reichel if (ret < 0)
2524f16cab1SSebastian Reichel return ret;
2534f16cab1SSebastian Reichel else
2544f16cab1SSebastian Reichel return sprintf(buf, "%d\n", input_tsireg_to_mv(hwmon, ret));
2554f16cab1SSebastian Reichel }
2564f16cab1SSebastian Reichel
da9052_tjunc_show(struct device * dev,struct device_attribute * devattr,char * buf)2576db587b7SGuenter Roeck static ssize_t da9052_tjunc_show(struct device *dev,
258e41f6432SAshish Jangam struct device_attribute *devattr, char *buf)
259e41f6432SAshish Jangam {
260e41f6432SAshish Jangam struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
261e41f6432SAshish Jangam int tjunc;
262e41f6432SAshish Jangam int toffset;
263e41f6432SAshish Jangam
264e41f6432SAshish Jangam tjunc = da9052_reg_read(hwmon->da9052, DA9052_TJUNC_RES_REG);
265e41f6432SAshish Jangam if (tjunc < 0)
266e41f6432SAshish Jangam return tjunc;
267e41f6432SAshish Jangam
268e41f6432SAshish Jangam toffset = da9052_reg_read(hwmon->da9052, DA9052_T_OFFSET_REG);
269e41f6432SAshish Jangam if (toffset < 0)
270e41f6432SAshish Jangam return toffset;
271e41f6432SAshish Jangam
272e41f6432SAshish Jangam /*
273e41f6432SAshish Jangam * Degrees celsius = 1.708 * (TJUNC_RES - T_OFFSET) - 108.8
274e41f6432SAshish Jangam * T_OFFSET is a trim value used to improve accuracy of the result
275e41f6432SAshish Jangam */
276e41f6432SAshish Jangam return sprintf(buf, "%d\n", 1708 * (tjunc - toffset) - 108800);
277e41f6432SAshish Jangam }
278e41f6432SAshish Jangam
da9052_vbbat_show(struct device * dev,struct device_attribute * devattr,char * buf)2796db587b7SGuenter Roeck static ssize_t da9052_vbbat_show(struct device *dev,
280e41f6432SAshish Jangam struct device_attribute *devattr, char *buf)
281e41f6432SAshish Jangam {
282e41f6432SAshish Jangam struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
283e41f6432SAshish Jangam int ret;
284e41f6432SAshish Jangam
285e41f6432SAshish Jangam ret = da9052_adc_manual_read(hwmon->da9052, DA9052_ADC_VBBAT);
286e41f6432SAshish Jangam if (ret < 0)
287e41f6432SAshish Jangam return ret;
288e41f6432SAshish Jangam
289088ce2acSGuenter Roeck return sprintf(buf, "%d\n", vbbat_reg_to_mv(ret));
290e41f6432SAshish Jangam }
291e41f6432SAshish Jangam
label_show(struct device * dev,struct device_attribute * devattr,char * buf)2926db587b7SGuenter Roeck static ssize_t label_show(struct device *dev,
293e41f6432SAshish Jangam struct device_attribute *devattr, char *buf)
294e41f6432SAshish Jangam {
295e41f6432SAshish Jangam return sprintf(buf, "%s\n",
296e41f6432SAshish Jangam input_names[to_sensor_dev_attr(devattr)->index]);
297e41f6432SAshish Jangam }
298e41f6432SAshish Jangam
da9052_channel_is_visible(struct kobject * kobj,struct attribute * attr,int index)2994f16cab1SSebastian Reichel static umode_t da9052_channel_is_visible(struct kobject *kobj,
3004f16cab1SSebastian Reichel struct attribute *attr, int index)
3014f16cab1SSebastian Reichel {
302*8c646ef1STian Tao struct device *dev = kobj_to_dev(kobj);
3034f16cab1SSebastian Reichel struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
3044f16cab1SSebastian Reichel struct device_attribute *dattr = container_of(attr,
3054f16cab1SSebastian Reichel struct device_attribute, attr);
3064f16cab1SSebastian Reichel struct sensor_device_attribute *sattr = to_sensor_dev_attr(dattr);
3074f16cab1SSebastian Reichel
3084f16cab1SSebastian Reichel if (!hwmon->tsi_as_adc) {
3094f16cab1SSebastian Reichel switch (sattr->index) {
3104f16cab1SSebastian Reichel case DA9052_ADC_TSI_XP:
3114f16cab1SSebastian Reichel case DA9052_ADC_TSI_YP:
3124f16cab1SSebastian Reichel case DA9052_ADC_TSI_XN:
3134f16cab1SSebastian Reichel case DA9052_ADC_TSI_YN:
3144f16cab1SSebastian Reichel return 0;
3154f16cab1SSebastian Reichel }
3164f16cab1SSebastian Reichel }
3174f16cab1SSebastian Reichel
3184f16cab1SSebastian Reichel return attr->mode;
3194f16cab1SSebastian Reichel }
3204f16cab1SSebastian Reichel
3216db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in0_input, da9052_vddout, DA9052_ADC_VDDOUT);
3226db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in0_label, label, DA9052_ADC_VDDOUT);
3236db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in3_input, da9052_vbat, DA9052_ADC_VBAT);
3246db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in3_label, label, DA9052_ADC_VBAT);
3256db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in4_input, da9052_misc_channel, DA9052_ADC_IN4);
3266db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in4_label, label, DA9052_ADC_IN4);
3276db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in5_input, da9052_misc_channel, DA9052_ADC_IN5);
3286db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in5_label, label, DA9052_ADC_IN5);
3296db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in6_input, da9052_misc_channel, DA9052_ADC_IN6);
3306db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in6_label, label, DA9052_ADC_IN6);
3316db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in9_input, da9052_vbbat, DA9052_ADC_VBBAT);
3326db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in9_label, label, DA9052_ADC_VBBAT);
333e41f6432SAshish Jangam
3346db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in70_input, da9052_tsi, DA9052_ADC_TSI_XP);
3356db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in70_label, label, DA9052_ADC_TSI_XP);
3366db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in71_input, da9052_tsi, DA9052_ADC_TSI_XN);
3376db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in71_label, label, DA9052_ADC_TSI_XN);
3386db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in72_input, da9052_tsi, DA9052_ADC_TSI_YP);
3396db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in72_label, label, DA9052_ADC_TSI_YP);
3406db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in73_input, da9052_tsi, DA9052_ADC_TSI_YN);
3416db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(in73_label, label, DA9052_ADC_TSI_YN);
3424f16cab1SSebastian Reichel
3436db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(curr1_input, da9052_ich, DA9052_ADC_ICH);
3446db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(curr1_label, label, DA9052_ADC_ICH);
345e41f6432SAshish Jangam
3466db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_input, da9052_tbat, DA9052_ADC_TBAT);
3476db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp2_label, label, DA9052_ADC_TBAT);
3486db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp8_input, da9052_tjunc, DA9052_ADC_TJUNC);
3496db587b7SGuenter Roeck static SENSOR_DEVICE_ATTR_RO(temp8_label, label, DA9052_ADC_TJUNC);
350e41f6432SAshish Jangam
3514222eb5fSAxel Lin static struct attribute *da9052_attrs[] = {
352e41f6432SAshish Jangam &sensor_dev_attr_in0_input.dev_attr.attr,
353e41f6432SAshish Jangam &sensor_dev_attr_in0_label.dev_attr.attr,
354e41f6432SAshish Jangam &sensor_dev_attr_in3_input.dev_attr.attr,
355e41f6432SAshish Jangam &sensor_dev_attr_in3_label.dev_attr.attr,
356e41f6432SAshish Jangam &sensor_dev_attr_in4_input.dev_attr.attr,
357e41f6432SAshish Jangam &sensor_dev_attr_in4_label.dev_attr.attr,
358e41f6432SAshish Jangam &sensor_dev_attr_in5_input.dev_attr.attr,
359e41f6432SAshish Jangam &sensor_dev_attr_in5_label.dev_attr.attr,
360e41f6432SAshish Jangam &sensor_dev_attr_in6_input.dev_attr.attr,
361e41f6432SAshish Jangam &sensor_dev_attr_in6_label.dev_attr.attr,
3624f16cab1SSebastian Reichel &sensor_dev_attr_in70_input.dev_attr.attr,
3634f16cab1SSebastian Reichel &sensor_dev_attr_in70_label.dev_attr.attr,
3644f16cab1SSebastian Reichel &sensor_dev_attr_in71_input.dev_attr.attr,
3654f16cab1SSebastian Reichel &sensor_dev_attr_in71_label.dev_attr.attr,
3664f16cab1SSebastian Reichel &sensor_dev_attr_in72_input.dev_attr.attr,
3674f16cab1SSebastian Reichel &sensor_dev_attr_in72_label.dev_attr.attr,
3684f16cab1SSebastian Reichel &sensor_dev_attr_in73_input.dev_attr.attr,
3694f16cab1SSebastian Reichel &sensor_dev_attr_in73_label.dev_attr.attr,
370e41f6432SAshish Jangam &sensor_dev_attr_in9_input.dev_attr.attr,
371e41f6432SAshish Jangam &sensor_dev_attr_in9_label.dev_attr.attr,
372e41f6432SAshish Jangam &sensor_dev_attr_curr1_input.dev_attr.attr,
373e41f6432SAshish Jangam &sensor_dev_attr_curr1_label.dev_attr.attr,
374e41f6432SAshish Jangam &sensor_dev_attr_temp2_input.dev_attr.attr,
375e41f6432SAshish Jangam &sensor_dev_attr_temp2_label.dev_attr.attr,
376e41f6432SAshish Jangam &sensor_dev_attr_temp8_input.dev_attr.attr,
377e41f6432SAshish Jangam &sensor_dev_attr_temp8_label.dev_attr.attr,
378e41f6432SAshish Jangam NULL
379e41f6432SAshish Jangam };
380e41f6432SAshish Jangam
3814f16cab1SSebastian Reichel static const struct attribute_group da9052_group = {
3824f16cab1SSebastian Reichel .attrs = da9052_attrs,
3834f16cab1SSebastian Reichel .is_visible = da9052_channel_is_visible,
3844f16cab1SSebastian Reichel };
3854f16cab1SSebastian Reichel __ATTRIBUTE_GROUPS(da9052);
3864f16cab1SSebastian Reichel
da9052_tsi_datardy_irq(int irq,void * data)3874f16cab1SSebastian Reichel static irqreturn_t da9052_tsi_datardy_irq(int irq, void *data)
3884f16cab1SSebastian Reichel {
3894f16cab1SSebastian Reichel struct da9052_hwmon *hwmon = data;
3904f16cab1SSebastian Reichel
3914f16cab1SSebastian Reichel complete(&hwmon->tsidone);
3924f16cab1SSebastian Reichel return IRQ_HANDLED;
3934f16cab1SSebastian Reichel }
394e41f6432SAshish Jangam
da9052_hwmon_probe(struct platform_device * pdev)3956c931ae1SBill Pemberton static int da9052_hwmon_probe(struct platform_device *pdev)
396e41f6432SAshish Jangam {
3974222eb5fSAxel Lin struct device *dev = &pdev->dev;
398e41f6432SAshish Jangam struct da9052_hwmon *hwmon;
3994222eb5fSAxel Lin struct device *hwmon_dev;
4004f16cab1SSebastian Reichel int err;
401e41f6432SAshish Jangam
4024222eb5fSAxel Lin hwmon = devm_kzalloc(dev, sizeof(struct da9052_hwmon), GFP_KERNEL);
403e41f6432SAshish Jangam if (!hwmon)
404e41f6432SAshish Jangam return -ENOMEM;
405e41f6432SAshish Jangam
4064f16cab1SSebastian Reichel platform_set_drvdata(pdev, hwmon);
4074f16cab1SSebastian Reichel
408e41f6432SAshish Jangam mutex_init(&hwmon->hwmon_lock);
409e41f6432SAshish Jangam hwmon->da9052 = dev_get_drvdata(pdev->dev.parent);
410e41f6432SAshish Jangam
4114f16cab1SSebastian Reichel init_completion(&hwmon->tsidone);
4124f16cab1SSebastian Reichel
4134f16cab1SSebastian Reichel hwmon->tsi_as_adc =
4144f16cab1SSebastian Reichel device_property_read_bool(pdev->dev.parent, "dlg,tsi-as-adc");
4154f16cab1SSebastian Reichel
4164f16cab1SSebastian Reichel if (hwmon->tsi_as_adc) {
4174f16cab1SSebastian Reichel hwmon->tsiref = devm_regulator_get(pdev->dev.parent, "tsiref");
4184f16cab1SSebastian Reichel if (IS_ERR(hwmon->tsiref)) {
4194f16cab1SSebastian Reichel err = PTR_ERR(hwmon->tsiref);
4204f16cab1SSebastian Reichel dev_err(&pdev->dev, "failed to get tsiref: %d", err);
4214f16cab1SSebastian Reichel return err;
4224f16cab1SSebastian Reichel }
4234f16cab1SSebastian Reichel
4244f16cab1SSebastian Reichel err = regulator_enable(hwmon->tsiref);
4254f16cab1SSebastian Reichel if (err)
4264f16cab1SSebastian Reichel return err;
4274f16cab1SSebastian Reichel
4284f16cab1SSebastian Reichel hwmon->tsiref_mv = regulator_get_voltage(hwmon->tsiref);
4294f16cab1SSebastian Reichel if (hwmon->tsiref_mv < 0) {
4304f16cab1SSebastian Reichel err = hwmon->tsiref_mv;
4314f16cab1SSebastian Reichel goto exit_regulator;
4324f16cab1SSebastian Reichel }
4334f16cab1SSebastian Reichel
4344f16cab1SSebastian Reichel /* convert from microvolt (DT) to millivolt (hwmon) */
4354f16cab1SSebastian Reichel hwmon->tsiref_mv /= 1000;
4364f16cab1SSebastian Reichel
4374f16cab1SSebastian Reichel /* TSIREF limits from datasheet */
4384f16cab1SSebastian Reichel if (hwmon->tsiref_mv < 1800 || hwmon->tsiref_mv > 2600) {
4394f16cab1SSebastian Reichel dev_err(hwmon->da9052->dev, "invalid TSIREF voltage: %d",
4404f16cab1SSebastian Reichel hwmon->tsiref_mv);
4414f16cab1SSebastian Reichel err = -ENXIO;
4424f16cab1SSebastian Reichel goto exit_regulator;
4434f16cab1SSebastian Reichel }
4444f16cab1SSebastian Reichel
4454f16cab1SSebastian Reichel /* disable touchscreen features */
4464f16cab1SSebastian Reichel da9052_reg_write(hwmon->da9052, DA9052_TSI_CONT_A_REG, 0x00);
4474f16cab1SSebastian Reichel
448b16918a5SMartyn Welch /* Sample every 1ms */
449b16918a5SMartyn Welch da9052_reg_update(hwmon->da9052, DA9052_ADC_CONT_REG,
450b16918a5SMartyn Welch DA9052_ADCCONT_ADCMODE,
451b16918a5SMartyn Welch DA9052_ADCCONT_ADCMODE);
452b16918a5SMartyn Welch
4534f16cab1SSebastian Reichel err = da9052_request_irq(hwmon->da9052, DA9052_IRQ_TSIREADY,
4544f16cab1SSebastian Reichel "tsiready-irq", da9052_tsi_datardy_irq,
4554f16cab1SSebastian Reichel hwmon);
4564f16cab1SSebastian Reichel if (err) {
4574f16cab1SSebastian Reichel dev_err(&pdev->dev, "Failed to register TSIRDY IRQ: %d",
4584f16cab1SSebastian Reichel err);
4594f16cab1SSebastian Reichel goto exit_regulator;
4604f16cab1SSebastian Reichel }
4614f16cab1SSebastian Reichel }
4624f16cab1SSebastian Reichel
4634222eb5fSAxel Lin hwmon_dev = devm_hwmon_device_register_with_groups(dev, "da9052",
4644222eb5fSAxel Lin hwmon,
4654222eb5fSAxel Lin da9052_groups);
4664f16cab1SSebastian Reichel err = PTR_ERR_OR_ZERO(hwmon_dev);
4674f16cab1SSebastian Reichel if (err)
4684f16cab1SSebastian Reichel goto exit_irq;
4694f16cab1SSebastian Reichel
4704f16cab1SSebastian Reichel return 0;
4714f16cab1SSebastian Reichel
4724f16cab1SSebastian Reichel exit_irq:
4734f16cab1SSebastian Reichel if (hwmon->tsi_as_adc)
4744f16cab1SSebastian Reichel da9052_free_irq(hwmon->da9052, DA9052_IRQ_TSIREADY, hwmon);
4754f16cab1SSebastian Reichel exit_regulator:
4764f16cab1SSebastian Reichel if (hwmon->tsiref)
4774f16cab1SSebastian Reichel regulator_disable(hwmon->tsiref);
4784f16cab1SSebastian Reichel
4794f16cab1SSebastian Reichel return err;
4804f16cab1SSebastian Reichel }
4814f16cab1SSebastian Reichel
da9052_hwmon_remove(struct platform_device * pdev)4824f16cab1SSebastian Reichel static int da9052_hwmon_remove(struct platform_device *pdev)
4834f16cab1SSebastian Reichel {
4844f16cab1SSebastian Reichel struct da9052_hwmon *hwmon = platform_get_drvdata(pdev);
4854f16cab1SSebastian Reichel
4864f16cab1SSebastian Reichel if (hwmon->tsi_as_adc) {
4874f16cab1SSebastian Reichel da9052_free_irq(hwmon->da9052, DA9052_IRQ_TSIREADY, hwmon);
4884f16cab1SSebastian Reichel regulator_disable(hwmon->tsiref);
4894f16cab1SSebastian Reichel }
4904f16cab1SSebastian Reichel
4914f16cab1SSebastian Reichel return 0;
492e41f6432SAshish Jangam }
493e41f6432SAshish Jangam
494e41f6432SAshish Jangam static struct platform_driver da9052_hwmon_driver = {
495e41f6432SAshish Jangam .probe = da9052_hwmon_probe,
4964f16cab1SSebastian Reichel .remove = da9052_hwmon_remove,
497e41f6432SAshish Jangam .driver = {
498e41f6432SAshish Jangam .name = "da9052-hwmon",
499e41f6432SAshish Jangam },
500e41f6432SAshish Jangam };
501e41f6432SAshish Jangam
502e41f6432SAshish Jangam module_platform_driver(da9052_hwmon_driver);
503e41f6432SAshish Jangam
504e41f6432SAshish Jangam MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
505e41f6432SAshish Jangam MODULE_DESCRIPTION("DA9052 HWMON driver");
506e41f6432SAshish Jangam MODULE_LICENSE("GPL");
507e41f6432SAshish Jangam MODULE_ALIAS("platform:da9052-hwmon");
508