Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a4bd3949 authored by Michael Hennerich's avatar Michael Hennerich Committed by Linus Torvalds
Browse files

drivers/misc/ad525x_dpot.c: new features



Add support for AD5270, AD5271, AD5272, AD5274 digital potentiometers.
Add 20-TP feature for AD5291 and AD5292 parts, and update feature list.
AD5291 rdac read back must be shifted by two.

Signed-off-by: default avatarMichael Hennerich <michael.hennerich@analog.com>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: Chris Verges <chrisv@cyberswitching.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 5f400cf4
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -24,7 +24,8 @@ config AD525X_DPOT
	  AD5260, AD5262, AD5263, AD5290, AD5291, AD5292, AD5293,
	  AD7376, AD8400, AD8402, AD8403, ADN2850, AD5241, AD5242,
	  AD5243, AD5245, AD5246, AD5247, AD5248, AD5280, AD5282,
	  ADN2860, AD5273, AD5171, AD5170, AD5172, AD5173
	  ADN2860, AD5273, AD5171, AD5170, AD5172, AD5173, AD5270,
	  AD5271, AD5272, AD5274
	  digital potentiometer chips.

	  See Documentation/misc-devices/ad525x_dpot.txt for the
+2 −0
Original line number Diff line number Diff line
@@ -102,6 +102,8 @@ static const struct i2c_device_id ad_dpot_id[] = {
	{"ad5170", AD5170_ID},
	{"ad5172", AD5172_ID},
	{"ad5173", AD5173_ID},
	{"ad5272", AD5272_ID},
	{"ad5274", AD5274_ID},
	{}
};
MODULE_DEVICE_TABLE(i2c, ad_dpot_id);
+2 −0
Original line number Diff line number Diff line
@@ -38,6 +38,8 @@ static const struct ad_dpot_id ad_dpot_spi_devlist[] = {
	{.name = "ad8402", .devid = AD8402_ID},
	{.name = "ad8403", .devid = AD8403_ID},
	{.name = "adn2850", .devid = ADN2850_ID},
	{.name = "ad5270", .devid = AD5270_ID},
	{.name = "ad5271", .devid = AD5271_ID},
	{}
};

+97 −10
Original line number Diff line number Diff line
@@ -29,9 +29,9 @@
 * AD5262		2		256		20, 50, 200
 * AD5263		4		256		20, 50, 200
 * AD5290		1		256		10, 50, 100
 * AD5291		1		256		20
 * AD5292		1		1024		20
 * AD5293		1		1024		20
 * AD5291		1		256		20, 50, 100  (20-TP)
 * AD5292		1		1024		20, 50, 100  (20-TP)
 * AD5293		1		1024		20, 50, 100
 * AD7376		1		128		10, 50, 100, 1M
 * AD8400		1		256		1, 10, 50, 100
 * AD8402		2		256		1, 10, 50, 100
@@ -52,6 +52,10 @@
 * AD5170		1		256		2.5, 10, 50, 100 (OTP)
 * AD5172		2		256		2.5, 10, 50, 100 (OTP)
 * AD5173		2		256		2.5, 10, 50, 100 (OTP)
 * AD5270		1		1024		20, 50, 100 (50-TP)
 * AD5271		1		256		20, 50, 100 (50-TP)
 * AD5272		1		1024		20, 50, 100 (50-TP)
 * AD5274		1		256		20, 50, 100 (50-TP)
 *
 * See Documentation/misc-devices/ad525x_dpot.txt for more info.
 *
