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

Configure Feed

Select the types of activity you want to include in your feed.

iio: bmi323: peripheral in lowest power state on suspend

The bmi323 is mounted on some devices that are powered
by an internal battery: help in reducing system overall power drain
while the system is in s2idle or the imu driver is not loaded
by resetting it in its lowest power draining state.

Signed-off-by: Denis Benato <benato.denis96@gmail.com>
Link: https://patch.msgid.link/20240824141122.334620-2-benato.denis96@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Denis Benato and committed by
Jonathan Cameron
16531118 525e9cd5

+159 -2
+159 -2
drivers/iio/imu/bmi323/bmi323_core.c
··· 118 118 }, 119 119 }; 120 120 121 + static const unsigned int bmi323_reg_savestate[] = { 122 + BMI323_INT_MAP1_REG, 123 + BMI323_INT_MAP2_REG, 124 + BMI323_IO_INT_CTR_REG, 125 + BMI323_IO_INT_CONF_REG, 126 + BMI323_ACC_CONF_REG, 127 + BMI323_GYRO_CONF_REG, 128 + BMI323_FEAT_IO0_REG, 129 + BMI323_FIFO_WTRMRK_REG, 130 + BMI323_FIFO_CONF_REG 131 + }; 132 + 133 + static const unsigned int bmi323_ext_reg_savestate[] = { 134 + BMI323_GEN_SET1_REG, 135 + BMI323_TAP1_REG, 136 + BMI323_TAP2_REG, 137 + BMI323_TAP3_REG, 138 + BMI323_FEAT_IO0_S_TAP_MSK, 139 + BMI323_STEP_SC1_REG, 140 + BMI323_ANYMO1_REG, 141 + BMI323_NOMO1_REG, 142 + BMI323_ANYMO1_REG + BMI323_MO2_OFFSET, 143 + BMI323_NOMO1_REG + BMI323_MO2_OFFSET, 144 + BMI323_ANYMO1_REG + BMI323_MO3_OFFSET, 145 + BMI323_NOMO1_REG + BMI323_MO3_OFFSET 146 + }; 147 + 148 + struct bmi323_regs_runtime_pm { 149 + unsigned int reg_settings[ARRAY_SIZE(bmi323_reg_savestate)]; 150 + unsigned int ext_reg_settings[ARRAY_SIZE(bmi323_ext_reg_savestate)]; 151 + }; 152 + 121 153 struct bmi323_data { 122 154 struct device *dev; 123 155 struct regmap *regmap; ··· 162 130 u32 odrns[BMI323_SENSORS_CNT]; 163 131 u32 odrhz[BMI323_SENSORS_CNT]; 164 132 unsigned int feature_events; 133 + struct bmi323_regs_runtime_pm runtime_pm_status; 165 134 166 135 /* 167 136 * Lock to protect the members of device's private data from concurrent ··· 2005 1972 2006 1973 bmi323_set_mode(data, BMI323_ACCEL, ACC_GYRO_MODE_DISABLE); 2007 1974 bmi323_set_mode(data, BMI323_GYRO, ACC_GYRO_MODE_DISABLE); 1975 + 1976 + /* 1977 + * Place the peripheral in its lowest power consuming state. 1978 + */ 1979 + regmap_write(data->regmap, BMI323_CMD_REG, BMI323_RST_VAL); 2008 1980 } 2009 1981 2010 1982 static int bmi323_set_bw(struct bmi323_data *data, ··· 2068 2030 return dev_err_probe(data->dev, -EINVAL, 2069 2031 "Sensor power error = 0x%x\n", val); 2070 2032 2033 + return 0; 2034 + } 2035 + 2036 + static int bmi323_init_reset(struct bmi323_data *data) 2037 + { 2038 + int ret; 2039 + 2071 2040 /* 2072 2041 * Set the Bandwidth coefficient which defines the 3 dB cutoff 2073 2042 * frequency in relation to the ODR. ··· 2123 2078 data = iio_priv(indio_dev); 2124 2079 data->dev = dev; 2125 2080 data->regmap = regmap; 2081 + data->irq_pin = BMI323_IRQ_DISABLED; 2082 + data->state = BMI323_IDLE; 2126 2083 mutex_init(&data->mutex); 2127 2084 2128 2085 ret = bmi323_init(data); 2086 + if (ret) 2087 + return -EINVAL; 2088 + 2089 + ret = bmi323_init_reset(data); 2129 2090 if (ret) 2130 2091 return -EINVAL; 2131 2092 ··· 2168 2117 return dev_err_probe(data->dev, ret, 2169 2118 "Unable to register iio device\n"); 2170 2119 2171 - return 0; 2120 + return bmi323_fifo_disable(data); 2172 2121 } 2173 2122 EXPORT_SYMBOL_NS_GPL(bmi323_core_probe, IIO_BMI323); 2174 2123 ··· 2176 2125 static int bmi323_core_runtime_suspend(struct device *dev) 2177 2126 { 2178 2127 struct iio_dev *indio_dev = dev_get_drvdata(dev); 2128 + struct bmi323_data *data = iio_priv(indio_dev); 2129 + struct bmi323_regs_runtime_pm *savestate = &data->runtime_pm_status; 2130 + int ret; 2179 2131 2180 - return iio_device_suspend_triggering(indio_dev); 2132 + guard(mutex)(&data->mutex); 2133 + 2134 + ret = iio_device_suspend_triggering(indio_dev); 2135 + if (ret) 2136 + return ret; 2137 + 2138 + /* Save registers meant to be restored by resume pm callback. */ 2139 + for (unsigned int i = 0; i < ARRAY_SIZE(bmi323_reg_savestate); i++) { 2140 + ret = regmap_read(data->regmap, bmi323_reg_savestate[i], 2141 + &savestate->reg_settings[i]); 2142 + if (ret) { 2143 + dev_err(data->dev, 2144 + "Error reading bmi323 reg 0x%x: %d\n", 2145 + bmi323_reg_savestate[i], ret); 2146 + return ret; 2147 + } 2148 + } 2149 + 2150 + for (unsigned int i = 0; i < ARRAY_SIZE(bmi323_ext_reg_savestate); i++) { 2151 + ret = bmi323_read_ext_reg(data, bmi323_reg_savestate[i], 2152 + &savestate->reg_settings[i]); 2153 + if (ret) { 2154 + dev_err(data->dev, 2155 + "Error reading bmi323 external reg 0x%x: %d\n", 2156 + bmi323_reg_savestate[i], ret); 2157 + return ret; 2158 + } 2159 + } 2160 + 2161 + /* Perform soft reset to place the device in its lowest power state. */ 2162 + ret = regmap_write(data->regmap, BMI323_CMD_REG, BMI323_RST_VAL); 2163 + if (ret) 2164 + return ret; 2165 + 2166 + return 0; 2181 2167 } 2182 2168 2183 2169 static int bmi323_core_runtime_resume(struct device *dev) 2184 2170 { 2185 2171 struct iio_dev *indio_dev = dev_get_drvdata(dev); 2172 + struct bmi323_data *data = iio_priv(indio_dev); 2173 + struct bmi323_regs_runtime_pm *savestate = &data->runtime_pm_status; 2174 + unsigned int val; 2175 + int ret; 2176 + 2177 + guard(mutex)(&data->mutex); 2178 + 2179 + /* 2180 + * Perform the device power-on and initial setup once again 2181 + * after being reset in the lower power state by runtime-pm. 2182 + */ 2183 + ret = bmi323_init(data); 2184 + if (!ret) 2185 + return ret; 2186 + 2187 + /* Register must be cleared before changing an active config */ 2188 + ret = regmap_write(data->regmap, BMI323_FEAT_IO0_REG, 0); 2189 + if (ret) { 2190 + dev_err(data->dev, "Error stopping feature engine\n"); 2191 + return ret; 2192 + } 2193 + 2194 + for (unsigned int i = 0; i < ARRAY_SIZE(bmi323_ext_reg_savestate); i++) { 2195 + ret = bmi323_write_ext_reg(data, bmi323_reg_savestate[i], 2196 + savestate->reg_settings[i]); 2197 + if (ret) { 2198 + dev_err(data->dev, 2199 + "Error writing bmi323 external reg 0x%x: %d\n", 2200 + bmi323_reg_savestate[i], ret); 2201 + return ret; 2202 + } 2203 + } 2204 + 2205 + for (unsigned int i = 0; i < ARRAY_SIZE(bmi323_reg_savestate); i++) { 2206 + ret = regmap_write(data->regmap, bmi323_reg_savestate[i], 2207 + savestate->reg_settings[i]); 2208 + if (ret) { 2209 + dev_err(data->dev, 2210 + "Error writing bmi323 reg 0x%x: %d\n", 2211 + bmi323_reg_savestate[i], ret); 2212 + return ret; 2213 + } 2214 + } 2215 + 2216 + /* 2217 + * Clear old FIFO samples that might be generated before suspend 2218 + * or generated from a peripheral state not equal to the saved one. 2219 + */ 2220 + if (data->state == BMI323_BUFFER_FIFO) { 2221 + ret = regmap_write(data->regmap, BMI323_FIFO_CTRL_REG, 2222 + BMI323_FIFO_FLUSH_MSK); 2223 + if (ret) { 2224 + dev_err(data->dev, "Error flushing FIFO buffer: %d\n", ret); 2225 + return ret; 2226 + } 2227 + } 2228 + 2229 + ret = regmap_read(data->regmap, BMI323_ERR_REG, &val); 2230 + if (ret) { 2231 + dev_err(data->dev, 2232 + "Error reading bmi323 error register: %d\n", ret); 2233 + return ret; 2234 + } 2235 + 2236 + if (val) { 2237 + dev_err(data->dev, 2238 + "Sensor power error in PM = 0x%x\n", val); 2239 + return -EINVAL; 2240 + } 2186 2241 2187 2242 return iio_device_resume_triggering(indio_dev); 2188 2243 }