Commit e3ae6847 authored by Michael Hennerich's avatar Michael Hennerich Committed by Linus Torvalds

ad525x_dpot: add support for AD524x pots

New parts supported:
	AD5241, AD5242, AD5243, AD5245, AD5246, AD5247, AD5248
Signed-off-by: default avatarMichael Hennerich <michael.hennerich@analog.com>
Signed-off-by: default avatarMike Frysinger <vapier@gentoo.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 6c536e4c
......@@ -22,7 +22,8 @@ config AD525X_DPOT
AD5160, AD5161, AD5162, AD5165, AD5200, AD5201, AD5203,
AD5204, AD5206, AD5207, AD5231, AD5232, AD5233, AD5235,
AD5260, AD5262, AD5263, AD5290, AD5291, AD5292, AD5293,
AD7376, AD8400, AD8402, AD8403, ADN2850
AD7376, AD8400, AD8402, AD8403, ADN2850, AD5241, AD5242,
AD5243, AD5245, AD5246, AD5247, AD5248
digital potentiometer chips.
See Documentation/misc-devices/ad525x_dpot.txt for the
......
......@@ -87,6 +87,13 @@ static const struct i2c_device_id ad_dpot_id[] = {
{"ad5253", AD5253_ID},
{"ad5254", AD5254_ID},
{"ad5255", AD5255_ID},
{"ad5241", AD5241_ID},
{"ad5242", AD5242_ID},
{"ad5243", AD5243_ID},
{"ad5245", AD5245_ID},
{"ad5246", AD5246_ID},
{"ad5247", AD5247_ID},
{"ad5248", AD5248_ID},
{}
};
MODULE_DEVICE_TABLE(i2c, ad_dpot_id);
......
......@@ -37,6 +37,13 @@
* AD8402 2 256 1, 10, 50, 100
* AD8403 4 256 1, 10, 50, 100
* ADN2850 3 512 25, 250
* AD5241 1 256 10, 100, 1M
* AD5246 1 128 5, 10, 50, 100
* AD5247 1 128 5, 10, 50, 100
* AD5245 1 256 5, 10, 50, 100
* AD5243 2 256 2.5, 10, 50, 100
* AD5248 2 256 2.5, 10, 50, 100
* AD5242 2 256 20, 50, 200
*
* See Documentation/misc-devices/ad525x_dpot.txt for more info.
*
......@@ -107,118 +114,169 @@ static inline int dpot_write_r8d16(struct dpot_data *dpot, u8 reg, u16 val)
return dpot->bdata.bops->write_r8d16(dpot->bdata.client, reg, val);
}
static s32 dpot_read(struct dpot_data *dpot, u8 reg)
static s32 dpot_read_spi(struct dpot_data *dpot, u8 reg)
{
unsigned val = 0;
unsigned ctrl = 0;
if (dpot->feat & F_SPI) {
if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) {
if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) {
if (dpot->feat & F_RDACS_WONLY)
return dpot->rdac_cache[reg & DPOT_RDAC_MASK];
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_AD5291_READ_RDAC << 2);
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_AD5291_READ_RDAC << 2);
val = DPOT_SPI_READ_RDAC;
} else if (reg & DPOT_ADDR_EEPROM) {
val = DPOT_SPI_READ_EEPROM;
}
ctrl = DPOT_SPI_READ_RDAC;
} else if (reg & DPOT_ADDR_EEPROM) {
ctrl = DPOT_SPI_READ_EEPROM;
}
if (dpot->feat & F_SPI_16BIT)
return dpot_read_r8d8(dpot, val);
else if (dpot->feat & F_SPI_24BIT)
return dpot_read_r8d16(dpot, val);
if (dpot->feat & F_SPI_16BIT)
return dpot_read_r8d8(dpot, ctrl);
else if (dpot->feat & F_SPI_24BIT)
return dpot_read_r8d16(dpot, ctrl);
} else { /* I2C */
return -EFAULT;
}
static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg)
{
unsigned ctrl = 0;
switch (dpot->uid) {
case DPOT_UID(AD5246_ID):
case DPOT_UID(AD5247_ID):
return dpot_read_d8(dpot);
case DPOT_UID(AD5245_ID):
case DPOT_UID(AD5241_ID):
case DPOT_UID(AD5242_ID):
case DPOT_UID(AD5243_ID):
case DPOT_UID(AD5248_ID):
ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
0 : DPOT_AD5291_RDAC_AB;
return dpot_read_r8d8(dpot, ctrl);
default:
if ((reg & DPOT_REG_TOL) || (dpot->max_pos > 256))
return dpot_read_r8d16(dpot, (reg & 0xF8) |
((reg & 0x7) << 1));
else
return dpot_read_r8d8(dpot, reg);
}
return -EFAULT;
}
static s32 dpot_write(struct dpot_data *dpot, u8 reg, u16 value)
static s32 dpot_read(struct dpot_data *dpot, u8 reg)
{
if (dpot->feat & F_SPI)
return dpot_read_spi(dpot, reg);
else
return dpot_read_i2c(dpot, reg);
}
static s32 dpot_write_spi(struct dpot_data *dpot, u8 reg, u16 value)
{
unsigned val = 0;
if (dpot->feat & F_SPI) {
if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) {
if (dpot->feat & F_RDACS_WONLY)
dpot->rdac_cache[reg & DPOT_RDAC_MASK] = value;
if (dpot->feat & F_AD_APPDATA) {
if (dpot->feat & F_SPI_8BIT) {
val = ((reg & DPOT_RDAC_MASK) <<
DPOT_MAX_POS(dpot->devid)) |
value;
return dpot_write_d8(dpot, val);
} else if (dpot->feat & F_SPI_16BIT) {
val = ((reg & DPOT_RDAC_MASK) <<
DPOT_MAX_POS(dpot->devid)) |
value;
return dpot_write_r8d8(dpot, val >> 8,
val & 0xFF);
} else
BUG();
} else {
if (dpot->uid == DPOT_UID(AD5291_ID) ||
dpot->uid == DPOT_UID(AD5292_ID) ||
dpot->uid == DPOT_UID(AD5293_ID))
return dpot_write_r8d8(dpot,
(DPOT_AD5291_RDAC << 2) |
(value >> 8), value & 0xFF);
val = DPOT_SPI_RDAC | (reg & DPOT_RDAC_MASK);
}
} else if (reg & DPOT_ADDR_EEPROM) {
val = DPOT_SPI_EEPROM | (reg & DPOT_RDAC_MASK);
} else if (reg & DPOT_ADDR_CMD) {
switch (reg) {
case DPOT_DEC_ALL_6DB:
val = DPOT_SPI_DEC_ALL_6DB;
break;
case DPOT_INC_ALL_6DB:
val = DPOT_SPI_INC_ALL_6DB;
break;
case DPOT_DEC_ALL:
val = DPOT_SPI_DEC_ALL;
break;
case DPOT_INC_ALL:
val = DPOT_SPI_INC_ALL;
break;
}
} else
BUG();
if (dpot->feat & F_SPI_16BIT)
return dpot_write_r8d8(dpot, val, value);
else if (dpot->feat & F_SPI_24BIT)
return dpot_write_r8d16(dpot, val, value);
} else {
/* Only write the instruction byte for certain commands */
if (reg & DPOT_ADDR_CMD)
return dpot_write_d8(dpot, reg);
if (dpot->max_pos > 256)
return dpot_write_r8d16(dpot, (reg & 0xF8) |
((reg & 0x7) << 1), value);
else
/* All other registers require instruction + data bytes */
return dpot_write_r8d8(dpot, reg, value);
if (!(reg & (DPOT_ADDR_EEPROM | DPOT_ADDR_CMD))) {
if (dpot->feat & F_RDACS_WONLY)
dpot->rdac_cache[reg & DPOT_RDAC_MASK] = value;
if (dpot->feat & F_AD_APPDATA) {
if (dpot->feat & F_SPI_8BIT) {
val = ((reg & DPOT_RDAC_MASK) <<
DPOT_MAX_POS(dpot->devid)) |
value;
return dpot_write_d8(dpot, val);
} else if (dpot->feat & F_SPI_16BIT) {
val = ((reg & DPOT_RDAC_MASK) <<
DPOT_MAX_POS(dpot->devid)) |
value;
return dpot_write_r8d8(dpot, val >> 8,
val & 0xFF);
} else
BUG();
} else {
if (dpot->uid == DPOT_UID(AD5291_ID) ||
dpot->uid == DPOT_UID(AD5292_ID) ||
dpot->uid == DPOT_UID(AD5293_ID))
return dpot_write_r8d8(dpot,
(DPOT_AD5291_RDAC << 2) |
(value >> 8), value & 0xFF);
}
val = DPOT_SPI_RDAC | (reg & DPOT_RDAC_MASK);
}
} else if (reg & DPOT_ADDR_EEPROM) {
val = DPOT_SPI_EEPROM | (reg & DPOT_RDAC_MASK);
} else if (reg & DPOT_ADDR_CMD) {
switch (reg) {
case DPOT_DEC_ALL_6DB:
val = DPOT_SPI_DEC_ALL_6DB;
break;
case DPOT_INC_ALL_6DB:
val = DPOT_SPI_INC_ALL_6DB;
break;
case DPOT_DEC_ALL:
val = DPOT_SPI_DEC_ALL;
break;
case DPOT_INC_ALL:
val = DPOT_SPI_INC_ALL;
break;
}
} else
BUG();
if (dpot->feat & F_SPI_16BIT)
return dpot_write_r8d8(dpot, val, value);
else if (dpot->feat & F_SPI_24BIT)
return dpot_write_r8d16(dpot, val, value);
return -EFAULT;
}
static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
{
/* Only write the instruction byte for certain commands */
unsigned ctrl = 0;
switch (dpot->uid) {
case DPOT_UID(AD5246_ID):
case DPOT_UID(AD5247_ID):
return dpot_write_d8(dpot, value);
break;
case DPOT_UID(AD5245_ID):
case DPOT_UID(AD5241_ID):
case DPOT_UID(AD5242_ID):
case DPOT_UID(AD5243_ID):
case DPOT_UID(AD5248_ID):
ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ? 0 : DPOT_AD5291_RDAC_AB;
return dpot_write_r8d8(dpot, ctrl, value);
break;
default:
if (reg & DPOT_ADDR_CMD)
return dpot_write_d8(dpot, reg);
if (dpot->max_pos > 256)
return dpot_write_r8d16(dpot, (reg & 0xF8) |
((reg & 0x7) << 1), value);
else
/* All other registers require instruction + data bytes */
return dpot_write_r8d8(dpot, reg, value);
}
}
static s32 dpot_write(struct dpot_data *dpot, u8 reg, u16 value)
{
if (dpot->feat & F_SPI)
return dpot_write_spi(dpot, reg, value);
else
return dpot_write_i2c(dpot, reg, value);
}
/* sysfs functions */
static ssize_t sysfs_show_reg(struct device *dev,
......
......@@ -29,13 +29,14 @@
#define F_CMD_INC (1 << 0) /* Features INC/DEC ALL, 6dB */
#define F_CMD_EEP (1 << 1) /* Features EEPROM */
#define F_CMD_TOL (1 << 2) /* RDACS are Read/Write + Tolerance REG */
#define F_RDACS_RW (1 << 3) /* RDACS are Read/Write + Tolerance REG */
#define F_RDACS_WONLY (1 << 4) /* RDACS are Write only */
#define F_AD_APPDATA (1 << 5) /* RDAC Address append to data */
#define F_SPI_8BIT (1 << 6) /* All SPI XFERS are 8-bit */
#define F_SPI_16BIT (1 << 7) /* All SPI XFERS are 16-bit */
#define F_SPI_24BIT (1 << 8) /* All SPI XFERS are 24-bit */
#define F_CMD_OTP (1 << 2) /* Features OTP */
#define F_CMD_TOL (1 << 3) /* RDACS feature Tolerance REG */
#define F_RDACS_RW (1 << 4) /* RDACS are Read/Write */
#define F_RDACS_WONLY (1 << 5) /* RDACS are Write only */
#define F_AD_APPDATA (1 << 6) /* RDAC Address append to data */
#define F_SPI_8BIT (1 << 7) /* All SPI XFERS are 8-bit */
#define F_SPI_16BIT (1 << 8) /* All SPI XFERS are 16-bit */
#define F_SPI_24BIT (1 << 9) /* All SPI XFERS are 24-bit */
#define F_RDACS_RW_TOL (F_RDACS_RW | F_CMD_EEP | F_CMD_TOL)
#define F_RDACS_RW_EEP (F_RDACS_RW | F_CMD_EEP)
......@@ -104,6 +105,15 @@ enum dpot_devid {
BRDAC0 | BRDAC1 | BRDAC2, 8, 31),
ADN2850_ID = DPOT_CONF(F_RDACS_RW_EEP | F_CMD_INC | F_SPI_24BIT,
BRDAC0 | BRDAC1, 10, 32),
AD5241_ID = DPOT_CONF(F_RDACS_RW, BRDAC0, 8, 33),
AD5242_ID = DPOT_CONF(F_RDACS_RW, BRDAC0 | BRDAC1, 8, 34),
AD5243_ID = DPOT_CONF(F_RDACS_RW, BRDAC0 | BRDAC1, 8, 35),
AD5245_ID = DPOT_CONF(F_RDACS_RW, BRDAC0, 8, 36),
AD5246_ID = DPOT_CONF(F_RDACS_RW, BRDAC0, 7, 37),
AD5247_ID = DPOT_CONF(F_RDACS_RW, BRDAC0, 7, 38),
AD5248_ID = DPOT_CONF(F_RDACS_RW, BRDAC0 | BRDAC1, 8, 39),
};
#define DPOT_RDAC0 0
......@@ -146,6 +156,9 @@ enum dpot_devid {
#define DPOT_AD5291_RDAC 0x01
#define DPOT_AD5291_READ_RDAC 0x02
/* AD524x use special commands */
#define DPOT_AD5291_RDAC_AB 0x80
struct dpot_data;
struct ad_dpot_bus_ops {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment