xref: /linux/drivers/misc/ad525x_dpot.c (revision 85385a51)
180503b23SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
24eb174beSMichael Hennerich /*
36c536e4cSMichael Hennerich  * ad525x_dpot: Driver for the Analog Devices digital potentiometers
46c536e4cSMichael Hennerich  * Copyright (c) 2009-2010 Analog Devices, Inc.
5dbd71398SMichael Hennerich  * Author: Michael Hennerich <michael.hennerich@analog.com>
64eb174beSMichael Hennerich  *
74eb174beSMichael Hennerich  * DEVID		#Wipers		#Positions	Resistor Options (kOhm)
84eb174beSMichael Hennerich  * AD5258		1		64		1, 10, 50, 100
94eb174beSMichael Hennerich  * AD5259		1		256		5, 10, 50, 100
104eb174beSMichael Hennerich  * AD5251		2		64		1, 10, 50, 100
114eb174beSMichael Hennerich  * AD5252		2		256		1, 10, 50, 100
124eb174beSMichael Hennerich  * AD5255		3		512		25, 250
134eb174beSMichael Hennerich  * AD5253		4		64		1, 10, 50, 100
144eb174beSMichael Hennerich  * AD5254		4		256		1, 10, 50, 100
156c536e4cSMichael Hennerich  * AD5160		1		256		5, 10, 50, 100
166c536e4cSMichael Hennerich  * AD5161		1		256		5, 10, 50, 100
176c536e4cSMichael Hennerich  * AD5162		2		256		2.5, 10, 50, 100
186c536e4cSMichael Hennerich  * AD5165		1		256		100
196c536e4cSMichael Hennerich  * AD5200		1		256		10, 50
206c536e4cSMichael Hennerich  * AD5201		1		33		10, 50
216c536e4cSMichael Hennerich  * AD5203		4		64		10, 100
226c536e4cSMichael Hennerich  * AD5204		4		256		10, 50, 100
236c536e4cSMichael Hennerich  * AD5206		6		256		10, 50, 100
246c536e4cSMichael Hennerich  * AD5207		2		256		10, 50, 100
256c536e4cSMichael Hennerich  * AD5231		1		1024		10, 50, 100
266c536e4cSMichael Hennerich  * AD5232		2		256		10, 50, 100
276c536e4cSMichael Hennerich  * AD5233		4		64		10, 50, 100
286c536e4cSMichael Hennerich  * AD5235		2		1024		25, 250
296c536e4cSMichael Hennerich  * AD5260		1		256		20, 50, 200
306c536e4cSMichael Hennerich  * AD5262		2		256		20, 50, 200
316c536e4cSMichael Hennerich  * AD5263		4		256		20, 50, 200
326c536e4cSMichael Hennerich  * AD5290		1		256		10, 50, 100
33a4bd3949SMichael Hennerich  * AD5291		1		256		20, 50, 100  (20-TP)
34a4bd3949SMichael Hennerich  * AD5292		1		1024		20, 50, 100  (20-TP)
35a4bd3949SMichael Hennerich  * AD5293		1		1024		20, 50, 100
366c536e4cSMichael Hennerich  * AD7376		1		128		10, 50, 100, 1M
376c536e4cSMichael Hennerich  * AD8400		1		256		1, 10, 50, 100
386c536e4cSMichael Hennerich  * AD8402		2		256		1, 10, 50, 100
396c536e4cSMichael Hennerich  * AD8403		4		256		1, 10, 50, 100
406c536e4cSMichael Hennerich  * ADN2850		3		512		25, 250
41e3ae6847SMichael Hennerich  * AD5241		1		256		10, 100, 1M
42e3ae6847SMichael Hennerich  * AD5246		1		128		5, 10, 50, 100
43e3ae6847SMichael Hennerich  * AD5247		1		128		5, 10, 50, 100
44e3ae6847SMichael Hennerich  * AD5245		1		256		5, 10, 50, 100
45e3ae6847SMichael Hennerich  * AD5243		2		256		2.5, 10, 50, 100
46e3ae6847SMichael Hennerich  * AD5248		2		256		2.5, 10, 50, 100
47e3ae6847SMichael Hennerich  * AD5242		2		256		20, 50, 200
48c74cba61SMichael Hennerich  * AD5280		1		256		20, 50, 200
49c74cba61SMichael Hennerich  * AD5282		2		256		20, 50, 200
50c74cba61SMichael Hennerich  * ADN2860		3		512		25, 250
5159592d0cSMichael Hennerich  * AD5273		1		64		1, 10, 50, 100 (OTP)
5259592d0cSMichael Hennerich  * AD5171		1		64		5, 10, 50, 100 (OTP)
5359592d0cSMichael Hennerich  * AD5170		1		256		2.5, 10, 50, 100 (OTP)
5459592d0cSMichael Hennerich  * AD5172		2		256		2.5, 10, 50, 100 (OTP)
5559592d0cSMichael Hennerich  * AD5173		2		256		2.5, 10, 50, 100 (OTP)
56a4bd3949SMichael Hennerich  * AD5270		1		1024		20, 50, 100 (50-TP)
57a4bd3949SMichael Hennerich  * AD5271		1		256		20, 50, 100 (50-TP)
58a4bd3949SMichael Hennerich  * AD5272		1		1024		20, 50, 100 (50-TP)
59a4bd3949SMichael Hennerich  * AD5274		1		256		20, 50, 100 (50-TP)
604eb174beSMichael Hennerich  *
618a05eb89SMauro Carvalho Chehab  * See Documentation/misc-devices/ad525x_dpot.rst for more info.
624eb174beSMichael Hennerich  *
634eb174beSMichael Hennerich  * derived from ad5258.c
644eb174beSMichael Hennerich  * Copyright (c) 2009 Cyber Switching, Inc.
654eb174beSMichael Hennerich  * Author: Chris Verges <chrisv@cyberswitching.com>
664eb174beSMichael Hennerich  *
674eb174beSMichael Hennerich  * derived from ad5252.c
68dbd71398SMichael Hennerich  * Copyright (c) 2006-2011 Michael Hennerich <michael.hennerich@analog.com>
694eb174beSMichael Hennerich  */
704eb174beSMichael Hennerich 
714eb174beSMichael Hennerich #include <linux/module.h>
724eb174beSMichael Hennerich #include <linux/device.h>
734eb174beSMichael Hennerich #include <linux/kernel.h>
744eb174beSMichael Hennerich #include <linux/delay.h>
756c536e4cSMichael Hennerich #include <linux/slab.h>
764eb174beSMichael Hennerich 
776c536e4cSMichael Hennerich #include "ad525x_dpot.h"
784eb174beSMichael Hennerich 
794eb174beSMichael Hennerich /*
804eb174beSMichael Hennerich  * Client data (each client gets its own)
814eb174beSMichael Hennerich  */
824eb174beSMichael Hennerich 
834eb174beSMichael Hennerich struct dpot_data {
846c536e4cSMichael Hennerich 	struct ad_dpot_bus_data	bdata;
854eb174beSMichael Hennerich 	struct mutex update_lock;
86d06d101bSDhaval Shah 	unsigned int rdac_mask;
87d06d101bSDhaval Shah 	unsigned int max_pos;
886c536e4cSMichael Hennerich 	unsigned long devid;
89d06d101bSDhaval Shah 	unsigned int uid;
90d06d101bSDhaval Shah 	unsigned int feat;
91d06d101bSDhaval Shah 	unsigned int wipers;
9259592d0cSMichael Hennerich 	u16 rdac_cache[MAX_RDACS];
9359592d0cSMichael Hennerich 	DECLARE_BITMAP(otp_en_mask, MAX_RDACS);
944eb174beSMichael Hennerich };
954eb174beSMichael Hennerich 
dpot_read_d8(struct dpot_data * dpot)966c536e4cSMichael Hennerich static inline int dpot_read_d8(struct dpot_data *dpot)
976c536e4cSMichael Hennerich {
986c536e4cSMichael Hennerich 	return dpot->bdata.bops->read_d8(dpot->bdata.client);
996c536e4cSMichael Hennerich }
1006c536e4cSMichael Hennerich 
dpot_read_r8d8(struct dpot_data * dpot,u8 reg)1016c536e4cSMichael Hennerich static inline int dpot_read_r8d8(struct dpot_data *dpot, u8 reg)
1026c536e4cSMichael Hennerich {
1036c536e4cSMichael Hennerich 	return dpot->bdata.bops->read_r8d8(dpot->bdata.client, reg);
1046c536e4cSMichael Hennerich }
1056c536e4cSMichael Hennerich 
dpot_read_r8d16(struct dpot_data * dpot,u8 reg)1066c536e4cSMichael Hennerich static inline int dpot_read_r8d16(struct dpot_data *dpot, u8 reg)
1076c536e4cSMichael Hennerich {
1086c536e4cSMichael Hennerich 	return dpot->bdata.bops->read_r8d16(dpot->bdata.client, reg);
1096c536e4cSMichael Hennerich }
1106c536e4cSMichael Hennerich 
dpot_write_d8(struct dpot_data * dpot,u8 val)1116c536e4cSMichael Hennerich static inline int dpot_write_d8(struct dpot_data *dpot, u8 val)
1126c536e4cSMichael Hennerich {
1136c536e4cSMichael Hennerich 	return dpot->bdata.bops->write_d8(dpot->bdata.client, val);
1146c536e4cSMichael Hennerich }
1156c536e4cSMichael Hennerich 
dpot_write_r8d8(struct dpot_data * dpot,u8 reg,u16 val)1166c536e4cSMichael Hennerich static inline int dpot_write_r8d8(struct dpot_data *dpot, u8 reg, u16 val)
1176c536e4cSMichael Hennerich {
1186c536e4cSMichael Hennerich 	return dpot->bdata.bops->write_r8d8(dpot->bdata.client, reg, val);
1196c536e4cSMichael Hennerich }
1206c536e4cSMichael Hennerich 
dpot_write_r8d16(struct dpot_data * dpot,u8 reg,u16 val)1216c536e4cSMichael Hennerich static inline int dpot_write_r8d16(struct dpot_data *dpot, u8 reg, u16 val)
1226c536e4cSMichael Hennerich {
1236c536e4cSMichael Hennerich 	return dpot->bdata.bops->write_r8d16(dpot->bdata.client, reg, val);
1246c536e4cSMichael Hennerich }
1256c536e4cSMichael Hennerich 
dpot_read_spi(struct dpot_data * dpot,u8 reg)126e3ae6847SMichael Hennerich static s32 dpot_read_spi(struct dpot_data *dpot, u8 reg)
1276c536e4cSMichael Hennerich {
128d06d101bSDhaval Shah 	unsigned int ctrl = 0;
129a4bd3949SMichael Hennerich 	int value;
1306c536e4cSMichael Hennerich 
1316c536e4cSMichael Hennerich 	if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) {
1326c536e4cSMichael Hennerich 
1336c536e4cSMichael Hennerich 		if (dpot->feat & F_RDACS_WONLY)
1346c536e4cSMichael Hennerich 			return dpot->rdac_cache[reg & DPOT_RDAC_MASK];
1356c536e4cSMichael Hennerich 		if (dpot->uid == DPOT_UID(AD5291_ID) ||
1366c536e4cSMichael Hennerich 			dpot->uid == DPOT_UID(AD5292_ID) ||
137a4bd3949SMichael Hennerich 			dpot->uid == DPOT_UID(AD5293_ID)) {
138a4bd3949SMichael Hennerich 
139a4bd3949SMichael Hennerich 			value = dpot_read_r8d8(dpot,
1406c536e4cSMichael Hennerich 				DPOT_AD5291_READ_RDAC << 2);
1416c536e4cSMichael Hennerich 
142f8096ff3SDinghao Liu 			if (value < 0)
143f8096ff3SDinghao Liu 				return value;
144f8096ff3SDinghao Liu 
145a4bd3949SMichael Hennerich 			if (dpot->uid == DPOT_UID(AD5291_ID))
146a4bd3949SMichael Hennerich 				value = value >> 2;
147a4bd3949SMichael Hennerich 
148a4bd3949SMichael Hennerich 			return value;
149a4bd3949SMichael Hennerich 		} else if (dpot->uid == DPOT_UID(AD5270_ID) ||
150a4bd3949SMichael Hennerich 			dpot->uid == DPOT_UID(AD5271_ID)) {
151a4bd3949SMichael Hennerich 
152a4bd3949SMichael Hennerich 			value = dpot_read_r8d8(dpot,
153a4bd3949SMichael Hennerich 				DPOT_AD5270_1_2_4_READ_RDAC << 2);
154a4bd3949SMichael Hennerich 
155a4bd3949SMichael Hennerich 			if (value < 0)
156a4bd3949SMichael Hennerich 				return value;
157a4bd3949SMichael Hennerich 
158a4bd3949SMichael Hennerich 			if (dpot->uid == DPOT_UID(AD5271_ID))
159a4bd3949SMichael Hennerich 				value = value >> 2;
160a4bd3949SMichael Hennerich 
161a4bd3949SMichael Hennerich 			return value;
162a4bd3949SMichael Hennerich 		}
163a4bd3949SMichael Hennerich 
164e3ae6847SMichael Hennerich 		ctrl = DPOT_SPI_READ_RDAC;
1656c536e4cSMichael Hennerich 	} else if (reg & DPOT_ADDR_EEPROM) {
166e3ae6847SMichael Hennerich 		ctrl = DPOT_SPI_READ_EEPROM;
1676c536e4cSMichael Hennerich 	}
1686c536e4cSMichael Hennerich 
1696c536e4cSMichael Hennerich 	if (dpot->feat & F_SPI_16BIT)
170e3ae6847SMichael Hennerich 		return dpot_read_r8d8(dpot, ctrl);
1716c536e4cSMichael Hennerich 	else if (dpot->feat & F_SPI_24BIT)
172e3ae6847SMichael Hennerich 		return dpot_read_r8d16(dpot, ctrl);
1736c536e4cSMichael Hennerich 
174e3ae6847SMichael Hennerich 	return -EFAULT;
175e3ae6847SMichael Hennerich }
1766c536e4cSMichael Hennerich 
dpot_read_i2c(struct dpot_data * dpot,u8 reg)177e3ae6847SMichael Hennerich static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg)
178e3ae6847SMichael Hennerich {
179a4bd3949SMichael Hennerich 	int value;
180d06d101bSDhaval Shah 	unsigned int ctrl = 0;
18115584555SMohammad Jamal 
182e3ae6847SMichael Hennerich 	switch (dpot->uid) {
183e3ae6847SMichael Hennerich 	case DPOT_UID(AD5246_ID):
184e3ae6847SMichael Hennerich 	case DPOT_UID(AD5247_ID):
185e3ae6847SMichael Hennerich 		return dpot_read_d8(dpot);
186e3ae6847SMichael Hennerich 	case DPOT_UID(AD5245_ID):
187e3ae6847SMichael Hennerich 	case DPOT_UID(AD5241_ID):
188e3ae6847SMichael Hennerich 	case DPOT_UID(AD5242_ID):
189e3ae6847SMichael Hennerich 	case DPOT_UID(AD5243_ID):
190e3ae6847SMichael Hennerich 	case DPOT_UID(AD5248_ID):
191c74cba61SMichael Hennerich 	case DPOT_UID(AD5280_ID):
192c74cba61SMichael Hennerich 	case DPOT_UID(AD5282_ID):
193e3ae6847SMichael Hennerich 		ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
1945f400cf4SMichael Hennerich 			0 : DPOT_AD5282_RDAC_AB;
195e3ae6847SMichael Hennerich 		return dpot_read_r8d8(dpot, ctrl);
19659592d0cSMichael Hennerich 	case DPOT_UID(AD5170_ID):
19759592d0cSMichael Hennerich 	case DPOT_UID(AD5171_ID):
19859592d0cSMichael Hennerich 	case DPOT_UID(AD5273_ID):
19959592d0cSMichael Hennerich 			return dpot_read_d8(dpot);
20059592d0cSMichael Hennerich 	case DPOT_UID(AD5172_ID):
20159592d0cSMichael Hennerich 	case DPOT_UID(AD5173_ID):
20259592d0cSMichael Hennerich 		ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
2035f400cf4SMichael Hennerich 			0 : DPOT_AD5172_3_A0;
20459592d0cSMichael Hennerich 		return dpot_read_r8d8(dpot, ctrl);
205a4bd3949SMichael Hennerich 	case DPOT_UID(AD5272_ID):
206a4bd3949SMichael Hennerich 	case DPOT_UID(AD5274_ID):
207a4bd3949SMichael Hennerich 		dpot_write_r8d8(dpot,
208a4bd3949SMichael Hennerich 				(DPOT_AD5270_1_2_4_READ_RDAC << 2), 0);
209a4bd3949SMichael Hennerich 
210068ad41eSColin Ian King 		value = dpot_read_r8d16(dpot, DPOT_AD5270_1_2_4_RDAC << 2);
211a4bd3949SMichael Hennerich 		if (value < 0)
212a4bd3949SMichael Hennerich 			return value;
213a4bd3949SMichael Hennerich 		/*
214a4bd3949SMichael Hennerich 		 * AD5272/AD5274 returns high byte first, however
215a4bd3949SMichael Hennerich 		 * underling smbus expects low byte first.
216a4bd3949SMichael Hennerich 		 */
217a4bd3949SMichael Hennerich 		value = swab16(value);
218a4bd3949SMichael Hennerich 
219f3df53e4SMichael Hennerich 		if (dpot->uid == DPOT_UID(AD5274_ID))
220a4bd3949SMichael Hennerich 			value = value >> 2;
221a4bd3949SMichael Hennerich 		return value;
222e3ae6847SMichael Hennerich 	default:
2236c536e4cSMichael Hennerich 		if ((reg & DPOT_REG_TOL) || (dpot->max_pos > 256))
2246c536e4cSMichael Hennerich 			return dpot_read_r8d16(dpot, (reg & 0xF8) |
2256c536e4cSMichael Hennerich 					((reg & 0x7) << 1));
2266c536e4cSMichael Hennerich 		else
2276c536e4cSMichael Hennerich 			return dpot_read_r8d8(dpot, reg);
2286c536e4cSMichael Hennerich 	}
2296c536e4cSMichael Hennerich }
2306c536e4cSMichael Hennerich 
dpot_read(struct dpot_data * dpot,u8 reg)231e3ae6847SMichael Hennerich static s32 dpot_read(struct dpot_data *dpot, u8 reg)
232e3ae6847SMichael Hennerich {
233e3ae6847SMichael Hennerich 	if (dpot->feat & F_SPI)
234e3ae6847SMichael Hennerich 		return dpot_read_spi(dpot, reg);
235e3ae6847SMichael Hennerich 	else
236e3ae6847SMichael Hennerich 		return dpot_read_i2c(dpot, reg);
237e3ae6847SMichael Hennerich }
238e3ae6847SMichael Hennerich 
dpot_write_spi(struct dpot_data * dpot,u8 reg,u16 value)239e3ae6847SMichael Hennerich static s32 dpot_write_spi(struct dpot_data *dpot, u8 reg, u16 value)
2406c536e4cSMichael Hennerich {
241d06d101bSDhaval Shah 	unsigned int val = 0;
2426c536e4cSMichael Hennerich 
243a4bd3949SMichael Hennerich 	if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD | DPOT_ADDR_OTP))) {
2446c536e4cSMichael Hennerich 		if (dpot->feat & F_RDACS_WONLY)
2456c536e4cSMichael Hennerich 			dpot->rdac_cache[reg & DPOT_RDAC_MASK] = value;
2466c536e4cSMichael Hennerich 
2476c536e4cSMichael Hennerich 		if (dpot->feat & F_AD_APPDATA) {
2486c536e4cSMichael Hennerich 			if (dpot->feat & F_SPI_8BIT) {
2496c536e4cSMichael Hennerich 				val = ((reg & DPOT_RDAC_MASK) <<
2506c536e4cSMichael Hennerich 					DPOT_MAX_POS(dpot->devid)) |
2516c536e4cSMichael Hennerich 					value;
2526c536e4cSMichael Hennerich 				return dpot_write_d8(dpot, val);
2536c536e4cSMichael Hennerich 			} else if (dpot->feat & F_SPI_16BIT) {
2546c536e4cSMichael Hennerich 				val = ((reg & DPOT_RDAC_MASK) <<
2556c536e4cSMichael Hennerich 					DPOT_MAX_POS(dpot->devid)) |
2566c536e4cSMichael Hennerich 					value;
2576c536e4cSMichael Hennerich 				return dpot_write_r8d8(dpot, val >> 8,
2586c536e4cSMichael Hennerich 					val & 0xFF);
2596c536e4cSMichael Hennerich 			} else
2606c536e4cSMichael Hennerich 				BUG();
2616c536e4cSMichael Hennerich 		} else {
2626c536e4cSMichael Hennerich 			if (dpot->uid == DPOT_UID(AD5291_ID) ||
2636c536e4cSMichael Hennerich 				dpot->uid == DPOT_UID(AD5292_ID) ||
264a4bd3949SMichael Hennerich 				dpot->uid == DPOT_UID(AD5293_ID)) {
265a4bd3949SMichael Hennerich 
266a4bd3949SMichael Hennerich 				dpot_write_r8d8(dpot, DPOT_AD5291_CTRLREG << 2,
267a4bd3949SMichael Hennerich 						DPOT_AD5291_UNLOCK_CMD);
268a4bd3949SMichael Hennerich 
269a4bd3949SMichael Hennerich 				if (dpot->uid == DPOT_UID(AD5291_ID))
270a4bd3949SMichael Hennerich 					value = value << 2;
271a4bd3949SMichael Hennerich 
2726c536e4cSMichael Hennerich 				return dpot_write_r8d8(dpot,
2736c536e4cSMichael Hennerich 					(DPOT_AD5291_RDAC << 2) |
2746c536e4cSMichael Hennerich 					(value >> 8), value & 0xFF);
275a4bd3949SMichael Hennerich 			} else if (dpot->uid == DPOT_UID(AD5270_ID) ||
276a4bd3949SMichael Hennerich 				dpot->uid == DPOT_UID(AD5271_ID)) {
277a4bd3949SMichael Hennerich 				dpot_write_r8d8(dpot,
278a4bd3949SMichael Hennerich 						DPOT_AD5270_1_2_4_CTRLREG << 2,
279a4bd3949SMichael Hennerich 						DPOT_AD5270_1_2_4_UNLOCK_CMD);
2806c536e4cSMichael Hennerich 
281a4bd3949SMichael Hennerich 				if (dpot->uid == DPOT_UID(AD5271_ID))
282a4bd3949SMichael Hennerich 					value = value << 2;
283a4bd3949SMichael Hennerich 
284a4bd3949SMichael Hennerich 				return dpot_write_r8d8(dpot,
285a4bd3949SMichael Hennerich 					(DPOT_AD5270_1_2_4_RDAC << 2) |
286a4bd3949SMichael Hennerich 					(value >> 8), value & 0xFF);
287a4bd3949SMichael Hennerich 			}
2886c536e4cSMichael Hennerich 			val = DPOT_SPI_RDAC | (reg & DPOT_RDAC_MASK);
2896c536e4cSMichael Hennerich 		}
2906c536e4cSMichael Hennerich 	} else if (reg & DPOT_ADDR_EEPROM) {
2916c536e4cSMichael Hennerich 		val = DPOT_SPI_EEPROM | (reg & DPOT_RDAC_MASK);
2926c536e4cSMichael Hennerich 	} else if (reg & DPOT_ADDR_CMD) {
2936c536e4cSMichael Hennerich 		switch (reg) {
2946c536e4cSMichael Hennerich 		case DPOT_DEC_ALL_6DB:
2956c536e4cSMichael Hennerich 			val = DPOT_SPI_DEC_ALL_6DB;
2966c536e4cSMichael Hennerich 			break;
2976c536e4cSMichael Hennerich 		case DPOT_INC_ALL_6DB:
2986c536e4cSMichael Hennerich 			val = DPOT_SPI_INC_ALL_6DB;
2996c536e4cSMichael Hennerich 			break;
3006c536e4cSMichael Hennerich 		case DPOT_DEC_ALL:
3016c536e4cSMichael Hennerich 			val = DPOT_SPI_DEC_ALL;
3026c536e4cSMichael Hennerich 			break;
3036c536e4cSMichael Hennerich 		case DPOT_INC_ALL:
3046c536e4cSMichael Hennerich 			val = DPOT_SPI_INC_ALL;
3056c536e4cSMichael Hennerich 			break;
3066c536e4cSMichael Hennerich 		}
307a4bd3949SMichael Hennerich 	} else if (reg & DPOT_ADDR_OTP) {
308a4bd3949SMichael Hennerich 		if (dpot->uid == DPOT_UID(AD5291_ID) ||
309a4bd3949SMichael Hennerich 			dpot->uid == DPOT_UID(AD5292_ID)) {
310a4bd3949SMichael Hennerich 			return dpot_write_r8d8(dpot,
311a4bd3949SMichael Hennerich 				DPOT_AD5291_STORE_XTPM << 2, 0);
312a4bd3949SMichael Hennerich 		} else if (dpot->uid == DPOT_UID(AD5270_ID) ||
313a4bd3949SMichael Hennerich 			dpot->uid == DPOT_UID(AD5271_ID)) {
314a4bd3949SMichael Hennerich 			return dpot_write_r8d8(dpot,
315a4bd3949SMichael Hennerich 				DPOT_AD5270_1_2_4_STORE_XTPM << 2, 0);
316a4bd3949SMichael Hennerich 		}
3176c536e4cSMichael Hennerich 	} else
3186c536e4cSMichael Hennerich 		BUG();
3196c536e4cSMichael Hennerich 
3206c536e4cSMichael Hennerich 	if (dpot->feat & F_SPI_16BIT)
3216c536e4cSMichael Hennerich 		return dpot_write_r8d8(dpot, val, value);
3226c536e4cSMichael Hennerich 	else if (dpot->feat & F_SPI_24BIT)
3236c536e4cSMichael Hennerich 		return dpot_write_r8d16(dpot, val, value);
324e3ae6847SMichael Hennerich 
325e3ae6847SMichael Hennerich 	return -EFAULT;
326e3ae6847SMichael Hennerich }
327e3ae6847SMichael Hennerich 
dpot_write_i2c(struct dpot_data * dpot,u8 reg,u16 value)328e3ae6847SMichael Hennerich static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
329e3ae6847SMichael Hennerich {
3306c536e4cSMichael Hennerich 	/* Only write the instruction byte for certain commands */
331d06d101bSDhaval Shah 	unsigned int tmp = 0, ctrl = 0;
332e3ae6847SMichael Hennerich 
333e3ae6847SMichael Hennerich 	switch (dpot->uid) {
334e3ae6847SMichael Hennerich 	case DPOT_UID(AD5246_ID):
335e3ae6847SMichael Hennerich 	case DPOT_UID(AD5247_ID):
336e3ae6847SMichael Hennerich 		return dpot_write_d8(dpot, value);
337e3ae6847SMichael Hennerich 
338e3ae6847SMichael Hennerich 	case DPOT_UID(AD5245_ID):
339e3ae6847SMichael Hennerich 	case DPOT_UID(AD5241_ID):
340e3ae6847SMichael Hennerich 	case DPOT_UID(AD5242_ID):
341e3ae6847SMichael Hennerich 	case DPOT_UID(AD5243_ID):
342e3ae6847SMichael Hennerich 	case DPOT_UID(AD5248_ID):
343c74cba61SMichael Hennerich 	case DPOT_UID(AD5280_ID):
344c74cba61SMichael Hennerich 	case DPOT_UID(AD5282_ID):
345c74cba61SMichael Hennerich 		ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
3465f400cf4SMichael Hennerich 			0 : DPOT_AD5282_RDAC_AB;
347e3ae6847SMichael Hennerich 		return dpot_write_r8d8(dpot, ctrl, value);
34859592d0cSMichael Hennerich 	case DPOT_UID(AD5171_ID):
34959592d0cSMichael Hennerich 	case DPOT_UID(AD5273_ID):
35059592d0cSMichael Hennerich 		if (reg & DPOT_ADDR_OTP) {
35159592d0cSMichael Hennerich 			tmp = dpot_read_d8(dpot);
35259592d0cSMichael Hennerich 			if (tmp >> 6) /* Ready to Program? */
35359592d0cSMichael Hennerich 				return -EFAULT;
35459592d0cSMichael Hennerich 			ctrl = DPOT_AD5273_FUSE;
35559592d0cSMichael Hennerich 		}
35659592d0cSMichael Hennerich 		return dpot_write_r8d8(dpot, ctrl, value);
35759592d0cSMichael Hennerich 	case DPOT_UID(AD5172_ID):
35859592d0cSMichael Hennerich 	case DPOT_UID(AD5173_ID):
35959592d0cSMichael Hennerich 		ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
3605f400cf4SMichael Hennerich 			0 : DPOT_AD5172_3_A0;
36159592d0cSMichael Hennerich 		if (reg & DPOT_ADDR_OTP) {
36259592d0cSMichael Hennerich 			tmp = dpot_read_r8d16(dpot, ctrl);
36359592d0cSMichael Hennerich 			if (tmp >> 14) /* Ready to Program? */
36459592d0cSMichael Hennerich 				return -EFAULT;
3655f400cf4SMichael Hennerich 			ctrl |= DPOT_AD5170_2_3_FUSE;
36659592d0cSMichael Hennerich 		}
36759592d0cSMichael Hennerich 		return dpot_write_r8d8(dpot, ctrl, value);
36859592d0cSMichael Hennerich 	case DPOT_UID(AD5170_ID):
36959592d0cSMichael Hennerich 		if (reg & DPOT_ADDR_OTP) {
37059592d0cSMichael Hennerich 			tmp = dpot_read_r8d16(dpot, tmp);
37159592d0cSMichael Hennerich 			if (tmp >> 14) /* Ready to Program? */
37259592d0cSMichael Hennerich 				return -EFAULT;
373a4bd3949SMichael Hennerich 			ctrl = DPOT_AD5170_2_3_FUSE;
37459592d0cSMichael Hennerich 		}
37559592d0cSMichael Hennerich 		return dpot_write_r8d8(dpot, ctrl, value);
376a4bd3949SMichael Hennerich 	case DPOT_UID(AD5272_ID):
377a4bd3949SMichael Hennerich 	case DPOT_UID(AD5274_ID):
378a4bd3949SMichael Hennerich 		dpot_write_r8d8(dpot, DPOT_AD5270_1_2_4_CTRLREG << 2,
379a4bd3949SMichael Hennerich 				DPOT_AD5270_1_2_4_UNLOCK_CMD);
380a4bd3949SMichael Hennerich 
381a4bd3949SMichael Hennerich 		if (reg & DPOT_ADDR_OTP)
382a4bd3949SMichael Hennerich 			return dpot_write_r8d8(dpot,
383a4bd3949SMichael Hennerich 					DPOT_AD5270_1_2_4_STORE_XTPM << 2, 0);
384a4bd3949SMichael Hennerich 
385a4bd3949SMichael Hennerich 		if (dpot->uid == DPOT_UID(AD5274_ID))
386a4bd3949SMichael Hennerich 			value = value << 2;
387a4bd3949SMichael Hennerich 
388a4bd3949SMichael Hennerich 		return dpot_write_r8d8(dpot, (DPOT_AD5270_1_2_4_RDAC << 2) |
389a4bd3949SMichael Hennerich 				       (value >> 8), value & 0xFF);
390e3ae6847SMichael Hennerich 	default:
3916c536e4cSMichael Hennerich 		if (reg & DPOT_ADDR_CMD)
3926c536e4cSMichael Hennerich 			return dpot_write_d8(dpot, reg);
3936c536e4cSMichael Hennerich 
3946c536e4cSMichael Hennerich 		if (dpot->max_pos > 256)
3956c536e4cSMichael Hennerich 			return dpot_write_r8d16(dpot, (reg & 0xF8) |
3966c536e4cSMichael Hennerich 						((reg & 0x7) << 1), value);
3976c536e4cSMichael Hennerich 		else
3986c536e4cSMichael Hennerich 			/* All other registers require instruction + data bytes */
3996c536e4cSMichael Hennerich 			return dpot_write_r8d8(dpot, reg, value);
400e3ae6847SMichael Hennerich 	}
4016c536e4cSMichael Hennerich }
4026c536e4cSMichael Hennerich 
dpot_write(struct dpot_data * dpot,u8 reg,u16 value)403e3ae6847SMichael Hennerich static s32 dpot_write(struct dpot_data *dpot, u8 reg, u16 value)
404e3ae6847SMichael Hennerich {
405e3ae6847SMichael Hennerich 	if (dpot->feat & F_SPI)
406e3ae6847SMichael Hennerich 		return dpot_write_spi(dpot, reg, value);
407e3ae6847SMichael Hennerich 	else
408e3ae6847SMichael Hennerich 		return dpot_write_i2c(dpot, reg, value);
4096c536e4cSMichael Hennerich }
4106c536e4cSMichael Hennerich 
4114eb174beSMichael Hennerich /* sysfs functions */
4124eb174beSMichael Hennerich 
sysfs_show_reg(struct device * dev,struct device_attribute * attr,char * buf,u32 reg)4134eb174beSMichael Hennerich static ssize_t sysfs_show_reg(struct device *dev,
4146c536e4cSMichael Hennerich 			      struct device_attribute *attr,
4156c536e4cSMichael Hennerich 			      char *buf, u32 reg)
4164eb174beSMichael Hennerich {
4176c536e4cSMichael Hennerich 	struct dpot_data *data = dev_get_drvdata(dev);
4184eb174beSMichael Hennerich 	s32 value;
4194eb174beSMichael Hennerich 
42059592d0cSMichael Hennerich 	if (reg & DPOT_ADDR_OTP_EN)
42159592d0cSMichael Hennerich 		return sprintf(buf, "%s\n",
42259592d0cSMichael Hennerich 			test_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask) ?
42359592d0cSMichael Hennerich 			"enabled" : "disabled");
42459592d0cSMichael Hennerich 
42559592d0cSMichael Hennerich 
4264eb174beSMichael Hennerich 	mutex_lock(&data->update_lock);
4276c536e4cSMichael Hennerich 	value = dpot_read(data, reg);
4284eb174beSMichael Hennerich 	mutex_unlock(&data->update_lock);
4294eb174beSMichael Hennerich 
4304eb174beSMichael Hennerich 	if (value < 0)
4314eb174beSMichael Hennerich 		return -EINVAL;
4324eb174beSMichael Hennerich 	/*
4334eb174beSMichael Hennerich 	 * Let someone else deal with converting this ...
4344eb174beSMichael Hennerich 	 * the tolerance is a two-byte value where the MSB
4354eb174beSMichael Hennerich 	 * is a sign + integer value, and the LSB is a
4364eb174beSMichael Hennerich 	 * decimal value.  See page 18 of the AD5258
4374eb174beSMichael Hennerich 	 * datasheet (Rev. A) for more details.
4384eb174beSMichael Hennerich 	 */
4394eb174beSMichael Hennerich 
4406c536e4cSMichael Hennerich 	if (reg & DPOT_REG_TOL)
4414eb174beSMichael Hennerich 		return sprintf(buf, "0x%04x\n", value & 0xFFFF);
4424eb174beSMichael Hennerich 	else
4434eb174beSMichael Hennerich 		return sprintf(buf, "%u\n", value & data->rdac_mask);
4444eb174beSMichael Hennerich }
4454eb174beSMichael Hennerich 
sysfs_set_reg(struct device * dev,struct device_attribute * attr,const char * buf,size_t count,u32 reg)4464eb174beSMichael Hennerich static ssize_t sysfs_set_reg(struct device *dev,
4474eb174beSMichael Hennerich 			     struct device_attribute *attr,
4484eb174beSMichael Hennerich 			     const char *buf, size_t count, u32 reg)
4494eb174beSMichael Hennerich {
4506c536e4cSMichael Hennerich 	struct dpot_data *data = dev_get_drvdata(dev);
4514eb174beSMichael Hennerich 	unsigned long value;
4524eb174beSMichael Hennerich 	int err;
4534eb174beSMichael Hennerich 
45459592d0cSMichael Hennerich 	if (reg & DPOT_ADDR_OTP_EN) {
4551bb850a1SDan Bogdan Nechita 		if (sysfs_streq(buf, "enabled"))
45659592d0cSMichael Hennerich 			set_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask);
45759592d0cSMichael Hennerich 		else
45859592d0cSMichael Hennerich 			clear_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask);
45959592d0cSMichael Hennerich 
46059592d0cSMichael Hennerich 		return count;
46159592d0cSMichael Hennerich 	}
46259592d0cSMichael Hennerich 
46359592d0cSMichael Hennerich 	if ((reg & DPOT_ADDR_OTP) &&
46459592d0cSMichael Hennerich 		!test_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask))
46559592d0cSMichael Hennerich 		return -EPERM;
46659592d0cSMichael Hennerich 
467f7b41276SJingoo Han 	err = kstrtoul(buf, 10, &value);
4684eb174beSMichael Hennerich 	if (err)
4694eb174beSMichael Hennerich 		return err;
4704eb174beSMichael Hennerich 
4714eb174beSMichael Hennerich 	if (value > data->rdac_mask)
4724eb174beSMichael Hennerich 		value = data->rdac_mask;
4734eb174beSMichael Hennerich 
4744eb174beSMichael Hennerich 	mutex_lock(&data->update_lock);
4756c536e4cSMichael Hennerich 	dpot_write(data, reg, value);
4766c536e4cSMichael Hennerich 	if (reg & DPOT_ADDR_EEPROM)
4774eb174beSMichael Hennerich 		msleep(26);	/* Sleep while the EEPROM updates */
47859592d0cSMichael Hennerich 	else if (reg & DPOT_ADDR_OTP)
47959592d0cSMichael Hennerich 		msleep(400);	/* Sleep while the OTP updates */
4804eb174beSMichael Hennerich 	mutex_unlock(&data->update_lock);
4814eb174beSMichael Hennerich 
4824eb174beSMichael Hennerich 	return count;
4834eb174beSMichael Hennerich }
4844eb174beSMichael Hennerich 
sysfs_do_cmd(struct device * dev,struct device_attribute * attr,const char * buf,size_t count,u32 reg)4854eb174beSMichael Hennerich static ssize_t sysfs_do_cmd(struct device *dev,
4864eb174beSMichael Hennerich 			    struct device_attribute *attr,
4874eb174beSMichael Hennerich 			    const char *buf, size_t count, u32 reg)
4884eb174beSMichael Hennerich {
4896c536e4cSMichael Hennerich 	struct dpot_data *data = dev_get_drvdata(dev);
4904eb174beSMichael Hennerich 
4914eb174beSMichael Hennerich 	mutex_lock(&data->update_lock);
4926c536e4cSMichael Hennerich 	dpot_write(data, reg, 0);
4934eb174beSMichael Hennerich 	mutex_unlock(&data->update_lock);
4944eb174beSMichael Hennerich 
4954eb174beSMichael Hennerich 	return count;
4964eb174beSMichael Hennerich }
4974eb174beSMichael Hennerich 
4984eb174beSMichael Hennerich /* ------------------------------------------------------------------------- */
4994eb174beSMichael Hennerich 
5000993dbedSMichael Hennerich #define DPOT_DEVICE_SHOW(_name, _reg) static ssize_t \
5010993dbedSMichael Hennerich show_##_name(struct device *dev, \
5020993dbedSMichael Hennerich 			  struct device_attribute *attr, char *buf) \
5030993dbedSMichael Hennerich { \
5040993dbedSMichael Hennerich 	return sysfs_show_reg(dev, attr, buf, _reg); \
5054eb174beSMichael Hennerich }
5064eb174beSMichael Hennerich 
5070993dbedSMichael Hennerich #define DPOT_DEVICE_SET(_name, _reg) static ssize_t \
5080993dbedSMichael Hennerich set_##_name(struct device *dev, \
5090993dbedSMichael Hennerich 			 struct device_attribute *attr, \
5100993dbedSMichael Hennerich 			 const char *buf, size_t count) \
5110993dbedSMichael Hennerich { \
5120993dbedSMichael Hennerich 	return sysfs_set_reg(dev, attr, buf, count, _reg); \
5134eb174beSMichael Hennerich }
5144eb174beSMichael Hennerich 
5150993dbedSMichael Hennerich #define DPOT_DEVICE_SHOW_SET(name, reg) \
5160993dbedSMichael Hennerich DPOT_DEVICE_SHOW(name, reg) \
5170993dbedSMichael Hennerich DPOT_DEVICE_SET(name, reg) \
51812eaa7a1SDhaval Shah static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, set_##name)
5194eb174beSMichael Hennerich 
5200993dbedSMichael Hennerich #define DPOT_DEVICE_SHOW_ONLY(name, reg) \
5210993dbedSMichael Hennerich DPOT_DEVICE_SHOW(name, reg) \
52212eaa7a1SDhaval Shah static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, NULL)
5234eb174beSMichael Hennerich 
5246c536e4cSMichael Hennerich DPOT_DEVICE_SHOW_SET(rdac0, DPOT_ADDR_RDAC | DPOT_RDAC0);
5256c536e4cSMichael Hennerich DPOT_DEVICE_SHOW_SET(eeprom0, DPOT_ADDR_EEPROM | DPOT_RDAC0);
5266c536e4cSMichael Hennerich DPOT_DEVICE_SHOW_ONLY(tolerance0, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC0);
52759592d0cSMichael Hennerich DPOT_DEVICE_SHOW_SET(otp0, DPOT_ADDR_OTP | DPOT_RDAC0);
52859592d0cSMichael Hennerich DPOT_DEVICE_SHOW_SET(otp0en, DPOT_ADDR_OTP_EN | DPOT_RDAC0);
5294eb174beSMichael Hennerich 
5306c536e4cSMichael Hennerich DPOT_DEVICE_SHOW_SET(rdac1, DPOT_ADDR_RDAC | DPOT_RDAC1);
5316c536e4cSMichael Hennerich DPOT_DEVICE_SHOW_SET(eeprom1, DPOT_ADDR_EEPROM | DPOT_RDAC1);
5326c536e4cSMichael Hennerich DPOT_DEVICE_SHOW_ONLY(tolerance1, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC1);
53359592d0cSMichael Hennerich DPOT_DEVICE_SHOW_SET(otp1, DPOT_ADDR_OTP | DPOT_RDAC1);
53459592d0cSMichael Hennerich DPOT_DEVICE_SHOW_SET(otp1en, DPOT_ADDR_OTP_EN | DPOT_RDAC1);
5354eb174beSMichael Hennerich 
5366c536e4cSMichael Hennerich DPOT_DEVICE_SHOW_SET(rdac2, DPOT_ADDR_RDAC | DPOT_RDAC2);
5376c536e4cSMichael Hennerich DPOT_DEVICE_SHOW_SET(eeprom2, DPOT_ADDR_EEPROM | DPOT_RDAC2);
5386c536e4cSMichael Hennerich DPOT_DEVICE_SHOW_ONLY(tolerance2, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC2);
53959592d0cSMichael Hennerich DPOT_DEVICE_SHOW_SET(otp2, DPOT_ADDR_OTP | DPOT_RDAC2);
54059592d0cSMichael Hennerich DPOT_DEVICE_SHOW_SET(otp2en, DPOT_ADDR_OTP_EN | DPOT_RDAC2);
5414eb174beSMichael Hennerich 
5426c536e4cSMichael Hennerich DPOT_DEVICE_SHOW_SET(rdac3, DPOT_ADDR_RDAC | DPOT_RDAC3);
5436c536e4cSMichael Hennerich DPOT_DEVICE_SHOW_SET(eeprom3, DPOT_ADDR_EEPROM | DPOT_RDAC3);
5446c536e4cSMichael Hennerich DPOT_DEVICE_SHOW_ONLY(tolerance3, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC3);
54559592d0cSMichael Hennerich DPOT_DEVICE_SHOW_SET(otp3, DPOT_ADDR_OTP | DPOT_RDAC3);
54659592d0cSMichael Hennerich DPOT_DEVICE_SHOW_SET(otp3en, DPOT_ADDR_OTP_EN | DPOT_RDAC3);
5474eb174beSMichael Hennerich 
5486c536e4cSMichael Hennerich DPOT_DEVICE_SHOW_SET(rdac4, DPOT_ADDR_RDAC | DPOT_RDAC4);
5496c536e4cSMichael Hennerich DPOT_DEVICE_SHOW_SET(eeprom4, DPOT_ADDR_EEPROM | DPOT_RDAC4);
5506c536e4cSMichael Hennerich DPOT_DEVICE_SHOW_ONLY(tolerance4, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC4);
55159592d0cSMichael Hennerich DPOT_DEVICE_SHOW_SET(otp4, DPOT_ADDR_OTP | DPOT_RDAC4);
55259592d0cSMichael Hennerich DPOT_DEVICE_SHOW_SET(otp4en, DPOT_ADDR_OTP_EN | DPOT_RDAC4);
5536c536e4cSMichael Hennerich 
5546c536e4cSMichael Hennerich DPOT_DEVICE_SHOW_SET(rdac5, DPOT_ADDR_RDAC | DPOT_RDAC5);
5556c536e4cSMichael Hennerich DPOT_DEVICE_SHOW_SET(eeprom5, DPOT_ADDR_EEPROM | DPOT_RDAC5);
5566c536e4cSMichael Hennerich DPOT_DEVICE_SHOW_ONLY(tolerance5, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC5);
55759592d0cSMichael Hennerich DPOT_DEVICE_SHOW_SET(otp5, DPOT_ADDR_OTP | DPOT_RDAC5);
55859592d0cSMichael Hennerich DPOT_DEVICE_SHOW_SET(otp5en, DPOT_ADDR_OTP_EN | DPOT_RDAC5);
5596c536e4cSMichael Hennerich 
5606c536e4cSMichael Hennerich static const struct attribute *dpot_attrib_wipers[] = {
5614eb174beSMichael Hennerich 	&dev_attr_rdac0.attr,
5624eb174beSMichael Hennerich 	&dev_attr_rdac1.attr,
5634eb174beSMichael Hennerich 	&dev_attr_rdac2.attr,
5644eb174beSMichael Hennerich 	&dev_attr_rdac3.attr,
5656c536e4cSMichael Hennerich 	&dev_attr_rdac4.attr,
5666c536e4cSMichael Hennerich 	&dev_attr_rdac5.attr,
5674eb174beSMichael Hennerich 	NULL
5684eb174beSMichael Hennerich };
5694eb174beSMichael Hennerich 
5706c536e4cSMichael Hennerich static const struct attribute *dpot_attrib_eeprom[] = {
5716c536e4cSMichael Hennerich 	&dev_attr_eeprom0.attr,
5726c536e4cSMichael Hennerich 	&dev_attr_eeprom1.attr,
5736c536e4cSMichael Hennerich 	&dev_attr_eeprom2.attr,
5746c536e4cSMichael Hennerich 	&dev_attr_eeprom3.attr,
5756c536e4cSMichael Hennerich 	&dev_attr_eeprom4.attr,
5766c536e4cSMichael Hennerich 	&dev_attr_eeprom5.attr,
5776c536e4cSMichael Hennerich 	NULL
5786c536e4cSMichael Hennerich };
5796c536e4cSMichael Hennerich 
58059592d0cSMichael Hennerich static const struct attribute *dpot_attrib_otp[] = {
58159592d0cSMichael Hennerich 	&dev_attr_otp0.attr,
58259592d0cSMichael Hennerich 	&dev_attr_otp1.attr,
58359592d0cSMichael Hennerich 	&dev_attr_otp2.attr,
58459592d0cSMichael Hennerich 	&dev_attr_otp3.attr,
58559592d0cSMichael Hennerich 	&dev_attr_otp4.attr,
58659592d0cSMichael Hennerich 	&dev_attr_otp5.attr,
58759592d0cSMichael Hennerich 	NULL
58859592d0cSMichael Hennerich };
58959592d0cSMichael Hennerich 
59059592d0cSMichael Hennerich static const struct attribute *dpot_attrib_otp_en[] = {
59159592d0cSMichael Hennerich 	&dev_attr_otp0en.attr,
59259592d0cSMichael Hennerich 	&dev_attr_otp1en.attr,
59359592d0cSMichael Hennerich 	&dev_attr_otp2en.attr,
59459592d0cSMichael Hennerich 	&dev_attr_otp3en.attr,
59559592d0cSMichael Hennerich 	&dev_attr_otp4en.attr,
59659592d0cSMichael Hennerich 	&dev_attr_otp5en.attr,
59759592d0cSMichael Hennerich 	NULL
59859592d0cSMichael Hennerich };
59959592d0cSMichael Hennerich 
6006c536e4cSMichael Hennerich static const struct attribute *dpot_attrib_tolerance[] = {
6016c536e4cSMichael Hennerich 	&dev_attr_tolerance0.attr,
6026c536e4cSMichael Hennerich 	&dev_attr_tolerance1.attr,
6036c536e4cSMichael Hennerich 	&dev_attr_tolerance2.attr,
6046c536e4cSMichael Hennerich 	&dev_attr_tolerance3.attr,
6056c536e4cSMichael Hennerich 	&dev_attr_tolerance4.attr,
6066c536e4cSMichael Hennerich 	&dev_attr_tolerance5.attr,
6076c536e4cSMichael Hennerich 	NULL
6084eb174beSMichael Hennerich };
6094eb174beSMichael Hennerich 
6104eb174beSMichael Hennerich /* ------------------------------------------------------------------------- */
6114eb174beSMichael Hennerich 
6120993dbedSMichael Hennerich #define DPOT_DEVICE_DO_CMD(_name, _cmd) static ssize_t \
6130993dbedSMichael Hennerich set_##_name(struct device *dev, \
6140993dbedSMichael Hennerich 			 struct device_attribute *attr, \
6150993dbedSMichael Hennerich 			 const char *buf, size_t count) \
6160993dbedSMichael Hennerich { \
6170993dbedSMichael Hennerich 	return sysfs_do_cmd(dev, attr, buf, count, _cmd); \
6180993dbedSMichael Hennerich } \
61912eaa7a1SDhaval Shah static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, NULL, set_##_name)
6204eb174beSMichael Hennerich 
6216c536e4cSMichael Hennerich DPOT_DEVICE_DO_CMD(inc_all, DPOT_INC_ALL);
6226c536e4cSMichael Hennerich DPOT_DEVICE_DO_CMD(dec_all, DPOT_DEC_ALL);
6236c536e4cSMichael Hennerich DPOT_DEVICE_DO_CMD(inc_all_6db, DPOT_INC_ALL_6DB);
6246c536e4cSMichael Hennerich DPOT_DEVICE_DO_CMD(dec_all_6db, DPOT_DEC_ALL_6DB);
6254eb174beSMichael Hennerich 
6264eb174beSMichael Hennerich static struct attribute *ad525x_attributes_commands[] = {
6274eb174beSMichael Hennerich 	&dev_attr_inc_all.attr,
6284eb174beSMichael Hennerich 	&dev_attr_dec_all.attr,
6294eb174beSMichael Hennerich 	&dev_attr_inc_all_6db.attr,
6304eb174beSMichael Hennerich 	&dev_attr_dec_all_6db.attr,
6314eb174beSMichael Hennerich 	NULL
6324eb174beSMichael Hennerich };
6334eb174beSMichael Hennerich 
6344eb174beSMichael Hennerich static const struct attribute_group ad525x_group_commands = {
6354eb174beSMichael Hennerich 	.attrs = ad525x_attributes_commands,
6364eb174beSMichael Hennerich };
6374eb174beSMichael Hennerich 
ad_dpot_add_files(struct device * dev,unsigned int features,unsigned int rdac)6381bdd2c45SRashika Kheria static int ad_dpot_add_files(struct device *dev,
639d06d101bSDhaval Shah 		unsigned int features, unsigned int rdac)
6404eb174beSMichael Hennerich {
6416c536e4cSMichael Hennerich 	int err = sysfs_create_file(&dev->kobj,
6426c536e4cSMichael Hennerich 		dpot_attrib_wipers[rdac]);
6436c536e4cSMichael Hennerich 	if (features & F_CMD_EEP)
6446c536e4cSMichael Hennerich 		err |= sysfs_create_file(&dev->kobj,
6456c536e4cSMichael Hennerich 			dpot_attrib_eeprom[rdac]);
6466c536e4cSMichael Hennerich 	if (features & F_CMD_TOL)
6476c536e4cSMichael Hennerich 		err |= sysfs_create_file(&dev->kobj,
6486c536e4cSMichael Hennerich 			dpot_attrib_tolerance[rdac]);
64959592d0cSMichael Hennerich 	if (features & F_CMD_OTP) {
65059592d0cSMichael Hennerich 		err |= sysfs_create_file(&dev->kobj,
65159592d0cSMichael Hennerich 			dpot_attrib_otp_en[rdac]);
65259592d0cSMichael Hennerich 		err |= sysfs_create_file(&dev->kobj,
65359592d0cSMichael Hennerich 			dpot_attrib_otp[rdac]);
65459592d0cSMichael Hennerich 	}
6554eb174beSMichael Hennerich 
6566c536e4cSMichael Hennerich 	if (err)
6576c536e4cSMichael Hennerich 		dev_err(dev, "failed to register sysfs hooks for RDAC%d\n",
6586c536e4cSMichael Hennerich 			rdac);
6596c536e4cSMichael Hennerich 
6606c536e4cSMichael Hennerich 	return err;
6614eb174beSMichael Hennerich }
6624eb174beSMichael Hennerich 
ad_dpot_remove_files(struct device * dev,unsigned int features,unsigned int rdac)6631bdd2c45SRashika Kheria static inline void ad_dpot_remove_files(struct device *dev,
664d06d101bSDhaval Shah 		unsigned int features, unsigned int rdac)
6654eb174beSMichael Hennerich {
6666c536e4cSMichael Hennerich 	sysfs_remove_file(&dev->kobj,
6676c536e4cSMichael Hennerich 		dpot_attrib_wipers[rdac]);
6686c536e4cSMichael Hennerich 	if (features & F_CMD_EEP)
6696c536e4cSMichael Hennerich 		sysfs_remove_file(&dev->kobj,
6706c536e4cSMichael Hennerich 			dpot_attrib_eeprom[rdac]);
6716c536e4cSMichael Hennerich 	if (features & F_CMD_TOL)
6726c536e4cSMichael Hennerich 		sysfs_remove_file(&dev->kobj,
6736c536e4cSMichael Hennerich 			dpot_attrib_tolerance[rdac]);
67459592d0cSMichael Hennerich 	if (features & F_CMD_OTP) {
67559592d0cSMichael Hennerich 		sysfs_remove_file(&dev->kobj,
67659592d0cSMichael Hennerich 			dpot_attrib_otp_en[rdac]);
67759592d0cSMichael Hennerich 		sysfs_remove_file(&dev->kobj,
67859592d0cSMichael Hennerich 			dpot_attrib_otp[rdac]);
67959592d0cSMichael Hennerich 	}
6804eb174beSMichael Hennerich }
6814eb174beSMichael Hennerich 
ad_dpot_probe(struct device * dev,struct ad_dpot_bus_data * bdata,unsigned long devid,const char * name)68280c8ae28SBill Pemberton int ad_dpot_probe(struct device *dev,
6837f3379deSMichael Hennerich 		struct ad_dpot_bus_data *bdata, unsigned long devid,
6847f3379deSMichael Hennerich 			    const char *name)
6854eb174beSMichael Hennerich {
6866c536e4cSMichael Hennerich 
6874eb174beSMichael Hennerich 	struct dpot_data *data;
6886c536e4cSMichael Hennerich 	int i, err = 0;
6894eb174beSMichael Hennerich 
6904eb174beSMichael Hennerich 	data = kzalloc(sizeof(struct dpot_data), GFP_KERNEL);
6914eb174beSMichael Hennerich 	if (!data) {
6924eb174beSMichael Hennerich 		err = -ENOMEM;
6934eb174beSMichael Hennerich 		goto exit;
6944eb174beSMichael Hennerich 	}
6954eb174beSMichael Hennerich 
6966c536e4cSMichael Hennerich 	dev_set_drvdata(dev, data);
6974eb174beSMichael Hennerich 	mutex_init(&data->update_lock);
6984eb174beSMichael Hennerich 
6996c536e4cSMichael Hennerich 	data->bdata = *bdata;
7007f3379deSMichael Hennerich 	data->devid = devid;
7016c536e4cSMichael Hennerich 
7027f3379deSMichael Hennerich 	data->max_pos = 1 << DPOT_MAX_POS(devid);
7036c536e4cSMichael Hennerich 	data->rdac_mask = data->max_pos - 1;
7047f3379deSMichael Hennerich 	data->feat = DPOT_FEAT(devid);
7057f3379deSMichael Hennerich 	data->uid = DPOT_UID(devid);
7067f3379deSMichael Hennerich 	data->wipers = DPOT_WIPERS(devid);
7076c536e4cSMichael Hennerich 
70859592d0cSMichael Hennerich 	for (i = DPOT_RDAC0; i < MAX_RDACS; i++)
7096c536e4cSMichael Hennerich 		if (data->wipers & (1 << i)) {
7106c536e4cSMichael Hennerich 			err = ad_dpot_add_files(dev, data->feat, i);
7116c536e4cSMichael Hennerich 			if (err)
7126c536e4cSMichael Hennerich 				goto exit_remove_files;
7136c536e4cSMichael Hennerich 			/* power-up midscale */
7146c536e4cSMichael Hennerich 			if (data->feat & F_RDACS_WONLY)
7156c536e4cSMichael Hennerich 				data->rdac_cache[i] = data->max_pos / 2;
7164eb174beSMichael Hennerich 		}
7174eb174beSMichael Hennerich 
7186c536e4cSMichael Hennerich 	if (data->feat & F_CMD_INC)
7196c536e4cSMichael Hennerich 		err = sysfs_create_group(&dev->kobj, &ad525x_group_commands);
7206c536e4cSMichael Hennerich 
7214eb174beSMichael Hennerich 	if (err) {
7224eb174beSMichael Hennerich 		dev_err(dev, "failed to register sysfs hooks\n");
7234eb174beSMichael Hennerich 		goto exit_free;
7244eb174beSMichael Hennerich 	}
7254eb174beSMichael Hennerich 
7264eb174beSMichael Hennerich 	dev_info(dev, "%s %d-Position Digital Potentiometer registered\n",
7277f3379deSMichael Hennerich 		 name, data->max_pos);
7284eb174beSMichael Hennerich 
7294eb174beSMichael Hennerich 	return 0;
7304eb174beSMichael Hennerich 
7316c536e4cSMichael Hennerich exit_remove_files:
73259592d0cSMichael Hennerich 	for (i = DPOT_RDAC0; i < MAX_RDACS; i++)
7336c536e4cSMichael Hennerich 		if (data->wipers & (1 << i))
7346c536e4cSMichael Hennerich 			ad_dpot_remove_files(dev, data->feat, i);
7356c536e4cSMichael Hennerich 
7364eb174beSMichael Hennerich exit_free:
7374eb174beSMichael Hennerich 	kfree(data);
7386c536e4cSMichael Hennerich 	dev_set_drvdata(dev, NULL);
7394eb174beSMichael Hennerich exit:
7406c536e4cSMichael Hennerich 	dev_err(dev, "failed to create client for %s ID 0x%lX\n",
7417f3379deSMichael Hennerich 		name, devid);
7424eb174beSMichael Hennerich 	return err;
7434eb174beSMichael Hennerich }
7446c536e4cSMichael Hennerich EXPORT_SYMBOL(ad_dpot_probe);
7454eb174beSMichael Hennerich 
ad_dpot_remove(struct device * dev)746*85385a51SUwe Kleine-König void ad_dpot_remove(struct device *dev)
7474eb174beSMichael Hennerich {
7486c536e4cSMichael Hennerich 	struct dpot_data *data = dev_get_drvdata(dev);
7496c536e4cSMichael Hennerich 	int i;
7504eb174beSMichael Hennerich 
75159592d0cSMichael Hennerich 	for (i = DPOT_RDAC0; i < MAX_RDACS; i++)
7526c536e4cSMichael Hennerich 		if (data->wipers & (1 << i))
7536c536e4cSMichael Hennerich 			ad_dpot_remove_files(dev, data->feat, i);
7544eb174beSMichael Hennerich 
7554eb174beSMichael Hennerich 	kfree(data);
7564eb174beSMichael Hennerich }
7576c536e4cSMichael Hennerich EXPORT_SYMBOL(ad_dpot_remove);
7584eb174beSMichael Hennerich 
7594eb174beSMichael Hennerich 
7604eb174beSMichael Hennerich MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>, "
761dbd71398SMichael Hennerich 	      "Michael Hennerich <michael.hennerich@analog.com>");
7626c536e4cSMichael Hennerich MODULE_DESCRIPTION("Digital potentiometer driver");
7634eb174beSMichael Hennerich MODULE_LICENSE("GPL");
764