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

iio: pressure: mpl115: Implementing low power mode by shutdown gpio

MPL115 supports shutdown gpio which can be used to set the state
to low power mode. Power from all internal circuits and
registers is removed. This is done by pulling the SHDN pin to low.
This patch enables runtime PM on MPL115 to increase power savings.

According to spec., a wakeup time period of ~5 ms exists between
waking up and actually communicating with the device. This is
implemented using sleep delay.

Signed-off-by: Rajat Khandelwal <rajat.khandelwal@linux.intel.com>
Link: https://lore.kernel.org/r/20221010173720.568916-1-rajat.khandelwal@linux.intel.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Rajat Khandelwal and committed by
Jonathan Cameron
0c3a3335 16afe125

+68 -1
+61 -1
drivers/iio/pressure/mpl115.c
··· 4 4 * 5 5 * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net> 6 6 * 7 - * TODO: shutdown pin 7 + * TODO: synchronization with system suspend 8 8 */ 9 9 10 10 #include <linux/module.h> 11 11 #include <linux/iio/iio.h> 12 12 #include <linux/delay.h> 13 + #include <linux/gpio/consumer.h> 13 14 14 15 #include "mpl115.h" 15 16 ··· 28 27 s16 a0; 29 28 s16 b1, b2; 30 29 s16 c12; 30 + struct gpio_desc *shutdown; 31 31 const struct mpl115_ops *ops; 32 32 }; 33 33 ··· 104 102 105 103 switch (mask) { 106 104 case IIO_CHAN_INFO_PROCESSED: 105 + pm_runtime_get_sync(data->dev); 107 106 ret = mpl115_comp_pressure(data, val, val2); 108 107 if (ret < 0) 109 108 return ret; 109 + pm_runtime_mark_last_busy(data->dev); 110 + pm_runtime_put_autosuspend(data->dev); 111 + 110 112 return IIO_VAL_INT_PLUS_MICRO; 111 113 case IIO_CHAN_INFO_RAW: 114 + pm_runtime_get_sync(data->dev); 112 115 /* temperature -5.35 C / LSB, 472 LSB is 25 C */ 113 116 ret = mpl115_read_temp(data); 114 117 if (ret < 0) 115 118 return ret; 119 + pm_runtime_mark_last_busy(data->dev); 120 + pm_runtime_put_autosuspend(data->dev); 116 121 *val = ret >> 6; 122 + 117 123 return IIO_VAL_INT; 118 124 case IIO_CHAN_INFO_OFFSET: 119 125 *val = -605; ··· 178 168 if (ret) 179 169 return ret; 180 170 171 + dev_set_drvdata(dev, indio_dev); 172 + 181 173 ret = data->ops->read(data->dev, MPL115_A0); 182 174 if (ret < 0) 183 175 return ret; ··· 197 185 return ret; 198 186 data->c12 = ret; 199 187 188 + data->shutdown = devm_gpiod_get_optional(dev, "shutdown", 189 + GPIOD_OUT_LOW); 190 + if (IS_ERR(data->shutdown)) 191 + return dev_err_probe(dev, PTR_ERR(data->shutdown), 192 + "cannot get shutdown gpio\n"); 193 + 194 + if (data->shutdown) { 195 + /* Enable runtime PM */ 196 + pm_runtime_get_noresume(dev); 197 + pm_runtime_set_active(dev); 198 + pm_runtime_enable(dev); 199 + 200 + /* 201 + * As the device takes 3 ms to come up with a fresh 202 + * reading after power-on and 5 ms to actually power-on, 203 + * do not shut it down unnecessarily. Set autosuspend to 204 + * 2000 ms. 205 + */ 206 + pm_runtime_set_autosuspend_delay(dev, 2000); 207 + pm_runtime_use_autosuspend(dev); 208 + pm_runtime_put(dev); 209 + 210 + dev_dbg(dev, "low-power mode enabled"); 211 + } else 212 + dev_dbg(dev, "low-power mode disabled"); 213 + 200 214 return devm_iio_device_register(dev, indio_dev); 201 215 } 202 216 EXPORT_SYMBOL_NS_GPL(mpl115_probe, IIO_MPL115); 217 + 218 + static int mpl115_runtime_suspend(struct device *dev) 219 + { 220 + struct mpl115_data *data = iio_priv(dev_get_drvdata(dev)); 221 + 222 + gpiod_set_value(data->shutdown, 1); 223 + 224 + return 0; 225 + } 226 + 227 + static int mpl115_runtime_resume(struct device *dev) 228 + { 229 + struct mpl115_data *data = iio_priv(dev_get_drvdata(dev)); 230 + 231 + gpiod_set_value(data->shutdown, 0); 232 + usleep_range(5000, 6000); 233 + 234 + return 0; 235 + } 236 + 237 + EXPORT_NS_RUNTIME_DEV_PM_OPS(mpl115_dev_pm_ops, mpl115_runtime_suspend, 238 + mpl115_runtime_resume, NULL, IIO_MPL115); 203 239 204 240 MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); 205 241 MODULE_DESCRIPTION("Freescale MPL115 pressure/temperature driver");
+5
drivers/iio/pressure/mpl115.h
··· 6 6 * Copyright (c) 2016 Akinobu Mita <akinobu.mita@gmail.com> 7 7 */ 8 8 9 + #include <linux/pm_runtime.h> 10 + 9 11 #ifndef _MPL115_H_ 10 12 #define _MPL115_H_ 11 13 ··· 19 17 20 18 int mpl115_probe(struct device *dev, const char *name, 21 19 const struct mpl115_ops *ops); 20 + 21 + /*PM ops */ 22 + extern const struct dev_pm_ops mpl115_dev_pm_ops; 22 23 23 24 #endif
+1
drivers/iio/pressure/mpl115_i2c.c
··· 53 53 static struct i2c_driver mpl115_i2c_driver = { 54 54 .driver = { 55 55 .name = "mpl115", 56 + .pm = pm_ptr(&mpl115_dev_pm_ops), 56 57 }, 57 58 .probe = mpl115_i2c_probe, 58 59 .id_table = mpl115_i2c_id,
+1
drivers/iio/pressure/mpl115_spi.c
··· 92 92 static struct spi_driver mpl115_spi_driver = { 93 93 .driver = { 94 94 .name = "mpl115", 95 + .pm = pm_ptr(&mpl115_dev_pm_ops), 95 96 }, 96 97 .probe = mpl115_spi_probe, 97 98 .id_table = mpl115_spi_ids,