0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 #include <linux/module.h>
0032 #include <linux/i2c.h>
0033 #include <linux/string.h>
0034 #include <linux/list.h>
0035 #include <linux/sysfs.h>
0036 #include <linux/ctype.h>
0037 #include <linux/hwmon-sysfs.h>
0038
0039
0040 #define DS1682_REG_CONFIG 0x00
0041 #define DS1682_REG_ALARM 0x01
0042 #define DS1682_REG_ELAPSED 0x05
0043 #define DS1682_REG_EVT_CNTR 0x09
0044 #define DS1682_REG_EEPROM 0x0b
0045 #define DS1682_REG_RESET 0x1d
0046 #define DS1682_REG_WRITE_DISABLE 0x1e
0047 #define DS1682_REG_WRITE_MEM_DISABLE 0x1f
0048
0049 #define DS1682_EEPROM_SIZE 10
0050
0051
0052
0053
0054 static ssize_t ds1682_show(struct device *dev, struct device_attribute *attr,
0055 char *buf)
0056 {
0057 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
0058 struct i2c_client *client = to_i2c_client(dev);
0059 unsigned long long val, check;
0060 __le32 val_le = 0;
0061 int rc;
0062
0063 dev_dbg(dev, "ds1682_show() called on %s\n", attr->attr.name);
0064
0065
0066 rc = i2c_smbus_read_i2c_block_data(client, sattr->index, sattr->nr,
0067 (u8 *)&val_le);
0068 if (rc < 0)
0069 return -EIO;
0070
0071 val = le32_to_cpu(val_le);
0072
0073 if (sattr->index == DS1682_REG_ELAPSED) {
0074 int retries = 5;
0075
0076
0077 do {
0078 rc = i2c_smbus_read_i2c_block_data(client, sattr->index,
0079 sattr->nr,
0080 (u8 *)&val_le);
0081 if (rc < 0 || retries <= 0)
0082 return -EIO;
0083
0084 check = val;
0085 val = le32_to_cpu(val_le);
0086 retries--;
0087 } while (val != check && val != (check + 1));
0088 }
0089
0090
0091
0092
0093
0094 return sprintf(buf, "%llu\n", (sattr->nr == 4) ? (val * 250) : val);
0095 }
0096
0097 static ssize_t ds1682_store(struct device *dev, struct device_attribute *attr,
0098 const char *buf, size_t count)
0099 {
0100 struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
0101 struct i2c_client *client = to_i2c_client(dev);
0102 u64 val;
0103 __le32 val_le;
0104 int rc;
0105
0106 dev_dbg(dev, "ds1682_store() called on %s\n", attr->attr.name);
0107
0108
0109 rc = kstrtoull(buf, 0, &val);
0110 if (rc < 0) {
0111 dev_dbg(dev, "input string not a number\n");
0112 return -EINVAL;
0113 }
0114
0115
0116
0117 if (sattr->nr == 4)
0118 do_div(val, 250);
0119
0120
0121 val_le = cpu_to_le32(val);
0122 rc = i2c_smbus_write_i2c_block_data(client, sattr->index, sattr->nr,
0123 (u8 *) & val_le);
0124 if (rc < 0) {
0125 dev_err(dev, "register write failed; reg=0x%x, size=%i\n",
0126 sattr->index, sattr->nr);
0127 return -EIO;
0128 }
0129
0130 return count;
0131 }
0132
0133
0134
0135
0136 static SENSOR_DEVICE_ATTR_2(elapsed_time, S_IRUGO | S_IWUSR, ds1682_show,
0137 ds1682_store, 4, DS1682_REG_ELAPSED);
0138 static SENSOR_DEVICE_ATTR_2(alarm_time, S_IRUGO | S_IWUSR, ds1682_show,
0139 ds1682_store, 4, DS1682_REG_ALARM);
0140 static SENSOR_DEVICE_ATTR_2(event_count, S_IRUGO | S_IWUSR, ds1682_show,
0141 ds1682_store, 2, DS1682_REG_EVT_CNTR);
0142
0143 static const struct attribute_group ds1682_group = {
0144 .attrs = (struct attribute *[]) {
0145 &sensor_dev_attr_elapsed_time.dev_attr.attr,
0146 &sensor_dev_attr_alarm_time.dev_attr.attr,
0147 &sensor_dev_attr_event_count.dev_attr.attr,
0148 NULL,
0149 },
0150 };
0151
0152
0153
0154
0155 static ssize_t ds1682_eeprom_read(struct file *filp, struct kobject *kobj,
0156 struct bin_attribute *attr,
0157 char *buf, loff_t off, size_t count)
0158 {
0159 struct i2c_client *client = kobj_to_i2c_client(kobj);
0160 int rc;
0161
0162 dev_dbg(&client->dev, "ds1682_eeprom_read(p=%p, off=%lli, c=%zi)\n",
0163 buf, off, count);
0164
0165 rc = i2c_smbus_read_i2c_block_data(client, DS1682_REG_EEPROM + off,
0166 count, buf);
0167 if (rc < 0)
0168 return -EIO;
0169
0170 return count;
0171 }
0172
0173 static ssize_t ds1682_eeprom_write(struct file *filp, struct kobject *kobj,
0174 struct bin_attribute *attr,
0175 char *buf, loff_t off, size_t count)
0176 {
0177 struct i2c_client *client = kobj_to_i2c_client(kobj);
0178
0179 dev_dbg(&client->dev, "ds1682_eeprom_write(p=%p, off=%lli, c=%zi)\n",
0180 buf, off, count);
0181
0182
0183 if (i2c_smbus_write_i2c_block_data(client, DS1682_REG_EEPROM + off,
0184 count, buf) < 0)
0185 return -EIO;
0186
0187 return count;
0188 }
0189
0190 static const struct bin_attribute ds1682_eeprom_attr = {
0191 .attr = {
0192 .name = "eeprom",
0193 .mode = S_IRUGO | S_IWUSR,
0194 },
0195 .size = DS1682_EEPROM_SIZE,
0196 .read = ds1682_eeprom_read,
0197 .write = ds1682_eeprom_write,
0198 };
0199
0200
0201
0202
0203 static int ds1682_probe(struct i2c_client *client,
0204 const struct i2c_device_id *id)
0205 {
0206 int rc;
0207
0208 if (!i2c_check_functionality(client->adapter,
0209 I2C_FUNC_SMBUS_I2C_BLOCK)) {
0210 dev_err(&client->dev, "i2c bus does not support the ds1682\n");
0211 rc = -ENODEV;
0212 goto exit;
0213 }
0214
0215 rc = sysfs_create_group(&client->dev.kobj, &ds1682_group);
0216 if (rc)
0217 goto exit;
0218
0219 rc = sysfs_create_bin_file(&client->dev.kobj, &ds1682_eeprom_attr);
0220 if (rc)
0221 goto exit_bin_attr;
0222
0223 return 0;
0224
0225 exit_bin_attr:
0226 sysfs_remove_group(&client->dev.kobj, &ds1682_group);
0227 exit:
0228 return rc;
0229 }
0230
0231 static int ds1682_remove(struct i2c_client *client)
0232 {
0233 sysfs_remove_bin_file(&client->dev.kobj, &ds1682_eeprom_attr);
0234 sysfs_remove_group(&client->dev.kobj, &ds1682_group);
0235 return 0;
0236 }
0237
0238 static const struct i2c_device_id ds1682_id[] = {
0239 { "ds1682", 0 },
0240 { }
0241 };
0242 MODULE_DEVICE_TABLE(i2c, ds1682_id);
0243
0244 static const struct of_device_id ds1682_of_match[] = {
0245 { .compatible = "dallas,ds1682", },
0246 {}
0247 };
0248 MODULE_DEVICE_TABLE(of, ds1682_of_match);
0249
0250 static struct i2c_driver ds1682_driver = {
0251 .driver = {
0252 .name = "ds1682",
0253 .of_match_table = ds1682_of_match,
0254 },
0255 .probe = ds1682_probe,
0256 .remove = ds1682_remove,
0257 .id_table = ds1682_id,
0258 };
0259
0260 module_i2c_driver(ds1682_driver);
0261
0262 MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
0263 MODULE_DESCRIPTION("DS1682 Elapsed Time Indicator driver");
0264 MODULE_LICENSE("GPL");