Merge tag 'media/v4.18-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media

Pull media updates from Mauro Carvalho Chehab:

 - remove of atomisp driver from staging, as nobody would have time to
   dedicate huge efforts to fix all the problems there. Also, we have a
   feeling that the driver may not even run the way it is.

 - move Zoran driver to staging, in order to be either fixed to use VB2
   and the proper media kAPIs or to be removed

 - remove videobuf-dvb driver, with is unused for a while

 - some V4L2 documentation fixes/improvements

 - new sensor drivers: imx258 and ov7251

 - a new driver was added to allow using I2C transparent drivers

 - several improvements at the ddbridge driver

 - several improvements at the ISDB pt1 driver, making it more coherent
   with the DVB framework

 - added a new platform driver for MIPI CSI-2 RX: cadence

 - now, all media drivers can be compiled on x86 with COMPILE_TEST

 - almost all media drivers now build on non-x86 architectures with
   COMPILE_TEST

 - lots of other random stuff: cleanups, support for new board models,
   bug fixes, etc

* tag 'media/v4.18-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (464 commits)
  media: omap2: fix compile-testing with FB_OMAP2=m
  media: media/radio/Kconfig: add back RADIO_ISA
  media: v4l2-ioctl.c: fix missing unlock in __video_do_ioctl()
  media: pxa_camera: ignore -ENOIOCTLCMD from v4l2_subdev_call for s_power
  media: arch: sh: migor: Fix TW9910 PDN gpio
  media: staging: tegra-vde: Reset VDE regardless of memory client resetting failure
  media: marvel-ccic: mmp: select VIDEOBUF2_VMALLOC/DMA_CONTIG
  media: marvel-ccic: allow ccic and mmp drivers to coexist
  media: uvcvideo: Prevent setting unavailable flags
  media: ddbridge: conditionally enable fast TS for stv0910-equipped bridges
  media: dvb-frontends/stv0910: make TS speed configurable
  media: ddbridge/mci: add identifiers to function definition arguments
  media: ddbridge/mci: protect against out-of-bounds array access in stop()
  media: rc: ensure input/lirc device can be opened after register
  media: rc: nuvoton: Keep device enabled during reg init
  media: rc: nuvoton: Keep track of users on CIR enable/disable
  media: rc: nuvoton: Tweak the interrupt enabling dance
  media: uvcvideo: Support realtek's UVC 1.5 device
  media: uvcvideo: Fix driver reference counting
  media: gspca_zc3xx: Enable short exposure times for OV7648
  ...
This commit is contained in:
Linus Torvalds
2018-06-07 12:34:37 -07:00
1168 changed files with 16826 additions and 176711 deletions

View File

@@ -575,6 +575,17 @@ config VIDEO_APTINA_PLL
config VIDEO_SMIAPP_PLL
tristate
config VIDEO_IMX258
tristate "Sony IMX258 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
---help---
This is a Video4Linux2 sensor-level driver for the Sony
IMX258 camera.
To compile this driver as a module, choose M here: the
module will be called imx258.
config VIDEO_IMX274
tristate "Sony IMX274 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
@@ -688,6 +699,18 @@ config VIDEO_OV5695
To compile this driver as a module, choose M here: the
module will be called ov5695.
config VIDEO_OV7251
tristate "OmniVision OV7251 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
select V4L2_FWNODE
help
This is a Video4Linux2 sensor-level driver for the OmniVision
OV7251 camera.
To compile this driver as a module, choose M here: the
module will be called ov7251.
config VIDEO_OV772X
tristate "OmniVision OV772x sensor support"
depends on I2C && VIDEO_V4L2
@@ -974,6 +997,19 @@ config VIDEO_M52790
To compile this driver as a module, choose M here: the
module will be called m52790.
config VIDEO_I2C
tristate "I2C transport video support"
depends on VIDEO_V4L2 && I2C
select VIDEOBUF2_VMALLOC
---help---
Enable the I2C transport video support which supports the
following:
* Panasonic AMG88xx Grid-Eye Sensors
To compile this driver as a module, choose M here: the
module will be called video-i2c
endmenu
menu "Sensors used on soc_camera driver"

View File

@@ -70,6 +70,7 @@ obj-$(CONFIG_VIDEO_OV5647) += ov5647.o
obj-$(CONFIG_VIDEO_OV5670) += ov5670.o
obj-$(CONFIG_VIDEO_OV5695) += ov5695.o
obj-$(CONFIG_VIDEO_OV6650) += ov6650.o
obj-$(CONFIG_VIDEO_OV7251) += ov7251.o
obj-$(CONFIG_VIDEO_OV7640) += ov7640.o
obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
obj-$(CONFIG_VIDEO_OV772X) += ov772x.o
@@ -96,9 +97,11 @@ obj-$(CONFIG_VIDEO_LM3646) += lm3646.o
obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o
obj-$(CONFIG_VIDEO_AK881X) += ak881x.o
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
obj-$(CONFIG_VIDEO_I2C) += video-i2c.o
obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o
obj-$(CONFIG_VIDEO_OV2659) += ov2659.o
obj-$(CONFIG_VIDEO_TC358743) += tc358743.o
obj-$(CONFIG_VIDEO_IMX258) += imx258.o
obj-$(CONFIG_VIDEO_IMX274) += imx274.o
obj-$(CONFIG_SDR_MAX2175) += max2175.o

View File

