Skip to content

Commit 1653111

Browse files
NeroReflexjic23
authored andcommitted
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 <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jonathan Cameron <[email protected]>
1 parent 525e9cd commit 1653111

File tree

1 file changed

+159
-2
lines changed

1 file changed

+159
-2
lines changed

drivers/iio/imu/bmi323/bmi323_core.c

Lines changed: 159 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,38 @@ static const struct bmi323_hw bmi323_hw[2] = {
118118
},
119119
};
120120

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+
121153
struct bmi323_data {
122154
struct device *dev;
123155
struct regmap *regmap;
@@ -130,6 +162,7 @@ struct bmi323_data {
130162
u32 odrns[BMI323_SENSORS_CNT];
131163
u32 odrhz[BMI323_SENSORS_CNT];
132164
unsigned int feature_events;
165+
struct bmi323_regs_runtime_pm runtime_pm_status;
133166

134167
/*
135168
* Lock to protect the members of device's private data from concurrent
@@ -1972,6 +2005,11 @@ static void bmi323_disable(void *data_ptr)
19722005

19732006
bmi323_set_mode(data, BMI323_ACCEL, ACC_GYRO_MODE_DISABLE);
19742007
bmi323_set_mode(data, BMI323_GYRO, ACC_GYRO_MODE_DISABLE);
2008+
2009+
/*
2010+
* Place the peripheral in its lowest power consuming state.
2011+
*/
2012+
regmap_write(data->regmap, BMI323_CMD_REG, BMI323_RST_VAL);
19752013
}
19762014

19772015
static int bmi323_set_bw(struct bmi323_data *data,
@@ -2030,6 +2068,13 @@ static int bmi323_init(struct bmi323_data *data)
20302068
return dev_err_probe(data->dev, -EINVAL,
20312069
"Sensor power error = 0x%x\n", val);
20322070

2071+
return 0;
2072+
}
2073+
2074+
static int bmi323_init_reset(struct bmi323_data *data)
2075+
{
2076+
int ret;
2077+
20332078
/*
20342079
* Set the Bandwidth coefficient which defines the 3 dB cutoff
20352080
* frequency in relation to the ODR.
@@ -2078,12 +2123,18 @@ int bmi323_core_probe(struct device *dev)
20782123
data = iio_priv(indio_dev);
20792124
data->dev = dev;
20802125
data->regmap = regmap;
2126+
data->irq_pin = BMI323_IRQ_DISABLED;
2127+
data->state = BMI323_IDLE;
20812128
mutex_init(&data->mutex);
20822129

20832130
ret = bmi323_init(data);
20842131
if (ret)
20852132
return -EINVAL;
20862133

2134+
ret = bmi323_init_reset(data);
2135+
if (ret)
2136+
return -EINVAL;
2137+
20872138
if (!iio_read_acpi_mount_matrix(dev, &data->orientation, "ROTM")) {
20882139
ret = iio_read_mount_matrix(dev, &data->orientation);
20892140
if (ret)
@@ -2117,21 +2168,127 @@ int bmi323_core_probe(struct device *dev)
21172168
return dev_err_probe(data->dev, ret,
21182169
"Unable to register iio device\n");
21192170

2120-
return 0;
2171+
return bmi323_fifo_disable(data);
21212172
}
21222173
EXPORT_SYMBOL_NS_GPL(bmi323_core_probe, IIO_BMI323);
21232174

21242175
#if defined(CONFIG_PM)
21252176
static int bmi323_core_runtime_suspend(struct device *dev)
21262177
{
21272178
struct iio_dev *indio_dev = dev_get_drvdata(dev);
2179+
struct bmi323_data *data = iio_priv(indio_dev);
2180+
struct bmi323_regs_runtime_pm *savestate = &data->runtime_pm_status;
2181+
int ret;
2182+
2183+
guard(mutex)(&data->mutex);
21282184

2129-
return iio_device_suspend_triggering(indio_dev);
2185+
ret = iio_device_suspend_triggering(indio_dev);
2186+
if (ret)
2187+
return ret;
2188+
2189+
/* Save registers meant to be restored by resume pm callback. */
2190+
for (unsigned int i = 0; i < ARRAY_SIZE(bmi323_reg_savestate); i++) {
2191+
ret = regmap_read(data->regmap, bmi323_reg_savestate[i],
2192+
&savestate->reg_settings[i]);
2193+
if (ret) {
2194+
dev_err(data->dev,
2195+
"Error reading bmi323 reg 0x%x: %d\n",
2196+
bmi323_reg_savestate[i], ret);
2197+
return ret;
2198+
}
2199+
}
2200+
2201+
for (unsigned int i = 0; i < ARRAY_SIZE(bmi323_ext_reg_savestate); i++) {
2202+
ret = bmi323_read_ext_reg(data, bmi323_reg_savestate[i],
2203+
&savestate->reg_settings[i]);
2204+
if (ret) {
2205+
dev_err(data->dev,
2206+
"Error reading bmi323 external reg 0x%x: %d\n",
2207+
bmi323_reg_savestate[i], ret);
2208+
return ret;
2209+
}
2210+
}
2211+
2212+
/* Perform soft reset to place the device in its lowest power state. */
2213+
ret = regmap_write(data->regmap, BMI323_CMD_REG, BMI323_RST_VAL);
2214+
if (ret)
2215+
return ret;
2216+
2217+
return 0;
21302218
}
21312219

21322220
static int bmi323_core_runtime_resume(struct device *dev)
21332221
{
21342222
struct iio_dev *indio_dev = dev_get_drvdata(dev);
2223+
struct bmi323_data *data = iio_priv(indio_dev);
2224+
struct bmi323_regs_runtime_pm *savestate = &data->runtime_pm_status;
2225+
unsigned int val;
2226+
int ret;
2227+
2228+
guard(mutex)(&data->mutex);
2229+
2230+
/*
2231+
* Perform the device power-on and initial setup once again
2232+
* after being reset in the lower power state by runtime-pm.
2233+
*/
2234+
ret = bmi323_init(data);
2235+
if (!ret)
2236+
return ret;
2237+
2238+
/* Register must be cleared before changing an active config */
2239+
ret = regmap_write(data->regmap, BMI323_FEAT_IO0_REG, 0);
2240+
if (ret) {
2241+
dev_err(data->dev, "Error stopping feature engine\n");
2242+
return ret;
2243+
}
2244+
2245+
for (unsigned int i = 0; i < ARRAY_SIZE(bmi323_ext_reg_savestate); i++) {
2246+
ret = bmi323_write_ext_reg(data, bmi323_reg_savestate[i],
2247+
savestate->reg_settings[i]);
2248+
if (ret) {
2249+
dev_err(data->dev,
2250+
"Error writing bmi323 external reg 0x%x: %d\n",
2251+
bmi323_reg_savestate[i], ret);
2252+
return ret;
2253+
}
2254+
}
2255+
2256+
for (unsigned int i = 0; i < ARRAY_SIZE(bmi323_reg_savestate); i++) {
2257+
ret = regmap_write(data->regmap, bmi323_reg_savestate[i],
2258+
savestate->reg_settings[i]);
2259+
if (ret) {
2260+
dev_err(data->dev,
2261+
"Error writing bmi323 reg 0x%x: %d\n",
2262+
bmi323_reg_savestate[i], ret);
2263+
return ret;
2264+
}
2265+
}
2266+
2267+
/*
2268+
* Clear old FIFO samples that might be generated before suspend
2269+
* or generated from a peripheral state not equal to the saved one.
2270+
*/
2271+
if (data->state == BMI323_BUFFER_FIFO) {
2272+
ret = regmap_write(data->regmap, BMI323_FIFO_CTRL_REG,
2273+
BMI323_FIFO_FLUSH_MSK);
2274+
if (ret) {
2275+
dev_err(data->dev, "Error flushing FIFO buffer: %d\n", ret);
2276+
return ret;
2277+
}
2278+
}
2279+
2280+
ret = regmap_read(data->regmap, BMI323_ERR_REG, &val);
2281+
if (ret) {
2282+
dev_err(data->dev,
2283+
"Error reading bmi323 error register: %d\n", ret);
2284+
return ret;
2285+
}
2286+
2287+
if (val) {
2288+
dev_err(data->dev,
2289+
"Sensor power error in PM = 0x%x\n", val);
2290+
return -EINVAL;
2291+
}
21352292

21362293
return iio_device_resume_triggering(indio_dev);
21372294
}

0 commit comments

Comments
 (0)