diff options
author | Guenter Roeck <linux@roeck-us.net> | 2016-06-20 12:55:46 -0400 |
---|---|---|
committer | Guenter Roeck <linux@roeck-us.net> | 2016-07-12 17:24:14 -0400 |
commit | 28a340db9043f11dfd092c1b8ea4043f59cc0ca1 (patch) | |
tree | 01889c6f36fc6fa9537f7cc6bc4c4484ca983714 | |
parent | a9f92ccf334f7e15124193b1d7b89b7e6e6624e2 (diff) |
hwmon: (tmp102) Convert to use regmap, and drop local cache
By converting the driver to regmap, we can use regmap to cache non-volatile
registers. Stop caching the temperature register; while potentially reading
it more often can result in reading it more often than necessary, this is
offset by the gain due to not re-reading the limit registers.
A positive side effect of this change is that limit registers can now be
read and updated before the first temperature conversion is complete.
Acked-by: Nishanth Menon <nm@ti.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
-rw-r--r-- | drivers/hwmon/Kconfig | 1 | ||||
-rw-r--r-- | drivers/hwmon/tmp102.c | 148 |
2 files changed, 71 insertions, 78 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index f271353b4b55..e72cd3d33d4e 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -1561,6 +1561,7 @@ config SENSORS_TMP102 | |||
1561 | tristate "Texas Instruments TMP102" | 1561 | tristate "Texas Instruments TMP102" |
1562 | depends on I2C | 1562 | depends on I2C |
1563 | depends on THERMAL || !THERMAL_OF | 1563 | depends on THERMAL || !THERMAL_OF |
1564 | select REGMAP_I2C | ||
1564 | help | 1565 | help |
1565 | If you say yes here you get support for Texas Instruments TMP102 | 1566 | If you say yes here you get support for Texas Instruments TMP102 |
1566 | sensor chips. | 1567 | sensor chips. |
diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c index 82a8a29af2e4..a942a2574a4d 100644 --- a/drivers/hwmon/tmp102.c +++ b/drivers/hwmon/tmp102.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/mutex.h> | 24 | #include <linux/mutex.h> |
25 | #include <linux/device.h> | 25 | #include <linux/device.h> |
26 | #include <linux/jiffies.h> | 26 | #include <linux/jiffies.h> |
27 | #include <linux/regmap.h> | ||
27 | #include <linux/thermal.h> | 28 | #include <linux/thermal.h> |
28 | #include <linux/of.h> | 29 | #include <linux/of.h> |
29 | 30 | ||
@@ -61,13 +62,9 @@ | |||
61 | #define CONVERSION_TIME_MS 35 /* in milli-seconds */ | 62 | #define CONVERSION_TIME_MS 35 /* in milli-seconds */ |
62 | 63 | ||
63 | struct tmp102 { | 64 | struct tmp102 { |
64 | struct i2c_client *client; | 65 | struct regmap *regmap; |
65 | struct mutex lock; | ||
66 | u16 config_orig; | 66 | u16 config_orig; |
67 | unsigned long last_update; | ||
68 | unsigned long ready_time; | 67 | unsigned long ready_time; |
69 | bool valid; | ||
70 | int temp[3]; | ||
71 | }; | 68 | }; |
72 | 69 | ||
73 | /* convert left adjusted 13-bit TMP102 register value to milliCelsius */ | 70 | /* convert left adjusted 13-bit TMP102 register value to milliCelsius */ |
@@ -82,45 +79,22 @@ static inline u16 tmp102_mC_to_reg(int val) | |||
82 | return (val * 128) / 1000; | 79 | return (val * 128) / 1000; |
83 | } | 80 | } |
84 | 81 | ||
85 | static const u8 tmp102_reg[] = { | ||
86 | TMP102_TEMP_REG, | ||
87 | TMP102_TLOW_REG, | ||
88 | TMP102_THIGH_REG, | ||
89 | }; | ||
90 | |||
91 | static void tmp102_update_device(struct device *dev) | ||
92 | { | ||
93 | struct tmp102 *tmp102 = dev_get_drvdata(dev); | ||
94 | struct i2c_client *client = tmp102->client; | ||
95 | |||
96 | mutex_lock(&tmp102->lock); | ||
97 | if (!tmp102->valid || | ||
98 | time_after(jiffies, tmp102->last_update + HZ / 3)) { | ||
99 | int i; | ||
100 | for (i = 0; i < ARRAY_SIZE(tmp102->temp); ++i) { | ||
101 | int status = i2c_smbus_read_word_swapped(client, | ||
102 | tmp102_reg[i]); | ||
103 | if (status > -1) | ||
104 | tmp102->temp[i] = tmp102_reg_to_mC(status); | ||
105 | } | ||
106 | tmp102->last_update = jiffies; | ||
107 | tmp102->valid = true; | ||
108 | } | ||
109 | mutex_unlock(&tmp102->lock); | ||
110 | } | ||
111 | |||
112 | static int tmp102_read_temp(void *dev, int *temp) | 82 | static int tmp102_read_temp(void *dev, int *temp) |
113 | { | 83 | { |
114 | struct tmp102 *tmp102 = dev_get_drvdata(dev); | 84 | struct tmp102 *tmp102 = dev_get_drvdata(dev); |
85 | unsigned int reg; | ||
86 | int ret; | ||
115 | 87 | ||
116 | if (time_before(jiffies, tmp102->ready_time)) { | 88 | if (time_before(jiffies, tmp102->ready_time)) { |
117 | dev_dbg(dev, "%s: Conversion not ready yet..\n", __func__); | 89 | dev_dbg(dev, "%s: Conversion not ready yet..\n", __func__); |
118 | return -EAGAIN; | 90 | return -EAGAIN; |
119 | } | 91 | } |
120 | 92 | ||
121 | tmp102_update_device(dev); | 93 | ret = regmap_read(tmp102->regmap, TMP102_TEMP_REG, ®); |
94 | if (ret < 0) | ||
95 | return ret; | ||
122 | 96 | ||
123 | *temp = tmp102->temp[0]; | 97 | *temp = tmp102_reg_to_mC(reg); |
124 | 98 | ||
125 | return 0; | 99 | return 0; |
126 | } | 100 | } |
@@ -131,13 +105,19 @@ static ssize_t tmp102_show_temp(struct device *dev, | |||
131 | { | 105 | { |
132 | struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); | 106 | struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); |
133 | struct tmp102 *tmp102 = dev_get_drvdata(dev); | 107 | struct tmp102 *tmp102 = dev_get_drvdata(dev); |
108 | int regaddr = sda->index; | ||
109 | unsigned int reg; | ||
110 | int err; | ||
134 | 111 | ||
135 | if (time_before(jiffies, tmp102->ready_time)) | 112 | if (regaddr == TMP102_TEMP_REG && |
113 | time_before(jiffies, tmp102->ready_time)) | ||
136 | return -EAGAIN; | 114 | return -EAGAIN; |
137 | 115 | ||
138 | tmp102_update_device(dev); | 116 | err = regmap_read(tmp102->regmap, regaddr, ®); |
117 | if (err < 0) | ||
118 | return err; | ||
139 | 119 | ||
140 | return sprintf(buf, "%d\n", tmp102->temp[sda->index]); | 120 | return sprintf(buf, "%d\n", tmp102_reg_to_mC(reg)); |
141 | } | 121 | } |
142 | 122 | ||
143 | static ssize_t tmp102_set_temp(struct device *dev, | 123 | static ssize_t tmp102_set_temp(struct device *dev, |
@@ -146,29 +126,26 @@ static ssize_t tmp102_set_temp(struct device *dev, | |||
146 | { | 126 | { |
147 | struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); | 127 | struct sensor_device_attribute *sda = to_sensor_dev_attr(attr); |
148 | struct tmp102 *tmp102 = dev_get_drvdata(dev); | 128 | struct tmp102 *tmp102 = dev_get_drvdata(dev); |
149 | struct i2c_client *client = tmp102->client; | 129 | int reg = sda->index; |
150 | long val; | 130 | long val; |
151 | int status; | 131 | int err; |
152 | 132 | ||
153 | if (kstrtol(buf, 10, &val) < 0) | 133 | if (kstrtol(buf, 10, &val) < 0) |
154 | return -EINVAL; | 134 | return -EINVAL; |
155 | val = clamp_val(val, -256000, 255000); | 135 | val = clamp_val(val, -256000, 255000); |
156 | 136 | ||
157 | mutex_lock(&tmp102->lock); | 137 | err = regmap_write(tmp102->regmap, reg, tmp102_mC_to_reg(val)); |
158 | tmp102->temp[sda->index] = val; | 138 | return err ? : count; |
159 | status = i2c_smbus_write_word_swapped(client, tmp102_reg[sda->index], | ||
160 | tmp102_mC_to_reg(val)); | ||
161 | mutex_unlock(&tmp102->lock); | ||
162 | return status ? : count; | ||
163 | } | 139 | } |
164 | 140 | ||
165 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, tmp102_show_temp, NULL , 0); | 141 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, tmp102_show_temp, NULL, |
142 | TMP102_TEMP_REG); | ||
166 | 143 | ||
167 | static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, tmp102_show_temp, | 144 | static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, tmp102_show_temp, |
168 | tmp102_set_temp, 1); | 145 | tmp102_set_temp, TMP102_TLOW_REG); |
169 | 146 | ||
170 | static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, tmp102_show_temp, | 147 | static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, tmp102_show_temp, |
171 | tmp102_set_temp, 2); | 148 | tmp102_set_temp, TMP102_THIGH_REG); |
172 | 149 | ||
173 | static struct attribute *tmp102_attrs[] = { | 150 | static struct attribute *tmp102_attrs[] = { |
174 | &sensor_dev_attr_temp1_input.dev_attr.attr, | 151 | &sensor_dev_attr_temp1_input.dev_attr.attr, |
@@ -185,19 +162,39 @@ static const struct thermal_zone_of_device_ops tmp102_of_thermal_ops = { | |||
185 | static void tmp102_restore_config(void *data) | 162 | static void tmp102_restore_config(void *data) |
186 | { | 163 | { |
187 | struct tmp102 *tmp102 = data; | 164 | struct tmp102 *tmp102 = data; |
188 | struct i2c_client *client = tmp102->client; | ||
189 | 165 | ||
190 | i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, | 166 | regmap_write(tmp102->regmap, TMP102_CONF_REG, tmp102->config_orig); |
191 | tmp102->config_orig); | 167 | } |
168 | |||
169 | static bool tmp102_is_writeable_reg(struct device *dev, unsigned int reg) | ||
170 | { | ||
171 | return reg != TMP102_TEMP_REG; | ||
192 | } | 172 | } |
193 | 173 | ||
174 | static bool tmp102_is_volatile_reg(struct device *dev, unsigned int reg) | ||
175 | { | ||
176 | return reg == TMP102_TEMP_REG; | ||
177 | } | ||
178 | |||
179 | static const struct regmap_config tmp102_regmap_config = { | ||
180 | .reg_bits = 8, | ||
181 | .val_bits = 16, | ||
182 | .max_register = TMP102_THIGH_REG, | ||
183 | .writeable_reg = tmp102_is_writeable_reg, | ||
184 | .volatile_reg = tmp102_is_volatile_reg, | ||
185 | .val_format_endian = REGMAP_ENDIAN_BIG, | ||
186 | .cache_type = REGCACHE_RBTREE, | ||
187 | .use_single_rw = true, | ||
188 | }; | ||
189 | |||
194 | static int tmp102_probe(struct i2c_client *client, | 190 | static int tmp102_probe(struct i2c_client *client, |
195 | const struct i2c_device_id *id) | 191 | const struct i2c_device_id *id) |
196 | { | 192 | { |
197 | struct device *dev = &client->dev; | 193 | struct device *dev = &client->dev; |
198 | struct device *hwmon_dev; | 194 | struct device *hwmon_dev; |
199 | struct tmp102 *tmp102; | 195 | struct tmp102 *tmp102; |
200 | int status; | 196 | unsigned int regval; |
197 | int err; | ||
201 | 198 | ||
202 | if (!i2c_check_functionality(client->adapter, | 199 | if (!i2c_check_functionality(client->adapter, |
203 | I2C_FUNC_SMBUS_WORD_DATA)) { | 200 | I2C_FUNC_SMBUS_WORD_DATA)) { |
@@ -211,35 +208,36 @@ static int tmp102_probe(struct i2c_client *client, | |||
211 | return -ENOMEM; | 208 | return -ENOMEM; |
212 | 209 | ||
213 | i2c_set_clientdata(client, tmp102); | 210 | i2c_set_clientdata(client, tmp102); |
214 | tmp102->client = client; | ||
215 | 211 | ||
216 | status = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); | 212 | tmp102->regmap = devm_regmap_init_i2c(client, &tmp102_regmap_config); |
217 | if (status < 0) { | 213 | if (IS_ERR(tmp102->regmap)) |
214 | return PTR_ERR(tmp102->regmap); | ||
215 | |||
216 | err = regmap_read(tmp102->regmap, TMP102_CONF_REG, ®val); | ||
217 | if (err < 0) { | ||
218 | dev_err(dev, "error reading config register\n"); | 218 | dev_err(dev, "error reading config register\n"); |
219 | return status; | 219 | return err; |
220 | } | 220 | } |
221 | 221 | ||
222 | if ((status & ~TMP102_CONFREG_MASK) != | 222 | if ((regval & ~TMP102_CONFREG_MASK) != |
223 | (TMP102_CONF_R0 | TMP102_CONF_R1)) { | 223 | (TMP102_CONF_R0 | TMP102_CONF_R1)) { |
224 | dev_err(dev, "unexpected config register value\n"); | 224 | dev_err(dev, "unexpected config register value\n"); |
225 | return -ENODEV; | 225 | return -ENODEV; |
226 | } | 226 | } |
227 | 227 | ||
228 | tmp102->config_orig = status; | 228 | tmp102->config_orig = regval; |
229 | 229 | ||
230 | devm_add_action(dev, tmp102_restore_config, tmp102); | 230 | devm_add_action(dev, tmp102_restore_config, tmp102); |
231 | 231 | ||
232 | status &= ~TMP102_CONFIG_CLEAR; | 232 | regval &= ~TMP102_CONFIG_CLEAR; |
233 | status |= TMP102_CONFIG_SET; | 233 | regval |= TMP102_CONFIG_SET; |
234 | 234 | ||
235 | status = i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, status); | 235 | err = regmap_write(tmp102->regmap, TMP102_CONF_REG, regval); |
236 | if (status < 0) { | 236 | if (err < 0) { |
237 | dev_err(dev, "error writing config register\n"); | 237 | dev_err(dev, "error writing config register\n"); |
238 | return status; | 238 | return err; |
239 | } | 239 | } |
240 | 240 | ||
241 | mutex_init(&tmp102->lock); | ||
242 | |||
243 | tmp102->ready_time = jiffies; | 241 | tmp102->ready_time = jiffies; |
244 | if (tmp102->config_orig & TMP102_CONF_SD) { | 242 | if (tmp102->config_orig & TMP102_CONF_SD) { |
245 | /* | 243 | /* |
@@ -268,30 +266,24 @@ static int tmp102_probe(struct i2c_client *client, | |||
268 | static int tmp102_suspend(struct device *dev) | 266 | static int tmp102_suspend(struct device *dev) |
269 | { | 267 | { |
270 | struct i2c_client *client = to_i2c_client(dev); | 268 | struct i2c_client *client = to_i2c_client(dev); |
271 | int config; | 269 | struct tmp102 *tmp102 = i2c_get_clientdata(client); |
272 | |||
273 | config = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); | ||
274 | if (config < 0) | ||
275 | return config; | ||
276 | 270 | ||
277 | config |= TMP102_CONF_SD; | 271 | return regmap_update_bits(tmp102->regmap, TMP102_CONF_REG, |
278 | return i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, config); | 272 | TMP102_CONF_SD, TMP102_CONF_SD); |
279 | } | 273 | } |
280 | 274 | ||
281 | static int tmp102_resume(struct device *dev) | 275 | static int tmp102_resume(struct device *dev) |
282 | { | 276 | { |
283 | struct i2c_client *client = to_i2c_client(dev); | 277 | struct i2c_client *client = to_i2c_client(dev); |
284 | struct tmp102 *tmp102 = i2c_get_clientdata(client); | 278 | struct tmp102 *tmp102 = i2c_get_clientdata(client); |
285 | int config; | 279 | int err; |
286 | 280 | ||
287 | config = i2c_smbus_read_word_swapped(client, TMP102_CONF_REG); | 281 | err = regmap_update_bits(tmp102->regmap, TMP102_CONF_REG, |
288 | if (config < 0) | 282 | TMP102_CONF_SD, 0); |
289 | return config; | ||
290 | 283 | ||
291 | tmp102->ready_time = jiffies + msecs_to_jiffies(CONVERSION_TIME_MS); | 284 | tmp102->ready_time = jiffies + msecs_to_jiffies(CONVERSION_TIME_MS); |
292 | 285 | ||
293 | config &= ~TMP102_CONF_SD; | 286 | return err; |
294 | return i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, config); | ||
295 | } | 287 | } |
296 | #endif /* CONFIG_PM */ | 288 | #endif /* CONFIG_PM */ |
297 | 289 | ||