764 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * ad525x_dpot: Driver for the Analog Devices digital potentiometers4 * Copyright (c) 2009-2010 Analog Devices, Inc.5 * Author: Michael Hennerich <michael.hennerich@analog.com>6 *7 * DEVID #Wipers #Positions Resistor Options (kOhm)8 * AD5258 1 64 1, 10, 50, 1009 * AD5259 1 256 5, 10, 50, 10010 * AD5251 2 64 1, 10, 50, 10011 * AD5252 2 256 1, 10, 50, 10012 * AD5255 3 512 25, 25013 * AD5253 4 64 1, 10, 50, 10014 * AD5254 4 256 1, 10, 50, 10015 * AD5160 1 256 5, 10, 50, 10016 * AD5161 1 256 5, 10, 50, 10017 * AD5162 2 256 2.5, 10, 50, 10018 * AD5165 1 256 10019 * AD5200 1 256 10, 5020 * AD5201 1 33 10, 5021 * AD5203 4 64 10, 10022 * AD5204 4 256 10, 50, 10023 * AD5206 6 256 10, 50, 10024 * AD5207 2 256 10, 50, 10025 * AD5231 1 1024 10, 50, 10026 * AD5232 2 256 10, 50, 10027 * AD5233 4 64 10, 50, 10028 * AD5235 2 1024 25, 25029 * AD5260 1 256 20, 50, 20030 * AD5262 2 256 20, 50, 20031 * AD5263 4 256 20, 50, 20032 * AD5290 1 256 10, 50, 10033 * AD5291 1 256 20, 50, 100 (20-TP)34 * AD5292 1 1024 20, 50, 100 (20-TP)35 * AD5293 1 1024 20, 50, 10036 * AD7376 1 128 10, 50, 100, 1M37 * AD8400 1 256 1, 10, 50, 10038 * AD8402 2 256 1, 10, 50, 10039 * AD8403 4 256 1, 10, 50, 10040 * ADN2850 3 512 25, 25041 * AD5241 1 256 10, 100, 1M42 * AD5246 1 128 5, 10, 50, 10043 * AD5247 1 128 5, 10, 50, 10044 * AD5245 1 256 5, 10, 50, 10045 * AD5243 2 256 2.5, 10, 50, 10046 * AD5248 2 256 2.5, 10, 50, 10047 * AD5242 2 256 20, 50, 20048 * AD5280 1 256 20, 50, 20049 * AD5282 2 256 20, 50, 20050 * ADN2860 3 512 25, 25051 * AD5273 1 64 1, 10, 50, 100 (OTP)52 * AD5171 1 64 5, 10, 50, 100 (OTP)53 * AD5170 1 256 2.5, 10, 50, 100 (OTP)54 * AD5172 2 256 2.5, 10, 50, 100 (OTP)55 * AD5173 2 256 2.5, 10, 50, 100 (OTP)56 * AD5270 1 1024 20, 50, 100 (50-TP)57 * AD5271 1 256 20, 50, 100 (50-TP)58 * AD5272 1 1024 20, 50, 100 (50-TP)59 * AD5274 1 256 20, 50, 100 (50-TP)60 *61 * See Documentation/misc-devices/ad525x_dpot.rst for more info.62 *63 * derived from ad5258.c64 * Copyright (c) 2009 Cyber Switching, Inc.65 * Author: Chris Verges <chrisv@cyberswitching.com>66 *67 * derived from ad5252.c68 * Copyright (c) 2006-2011 Michael Hennerich <michael.hennerich@analog.com>69 */70 71#include <linux/module.h>72#include <linux/device.h>73#include <linux/kernel.h>74#include <linux/delay.h>75#include <linux/slab.h>76 77#include "ad525x_dpot.h"78 79/*80 * Client data (each client gets its own)81 */82 83struct dpot_data {84 struct ad_dpot_bus_data bdata;85 struct mutex update_lock;86 unsigned int rdac_mask;87 unsigned int max_pos;88 unsigned long devid;89 unsigned int uid;90 unsigned int feat;91 unsigned int wipers;92 u16 rdac_cache[MAX_RDACS];93 DECLARE_BITMAP(otp_en_mask, MAX_RDACS);94};95 96static inline int dpot_read_d8(struct dpot_data *dpot)97{98 return dpot->bdata.bops->read_d8(dpot->bdata.client);99}100 101static inline int dpot_read_r8d8(struct dpot_data *dpot, u8 reg)102{103 return dpot->bdata.bops->read_r8d8(dpot->bdata.client, reg);104}105 106static inline int dpot_read_r8d16(struct dpot_data *dpot, u8 reg)107{108 return dpot->bdata.bops->read_r8d16(dpot->bdata.client, reg);109}110 111static inline int dpot_write_d8(struct dpot_data *dpot, u8 val)112{113 return dpot->bdata.bops->write_d8(dpot->bdata.client, val);114}115 116static inline int dpot_write_r8d8(struct dpot_data *dpot, u8 reg, u16 val)117{118 return dpot->bdata.bops->write_r8d8(dpot->bdata.client, reg, val);119}120 121static inline int dpot_write_r8d16(struct dpot_data *dpot, u8 reg, u16 val)122{123 return dpot->bdata.bops->write_r8d16(dpot->bdata.client, reg, val);124}125 126static s32 dpot_read_spi(struct dpot_data *dpot, u8 reg)127{128 unsigned int ctrl = 0;129 int value;130 131 if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) {132 133 if (dpot->feat & F_RDACS_WONLY)134 return dpot->rdac_cache[reg & DPOT_RDAC_MASK];135 if (dpot->uid == DPOT_UID(AD5291_ID) ||136 dpot->uid == DPOT_UID(AD5292_ID) ||137 dpot->uid == DPOT_UID(AD5293_ID)) {138 139 value = dpot_read_r8d8(dpot,140 DPOT_AD5291_READ_RDAC << 2);141 142 if (value < 0)143 return value;144 145 if (dpot->uid == DPOT_UID(AD5291_ID))146 value = value >> 2;147 148 return value;149 } else if (dpot->uid == DPOT_UID(AD5270_ID) ||150 dpot->uid == DPOT_UID(AD5271_ID)) {151 152 value = dpot_read_r8d8(dpot,153 DPOT_AD5270_1_2_4_READ_RDAC << 2);154 155 if (value < 0)156 return value;157 158 if (dpot->uid == DPOT_UID(AD5271_ID))159 value = value >> 2;160 161 return value;162 }163 164 ctrl = DPOT_SPI_READ_RDAC;165 } else if (reg & DPOT_ADDR_EEPROM) {166 ctrl = DPOT_SPI_READ_EEPROM;167 }168 169 if (dpot->feat & F_SPI_16BIT)170 return dpot_read_r8d8(dpot, ctrl);171 else if (dpot->feat & F_SPI_24BIT)172 return dpot_read_r8d16(dpot, ctrl);173 174 return -EFAULT;175}176 177static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg)178{179 int value;180 unsigned int ctrl = 0;181 182 switch (dpot->uid) {183 case DPOT_UID(AD5246_ID):184 case DPOT_UID(AD5247_ID):185 return dpot_read_d8(dpot);186 case DPOT_UID(AD5245_ID):187 case DPOT_UID(AD5241_ID):188 case DPOT_UID(AD5242_ID):189 case DPOT_UID(AD5243_ID):190 case DPOT_UID(AD5248_ID):191 case DPOT_UID(AD5280_ID):192 case DPOT_UID(AD5282_ID):193 ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?194 0 : DPOT_AD5282_RDAC_AB;195 return dpot_read_r8d8(dpot, ctrl);196 case DPOT_UID(AD5170_ID):197 case DPOT_UID(AD5171_ID):198 case DPOT_UID(AD5273_ID):199 return dpot_read_d8(dpot);200 case DPOT_UID(AD5172_ID):201 case DPOT_UID(AD5173_ID):202 ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?203 0 : DPOT_AD5172_3_A0;204 return dpot_read_r8d8(dpot, ctrl);205 case DPOT_UID(AD5272_ID):206 case DPOT_UID(AD5274_ID):207 dpot_write_r8d8(dpot,208 (DPOT_AD5270_1_2_4_READ_RDAC << 2), 0);209 210 value = dpot_read_r8d16(dpot, DPOT_AD5270_1_2_4_RDAC << 2);211 if (value < 0)212 return value;213 /*214 * AD5272/AD5274 returns high byte first, however215 * underling smbus expects low byte first.216 */217 value = swab16(value);218 219 if (dpot->uid == DPOT_UID(AD5274_ID))220 value = value >> 2;221 return value;222 default:223 if ((reg & DPOT_REG_TOL) || (dpot->max_pos > 256))224 return dpot_read_r8d16(dpot, (reg & 0xF8) |225 ((reg & 0x7) << 1));226 else227 return dpot_read_r8d8(dpot, reg);228 }229}230 231static s32 dpot_read(struct dpot_data *dpot, u8 reg)232{233 if (dpot->feat & F_SPI)234 return dpot_read_spi(dpot, reg);235 else236 return dpot_read_i2c(dpot, reg);237}238 239static s32 dpot_write_spi(struct dpot_data *dpot, u8 reg, u16 value)240{241 unsigned int val = 0;242 243 if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD | DPOT_ADDR_OTP))) {244 if (dpot->feat & F_RDACS_WONLY)245 dpot->rdac_cache[reg & DPOT_RDAC_MASK] = value;246 247 if (dpot->feat & F_AD_APPDATA) {248 if (dpot->feat & F_SPI_8BIT) {249 val = ((reg & DPOT_RDAC_MASK) <<250 DPOT_MAX_POS(dpot->devid)) |251 value;252 return dpot_write_d8(dpot, val);253 } else if (dpot->feat & F_SPI_16BIT) {254 val = ((reg & DPOT_RDAC_MASK) <<255 DPOT_MAX_POS(dpot->devid)) |256 value;257 return dpot_write_r8d8(dpot, val >> 8,258 val & 0xFF);259 } else260 BUG();261 } else {262 if (dpot->uid == DPOT_UID(AD5291_ID) ||263 dpot->uid == DPOT_UID(AD5292_ID) ||264 dpot->uid == DPOT_UID(AD5293_ID)) {265 266 dpot_write_r8d8(dpot, DPOT_AD5291_CTRLREG << 2,267 DPOT_AD5291_UNLOCK_CMD);268 269 if (dpot->uid == DPOT_UID(AD5291_ID))270 value = value << 2;271 272 return dpot_write_r8d8(dpot,273 (DPOT_AD5291_RDAC << 2) |274 (value >> 8), value & 0xFF);275 } else if (dpot->uid == DPOT_UID(AD5270_ID) ||276 dpot->uid == DPOT_UID(AD5271_ID)) {277 dpot_write_r8d8(dpot,278 DPOT_AD5270_1_2_4_CTRLREG << 2,279 DPOT_AD5270_1_2_4_UNLOCK_CMD);280 281 if (dpot->uid == DPOT_UID(AD5271_ID))282 value = value << 2;283 284 return dpot_write_r8d8(dpot,285 (DPOT_AD5270_1_2_4_RDAC << 2) |286 (value >> 8), value & 0xFF);287 }288 val = DPOT_SPI_RDAC | (reg & DPOT_RDAC_MASK);289 }290 } else if (reg & DPOT_ADDR_EEPROM) {291 val = DPOT_SPI_EEPROM | (reg & DPOT_RDAC_MASK);292 } else if (reg & DPOT_ADDR_CMD) {293 switch (reg) {294 case DPOT_DEC_ALL_6DB:295 val = DPOT_SPI_DEC_ALL_6DB;296 break;297 case DPOT_INC_ALL_6DB:298 val = DPOT_SPI_INC_ALL_6DB;299 break;300 case DPOT_DEC_ALL:301 val = DPOT_SPI_DEC_ALL;302 break;303 case DPOT_INC_ALL:304 val = DPOT_SPI_INC_ALL;305 break;306 }307 } else if (reg & DPOT_ADDR_OTP) {308 if (dpot->uid == DPOT_UID(AD5291_ID) ||309 dpot->uid == DPOT_UID(AD5292_ID)) {310 return dpot_write_r8d8(dpot,311 DPOT_AD5291_STORE_XTPM << 2, 0);312 } else if (dpot->uid == DPOT_UID(AD5270_ID) ||313 dpot->uid == DPOT_UID(AD5271_ID)) {314 return dpot_write_r8d8(dpot,315 DPOT_AD5270_1_2_4_STORE_XTPM << 2, 0);316 }317 } else318 BUG();319 320 if (dpot->feat & F_SPI_16BIT)321 return dpot_write_r8d8(dpot, val, value);322 else if (dpot->feat & F_SPI_24BIT)323 return dpot_write_r8d16(dpot, val, value);324 325 return -EFAULT;326}327 328static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)329{330 /* Only write the instruction byte for certain commands */331 unsigned int tmp = 0, ctrl = 0;332 333 switch (dpot->uid) {334 case DPOT_UID(AD5246_ID):335 case DPOT_UID(AD5247_ID):336 return dpot_write_d8(dpot, value);337 338 case DPOT_UID(AD5245_ID):339 case DPOT_UID(AD5241_ID):340 case DPOT_UID(AD5242_ID):341 case DPOT_UID(AD5243_ID):342 case DPOT_UID(AD5248_ID):343 case DPOT_UID(AD5280_ID):344 case DPOT_UID(AD5282_ID):345 ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?346 0 : DPOT_AD5282_RDAC_AB;347 return dpot_write_r8d8(dpot, ctrl, value);348 case DPOT_UID(AD5171_ID):349 case DPOT_UID(AD5273_ID):350 if (reg & DPOT_ADDR_OTP) {351 tmp = dpot_read_d8(dpot);352 if (tmp >> 6) /* Ready to Program? */353 return -EFAULT;354 ctrl = DPOT_AD5273_FUSE;355 }356 return dpot_write_r8d8(dpot, ctrl, value);357 case DPOT_UID(AD5172_ID):358 case DPOT_UID(AD5173_ID):359 ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?360 0 : DPOT_AD5172_3_A0;361 if (reg & DPOT_ADDR_OTP) {362 tmp = dpot_read_r8d16(dpot, ctrl);363 if (tmp >> 14) /* Ready to Program? */364 return -EFAULT;365 ctrl |= DPOT_AD5170_2_3_FUSE;366 }367 return dpot_write_r8d8(dpot, ctrl, value);368 case DPOT_UID(AD5170_ID):369 if (reg & DPOT_ADDR_OTP) {370 tmp = dpot_read_r8d16(dpot, tmp);371 if (tmp >> 14) /* Ready to Program? */372 return -EFAULT;373 ctrl = DPOT_AD5170_2_3_FUSE;374 }375 return dpot_write_r8d8(dpot, ctrl, value);376 case DPOT_UID(AD5272_ID):377 case DPOT_UID(AD5274_ID):378 dpot_write_r8d8(dpot, DPOT_AD5270_1_2_4_CTRLREG << 2,379 DPOT_AD5270_1_2_4_UNLOCK_CMD);380 381 if (reg & DPOT_ADDR_OTP)382 return dpot_write_r8d8(dpot,383 DPOT_AD5270_1_2_4_STORE_XTPM << 2, 0);384 385 if (dpot->uid == DPOT_UID(AD5274_ID))386 value = value << 2;387 388 return dpot_write_r8d8(dpot, (DPOT_AD5270_1_2_4_RDAC << 2) |389 (value >> 8), value & 0xFF);390 default:391 if (reg & DPOT_ADDR_CMD)392 return dpot_write_d8(dpot, reg);393 394 if (dpot->max_pos > 256)395 return dpot_write_r8d16(dpot, (reg & 0xF8) |396 ((reg & 0x7) << 1), value);397 else398 /* All other registers require instruction + data bytes */399 return dpot_write_r8d8(dpot, reg, value);400 }401}402 403static s32 dpot_write(struct dpot_data *dpot, u8 reg, u16 value)404{405 if (dpot->feat & F_SPI)406 return dpot_write_spi(dpot, reg, value);407 else408 return dpot_write_i2c(dpot, reg, value);409}410 411/* sysfs functions */412 413static ssize_t sysfs_show_reg(struct device *dev,414 struct device_attribute *attr,415 char *buf, u32 reg)416{417 struct dpot_data *data = dev_get_drvdata(dev);418 s32 value;419 420 if (reg & DPOT_ADDR_OTP_EN)421 return sprintf(buf, "%s\n",422 test_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask) ?423 "enabled" : "disabled");424 425 426 mutex_lock(&data->update_lock);427 value = dpot_read(data, reg);428 mutex_unlock(&data->update_lock);429 430 if (value < 0)431 return -EINVAL;432 /*433 * Let someone else deal with converting this ...434 * the tolerance is a two-byte value where the MSB435 * is a sign + integer value, and the LSB is a436 * decimal value. See page 18 of the AD5258437 * datasheet (Rev. A) for more details.438 */439 440 if (reg & DPOT_REG_TOL)441 return sprintf(buf, "0x%04x\n", value & 0xFFFF);442 else443 return sprintf(buf, "%u\n", value & data->rdac_mask);444}445 446static ssize_t sysfs_set_reg(struct device *dev,447 struct device_attribute *attr,448 const char *buf, size_t count, u32 reg)449{450 struct dpot_data *data = dev_get_drvdata(dev);451 unsigned long value;452 int err;453 454 if (reg & DPOT_ADDR_OTP_EN) {455 if (sysfs_streq(buf, "enabled"))456 set_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask);457 else458 clear_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask);459 460 return count;461 }462 463 if ((reg & DPOT_ADDR_OTP) &&464 !test_bit(DPOT_RDAC_MASK & reg, data->otp_en_mask))465 return -EPERM;466 467 err = kstrtoul(buf, 10, &value);468 if (err)469 return err;470 471 if (value > data->rdac_mask)472 value = data->rdac_mask;473 474 mutex_lock(&data->update_lock);475 dpot_write(data, reg, value);476 if (reg & DPOT_ADDR_EEPROM)477 msleep(26); /* Sleep while the EEPROM updates */478 else if (reg & DPOT_ADDR_OTP)479 msleep(400); /* Sleep while the OTP updates */480 mutex_unlock(&data->update_lock);481 482 return count;483}484 485static ssize_t sysfs_do_cmd(struct device *dev,486 struct device_attribute *attr,487 const char *buf, size_t count, u32 reg)488{489 struct dpot_data *data = dev_get_drvdata(dev);490 491 mutex_lock(&data->update_lock);492 dpot_write(data, reg, 0);493 mutex_unlock(&data->update_lock);494 495 return count;496}497 498/* ------------------------------------------------------------------------- */499 500#define DPOT_DEVICE_SHOW(_name, _reg) static ssize_t \501show_##_name(struct device *dev, \502 struct device_attribute *attr, char *buf) \503{ \504 return sysfs_show_reg(dev, attr, buf, _reg); \505}506 507#define DPOT_DEVICE_SET(_name, _reg) static ssize_t \508set_##_name(struct device *dev, \509 struct device_attribute *attr, \510 const char *buf, size_t count) \511{ \512 return sysfs_set_reg(dev, attr, buf, count, _reg); \513}514 515#define DPOT_DEVICE_SHOW_SET(name, reg) \516DPOT_DEVICE_SHOW(name, reg) \517DPOT_DEVICE_SET(name, reg) \518static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, set_##name)519 520#define DPOT_DEVICE_SHOW_ONLY(name, reg) \521DPOT_DEVICE_SHOW(name, reg) \522static DEVICE_ATTR(name, S_IWUSR | S_IRUGO, show_##name, NULL)523 524DPOT_DEVICE_SHOW_SET(rdac0, DPOT_ADDR_RDAC | DPOT_RDAC0);525DPOT_DEVICE_SHOW_SET(eeprom0, DPOT_ADDR_EEPROM | DPOT_RDAC0);526DPOT_DEVICE_SHOW_ONLY(tolerance0, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC0);527DPOT_DEVICE_SHOW_SET(otp0, DPOT_ADDR_OTP | DPOT_RDAC0);528DPOT_DEVICE_SHOW_SET(otp0en, DPOT_ADDR_OTP_EN | DPOT_RDAC0);529 530DPOT_DEVICE_SHOW_SET(rdac1, DPOT_ADDR_RDAC | DPOT_RDAC1);531DPOT_DEVICE_SHOW_SET(eeprom1, DPOT_ADDR_EEPROM | DPOT_RDAC1);532DPOT_DEVICE_SHOW_ONLY(tolerance1, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC1);533DPOT_DEVICE_SHOW_SET(otp1, DPOT_ADDR_OTP | DPOT_RDAC1);534DPOT_DEVICE_SHOW_SET(otp1en, DPOT_ADDR_OTP_EN | DPOT_RDAC1);535 536DPOT_DEVICE_SHOW_SET(rdac2, DPOT_ADDR_RDAC | DPOT_RDAC2);537DPOT_DEVICE_SHOW_SET(eeprom2, DPOT_ADDR_EEPROM | DPOT_RDAC2);538DPOT_DEVICE_SHOW_ONLY(tolerance2, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC2);539DPOT_DEVICE_SHOW_SET(otp2, DPOT_ADDR_OTP | DPOT_RDAC2);540DPOT_DEVICE_SHOW_SET(otp2en, DPOT_ADDR_OTP_EN | DPOT_RDAC2);541 542DPOT_DEVICE_SHOW_SET(rdac3, DPOT_ADDR_RDAC | DPOT_RDAC3);543DPOT_DEVICE_SHOW_SET(eeprom3, DPOT_ADDR_EEPROM | DPOT_RDAC3);544DPOT_DEVICE_SHOW_ONLY(tolerance3, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC3);545DPOT_DEVICE_SHOW_SET(otp3, DPOT_ADDR_OTP | DPOT_RDAC3);546DPOT_DEVICE_SHOW_SET(otp3en, DPOT_ADDR_OTP_EN | DPOT_RDAC3);547 548DPOT_DEVICE_SHOW_SET(rdac4, DPOT_ADDR_RDAC | DPOT_RDAC4);549DPOT_DEVICE_SHOW_SET(eeprom4, DPOT_ADDR_EEPROM | DPOT_RDAC4);550DPOT_DEVICE_SHOW_ONLY(tolerance4, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC4);551DPOT_DEVICE_SHOW_SET(otp4, DPOT_ADDR_OTP | DPOT_RDAC4);552DPOT_DEVICE_SHOW_SET(otp4en, DPOT_ADDR_OTP_EN | DPOT_RDAC4);553 554DPOT_DEVICE_SHOW_SET(rdac5, DPOT_ADDR_RDAC | DPOT_RDAC5);555DPOT_DEVICE_SHOW_SET(eeprom5, DPOT_ADDR_EEPROM | DPOT_RDAC5);556DPOT_DEVICE_SHOW_ONLY(tolerance5, DPOT_ADDR_EEPROM | DPOT_TOL_RDAC5);557DPOT_DEVICE_SHOW_SET(otp5, DPOT_ADDR_OTP | DPOT_RDAC5);558DPOT_DEVICE_SHOW_SET(otp5en, DPOT_ADDR_OTP_EN | DPOT_RDAC5);559 560static const struct attribute *dpot_attrib_wipers[] = {561 &dev_attr_rdac0.attr,562 &dev_attr_rdac1.attr,563 &dev_attr_rdac2.attr,564 &dev_attr_rdac3.attr,565 &dev_attr_rdac4.attr,566 &dev_attr_rdac5.attr,567 NULL568};569 570static const struct attribute *dpot_attrib_eeprom[] = {571 &dev_attr_eeprom0.attr,572 &dev_attr_eeprom1.attr,573 &dev_attr_eeprom2.attr,574 &dev_attr_eeprom3.attr,575 &dev_attr_eeprom4.attr,576 &dev_attr_eeprom5.attr,577 NULL578};579 580static const struct attribute *dpot_attrib_otp[] = {581 &dev_attr_otp0.attr,582 &dev_attr_otp1.attr,583 &dev_attr_otp2.attr,584 &dev_attr_otp3.attr,585 &dev_attr_otp4.attr,586 &dev_attr_otp5.attr,587 NULL588};589 590static const struct attribute *dpot_attrib_otp_en[] = {591 &dev_attr_otp0en.attr,592 &dev_attr_otp1en.attr,593 &dev_attr_otp2en.attr,594 &dev_attr_otp3en.attr,595 &dev_attr_otp4en.attr,596 &dev_attr_otp5en.attr,597 NULL598};599 600static const struct attribute *dpot_attrib_tolerance[] = {601 &dev_attr_tolerance0.attr,602 &dev_attr_tolerance1.attr,603 &dev_attr_tolerance2.attr,604 &dev_attr_tolerance3.attr,605 &dev_attr_tolerance4.attr,606 &dev_attr_tolerance5.attr,607 NULL608};609 610/* ------------------------------------------------------------------------- */611 612#define DPOT_DEVICE_DO_CMD(_name, _cmd) static ssize_t \613set_##_name(struct device *dev, \614 struct device_attribute *attr, \615 const char *buf, size_t count) \616{ \617 return sysfs_do_cmd(dev, attr, buf, count, _cmd); \618} \619static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, NULL, set_##_name)620 621DPOT_DEVICE_DO_CMD(inc_all, DPOT_INC_ALL);622DPOT_DEVICE_DO_CMD(dec_all, DPOT_DEC_ALL);623DPOT_DEVICE_DO_CMD(inc_all_6db, DPOT_INC_ALL_6DB);624DPOT_DEVICE_DO_CMD(dec_all_6db, DPOT_DEC_ALL_6DB);625 626static struct attribute *ad525x_attributes_commands[] = {627 &dev_attr_inc_all.attr,628 &dev_attr_dec_all.attr,629 &dev_attr_inc_all_6db.attr,630 &dev_attr_dec_all_6db.attr,631 NULL632};633 634static const struct attribute_group ad525x_group_commands = {635 .attrs = ad525x_attributes_commands,636};637 638static int ad_dpot_add_files(struct device *dev,639 unsigned int features, unsigned int rdac)640{641 int err = sysfs_create_file(&dev->kobj,642 dpot_attrib_wipers[rdac]);643 if (features & F_CMD_EEP)644 err |= sysfs_create_file(&dev->kobj,645 dpot_attrib_eeprom[rdac]);646 if (features & F_CMD_TOL)647 err |= sysfs_create_file(&dev->kobj,648 dpot_attrib_tolerance[rdac]);649 if (features & F_CMD_OTP) {650 err |= sysfs_create_file(&dev->kobj,651 dpot_attrib_otp_en[rdac]);652 err |= sysfs_create_file(&dev->kobj,653 dpot_attrib_otp[rdac]);654 }655 656 if (err)657 dev_err(dev, "failed to register sysfs hooks for RDAC%d\n",658 rdac);659 660 return err;661}662 663static inline void ad_dpot_remove_files(struct device *dev,664 unsigned int features, unsigned int rdac)665{666 sysfs_remove_file(&dev->kobj,667 dpot_attrib_wipers[rdac]);668 if (features & F_CMD_EEP)669 sysfs_remove_file(&dev->kobj,670 dpot_attrib_eeprom[rdac]);671 if (features & F_CMD_TOL)672 sysfs_remove_file(&dev->kobj,673 dpot_attrib_tolerance[rdac]);674 if (features & F_CMD_OTP) {675 sysfs_remove_file(&dev->kobj,676 dpot_attrib_otp_en[rdac]);677 sysfs_remove_file(&dev->kobj,678 dpot_attrib_otp[rdac]);679 }680}681 682int ad_dpot_probe(struct device *dev,683 struct ad_dpot_bus_data *bdata, unsigned long devid,684 const char *name)685{686 687 struct dpot_data *data;688 int i, err = 0;689 690 data = kzalloc(sizeof(struct dpot_data), GFP_KERNEL);691 if (!data) {692 err = -ENOMEM;693 goto exit;694 }695 696 dev_set_drvdata(dev, data);697 mutex_init(&data->update_lock);698 699 data->bdata = *bdata;700 data->devid = devid;701 702 data->max_pos = 1 << DPOT_MAX_POS(devid);703 data->rdac_mask = data->max_pos - 1;704 data->feat = DPOT_FEAT(devid);705 data->uid = DPOT_UID(devid);706 data->wipers = DPOT_WIPERS(devid);707 708 for (i = DPOT_RDAC0; i < MAX_RDACS; i++)709 if (data->wipers & (1 << i)) {710 err = ad_dpot_add_files(dev, data->feat, i);711 if (err)712 goto exit_remove_files;713 /* power-up midscale */714 if (data->feat & F_RDACS_WONLY)715 data->rdac_cache[i] = data->max_pos / 2;716 }717 718 if (data->feat & F_CMD_INC)719 err = sysfs_create_group(&dev->kobj, &ad525x_group_commands);720 721 if (err) {722 dev_err(dev, "failed to register sysfs hooks\n");723 goto exit_free;724 }725 726 dev_info(dev, "%s %d-Position Digital Potentiometer registered\n",727 name, data->max_pos);728 729 return 0;730 731exit_remove_files:732 for (i = DPOT_RDAC0; i < MAX_RDACS; i++)733 if (data->wipers & (1 << i))734 ad_dpot_remove_files(dev, data->feat, i);735 736exit_free:737 kfree(data);738 dev_set_drvdata(dev, NULL);739exit:740 dev_err(dev, "failed to create client for %s ID 0x%lX\n",741 name, devid);742 return err;743}744EXPORT_SYMBOL(ad_dpot_probe);745 746void ad_dpot_remove(struct device *dev)747{748 struct dpot_data *data = dev_get_drvdata(dev);749 int i;750 751 for (i = DPOT_RDAC0; i < MAX_RDACS; i++)752 if (data->wipers & (1 << i))753 ad_dpot_remove_files(dev, data->feat, i);754 755 kfree(data);756}757EXPORT_SYMBOL(ad_dpot_remove);758 759 760MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>, "761 "Michael Hennerich <michael.hennerich@analog.com>");762MODULE_DESCRIPTION("Digital potentiometer driver");763MODULE_LICENSE("GPL");764