Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iio: temperature: tmp006: make sure the chip is powered up in probe

When the device is probed, there's no guarantee that the device is not in
power-down mode. This can happen if the driver is unregistered and
re-probed.

To make sure this doesn't happen, the value of the TMP006_CONFIG register
(which is read in the probe function and stored in the device's private
data) is being checked to see if the MOD bits have the correct value.

This is a fix for a somewhat-rare corner case. As it stands, this doesn't
look like a high priority to go into the Fixes route.

Signed-off-by: Alexandru Ardelean <aardelean@deviqon.com>
Link: https://lore.kernel.org/r/20210624081924.15897-2-aardelean@deviqon.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Alexandru Ardelean and committed by
Jonathan Cameron
c359a80c 2bb3b8f6

+22 -11
+22 -11
drivers/iio/temperature/tmp006.c
··· 193 193 return mid == TMP006_MANUFACTURER_MAGIC && did == TMP006_DEVICE_MAGIC; 194 194 } 195 195 196 - static int tmp006_powerdown(struct tmp006_data *data) 196 + static int tmp006_power(struct device *dev, bool up) 197 197 { 198 + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); 199 + struct tmp006_data *data = iio_priv(indio_dev); 200 + 201 + if (up) 202 + data->config |= TMP006_CONFIG_MOD_MASK; 203 + else 204 + data->config &= ~TMP006_CONFIG_MOD_MASK; 205 + 198 206 return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG, 199 - data->config & ~TMP006_CONFIG_MOD_MASK); 207 + data->config); 200 208 } 201 209 202 - static void tmp006_powerdown_cleanup(void *data) 210 + static void tmp006_powerdown_cleanup(void *dev) 203 211 { 204 - tmp006_powerdown(data); 212 + tmp006_power(dev, false); 205 213 } 206 214 207 215 static int tmp006_probe(struct i2c_client *client, ··· 247 239 return ret; 248 240 data->config = ret; 249 241 250 - ret = devm_add_action(&client->dev, tmp006_powerdown_cleanup, data); 242 + if ((ret & TMP006_CONFIG_MOD_MASK) != TMP006_CONFIG_MOD_MASK) { 243 + ret = tmp006_power(&client->dev, true); 244 + if (ret < 0) 245 + return ret; 246 + } 247 + 248 + ret = devm_add_action_or_reset(&client->dev, tmp006_powerdown_cleanup, 249 + &client->dev); 251 250 if (ret < 0) 252 251 return ret; 253 252 ··· 264 249 #ifdef CONFIG_PM_SLEEP 265 250 static int tmp006_suspend(struct device *dev) 266 251 { 267 - struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); 268 - return tmp006_powerdown(iio_priv(indio_dev)); 252 + return tmp006_power(dev, false); 269 253 } 270 254 271 255 static int tmp006_resume(struct device *dev) 272 256 { 273 - struct tmp006_data *data = iio_priv(i2c_get_clientdata( 274 - to_i2c_client(dev))); 275 - return i2c_smbus_write_word_swapped(data->client, TMP006_CONFIG, 276 - data->config | TMP006_CONFIG_MOD_MASK); 257 + return tmp006_power(dev, true); 277 258 } 278 259 #endif 279 260