Linux Audio

Check our new training course

Loading...
v4.10.11
 
  1/*
  2 * HWMON Driver for Dialog DA9052
  3 *
  4 * Copyright(c) 2012 Dialog Semiconductor Ltd.
  5 *
  6 * Author: David Dajun Chen <dchen@diasemi.com>
  7 *
  8 *  This program is free software; you can redistribute  it and/or modify it
  9 *  under  the terms of  the GNU General  Public License as published by the
 10 *  Free Software Foundation;  either version 2 of the  License, or (at your
 11 *  option) any later version.
 12 *
 13 */
 14
 15#include <linux/err.h>
 16#include <linux/hwmon.h>
 17#include <linux/hwmon-sysfs.h>
 18#include <linux/init.h>
 19#include <linux/kernel.h>
 20#include <linux/module.h>
 21#include <linux/slab.h>
 22#include <linux/platform_device.h>
 
 23
 24#include <linux/mfd/da9052/da9052.h>
 25#include <linux/mfd/da9052/reg.h>
 
 26
 27struct da9052_hwmon {
 28	struct da9052	*da9052;
 29	struct mutex	hwmon_lock;
 
 
 
 30};
 31
 32static const char * const input_names[] = {
 33	[DA9052_ADC_VDDOUT]	=	"VDDOUT",
 34	[DA9052_ADC_ICH]	=	"CHARGING CURRENT",
 35	[DA9052_ADC_TBAT]	=	"BATTERY TEMP",
 36	[DA9052_ADC_VBAT]	=	"BATTERY VOLTAGE",
 37	[DA9052_ADC_IN4]	=	"ADC IN4",
 38	[DA9052_ADC_IN5]	=	"ADC IN5",
 39	[DA9052_ADC_IN6]	=	"ADC IN6",
 
 
 
 
 40	[DA9052_ADC_TJUNC]	=	"BATTERY JUNCTION TEMP",
 41	[DA9052_ADC_VBBAT]	=	"BACK-UP BATTERY VOLTAGE",
 42};
 43
 44/* Conversion function for VDDOUT and VBAT */
 45static inline int volt_reg_to_mv(int value)
 46{
 47	return DIV_ROUND_CLOSEST(value * 2000, 1023) + 2500;
 48}
 49
 50/* Conversion function for ADC channels 4, 5 and 6 */
 51static inline int input_reg_to_mv(int value)
 52{
 53	return DIV_ROUND_CLOSEST(value * 2500, 1023);
 54}
 55
 56/* Conversion function for VBBAT */
 57static inline int vbbat_reg_to_mv(int value)
 58{
 59	return DIV_ROUND_CLOSEST(value * 5000, 1023);
 60}
 61
 
 
 
 
 
 62static inline int da9052_enable_vddout_channel(struct da9052 *da9052)
 63{
 64	return da9052_reg_update(da9052, DA9052_ADC_CONT_REG,
 65				 DA9052_ADCCONT_AUTOVDDEN,
 66				 DA9052_ADCCONT_AUTOVDDEN);
 67}
 68
 69static inline int da9052_disable_vddout_channel(struct da9052 *da9052)
 70{
 71	return da9052_reg_update(da9052, DA9052_ADC_CONT_REG,
 72				 DA9052_ADCCONT_AUTOVDDEN, 0);
 73}
 74
 75static ssize_t da9052_read_vddout(struct device *dev,
 76				  struct device_attribute *devattr, char *buf)
 77{
 78	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
 79	int ret, vdd;
 80
 81	mutex_lock(&hwmon->hwmon_lock);
 82
 83	ret = da9052_enable_vddout_channel(hwmon->da9052);
 84	if (ret < 0)
 85		goto hwmon_err;
 86
 87	vdd = da9052_reg_read(hwmon->da9052, DA9052_VDD_RES_REG);
 88	if (vdd < 0) {
 89		ret = vdd;
 90		goto hwmon_err_release;
 91	}
 92
 93	ret = da9052_disable_vddout_channel(hwmon->da9052);
 94	if (ret < 0)
 95		goto hwmon_err;
 96
 97	mutex_unlock(&hwmon->hwmon_lock);
 98	return sprintf(buf, "%d\n", volt_reg_to_mv(vdd));
 99
100hwmon_err_release:
101	da9052_disable_vddout_channel(hwmon->da9052);
102hwmon_err:
103	mutex_unlock(&hwmon->hwmon_lock);
104	return ret;
105}
106
107static ssize_t da9052_read_ich(struct device *dev,
108			       struct device_attribute *devattr, char *buf)
109{
110	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
111	int ret;
112
113	ret = da9052_reg_read(hwmon->da9052, DA9052_ICHG_AV_REG);
114	if (ret < 0)
115		return ret;
116
117	/* Equivalent to 3.9mA/bit in register ICHG_AV */
118	return sprintf(buf, "%d\n", DIV_ROUND_CLOSEST(ret * 39, 10));
119}
120
121static ssize_t da9052_read_tbat(struct device *dev,
122				struct device_attribute *devattr, char *buf)
123{
124	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
125
126	return sprintf(buf, "%d\n", da9052_adc_read_temp(hwmon->da9052));
127}
128
129static ssize_t da9052_read_vbat(struct device *dev,
130				struct device_attribute *devattr, char *buf)
131{
132	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
133	int ret;
134
135	ret = da9052_adc_manual_read(hwmon->da9052, DA9052_ADC_VBAT);
136	if (ret < 0)
137		return ret;
138
139	return sprintf(buf, "%d\n", volt_reg_to_mv(ret));
140}
141
142static ssize_t da9052_read_misc_channel(struct device *dev,
143					struct device_attribute *devattr,
144					char *buf)
145{
146	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
147	int channel = to_sensor_dev_attr(devattr)->index;
148	int ret;
149
150	ret = da9052_adc_manual_read(hwmon->da9052, channel);
151	if (ret < 0)
152		return ret;
153
154	return sprintf(buf, "%d\n", input_reg_to_mv(ret));
155}
156
157static ssize_t da9052_read_tjunc(struct device *dev,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158				 struct device_attribute *devattr, char *buf)
159{
160	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
161	int tjunc;
162	int toffset;
163
164	tjunc = da9052_reg_read(hwmon->da9052, DA9052_TJUNC_RES_REG);
165	if (tjunc < 0)
166		return tjunc;
167
168	toffset = da9052_reg_read(hwmon->da9052, DA9052_T_OFFSET_REG);
169	if (toffset < 0)
170		return toffset;
171
172	/*
173	 * Degrees celsius = 1.708 * (TJUNC_RES - T_OFFSET) - 108.8
174	 * T_OFFSET is a trim value used to improve accuracy of the result
175	 */
176	return sprintf(buf, "%d\n", 1708 * (tjunc - toffset) - 108800);
177}
178
179static ssize_t da9052_read_vbbat(struct device *dev,
180				 struct device_attribute *devattr, char *buf)
181{
182	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
183	int ret;
184
185	ret = da9052_adc_manual_read(hwmon->da9052, DA9052_ADC_VBBAT);
186	if (ret < 0)
187		return ret;
188
189	return sprintf(buf, "%d\n", vbbat_reg_to_mv(ret));
190}
191
192static ssize_t show_label(struct device *dev,
193			  struct device_attribute *devattr, char *buf)
194{
195	return sprintf(buf, "%s\n",
196		       input_names[to_sensor_dev_attr(devattr)->index]);
197}
198
199static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, da9052_read_vddout, NULL,
200			  DA9052_ADC_VDDOUT);
201static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, show_label, NULL,
202			  DA9052_ADC_VDDOUT);
203static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, da9052_read_vbat, NULL,
204			  DA9052_ADC_VBAT);
205static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL,
206			  DA9052_ADC_VBAT);
207static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, da9052_read_misc_channel, NULL,
208			  DA9052_ADC_IN4);
209static SENSOR_DEVICE_ATTR(in4_label, S_IRUGO, show_label, NULL,
210			  DA9052_ADC_IN4);
211static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, da9052_read_misc_channel, NULL,
212			  DA9052_ADC_IN5);
213static SENSOR_DEVICE_ATTR(in5_label, S_IRUGO, show_label, NULL,
214			  DA9052_ADC_IN5);
215static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, da9052_read_misc_channel, NULL,
216			  DA9052_ADC_IN6);
217static SENSOR_DEVICE_ATTR(in6_label, S_IRUGO, show_label, NULL,
218			  DA9052_ADC_IN6);
219static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, da9052_read_vbbat, NULL,
220			  DA9052_ADC_VBBAT);
221static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL,
222			  DA9052_ADC_VBBAT);
223
224static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, da9052_read_ich, NULL,
225			  DA9052_ADC_ICH);
226static SENSOR_DEVICE_ATTR(curr1_label, S_IRUGO, show_label, NULL,
227			  DA9052_ADC_ICH);
228
229static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, da9052_read_tbat, NULL,
230			  DA9052_ADC_TBAT);
231static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, show_label, NULL,
232			  DA9052_ADC_TBAT);
233static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, da9052_read_tjunc, NULL,
234			  DA9052_ADC_TJUNC);
235static SENSOR_DEVICE_ATTR(temp8_label, S_IRUGO, show_label, NULL,
236			  DA9052_ADC_TJUNC);
 
 
 
 
 
 
 
 
 
 
 
 
 
