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