mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-28 22:54:05 +08:00
iio: light: bu27008: add chip info
The ROHM BU27010 RGB + flickering sensor is in many regards similar to the BU27008. Prepare for adding support for BU27010 by allowing chip-specific properties to be brought from the of_device_id data. Signed-off-by: Matti Vaittinen <mazziesaccount@gmail.com> Link: https://lore.kernel.org/r/d5994648033d5513993b8d72eb186ddda211b5ac.1690958450.git.mazziesaccount@gmail.com Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
parent
ce2a8c1600
commit
ccca97fb3c
@ -211,7 +211,35 @@ static const struct iio_chan_spec bu27008_channels[] = {
|
||||
IIO_CHAN_SOFT_TIMESTAMP(BU27008_NUM_CHANS),
|
||||
};
|
||||
|
||||
struct bu27008_data;
|
||||
|
||||
struct bu27_chip_data {
|
||||
const char *name;
|
||||
int (*chip_init)(struct bu27008_data *data);
|
||||
int (*get_gain_sel)(struct bu27008_data *data, int *sel);
|
||||
int (*write_gain_sel)(struct bu27008_data *data, int sel);
|
||||
const struct regmap_config *regmap_cfg;
|
||||
const struct iio_gain_sel_pair *gains;
|
||||
const struct iio_gain_sel_pair *gains_ir;
|
||||
const struct iio_itime_sel_mul *itimes;
|
||||
int num_gains;
|
||||
int num_gains_ir;
|
||||
int num_itimes;
|
||||
int scale1x;
|
||||
|
||||
int drdy_en_reg;
|
||||
int drdy_en_mask;
|
||||
int meas_en_reg;
|
||||
int meas_en_mask;
|
||||
int valid_reg;
|
||||
int chan_sel_reg;
|
||||
int chan_sel_mask;
|
||||
int int_time_mask;
|
||||
u8 part_id;
|
||||
};
|
||||
|
||||
struct bu27008_data {
|
||||
const struct bu27_chip_data *cd;
|
||||
struct regmap *regmap;
|
||||
struct iio_trigger *trig;
|
||||
struct device *dev;
|
||||
@ -282,51 +310,6 @@ static const struct regmap_config bu27008_regmap = {
|
||||
.disable_locking = true,
|
||||
};
|
||||
|
||||
#define BU27008_MAX_VALID_RESULT_WAIT_US 50000
|
||||
#define BU27008_VALID_RESULT_WAIT_QUANTA_US 1000
|
||||
|
||||
static int bu27008_chan_read_data(struct bu27008_data *data, int reg, int *val)
|
||||
{
|
||||
int ret, valid;
|
||||
__le16 tmp;
|
||||
|
||||
ret = regmap_read_poll_timeout(data->regmap, BU27008_REG_MODE_CONTROL3,
|
||||
valid, (valid & BU27008_MASK_VALID),
|
||||
BU27008_VALID_RESULT_WAIT_QUANTA_US,
|
||||
BU27008_MAX_VALID_RESULT_WAIT_US);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_bulk_read(data->regmap, reg, &tmp, sizeof(tmp));
|
||||
if (ret)
|
||||
dev_err(data->dev, "Reading channel data failed\n");
|
||||
|
||||
*val = le16_to_cpu(tmp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bu27008_get_gain(struct bu27008_data *data, struct iio_gts *gts, int *gain)
|
||||
{
|
||||
int ret, sel;
|
||||
|
||||
ret = regmap_read(data->regmap, BU27008_REG_MODE_CONTROL2, &sel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
sel = FIELD_GET(BU27008_MASK_RGBC_GAIN, sel);
|
||||
|
||||
ret = iio_gts_find_gain_by_sel(gts, sel);
|
||||
if (ret < 0) {
|
||||
dev_err(data->dev, "unknown gain value 0x%x\n", sel);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*gain = ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bu27008_write_gain_sel(struct bu27008_data *data, int sel)
|
||||
{
|
||||
int regval;
|
||||
@ -368,6 +351,123 @@ static int bu27008_write_gain_sel(struct bu27008_data *data, int sel)
|
||||
BU27008_MASK_RGBC_GAIN, regval);
|
||||
}
|
||||
|
||||
static int bu27008_get_gain_sel(struct bu27008_data *data, int *sel)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* If we always "lock" the gain selectors for all channels to prevent
|
||||
* unsupported configs, then it does not matter which channel is used
|
||||
* we can just return selector from any of them.
|
||||
*
|
||||
* This, however is not true if we decide to support only 4X and 16X
|
||||
* and then individual gains for channels. Currently this is not the
|
||||
* case.
|
||||
*
|
||||
* If we some day decide to support individual gains, then we need to
|
||||
* have channel information here.
|
||||
*/
|
||||
|
||||
ret = regmap_read(data->regmap, BU27008_REG_MODE_CONTROL2, sel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*sel = FIELD_GET(BU27008_MASK_RGBC_GAIN, *sel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bu27008_chip_init(struct bu27008_data *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_write_bits(data->regmap, BU27008_REG_SYSTEM_CONTROL,
|
||||
BU27008_MASK_SW_RESET, BU27008_MASK_SW_RESET);
|
||||
if (ret)
|
||||
return dev_err_probe(data->dev, ret, "Sensor reset failed\n");
|
||||
|
||||
/*
|
||||
* The data-sheet does not tell how long performing the IC reset takes.
|
||||
* However, the data-sheet says the minimum time it takes the IC to be
|
||||
* able to take inputs after power is applied, is 100 uS. I'd assume
|
||||
* > 1 mS is enough.
|
||||
*/
|
||||
msleep(1);
|
||||
|
||||
ret = regmap_reinit_cache(data->regmap, data->cd->regmap_cfg);
|
||||
if (ret)
|
||||
dev_err(data->dev, "Failed to reinit reg cache\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct bu27_chip_data bu27008_chip = {
|
||||
.name = "bu27008",
|
||||
.chip_init = bu27008_chip_init,
|
||||
.get_gain_sel = bu27008_get_gain_sel,
|
||||
.write_gain_sel = bu27008_write_gain_sel,
|
||||
.regmap_cfg = &bu27008_regmap,
|
||||
.gains = &bu27008_gains[0],
|
||||
.gains_ir = &bu27008_gains_ir[0],
|
||||
.itimes = &bu27008_itimes[0],
|
||||
.num_gains = ARRAY_SIZE(bu27008_gains),
|
||||
.num_gains_ir = ARRAY_SIZE(bu27008_gains_ir),
|
||||
.num_itimes = ARRAY_SIZE(bu27008_itimes),
|
||||
.scale1x = BU27008_SCALE_1X,
|
||||
.drdy_en_reg = BU27008_REG_MODE_CONTROL3,
|
||||
.drdy_en_mask = BU27008_MASK_INT_EN,
|
||||
.valid_reg = BU27008_REG_MODE_CONTROL3,
|
||||
.meas_en_reg = BU27008_REG_MODE_CONTROL3,
|
||||
.meas_en_mask = BU27008_MASK_MEAS_EN,
|
||||
.chan_sel_reg = BU27008_REG_MODE_CONTROL3,
|
||||
.chan_sel_mask = BU27008_MASK_CHAN_SEL,
|
||||
.int_time_mask = BU27008_MASK_MEAS_MODE,
|
||||
.part_id = BU27008_ID,
|
||||
};
|
||||
|
||||
#define BU27008_MAX_VALID_RESULT_WAIT_US 50000
|
||||
#define BU27008_VALID_RESULT_WAIT_QUANTA_US 1000
|
||||
|
||||
static int bu27008_chan_read_data(struct bu27008_data *data, int reg, int *val)
|
||||
{
|
||||
int ret, valid;
|
||||
__le16 tmp;
|
||||
|
||||
ret = regmap_read_poll_timeout(data->regmap, data->cd->valid_reg,
|
||||
valid, (valid & BU27008_MASK_VALID),
|
||||
BU27008_VALID_RESULT_WAIT_QUANTA_US,
|
||||
BU27008_MAX_VALID_RESULT_WAIT_US);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_bulk_read(data->regmap, reg, &tmp, sizeof(tmp));
|
||||
if (ret)
|
||||
dev_err(data->dev, "Reading channel data failed\n");
|
||||
|
||||
*val = le16_to_cpu(tmp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bu27008_get_gain(struct bu27008_data *data, struct iio_gts *gts, int *gain)
|
||||
{
|
||||
int ret, sel;
|
||||
|
||||
ret = data->cd->get_gain_sel(data, &sel);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = iio_gts_find_gain_by_sel(gts, sel);
|
||||
if (ret < 0) {
|
||||
dev_err(data->dev, "unknown gain value 0x%x\n", sel);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*gain = ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bu27008_set_gain(struct bu27008_data *data, int gain)
|
||||
{
|
||||
int ret;
|
||||
@ -376,7 +476,7 @@ static int bu27008_set_gain(struct bu27008_data *data, int gain)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return bu27008_write_gain_sel(data, ret);
|
||||
return data->cd->write_gain_sel(data, ret);
|
||||
}
|
||||
|
||||
static int bu27008_get_int_time_sel(struct bu27008_data *data, int *sel)
|
||||
@ -384,15 +484,23 @@ static int bu27008_get_int_time_sel(struct bu27008_data *data, int *sel)
|
||||
int ret, val;
|
||||
|
||||
ret = regmap_read(data->regmap, BU27008_REG_MODE_CONTROL1, &val);
|
||||
*sel = FIELD_GET(BU27008_MASK_MEAS_MODE, val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
val &= data->cd->int_time_mask;
|
||||
val >>= ffs(data->cd->int_time_mask) - 1;
|
||||
|
||||
*sel = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bu27008_set_int_time_sel(struct bu27008_data *data, int sel)
|
||||
{
|
||||
sel <<= ffs(data->cd->int_time_mask) - 1;
|
||||
|
||||
return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL1,
|
||||
BU27008_MASK_MEAS_MODE, sel);
|
||||
data->cd->int_time_mask, sel);
|
||||
}
|
||||
|
||||
static int bu27008_get_int_time_us(struct bu27008_data *data)
|
||||
@ -448,8 +556,7 @@ static int bu27008_set_int_time(struct bu27008_data *data, int time)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL1,
|
||||
BU27008_MASK_MEAS_MODE, ret);
|
||||
return bu27008_set_int_time_sel(data, ret);
|
||||
}
|
||||
|
||||
/* Try to change the time so that the scale is maintained */
|
||||
@ -527,10 +634,13 @@ unlock_out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bu27008_meas_set(struct bu27008_data *data, int state)
|
||||
static int bu27008_meas_set(struct bu27008_data *data, bool enable)
|
||||
{
|
||||
return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL3,
|
||||
BU27008_MASK_MEAS_EN, state);
|
||||
if (enable)
|
||||
return regmap_set_bits(data->regmap, data->cd->meas_en_reg,
|
||||
data->cd->meas_en_mask);
|
||||
return regmap_clear_bits(data->regmap, data->cd->meas_en_reg,
|
||||
data->cd->meas_en_mask);
|
||||
}
|
||||
|
||||
static int bu27008_chan_cfg(struct bu27008_data *data,
|
||||
@ -543,9 +653,15 @@ static int bu27008_chan_cfg(struct bu27008_data *data,
|
||||
else
|
||||
chan_sel = BU27008_CLEAR2_IR3;
|
||||
|
||||
chan_sel = FIELD_PREP(BU27008_MASK_CHAN_SEL, chan_sel);
|
||||
/*
|
||||
* prepare bitfield for channel sel. The FIELD_PREP works only when
|
||||
* mask is constant. In our case the mask is assigned based on the
|
||||
* chip type. Hence the open-coded FIELD_PREP here. We don't bother
|
||||
* zeroing the irrelevant bits though - update_bits takes care of that.
|
||||
*/
|
||||
chan_sel <<= ffs(data->cd->chan_sel_mask) - 1;
|
||||
|
||||
return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL3,
|
||||
return regmap_update_bits(data->regmap, data->cd->chan_sel_reg,
|
||||
BU27008_MASK_CHAN_SEL, chan_sel);
|
||||
}
|
||||
|
||||
@ -558,7 +674,7 @@ static int bu27008_read_one(struct bu27008_data *data, struct iio_dev *idev,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = bu27008_meas_set(data, BU27008_MEAS_EN);
|
||||
ret = bu27008_meas_set(data, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -574,7 +690,7 @@ static int bu27008_read_one(struct bu27008_data *data, struct iio_dev *idev,
|
||||
if (!ret)
|
||||
ret = IIO_VAL_INT;
|
||||
|
||||
if (bu27008_meas_set(data, BU27008_MEAS_DIS))
|
||||
if (bu27008_meas_set(data, false))
|
||||
dev_warn(data->dev, "measurement disabling failed\n");
|
||||
|
||||
return ret;
|
||||
@ -669,7 +785,7 @@ static int bu27008_set_scale(struct bu27008_data *data,
|
||||
goto unlock_out;
|
||||
|
||||
}
|
||||
ret = bu27008_write_gain_sel(data, gain_sel);
|
||||
ret = data->cd->write_gain_sel(data, gain_sel);
|
||||
|
||||
unlock_out:
|
||||
mutex_unlock(&data->mutex);
|
||||
@ -747,10 +863,10 @@ static int bu27008_update_scan_mode(struct iio_dev *idev,
|
||||
chan_sel = BU27008_CLEAR2_IR3;
|
||||
}
|
||||
|
||||
chan_sel = FIELD_PREP(BU27008_MASK_CHAN_SEL, chan_sel);
|
||||
chan_sel <<= ffs(data->cd->chan_sel_mask) - 1;
|
||||
|
||||
return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL3,
|
||||
BU27008_MASK_CHAN_SEL, chan_sel);
|
||||
return regmap_update_bits(data->regmap, data->cd->chan_sel_reg,
|
||||
data->cd->chan_sel_mask, chan_sel);
|
||||
}
|
||||
|
||||
static const struct iio_info bu27008_info = {
|
||||
@ -761,46 +877,18 @@ static const struct iio_info bu27008_info = {
|
||||
.validate_trigger = iio_validate_own_trigger,
|
||||
};
|
||||
|
||||
static int bu27008_chip_init(struct bu27008_data *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regmap_write_bits(data->regmap, BU27008_REG_SYSTEM_CONTROL,
|
||||
BU27008_MASK_SW_RESET, BU27008_MASK_SW_RESET);
|
||||
if (ret)
|
||||
return dev_err_probe(data->dev, ret, "Sensor reset failed\n");
|
||||
|
||||
/*
|
||||
* The data-sheet does not tell how long performing the IC reset takes.
|
||||
* However, the data-sheet says the minimum time it takes the IC to be
|
||||
* able to take inputs after power is applied, is 100 uS. I'd assume
|
||||
* > 1 mS is enough.
|
||||
*/
|
||||
msleep(1);
|
||||
|
||||
ret = regmap_reinit_cache(data->regmap, &bu27008_regmap);
|
||||
if (ret)
|
||||
dev_err(data->dev, "Failed to reinit reg cache\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bu27008_set_drdy_irq(struct bu27008_data *data, int state)
|
||||
{
|
||||
return regmap_update_bits(data->regmap, BU27008_REG_MODE_CONTROL3,
|
||||
BU27008_MASK_INT_EN, state);
|
||||
}
|
||||
|
||||
static int bu27008_trigger_set_state(struct iio_trigger *trig,
|
||||
bool state)
|
||||
static int bu27008_trigger_set_state(struct iio_trigger *trig, bool state)
|
||||
{
|
||||
struct bu27008_data *data = iio_trigger_get_drvdata(trig);
|
||||
int ret;
|
||||
|
||||
|
||||
if (state)
|
||||
ret = bu27008_set_drdy_irq(data, BU27008_INT_EN);
|
||||
ret = regmap_set_bits(data->regmap, data->cd->drdy_en_reg,
|
||||
data->cd->drdy_en_mask);
|
||||
else
|
||||
ret = bu27008_set_drdy_irq(data, BU27008_INT_DIS);
|
||||
ret = regmap_clear_bits(data->regmap, data->cd->drdy_en_reg,
|
||||
data->cd->drdy_en_mask);
|
||||
if (ret)
|
||||
dev_err(data->dev, "Failed to set trigger state\n");
|
||||
|
||||
@ -836,7 +924,7 @@ static irqreturn_t bu27008_trigger_handler(int irq, void *p)
|
||||
* After some measurements, it seems reading the
|
||||
* BU27008_REG_MODE_CONTROL3 debounces the IRQ line
|
||||
*/
|
||||
ret = regmap_read(data->regmap, BU27008_REG_MODE_CONTROL3, &dummy);
|
||||
ret = regmap_read(data->regmap, data->cd->valid_reg, &dummy);
|
||||
if (ret < 0)
|
||||
goto err_read;
|
||||
|
||||
@ -856,14 +944,14 @@ static int bu27008_buffer_preenable(struct iio_dev *idev)
|
||||
{
|
||||
struct bu27008_data *data = iio_priv(idev);
|
||||
|
||||
return bu27008_meas_set(data, BU27008_MEAS_EN);
|
||||
return bu27008_meas_set(data, true);
|
||||
}
|
||||
|
||||
static int bu27008_buffer_postdisable(struct iio_dev *idev)
|
||||
{
|
||||
struct bu27008_data *data = iio_priv(idev);
|
||||
|
||||
return bu27008_meas_set(data, BU27008_MEAS_DIS);
|
||||
return bu27008_meas_set(data, false);
|
||||
}
|
||||
|
||||
static const struct iio_buffer_setup_ops bu27008_buffer_ops = {
|
||||
@ -936,11 +1024,6 @@ static int bu27008_probe(struct i2c_client *i2c)
|
||||
struct iio_dev *idev;
|
||||
int ret;
|
||||
|
||||
regmap = devm_regmap_init_i2c(i2c, &bu27008_regmap);
|
||||
if (IS_ERR(regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(regmap),
|
||||
"Failed to initialize Regmap\n");
|
||||
|
||||
idev = devm_iio_device_alloc(dev, sizeof(*data));
|
||||
if (!idev)
|
||||
return -ENOMEM;
|
||||
@ -951,24 +1034,34 @@ static int bu27008_probe(struct i2c_client *i2c)
|
||||
|
||||
data = iio_priv(idev);
|
||||
|
||||
data->cd = device_get_match_data(&i2c->dev);
|
||||
if (!data->cd)
|
||||
return -ENODEV;
|
||||
|
||||
regmap = devm_regmap_init_i2c(i2c, data->cd->regmap_cfg);
|
||||
if (IS_ERR(regmap))
|
||||
return dev_err_probe(dev, PTR_ERR(regmap),
|
||||
"Failed to initialize Regmap\n");
|
||||
|
||||
|
||||
ret = regmap_read(regmap, BU27008_REG_SYSTEM_CONTROL, ®);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to access sensor\n");
|
||||
|
||||
part_id = FIELD_GET(BU27008_MASK_PART_ID, reg);
|
||||
|
||||
if (part_id != BU27008_ID)
|
||||
if (part_id != data->cd->part_id)
|
||||
dev_warn(dev, "unknown device 0x%x\n", part_id);
|
||||
|
||||
ret = devm_iio_init_iio_gts(dev, BU27008_SCALE_1X, 0, bu27008_gains,
|
||||
ARRAY_SIZE(bu27008_gains), bu27008_itimes,
|
||||
ARRAY_SIZE(bu27008_itimes), &data->gts);
|
||||
ret = devm_iio_init_iio_gts(dev, data->cd->scale1x, 0, data->cd->gains,
|
||||
data->cd->num_gains, data->cd->itimes,
|
||||
data->cd->num_itimes, &data->gts);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_iio_init_iio_gts(dev, BU27008_SCALE_1X, 0, bu27008_gains_ir,
|
||||
ARRAY_SIZE(bu27008_gains_ir), bu27008_itimes,
|
||||
ARRAY_SIZE(bu27008_itimes), &data->gts_ir);
|
||||
ret = devm_iio_init_iio_gts(dev, data->cd->scale1x, 0, data->cd->gains_ir,
|
||||
data->cd->num_gains_ir, data->cd->itimes,
|
||||
data->cd->num_itimes, &data->gts_ir);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -979,12 +1072,12 @@ static int bu27008_probe(struct i2c_client *i2c)
|
||||
|
||||
idev->channels = bu27008_channels;
|
||||
idev->num_channels = ARRAY_SIZE(bu27008_channels);
|
||||
idev->name = "bu27008";
|
||||
idev->name = data->cd->name;
|
||||
idev->info = &bu27008_info;
|
||||
idev->modes = INDIO_DIRECT_MODE;
|
||||
idev->available_scan_masks = bu27008_scan_masks;
|
||||
|
||||
ret = bu27008_chip_init(data);
|
||||
ret = data->cd->chip_init(data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -1005,7 +1098,7 @@ static int bu27008_probe(struct i2c_client *i2c)
|
||||
}
|
||||
|
||||
static const struct of_device_id bu27008_of_match[] = {
|
||||
{ .compatible = "rohm,bu27008" },
|
||||
{ .compatible = "rohm,bu27008", .data = &bu27008_chip },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, bu27008_of_match);
|
||||
|
Loading…
Reference in New Issue
Block a user