drivers/misc/ad525x_dpot.c: new features
authorMichael Hennerich <michael.hennerich@analog.com>
Tue, 26 Oct 2010 21:22:36 +0000 (14:22 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 26 Oct 2010 23:52:14 +0000 (16:52 -0700)
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: Michael Hennerich <michael.hennerich@analog.com>
Cc: Mike Frysinger <vapier@gentoo.org>
Cc: Chris Verges <chrisv@cyberswitching.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/misc/Kconfig
drivers/misc/ad525x_dpot-i2c.c
drivers/misc/ad525x_dpot-spi.c
drivers/misc/ad525x_dpot.c
drivers/misc/ad525x_dpot.h

index 1f69743b12ec036239fa6fe05540cec600c5b4b9..3d57adfc87033f925484bfcd247e8ae67ff891f2 100644 (file)
@@ -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
index 374352af79791f8fed39281789169519ce764ceb..4ff73c215746688357ca5406e332b3ed320a5985 100644 (file)
@@ -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);
index 6cfcb636577a04c64e4da856c8e320e8d91cbfc0..7f9a55afe05d77b224c88f87ac38d367788d643f 100644 (file)
@@ -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},
        {}
 };
 
index 9698c7546911310e0761b5b52e0394ee0c6962f2..7cb911028d094ca4416382806191a5e3e4b68e82 100644 (file)
@@ -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
  * 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)
index 7609d49efd31a767f1ec2f15ac6423bd799aa9f7..3b9e355489ae5823122522559a0bba1837fa1783 100644 (file)
@@ -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