1 /* 2 * ads7828.c - driver for TI ADS7828 8-channel A/D converter and compatibles 3 * (C) 2007 EADS Astrium 4 * 5 * This driver is based on the lm75 and other lm_sensors/hwmon drivers 6 * 7 * Written by Steve Hardy <shardy@redhat.com> 8 * 9 * ADS7830 support, by Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> 10 * 11 * For further information, see the Documentation/hwmon/ads7828 file. 12 * 13 * This program is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU General Public License as published by 15 * the Free Software Foundation; either version 2 of the License, or 16 * (at your option) any later version. 17 * 18 * This program is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU General Public License for more details. 22 * 23 * You should have received a copy of the GNU General Public License 24 * along with this program; if not, write to the Free Software 25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 26 */ 27 28 #include <linux/err.h> 29 #include <linux/hwmon.h> 30 #include <linux/hwmon-sysfs.h> 31 #include <linux/i2c.h> 32 #include <linux/init.h> 33 #include <linux/module.h> 34 #include <linux/platform_data/ads7828.h> 35 #include <linux/regmap.h> 36 #include <linux/slab.h> 37 38 /* The ADS7828 registers */ 39 #define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */ 40 #define ADS7828_CMD_PD1 0x04 /* Internal vref OFF && A/D ON */ 41 #define ADS7828_CMD_PD3 0x0C /* Internal vref ON && A/D ON */ 42 #define ADS7828_INT_VREF_MV 2500 /* Internal vref is 2.5V, 2500mV */ 43 #define ADS7828_EXT_VREF_MV_MIN 50 /* External vref min value 0.05V */ 44 #define ADS7828_EXT_VREF_MV_MAX 5250 /* External vref max value 5.25V */ 45 46 /* List of supported devices */ 47 enum ads7828_chips { ads7828, ads7830 }; 48 49 /* Client specific data */ 50 struct ads7828_data { 51 struct regmap *regmap; 52 u8 cmd_byte; /* Command byte without channel bits */ 53 unsigned int lsb_resol; /* Resolution of the ADC sample LSB */ 54 }; 55 56 /* Command byte C2,C1,C0 - see datasheet */ 57 static inline u8 ads7828_cmd_byte(u8 cmd, int ch) 58 { 59 return cmd | (((ch >> 1) | (ch & 0x01) << 2) << 4); 60 } 61 62 /* sysfs callback function */ 63 static ssize_t ads7828_show_in(struct device *dev, struct device_attribute *da, 64 char *buf) 65 { 66 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 67 struct ads7828_data *data = dev_get_drvdata(dev); 68 u8 cmd = ads7828_cmd_byte(data->cmd_byte, attr->index); 69 unsigned int regval; 70 int err; 71 72 err = regmap_read(data->regmap, cmd, ®val); 73 if (err < 0) 74 return err; 75 76 return sprintf(buf, "%d\n", 77 DIV_ROUND_CLOSEST(regval * data->lsb_resol, 1000)); 78 } 79 80 static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ads7828_show_in, NULL, 0); 81 static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ads7828_show_in, NULL, 1); 82 static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ads7828_show_in, NULL, 2); 83 static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ads7828_show_in, NULL, 3); 84 static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ads7828_show_in, NULL, 4); 85 static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, ads7828_show_in, NULL, 5); 86 static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, ads7828_show_in, NULL, 6); 87 static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, ads7828_show_in, NULL, 7); 88 89 static struct attribute *ads7828_attrs[] = { 90 &sensor_dev_attr_in0_input.dev_attr.attr, 91 &sensor_dev_attr_in1_input.dev_attr.attr, 92 &sensor_dev_attr_in2_input.dev_attr.attr, 93 &sensor_dev_attr_in3_input.dev_attr.attr, 94 &sensor_dev_attr_in4_input.dev_attr.attr, 95 &sensor_dev_attr_in5_input.dev_attr.attr, 96 &sensor_dev_attr_in6_input.dev_attr.attr, 97 &sensor_dev_attr_in7_input.dev_attr.attr, 98 NULL 99 }; 100 101 ATTRIBUTE_GROUPS(ads7828); 102 103 static const struct regmap_config ads2828_regmap_config = { 104 .reg_bits = 8, 105 .val_bits = 16, 106 }; 107 108 static const struct regmap_config ads2830_regmap_config = { 109 .reg_bits = 8, 110 .val_bits = 8, 111 }; 112 113 static int ads7828_probe(struct i2c_client *client, 114 const struct i2c_device_id *id) 115 { 116 struct device *dev = &client->dev; 117 struct ads7828_platform_data *pdata = dev_get_platdata(dev); 118 struct ads7828_data *data; 119 struct device *hwmon_dev; 120 unsigned int vref_mv = ADS7828_INT_VREF_MV; 121 bool diff_input = false; 122 bool ext_vref = false; 123 124 data = devm_kzalloc(dev, sizeof(struct ads7828_data), GFP_KERNEL); 125 if (!data) 126 return -ENOMEM; 127 128 if (pdata) { 129 diff_input = pdata->diff_input; 130 ext_vref = pdata->ext_vref; 131 if (ext_vref && pdata->vref_mv) 132 vref_mv = pdata->vref_mv; 133 } 134 135 /* Bound Vref with min/max values */ 136 vref_mv = clamp_val(vref_mv, ADS7828_EXT_VREF_MV_MIN, 137 ADS7828_EXT_VREF_MV_MAX); 138 139 /* ADS7828 uses 12-bit samples, while ADS7830 is 8-bit */ 140 if (id->driver_data == ads7828) { 141 data->lsb_resol = DIV_ROUND_CLOSEST(vref_mv * 1000, 4096); 142 data->regmap = devm_regmap_init_i2c(client, 143 &ads2828_regmap_config); 144 } else { 145 data->lsb_resol = DIV_ROUND_CLOSEST(vref_mv * 1000, 256); 146 data->regmap = devm_regmap_init_i2c(client, 147 &ads2830_regmap_config); 148 } 149 150 if (IS_ERR(data->regmap)) 151 return PTR_ERR(data->regmap); 152 153 data->cmd_byte = ext_vref ? ADS7828_CMD_PD1 : ADS7828_CMD_PD3; 154 if (!diff_input) 155 data->cmd_byte |= ADS7828_CMD_SD_SE; 156 157 hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, 158 data, 159 ads7828_groups); 160 return PTR_ERR_OR_ZERO(hwmon_dev); 161 } 162 163 static const struct i2c_device_id ads7828_device_ids[] = { 164 { "ads7828", ads7828 }, 165 { "ads7830", ads7830 }, 166 { } 167 }; 168 MODULE_DEVICE_TABLE(i2c, ads7828_device_ids); 169 170 static struct i2c_driver ads7828_driver = { 171 .driver = { 172 .name = "ads7828", 173 }, 174 175 .id_table = ads7828_device_ids, 176 .probe = ads7828_probe, 177 }; 178 179 module_i2c_driver(ads7828_driver); 180 181 MODULE_LICENSE("GPL"); 182 MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>"); 183 MODULE_DESCRIPTION("Driver for TI ADS7828 A/D converter and compatibles"); 184