iio: accel: mxc4005: Reset chip on probe() and resume()
[ Upstream commit 6b8cffdc4a31e4a72f75ecd1bc13fbf0dafee390 ] On some designs the chip is not properly reset when powered up at boot or after a suspend/resume cycle. Use the sw-reset feature to ensure that the chip is in a clean state after probe() / resume() and in the case of resume() restore the settings (scale, trigger-enabled). Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218578 Signed-off-by: Hans de Goede <hdegoede@redhat.com> Link: https://lore.kernel.org/r/20240326113700.56725-3-hdegoede@redhat.com Cc: <Stable@vger.kernel.org> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
02db59533b
commit
5253a35ea5
@ -5,6 +5,7 @@
|
|||||||
* Copyright (c) 2014, Intel Corporation.
|
* Copyright (c) 2014, Intel Corporation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/iio/iio.h>
|
#include <linux/iio/iio.h>
|
||||||
@ -36,6 +37,7 @@
|
|||||||
|
|
||||||
#define MXC4005_REG_INT_CLR1 0x01
|
#define MXC4005_REG_INT_CLR1 0x01
|
||||||
#define MXC4005_REG_INT_CLR1_BIT_DRDYC 0x01
|
#define MXC4005_REG_INT_CLR1_BIT_DRDYC 0x01
|
||||||
|
#define MXC4005_REG_INT_CLR1_SW_RST 0x10
|
||||||
|
|
||||||
#define MXC4005_REG_CONTROL 0x0D
|
#define MXC4005_REG_CONTROL 0x0D
|
||||||
#define MXC4005_REG_CONTROL_MASK_FSR GENMASK(6, 5)
|
#define MXC4005_REG_CONTROL_MASK_FSR GENMASK(6, 5)
|
||||||
@ -43,6 +45,9 @@
|
|||||||
|
|
||||||
#define MXC4005_REG_DEVICE_ID 0x0E
|
#define MXC4005_REG_DEVICE_ID 0x0E
|
||||||
|
|
||||||
|
/* Datasheet does not specify a reset time, this is a conservative guess */
|
||||||
|
#define MXC4005_RESET_TIME_US 2000
|
||||||
|
|
||||||
enum mxc4005_axis {
|
enum mxc4005_axis {
|
||||||
AXIS_X,
|
AXIS_X,
|
||||||
AXIS_Y,
|
AXIS_Y,
|
||||||
@ -66,6 +71,8 @@ struct mxc4005_data {
|
|||||||
s64 timestamp __aligned(8);
|
s64 timestamp __aligned(8);
|
||||||
} scan;
|
} scan;
|
||||||
bool trigger_enabled;
|
bool trigger_enabled;
|
||||||
|
unsigned int control;
|
||||||
|
unsigned int int_mask1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -349,6 +356,7 @@ static int mxc4005_set_trigger_state(struct iio_trigger *trig,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data->int_mask1 = val;
|
||||||
data->trigger_enabled = state;
|
data->trigger_enabled = state;
|
||||||
mutex_unlock(&data->mutex);
|
mutex_unlock(&data->mutex);
|
||||||
|
|
||||||
@ -384,6 +392,13 @@ static int mxc4005_chip_init(struct mxc4005_data *data)
|
|||||||
|
|
||||||
dev_dbg(data->dev, "MXC4005 chip id %02x\n", reg);
|
dev_dbg(data->dev, "MXC4005 chip id %02x\n", reg);
|
||||||
|
|
||||||
|
ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1,
|
||||||
|
MXC4005_REG_INT_CLR1_SW_RST);
|
||||||
|
if (ret < 0)
|
||||||
|
return dev_err_probe(data->dev, ret, "resetting chip\n");
|
||||||
|
|
||||||
|
fsleep(MXC4005_RESET_TIME_US);
|
||||||
|
|
||||||
ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK0, 0);
|
ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK0, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return dev_err_probe(data->dev, ret, "writing INT_MASK0\n");
|
return dev_err_probe(data->dev, ret, "writing INT_MASK0\n");
|
||||||
@ -480,6 +495,58 @@ static int mxc4005_probe(struct i2c_client *client,
|
|||||||
return devm_iio_device_register(&client->dev, indio_dev);
|
return devm_iio_device_register(&client->dev, indio_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mxc4005_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||||
|
struct mxc4005_data *data = iio_priv(indio_dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Save control to restore it on resume */
|
||||||
|
ret = regmap_read(data->regmap, MXC4005_REG_CONTROL, &data->control);
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(data->dev, "failed to read reg_control\n");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mxc4005_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||||
|
struct mxc4005_data *data = iio_priv(indio_dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = regmap_write(data->regmap, MXC4005_REG_INT_CLR1,
|
||||||
|
MXC4005_REG_INT_CLR1_SW_RST);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(data->dev, "failed to reset chip: %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
fsleep(MXC4005_RESET_TIME_US);
|
||||||
|
|
||||||
|
ret = regmap_write(data->regmap, MXC4005_REG_CONTROL, data->control);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(data->dev, "failed to restore control register\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK0, 0);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(data->dev, "failed to restore interrupt 0 mask\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = regmap_write(data->regmap, MXC4005_REG_INT_MASK1, data->int_mask1);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(data->dev, "failed to restore interrupt 1 mask\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEFINE_SIMPLE_DEV_PM_OPS(mxc4005_pm_ops, mxc4005_suspend, mxc4005_resume);
|
||||||
|
|
||||||
static const struct acpi_device_id mxc4005_acpi_match[] = {
|
static const struct acpi_device_id mxc4005_acpi_match[] = {
|
||||||
{"MXC4005", 0},
|
{"MXC4005", 0},
|
||||||
{"MXC6655", 0},
|
{"MXC6655", 0},
|
||||||
@ -506,6 +573,7 @@ static struct i2c_driver mxc4005_driver = {
|
|||||||
.name = MXC4005_DRV_NAME,
|
.name = MXC4005_DRV_NAME,
|
||||||
.acpi_match_table = ACPI_PTR(mxc4005_acpi_match),
|
.acpi_match_table = ACPI_PTR(mxc4005_acpi_match),
|
||||||
.of_match_table = mxc4005_of_match,
|
.of_match_table = mxc4005_of_match,
|
||||||
|
.pm = pm_sleep_ptr(&mxc4005_pm_ops),
|
||||||
},
|
},
|
||||||
.probe = mxc4005_probe,
|
.probe = mxc4005_probe,
|
||||||
.id_table = mxc4005_id,
|
.id_table = mxc4005_id,
|
||||||
|
Loading…
Reference in New Issue
Block a user