@@ -126,18 +130,38 @@ static inline int dpot_write_r8d16(struct dpot_data *dpot, u8 reg, u16 val)
static s32 dpot_read_spi(struct dpot_data *dpot, u8 reg)
{
	unsigned ctrl = 0;
	int value;

	if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) {

		if (dpot->feat & F_RDACS_WONLY)
			return dpot->rdac_cache[reg & DPOT_RDAC_MASK];

		if (dpot->uid == DPOT_UID(AD5291_ID) ||
			dpot->uid == DPOT_UID(AD5292_ID) ||
			dpot->uid == DPOT_UID(AD5293_ID))
			return dpot_read_r8d8(dpot,
			dpot->uid == DPOT_UID(AD5293_ID)) {

			value = dpot_read_r8d8(dpot,
				DPOT_AD5291_READ_RDAC << 2);

			if (dpot->uid == DPOT_UID(AD5291_ID))
				value = value >> 2;

			return value;
		} else if (dpot->uid == DPOT_UID(AD5270_ID) ||
			dpot->uid == DPOT_UID(AD5271_ID)) {

			value = dpot_read_r8d8(dpot,
				DPOT_AD5270_1_2_4_READ_RDAC << 2);

			if (value < 0)
				return value;

			if (dpot->uid == DPOT_UID(AD5271_ID))
				value = value >> 2;

			return value;
		}

		ctrl = DPOT_SPI_READ_RDAC;
	} else if (reg & DPOT_ADDR_EEPROM) {
		ctrl = DPOT_SPI_READ_EEPROM;
@@ -153,6 +177,7 @@ static s32 dpot_read_spi(struct dpot_data *dpot, u8 reg)

static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg)
{
	int value;
	unsigned ctrl = 0;
	switch (dpot->uid) {
	case DPOT_UID(AD5246_ID):
@@ -177,6 +202,25 @@ static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg)
		ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
			0 : DPOT_AD5172_3_A0;
		return dpot_read_r8d8(dpot, ctrl);
	case DPOT_UID(AD5272_ID):
	case DPOT_UID(AD5274_ID):
			dpot_write_r8d8(dpot,
				(DPOT_AD5270_1_2_4_READ_RDAC << 2), 0);

			value = dpot_read_r8d16(dpot,
				DPOT_AD5270_1_2_4_RDAC << 2);

			if (value < 0)
				return value;
			/*
			 * AD5272/AD5274 returns high byte first, however
			 * underling smbus expects low byte first.
			 */
			value = swab16(value);

			if (dpot->uid == DPOT_UID(AD5271_ID))
				value = value >> 2;
		return value;
	default:
		if ((reg & DPOT_REG_TOL) || (dpot->max_pos > 256))
			return dpot_read_r8d16(dpot, (reg & 0xF8) |
@@ -198,7 +242,7 @@ static s32 dpot_write_spi(struct dpot_data *dpot, u8 reg, u16 value)
{
	unsigned val = 0;

	if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) {
	if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD | DPOT_ADDR_OTP))) {
		if (dpot->feat & F_RDACS_WONLY)
			dpot->rdac_cache[reg & DPOT_RDAC_MASK] = value;

@@ -219,11 +263,30 @@ static s32 dpot_write_spi(struct dpot_data *dpot, u8 reg, u16 value)
		} else {
			if (dpot->uid == DPOT_UID(AD5291_ID) ||
				dpot->uid == DPOT_UID(AD5292_ID) ||
				dpot->uid == DPOT_UID(AD5293_ID))
				dpot->uid == DPOT_UID(AD5293_ID)) {

				dpot_write_r8d8(dpot, DPOT_AD5291_CTRLREG << 2,
						DPOT_AD5291_UNLOCK_CMD);

				if (dpot->uid == DPOT_UID(AD5291_ID))
					value = value << 2;

				return dpot_write_r8d8(dpot,
					(DPOT_AD5291_RDAC << 2) |
					(value >> 8), value & 0xFF);
			} else if (dpot->uid == DPOT_UID(AD5270_ID) ||
				dpot->uid == DPOT_UID(AD5271_ID)) {
				dpot_write_r8d8(dpot,
						DPOT_AD5270_1_2_4_CTRLREG << 2,
						DPOT_AD5270_1_2_4_UNLOCK_CMD);

				if (dpot->uid == DPOT_UID(AD5271_ID))
					value = value << 2;

				return dpot_write_r8d8(dpot,
					(DPOT_AD5270_1_2_4_RDAC << 2) |
					(value >> 8), value & 0xFF);
			}
			val = DPOT_SPI_RDAC | (reg & DPOT_RDAC_MASK);
		}
	} else if (reg & DPOT_ADDR_EEPROM) {
@@ -243,6 +306,16 @@ static s32 dpot_write_spi(struct dpot_data *dpot, u8 reg, u16 value)
			val = DPOT_SPI_INC_ALL;
			break;
		}
	} else if (reg & DPOT_ADDR_OTP) {
		if (dpot->uid == DPOT_UID(AD5291_ID) ||
			dpot->uid == DPOT_UID(AD5292_ID)) {
			return dpot_write_r8d8(dpot,
				DPOT_AD5291_STORE_XTPM << 2, 0);
		} else if (dpot->uid == DPOT_UID(AD5270_ID) ||
			dpot->uid == DPOT_UID(AD5271_ID)) {
			return dpot_write_r8d8(dpot,
				DPOT_AD5270_1_2_4_STORE_XTPM << 2, 0);
		}
	} else
		BUG();

