|
@@ -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);
|
|
|
|