[media] mt9v032: use regmap
This switches all register accesses to use regmap. It allows to use the regmap cache, tracing, and debug register dump facilities, and removes the need to open code read-modify-writes. Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
This commit is contained in:
parent
94b76ce83d
commit
80b44ef23a
|
@ -551,6 +551,7 @@ config VIDEO_MT9V032
|
||||||
tristate "Micron MT9V032 sensor support"
|
tristate "Micron MT9V032 sensor support"
|
||||||
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
|
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
|
||||||
depends on MEDIA_CAMERA_SUPPORT
|
depends on MEDIA_CAMERA_SUPPORT
|
||||||
|
select REGMAP_I2C
|
||||||
---help---
|
---help---
|
||||||
This is a Video4Linux2 sensor-level driver for the Micron
|
This is a Video4Linux2 sensor-level driver for the Micron
|
||||||
MT9V032 752x480 CMOS sensor.
|
MT9V032 752x480 CMOS sensor.
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/log2.h>
|
#include <linux/log2.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/videodev2.h>
|
#include <linux/videodev2.h>
|
||||||
#include <linux/v4l2-mediabus.h>
|
#include <linux/v4l2-mediabus.h>
|
||||||
|
@ -245,6 +246,7 @@ struct mt9v032 {
|
||||||
struct mutex power_lock;
|
struct mutex power_lock;
|
||||||
int power_count;
|
int power_count;
|
||||||
|
|
||||||
|
struct regmap *regmap;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
|
|
||||||
struct mt9v032_platform_data *pdata;
|
struct mt9v032_platform_data *pdata;
|
||||||
|
@ -252,7 +254,6 @@ struct mt9v032 {
|
||||||
const struct mt9v032_model_version *version;
|
const struct mt9v032_model_version *version;
|
||||||
|
|
||||||
u32 sysclk;
|
u32 sysclk;
|
||||||
u16 chip_control;
|
|
||||||
u16 aec_agc;
|
u16 aec_agc;
|
||||||
u16 hblank;
|
u16 hblank;
|
||||||
struct {
|
struct {
|
||||||
|
@ -266,40 +267,10 @@ static struct mt9v032 *to_mt9v032(struct v4l2_subdev *sd)
|
||||||
return container_of(sd, struct mt9v032, subdev);
|
return container_of(sd, struct mt9v032, subdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mt9v032_read(struct i2c_client *client, const u8 reg)
|
|
||||||
{
|
|
||||||
s32 data = i2c_smbus_read_word_swapped(client, reg);
|
|
||||||
dev_dbg(&client->dev, "%s: read 0x%04x from 0x%02x\n", __func__,
|
|
||||||
data, reg);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mt9v032_write(struct i2c_client *client, const u8 reg,
|
|
||||||
const u16 data)
|
|
||||||
{
|
|
||||||
dev_dbg(&client->dev, "%s: writing 0x%04x to 0x%02x\n", __func__,
|
|
||||||
data, reg);
|
|
||||||
return i2c_smbus_write_word_swapped(client, reg, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mt9v032_set_chip_control(struct mt9v032 *mt9v032, u16 clear, u16 set)
|
|
||||||
{
|
|
||||||
struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
|
|
||||||
u16 value = (mt9v032->chip_control & ~clear) | set;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = mt9v032_write(client, MT9V032_CHIP_CONTROL, value);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
mt9v032->chip_control = value;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
mt9v032_update_aec_agc(struct mt9v032 *mt9v032, u16 which, int enable)
|
mt9v032_update_aec_agc(struct mt9v032 *mt9v032, u16 which, int enable)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
|
struct regmap *map = mt9v032->regmap;
|
||||||
u16 value = mt9v032->aec_agc;
|
u16 value = mt9v032->aec_agc;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -308,7 +279,7 @@ mt9v032_update_aec_agc(struct mt9v032 *mt9v032, u16 which, int enable)
|
||||||
else
|
else
|
||||||
value &= ~which;
|
value &= ~which;
|
||||||
|
|
||||||
ret = mt9v032_write(client, MT9V032_AEC_AGC_ENABLE, value);
|
ret = regmap_write(map, MT9V032_AEC_AGC_ENABLE, value);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -319,7 +290,6 @@ mt9v032_update_aec_agc(struct mt9v032 *mt9v032, u16 which, int enable)
|
||||||
static int
|
static int
|
||||||
mt9v032_update_hblank(struct mt9v032 *mt9v032)
|
mt9v032_update_hblank(struct mt9v032 *mt9v032)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
|
|
||||||
struct v4l2_rect *crop = &mt9v032->crop;
|
struct v4l2_rect *crop = &mt9v032->crop;
|
||||||
unsigned int min_hblank = mt9v032->model->data->min_hblank;
|
unsigned int min_hblank = mt9v032->model->data->min_hblank;
|
||||||
unsigned int hblank;
|
unsigned int hblank;
|
||||||
|
@ -330,12 +300,13 @@ mt9v032_update_hblank(struct mt9v032 *mt9v032)
|
||||||
min_hblank);
|
min_hblank);
|
||||||
hblank = max_t(unsigned int, mt9v032->hblank, min_hblank);
|
hblank = max_t(unsigned int, mt9v032->hblank, min_hblank);
|
||||||
|
|
||||||
return mt9v032_write(client, MT9V032_HORIZONTAL_BLANKING, hblank);
|
return regmap_write(mt9v032->regmap, MT9V032_HORIZONTAL_BLANKING,
|
||||||
|
hblank);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mt9v032_power_on(struct mt9v032 *mt9v032)
|
static int mt9v032_power_on(struct mt9v032 *mt9v032)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
|
struct regmap *map = mt9v032->regmap;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = clk_set_rate(mt9v032->clk, mt9v032->sysclk);
|
ret = clk_set_rate(mt9v032->clk, mt9v032->sysclk);
|
||||||
|
@ -349,15 +320,15 @@ static int mt9v032_power_on(struct mt9v032 *mt9v032)
|
||||||
udelay(1);
|
udelay(1);
|
||||||
|
|
||||||
/* Reset the chip and stop data read out */
|
/* Reset the chip and stop data read out */
|
||||||
ret = mt9v032_write(client, MT9V032_RESET, 1);
|
ret = regmap_write(map, MT9V032_RESET, 1);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = mt9v032_write(client, MT9V032_RESET, 0);
|
ret = regmap_write(map, MT9V032_RESET, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
return mt9v032_write(client, MT9V032_CHIP_CONTROL, 0);
|
return regmap_write(map, MT9V032_CHIP_CONTROL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mt9v032_power_off(struct mt9v032 *mt9v032)
|
static void mt9v032_power_off(struct mt9v032 *mt9v032)
|
||||||
|
@ -367,7 +338,7 @@ static void mt9v032_power_off(struct mt9v032 *mt9v032)
|
||||||
|
|
||||||
static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
|
static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
|
||||||
{
|
{
|
||||||
struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
|
struct regmap *map = mt9v032->regmap;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!on) {
|
if (!on) {
|
||||||
|
@ -381,14 +352,14 @@ static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
|
||||||
|
|
||||||
/* Configure the pixel clock polarity */
|
/* Configure the pixel clock polarity */
|
||||||
if (mt9v032->pdata && mt9v032->pdata->clk_pol) {
|
if (mt9v032->pdata && mt9v032->pdata->clk_pol) {
|
||||||
ret = mt9v032_write(client, mt9v032->model->data->pclk_reg,
|
ret = regmap_write(map, mt9v032->model->data->pclk_reg,
|
||||||
MT9V032_PIXEL_CLOCK_INV_PXL_CLK);
|
MT9V032_PIXEL_CLOCK_INV_PXL_CLK);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable the noise correction algorithm and restore the controls. */
|
/* Disable the noise correction algorithm and restore the controls. */
|
||||||
ret = mt9v032_write(client, MT9V032_ROW_NOISE_CORR_CONTROL, 0);
|
ret = regmap_write(map, MT9V032_ROW_NOISE_CORR_CONTROL, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -432,43 +403,39 @@ static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable)
|
||||||
const u16 mode = MT9V032_CHIP_CONTROL_MASTER_MODE
|
const u16 mode = MT9V032_CHIP_CONTROL_MASTER_MODE
|
||||||
| MT9V032_CHIP_CONTROL_DOUT_ENABLE
|
| MT9V032_CHIP_CONTROL_DOUT_ENABLE
|
||||||
| MT9V032_CHIP_CONTROL_SEQUENTIAL;
|
| MT9V032_CHIP_CONTROL_SEQUENTIAL;
|
||||||
struct i2c_client *client = v4l2_get_subdevdata(subdev);
|
|
||||||
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
|
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
|
||||||
struct v4l2_rect *crop = &mt9v032->crop;
|
struct v4l2_rect *crop = &mt9v032->crop;
|
||||||
unsigned int read_mode;
|
struct regmap *map = mt9v032->regmap;
|
||||||
unsigned int hbin;
|
unsigned int hbin;
|
||||||
unsigned int vbin;
|
unsigned int vbin;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!enable)
|
if (!enable)
|
||||||
return mt9v032_set_chip_control(mt9v032, mode, 0);
|
return regmap_update_bits(map, MT9V032_CHIP_CONTROL, mode, 0);
|
||||||
|
|
||||||
/* Configure the window size and row/column bin */
|
/* Configure the window size and row/column bin */
|
||||||
hbin = fls(mt9v032->hratio) - 1;
|
hbin = fls(mt9v032->hratio) - 1;
|
||||||
vbin = fls(mt9v032->vratio) - 1;
|
vbin = fls(mt9v032->vratio) - 1;
|
||||||
read_mode = mt9v032_read(client, MT9V032_READ_MODE);
|
ret = regmap_update_bits(map, MT9V032_READ_MODE,
|
||||||
if (read_mode < 0)
|
~MT9V032_READ_MODE_RESERVED,
|
||||||
return read_mode;
|
hbin << MT9V032_READ_MODE_COLUMN_BIN_SHIFT |
|
||||||
read_mode &= MT9V032_READ_MODE_RESERVED;
|
vbin << MT9V032_READ_MODE_ROW_BIN_SHIFT);
|
||||||
read_mode |= hbin << MT9V032_READ_MODE_COLUMN_BIN_SHIFT |
|
|
||||||
vbin << MT9V032_READ_MODE_ROW_BIN_SHIFT;
|
|
||||||
ret = mt9v032_write(client, MT9V032_READ_MODE, read_mode);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = mt9v032_write(client, MT9V032_COLUMN_START, crop->left);
|
ret = regmap_write(map, MT9V032_COLUMN_START, crop->left);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = mt9v032_write(client, MT9V032_ROW_START, crop->top);
|
ret = regmap_write(map, MT9V032_ROW_START, crop->top);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = mt9v032_write(client, MT9V032_WINDOW_WIDTH, crop->width);
|
ret = regmap_write(map, MT9V032_WINDOW_WIDTH, crop->width);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = mt9v032_write(client, MT9V032_WINDOW_HEIGHT, crop->height);
|
ret = regmap_write(map, MT9V032_WINDOW_HEIGHT, crop->height);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -477,7 +444,7 @@ static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* Switch to master "normal" mode */
|
/* Switch to master "normal" mode */
|
||||||
return mt9v032_set_chip_control(mt9v032, 0, mode);
|
return regmap_update_bits(map, MT9V032_CHIP_CONTROL, mode, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev,
|
static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev,
|
||||||
|
@ -659,7 +626,7 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||||
{
|
{
|
||||||
struct mt9v032 *mt9v032 =
|
struct mt9v032 *mt9v032 =
|
||||||
container_of(ctrl->handler, struct mt9v032, ctrls);
|
container_of(ctrl->handler, struct mt9v032, ctrls);
|
||||||
struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
|
struct regmap *map = mt9v032->regmap;
|
||||||
u32 freq;
|
u32 freq;
|
||||||
u16 data;
|
u16 data;
|
||||||
|
|
||||||
|
@ -669,23 +636,23 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||||
ctrl->val);
|
ctrl->val);
|
||||||
|
|
||||||
case V4L2_CID_GAIN:
|
case V4L2_CID_GAIN:
|
||||||
return mt9v032_write(client, MT9V032_ANALOG_GAIN, ctrl->val);
|
return regmap_write(map, MT9V032_ANALOG_GAIN, ctrl->val);
|
||||||
|
|
||||||
case V4L2_CID_EXPOSURE_AUTO:
|
case V4L2_CID_EXPOSURE_AUTO:
|
||||||
return mt9v032_update_aec_agc(mt9v032, MT9V032_AEC_ENABLE,
|
return mt9v032_update_aec_agc(mt9v032, MT9V032_AEC_ENABLE,
|
||||||
!ctrl->val);
|
!ctrl->val);
|
||||||
|
|
||||||
case V4L2_CID_EXPOSURE:
|
case V4L2_CID_EXPOSURE:
|
||||||
return mt9v032_write(client, MT9V032_TOTAL_SHUTTER_WIDTH,
|
return regmap_write(map, MT9V032_TOTAL_SHUTTER_WIDTH,
|
||||||
ctrl->val);
|
ctrl->val);
|
||||||
|
|
||||||
case V4L2_CID_HBLANK:
|
case V4L2_CID_HBLANK:
|
||||||
mt9v032->hblank = ctrl->val;
|
mt9v032->hblank = ctrl->val;
|
||||||
return mt9v032_update_hblank(mt9v032);
|
return mt9v032_update_hblank(mt9v032);
|
||||||
|
|
||||||
case V4L2_CID_VBLANK:
|
case V4L2_CID_VBLANK:
|
||||||
return mt9v032_write(client, MT9V032_VERTICAL_BLANKING,
|
return regmap_write(map, MT9V032_VERTICAL_BLANKING,
|
||||||
ctrl->val);
|
ctrl->val);
|
||||||
|
|
||||||
case V4L2_CID_PIXEL_RATE:
|
case V4L2_CID_PIXEL_RATE:
|
||||||
case V4L2_CID_LINK_FREQ:
|
case V4L2_CID_LINK_FREQ:
|
||||||
|
@ -722,7 +689,7 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||||
| MT9V032_TEST_PATTERN_FLIP;
|
| MT9V032_TEST_PATTERN_FLIP;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return mt9v032_write(client, MT9V032_TEST_PATTERN, data);
|
return regmap_write(map, MT9V032_TEST_PATTERN, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -790,7 +757,7 @@ static int mt9v032_registered(struct v4l2_subdev *subdev)
|
||||||
struct i2c_client *client = v4l2_get_subdevdata(subdev);
|
struct i2c_client *client = v4l2_get_subdevdata(subdev);
|
||||||
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
|
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
s32 version;
|
u32 version;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n",
|
dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n",
|
||||||
|
@ -803,10 +770,10 @@ static int mt9v032_registered(struct v4l2_subdev *subdev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read and check the sensor version */
|
/* Read and check the sensor version */
|
||||||
version = mt9v032_read(client, MT9V032_CHIP_VERSION);
|
ret = regmap_read(mt9v032->regmap, MT9V032_CHIP_VERSION, &version);
|
||||||
if (version < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&client->dev, "Failed reading chip version\n");
|
dev_err(&client->dev, "Failed reading chip version\n");
|
||||||
return version;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(mt9v032_versions); ++i) {
|
for (i = 0; i < ARRAY_SIZE(mt9v032_versions); ++i) {
|
||||||
|
@ -893,6 +860,13 @@ static const struct v4l2_subdev_internal_ops mt9v032_subdev_internal_ops = {
|
||||||
.close = mt9v032_close,
|
.close = mt9v032_close,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct regmap_config mt9v032_regmap_config = {
|
||||||
|
.reg_bits = 8,
|
||||||
|
.val_bits = 16,
|
||||||
|
.max_register = 0xff,
|
||||||
|
.cache_type = REGCACHE_RBTREE,
|
||||||
|
};
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
* Driver initialization and probing
|
* Driver initialization and probing
|
||||||
*/
|
*/
|
||||||
|
@ -916,6 +890,10 @@ static int mt9v032_probe(struct i2c_client *client,
|
||||||
if (!mt9v032)
|
if (!mt9v032)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
mt9v032->regmap = devm_regmap_init_i2c(client, &mt9v032_regmap_config);
|
||||||
|
if (IS_ERR(mt9v032->regmap))
|
||||||
|
return PTR_ERR(mt9v032->regmap);
|
||||||
|
|
||||||
mt9v032->clk = devm_clk_get(&client->dev, NULL);
|
mt9v032->clk = devm_clk_get(&client->dev, NULL);
|
||||||
if (IS_ERR(mt9v032->clk))
|
if (IS_ERR(mt9v032->clk))
|
||||||
return PTR_ERR(mt9v032->clk);
|
return PTR_ERR(mt9v032->clk);
|
||||||
|
|
Loading…
Reference in New Issue