@@ -303,10 +376,25 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
			tmp = dpot_read_r8d16(dpot, tmp);
			if (tmp >> 14) /* Ready to Program? */
				return -EFAULT;
			ctrl = DPOT_AD5270_2_3_FUSE;
			ctrl = DPOT_AD5170_2_3_FUSE;
		}
		return dpot_write_r8d8(dpot, ctrl, value);
		break;
	case DPOT_UID(AD5272_ID):
	case DPOT_UID(AD5274_ID):
		dpot_write_r8d8(dpot, DPOT_AD5270_1_2_4_CTRLREG << 2,
				DPOT_AD5270_1_2_4_UNLOCK_CMD);

		if (reg & DPOT_ADDR_OTP)
			return dpot_write_r8d8(dpot,
					DPOT_AD5270_1_2_4_STORE_XTPM << 2, 0);

		if (dpot->uid == DPOT_UID(AD5274_ID))
			value = value << 2;

		return dpot_write_r8d8(dpot, (DPOT_AD5270_1_2_4_RDAC << 2) |
				       (value >> 8), value & 0xFF);
		break;
	default:
		if (reg & DPOT_ADDR_CMD)
			return dpot_write_d8(dpot, reg);
@@ -320,7 +408,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
	}
}


static s32 dpot_write(struct dpot_data *dpot, u8 reg, u16 value)
{
	if (dpot->feat & F_SPI)
+20 −3
Original line number Diff line number Diff line
@@ -93,8 +93,10 @@ enum dpot_devid {
			BRDAC0 | BRDAC1 | BRDAC2 | BRDAC3, 8, 23),
	AD5290_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
			BRDAC0, 8, 24),
	AD5291_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 8, 25),
	AD5292_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 10, 26),
	AD5291_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT | F_CMD_OTP,
			BRDAC0, 8, 25),
	AD5292_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT | F_CMD_OTP,
			BRDAC0, 10, 26),
	AD5293_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 10, 27),
	AD7376_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT,
			BRDAC0, 7, 28),
@@ -122,6 +124,12 @@ enum dpot_devid {
	AD5170_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0, 8, 45),
	AD5172_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0 | BRDAC1, 8, 46),
	AD5173_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0 | BRDAC1, 8, 47),
	AD5270_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP | F_SPI_16BIT,
			BRDAC0, 10, 48),
	AD5271_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP | F_SPI_16BIT,
			BRDAC0, 8, 49),
	AD5272_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0, 10, 50),
	AD5274_ID = DPOT_CONF(F_RDACS_RW | F_CMD_OTP, BRDAC0, 8, 51),
};

#define DPOT_RDAC0		0
@@ -165,10 +173,19 @@ enum dpot_devid {
/* AD5291/2/3 use special commands */
#define DPOT_AD5291_RDAC	0x01
#define DPOT_AD5291_READ_RDAC	0x02
#define DPOT_AD5291_STORE_XTPM	0x03
#define DPOT_AD5291_CTRLREG	0x06
#define DPOT_AD5291_UNLOCK_CMD	0x03

#define DPOT_AD5291_RDAC_AB	0x80
/* AD5270/1/2/4 use special commands */
#define DPOT_AD5270_1_2_4_RDAC		0x01
#define DPOT_AD5270_1_2_4_READ_RDAC	0x02
#define DPOT_AD5270_1_2_4_STORE_XTPM	0x03
#define DPOT_AD5270_1_2_4_CTRLREG	0x07
#define DPOT_AD5270_1_2_4_UNLOCK_CMD	0x03

#define DPOT_AD5282_RDAC_AB	0x80

#define DPOT_AD5273_FUSE	0x80
#define DPOT_AD5170_2_3_FUSE	0x20
#define DPOT_AD5170_2_3_OW	0x08