media: ov772x: use SCCB regmap

Convert ov772x register access to use SCCB regmap.

Cc: Mark Brown <broonie@kernel.org>
Cc: Peter Rosin <peda@axentia.se>
Cc: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
Cc: Wolfram Sang <wsa@the-dreams.de>
Cc: Sylwester Nawrocki <s.nawrocki@samsung.com>
Cc: Jacopo Mondi <jacopo+renesas@jmondi.org>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Cc: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Acked-by: Wolfram Sang <wsa+renesas@sang-engineering.com> (I2C parts)
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
This commit is contained in:
Akinobu Mita 2018-07-16 11:47:49 -04:00 committed by Mauro Carvalho Chehab
parent be5a1509af
commit 5bbf32217b
2 changed files with 82 additions and 111 deletions

View file

@ -747,6 +747,7 @@ config VIDEO_OV772X
tristate "OmniVision OV772x sensor support"
depends on I2C && VIDEO_V4L2
depends on MEDIA_CAMERA_SUPPORT
select REGMAP_SCCB
---help---
This is a Video4Linux2 sensor driver for the OmniVision
OV772x camera.

View file

@ -21,6 +21,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/v4l2-mediabus.h>
#include <linux/videodev2.h>
@ -414,6 +415,7 @@ struct ov772x_priv {
struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl;
struct clk *clk;
struct regmap *regmap;
struct ov772x_camera_info *info;
struct gpio_desc *pwdn_gpio;
struct gpio_desc *rstb_gpio;
@ -549,51 +551,18 @@ static struct ov772x_priv *to_ov772x(struct v4l2_subdev *sd)
return container_of(sd, struct ov772x_priv, subdev);
}
static int ov772x_read(struct i2c_client *client, u8 addr)
{
int ret;
u8 val;
ret = i2c_master_send(client, &addr, 1);
if (ret < 0)
return ret;
ret = i2c_master_recv(client, &val, 1);
if (ret < 0)
return ret;
return val;
}
static inline int ov772x_write(struct i2c_client *client, u8 addr, u8 value)
{
return i2c_smbus_write_byte_data(client, addr, value);
}
static int ov772x_mask_set(struct i2c_client *client, u8 command, u8 mask,
u8 set)
{
s32 val = ov772x_read(client, command);
if (val < 0)
return val;
val &= ~mask;
val |= set & mask;
return ov772x_write(client, command, val);
}
static int ov772x_reset(struct i2c_client *client)
static int ov772x_reset(struct ov772x_priv *priv)
{
int ret;
ret = ov772x_write(client, COM7, SCCB_RESET);
ret = regmap_write(priv->regmap, COM7, SCCB_RESET);
if (ret < 0)
return ret;
usleep_range(1000, 5000);
return ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
return regmap_update_bits(priv->regmap, COM2, SOFT_SLEEP_MODE,
SOFT_SLEEP_MODE);
}
/*
@ -611,8 +580,8 @@ static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
if (priv->streaming == enable)
goto done;
ret = ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE,
enable ? 0 : SOFT_SLEEP_MODE);
ret = regmap_update_bits(priv->regmap, COM2, SOFT_SLEEP_MODE,
enable ? 0 : SOFT_SLEEP_MODE);
if (ret)
goto done;
@ -657,7 +626,6 @@ static int ov772x_set_frame_rate(struct ov772x_priv *priv,
const struct ov772x_color_format *cfmt,
const struct ov772x_win_size *win)
{
struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
unsigned long fin = clk_get_rate(priv->clk);
unsigned int best_diff;
unsigned int fsize;
@ -723,11 +691,11 @@ static int ov772x_set_frame_rate(struct ov772x_priv *priv,
}
}
ret = ov772x_write(client, COM4, com4 | COM4_RESERVED);
ret = regmap_write(priv->regmap, COM4, com4 | COM4_RESERVED);
if (ret < 0)
return ret;
ret = ov772x_write(client, CLKRC, clkrc | CLKRC_RESERVED);
ret = regmap_write(priv->regmap, CLKRC, clkrc | CLKRC_RESERVED);
if (ret < 0)
return ret;
@ -788,8 +756,7 @@ static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct ov772x_priv *priv = container_of(ctrl->handler,
struct ov772x_priv, hdl);
struct v4l2_subdev *sd = &priv->subdev;
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct regmap *regmap = priv->regmap;
int ret = 0;
u8 val;
@ -808,27 +775,27 @@ static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl)
val = ctrl->val ? VFLIP_IMG : 0x00;
if (priv->info && (priv->info->flags & OV772X_FLAG_VFLIP))
val ^= VFLIP_IMG;
return ov772x_mask_set(client, COM3, VFLIP_IMG, val);
return regmap_update_bits(regmap, COM3, VFLIP_IMG, val);
case V4L2_CID_HFLIP:
val = ctrl->val ? HFLIP_IMG : 0x00;
if (priv->info && (priv->info->flags & OV772X_FLAG_HFLIP))
val ^= HFLIP_IMG;
return ov772x_mask_set(client, COM3, HFLIP_IMG, val);
return regmap_update_bits(regmap, COM3, HFLIP_IMG, val);
case V4L2_CID_BAND_STOP_FILTER:
if (!ctrl->val) {
/* Switch the filter off, it is on now */
ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff);
ret = regmap_update_bits(regmap, BDBASE, 0xff, 0xff);
if (!ret)
ret = ov772x_mask_set(client, COM8,
BNDF_ON_OFF, 0);
ret = regmap_update_bits(regmap, COM8,
BNDF_ON_OFF, 0);
} else {
/* Switch the filter on, set AEC low limit */
val = 256 - ctrl->val;
ret = ov772x_mask_set(client, COM8,
BNDF_ON_OFF, BNDF_ON_OFF);
ret = regmap_update_bits(regmap, COM8,
BNDF_ON_OFF, BNDF_ON_OFF);
if (!ret)
ret = ov772x_mask_set(client, BDBASE,
0xff, val);
ret = regmap_update_bits(regmap, BDBASE,
0xff, val);
}
return ret;
@ -841,18 +808,19 @@ static int ov772x_s_ctrl(struct v4l2_ctrl *ctrl)
static int ov772x_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov772x_priv *priv = to_ov772x(sd);
int ret;
unsigned int val;
reg->size = 1;
if (reg->reg > 0xff)
return -EINVAL;
ret = ov772x_read(client, reg->reg);
ret = regmap_read(priv->regmap, reg->reg, &val);
if (ret < 0)
return ret;
reg->val = (__u64)ret;
reg->val = (__u64)val;
return 0;
}
@ -860,13 +828,13 @@ static int ov772x_g_register(struct v4l2_subdev *sd,
static int ov772x_s_register(struct v4l2_subdev *sd,
const struct v4l2_dbg_register *reg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov772x_priv *priv = to_ov772x(sd);
if (reg->reg > 0xff ||
reg->val > 0xff)
return -EINVAL;
return ov772x_write(client, reg->reg, reg->val);
return regmap_write(priv->regmap, reg->reg, reg->val);
}
#endif
@ -1004,7 +972,7 @@ static void ov772x_select_params(const struct v4l2_mbus_framefmt *mf,
static int ov772x_edgectrl(struct ov772x_priv *priv)
{
struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
struct regmap *regmap = priv->regmap;
int ret;
if (!priv->info)
@ -1018,19 +986,19 @@ static int ov772x_edgectrl(struct ov772x_priv *priv)
* Remove it when manual mode.
*/
ret = ov772x_mask_set(client, DSPAUTO, EDGE_ACTRL, 0x00);
ret = regmap_update_bits(regmap, DSPAUTO, EDGE_ACTRL, 0x00);
if (ret < 0)
return ret;
ret = ov772x_mask_set(client,
EDGE_TRSHLD, OV772X_EDGE_THRESHOLD_MASK,
priv->info->edgectrl.threshold);
ret = regmap_update_bits(regmap, EDGE_TRSHLD,
OV772X_EDGE_THRESHOLD_MASK,
priv->info->edgectrl.threshold);
if (ret < 0)
return ret;
ret = ov772x_mask_set(client,
EDGE_STRNGT, OV772X_EDGE_STRENGTH_MASK,
priv->info->edgectrl.strength);
ret = regmap_update_bits(regmap, EDGE_STRNGT,
OV772X_EDGE_STRENGTH_MASK,
priv->info->edgectrl.strength);
if (ret < 0)
return ret;
@ -1040,15 +1008,15 @@ static int ov772x_edgectrl(struct ov772x_priv *priv)
*
* Set upper and lower limit.
*/
ret = ov772x_mask_set(client,
EDGE_UPPER, OV772X_EDGE_UPPER_MASK,
priv->info->edgectrl.upper);
ret = regmap_update_bits(regmap, EDGE_UPPER,
OV772X_EDGE_UPPER_MASK,
priv->info->edgectrl.upper);
if (ret < 0)
return ret;
ret = ov772x_mask_set(client,
EDGE_LOWER, OV772X_EDGE_LOWER_MASK,
priv->info->edgectrl.lower);
ret = regmap_update_bits(regmap, EDGE_LOWER,
OV772X_EDGE_LOWER_MASK,
priv->info->edgectrl.lower);
if (ret < 0)
return ret;
}
@ -1060,12 +1028,11 @@ static int ov772x_set_params(struct ov772x_priv *priv,
const struct ov772x_color_format *cfmt,
const struct ov772x_win_size *win)
{
struct i2c_client *client = v4l2_get_subdevdata(&priv->subdev);
int ret;
u8 val;
/* Reset hardware. */
ov772x_reset(client);
ov772x_reset(priv);
/* Edge Ctrl. */
ret = ov772x_edgectrl(priv);
@ -1073,32 +1040,32 @@ static int ov772x_set_params(struct ov772x_priv *priv,
return ret;
/* Format and window size. */
ret = ov772x_write(client, HSTART, win->rect.left >> 2);
ret = regmap_write(priv->regmap, HSTART, win->rect.left >> 2);
if (ret < 0)
goto ov772x_set_fmt_error;
ret = ov772x_write(client, HSIZE, win->rect.width >> 2);
ret = regmap_write(priv->regmap, HSIZE, win->rect.width >> 2);
if (ret < 0)
goto ov772x_set_fmt_error;
ret = ov772x_write(client, VSTART, win->rect.top >> 1);
ret = regmap_write(priv->regmap, VSTART, win->rect.top >> 1);
if (ret < 0)
goto ov772x_set_fmt_error;
ret = ov772x_write(client, VSIZE, win->rect.height >> 1);
ret = regmap_write(priv->regmap, VSIZE, win->rect.height >> 1);
if (ret < 0)
goto ov772x_set_fmt_error;
ret = ov772x_write(client, HOUTSIZE, win->rect.width >> 2);
ret = regmap_write(priv->regmap, HOUTSIZE, win->rect.width >> 2);
if (ret < 0)
goto ov772x_set_fmt_error;
ret = ov772x_write(client, VOUTSIZE, win->rect.height >> 1);
ret = regmap_write(priv->regmap, VOUTSIZE, win->rect.height >> 1);
if (ret < 0)
goto ov772x_set_fmt_error;
ret = ov772x_write(client, HREF,
ret = regmap_write(priv->regmap, HREF,
((win->rect.top & 1) << HREF_VSTART_SHIFT) |
((win->rect.left & 3) << HREF_HSTART_SHIFT) |
((win->rect.height & 1) << HREF_VSIZE_SHIFT) |
((win->rect.width & 3) << HREF_HSIZE_SHIFT));
if (ret < 0)
goto ov772x_set_fmt_error;
ret = ov772x_write(client, EXHCH,
ret = regmap_write(priv->regmap, EXHCH,
((win->rect.height & 1) << EXHCH_VSIZE_SHIFT) |
((win->rect.width & 3) << EXHCH_HSIZE_SHIFT));
if (ret < 0)
@ -1107,15 +1074,14 @@ static int ov772x_set_params(struct ov772x_priv *priv,
/* Set DSP_CTRL3. */
val = cfmt->dsp3;
if (val) {
ret = ov772x_mask_set(client,
DSP_CTRL3, UV_MASK, val);
ret = regmap_update_bits(priv->regmap, DSP_CTRL3, UV_MASK, val);
if (ret < 0)
goto ov772x_set_fmt_error;
}
/* DSP_CTRL4: AEC reference point and DSP output format. */
if (cfmt->dsp4) {
ret = ov772x_write(client, DSP_CTRL4, cfmt->dsp4);
ret = regmap_write(priv->regmap, DSP_CTRL4, cfmt->dsp4);
if (ret < 0)
goto ov772x_set_fmt_error;
}
@ -1131,13 +1097,12 @@ static int ov772x_set_params(struct ov772x_priv *priv,
if (priv->hflip_ctrl->val)
val ^= HFLIP_IMG;
ret = ov772x_mask_set(client,
COM3, SWAP_MASK | IMG_MASK, val);
ret = regmap_update_bits(priv->regmap, COM3, SWAP_MASK | IMG_MASK, val);
if (ret < 0)
goto ov772x_set_fmt_error;
/* COM7: Sensor resolution and output format control. */
ret = ov772x_write(client, COM7, win->com7_bit | cfmt->com7);
ret = regmap_write(priv->regmap, COM7, win->com7_bit | cfmt->com7);
if (ret < 0)
goto ov772x_set_fmt_error;
@ -1150,10 +1115,11 @@ static int ov772x_set_params(struct ov772x_priv *priv,
if (priv->band_filter_ctrl->val) {
unsigned short band_filter = priv->band_filter_ctrl->val;
ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, BNDF_ON_OFF);
ret = regmap_update_bits(priv->regmap, COM8,
BNDF_ON_OFF, BNDF_ON_OFF);
if (!ret)
ret = ov772x_mask_set(client, BDBASE,
0xff, 256 - band_filter);
ret = regmap_update_bits(priv->regmap, BDBASE,
0xff, 256 - band_filter);
if (ret < 0)
goto ov772x_set_fmt_error;
}
@ -1162,7 +1128,7 @@ static int ov772x_set_params(struct ov772x_priv *priv,
ov772x_set_fmt_error:
ov772x_reset(client);
ov772x_reset(priv);
return ret;
}
@ -1276,12 +1242,12 @@ static int ov772x_video_probe(struct ov772x_priv *priv)
return ret;
/* Check and show product ID and manufacturer ID. */
pid = ov772x_read(client, PID);
if (pid < 0)
return pid;
ver = ov772x_read(client, VER);
if (ver < 0)
return ver;
ret = regmap_read(priv->regmap, PID, &pid);
if (ret < 0)
return ret;
ret = regmap_read(priv->regmap, VER, &ver);
if (ret < 0)
return ret;
switch (VERSION(pid, ver)) {
case OV7720:
@ -1297,12 +1263,12 @@ static int ov772x_video_probe(struct ov772x_priv *priv)
goto done;
}
midh = ov772x_read(client, MIDH);
if (midh < 0)
return midh;
midl = ov772x_read(client, MIDL);
if (midl < 0)
return midl;
ret = regmap_read(priv->regmap, MIDH, &midh);
if (ret < 0)
return ret;
ret = regmap_read(priv->regmap, MIDL, &midl);
if (ret < 0)
return ret;
dev_info(&client->dev,
"%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
@ -1386,8 +1352,12 @@ static int ov772x_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct ov772x_priv *priv;
struct i2c_adapter *adapter = client->adapter;
int ret;
static const struct regmap_config ov772x_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = DSPAUTO,
};
if (!client->dev.of_node && !client->dev.platform_data) {
dev_err(&client->dev,
@ -1395,16 +1365,16 @@ static int ov772x_probe(struct i2c_client *client,
return -EINVAL;
}
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&adapter->dev,
"I2C-Adapter doesn't support SMBUS_BYTE_DATA\n");
return -EIO;
}
priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->regmap = devm_regmap_init_sccb(client, &ov772x_regmap_config);
if (IS_ERR(priv->regmap)) {
dev_err(&client->dev, "Failed to allocate register map\n");
return PTR_ERR(priv->regmap);
}
priv->info = client->dev.platform_data;
mutex_init(&priv->lock);