237
238static struct attribute *da9052_attrs[] = {
239	&sensor_dev_attr_in0_input.dev_attr.attr,
240	&sensor_dev_attr_in0_label.dev_attr.attr,
241	&sensor_dev_attr_in3_input.dev_attr.attr,
242	&sensor_dev_attr_in3_label.dev_attr.attr,
243	&sensor_dev_attr_in4_input.dev_attr.attr,
244	&sensor_dev_attr_in4_label.dev_attr.attr,
245	&sensor_dev_attr_in5_input.dev_attr.attr,
246	&sensor_dev_attr_in5_label.dev_attr.attr,
247	&sensor_dev_attr_in6_input.dev_attr.attr,
248	&sensor_dev_attr_in6_label.dev_attr.attr,
 
 
 
 
 
 
 
 
249	&sensor_dev_attr_in9_input.dev_attr.attr,
250	&sensor_dev_attr_in9_label.dev_attr.attr,
251	&sensor_dev_attr_curr1_input.dev_attr.attr,
252	&sensor_dev_attr_curr1_label.dev_attr.attr,
253	&sensor_dev_attr_temp2_input.dev_attr.attr,
254	&sensor_dev_attr_temp2_label.dev_attr.attr,
255	&sensor_dev_attr_temp8_input.dev_attr.attr,
256	&sensor_dev_attr_temp8_label.dev_attr.attr,
257	NULL
258};
259
260ATTRIBUTE_GROUPS(da9052);
 
 
 
 
 
 
 
 
 
 
 
 
261
262static int da9052_hwmon_probe(struct platform_device *pdev)
263{
264	struct device *dev = &pdev->dev;
265	struct da9052_hwmon *hwmon;
266	struct device *hwmon_dev;
 
267
268	hwmon = devm_kzalloc(dev, sizeof(struct da9052_hwmon), GFP_KERNEL);
269	if (!hwmon)
270		return -ENOMEM;
271
 
 
272	mutex_init(&hwmon->hwmon_lock);
273	hwmon->da9052 = dev_get_drvdata(pdev->dev.parent);
274
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275	hwmon_dev = devm_hwmon_device_register_with_groups(dev, "da9052",
276							   hwmon,
277							   da9052_groups);
278	return PTR_ERR_OR_ZERO(hwmon_dev);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
279}
280
281static struct platform_driver da9052_hwmon_driver = {
282	.probe = da9052_hwmon_probe,
 
283	.driver = {
284		.name = "da9052-hwmon",
285	},
286};
287
288module_platform_driver(da9052_hwmon_driver);
289
290MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
291MODULE_DESCRIPTION("DA9052 HWMON driver");
292MODULE_LICENSE("GPL");
293MODULE_ALIAS("platform:da9052-hwmon");
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * HWMON Driver for Dialog DA9052
  4 *
  5 * Copyright(c) 2012 Dialog Semiconductor Ltd.
  6 *
  7 * Author: David Dajun Chen <dchen@diasemi.com>
 
 
 
 
 
 
  8 */
  9
 10#include <linux/err.h>
 11#include <linux/hwmon.h>
 12#include <linux/hwmon-sysfs.h>
 13#include <linux/init.h>
 14#include <linux/kernel.h>
 15#include <linux/module.h>
 16#include <linux/slab.h>
 17#include <linux/platform_device.h>
 18#include <linux/property.h>
 19
 20#include <linux/mfd/da9052/da9052.h>
 21#include <linux/mfd/da9052/reg.h>
 22#include <linux/regulator/consumer.h>
 23
 24struct da9052_hwmon {
 25	struct da9052		*da9052;
 26	struct mutex		hwmon_lock;
 27	bool			tsi_as_adc;
 28	int			tsiref_mv;
 29	struct completion	tsidone;
 30};
 31
 32static const char * const input_names[] = {
 33	[DA9052_ADC_VDDOUT]	=	"VDDOUT",
 34	[DA9052_ADC_ICH]	=	"CHARGING CURRENT",
 35	[DA9052_ADC_TBAT]	=	"BATTERY TEMP",
 36	[DA9052_ADC_VBAT]	=	"BATTERY VOLTAGE",
 37	[DA9052_ADC_IN4]	=	"ADC IN4",
 38	[DA9052_ADC_IN5]	=	"ADC IN5",
 39	[DA9052_ADC_IN6]	=	"ADC IN6",
 40	[DA9052_ADC_TSI_XP]	=	"ADC TS X+",
 41	[DA9052_ADC_TSI_YP]	=	"ADC TS Y+",
 42	[DA9052_ADC_TSI_XN]	=	"ADC TS X-",
 43	[DA9052_ADC_TSI_YN]	=	"ADC TS Y-",
 44	[DA9052_ADC_TJUNC]	=	"BATTERY JUNCTION TEMP",
 45	[DA9052_ADC_VBBAT]	=	"BACK-UP BATTERY VOLTAGE",
 46};
 47
 48/* Conversion function for VDDOUT and VBAT */
 49static inline int volt_reg_to_mv(int value)
 50{
 51	return DIV_ROUND_CLOSEST(value * 2000, 1023) + 2500;
 52}
 53
 54/* Conversion function for ADC channels 4, 5 and 6 */
 55static inline int input_reg_to_mv(int value)
 56{
 57	return DIV_ROUND_CLOSEST(value * 2500, 1023);
 58}
 59
 60/* Conversion function for VBBAT */
 61static inline int vbbat_reg_to_mv(int value)
 62{
 63	return DIV_ROUND_CLOSEST(value * 5000, 1023);
 64}
 65
 66static inline int input_tsireg_to_mv(struct da9052_hwmon *hwmon, int value)
 67{
 68	return DIV_ROUND_CLOSEST(value * hwmon->tsiref_mv, 1023);
 69}
 70
 71static inline int da9052_enable_vddout_channel(struct da9052 *da9052)
 72{
 73	return da9052_reg_update(da9052, DA9052_ADC_CONT_REG,
 74				 DA9052_ADCCONT_AUTOVDDEN,
 75				 DA9052_ADCCONT_AUTOVDDEN);
 76}
 77
 78static inline int da9052_disable_vddout_channel(struct da9052 *da9052)
 79{
 80	return da9052_reg_update(da9052, DA9052_ADC_CONT_REG,
 81				 DA9052_ADCCONT_AUTOVDDEN, 0);
 82}
 83
 84static ssize_t da9052_vddout_show(struct device *dev,
 85				  struct device_attribute *devattr, char *buf)
 86{
 87	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
 88	int ret, vdd;
 89
 90	mutex_lock(&hwmon->hwmon_lock);
 91
 92	ret = da9052_enable_vddout_channel(hwmon->da9052);
 93	if (ret < 0)
 94		goto hwmon_err;
 95
 96	vdd = da9052_reg_read(hwmon->da9052, DA9052_VDD_RES_REG);
 97	if (vdd < 0) {
 98		ret = vdd;
 99		goto hwmon_err_release;
100	}
101
102	ret = da9052_disable_vddout_channel(hwmon->da9052);
103	if (ret < 0)
104		goto hwmon_err;
105
106	mutex_unlock(&hwmon->hwmon_lock);
107	return sprintf(buf, "%d\n", volt_reg_to_mv(vdd));
108
109hwmon_err_release:
110	da9052_disable_vddout_channel(hwmon->da9052);
111hwmon_err:
112	mutex_unlock(&hwmon->hwmon_lock);
113	return ret;
114}
115
116static ssize_t da9052_ich_show(struct device *dev,
117			       struct device_attribute *devattr, char *buf)
118{
119	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
120	int ret;
121
122	ret = da9052_reg_read(hwmon->da9052, DA9052_ICHG_AV_REG);
123	if (ret < 0)
124		return ret;
125
126	/* Equivalent to 3.9mA/bit in register ICHG_AV */
127	return sprintf(buf, "%d\n", DIV_ROUND_CLOSEST(ret * 39, 10));
128}
129
130static ssize_t da9052_tbat_show(struct device *dev,
131				struct device_attribute *devattr, char *buf)
132{
133	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
134
135	return sprintf(buf, "%d\n", da9052_adc_read_temp(hwmon->da9052));
136}
137
138static ssize_t da9052_vbat_show(struct device *dev,
139				struct device_attribute *devattr, char *buf)
140{
141	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
142	int ret;
143
144	ret = da9052_adc_manual_read(hwmon->da9052, DA9052_ADC_VBAT);
145	if (ret < 0)
146		return ret;
147
148	return sprintf(buf, "%d\n", volt_reg_to_mv(ret));
149}
150
151static ssize_t da9052_misc_channel_show(struct device *dev,
152					struct device_attribute *devattr,
153					char *buf)
154{
155	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
156	int channel = to_sensor_dev_attr(devattr)->index;
157	int ret;
158
159	ret = da9052_adc_manual_read(hwmon->da9052, channel);
160	if (ret < 0)
161		return ret;
162
163	return sprintf(buf, "%d\n", input_reg_to_mv(ret));
164}
165
166static int da9052_request_tsi_read(struct da9052_hwmon *hwmon, int channel)
167{
168	u8 val = DA9052_TSICONTB_TSIMAN;
169
170	switch (channel) {
171	case DA9052_ADC_TSI_XP:
172		val |= DA9052_TSICONTB_TSIMUX_XP;
173		break;
174	case DA9052_ADC_TSI_YP:
175		val |= DA9052_TSICONTB_TSIMUX_YP;
176		break;
177	case DA9052_ADC_TSI_XN:
178		val |= DA9052_TSICONTB_TSIMUX_XN;
179		break;
180	case DA9052_ADC_TSI_YN:
181		val |= DA9052_TSICONTB_TSIMUX_YN;
182		break;
183	}
184
185	return da9052_reg_write(hwmon->da9052, DA9052_TSI_CONT_B_REG, val);
186}
187
188static int da9052_get_tsi_result(struct da9052_hwmon *hwmon, int channel)
189{
190	u8 regs[3];
191	int msb, lsb, err;
192
193	/* block read to avoid separation of MSB and LSB */
194	err = da9052_group_read(hwmon->da9052, DA9052_TSI_X_MSB_REG,
195				ARRAY_SIZE(regs), regs);
196	if (err)
197		return err;
198
199	switch (channel) {
200	case DA9052_ADC_TSI_XP:
201	case DA9052_ADC_TSI_XN:
202		msb = regs[0] << DA9052_TSILSB_TSIXL_BITS;
203		lsb = regs[2] & DA9052_TSILSB_TSIXL;
204		lsb >>= DA9052_TSILSB_TSIXL_SHIFT;
205		break;
206	case DA9052_ADC_TSI_YP:
207	case DA9052_ADC_TSI_YN:
208		msb = regs[1] << DA9052_TSILSB_TSIYL_BITS;
209		lsb = regs[2] & DA9052_TSILSB_TSIYL;
210		lsb >>= DA9052_TSILSB_TSIYL_SHIFT;
211		break;
212	default:
213		return -EINVAL;
214	}
215
216	return msb | lsb;
217}
218
219
220static ssize_t __da9052_read_tsi(struct device *dev, int channel)
221{
222	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
223	int ret;
224
225	reinit_completion(&hwmon->tsidone);
226
227	ret = da9052_request_tsi_read(hwmon, channel);
228	if (ret < 0)
229		return ret;
230
231	/* Wait for an conversion done interrupt */
232	if (!wait_for_completion_timeout(&hwmon->tsidone,
233					 msecs_to_jiffies(500)))
234		return -ETIMEDOUT;
235
236	return da9052_get_tsi_result(hwmon, channel);
237}
238
239static ssize_t da9052_tsi_show(struct device *dev,
240			       struct device_attribute *devattr, char *buf)
241{
242	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
243	int channel = to_sensor_dev_attr(devattr)->index;
244	int ret;
245
246	mutex_lock(&hwmon->da9052->auxadc_lock);
247	ret = __da9052_read_tsi(dev, channel);
248	mutex_unlock(&hwmon->da9052->auxadc_lock);
249
250	if (ret < 0)
251		return ret;
252	else
253		return sprintf(buf, "%d\n", input_tsireg_to_mv(hwmon, ret));
254}
255
256static ssize_t da9052_tjunc_show(struct device *dev,
257				 struct device_attribute *devattr, char *buf)
258{
259	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
260	int tjunc;
261	int toffset;
262
263	tjunc = da9052_reg_read(hwmon->da9052, DA9052_TJUNC_RES_REG);
264	if (tjunc < 0)
265		return tjunc;
266
267	toffset = da9052_reg_read(hwmon->da9052, DA9052_T_OFFSET_REG);
268	if (toffset < 0)
269		return toffset;
270
271	/*
272	 * Degrees celsius = 1.708 * (TJUNC_RES - T_OFFSET) - 108.8
273	 * T_OFFSET is a trim value used to improve accuracy of the result
274	 */
275	return sprintf(buf, "%d\n", 1708 * (tjunc - toffset) - 108800);
276}
277
278static ssize_t da9052_vbbat_show(struct device *dev,
279				 struct device_attribute *devattr, char *buf)
280{
281	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
282	int ret;
283
284	ret = da9052_adc_manual_read(hwmon->da9052, DA9052_ADC_VBBAT);
285	if (ret < 0)
286		return ret;
287
288	return sprintf(buf, "%d\n", vbbat_reg_to_mv(ret));
289}
290
291static ssize_t label_show(struct device *dev,
292			  struct device_attribute *devattr, char *buf)
293{
294	return sprintf(buf, "%s\n",
295		       input_names[to_sensor_dev_attr(devattr)->index]);
296}
297
298static umode_t da9052_channel_is_visible(struct kobject *kobj,
299					 struct attribute *attr, int index)
300{
301	struct device *dev = kobj_to_dev(kobj);
302	struct da9052_hwmon *hwmon = dev_get_drvdata(dev);
303	struct device_attribute *dattr = container_of(attr,
304				struct device_attribute, attr);
305	struct sensor_device_attribute *sattr = to_sensor_dev_attr(dattr);
306
307	if (!hwmon->tsi_as_adc) {
308		switch (sattr->index) {
309		case DA9052_ADC_TSI_XP:
310		case DA9052_ADC_TSI_YP:
311		case DA9052_ADC_TSI_XN:
312		case DA9052_ADC_TSI_YN:
313			return 0;
314		}
315	}
316
317	return attr->mode;
318}
319
320static SENSOR_DEVICE_ATTR_RO(in0_input, da9052_vddout, DA9052_ADC_VDDOUT);
321static SENSOR_DEVICE_ATTR_RO(in0_label, label, DA9052_ADC_VDDOUT);
322static SENSOR_DEVICE_ATTR_RO(in3_input, da9052_vbat, DA9052_ADC_VBAT);
323static SENSOR_DEVICE_ATTR_RO(in3_label, label, DA9052_ADC_VBAT);
324static SENSOR_DEVICE_ATTR_RO(in4_input, da9052_misc_channel, DA9052_ADC_IN4);
325static SENSOR_DEVICE_ATTR_RO(in4_label, label, DA9052_ADC_IN4);
326static SENSOR_DEVICE_ATTR_RO(in5_input, da9052_misc_channel, DA9052_ADC_IN5);
327static SENSOR_DEVICE_ATTR_RO(in5_label, label, DA9052_ADC_IN5);
328static SENSOR_DEVICE_ATTR_RO(in6_input, da9052_misc_channel, DA9052_ADC_IN6);
329static SENSOR_DEVICE_ATTR_RO(in6_label, label, DA9052_ADC_IN6);
330static SENSOR_DEVICE_ATTR_RO(in9_input, da9052_vbbat, DA9052_ADC_VBBAT);
331static SENSOR_DEVICE_ATTR_RO(in9_label, label, DA9052_ADC_VBBAT);
332
333static SENSOR_DEVICE_ATTR_RO(in70_input, da9052_tsi, DA9052_ADC_TSI_XP);
334static SENSOR_DEVICE_ATTR_RO(in70_label, label, DA9052_ADC_TSI_XP);
335static SENSOR_DEVICE_ATTR_RO(in71_input, da9052_tsi, DA9052_ADC_TSI_XN);
336static SENSOR_DEVICE_ATTR_RO(in71_label, label, DA9052_ADC_TSI_XN);
337static SENSOR_DEVICE_ATTR_RO(in72_input, da9052_tsi, DA9052_ADC_TSI_YP);
338static SENSOR_DEVICE_ATTR_RO(in72_label, label, DA9052_ADC_TSI_YP);
339static SENSOR_DEVICE_ATTR_RO(in73_input, da9052_tsi, DA9052_ADC_TSI_YN);
340static SENSOR_DEVICE_ATTR_RO(in73_label, label, DA9052_ADC_TSI_YN);
341
342static SENSOR_DEVICE_ATTR_RO(curr1_input, da9052_ich, DA9052_ADC_ICH);
343static SENSOR_DEVICE_ATTR_RO(curr1_label, label, DA9052_ADC_ICH);
344
345static SENSOR_DEVICE_ATTR_RO(temp2_input, da9052_tbat, DA9052_ADC_TBAT);
346static SENSOR_DEVICE_ATTR_RO(temp2_label, label, DA9052_ADC_TBAT);
347static SENSOR_DEVICE_ATTR_RO(temp8_input, da9052_tjunc, DA9052_ADC_TJUNC);
348static SENSOR_DEVICE_ATTR_RO(temp8_label, label, DA9052_ADC_TJUNC);
349
350static struct attribute *da9052_attrs[] = {
351	&sensor_dev_attr_in0_input.dev_attr.attr,
352	&sensor_dev_attr_in0_label.dev_attr.attr,
353	&sensor_dev_attr_in3_input.dev_attr.attr,
354	&sensor_dev_attr_in3_label.dev_attr.attr,
355	&sensor_dev_attr_in4_input.dev_attr.attr,
356	&sensor_dev_attr_in4_label.dev_attr.attr,
357	&sensor_dev_attr_in5_input.dev_attr.attr,
358	&sensor_dev_attr_in5_label.dev_attr.attr,
359	&sensor_dev_attr_in6_input.dev_attr.attr,
360	&sensor_dev_attr_in6_label.dev_attr.attr,
361	&sensor_dev_attr_in70_input.dev_attr.attr,
362	&sensor_dev_attr_in70_label.dev_attr.attr,
363	&sensor_dev_attr_in71_input.dev_attr.attr,
364	&sensor_dev_attr_in71_label.dev_attr.attr,
365	&sensor_dev_attr_in72_input.dev_attr.attr,
366	&sensor_dev_attr_in72_label.dev_attr.attr,
367	&sensor_dev_attr_in73_input.dev_attr.attr,
368	&sensor_dev_attr_in73_label.dev_attr.attr,
369	&sensor_dev_attr_in9_input.dev_attr.attr,
370	&sensor_dev_attr_in9_label.dev_attr.attr,
371	&sensor_dev_attr_curr1_input.dev_attr.attr,
372	&sensor_dev_attr_curr1_label.dev_attr.attr,
373	&sensor_dev_attr_temp2_input.dev_attr.attr,
374	&sensor_dev_attr_temp2_label.dev_attr.attr,
375	&sensor_dev_attr_temp8_input.dev_attr.attr,
376	&sensor_dev_attr_temp8_label.dev_attr.attr,
377	NULL
378};
379
380static const struct attribute_group da9052_group = {
381	.attrs = da9052_attrs,
382	.is_visible = da9052_channel_is_visible,
383};
384__ATTRIBUTE_GROUPS(da9052);
385
386static irqreturn_t da9052_tsi_datardy_irq(int irq, void *data)
387{
388	struct da9052_hwmon *hwmon = data;
389
390	complete(&hwmon->tsidone);
391	return IRQ_HANDLED;
392}
393
394static int da9052_hwmon_probe(struct platform_device *pdev)
395{
396	struct device *dev = &pdev->dev;
397	struct da9052_hwmon *hwmon;
398	struct device *hwmon_dev;
399	int err, tsiref_uv;
400
401	hwmon = devm_kzalloc(dev, sizeof(struct da9052_hwmon), GFP_KERNEL);
402	if (!hwmon)
403		return -ENOMEM;
404
405	platform_set_drvdata(pdev, hwmon);
406
407	mutex_init(&hwmon->hwmon_lock);
408	hwmon->da9052 = dev_get_drvdata(pdev->dev.parent);
409
410	init_completion(&hwmon->tsidone);
411
412	hwmon->tsi_as_adc =
413		device_property_read_bool(pdev->dev.parent, "dlg,tsi-as-adc");
414
415	if (hwmon->tsi_as_adc) {
416		tsiref_uv = devm_regulator_get_enable_read_voltage(dev->parent,
417								   "tsiref");
418		if (tsiref_uv < 0)
419			return dev_err_probe(dev, tsiref_uv,
420					     "failed to get tsiref voltage\n");
421
422		/* convert from microvolt (DT) to millivolt (hwmon) */
423		hwmon->tsiref_mv = tsiref_uv / 1000;
424
425		/* TSIREF limits from datasheet */
426		if (hwmon->tsiref_mv < 1800 || hwmon->tsiref_mv > 2600) {
427			dev_err(hwmon->da9052->dev, "invalid TSIREF voltage: %d",
428				hwmon->tsiref_mv);
429			return -ENXIO;
430		}
431
432		/* disable touchscreen features */
433		da9052_reg_write(hwmon->da9052, DA9052_TSI_CONT_A_REG, 0x00);
434
435		/* Sample every 1ms */
436		da9052_reg_update(hwmon->da9052, DA9052_ADC_CONT_REG,
437					  DA9052_ADCCONT_ADCMODE,
438					  DA9052_ADCCONT_ADCMODE);
439
440		err = da9052_request_irq(hwmon->da9052, DA9052_IRQ_TSIREADY,
441					 "tsiready-irq", da9052_tsi_datardy_irq,
442					 hwmon);
443		if (err) {
444			dev_err(&pdev->dev, "Failed to register TSIRDY IRQ: %d",
445				err);
446			return err;
447		}
448	}
449
450	hwmon_dev = devm_hwmon_device_register_with_groups(dev, "da9052",
451							   hwmon,
452							   da9052_groups);
453	err = PTR_ERR_OR_ZERO(hwmon_dev);
454	if (err)
455		goto exit_irq;
456
457	return 0;
458
459exit_irq:
460	if (hwmon->tsi_as_adc)
461		da9052_free_irq(hwmon->da9052, DA9052_IRQ_TSIREADY, hwmon);
462
463	return err;
464}
465
466static void da9052_hwmon_remove(struct platform_device *pdev)
467{
468	struct da9052_hwmon *hwmon = platform_get_drvdata(pdev);
469
470	if (hwmon->tsi_as_adc)
471		da9052_free_irq(hwmon->da9052, DA9052_IRQ_TSIREADY, hwmon);
472}
473
474static struct platform_driver da9052_hwmon_driver = {
475	.probe = da9052_hwmon_probe,
476	.remove = da9052_hwmon_remove,
477	.driver = {
478		.name = "da9052-hwmon",
479	},
480};
481
482module_platform_driver(da9052_hwmon_driver);
483
484MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
485MODULE_DESCRIPTION("DA9052 HWMON driver");
486MODULE_LICENSE("GPL");
487MODULE_ALIAS("platform:da9052-hwmon");