0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/module.h>
0010 #include <linux/init.h>
0011 #include <linux/regmap.h>
0012 #include <linux/spi/spi.h>
0013 #include <asm/unaligned.h>
0014
0015 #include "adt7x10.h"
0016
0017 #define ADT7310_STATUS 0
0018 #define ADT7310_CONFIG 1
0019 #define ADT7310_TEMPERATURE 2
0020 #define ADT7310_ID 3
0021 #define ADT7310_T_CRIT 4
0022 #define ADT7310_T_HYST 5
0023 #define ADT7310_T_ALARM_HIGH 6
0024 #define ADT7310_T_ALARM_LOW 7
0025
0026 static const u8 adt7310_reg_table[] = {
0027 [ADT7X10_TEMPERATURE] = ADT7310_TEMPERATURE,
0028 [ADT7X10_STATUS] = ADT7310_STATUS,
0029 [ADT7X10_CONFIG] = ADT7310_CONFIG,
0030 [ADT7X10_T_ALARM_HIGH] = ADT7310_T_ALARM_HIGH,
0031 [ADT7X10_T_ALARM_LOW] = ADT7310_T_ALARM_LOW,
0032 [ADT7X10_T_CRIT] = ADT7310_T_CRIT,
0033 [ADT7X10_T_HYST] = ADT7310_T_HYST,
0034 [ADT7X10_ID] = ADT7310_ID,
0035 };
0036
0037 #define ADT7310_CMD_REG_OFFSET 3
0038 #define ADT7310_CMD_READ 0x40
0039
0040 #define AD7310_COMMAND(reg) (adt7310_reg_table[(reg)] << ADT7310_CMD_REG_OFFSET)
0041
0042 static int adt7310_spi_read_word(struct spi_device *spi, u8 reg)
0043 {
0044 return spi_w8r16be(spi, AD7310_COMMAND(reg) | ADT7310_CMD_READ);
0045 }
0046
0047 static int adt7310_spi_write_word(struct spi_device *spi, u8 reg, u16 data)
0048 {
0049 u8 buf[3];
0050
0051 buf[0] = AD7310_COMMAND(reg);
0052 put_unaligned_be16(data, &buf[1]);
0053
0054 return spi_write(spi, buf, sizeof(buf));
0055 }
0056
0057 static int adt7310_spi_read_byte(struct spi_device *spi, u8 reg)
0058 {
0059 return spi_w8r8(spi, AD7310_COMMAND(reg) | ADT7310_CMD_READ);
0060 }
0061
0062 static int adt7310_spi_write_byte(struct spi_device *spi, u8 reg, u8 data)
0063 {
0064 u8 buf[2];
0065
0066 buf[0] = AD7310_COMMAND(reg);
0067 buf[1] = data;
0068
0069 return spi_write(spi, buf, sizeof(buf));
0070 }
0071
0072 static bool adt7310_regmap_is_volatile(struct device *dev, unsigned int reg)
0073 {
0074 switch (reg) {
0075 case ADT7X10_TEMPERATURE:
0076 case ADT7X10_STATUS:
0077 return true;
0078 default:
0079 return false;
0080 }
0081 }
0082
0083 static int adt7310_reg_read(void *context, unsigned int reg, unsigned int *val)
0084 {
0085 struct spi_device *spi = context;
0086 int regval;
0087
0088 switch (reg) {
0089 case ADT7X10_TEMPERATURE:
0090 case ADT7X10_T_ALARM_HIGH:
0091 case ADT7X10_T_ALARM_LOW:
0092 case ADT7X10_T_CRIT:
0093 regval = adt7310_spi_read_word(spi, reg);
0094 break;
0095 default:
0096 regval = adt7310_spi_read_byte(spi, reg);
0097 break;
0098 }
0099 if (regval < 0)
0100 return regval;
0101 *val = regval;
0102 return 0;
0103 }
0104
0105 static int adt7310_reg_write(void *context, unsigned int reg, unsigned int val)
0106 {
0107 struct spi_device *spi = context;
0108 int ret;
0109
0110 switch (reg) {
0111 case ADT7X10_TEMPERATURE:
0112 case ADT7X10_T_ALARM_HIGH:
0113 case ADT7X10_T_ALARM_LOW:
0114 case ADT7X10_T_CRIT:
0115 ret = adt7310_spi_write_word(spi, reg, val);
0116 break;
0117 default:
0118 ret = adt7310_spi_write_byte(spi, reg, val);
0119 break;
0120 }
0121 return ret;
0122 }
0123
0124 static const struct regmap_config adt7310_regmap_config = {
0125 .reg_bits = 8,
0126 .val_bits = 16,
0127 .cache_type = REGCACHE_RBTREE,
0128 .volatile_reg = adt7310_regmap_is_volatile,
0129 .reg_read = adt7310_reg_read,
0130 .reg_write = adt7310_reg_write,
0131 };
0132
0133 static int adt7310_spi_probe(struct spi_device *spi)
0134 {
0135 struct regmap *regmap;
0136
0137 regmap = devm_regmap_init(&spi->dev, NULL, spi, &adt7310_regmap_config);
0138 if (IS_ERR(regmap))
0139 return PTR_ERR(regmap);
0140
0141 return adt7x10_probe(&spi->dev, spi_get_device_id(spi)->name, spi->irq,
0142 regmap);
0143 }
0144
0145 static const struct spi_device_id adt7310_id[] = {
0146 { "adt7310", 0 },
0147 { "adt7320", 0 },
0148 {}
0149 };
0150 MODULE_DEVICE_TABLE(spi, adt7310_id);
0151
0152 static struct spi_driver adt7310_driver = {
0153 .driver = {
0154 .name = "adt7310",
0155 .pm = ADT7X10_DEV_PM_OPS,
0156 },
0157 .probe = adt7310_spi_probe,
0158 .id_table = adt7310_id,
0159 };
0160 module_spi_driver(adt7310_driver);
0161
0162 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
0163 MODULE_DESCRIPTION("ADT7310/ADT7320 driver");
0164 MODULE_LICENSE("GPL");