@@ -321,17 +321,17 @@ static const struct v4l2_subdev_video_ops adv748x_afe_video_ops = {
static int adv748x_afe_propagate_pixelrate(struct adv748x_afe *afe)
{
struct v4l2_subdev *tx;
unsigned int width, height, fps;
tx = adv748x_get_remote_sd(&afe->pads[ADV748X_AFE_SOURCE]);
if (!tx)
return -ENOLINK;
width = 720;
height = afe->curr_norm & V4L2_STD_525_60 ? 480 : 576;
fps = afe->curr_norm & V4L2_STD_525_60 ? 30 : 25;
return adv748x_csi2_set_pixelrate(tx, width * height * fps);
/*
* The ADV748x ADC sampling frequency is twice the externally supplied
* clock whose frequency is required to be 28.63636 MHz. It oversamples
* with a factor of 4 resulting in a pixel rate of 14.3180180 MHz.
*/
return adv748x_csi2_set_pixelrate(tx, 14318180);
}
static int adv748x_afe_enum_mbus_code(struct v4l2_subdev *sd,

View File

@@ -402,8 +402,6 @@ static int adv748x_hdmi_propagate_pixelrate(struct adv748x_hdmi *hdmi)
{
struct v4l2_subdev *tx;
struct v4l2_dv_timings timings;
struct v4l2_bt_timings *bt = &timings.bt;
unsigned int fps;
tx = adv748x_get_remote_sd(&hdmi->pads[ADV748X_HDMI_SOURCE]);
if (!tx)
@@ -411,11 +409,7 @@ static int adv748x_hdmi_propagate_pixelrate(struct adv748x_hdmi *hdmi)
adv748x_hdmi_query_dv_timings(&hdmi->sd, &timings);
fps = DIV_ROUND_CLOSEST_ULL(bt->pixelclock,
V4L2_DV_BT_FRAME_WIDTH(bt) *
V4L2_DV_BT_FRAME_HEIGHT(bt));
return adv748x_csi2_set_pixelrate(tx, bt->width * bt->height * fps);
return adv748x_csi2_set_pixelrate(tx, timings.bt.pixelclock);
}
static int adv748x_hdmi_enum_mbus_code(struct v4l2_subdev *sd,

View File

@@ -732,8 +732,8 @@ static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable)
/* power up cec section */
adv7511_cec_write_and_or(sd, 0x4e, 0xfc, 0x01);
/* legacy mode and clear all rx buffers */
adv7511_cec_write(sd, 0x4a, 0x00);
adv7511_cec_write(sd, 0x4a, 0x07);
adv7511_cec_write(sd, 0x4a, 0);
adv7511_cec_write_and_or(sd, 0x11, 0xfe, 0); /* initially disable tx */
/* enabled irqs: */
/* tx: ready */
@@ -831,8 +831,8 @@ static int adv7511_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
*/
adv7511_cec_write_and_or(sd, 0x12, ~0x70, max(1, attempts - 1) << 4);
/* blocking, clear cec tx irq status */
adv7511_wr_and_or(sd, 0x97, 0xc7, 0x38);
/* clear cec tx irq status */
adv7511_wr(sd, 0x97, 0x38);
/* write data */
for (i = 0; i < len; i++)
@@ -917,9 +917,6 @@ static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable)
else if (adv7511_have_hotplug(sd))
irqs |= MASK_ADV7511_EDID_RDY_INT;
adv7511_wr_and_or(sd, 0x95, 0xc0,
(state->cec_enabled_adap && enable) ? 0x39 : 0x00);
/*
* This i2c write can fail (approx. 1 in 1000 writes). But it
* is essential that this register is correct, so retry it
@@ -933,9 +930,11 @@ static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable)
irqs_rd = adv7511_rd(sd, 0x94);
} while (retries-- && irqs_rd != irqs);
if (irqs_rd == irqs)
return;
v4l2_err(sd, "Could not set interrupts: hw failure?\n");
if (irqs_rd != irqs)
v4l2_err(sd, "Could not set interrupts: hw failure?\n");
adv7511_wr_and_or(sd, 0x95, 0xc0,
(state->cec_enabled_adap && enable) ? 0x39 : 0x00);
}
/* Interrupt handler */
@@ -982,8 +981,8 @@ static int adv7511_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
for (i = 0; i < msg.len; i++)
msg.msg[i] = adv7511_cec_read(sd, i + 0x15);
adv7511_cec_write(sd, 0x4a, 1); /* toggle to re-enable rx 1 */
adv7511_cec_write(sd, 0x4a, 0);
adv7511_cec_write(sd, 0x4a, 0); /* toggle to re-enable rx 1 */
adv7511_cec_write(sd, 0x4a, 1);
cec_received_msg(state->cec_adap, &msg);
}
}
@@ -1778,6 +1777,7 @@ static void adv7511_init_setup(struct v4l2_subdev *sd)
/* legacy mode */
adv7511_cec_write(sd, 0x4a, 0x00);
adv7511_cec_write(sd, 0x4a, 0x07);
if (cec_clk % 750000 != 0)
v4l2_err(sd, "%s: cec_clk %d, not multiple of 750 Khz\n",

1318
drivers/media/i2c/imx258.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -87,7 +87,7 @@
#define IMX274_SHR_LIMIT_CONST (4)
/*
* Constants for sensor reset delay
* Min and max sensor reset delay (microseconds)
*/
#define IMX274_RESET_DELAY1 (2000)
#define IMX274_RESET_DELAY2 (2200)
@@ -107,15 +107,15 @@
/*
* IMX274 register definitions
*/
#define IMX274_FRAME_LENGTH_ADDR_1 0x30FA /* VMAX, MSB */
#define IMX274_FRAME_LENGTH_ADDR_2 0x30F9 /* VMAX */
#define IMX274_FRAME_LENGTH_ADDR_3 0x30F8 /* VMAX, LSB */
#define IMX274_SHR_REG_MSB 0x300D /* SHR */
#define IMX274_SHR_REG_LSB 0x300C /* SHR */
#define IMX274_SVR_REG_MSB 0x300F /* SVR */
#define IMX274_SVR_REG_LSB 0x300E /* SVR */
#define IMX274_VMAX_REG_1 0x30FA /* VMAX, MSB */
#define IMX274_VMAX_REG_2 0x30F9 /* VMAX */
#define IMX274_VMAX_REG_3 0x30F8 /* VMAX, LSB */
#define IMX274_HMAX_REG_MSB 0x30F7 /* HMAX */
#define IMX274_HMAX_REG_LSB 0x30F6 /* HMAX */
#define IMX274_COARSE_TIME_ADDR_MSB 0x300D /* SHR */
#define IMX274_COARSE_TIME_ADDR_LSB 0x300C /* SHR */
#define IMX274_ANALOG_GAIN_ADDR_LSB 0x300A /* ANALOG GAIN LSB */
#define IMX274_ANALOG_GAIN_ADDR_MSB 0x300B /* ANALOG GAIN MSB */
#define IMX274_DIGITAL_GAIN_REG 0x3012 /* Digital Gain */
@@ -144,22 +144,13 @@ enum imx274_mode {
IMX274_MODE_3840X2160,
IMX274_MODE_1920X1080,
IMX274_MODE_1280X720,
IMX274_MODE_START_STREAM_1,
IMX274_MODE_START_STREAM_2,
IMX274_MODE_START_STREAM_3,
IMX274_MODE_START_STREAM_4,
IMX274_MODE_STOP_STREAM
};
/*
* imx274 format related structure
*/
struct imx274_frmfmt {
u32 mbus_code;
enum v4l2_colorspace colorspace;
struct v4l2_frmsize_discrete size;
enum imx274_mode mode;
};
/*
@@ -489,24 +480,15 @@ static const struct reg_8 *mode_table[] = {
[IMX274_MODE_3840X2160] = imx274_mode1_3840x2160_raw10,
[IMX274_MODE_1920X1080] = imx274_mode3_1920x1080_raw10,
[IMX274_MODE_1280X720] = imx274_mode5_1280x720_raw10,
[IMX274_MODE_START_STREAM_1] = imx274_start_1,
[IMX274_MODE_START_STREAM_2] = imx274_start_2,
[IMX274_MODE_START_STREAM_3] = imx274_start_3,
[IMX274_MODE_START_STREAM_4] = imx274_start_4,
[IMX274_MODE_STOP_STREAM] = imx274_stop,
};
/*
* imx274 format related structure
*/
static const struct imx274_frmfmt imx274_formats[] = {
{MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_COLORSPACE_SRGB, {3840, 2160},
IMX274_MODE_3840X2160},
{MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_COLORSPACE_SRGB, {1920, 1080},
IMX274_MODE_1920X1080},
{MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_COLORSPACE_SRGB, {1280, 720},
IMX274_MODE_1280X720},
{ {3840, 2160} },
{ {1920, 1080} },
{ {1280, 720} },
};
/*
@@ -737,11 +719,11 @@ static int imx274_mode_regs(struct stimx274 *priv, int mode)
{
int err = 0;
err = imx274_write_table(priv, mode_table[IMX274_MODE_START_STREAM_1]);
err = imx274_write_table(priv, imx274_start_1);
if (err)
return err;
err = imx274_write_table(priv, mode_table[IMX274_MODE_START_STREAM_2]);
err = imx274_write_table(priv, imx274_start_2);
if (err)
return err;
@@ -766,7 +748,7 @@ static int imx274_start_stream(struct stimx274 *priv)
* give it 1 extra ms for margin
*/
msleep_range(11);
err = imx274_write_table(priv, mode_table[IMX274_MODE_START_STREAM_3]);
err = imx274_write_table(priv, imx274_start_3);
if (err)
return err;
@@ -776,7 +758,7 @@ static int imx274_start_stream(struct stimx274 *priv)
* give it 1 extra ms for margin
*/
msleep_range(8);
err = imx274_write_table(priv, mode_table[IMX274_MODE_START_STREAM_4]);
err = imx274_write_table(priv, imx274_start_4);
if (err)
return err;
@@ -890,9 +872,8 @@ static int imx274_set_fmt(struct v4l2_subdev *sd,
int index;
dev_dbg(&client->dev,
"%s: width = %d height = %d code = %d mbus_code = %d\n",
__func__, fmt->width, fmt->height, fmt->code,
imx274_formats[imx274->mode_index].mbus_code);
"%s: width = %d height = %d code = %d\n",
__func__, fmt->width, fmt->height, fmt->code);
mutex_lock(&imx274->lock);
@@ -971,7 +952,7 @@ static int imx274_s_frame_interval(struct v4l2_subdev *sd,
if (!ret) {
/*
* exposure time range is decided by frame interval
* need to update it after frame interal changes
* need to update it after frame interval changes
*/
min = IMX274_MIN_EXPOSURE_TIME;
max = fi->interval.numerator * 1000000
@@ -984,7 +965,7 @@ static int imx274_s_frame_interval(struct v4l2_subdev *sd,
}
/* update exposure time accordingly */
imx274_set_exposure(imx274, imx274->ctrls.exposure->val);
imx274_set_exposure(imx274, ctrl->val);
dev_dbg(&imx274->client->dev, "set frame interval to %uus\n",
fi->interval.numerator * 1000000
@@ -1088,8 +1069,7 @@ static int imx274_s_stream(struct v4l2_subdev *sd, int on)
goto fail;
} else {
/* stop stream */
ret = imx274_write_table(imx274,
mode_table[IMX274_MODE_STOP_STREAM]);
ret = imx274_write_table(imx274, imx274_stop);
if (ret)
goto fail;
}
@@ -1133,15 +1113,15 @@ static int imx274_get_frame_length(struct stimx274 *priv, u32 *val)
svr = (reg_val[1] << IMX274_SHIFT_8_BITS) + reg_val[0];
/* vmax */
err = imx274_read_reg(priv, IMX274_FRAME_LENGTH_ADDR_3, &reg_val[0]);
err = imx274_read_reg(priv, IMX274_VMAX_REG_3, &reg_val[0]);
if (err)
goto fail;
err = imx274_read_reg(priv, IMX274_FRAME_LENGTH_ADDR_2, &reg_val[1]);
err = imx274_read_reg(priv, IMX274_VMAX_REG_2, &reg_val[1]);
if (err)
goto fail;
err = imx274_read_reg(priv, IMX274_FRAME_LENGTH_ADDR_1, &reg_val[2]);
err = imx274_read_reg(priv, IMX274_VMAX_REG_1, &reg_val[2]);
if (err)
goto fail;
@@ -1300,10 +1280,10 @@ fail:
static inline void imx274_calculate_coarse_time_regs(struct reg_8 regs[2],
u32 coarse_time)
{
regs->addr = IMX274_COARSE_TIME_ADDR_MSB;
regs->addr = IMX274_SHR_REG_MSB;
regs->val = (coarse_time >> IMX274_SHIFT_8_BITS)
& IMX274_MASK_LSB_8_BITS;
(regs + 1)->addr = IMX274_COARSE_TIME_ADDR_LSB;
(regs + 1)->addr = IMX274_SHR_REG_LSB;
(regs + 1)->val = (coarse_time) & IMX274_MASK_LSB_8_BITS;
}
@@ -1471,13 +1451,13 @@ static int imx274_set_test_pattern(struct stimx274 *priv, int val)
static inline void imx274_calculate_frame_length_regs(struct reg_8 regs[3],
u32 frame_length)
{
regs->addr = IMX274_FRAME_LENGTH_ADDR_1;
regs->addr = IMX274_VMAX_REG_1;
regs->val = (frame_length >> IMX274_SHIFT_16_BITS)
& IMX274_MASK_LSB_4_BITS;
(regs + 1)->addr = IMX274_FRAME_LENGTH_ADDR_2;
(regs + 1)->addr = IMX274_VMAX_REG_2;
(regs + 1)->val = (frame_length >> IMX274_SHIFT_8_BITS)
& IMX274_MASK_LSB_8_BITS;
(regs + 2)->addr = IMX274_FRAME_LENGTH_ADDR_3;
(regs + 2)->addr = IMX274_VMAX_REG_3;
(regs + 2)->val = (frame_length) & IMX274_MASK_LSB_8_BITS;
}
@@ -1786,7 +1766,7 @@ static int imx274_remove(struct i2c_client *client)
struct stimx274 *imx274 = to_imx274(sd);
/* stop stream */
imx274_write_table(imx274, mode_table[IMX274_MODE_STOP_STREAM]);
imx274_write_table(imx274, imx274_stop);
v4l2_async_unregister_subdev(sd);
v4l2_ctrl_handler_free(&imx274->ctrls.handler);

View File

@@ -739,6 +739,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
struct rc_dev *rc = NULL;
struct i2c_adapter *adap = client->adapter;
unsigned short addr = client->addr;
bool probe_tx = (id->driver_data & FLAG_TX) != 0;
int err;
if ((id->driver_data & FLAG_HDPVR) && !enable_hdpvr) {
@@ -800,6 +801,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
rc_proto = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_MCE |
RC_PROTO_BIT_RC6_6A_32;
ir_codes = RC_MAP_HAUPPAUGE;
probe_tx = true;
break;
}
@@ -892,7 +894,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
INIT_DELAYED_WORK(&ir->work, ir_work);
if (id->driver_data & FLAG_TX) {
if (probe_tx) {
ir->tx_c = i2c_new_dummy(client->adapter, 0x70);
if (!ir->tx_c) {
dev_err(&client->dev, "failed to setup tx i2c address");

View File

@@ -1796,7 +1796,6 @@ MODULE_DEVICE_TABLE(acpi, ov13858_acpi_ids);
static struct i2c_driver ov13858_i2c_driver = {
.driver = {
.name = "ov13858",
.owner = THIS_MODULE,
.pm = &ov13858_pm_ops,
.acpi_match_table = ACPI_PTR(ov13858_acpi_ids),
},

View File

@@ -307,6 +307,10 @@ struct ov2640_priv {
struct gpio_desc *resetb_gpio;
struct gpio_desc *pwdn_gpio;
struct mutex lock; /* lock to protect streaming and power_count */
bool streaming;
int power_count;
};
/*
@@ -709,9 +713,20 @@ static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl)
struct v4l2_subdev *sd =
&container_of(ctrl->handler, struct ov2640_priv, hdl)->subdev;
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov2640_priv *priv = to_ov2640(client);
u8 val;
int ret;
/* v4l2_ctrl_lock() locks our own mutex */
/*
* If the device is not powered up by the host driver, do not apply any
* controls to H/W at this time. Instead the controls will be restored
* when the streaming is started.
*/
if (!priv->power_count)
return 0;
ret = i2c_smbus_write_byte_data(client, BANK_SEL, BANK_SEL_SENS);
if (ret < 0)
return ret;
@@ -763,12 +778,9 @@ static int ov2640_s_register(struct v4l2_subdev *sd,
}
#endif
static int ov2640_s_power(struct v4l2_subdev *sd, int on)
static void ov2640_set_power(struct ov2640_priv *priv, int on)
{
#ifdef CONFIG_GPIOLIB
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov2640_priv *priv = to_ov2640(client);
if (priv->pwdn_gpio)
gpiod_direction_output(priv->pwdn_gpio, !on);
if (on && priv->resetb_gpio) {
@@ -778,6 +790,25 @@ static int ov2640_s_power(struct v4l2_subdev *sd, int on)
gpiod_set_value(priv->resetb_gpio, 0);
}
#endif
}
static int ov2640_s_power(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov2640_priv *priv = to_ov2640(client);
mutex_lock(&priv->lock);
/*
* If the power count is modified from 0 to != 0 or from != 0 to 0,
* update the power state.
*/
if (priv->power_count == !on)
ov2640_set_power(priv, on);
priv->power_count += on ? 1 : -1;
WARN_ON(priv->power_count < 0);
mutex_unlock(&priv->lock);
return 0;
}
@@ -798,16 +829,13 @@ static const struct ov2640_win_size *ov2640_select_win(u32 width, u32 height)
static int ov2640_set_params(struct i2c_client *client,
const struct ov2640_win_size *win, u32 code)
{
struct ov2640_priv *priv = to_ov2640(client);
const struct regval_list *selected_cfmt_regs;
u8 val;
int ret;
/* select win */
priv->win = win;
if (!win)
return -EINVAL;
/* select format */
priv->cfmt_code = 0;
switch (code) {
case MEDIA_BUS_FMT_RGB565_2X8_BE:
dev_dbg(&client->dev, "%s: Selected cfmt RGB565 BE", __func__);
@@ -846,13 +874,13 @@ static int ov2640_set_params(struct i2c_client *client,
goto err;
/* select preamble */
dev_dbg(&client->dev, "%s: Set size to %s", __func__, priv->win->name);
dev_dbg(&client->dev, "%s: Set size to %s", __func__, win->name);
ret = ov2640_write_array(client, ov2640_size_change_preamble_regs);
if (ret < 0)
goto err;
/* set size win */
ret = ov2640_write_array(client, priv->win->regs);
ret = ov2640_write_array(client, win->regs);
if (ret < 0)
goto err;
@@ -872,14 +900,11 @@ static int ov2640_set_params(struct i2c_client *client,
if (ret < 0)
goto err;
priv->cfmt_code = code;
return 0;
err:
dev_err(&client->dev, "%s: Error %d", __func__, ret);
ov2640_reset(client);
priv->win = NULL;
return ret;
}
@@ -915,11 +940,15 @@ static int ov2640_set_fmt(struct v4l2_subdev *sd,
{
struct v4l2_mbus_framefmt *mf = &format->format;
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov2640_priv *priv = to_ov2640(client);
const struct ov2640_win_size *win;
int ret = 0;
if (format->pad)
return -EINVAL;
mutex_lock(&priv->lock);
/* select suitable win */
win = ov2640_select_win(mf->width, mf->height);
mf->width = win->width;
@@ -941,10 +970,24 @@ static int ov2640_set_fmt(struct v4l2_subdev *sd,
break;
}
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
return ov2640_set_params(client, win, mf->code);
cfg->try_fmt = *mf;
return 0;
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
struct ov2640_priv *priv = to_ov2640(client);
if (priv->streaming) {
ret = -EBUSY;
goto out;
}
/* select win */
priv->win = win;
/* select format */
priv->cfmt_code = mf->code;
} else {
cfg->try_fmt = *mf;
}
out:
mutex_unlock(&priv->lock);
return ret;
}
static int ov2640_enum_mbus_code(struct v4l2_subdev *sd,
@@ -979,6 +1022,28 @@ static int ov2640_get_selection(struct v4l2_subdev *sd,
}
}
static int ov2640_s_stream(struct v4l2_subdev *sd, int on)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov2640_priv *priv = to_ov2640(client);
int ret = 0;
mutex_lock(&priv->lock);
if (priv->streaming == !on) {
if (on) {
ret = ov2640_set_params(client, priv->win,
priv->cfmt_code);
if (!ret)
ret = __v4l2_ctrl_handler_setup(&priv->hdl);
}
}
if (!ret)
priv->streaming = on;
mutex_unlock(&priv->lock);
return ret;
}
static int ov2640_video_probe(struct i2c_client *client)
{
struct ov2640_priv *priv = to_ov2640(client);
@@ -1014,8 +1079,6 @@ static int ov2640_video_probe(struct i2c_client *client)
"%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
devname, pid, ver, midh, midl);
ret = v4l2_ctrl_handler_setup(&priv->hdl);
done:
ov2640_s_power(&priv->subdev, 0);
return ret;
@@ -1040,9 +1103,14 @@ static const struct v4l2_subdev_pad_ops ov2640_subdev_pad_ops = {
.set_fmt = ov2640_set_fmt,
};
static const struct v4l2_subdev_video_ops ov2640_subdev_video_ops = {
.s_stream = ov2640_s_stream,
};
static const struct v4l2_subdev_ops ov2640_subdev_ops = {
.core = &ov2640_subdev_core_ops,
.pad = &ov2640_subdev_pad_ops,
.video = &ov2640_subdev_video_ops,
};
static int ov2640_probe_dt(struct i2c_client *client,
@@ -1116,7 +1184,9 @@ static int ov2640_probe(struct i2c_client *client,
v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops);
priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
mutex_init(&priv->lock);
v4l2_ctrl_handler_init(&priv->hdl, 2);
priv->hdl.lock = &priv->lock;
v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops,
@@ -1150,6 +1220,7 @@ err_videoprobe:
media_entity_cleanup(&priv->subdev.entity);
err_hdl:
v4l2_ctrl_handler_free(&priv->hdl);
mutex_destroy(&priv->lock);
err_clk:
clk_disable_unprepare(priv->clk);
return ret;
@@ -1161,6 +1232,7 @@ static int ov2640_remove(struct i2c_client *client)
v4l2_async_unregister_subdev(&priv->subdev);
v4l2_ctrl_handler_free(&priv->hdl);
mutex_destroy(&priv->lock);
media_entity_cleanup(&priv->subdev.entity);
v4l2_device_unregister_subdev(&priv->subdev);
clk_disable_unprepare(priv->clk);

View File

@@ -60,6 +60,8 @@
#define OV5640_REG_AEC_PK_MANUAL 0x3503
#define OV5640_REG_AEC_PK_REAL_GAIN 0x350a
#define OV5640_REG_AEC_PK_VTS 0x350c
#define OV5640_REG_TIMING_DVPHO 0x3808
#define OV5640_REG_TIMING_DVPVO 0x380a
#define OV5640_REG_TIMING_HTS 0x380c
#define OV5640_REG_TIMING_VTS 0x380e
#define OV5640_REG_TIMING_TC_REG21 0x3821
@@ -91,6 +93,9 @@
#define OV5640_REG_SDE_CTRL5 0x5585
#define OV5640_REG_AVG_READOUT 0x56a1
#define OV5640_SCLK2X_ROOT_DIVIDER_DEFAULT 1
#define OV5640_SCLK_ROOT_DIVIDER_DEFAULT 2
enum ov5640_mode_id {
OV5640_MODE_QCIF_176_144 = 0,
OV5640_MODE_QVGA_320_240,
@@ -165,8 +170,10 @@ struct reg_value {
struct ov5640_mode_info {
enum ov5640_mode_id id;
enum ov5640_downsize_mode dn_mode;
u32 width;
u32 height;
u32 hact;
u32 htot;
u32 vact;
u32 vtot;
const struct reg_value *reg_data;
u32 reg_data_size;
};
@@ -187,6 +194,7 @@ struct ov5640_ctrls {
struct v4l2_ctrl *gain;
};
struct v4l2_ctrl *brightness;
struct v4l2_ctrl *light_freq;
struct v4l2_ctrl *saturation;
struct v4l2_ctrl *contrast;
struct v4l2_ctrl *hue;
@@ -248,7 +256,7 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
{0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0},
{0x3034, 0x18, 0, 0}, {0x3035, 0x14, 0, 0}, {0x3036, 0x38, 0, 0},
{0x3037, 0x13, 0, 0}, {0x3108, 0x01, 0, 0}, {0x3630, 0x36, 0, 0},
{0x3037, 0x13, 0, 0}, {0x3630, 0x36, 0, 0},
{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
@@ -265,9 +273,7 @@ static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
{0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
{0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
{0x3810, 0x00, 0, 0},
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
@@ -339,9 +345,7 @@ static const struct reg_value ov5640_setting_30fps_VGA_640_480[] = {
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
{0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
{0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
{0x380e, 0x04, 0, 0}, {0x380f, 0x38, 0, 0}, {0x3810, 0x00, 0, 0},
{0x3810, 0x00, 0, 0},
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
@@ -360,9 +364,7 @@ static const struct reg_value ov5640_setting_15fps_VGA_640_480[] = {
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
{0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
{0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
{0x3810, 0x00, 0, 0},
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
@@ -381,9 +383,7 @@ static const struct reg_value ov5640_setting_30fps_XGA_1024_768[] = {
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
{0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
{0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
{0x380e, 0x04, 0, 0}, {0x380f, 0x38, 0, 0}, {0x3810, 0x00, 0, 0},
{0x3810, 0x00, 0, 0},
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
@@ -393,8 +393,7 @@ static const struct reg_value ov5640_setting_30fps_XGA_1024_768[] = {
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3503, 0x00, 0, 0},
{0x3808, 0x04, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0},
{0x380b, 0x00, 0, 0}, {0x3035, 0x12, 0, 0},
{0x3035, 0x12, 0, 0},
};
static const struct reg_value ov5640_setting_15fps_XGA_1024_768[] = {
@@ -404,9 +403,7 @@ static const struct reg_value ov5640_setting_15fps_XGA_1024_768[] = {
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
{0x3808, 0x02, 0, 0}, {0x3809, 0x80, 0, 0}, {0x380a, 0x01, 0, 0},
{0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
{0x3810, 0x00, 0, 0},
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
@@ -415,8 +412,7 @@ static const struct reg_value ov5640_setting_15fps_XGA_1024_768[] = {
{0x3a0d, 0x04, 0, 0}, {0x3a14, 0x03, 0, 0}, {0x3a15, 0xd8, 0, 0},
{0x4001, 0x02, 0, 0}, {0x4004, 0x02, 0, 0}, {0x4713, 0x03, 0, 0},
{0x4407, 0x04, 0, 0}, {0x460b, 0x35, 0, 0}, {0x460c, 0x22, 0, 0},
{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0}, {0x3808, 0x04, 0, 0},
{0x3809, 0x00, 0, 0}, {0x380a, 0x03, 0, 0}, {0x380b, 0x00, 0, 0},
{0x3824, 0x02, 0, 0}, {0x5001, 0xa3, 0, 0},
};
static const struct reg_value ov5640_setting_30fps_QVGA_320_240[] = {
@@ -426,9 +422,7 @@ static const struct reg_value ov5640_setting_30fps_QVGA_320_240[] = {
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
{0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0},
{0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
{0x3810, 0x00, 0, 0},
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
@@ -447,9 +441,7 @@ static const struct reg_value ov5640_setting_15fps_QVGA_320_240[] = {
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
{0x3808, 0x01, 0, 0}, {0x3809, 0x40, 0, 0}, {0x380a, 0x00, 0, 0},
{0x380b, 0xf0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
{0x3810, 0x00, 0, 0},
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
@@ -468,9 +460,7 @@ static const struct reg_value ov5640_setting_30fps_QCIF_176_144[] = {
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
{0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0},
{0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
{0x3810, 0x00, 0, 0},
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
@@ -489,9 +479,7 @@ static const struct reg_value ov5640_setting_15fps_QCIF_176_144[] = {
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
{0x3808, 0x00, 0, 0}, {0x3809, 0xb0, 0, 0}, {0x380a, 0x00, 0, 0},
{0x380b, 0x90, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
{0x3810, 0x00, 0, 0},
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
@@ -510,9 +498,7 @@ static const struct reg_value ov5640_setting_30fps_NTSC_720_480[] = {
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
{0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0},
{0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
{0x3810, 0x00, 0, 0},
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0},
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
@@ -531,9 +517,7 @@ static const struct reg_value ov5640_setting_15fps_NTSC_720_480[] = {
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
{0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x01, 0, 0},
{0x380b, 0xe0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
{0x3810, 0x00, 0, 0},
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x3c, 0, 0},
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
@@ -552,9 +536,7 @@ static const struct reg_value ov5640_setting_30fps_PAL_720_576[] = {
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
{0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x02, 0, 0},
{0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
{0x3810, 0x00, 0, 0},
{0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
@@ -573,9 +555,7 @@ static const struct reg_value ov5640_setting_15fps_PAL_720_576[] = {
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
{0x3802, 0x00, 0, 0}, {0x3803, 0x04, 0, 0}, {0x3804, 0x0a, 0, 0},
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9b, 0, 0},
{0x3808, 0x02, 0, 0}, {0x3809, 0xd0, 0, 0}, {0x380a, 0x02, 0, 0},
{0x380b, 0x40, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x68, 0, 0},
{0x380e, 0x03, 0, 0}, {0x380f, 0xd8, 0, 0}, {0x3810, 0x00, 0, 0},
{0x3810, 0x00, 0, 0},
{0x3811, 0x38, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x06, 0, 0},
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x03, 0, 0},
@@ -595,9 +575,7 @@ static const struct reg_value ov5640_setting_30fps_720P_1280_720[] = {
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
{0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
{0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
{0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0},
{0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0},
{0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0},
{0x3810, 0x00, 0, 0},
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
@@ -617,9 +595,7 @@ static const struct reg_value ov5640_setting_15fps_720P_1280_720[] = {
{0x3815, 0x31, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
{0x3802, 0x00, 0, 0}, {0x3803, 0xfa, 0, 0}, {0x3804, 0x0a, 0, 0},
{0x3805, 0x3f, 0, 0}, {0x3806, 0x06, 0, 0}, {0x3807, 0xa9, 0, 0},
{0x3808, 0x05, 0, 0}, {0x3809, 0x00, 0, 0}, {0x380a, 0x02, 0, 0},
{0x380b, 0xd0, 0, 0}, {0x380c, 0x07, 0, 0}, {0x380d, 0x64, 0, 0},
{0x380e, 0x02, 0, 0}, {0x380f, 0xe4, 0, 0}, {0x3810, 0x00, 0, 0},
{0x3810, 0x00, 0, 0},
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
{0x3618, 0x00, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3709, 0x52, 0, 0}, {0x370c, 0x03, 0, 0}, {0x3a02, 0x02, 0, 0},
@@ -639,9 +615,7 @@ static const struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = {
{0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
{0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
{0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0},
{0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0},
{0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0},
{0x3810, 0x00, 0, 0},
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
@@ -655,10 +629,8 @@ static const struct reg_value ov5640_setting_30fps_1080P_1920_1080[] = {
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
{0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0},
{0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3808, 0x07, 0, 0},
{0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0},
{0x380c, 0x09, 0, 0}, {0x380d, 0xc4, 0, 0}, {0x380e, 0x04, 0, 0},
{0x380f, 0x60, 0, 0}, {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0},
{0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
@@ -676,9 +648,7 @@ static const struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = {
{0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
{0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
{0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0},
{0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0},
{0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0},
{0x3810, 0x00, 0, 0},
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
@@ -692,10 +662,8 @@ static const struct reg_value ov5640_setting_15fps_1080P_1920_1080[] = {
{0x3c09, 0x1c, 0, 0}, {0x3c0a, 0x9c, 0, 0}, {0x3c0b, 0x40, 0, 0},
{0x3800, 0x01, 0, 0}, {0x3801, 0x50, 0, 0}, {0x3802, 0x01, 0, 0},
{0x3803, 0xb2, 0, 0}, {0x3804, 0x08, 0, 0}, {0x3805, 0xef, 0, 0},
{0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0}, {0x3808, 0x07, 0, 0},
{0x3809, 0x80, 0, 0}, {0x380a, 0x04, 0, 0}, {0x380b, 0x38, 0, 0},
{0x380c, 0x09, 0, 0}, {0x380d, 0xc4, 0, 0}, {0x380e, 0x04, 0, 0},
{0x380f, 0x60, 0, 0}, {0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3806, 0x05, 0, 0}, {0x3807, 0xf1, 0, 0},
{0x3612, 0x2b, 0, 0}, {0x3708, 0x64, 0, 0},
{0x3a02, 0x04, 0, 0}, {0x3a03, 0x60, 0, 0}, {0x3a08, 0x01, 0, 0},
{0x3a09, 0x50, 0, 0}, {0x3a0a, 0x01, 0, 0}, {0x3a0b, 0x18, 0, 0},
{0x3a0e, 0x03, 0, 0}, {0x3a0d, 0x04, 0, 0}, {0x3a14, 0x04, 0, 0},
@@ -712,9 +680,7 @@ static const struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = {
{0x3815, 0x11, 0, 0}, {0x3800, 0x00, 0, 0}, {0x3801, 0x00, 0, 0},
{0x3802, 0x00, 0, 0}, {0x3803, 0x00, 0, 0}, {0x3804, 0x0a, 0, 0},
{0x3805, 0x3f, 0, 0}, {0x3806, 0x07, 0, 0}, {0x3807, 0x9f, 0, 0},
{0x3808, 0x0a, 0, 0}, {0x3809, 0x20, 0, 0}, {0x380a, 0x07, 0, 0},
{0x380b, 0x98, 0, 0}, {0x380c, 0x0b, 0, 0}, {0x380d, 0x1c, 0, 0},
{0x380e, 0x07, 0, 0}, {0x380f, 0xb0, 0, 0}, {0x3810, 0x00, 0, 0},
{0x3810, 0x00, 0, 0},
{0x3811, 0x10, 0, 0}, {0x3812, 0x00, 0, 0}, {0x3813, 0x04, 0, 0},
{0x3618, 0x04, 0, 0}, {0x3612, 0x29, 0, 0}, {0x3708, 0x21, 0, 0},
{0x3709, 0x12, 0, 0}, {0x370c, 0x00, 0, 0}, {0x3a02, 0x03, 0, 0},
@@ -728,66 +694,84 @@ static const struct reg_value ov5640_setting_15fps_QSXGA_2592_1944[] = {
/* power-on sensor init reg table */
static const struct ov5640_mode_info ov5640_mode_init_data = {
0, SUBSAMPLING, 640, 480, ov5640_init_setting_30fps_VGA,
0, SUBSAMPLING, 640, 1896, 480, 984,
ov5640_init_setting_30fps_VGA,
ARRAY_SIZE(ov5640_init_setting_30fps_VGA),
};
static const struct ov5640_mode_info
ov5640_mode_data[OV5640_NUM_FRAMERATES][OV5640_NUM_MODES] = {
{
{OV5640_MODE_QCIF_176_144, SUBSAMPLING, 176, 144,
{OV5640_MODE_QCIF_176_144, SUBSAMPLING,
176, 1896, 144, 984,
ov5640_setting_15fps_QCIF_176_144,
ARRAY_SIZE(ov5640_setting_15fps_QCIF_176_144)},
{OV5640_MODE_QVGA_320_240, SUBSAMPLING, 320, 240,
{OV5640_MODE_QVGA_320_240, SUBSAMPLING,
320, 1896, 240, 984,
ov5640_setting_15fps_QVGA_320_240,
ARRAY_SIZE(ov5640_setting_15fps_QVGA_320_240)},
{OV5640_MODE_VGA_640_480, SUBSAMPLING, 640, 480,
{OV5640_MODE_VGA_640_480, SUBSAMPLING,
640, 1896, 480, 1080,
ov5640_setting_15fps_VGA_640_480,
ARRAY_SIZE(ov5640_setting_15fps_VGA_640_480)},
{OV5640_MODE_NTSC_720_480, SUBSAMPLING, 720, 480,
{OV5640_MODE_NTSC_720_480, SUBSAMPLING,
720, 1896, 480, 984,
ov5640_setting_15fps_NTSC_720_480,
ARRAY_SIZE(ov5640_setting_15fps_NTSC_720_480)},
{OV5640_MODE_PAL_720_576, SUBSAMPLING, 720, 576,
{OV5640_MODE_PAL_720_576, SUBSAMPLING,
720, 1896, 576, 984,
ov5640_setting_15fps_PAL_720_576,
ARRAY_SIZE(ov5640_setting_15fps_PAL_720_576)},
{OV5640_MODE_XGA_1024_768, SUBSAMPLING, 1024, 768,
{OV5640_MODE_XGA_1024_768, SUBSAMPLING,
1024, 1896, 768, 1080,
ov5640_setting_15fps_XGA_1024_768,
ARRAY_SIZE(ov5640_setting_15fps_XGA_1024_768)},
{OV5640_MODE_720P_1280_720, SUBSAMPLING, 1280, 720,
{OV5640_MODE_720P_1280_720, SUBSAMPLING,
1280, 1892, 720, 740,
ov5640_setting_15fps_720P_1280_720,
ARRAY_SIZE(ov5640_setting_15fps_720P_1280_720)},
{OV5640_MODE_1080P_1920_1080, SCALING, 1920, 1080,
{OV5640_MODE_1080P_1920_1080, SCALING,
1920, 2500, 1080, 1120,
ov5640_setting_15fps_1080P_1920_1080,
ARRAY_SIZE(ov5640_setting_15fps_1080P_1920_1080)},
{OV5640_MODE_QSXGA_2592_1944, SCALING, 2592, 1944,
{OV5640_MODE_QSXGA_2592_1944, SCALING,
2592, 2844, 1944, 1968,
ov5640_setting_15fps_QSXGA_2592_1944,
ARRAY_SIZE(ov5640_setting_15fps_QSXGA_2592_1944)},
}, {
{OV5640_MODE_QCIF_176_144, SUBSAMPLING, 176, 144,
{OV5640_MODE_QCIF_176_144, SUBSAMPLING,
176, 1896, 144, 984,
ov5640_setting_30fps_QCIF_176_144,
ARRAY_SIZE(ov5640_setting_30fps_QCIF_176_144)},
{OV5640_MODE_QVGA_320_240, SUBSAMPLING, 320, 240,
{OV5640_MODE_QVGA_320_240, SUBSAMPLING,
320, 1896, 240, 984,
ov5640_setting_30fps_QVGA_320_240,
ARRAY_SIZE(ov5640_setting_30fps_QVGA_320_240)},
{OV5640_MODE_VGA_640_480, SUBSAMPLING, 640, 480,
{OV5640_MODE_VGA_640_480, SUBSAMPLING,
640, 1896, 480, 1080,
ov5640_setting_30fps_VGA_640_480,
ARRAY_SIZE(ov5640_setting_30fps_VGA_640_480)},
{OV5640_MODE_NTSC_720_480, SUBSAMPLING, 720, 480,
{OV5640_MODE_NTSC_720_480, SUBSAMPLING,
720, 1896, 480, 984,
ov5640_setting_30fps_NTSC_720_480,
ARRAY_SIZE(ov5640_setting_30fps_NTSC_720_480)},
{OV5640_MODE_PAL_720_576, SUBSAMPLING, 720, 576,
{OV5640_MODE_PAL_720_576, SUBSAMPLING,
720, 1896, 576, 984,
ov5640_setting_30fps_PAL_720_576,
ARRAY_SIZE(ov5640_setting_30fps_PAL_720_576)},
{OV5640_MODE_XGA_1024_768, SUBSAMPLING, 1024, 768,
{OV5640_MODE_XGA_1024_768, SUBSAMPLING,
1024, 1896, 768, 1080,
ov5640_setting_30fps_XGA_1024_768,
ARRAY_SIZE(ov5640_setting_30fps_XGA_1024_768)},
{OV5640_MODE_720P_1280_720, SUBSAMPLING, 1280, 720,
{OV5640_MODE_720P_1280_720, SUBSAMPLING,
1280, 1892, 720, 740,
ov5640_setting_30fps_720P_1280_720,
ARRAY_SIZE(ov5640_setting_30fps_720P_1280_720)},
{OV5640_MODE_1080P_1920_1080, SCALING, 1920, 1080,
{OV5640_MODE_1080P_1920_1080, SCALING,
1920, 2500, 1080, 1120,
ov5640_setting_30fps_1080P_1920_1080,
ARRAY_SIZE(ov5640_setting_30fps_1080P_1920_1080)},
{OV5640_MODE_QSXGA_2592_1944, -1, 0, 0, NULL, 0},
{OV5640_MODE_QSXGA_2592_1944, -1, 0, 0, 0, 0, NULL, 0},
},
};
@@ -1377,6 +1361,30 @@ static int ov5640_set_virtual_channel(struct ov5640_dev *sensor)
return ov5640_write_reg(sensor, OV5640_REG_DEBUG_MODE, temp);
}
static int ov5640_set_timings(struct ov5640_dev *sensor,
const struct ov5640_mode_info *mode)
{
int ret;
ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPHO, mode->hact);
if (ret < 0)
return ret;
ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_DVPVO, mode->vact);
if (ret < 0)
return ret;
ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_HTS, mode->htot);
if (ret < 0)
return ret;
ret = ov5640_write_reg16(sensor, OV5640_REG_TIMING_VTS, mode->vtot);
if (ret < 0)
return ret;
return 0;
}
static const struct ov5640_mode_info *
ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr,
int width, int height, bool nearest)
@@ -1390,10 +1398,10 @@ ov5640_find_mode(struct ov5640_dev *sensor, enum ov5640_frame_rate fr,
if (!mode->reg_data)
continue;
if ((nearest && mode->width <= width &&
mode->height <= height) ||
(!nearest && mode->width == width &&
mode->height == height))
if ((nearest && mode->hact <= width &&
mode->vact <= height) ||
(!nearest && mode->hact == width &&
mode->vact == height))
break;
}
@@ -1568,7 +1576,8 @@ static int ov5640_set_mode_exposure_calc(struct ov5640_dev *sensor,
* change mode directly
*/
static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
const struct ov5640_mode_info *mode)
const struct ov5640_mode_info *mode,
s32 exposure)
{
int ret;
@@ -1584,7 +1593,8 @@ static int ov5640_set_mode_direct(struct ov5640_dev *sensor,
ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.auto_gain, 1);
if (ret)
return ret;
return __v4l2_ctrl_s_ctrl(sensor->ctrls.auto_exp, V4L2_EXPOSURE_AUTO);
return __v4l2_ctrl_s_ctrl(sensor->ctrls.auto_exp, exposure);
}
static int ov5640_set_mode(struct ov5640_dev *sensor,
@@ -1592,6 +1602,7 @@ static int ov5640_set_mode(struct ov5640_dev *sensor,
{
const struct ov5640_mode_info *mode = sensor->current_mode;
enum ov5640_downsize_mode dn_mode, orig_dn_mode;
s32 exposure;
int ret;
dn_mode = mode->dn_mode;
@@ -1601,7 +1612,9 @@ static int ov5640_set_mode(struct ov5640_dev *sensor,
ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.auto_gain, 0);
if (ret)
return ret;
ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.auto_exp, V4L2_EXPOSURE_MANUAL);
exposure = sensor->ctrls.auto_exp->val;
ret = ov5640_set_exposure(sensor, V4L2_EXPOSURE_MANUAL);
if (ret)
return ret;
@@ -1617,9 +1630,13 @@ static int ov5640_set_mode(struct ov5640_dev *sensor,
* change inside subsampling or scaling
* download firmware directly
*/
ret = ov5640_set_mode_direct(sensor, mode);
ret = ov5640_set_mode_direct(sensor, mode, exposure);
}
if (ret < 0)
return ret;
ret = ov5640_set_timings(sensor, mode);
if (ret < 0)
return ret;
@@ -1654,6 +1671,12 @@ static int ov5640_restore_mode(struct ov5640_dev *sensor)
if (ret < 0)
return ret;
ret = ov5640_mod_reg(sensor, OV5640_REG_SYS_ROOT_DIVIDER, 0x3f,
(ilog2(OV5640_SCLK2X_ROOT_DIVIDER_DEFAULT) << 2) |
ilog2(OV5640_SCLK_ROOT_DIVIDER_DEFAULT));
if (ret)
return ret;
/* now restore the last capture mode */
ret = ov5640_set_mode(sensor, &ov5640_mode_init_data);
if (ret < 0)
@@ -1871,8 +1894,8 @@ static int ov5640_try_fmt_internal(struct v4l2_subdev *sd,
mode = ov5640_find_mode(sensor, fr, fmt->width, fmt->height, true);
if (!mode)
return -EINVAL;
fmt->width = mode->width;
fmt->height = mode->height;
fmt->width = mode->hact;
fmt->height = mode->vact;
if (new_mode)
*new_mode = mode;
@@ -2155,6 +2178,21 @@ static int ov5640_set_ctrl_test_pattern(struct ov5640_dev *sensor, int value)
0xa4, value ? 0xa4 : 0);
}
static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value)
{
int ret;
ret = ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL01, BIT(7),
(value == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) ?
0 : BIT(7));
if (ret)
return ret;
return ov5640_mod_reg(sensor, OV5640_REG_HZ5060_CTRL00, BIT(2),
(value == V4L2_CID_POWER_LINE_FREQUENCY_50HZ) ?
BIT(2) : 0);
}
static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
@@ -2223,6 +2261,9 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_TEST_PATTERN:
ret = ov5640_set_ctrl_test_pattern(sensor, ctrl->val);
break;
case V4L2_CID_POWER_LINE_FREQUENCY:
ret = ov5640_set_ctrl_light_freq(sensor, ctrl->val);
break;
default:
ret = -EINVAL;
break;
@@ -2285,6 +2326,12 @@ static int ov5640_init_controls(struct ov5640_dev *sensor)
ARRAY_SIZE(test_pattern_menu) - 1,
0, 0, test_pattern_menu);
ctrls->light_freq =
v4l2_ctrl_new_std_menu(hdl, ops,
V4L2_CID_POWER_LINE_FREQUENCY,
V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
if (hdl->error) {
ret = hdl->error;
goto free_ctrls;
@@ -2315,10 +2362,10 @@ static int ov5640_enum_frame_size(struct v4l2_subdev *sd,
return -EINVAL;
fse->min_width =
ov5640_mode_data[0][fse->index].width;
ov5640_mode_data[0][fse->index].hact;
fse->max_width = fse->min_width;
fse->min_height =
ov5640_mode_data[0][fse->index].height;
ov5640_mode_data[0][fse->index].vact;
fse->max_height = fse->min_height;
return 0;
@@ -2382,14 +2429,14 @@ static int ov5640_s_frame_interval(struct v4l2_subdev *sd,
mode = sensor->current_mode;
frame_rate = ov5640_try_frame_interval(sensor, &fi->interval,
mode->width, mode->height);
mode->hact, mode->vact);
if (frame_rate < 0)
frame_rate = OV5640_15_FPS;
sensor->current_fr = frame_rate;
sensor->frame_interval = fi->interval;
sensor->current_mode = ov5640_find_mode(sensor, frame_rate, mode->width,
mode->height, true);
sensor->current_mode = ov5640_find_mode(sensor, frame_rate, mode->hact,
mode->vact, true);
sensor->pending_mode_change = true;
out:
mutex_unlock(&sensor->lock);
@@ -2536,8 +2583,8 @@ static int ov5640_probe(struct i2c_client *client,
sensor->ae_target = 52;
endpoint = fwnode_graph_get_next_endpoint(
of_fwnode_handle(client->dev.of_node), NULL);
endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
NULL);
if (!endpoint) {
dev_err(dev, "endpoint node not found\n");
return -EINVAL;

View File

@@ -600,11 +600,13 @@ static int ov5645_write_reg(struct ov5645 *ov5645, u16 reg, u8 val)
regbuf[2] = val;
ret = i2c_master_send(ov5645->i2c_client, regbuf, 3);
if (ret < 0)
if (ret < 0) {
dev_err(ov5645->dev, "%s: write reg error %d: reg=%x, val=%x\n",
__func__, ret, reg, val);
return ret;
}
return ret;
return 0;
}
static int ov5645_read_reg(struct ov5645 *ov5645, u16 reg, u8 *val)

View File

@@ -1385,7 +1385,6 @@ MODULE_DEVICE_TABLE(of, ov5695_of_match);
static struct i2c_driver ov5695_i2c_driver = {
.driver = {
.name = "ov5695",
.owner = THIS_MODULE,
.pm = &ov5695_pm_ops,
.of_match_table = of_match_ptr(ov5695_of_match),
},

1503
drivers/media/i2c/ov7251.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1035,7 +1035,7 @@ static int ov772x_set_params(struct ov772x_priv *priv,
/* Set COM8. */
if (priv->band_filter) {
ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, 1);
ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, BNDF_ON_OFF);
if (!ret)
ret = ov772x_mask_set(client, BDBASE,
0xff, 256 - priv->band_filter);

View File

@@ -953,7 +953,7 @@ static int ov7740_init_controls(struct ov7740 *ov7740)
struct v4l2_ctrl_handler *ctrl_hdlr = &ov7740->ctrl_handler;
int ret;
ret = v4l2_ctrl_handler_init(ctrl_hdlr, 2);
ret = v4l2_ctrl_handler_init(ctrl_hdlr, 12);
if (ret < 0)
return ret;
@@ -980,27 +980,39 @@ static int ov7740_init_controls(struct ov7740 *ov7740)
V4L2_CID_HFLIP, 0, 1, 1, 0);
ov7740->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
ov7740->gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
V4L2_CID_GAIN, 0, 1023, 1, 500);
if (ov7740->gain)
ov7740->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
ov7740->auto_gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
ov7740->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
V4L2_CID_EXPOSURE, 0, 65535, 1, 500);
if (ov7740->exposure)
ov7740->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
ov7740->auto_exposure = v4l2_ctrl_new_std_menu(ctrl_hdlr,
&ov7740_ctrl_ops,
V4L2_CID_EXPOSURE_AUTO,
V4L2_EXPOSURE_MANUAL, 0,
V4L2_EXPOSURE_AUTO);
ov7740->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
ov7740->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
v4l2_ctrl_auto_cluster(3, &ov7740->auto_wb, 0, false);
v4l2_ctrl_auto_cluster(2, &ov7740->auto_gain, 0, true);
v4l2_ctrl_auto_cluster(2, &ov7740->auto_exposure,
V4L2_EXPOSURE_MANUAL, false);
v4l2_ctrl_cluster(2, &ov7740->hflip);
if (ctrl_hdlr->error) {
ret = ctrl_hdlr->error;
dev_err(&client->dev, "controls initialisation failed (%d)\n",
ret);
goto error;
}
ret = v4l2_ctrl_handler_setup(ctrl_hdlr);
if (ret) {
dev_err(&client->dev, "%s control init failed (%d)\n",
@@ -1074,7 +1086,7 @@ static int ov7740_probe(struct i2c_client *client,
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
sd->internal_ops = &ov7740_subdev_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
#endif
#if defined(CONFIG_MEDIA_CONTROLLER)

View File

@@ -1001,7 +1001,7 @@ static int smiapp_read_nvm(struct smiapp_sensor *sensor,
if (rval)
goto out;
for (i = 0; i < 1000; i++) {
for (i = 1000; i > 0; i--) {
rval = smiapp_read(
sensor,
SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS, &s);
@@ -1012,11 +1012,10 @@ static int smiapp_read_nvm(struct smiapp_sensor *sensor,
if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY)
break;
if (--i == 0) {
rval = -ETIMEDOUT;
goto out;
}
}
if (!i) {
rval = -ETIMEDOUT;
goto out;
}
for (i = 0; i < SMIAPP_NVM_PAGE_SIZE; i++) {

View File

@@ -2569,7 +2569,7 @@ static int tda1997x_probe(struct i2c_client *client,
snprintf(sd->name, sizeof(sd->name), "%s %d-%04x",
id->name, i2c_adapter_id(client->adapter),
client->addr);
sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
sd->entity.function = MEDIA_ENT_F_DTV_DECODER;
sd->entity.ops = &tda1997x_media_ops;
@@ -2723,7 +2723,7 @@ static int tda1997x_probe(struct i2c_client *client,
state->pads);
if (ret) {
v4l_err(client, "failed entity_init: %d", ret);
goto err_free_mutex;
goto err_free_handler;
}
ret = v4l2_async_register_subdev(sd);

View File

@@ -319,136 +319,136 @@ struct i2c_reg_value {
/* Default values as sugested at TVP5150AM1 datasheet */
static const struct i2c_reg_value tvp5150_init_default[] = {
{ /* 0x00 */
TVP5150_VD_IN_SRC_SEL_1,0x00
TVP5150_VD_IN_SRC_SEL_1, 0x00
},
{ /* 0x01 */
TVP5150_ANAL_CHL_CTL,0x15
TVP5150_ANAL_CHL_CTL, 0x15
},
{ /* 0x02 */
TVP5150_OP_MODE_CTL,0x00
TVP5150_OP_MODE_CTL, 0x00
},
{ /* 0x03 */
TVP5150_MISC_CTL,0x01
TVP5150_MISC_CTL, 0x01
},
{ /* 0x06 */
TVP5150_COLOR_KIL_THSH_CTL,0x10
TVP5150_COLOR_KIL_THSH_CTL, 0x10
},
{ /* 0x07 */
TVP5150_LUMA_PROC_CTL_1,0x60
TVP5150_LUMA_PROC_CTL_1, 0x60
},
{ /* 0x08 */
TVP5150_LUMA_PROC_CTL_2,0x00
TVP5150_LUMA_PROC_CTL_2, 0x00
},
{ /* 0x09 */
TVP5150_BRIGHT_CTL,0x80
TVP5150_BRIGHT_CTL, 0x80
},
{ /* 0x0a */
TVP5150_SATURATION_CTL,0x80
TVP5150_SATURATION_CTL, 0x80
},
{ /* 0x0b */
TVP5150_HUE_CTL,0x00
TVP5150_HUE_CTL, 0x00
},
{ /* 0x0c */
TVP5150_CONTRAST_CTL,0x80
TVP5150_CONTRAST_CTL, 0x80
},
{ /* 0x0d */
TVP5150_DATA_RATE_SEL,0x47
TVP5150_DATA_RATE_SEL, 0x47
},
{ /* 0x0e */
TVP5150_LUMA_PROC_CTL_3,0x00
TVP5150_LUMA_PROC_CTL_3, 0x00
},
{ /* 0x0f */
TVP5150_CONF_SHARED_PIN,0x08
TVP5150_CONF_SHARED_PIN, 0x08
},
{ /* 0x11 */
TVP5150_ACT_VD_CROP_ST_MSB,0x00
TVP5150_ACT_VD_CROP_ST_MSB, 0x00
},
{ /* 0x12 */
TVP5150_ACT_VD_CROP_ST_LSB,0x00
TVP5150_ACT_VD_CROP_ST_LSB, 0x00
},
{ /* 0x13 */
TVP5150_ACT_VD_CROP_STP_MSB,0x00
TVP5150_ACT_VD_CROP_STP_MSB, 0x00
},
{ /* 0x14 */
TVP5150_ACT_VD_CROP_STP_LSB,0x00
TVP5150_ACT_VD_CROP_STP_LSB, 0x00
},
{ /* 0x15 */
TVP5150_GENLOCK,0x01
TVP5150_GENLOCK, 0x01
},
{ /* 0x16 */
TVP5150_HORIZ_SYNC_START,0x80
TVP5150_HORIZ_SYNC_START, 0x80
},
{ /* 0x18 */
TVP5150_VERT_BLANKING_START,0x00
TVP5150_VERT_BLANKING_START, 0x00
},
{ /* 0x19 */
TVP5150_VERT_BLANKING_STOP,0x00
TVP5150_VERT_BLANKING_STOP, 0x00
},
{ /* 0x1a */
TVP5150_CHROMA_PROC_CTL_1,0x0c
TVP5150_CHROMA_PROC_CTL_1, 0x0c
},
{ /* 0x1b */
TVP5150_CHROMA_PROC_CTL_2,0x14
TVP5150_CHROMA_PROC_CTL_2, 0x14
},
{ /* 0x1c */
TVP5150_INT_RESET_REG_B,0x00
TVP5150_INT_RESET_REG_B, 0x00
},
{ /* 0x1d */
TVP5150_INT_ENABLE_REG_B,0x00
TVP5150_INT_ENABLE_REG_B, 0x00
},
{ /* 0x1e */
TVP5150_INTT_CONFIG_REG_B,0x00
TVP5150_INTT_CONFIG_REG_B, 0x00
},
{ /* 0x28 */
TVP5150_VIDEO_STD,0x00
TVP5150_VIDEO_STD, 0x00
},
{ /* 0x2e */
TVP5150_MACROVISION_ON_CTR,0x0f
TVP5150_MACROVISION_ON_CTR, 0x0f
},
{ /* 0x2f */
TVP5150_MACROVISION_OFF_CTR,0x01
TVP5150_MACROVISION_OFF_CTR, 0x01
},
{ /* 0xbb */
TVP5150_TELETEXT_FIL_ENA,0x00
TVP5150_TELETEXT_FIL_ENA, 0x00
},
{ /* 0xc0 */
TVP5150_INT_STATUS_REG_A,0x00
TVP5150_INT_STATUS_REG_A, 0x00
},
{ /* 0xc1 */
TVP5150_INT_ENABLE_REG_A,0x00
TVP5150_INT_ENABLE_REG_A, 0x00
},
{ /* 0xc2 */
TVP5150_INT_CONF,0x04
TVP5150_INT_CONF, 0x04
},
{ /* 0xc8 */
TVP5150_FIFO_INT_THRESHOLD,0x80
TVP5150_FIFO_INT_THRESHOLD, 0x80
},
{ /* 0xc9 */
TVP5150_FIFO_RESET,0x00
TVP5150_FIFO_RESET, 0x00
},
{ /* 0xca */
TVP5150_LINE_NUMBER_INT,0x00
TVP5150_LINE_NUMBER_INT, 0x00
},
{ /* 0xcb */
TVP5150_PIX_ALIGN_REG_LOW,0x4e
TVP5150_PIX_ALIGN_REG_LOW, 0x4e
},
{ /* 0xcc */
TVP5150_PIX_ALIGN_REG_HIGH,0x00
TVP5150_PIX_ALIGN_REG_HIGH, 0x00
},
{ /* 0xcd */
TVP5150_FIFO_OUT_CTRL,0x01
TVP5150_FIFO_OUT_CTRL, 0x01
},
{ /* 0xcf */
TVP5150_FULL_FIELD_ENA,0x00
TVP5150_FULL_FIELD_ENA, 0x00
},
{ /* 0xd0 */
TVP5150_LINE_MODE_INI,0x00
TVP5150_LINE_MODE_INI, 0x00
},
{ /* 0xfc */
TVP5150_FULL_FIELD_MODE_REG,0x7f
TVP5150_FULL_FIELD_MODE_REG, 0x7f
},
{ /* end of data */
0xff,0xff
0xff, 0xff
}
};
@@ -456,27 +456,27 @@ static const struct i2c_reg_value tvp5150_init_default[] = {
static const struct i2c_reg_value tvp5150_init_enable[] = {
{
TVP5150_CONF_SHARED_PIN, 2
},{ /* Automatic offset and AGC enabled */
}, { /* Automatic offset and AGC enabled */
TVP5150_ANAL_CHL_CTL, 0x15
},{ /* Activate YCrCb output 0x9 or 0xd ? */
}, { /* Activate YCrCb output 0x9 or 0xd ? */
TVP5150_MISC_CTL, TVP5150_MISC_CTL_GPCL |
TVP5150_MISC_CTL_INTREQ_OE |
TVP5150_MISC_CTL_YCBCR_OE |
TVP5150_MISC_CTL_SYNC_OE |
TVP5150_MISC_CTL_VBLANK |
TVP5150_MISC_CTL_CLOCK_OE,
},{ /* Activates video std autodetection for all standards */
}, { /* Activates video std autodetection for all standards */
TVP5150_AUTOSW_MSK, 0x0
},{ /* Default format: 0x47. For 4:2:2: 0x40 */
}, { /* Default format: 0x47. For 4:2:2: 0x40 */
TVP5150_DATA_RATE_SEL, 0x47
},{
}, {
TVP5150_CHROMA_PROC_CTL_1, 0x0c
},{
}, {
TVP5150_CHROMA_PROC_CTL_2, 0x54
},{ /* Non documented, but initialized on WinTV USB2 */
}, { /* Non documented, but initialized on WinTV USB2 */
0x27, 0x20
},{
0xff,0xff
}, {
0xff, 0xff
}
};
@@ -500,78 +500,80 @@ struct i2c_vbi_ram_value {
* and so on. There are 16 possible locations from 0 to 15.
*/
static struct i2c_vbi_ram_value vbi_ram_default[] =
{
/* FIXME: Current api doesn't handle all VBI types, those not
yet supported are placed under #if 0 */
static struct i2c_vbi_ram_value vbi_ram_default[] = {
/*
* FIXME: Current api doesn't handle all VBI types, those not
* yet supported are placed under #if 0
*/
#if 0
[0] = {0x010, /* Teletext, SECAM, WST System A */
{V4L2_SLICED_TELETEXT_SECAM,6,23,1},
{V4L2_SLICED_TELETEXT_SECAM, 6, 23, 1},
{ 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26,
0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 }
},
#endif
[1] = {0x030, /* Teletext, PAL, WST System B */
{V4L2_SLICED_TELETEXT_B,6,22,1},
{V4L2_SLICED_TELETEXT_B, 6, 22, 1},
{ 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b,
0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 }
},
#if 0
[2] = {0x050, /* Teletext, PAL, WST System C */
{V4L2_SLICED_TELETEXT_PAL_C,6,22,1},
{V4L2_SLICED_TELETEXT_PAL_C, 6, 22, 1},
{ 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22,
0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
},
[3] = {0x070, /* Teletext, NTSC, WST System B */
{V4L2_SLICED_TELETEXT_NTSC_B,10,21,1},
{V4L2_SLICED_TELETEXT_NTSC_B, 10, 21, 1},
{ 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23,
0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
},
[4] = {0x090, /* Tetetext, NTSC NABTS System C */
{V4L2_SLICED_TELETEXT_NTSC_C,10,21,1},
{V4L2_SLICED_TELETEXT_NTSC_C, 10, 21, 1},
{ 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22,
0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 }
},
[5] = {0x0b0, /* Teletext, NTSC-J, NABTS System D */
{V4L2_SLICED_TELETEXT_NTSC_D,10,21,1},
{V4L2_SLICED_TELETEXT_NTSC_D, 10, 21, 1},
{ 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23,
0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
},
[6] = {0x0d0, /* Closed Caption, PAL/SECAM */
{V4L2_SLICED_CAPTION_625,22,22,1},
{V4L2_SLICED_CAPTION_625, 22, 22, 1},
{ 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02,
0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 }
},
#endif
[7] = {0x0f0, /* Closed Caption, NTSC */
{V4L2_SLICED_CAPTION_525,21,21,1},
{V4L2_SLICED_CAPTION_525, 21, 21, 1},
{ 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02,
0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 }
},
[8] = {0x110, /* Wide Screen Signal, PAL/SECAM */
{V4L2_SLICED_WSS_625,23,23,1},
{V4L2_SLICED_WSS_625, 23, 23, 1},
{ 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42,
0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 }
},
#if 0
[9] = {0x130, /* Wide Screen Signal, NTSC C */
{V4L2_SLICED_WSS_525,20,20,1},
{V4L2_SLICED_WSS_525, 20, 20, 1},
{ 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43,
0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 }
},
[10] = {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */
{V4l2_SLICED_VITC_625,6,22,0},
{V4l2_SLICED_VITC_625, 6, 22, 0},
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49,
0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 }
},
[11] = {0x170, /* Vertical Interval Timecode (VITC), NTSC */
{V4l2_SLICED_VITC_525,10,20,0},
{V4l2_SLICED_VITC_525, 10, 20, 0},
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49,
0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 }
},
#endif
[12] = {0x190, /* Video Program System (VPS), PAL */
{V4L2_SLICED_VPS,16,16,0},
{V4L2_SLICED_VPS, 16, 16, 0},
{ 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d,
0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 }
},
@@ -623,7 +625,7 @@ static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd,
int line, i;
dev_dbg_lvl(sd->dev, 1, debug, "g_sliced_vbi_cap\n");
memset(cap, 0, sizeof *cap);
memset(cap, 0, sizeof(*cap));
for (i = 0; i < ARRAY_SIZE(vbi_ram_default); i++) {
const struct i2c_vbi_ram_value *regs = &vbi_ram_default[i];
@@ -655,7 +657,7 @@ static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd,
* MSB = field2
*/
static int tvp5150_set_vbi(struct v4l2_subdev *sd,
unsigned int type,u8 flags, int line,
unsigned int type, u8 flags, int line,
const int fields)
{
struct tvp5150 *decoder = to_tvp5150(sd);
@@ -1101,11 +1103,14 @@ static int tvp5150_s_routing(struct v4l2_subdev *sd,
static int tvp5150_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
{
/* this is for capturing 36 raw vbi lines
if there's a way to cut off the beginning 2 vbi lines
with the tvp5150 then the vbi line count could be lowered
to 17 lines/field again, although I couldn't find a register
which could do that cropping */
/*
* this is for capturing 36 raw vbi lines
* if there's a way to cut off the beginning 2 vbi lines
* with the tvp5150 then the vbi line count could be lowered
* to 17 lines/field again, although I couldn't find a register
* which could do that cropping
*/
if (fmt->sample_format == V4L2_PIX_FMT_GREY)
tvp5150_write(sd, TVP5150_LUMA_PROC_CTL_1, 0x70);
if (fmt->count[0] == 18 && fmt->count[1] == 18) {

View File

@@ -0,0 +1,564 @@
// SPDX-License-Identifier: GPL-2.0
/*
* video-i2c.c - Support for I2C transport video devices
*
* Copyright (C) 2018 Matt Ranostay <matt.ranostay@konsulko.com>
*
* Supported:
* - Panasonic AMG88xx Grid-Eye Sensors
*/
#include <linux/delay.h>
#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/i2c.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-vmalloc.h>
#define VIDEO_I2C_DRIVER "video-i2c"
struct video_i2c_chip;
struct video_i2c_buffer {
struct vb2_v4l2_buffer vb;
struct list_head list;
};
struct video_i2c_data {
struct i2c_client *client;
const struct video_i2c_chip *chip;
struct mutex lock;
spinlock_t slock;
unsigned int sequence;
struct mutex queue_lock;
struct v4l2_device v4l2_dev;
struct video_device vdev;
struct vb2_queue vb_vidq;
struct task_struct *kthread_vid_cap;
struct list_head vid_cap_active;
};
static const struct v4l2_fmtdesc amg88xx_format = {
.pixelformat = V4L2_PIX_FMT_Y12,
};
static const struct v4l2_frmsize_discrete amg88xx_size = {
.width = 8,
.height = 8,
};
struct video_i2c_chip {
/* video dimensions */
const struct v4l2_fmtdesc *format;
const struct v4l2_frmsize_discrete *size;
/* max frames per second */
unsigned int max_fps;
/* pixel buffer size */
unsigned int buffer_size;
/* pixel size in bits */
unsigned int bpp;
/* xfer function */
int (*xfer)(struct video_i2c_data *data, char *buf);
};
static int amg88xx_xfer(struct video_i2c_data *data, char *buf)
{
struct i2c_client *client = data->client;
struct i2c_msg msg[2];
u8 reg = 0x80;
int ret;
msg[0].addr = client->addr;
msg[0].flags = 0;
msg[0].len = 1;
msg[0].buf = (char *)&reg;
msg[1].addr = client->addr;
msg[1].flags = I2C_M_RD;
msg[1].len = data->chip->buffer_size;
msg[1].buf = (char *)buf;
ret = i2c_transfer(client->adapter, msg, 2);
return (ret == 2) ? 0 : -EIO;
}
#define AMG88XX 0
static const struct video_i2c_chip video_i2c_chip[] = {
[AMG88XX] = {
.size = &amg88xx_size,
.format = &amg88xx_format,
.max_fps = 10,
.buffer_size = 128,
.bpp = 16,
.xfer = &amg88xx_xfer,
},
};
static const struct v4l2_file_operations video_i2c_fops = {
.owner = THIS_MODULE,
.open = v4l2_fh_open,
.release = vb2_fop_release,
.poll = vb2_fop_poll,
.read = vb2_fop_read,
.mmap = vb2_fop_mmap,
.unlocked_ioctl = video_ioctl2,
};
static int queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], struct device *alloc_devs[])
{
struct video_i2c_data *data = vb2_get_drv_priv(vq);
unsigned int size = data->chip->buffer_size;
if (vq->num_buffers + *nbuffers < 2)
*nbuffers = 2;
if (*nplanes)
return sizes[0] < size ? -EINVAL : 0;
*nplanes = 1;
sizes[0] = size;
return 0;
}
static int buffer_prepare(struct vb2_buffer *vb)
{
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct video_i2c_data *data = vb2_get_drv_priv(vb->vb2_queue);
unsigned int size = data->chip->buffer_size;
if (vb2_plane_size(vb, 0) < size)
return -EINVAL;
vbuf->field = V4L2_FIELD_NONE;
vb2_set_plane_payload(vb, 0, size);
return 0;
}
static void buffer_queue(struct vb2_buffer *vb)
{
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct video_i2c_data *data = vb2_get_drv_priv(vb->vb2_queue);
struct video_i2c_buffer *buf =
container_of(vbuf, struct video_i2c_buffer, vb);
spin_lock(&data->slock);
list_add_tail(&buf->list, &data->vid_cap_active);
spin_unlock(&data->slock);
}
static int video_i2c_thread_vid_cap(void *priv)
{
struct video_i2c_data *data = priv;
unsigned int delay = msecs_to_jiffies(1000 / data->chip->max_fps);
set_freezable();
do {
unsigned long start_jiffies = jiffies;
struct video_i2c_buffer *vid_cap_buf = NULL;
int schedule_delay;
try_to_freeze();
spin_lock(&data->slock);
if (!list_empty(&data->vid_cap_active)) {
vid_cap_buf = list_last_entry(&data->vid_cap_active,
struct video_i2c_buffer, list);
list_del(&vid_cap_buf->list);
}
spin_unlock(&data->slock);
if (vid_cap_buf) {
struct vb2_buffer *vb2_buf = &vid_cap_buf->vb.vb2_buf;
void *vbuf = vb2_plane_vaddr(vb2_buf, 0);
int ret;
ret = data->chip->xfer(data, vbuf);
vb2_buf->timestamp = ktime_get_ns();
vid_cap_buf->vb.sequence = data->sequence++;
vb2_buffer_done(vb2_buf, ret ?
VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
}
schedule_delay = delay - (jiffies - start_jiffies);
if (time_after(jiffies, start_jiffies + delay))
schedule_delay = delay;
schedule_timeout_interruptible(schedule_delay);
} while (!kthread_should_stop());
return 0;
}
static void video_i2c_del_list(struct vb2_queue *vq, enum vb2_buffer_state state)
{
struct video_i2c_data *data = vb2_get_drv_priv(vq);
struct video_i2c_buffer *buf, *tmp;
spin_lock(&data->slock);
list_for_each_entry_safe(buf, tmp, &data->vid_cap_active, list) {
list_del(&buf->list);
vb2_buffer_done(&buf->vb.vb2_buf, state);
}
spin_unlock(&data->slock);
}
static int start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct video_i2c_data *data = vb2_get_drv_priv(vq);
if (data->kthread_vid_cap)
return 0;
data->sequence = 0;
data->kthread_vid_cap = kthread_run(video_i2c_thread_vid_cap, data,
"%s-vid-cap", data->v4l2_dev.name);
if (!IS_ERR(data->kthread_vid_cap))
return 0;
video_i2c_del_list(vq, VB2_BUF_STATE_QUEUED);
return PTR_ERR(data->kthread_vid_cap);
}
static void stop_streaming(struct vb2_queue *vq)
{
struct video_i2c_data *data = vb2_get_drv_priv(vq);
if (data->kthread_vid_cap == NULL)
return;
kthread_stop(data->kthread_vid_cap);
data->kthread_vid_cap = NULL;
video_i2c_del_list(vq, VB2_BUF_STATE_ERROR);
}
static struct vb2_ops video_i2c_video_qops = {
.queue_setup = queue_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
};
static int video_i2c_querycap(struct file *file, void *priv,
struct v4l2_capability *vcap)
{
struct video_i2c_data *data = video_drvdata(file);
struct i2c_client *client = data->client;
strlcpy(vcap->driver, data->v4l2_dev.name, sizeof(vcap->driver));
strlcpy(vcap->card, data->vdev.name, sizeof(vcap->card));
sprintf(vcap->bus_info, "I2C:%d-%d", client->adapter->nr, client->addr);
return 0;
}
static int video_i2c_g_input(struct file *file, void *fh, unsigned int *inp)
{
*inp = 0;
return 0;
}
static int video_i2c_s_input(struct file *file, void *fh, unsigned int inp)
{
return (inp > 0) ? -EINVAL : 0;
}
static int video_i2c_enum_input(struct file *file, void *fh,
struct v4l2_input *vin)
{
if (vin->index > 0)
return -EINVAL;
strlcpy(vin->name, "Camera", sizeof(vin->name));
vin->type = V4L2_INPUT_TYPE_CAMERA;
return 0;
}
static int video_i2c_enum_fmt_vid_cap(struct file *file, void *fh,
struct v4l2_fmtdesc *fmt)
{
struct video_i2c_data *data = video_drvdata(file);
enum v4l2_buf_type type = fmt->type;
if (fmt->index > 0)
return -EINVAL;
*fmt = *data->chip->format;
fmt->type = type;
return 0;
}
static int video_i2c_enum_framesizes(struct file *file, void *fh,
struct v4l2_frmsizeenum *fsize)
{
const struct video_i2c_data *data = video_drvdata(file);
const struct v4l2_frmsize_discrete *size = data->chip->size;
/* currently only one frame size is allowed */
if (fsize->index > 0)
return -EINVAL;
if (fsize->pixel_format != data->chip->format->pixelformat)
return -EINVAL;
fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
fsize->discrete.width = size->width;
fsize->discrete.height = size->height;
return 0;
}
static int video_i2c_enum_frameintervals(struct file *file, void *priv,
struct v4l2_frmivalenum *fe)
{
const struct video_i2c_data *data = video_drvdata(file);
const struct v4l2_frmsize_discrete *size = data->chip->size;
if (fe->index > 0)
return -EINVAL;
if (fe->width != size->width || fe->height != size->height)
return -EINVAL;
fe->type = V4L2_FRMIVAL_TYPE_DISCRETE;
fe->discrete.numerator = 1;
fe->discrete.denominator = data->chip->max_fps;
return 0;
}
static int video_i2c_try_fmt_vid_cap(struct file *file, void *fh,
struct v4l2_format *fmt)
{
const struct video_i2c_data *data = video_drvdata(file);
const struct v4l2_frmsize_discrete *size = data->chip->size;
struct v4l2_pix_format *pix = &fmt->fmt.pix;
unsigned int bpp = data->chip->bpp / 8;
pix->width = size->width;
pix->height = size->height;
pix->pixelformat = data->chip->format->pixelformat;
pix->field = V4L2_FIELD_NONE;
pix->bytesperline = pix->width * bpp;
pix->sizeimage = pix->bytesperline * pix->height;
pix->colorspace = V4L2_COLORSPACE_RAW;
return 0;
}
static int video_i2c_s_fmt_vid_cap(struct file *file, void *fh,
struct v4l2_format *fmt)
{
struct video_i2c_data *data = video_drvdata(file);
if (vb2_is_busy(&data->vb_vidq))
return -EBUSY;
return video_i2c_try_fmt_vid_cap(file, fh, fmt);
}
static int video_i2c_g_parm(struct file *filp, void *priv,
struct v4l2_streamparm *parm)
{
struct video_i2c_data *data = video_drvdata(filp);
if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
parm->parm.capture.readbuffers = 1;
parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
parm->parm.capture.timeperframe.numerator = 1;
parm->parm.capture.timeperframe.denominator = data->chip->max_fps;
return 0;
}
static const struct v4l2_ioctl_ops video_i2c_ioctl_ops = {
.vidioc_querycap = video_i2c_querycap,
.vidioc_g_input = video_i2c_g_input,
.vidioc_s_input = video_i2c_s_input,
.vidioc_enum_input = video_i2c_enum_input,
.vidioc_enum_fmt_vid_cap = video_i2c_enum_fmt_vid_cap,
.vidioc_enum_framesizes = video_i2c_enum_framesizes,
.vidioc_enum_frameintervals = video_i2c_enum_frameintervals,
.vidioc_g_fmt_vid_cap = video_i2c_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = video_i2c_s_fmt_vid_cap,
.vidioc_g_parm = video_i2c_g_parm,
.vidioc_s_parm = video_i2c_g_parm,
.vidioc_try_fmt_vid_cap = video_i2c_try_fmt_vid_cap,
.vidioc_reqbufs = vb2_ioctl_reqbufs,
.vidioc_create_bufs = vb2_ioctl_create_bufs,
.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
.vidioc_querybuf = vb2_ioctl_querybuf,
.vidioc_qbuf = vb2_ioctl_qbuf,
.vidioc_dqbuf = vb2_ioctl_dqbuf,
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
};
static void video_i2c_release(struct video_device *vdev)
{
kfree(video_get_drvdata(vdev));
}
static int video_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct video_i2c_data *data;
struct v4l2_device *v4l2_dev;
struct vb2_queue *queue;
int ret = -ENODEV;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
if (dev_fwnode(&client->dev))
data->chip = device_get_match_data(&client->dev);
else if (id)
data->chip = &video_i2c_chip[id->driver_data];
else
goto error_free_device;
data->client = client;
v4l2_dev = &data->v4l2_dev;
strlcpy(v4l2_dev->name, VIDEO_I2C_DRIVER, sizeof(v4l2_dev->name));
ret = v4l2_device_register(&client->dev, v4l2_dev);
if (ret < 0)
goto error_free_device;
mutex_init(&data->lock);
mutex_init(&data->queue_lock);
queue = &data->vb_vidq;
queue->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
queue->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR | VB2_READ;
queue->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
queue->drv_priv = data;
queue->buf_struct_size = sizeof(struct video_i2c_buffer);
queue->min_buffers_needed = 1;
queue->ops = &video_i2c_video_qops;
queue->mem_ops = &vb2_vmalloc_memops;
ret = vb2_queue_init(queue);
if (ret < 0)
goto error_unregister_device;
data->vdev.queue = queue;
data->vdev.queue->lock = &data->queue_lock;
snprintf(data->vdev.name, sizeof(data->vdev.name),
"I2C %d-%d Transport Video",
client->adapter->nr, client->addr);
data->vdev.v4l2_dev = v4l2_dev;
data->vdev.fops = &video_i2c_fops;
data->vdev.lock = &data->lock;
data->vdev.ioctl_ops = &video_i2c_ioctl_ops;
data->vdev.release = video_i2c_release;
data->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
spin_lock_init(&data->slock);
INIT_LIST_HEAD(&data->vid_cap_active);
video_set_drvdata(&data->vdev, data);
i2c_set_clientdata(client, data);
ret = video_register_device(&data->vdev, VFL_TYPE_GRABBER, -1);
if (ret < 0)
goto error_unregister_device;
return 0;
error_unregister_device:
v4l2_device_unregister(v4l2_dev);
mutex_destroy(&data->lock);
mutex_destroy(&data->queue_lock);
error_free_device:
kfree(data);
return ret;
}
static int video_i2c_remove(struct i2c_client *client)
{
struct video_i2c_data *data = i2c_get_clientdata(client);
video_unregister_device(&data->vdev);
v4l2_device_unregister(&data->v4l2_dev);
mutex_destroy(&data->lock);
mutex_destroy(&data->queue_lock);
return 0;
}
static const struct i2c_device_id video_i2c_id_table[] = {
{ "amg88xx", AMG88XX },
{}
};
MODULE_DEVICE_TABLE(i2c, video_i2c_id_table);
static const struct of_device_id video_i2c_of_match[] = {
{ .compatible = "panasonic,amg88xx", .data = &video_i2c_chip[AMG88XX] },
{}
};
MODULE_DEVICE_TABLE(of, video_i2c_of_match);
static struct i2c_driver video_i2c_driver = {
.driver = {
.name = VIDEO_I2C_DRIVER,
.of_match_table = video_i2c_of_match,
},
.probe = video_i2c_probe,
.remove = video_i2c_remove,
.id_table = video_i2c_id_table,
};
module_i2c_driver(video_i2c_driver);
MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
MODULE_DESCRIPTION("I2C transport video support");
MODULE_LICENSE("GPL v2");