diff options
Diffstat (limited to 'drivers/media/i2c')
42 files changed, 2325 insertions, 1274 deletions
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index cb5d7ff82915..9f18cd296841 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -665,6 +665,14 @@ config VIDEO_OV7670 OV7670 VGA camera. It currently only works with the M88ALP01 controller. +config VIDEO_OV7740 + tristate "OmniVision OV7740 sensor support" + depends on I2C && VIDEO_V4L2 + depends on MEDIA_CAMERA_SUPPORT + ---help--- + This is a Video4Linux2 sensor-level driver for the OmniVision + OV7740 VGA camera sensor. + config VIDEO_OV9650 tristate "OmniVision OV9650/OV9652 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API @@ -777,12 +785,12 @@ config VIDEO_S5K6A3 camera sensor. config VIDEO_S5K4ECGX - tristate "Samsung S5K4ECGX sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + tristate "Samsung S5K4ECGX sensor support" + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API select CRC32 - ---help--- - This is a V4L2 sensor-level driver for Samsung S5K4ECGX 5M - camera sensor with an embedded SoC image signal processor. + ---help--- + This is a V4L2 sensor-level driver for Samsung S5K4ECGX 5M + camera sensor with an embedded SoC image signal processor. config VIDEO_S5K5BAF tristate "Samsung S5K5BAF sensor support" @@ -813,14 +821,6 @@ config VIDEO_ADP1653 This is a driver for the ADP1653 flash controller. It is used for example in Nokia N900. -config VIDEO_AS3645A - tristate "AS3645A flash driver support" - depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER - depends on MEDIA_CAMERA_SUPPORT - ---help--- - This is a driver for the AS3645A and LM3555 flash controllers. It has - build in control for flash, torch and indicator LEDs. - config VIDEO_LM3560 tristate "LM3560 dual flash driver support" depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 548a9efce966..c0f94cd8d56d 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_VIDEO_OV5670) += ov5670.o obj-$(CONFIG_VIDEO_OV6650) += ov6650.o obj-$(CONFIG_VIDEO_OV7640) += ov7640.o obj-$(CONFIG_VIDEO_OV7670) += ov7670.o +obj-$(CONFIG_VIDEO_OV7740) += ov7740.o obj-$(CONFIG_VIDEO_OV9650) += ov9650.o obj-$(CONFIG_VIDEO_OV13858) += ov13858.o obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o @@ -84,7 +85,6 @@ obj-$(CONFIG_VIDEO_S5K4ECGX) += s5k4ecgx.o obj-$(CONFIG_VIDEO_S5K5BAF) += s5k5baf.o obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3/ obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o -obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o obj-$(CONFIG_VIDEO_LM3560) += lm3560.o obj-$(CONFIG_VIDEO_LM3646) += lm3646.o obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 6fb818a775db..25d24a3f10a7 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -1366,11 +1366,9 @@ err_media_entity_cleanup: err_free_ctrl: adv7180_exit_controls(state); err_unregister_vpp_client: - if (state->chip_info->flags & ADV7180_FLAG_I2P) - i2c_unregister_device(state->vpp_client); + i2c_unregister_device(state->vpp_client); err_unregister_csi_client: - if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) - i2c_unregister_device(state->csi_client); + i2c_unregister_device(state->csi_client); mutex_destroy(&state->mutex); return ret; } @@ -1388,10 +1386,8 @@ static int adv7180_remove(struct i2c_client *client) media_entity_cleanup(&sd->entity); adv7180_exit_controls(state); - if (state->chip_info->flags & ADV7180_FLAG_I2P) - i2c_unregister_device(state->vpp_client); - if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) - i2c_unregister_device(state->csi_client); + i2c_unregister_device(state->vpp_client); + i2c_unregister_device(state->csi_client); adv7180_set_power_pin(state, false); diff --git a/drivers/media/i2c/adv7343.c b/drivers/media/i2c/adv7343.c index 11f9029433cf..4a441ee99dd8 100644 --- a/drivers/media/i2c/adv7343.c +++ b/drivers/media/i2c/adv7343.c @@ -100,7 +100,7 @@ static const u8 adv7343_init_reg_val[] = { }; /* - * 2^32 + * 2^32 * FSC(reg) = FSC (HZ) * -------- * 27000000 */ diff --git a/drivers/media/i2c/adv7393.c b/drivers/media/i2c/adv7393.c index f19ad4ecd11e..b6234c8231c9 100644 --- a/drivers/media/i2c/adv7393.c +++ b/drivers/media/i2c/adv7393.c @@ -103,7 +103,7 @@ static const u8 adv7393_init_reg_val[] = { }; /* - * 2^32 + * 2^32 * FSC(reg) = FSC (HZ) * -------- * 27000000 */ diff --git a/drivers/media/i2c/adv748x/adv748x-afe.c b/drivers/media/i2c/adv748x/adv748x-afe.c index 4aa8e45b5cd3..5188178588c9 100644 --- a/drivers/media/i2c/adv748x/adv748x-afe.c +++ b/drivers/media/i2c/adv748x/adv748x-afe.c @@ -267,6 +267,7 @@ static int adv748x_afe_g_input_status(struct v4l2_subdev *sd, u32 *status) ret = adv748x_afe_status(afe, status, NULL); mutex_unlock(&state->mutex); + return ret; } diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c index 5ee14f2c2747..fd92c9e4b519 100644 --- a/drivers/media/i2c/adv748x/adv748x-core.c +++ b/drivers/media/i2c/adv748x/adv748x-core.c @@ -225,10 +225,8 @@ static void adv748x_unregister_clients(struct adv748x_state *state) { unsigned int i; - for (i = 1; i < ARRAY_SIZE(state->i2c_clients); ++i) { - if (state->i2c_clients[i]) - i2c_unregister_device(state->i2c_clients[i]); - } + for (i = 1; i < ARRAY_SIZE(state->i2c_clients); ++i) + i2c_unregister_device(state->i2c_clients[i]); } static int adv748x_initialise_clients(struct adv748x_state *state) @@ -646,14 +644,12 @@ static int adv748x_parse_dt(struct adv748x_state *state) for_each_endpoint_of_node(state->dev->of_node, ep_np) { of_graph_parse_endpoint(ep_np, &ep); - adv_info(state, "Endpoint %s on port %d", - of_node_full_name(ep.local_node), - ep.port); + adv_info(state, "Endpoint %pOF on port %d", ep.local_node, + ep.port); if (ep.port >= ADV748X_PORT_MAX) { - adv_err(state, "Invalid endpoint %s on port %d", - of_node_full_name(ep.local_node), - ep.port); + adv_err(state, "Invalid endpoint %pOF on port %d", + ep.local_node, ep.port); continue; } diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c index 979825d4a419..820b44ed56a8 100644 --- a/drivers/media/i2c/adv748x/adv748x-csi2.c +++ b/drivers/media/i2c/adv748x/adv748x-csi2.c @@ -223,13 +223,12 @@ static const struct v4l2_subdev_ops adv748x_csi2_ops = { int adv748x_csi2_set_pixelrate(struct v4l2_subdev *sd, s64 rate) { - struct v4l2_ctrl *ctrl; + struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); - ctrl = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_PIXEL_RATE); - if (!ctrl) + if (!tx->pixel_rate) return -EINVAL; - return v4l2_ctrl_s_ctrl_int64(ctrl, rate); + return v4l2_ctrl_s_ctrl_int64(tx->pixel_rate, rate); } static int adv748x_csi2_s_ctrl(struct v4l2_ctrl *ctrl) @@ -251,8 +250,10 @@ static int adv748x_csi2_init_controls(struct adv748x_csi2 *tx) v4l2_ctrl_handler_init(&tx->ctrl_hdl, 1); - v4l2_ctrl_new_std(&tx->ctrl_hdl, &adv748x_csi2_ctrl_ops, - V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1); + tx->pixel_rate = v4l2_ctrl_new_std(&tx->ctrl_hdl, + &adv748x_csi2_ctrl_ops, + V4L2_CID_PIXEL_RATE, 1, INT_MAX, + 1, 1); tx->sd.ctrl_handler = &tx->ctrl_hdl; if (tx->ctrl_hdl.error) { diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h index cc4151b5b31e..6789e2f3bc8c 100644 --- a/drivers/media/i2c/adv748x/adv748x.h +++ b/drivers/media/i2c/adv748x/adv748x.h @@ -97,6 +97,7 @@ struct adv748x_csi2 { struct media_pad pads[ADV748X_CSI2_NR_PADS]; struct v4l2_ctrl_handler ctrl_hdl; + struct v4l2_ctrl *pixel_rate; struct v4l2_subdev sd; }; diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index c786cd125417..1544920ec52d 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1982,6 +1982,7 @@ static void adv76xx_cec_tx_raw_status(struct v4l2_subdev *sd, u8 tx_raw_status) __func__); cec_transmit_done(state->cec_adap, CEC_TX_STATUS_ARB_LOST, 1, 0, 0, 0); + return; } if (tx_raw_status & 0x04) { u8 status; diff --git a/drivers/media/i2c/as3645a.c b/drivers/media/i2c/as3645a.c deleted file mode 100644 index af5db71a0888..000000000000 --- a/drivers/media/i2c/as3645a.c +++ /dev/null @@ -1,880 +0,0 @@ -/* - * drivers/media/i2c/as3645a.c - AS3645A and LM3555 flash controllers driver - * - * Copyright (C) 2008-2011 Nokia Corporation - * Copyright (c) 2011, Intel Corporation. - * - * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * TODO: - * - Check hardware FSTROBE control when sensor driver add support for this - * - */ - -#include <linux/delay.h> -#include <linux/i2c.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/slab.h> - -#include <media/i2c/as3645a.h> -#include <media/v4l2-ctrls.h> -#include <media/v4l2-device.h> - -#define AS_TIMER_MS_TO_CODE(t) (((t) - 100) / 50) -#define AS_TIMER_CODE_TO_MS(c) (50 * (c) + 100) - -/* Register definitions */ - -/* Read-only Design info register: Reset state: xxxx 0001 */ -#define AS_DESIGN_INFO_REG 0x00 -#define AS_DESIGN_INFO_FACTORY(x) (((x) >> 4)) -#define AS_DESIGN_INFO_MODEL(x) ((x) & 0x0f) - -/* Read-only Version control register: Reset state: 0000 0000 - * for first engineering samples - */ -#define AS_VERSION_CONTROL_REG 0x01 -#define AS_VERSION_CONTROL_RFU(x) (((x) >> 4)) -#define AS_VERSION_CONTROL_VERSION(x) ((x) & 0x0f) - -/* Read / Write (Indicator and timer register): Reset state: 0000 1111 */ -#define AS_INDICATOR_AND_TIMER_REG 0x02 -#define AS_INDICATOR_AND_TIMER_TIMEOUT_SHIFT 0 -#define AS_INDICATOR_AND_TIMER_VREF_SHIFT 4 -#define AS_INDICATOR_AND_TIMER_INDICATOR_SHIFT 6 - -/* Read / Write (Current set register): Reset state: 0110 1001 */ -#define AS_CURRENT_SET_REG 0x03 -#define AS_CURRENT_ASSIST_LIGHT_SHIFT 0 -#define AS_CURRENT_LED_DET_ON (1 << 3) -#define AS_CURRENT_FLASH_CURRENT_SHIFT 4 - -/* Read / Write (Control register): Reset state: 1011 0100 */ -#define AS_CONTROL_REG 0x04 -#define AS_CONTROL_MODE_SETTING_SHIFT 0 -#define AS_CONTROL_STROBE_ON (1 << 2) -#define AS_CONTROL_OUT_ON (1 << 3) -#define AS_CONTROL_EXT_TORCH_ON (1 << 4) -#define AS_CONTROL_STROBE_TYPE_EDGE (0 << 5) -#define AS_CONTROL_STROBE_TYPE_LEVEL (1 << 5) -#define AS_CONTROL_COIL_PEAK_SHIFT 6 - -/* Read only (D3 is read / write) (Fault and info): Reset state: 0000 x000 */ -#define AS_FAULT_INFO_REG 0x05 -#define AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT (1 << 1) -#define AS_FAULT_INFO_INDICATOR_LED (1 << 2) -#define AS_FAULT_INFO_LED_AMOUNT (1 << 3) -#define AS_FAULT_INFO_TIMEOUT (1 << 4) -#define AS_FAULT_INFO_OVER_TEMPERATURE (1 << 5) -#define AS_FAULT_INFO_SHORT_CIRCUIT (1 << 6) -#define AS_FAULT_INFO_OVER_VOLTAGE (1 << 7) - -/* Boost register */ -#define AS_BOOST_REG 0x0d -#define AS_BOOST_CURRENT_DISABLE (0 << 0) -#define AS_BOOST_CURRENT_ENABLE (1 << 0) - -/* Password register is used to unlock boost register writing */ -#define AS_PASSWORD_REG 0x0f -#define AS_PASSWORD_UNLOCK_VALUE 0x55 - -enum as_mode { - AS_MODE_EXT_TORCH = 0 << AS_CONTROL_MODE_SETTING_SHIFT, - AS_MODE_INDICATOR = 1 << AS_CONTROL_MODE_SETTING_SHIFT, - AS_MODE_ASSIST = 2 << AS_CONTROL_MODE_SETTING_SHIFT, - AS_MODE_FLASH = 3 << AS_CONTROL_MODE_SETTING_SHIFT, -}; - -/* - * struct as3645a - * - * @subdev: V4L2 subdev - * @pdata: Flash platform data - * @power_lock: Protects power_count - * @power_count: Power reference count - * @led_mode: V4L2 flash LED mode - * @timeout: Flash timeout in microseconds - * @flash_current: Flash current (0=200mA ... 15=500mA). Maximum - * values are 400mA for two LEDs and 500mA for one LED. - * @assist_current: Torch/Assist light current (0=20mA, 1=40mA ... 7=160mA) - * @indicator_current: Indicator LED current (0=0mA, 1=2.5mA ... 4=10mA) - * @strobe_source: Flash strobe source (software or external) - */ -struct as3645a { - struct v4l2_subdev subdev; - const struct as3645a_platform_data *pdata; - - struct mutex power_lock; - int power_count; - - /* Controls */ - struct v4l2_ctrl_handler ctrls; - - enum v4l2_flash_led_mode led_mode; - unsigned int timeout; - u8 flash_current; - u8 assist_current; - u8 indicator_current; - enum v4l2_flash_strobe_source strobe_source; -}; - -#define to_as3645a(sd) container_of(sd, struct as3645a, subdev) - -/* Return negative errno else zero on success */ -static int as3645a_write(struct as3645a *flash, u8 addr, u8 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); - int rval; - - rval = i2c_smbus_write_byte_data(client, addr, val); - - dev_dbg(&client->dev, "Write Addr:%02X Val:%02X %s\n", addr, val, - rval < 0 ? "fail" : "ok"); - - return rval; -} - -/* Return negative errno else a data byte received from the device. */ -static int as3645a_read(struct as3645a *flash, u8 addr) -{ - struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); - int rval; - - rval = i2c_smbus_read_byte_data(client, addr); - - dev_dbg(&client->dev, "Read Addr:%02X Val:%02X %s\n", addr, rval, - rval < 0 ? "fail" : "ok"); - - return rval; -} - -/* ----------------------------------------------------------------------------- - * Hardware configuration and trigger - */ - -/* - * as3645a_set_config - Set flash configuration registers - * @flash: The flash - * - * Configure the hardware with flash, assist and indicator currents, as well as - * flash timeout. - * - * Return 0 on success, or a negative error code if an I2C communication error - * occurred. - */ -static int as3645a_set_config(struct as3645a *flash) -{ - int ret; - u8 val; - - val = (flash->flash_current << AS_CURRENT_FLASH_CURRENT_SHIFT) - | (flash->assist_current << AS_CURRENT_ASSIST_LIGHT_SHIFT) - | AS_CURRENT_LED_DET_ON; - - ret = as3645a_write(flash, AS_CURRENT_SET_REG, val); - if (ret < 0) - return ret; - - val = AS_TIMER_MS_TO_CODE(flash->timeout / 1000) - << AS_INDICATOR_AND_TIMER_TIMEOUT_SHIFT; - - val |= (flash->pdata->vref << AS_INDICATOR_AND_TIMER_VREF_SHIFT) - | ((flash->indicator_current ? flash->indicator_current - 1 : 0) - << AS_INDICATOR_AND_TIMER_INDICATOR_SHIFT); - - return as3645a_write(flash, AS_INDICATOR_AND_TIMER_REG, val); -} - -/* - * as3645a_set_control - Set flash control register - * @flash: The flash - * @mode: Desired output mode - * @on: Desired output state - * - * Configure the hardware with output mode and state. - * - * Return 0 on success, or a negative error code if an I2C communication error - * occurred. - */ -static int -as3645a_set_control(struct as3645a *flash, enum as_mode mode, bool on) -{ - u8 reg; - - /* Configure output parameters and operation mode. */ - reg = (flash->pdata->peak << AS_CONTROL_COIL_PEAK_SHIFT) - | (on ? AS_CONTROL_OUT_ON : 0) - | mode; - - if (flash->led_mode == V4L2_FLASH_LED_MODE_FLASH && - flash->strobe_source == V4L2_FLASH_STROBE_SOURCE_EXTERNAL) { - reg |= AS_CONTROL_STROBE_TYPE_LEVEL - | AS_CONTROL_STROBE_ON; - } - - return as3645a_write(flash, AS_CONTROL_REG, reg); -} - -/* - * as3645a_set_output - Configure output and operation mode - * @flash: Flash controller - * @strobe: Strobe the flash (only valid in flash mode) - * - * Turn the LEDs output on/off and set the operation mode based on the current - * parameters. - * - * The AS3645A can't control the indicator LED independently of the flash/torch - * LED. If the flash controller is in V4L2_FLASH_LED_MODE_NONE mode, set the - * chip to indicator mode. Otherwise set it to assist light (torch) or flash - * mode. - * - * In indicator and assist modes, turn the output on/off based on the indicator - * and torch currents. In software strobe flash mode, turn the output on/off - * based on the strobe parameter. - */ -static int as3645a_set_output(struct as3645a *flash, bool strobe) -{ - enum as_mode mode; - bool on; - - switch (flash->led_mode) { - case V4L2_FLASH_LED_MODE_NONE: - on = flash->indicator_current != 0; - mode = AS_MODE_INDICATOR; - break; - case V4L2_FLASH_LED_MODE_TORCH: - on = true; - mode = AS_MODE_ASSIST; - break; - case V4L2_FLASH_LED_MODE_FLASH: - on = strobe; - mode = AS_MODE_FLASH; - break; - default: - BUG(); - } - - /* Configure output parameters and operation mode. */ - return as3645a_set_control(flash, mode, on); -} - -/* ----------------------------------------------------------------------------- - * V4L2 controls - */ - -static int as3645a_is_active(struct as3645a *flash) -{ - int ret; - - ret = as3645a_read(flash, AS_CONTROL_REG); - return ret < 0 ? ret : !!(ret & AS_CONTROL_OUT_ON); -} - -static int as3645a_read_fault(struct as3645a *flash) -{ - struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); - int rval; - - /* NOTE: reading register clear fault status */ - rval = as3645a_read(flash, AS_FAULT_INFO_REG); - if (rval < 0) - return rval; - - if (rval & AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT) - dev_dbg(&client->dev, "Inductor Peak limit fault\n"); - - if (rval & AS_FAULT_INFO_INDICATOR_LED) - dev_dbg(&client->dev, - "Indicator LED fault: Short circuit or open loop\n"); - - dev_dbg(&client->dev, "%u connected LEDs\n", - rval & AS_FAULT_INFO_LED_AMOUNT ? 2 : 1); - - if (rval & AS_FAULT_INFO_TIMEOUT) - dev_dbg(&client->dev, "Timeout fault\n"); - - if (rval & AS_FAULT_INFO_OVER_TEMPERATURE) - dev_dbg(&client->dev, "Over temperature fault\n"); - - if (rval & AS_FAULT_INFO_SHORT_CIRCUIT) - dev_dbg(&client->dev, "Short circuit fault\n"); - - if (rval & AS_FAULT_INFO_OVER_VOLTAGE) - dev_dbg(&client->dev, - "Over voltage fault: Indicates missing capacitor or open connection\n"); - - return rval; -} - -static int as3645a_get_ctrl(struct v4l2_ctrl *ctrl) -{ - struct as3645a *flash = - container_of(ctrl->handler, struct as3645a, ctrls); - struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); - int value; - - switch (ctrl->id) { - case V4L2_CID_FLASH_FAULT: - value = as3645a_read_fault(flash); - if (value < 0) - return value; - - ctrl->cur.val = 0; - if (value & AS_FAULT_INFO_SHORT_CIRCUIT) - ctrl->cur.val |= V4L2_FLASH_FAULT_SHORT_CIRCUIT; - if (value & AS_FAULT_INFO_OVER_TEMPERATURE) - ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_TEMPERATURE; - if (value & AS_FAULT_INFO_TIMEOUT) - ctrl->cur.val |= V4L2_FLASH_FAULT_TIMEOUT; - if (value & AS_FAULT_INFO_OVER_VOLTAGE) - ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_VOLTAGE; - if (value & AS_FAULT_INFO_INDUCTOR_PEAK_LIMIT) - ctrl->cur.val |= V4L2_FLASH_FAULT_OVER_CURRENT; - if (value & AS_FAULT_INFO_INDICATOR_LED) - ctrl->cur.val |= V4L2_FLASH_FAULT_INDICATOR; - break; - - case V4L2_CID_FLASH_STROBE_STATUS: - if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) { - ctrl->cur.val = 0; - break; - } - - value = as3645a_is_active(flash); - if (value < 0) - return value; - - ctrl->cur.val = value; - break; - } - - dev_dbg(&client->dev, "G_CTRL %08x:%d\n", ctrl->id, ctrl->cur.val); - - return 0; -} - -static int as3645a_set_ctrl(struct v4l2_ctrl *ctrl) -{ - struct as3645a *flash = - container_of(ctrl->handler, struct as3645a, ctrls); - struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); - int ret; - - dev_dbg(&client->dev, "S_CTRL %08x:%d\n", ctrl->id, ctrl->val); - - /* If a control that doesn't apply to the current mode is modified, - * we store the value and return immediately. The setting will be - * applied when the LED mode is changed. Otherwise we apply the setting - * immediately. - */ - - switch (ctrl->id) { - case V4L2_CID_FLASH_LED_MODE: - if (flash->indicator_current) - return -EBUSY; - - ret = as3645a_set_config(flash); - if (ret < 0) - return ret; - - flash->led_mode = ctrl->val; - return as3645a_set_output(flash, false); - - case V4L2_CID_FLASH_STROBE_SOURCE: - flash->strobe_source = ctrl->val; - - /* Applies to flash mode only. */ - if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) - break; - - return as3645a_set_output(flash, false); - - case V4L2_CID_FLASH_STROBE: - if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) - return -EBUSY; - - return as3645a_set_output(flash, true); - - case V4L2_CID_FLASH_STROBE_STOP: - if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) - return -EBUSY; - - return as3645a_set_output(flash, false); - - case V4L2_CID_FLASH_TIMEOUT: - flash->timeout = ctrl->val; - - /* Applies to flash mode only. */ - if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) - break; - - return as3645a_set_config(flash); - - case V4L2_CID_FLASH_INTENSITY: - flash->flash_current = (ctrl->val - AS3645A_FLASH_INTENSITY_MIN) - / AS3645A_FLASH_INTENSITY_STEP; - - /* Applies to flash mode only. */ - if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) - break; - - return as3645a_set_config(flash); - - case V4L2_CID_FLASH_TORCH_INTENSITY: - flash->assist_current = - (ctrl->val - AS3645A_TORCH_INTENSITY_MIN) - / AS3645A_TORCH_INTENSITY_STEP; - - /* Applies to torch mode only. */ - if (flash->led_mode != V4L2_FLASH_LED_MODE_TORCH) - break; - - return as3645a_set_config(flash); - - case V4L2_CID_FLASH_INDICATOR_INTENSITY: - if (flash->led_mode != V4L2_FLASH_LED_MODE_NONE) - return -EBUSY; - - flash->indicator_current = - (ctrl->val - AS3645A_INDICATOR_INTENSITY_MIN) - / AS3645A_INDICATOR_INTENSITY_STEP; - - ret = as3645a_set_config(flash); - if (ret < 0) - return ret; - - if ((ctrl->val == 0) == (ctrl->cur.val == 0)) - break; - - return as3645a_set_output(flash, false); - } - - return 0; -} - -static const struct v4l2_ctrl_ops as3645a_ctrl_ops = { - .g_volatile_ctrl = as3645a_get_ctrl, - .s_ctrl = as3645a_set_ctrl, -}; - -/* ----------------------------------------------------------------------------- - * V4L2 subdev core operations - */ - -/* Put device into know state. */ -static int as3645a_setup(struct as3645a *flash) -{ - struct i2c_client *client = v4l2_get_subdevdata(&flash->subdev); - int ret; - - /* clear errors */ - ret = as3645a_read(flash, AS_FAULT_INFO_REG); - if (ret < 0) - return ret; - - dev_dbg(&client->dev, "Fault info: %02x\n", ret); - - ret = as3645a_set_config(flash); - if (ret < 0) - return ret; - - ret = as3645a_set_output(flash, false); - if (ret < 0) - return ret; - - /* read status */ - ret = as3645a_read_fault(flash); - if (ret < 0) - return ret; - - dev_dbg(&client->dev, "AS_INDICATOR_AND_TIMER_REG: %02x\n", - as3645a_read(flash, AS_INDICATOR_AND_TIMER_REG)); - dev_dbg(&client->dev, "AS_CURRENT_SET_REG: %02x\n", - as3645a_read(flash, AS_CURRENT_SET_REG)); - dev_dbg(&client->dev, "AS_CONTROL_REG: %02x\n", - as3645a_read(flash, AS_CONTROL_REG)); - - return ret & ~AS_FAULT_INFO_LED_AMOUNT ? -EIO : 0; -} - -static int __as3645a_set_power(struct as3645a *flash, int on) -{ - int ret; - - if (!on) - as3645a_set_control(flash, AS_MODE_EXT_TORCH, false); - - if (flash->pdata->set_power) { - ret = flash->pdata->set_power(&flash->subdev, on); - if (ret < 0) - return ret; - } - - if (!on) - return 0; - - ret = as3645a_setup(flash); - if (ret < 0) { - if (flash->pdata->set_power) - flash->pdata->set_power(&flash->subdev, 0); - } - - return ret; -} - -static int as3645a_set_power(struct v4l2_subdev *sd, int on) -{ - struct as3645a *flash = to_as3645a(sd); - int ret = 0; - - mutex_lock(&flash->power_lock); - - if (flash->power_count == !on) { - ret = __as3645a_set_power(flash, !!on); - if (ret < 0) - goto done; - } - - flash->power_count += on ? 1 : -1; - WARN_ON(flash->power_count < 0); - -done: - mutex_unlock(&flash->power_lock); - return ret; -} - -static int as3645a_registered(struct v4l2_subdev *sd) -{ - struct as3645a *flash = to_as3645a(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int rval, man, model, rfu, version; - const char *vendor; - - /* Power up the flash driver and read manufacturer ID, model ID, RFU - * and version. - */ - rval = as3645a_set_power(&flash->subdev, 1); - if (rval < 0) - return rval; - - rval = as3645a_read(flash, AS_DESIGN_INFO_REG); - if (rval < 0) - goto power_off; - - man = AS_DESIGN_INFO_FACTORY(rval); - model = AS_DESIGN_INFO_MODEL(rval); - - rval = as3645a_read(flash, AS_VERSION_CONTROL_REG); - if (rval < 0) - goto power_off; - - rfu = AS_VERSION_CONTROL_RFU(rval); - version = AS_VERSION_CONTROL_VERSION(rval); - - /* Verify the chip model and version. */ - if (model != 0x01 || rfu != 0x00) { - dev_err(&client->dev, - "AS3645A not detected (model %d rfu %d)\n", model, rfu); - rval = -ENODEV; - goto power_off; - } - - switch (man) { - case 1: - vendor = "AMS, Austria Micro Systems"; - break; - case 2: - vendor = "ADI, Analog Devices Inc."; - break; - case 3: - vendor = "NSC, National Semiconductor"; - break; - case 4: - vendor = "NXP"; - break; - case 5: - vendor = "TI, Texas Instrument"; - break; - default: - vendor = "Unknown"; - } - - dev_info(&client->dev, "Chip vendor: %s (%d) Version: %d\n", vendor, - man, version); - - rval = as3645a_write(flash, AS_PASSWORD_REG, AS_PASSWORD_UNLOCK_VALUE); - if (rval < 0) - goto power_off; - - rval = as3645a_write(flash, AS_BOOST_REG, AS_BOOST_CURRENT_DISABLE); - if (rval < 0) - goto power_off; - - /* Setup default values. This makes sure that the chip is in a known - * state, in case the power rail can't be controlled. - */ - rval = as3645a_setup(flash); - -power_off: - as3645a_set_power(&flash->subdev, 0); - - return rval; -} - -static int as3645a_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - return as3645a_set_power(sd, 1); -} - -static int as3645a_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - return as3645a_set_power(sd, 0); -} - -static const struct v4l2_subdev_core_ops as3645a_core_ops = { - .s_power = as3645a_set_power, -}; - -static const struct v4l2_subdev_ops as3645a_ops = { - .core = &as3645a_core_ops, -}; - -static const struct v4l2_subdev_internal_ops as3645a_internal_ops = { - .registered = as3645a_registered, - .open = as3645a_open, - .close = as3645a_close, -}; - -/* ----------------------------------------------------------------------------- - * I2C driver - */ -#ifdef CONFIG_PM - -static int as3645a_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); - struct as3645a *flash = to_as3645a(subdev); - int rval; - - if (flash->power_count == 0) - return 0; - - rval = __as3645a_set_power(flash, 0); - - dev_dbg(&client->dev, "Suspend %s\n", rval < 0 ? "failed" : "ok"); - - return rval; -} - -static int as3645a_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); - struct as3645a *flash = to_as3645a(subdev); - int rval; - - if (flash->power_count == 0) - return 0; - - rval = __as3645a_set_power(flash, 1); - - dev_dbg(&client->dev, "Resume %s\n", rval < 0 ? "fail" : "ok"); - - return rval; -} - -#else - -#define as3645a_suspend NULL -#define as3645a_resume NULL - -#endif /* CONFIG_PM */ - -/* - * as3645a_init_controls - Create controls - * @flash: The flash - * - * The number of LEDs reported in platform data is used to compute default - * limits. Parameters passed through platform data can override those limits. - */ -static int as3645a_init_controls(struct as3645a *flash) -{ - const struct as3645a_platform_data *pdata = flash->pdata; - struct v4l2_ctrl *ctrl; - int maximum; - - v4l2_ctrl_handler_init(&flash->ctrls, 10); - - /* V4L2_CID_FLASH_LED_MODE */ - v4l2_ctrl_new_std_menu(&flash->ctrls, &as3645a_ctrl_ops, - V4L2_CID_FLASH_LED_MODE, 2, ~7, - V4L2_FLASH_LED_MODE_NONE); - - /* V4L2_CID_FLASH_STROBE_SOURCE */ - v4l2_ctrl_new_std_menu(&flash->ctrls, &as3645a_ctrl_ops, - V4L2_CID_FLASH_STROBE_SOURCE, - pdata->ext_strobe ? 1 : 0, - pdata->ext_strobe ? ~3 : ~1, - V4L2_FLASH_STROBE_SOURCE_SOFTWARE); - - flash->strobe_source = V4L2_FLASH_STROBE_SOURCE_SOFTWARE; - - /* V4L2_CID_FLASH_STROBE */ - v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, - V4L2_CID_FLASH_STROBE, 0, 0, 0, 0); - - /* V4L2_CID_FLASH_STROBE_STOP */ - v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, - V4L2_CID_FLASH_STROBE_STOP, 0, 0, 0, 0); - - /* V4L2_CID_FLASH_STROBE_STATUS */ - ctrl = v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, - V4L2_CID_FLASH_STROBE_STATUS, 0, 1, 1, 1); - if (ctrl != NULL) - ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; - - /* V4L2_CID_FLASH_TIMEOUT */ - maximum = pdata->timeout_max; - - v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, - V4L2_CID_FLASH_TIMEOUT, AS3645A_FLASH_TIMEOUT_MIN, - maximum, AS3645A_FLASH_TIMEOUT_STEP, maximum); - - flash->timeout = maximum; - - /* V4L2_CID_FLASH_INTENSITY */ - maximum = pdata->flash_max_current; - - v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, - V4L2_CID_FLASH_INTENSITY, AS3645A_FLASH_INTENSITY_MIN, - maximum, AS3645A_FLASH_INTENSITY_STEP, maximum); - - flash->flash_current = (maximum - AS3645A_FLASH_INTENSITY_MIN) - / AS3645A_FLASH_INTENSITY_STEP; - - /* V4L2_CID_FLASH_TORCH_INTENSITY */ - maximum = pdata->torch_max_current; - - v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, - V4L2_CID_FLASH_TORCH_INTENSITY, - AS3645A_TORCH_INTENSITY_MIN, maximum, - AS3645A_TORCH_INTENSITY_STEP, - AS3645A_TORCH_INTENSITY_MIN); - - flash->assist_current = 0; - - /* V4L2_CID_FLASH_INDICATOR_INTENSITY */ - v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, - V4L2_CID_FLASH_INDICATOR_INTENSITY, - AS3645A_INDICATOR_INTENSITY_MIN, - AS3645A_INDICATOR_INTENSITY_MAX, - AS3645A_INDICATOR_INTENSITY_STEP, - AS3645A_INDICATOR_INTENSITY_MIN); - - flash->indicator_current = 0; - - /* V4L2_CID_FLASH_FAULT */ - ctrl = v4l2_ctrl_new_std(&flash->ctrls, &as3645a_ctrl_ops, - V4L2_CID_FLASH_FAULT, 0, - V4L2_FLASH_FAULT_OVER_VOLTAGE | - V4L2_FLASH_FAULT_TIMEOUT | - V4L2_FLASH_FAULT_OVER_TEMPERATURE | - V4L2_FLASH_FAULT_SHORT_CIRCUIT, 0, 0); - if (ctrl != NULL) - ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; - - flash->subdev.ctrl_handler = &flash->ctrls; - - return flash->ctrls.error; -} - -static int as3645a_probe(struct i2c_client *client, - const struct i2c_device_id *devid) -{ - struct as3645a *flash; - int ret; - - if (client->dev.platform_data == NULL) - return -ENODEV; - - flash = devm_kzalloc(&client->dev, sizeof(*flash), GFP_KERNEL); - if (flash == NULL) - return -ENOMEM; - - flash->pdata = client->dev.platform_data; - - v4l2_i2c_subdev_init(&flash->subdev, client, &as3645a_ops); - flash->subdev.internal_ops = &as3645a_internal_ops; - flash->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - - ret = as3645a_init_controls(flash); - if (ret < 0) - goto done; - - ret = media_entity_pads_init(&flash->subdev.entity, 0, NULL); - if (ret < 0) - goto done; - - flash->subdev.entity.function = MEDIA_ENT_F_FLASH; - - mutex_init(&flash->power_lock); - - flash->led_mode = V4L2_FLASH_LED_MODE_NONE; - -done: - if (ret < 0) - v4l2_ctrl_handler_free(&flash->ctrls); - - return ret; -} - -static int as3645a_remove(struct i2c_client *client) -{ - struct v4l2_subdev *subdev = i2c_get_clientdata(client); - struct as3645a *flash = to_as3645a(subdev); - - v4l2_device_unregister_subdev(subdev); - v4l2_ctrl_handler_free(&flash->ctrls); - media_entity_cleanup(&flash->subdev.entity); - mutex_destroy(&flash->power_lock); - - return 0; -} - -static const struct i2c_device_id as3645a_id_table[] = { - { AS3645A_NAME, 0 }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, as3645a_id_table); - -static const struct dev_pm_ops as3645a_pm_ops = { - .suspend = as3645a_suspend, - .resume = as3645a_resume, -}; - -static struct i2c_driver as3645a_i2c_driver = { - .driver = { - .name = AS3645A_NAME, - .pm = &as3645a_pm_ops, - }, - .probe = as3645a_probe, - .remove = as3645a_remove, - .id_table = as3645a_id_table, -}; - -module_i2c_driver(as3645a_i2c_driver); - -MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); -MODULE_DESCRIPTION("LED flash driver for AS3645A, LM3555 and their clones"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/cx25840/Makefile b/drivers/media/i2c/cx25840/Makefile index 898eb13340ae..ac545812fc6a 100644 --- a/drivers/media/i2c/cx25840/Makefile +++ b/drivers/media/i2c/cx25840/Makefile @@ -2,5 +2,3 @@ cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \ cx25840-vbi.o cx25840-ir.o obj-$(CONFIG_VIDEO_CX25840) += cx25840.o - -ccflags-y += -Idrivers/media/i2c diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index f38bf819d805..98be63ae8590 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -201,14 +201,14 @@ static int cx23885_s_io_pin_config(struct v4l2_subdev *sd, size_t n, } else { /* IRQ_N */ if (p[i].flags & - (V4L2_SUBDEV_IO_PIN_DISABLE | - V4L2_SUBDEV_IO_PIN_INPUT)) { + (BIT(V4L2_SUBDEV_IO_PIN_DISABLE) | + BIT(V4L2_SUBDEV_IO_PIN_INPUT))) { pin_ctrl &= ~(0x1 << 25); } else { pin_ctrl |= (0x1 << 25); } if (p[i].flags & - V4L2_SUBDEV_IO_PIN_ACTIVE_LOW) { + BIT(V4L2_SUBDEV_IO_PIN_ACTIVE_LOW)) { pin_ctrl &= ~(0x1 << 24); } else { pin_ctrl |= (0x1 << 24); @@ -224,7 +224,7 @@ static int cx23885_s_io_pin_config(struct v4l2_subdev *sd, size_t n, } else { /* GPIO19 */ gpio_oe &= ~(0x1 << 0); - if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) { + if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_SET_VALUE)) { gpio_data &= ~(0x1 << 0); gpio_data |= ((p[i].value & 0x1) << 0); } @@ -236,7 +236,7 @@ static int cx23885_s_io_pin_config(struct v4l2_subdev *sd, size_t n, if (p[i].function != CX23885_PAD_GPIO20) { /* IR_TX */ gpio_oe |= (0x1 << 1); - if (p[i].flags & V4L2_SUBDEV_IO_PIN_DISABLE) + if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_DISABLE)) pin_ctrl &= ~(0x1 << 10); else pin_ctrl |= (0x1 << 10); @@ -245,7 +245,7 @@ static int cx23885_s_io_pin_config(struct v4l2_subdev *sd, size_t n, } else { /* GPIO20 */ gpio_oe &= ~(0x1 << 1); - if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) { + if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_SET_VALUE)) { gpio_data &= ~(0x1 << 1); gpio_data |= ((p[i].value & 0x1) << 1); } @@ -263,7 +263,7 @@ static int cx23885_s_io_pin_config(struct v4l2_subdev *sd, size_t n, } else { /* GPIO21 */ gpio_oe &= ~(0x1 << 2); - if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) { + if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_SET_VALUE)) { gpio_data &= ~(0x1 << 2); gpio_data |= ((p[i].value & 0x1) << 2); } @@ -281,7 +281,7 @@ static int cx23885_s_io_pin_config(struct v4l2_subdev *sd, size_t n, } else { /* GPIO22 */ gpio_oe &= ~(0x1 << 3); - if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) { + if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_SET_VALUE)) { gpio_data &= ~(0x1 << 3); gpio_data |= ((p[i].value & 0x1) << 3); } @@ -299,7 +299,7 @@ static int cx23885_s_io_pin_config(struct v4l2_subdev *sd, size_t n, } else { /* GPIO23 */ gpio_oe &= ~(0x1 << 4); - if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) { + if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_SET_VALUE)) { gpio_data &= ~(0x1 << 4); gpio_data |= ((p[i].value & 0x1) << 4); } @@ -1263,7 +1263,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp static int set_v4lstd(struct i2c_client *client) { struct cx25840_state *state = to_state(i2c_get_clientdata(client)); - u8 fmt = 0; /* zero is autodetect */ + u8 fmt = 0; /* zero is autodetect */ u8 pal_m = 0; /* First tests should be against specific std */ @@ -1395,8 +1395,9 @@ static int cx25840_set_fmt(struct v4l2_subdev *sd, * height. Without that margin the cx23885 fails in this * check. */ - if ((fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) || - (Vlines * 8 < Vsrc) || (Vsrc + 1 < Vlines)) { + if ((fmt->width == 0) || (Vlines == 0) || + (fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) || + (Vlines * 8 < Vsrc) || (Vsrc + 1 < Vlines)) { v4l_err(client, "%dx%d is not a valid size!\n", fmt->width, fmt->height); return -ERANGE; @@ -1759,9 +1760,9 @@ static int cx25840_g_std(struct v4l2_subdev *sd, v4l2_std_id *std) /* 1001 */ V4L2_STD_UNKNOWN, /* 1010 */ V4L2_STD_UNKNOWN, - /* 1001 */ V4L2_STD_UNKNOWN, - /* 1010 */ V4L2_STD_UNKNOWN, /* 1011 */ V4L2_STD_UNKNOWN, + /* 1100 */ V4L2_STD_SECAM, + /* 1101 */ V4L2_STD_UNKNOWN, /* 1110 */ V4L2_STD_UNKNOWN, /* 1111 */ V4L2_STD_UNKNOWN }; @@ -2064,10 +2065,10 @@ static void cx23885_dif_setup(struct i2c_client *client, u32 ifHz) /* Assuming TV */ /* Calculate the PLL frequency word based on the adjusted ifHz */ - pll_freq = div_u64((u64)ifHz * 268435456, 50000000); - pll_freq_word = (u32)pll_freq; + pll_freq = div_u64((u64)ifHz * 268435456, 50000000); + pll_freq_word = (u32)pll_freq; - cx25840_write4(client, DIF_PLL_FREQ_WORD, pll_freq_word); + cx25840_write4(client, DIF_PLL_FREQ_WORD, pll_freq_word); /* Round down to the nearest 100KHz */ ifHz = (ifHz / 100000) * 100000; diff --git a/drivers/media/i2c/cx25840/cx25840-core.h b/drivers/media/i2c/cx25840/cx25840-core.h index 55432ed42714..fb13a624d2e3 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.h +++ b/drivers/media/i2c/cx25840/cx25840-core.h @@ -118,7 +118,7 @@ static inline bool is_cx23888(struct cx25840_state *state) } /* ----------------------------------------------------------------------- */ -/* cx25850-core.c */ +/* cx25850-core.c */ int cx25840_write(struct i2c_client *client, u16 addr, u8 value); int cx25840_write4(struct i2c_client *client, u16 addr, u32 value); u8 cx25840_read(struct i2c_client *client, u16 addr); diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c index 9b65c7d2fa84..ad7f66c7aac8 100644 --- a/drivers/media/i2c/cx25840/cx25840-ir.c +++ b/drivers/media/i2c/cx25840/cx25840-ir.c @@ -28,7 +28,7 @@ static unsigned int ir_debug; module_param(ir_debug, int, 0644); MODULE_PARM_DESC(ir_debug, "enable integrated IR debug messages"); -#define CX25840_IR_REG_BASE 0x200 +#define CX25840_IR_REG_BASE 0x200 #define CX25840_IR_CNTRL_REG 0x200 #define CNTRL_WIN_3_3 0x00000000 @@ -131,7 +131,7 @@ static inline struct cx25840_ir_state *to_ir_state(struct v4l2_subdev *sd) * Rx and Tx Clock Divider register computations * * Note the largest clock divider value of 0xffff corresponds to: - * (0xffff + 1) * 1000 / 108/2 MHz = 1,213,629.629... ns + * (0xffff + 1) * 1000 / 108/2 MHz = 1,213,629.629... ns * which fits in 21 bits, so we'll use unsigned int for time arguments. */ static inline u16 count_to_clock_divider(unsigned int d) @@ -187,7 +187,7 @@ static inline unsigned int clock_divider_to_freq(unsigned int divider, * Low Pass Filter register calculations * * Note the largest count value of 0xffff corresponds to: - * 0xffff * 1000 / 108/2 MHz = 1,213,611.11... ns + * 0xffff * 1000 / 108/2 MHz = 1,213,611.11... ns * which fits in 21 bits, so we'll use unsigned int for time arguments. */ static inline u16 count_to_lpf_count(unsigned int d) diff --git a/drivers/media/i2c/dw9714.c b/drivers/media/i2c/dw9714.c index ed01e8bd4331..8dbbf0f917df 100644 --- a/drivers/media/i2c/dw9714.c +++ b/drivers/media/i2c/dw9714.c @@ -42,7 +42,6 @@ /* dw9714 device structure */ struct dw9714_device { - struct i2c_client *client; struct v4l2_ctrl_handler ctrls_vcm; struct v4l2_subdev sd; u16 current_val; @@ -61,7 +60,7 @@ static inline struct dw9714_device *sd_to_dw9714_vcm(struct v4l2_subdev *subdev) static int dw9714_i2c_write(struct i2c_client *client, u16 data) { int ret; - u16 val = cpu_to_be16(data); + __be16 val = cpu_to_be16(data); ret = i2c_master_send(client, (const char *)&val, sizeof(val)); if (ret != sizeof(val)) { @@ -73,7 +72,7 @@ static int dw9714_i2c_write(struct i2c_client *client, u16 data) static int dw9714_t_focus_vcm(struct dw9714_device *dw9714_dev, u16 val) { - struct i2c_client *client = dw9714_dev->client; + struct i2c_client *client = v4l2_get_subdevdata(&dw9714_dev->sd); dw9714_dev->current_val = val; @@ -96,13 +95,11 @@ static const struct v4l2_ctrl_ops dw9714_vcm_ctrl_ops = { static int dw9714_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - struct dw9714_device *dw9714_dev = sd_to_dw9714_vcm(sd); - struct device *dev = &dw9714_dev->client->dev; int rval; - rval = pm_runtime_get_sync(dev); + rval = pm_runtime_get_sync(sd->dev); if (rval < 0) { - pm_runtime_put_noidle(dev); + pm_runtime_put_noidle(sd->dev); return rval; } @@ -111,10 +108,7 @@ static int dw9714_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) static int dw9714_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - struct dw9714_device *dw9714_dev = sd_to_dw9714_vcm(sd); - struct device *dev = &dw9714_dev->client->dev; - - pm_runtime_put(dev); + pm_runtime_put(sd->dev); return 0; } @@ -137,7 +131,6 @@ static int dw9714_init_controls(struct dw9714_device *dev_vcm) { struct v4l2_ctrl_handler *hdl = &dev_vcm->ctrls_vcm; const struct v4l2_ctrl_ops *ops = &dw9714_vcm_ctrl_ops; - struct i2c_client *client = dev_vcm->client; v4l2_ctrl_handler_init(hdl, 1); @@ -145,7 +138,7 @@ static int dw9714_init_controls(struct dw9714_device *dev_vcm) 0, DW9714_MAX_FOCUS_POS, DW9714_FOCUS_STEPS, 0); if (hdl->error) - dev_err(&client->dev, "%s fail error: 0x%x\n", + dev_err(dev_vcm->sd.dev, "%s fail error: 0x%x\n", __func__, hdl->error); dev_vcm->sd.ctrl_handler = hdl; return hdl->error; @@ -161,8 +154,6 @@ static int dw9714_probe(struct i2c_client *client) if (dw9714_dev == NULL) return -ENOMEM; - dw9714_dev->client = client; - v4l2_i2c_subdev_init(&dw9714_dev->sd, client, &dw9714_ops); dw9714_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; dw9714_dev->sd.internal_ops = &dw9714_int_ops; @@ -183,6 +174,7 @@ static int dw9714_probe(struct i2c_client *client) pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); + pm_runtime_idle(&client->dev); return 0; diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c index 2f71af2f90bf..664e8acdf2a0 100644 --- a/drivers/media/i2c/imx274.c +++ b/drivers/media/i2c/imx274.c @@ -634,7 +634,7 @@ static int imx274_regmap_util_write_table_8(struct regmap *regmap, const struct reg_8 table[], u16 wait_ms_addr, u16 end_addr) { - int err; + int err = 0; const struct reg_8 *next; u8 val; @@ -655,6 +655,8 @@ static int imx274_regmap_util_write_table_8(struct regmap *regmap, err = regmap_bulk_write(regmap, range_start, &range_vals[0], range_count); + else + err = 0; if (err) return err; diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 8b5f7d0435e4..193020d64e51 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -18,6 +18,20 @@ * Brian Rogers <brian_rogers@comcast.net> * modified for AVerMedia Cardbus by * Oldrich Jedlicka <oldium.pro@seznam.cz> + * Zilog Transmitter portions/ideas were derived from GPLv2+ sources: + * - drivers/char/pctv_zilogir.[ch] from Hauppauge Broadway product + * Copyright 2011 Hauppauge Computer works + * - drivers/staging/media/lirc/lirc_zilog.c + * Copyright (c) 2000 Gerd Knorr <kraxel@goldbach.in-berlin.de> + * Michal Kochanowicz <mkochano@pld.org.pl> + * Christoph Bartelmus <lirc@bartelmus.de> + * Ulrich Mueller <ulrich.mueller42@web.de> + * Stefan Jahn <stefan@lkcc.org> + * Jerome Brock <jbrock@users.sourceforge.net> + * Thomas Reitmayr (treitmayr@yahoo.com) + * Mark Weaver <mark@npsl.co.uk> + * Jarod Wilson <jarod@redhat.com> + * Copyright (C) 2011 Andy Walls <awalls@md.metrocast.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -46,18 +60,11 @@ #include <media/rc-core.h> #include <media/i2c/ir-kbd-i2c.h> -/* ----------------------------------------------------------------------- */ -/* insmod parameters */ - -static int debug; -module_param(debug, int, 0644); /* debug level (0,1,2) */ - +#define FLAG_TX 1 +#define FLAG_HDPVR 2 -#define MODULE_NAME "ir-kbd-i2c" -#define dprintk(level, fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG MODULE_NAME ": " fmt , ## arg) - -/* ----------------------------------------------------------------------- */ +static bool enable_hdpvr; +module_param(enable_hdpvr, bool, 0644); static int get_key_haup_common(struct IR_i2c *ir, enum rc_proto *protocol, u32 *scancode, u8 *ptoggle, int size) @@ -96,7 +103,8 @@ static int get_key_haup_common(struct IR_i2c *ir, enum rc_proto *protocol, if (!range) code += 64; - dprintk(1, "ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n", + dev_dbg(&ir->rc->dev, + "ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n", start, range, toggle, dev, code); *protocol = RC_PROTO_RC5; @@ -113,13 +121,15 @@ static int get_key_haup_common(struct IR_i2c *ir, enum rc_proto *protocol, *ptoggle = (dev & 0x80) != 0; *protocol = RC_PROTO_RC6_MCE; dev &= 0x7f; - dprintk(1, "ir hauppauge (rc6-mce): t%d vendor=%d dev=%d code=%d\n", - *ptoggle, vendor, dev, code); + dev_dbg(&ir->rc->dev, + "ir hauppauge (rc6-mce): t%d vendor=%d dev=%d code=%d\n", + *ptoggle, vendor, dev, code); } else { *ptoggle = 0; *protocol = RC_PROTO_RC6_6A_32; - dprintk(1, "ir hauppauge (rc6-6a-32): vendor=%d dev=%d code=%d\n", - vendor, dev, code); + dev_dbg(&ir->rc->dev, + "ir hauppauge (rc6-6a-32): vendor=%d dev=%d code=%d\n", + vendor, dev, code); } *scancode = RC_SCANCODE_RC6_6A(vendor, dev, code); @@ -162,7 +172,7 @@ static int get_key_pixelview(struct IR_i2c *ir, enum rc_proto *protocol, /* poll IR chip */ if (1 != i2c_master_recv(ir->c, &b, 1)) { - dprintk(1,"read error\n"); + dev_dbg(&ir->rc->dev, "read error\n"); return -EIO; } @@ -179,13 +189,12 @@ static int get_key_fusionhdtv(struct IR_i2c *ir, enum rc_proto *protocol, /* poll IR chip */ if (4 != i2c_master_recv(ir->c, buf, 4)) { - dprintk(1,"read error\n"); + dev_dbg(&ir->rc->dev, "read error\n"); return -EIO; } - if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0) - dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __func__, - buf[0], buf[1], buf[2], buf[3]); + if (buf[0] != 0 || buf[1] != 0 || buf[2] != 0 || buf[3] != 0) + dev_dbg(&ir->rc->dev, "%s: %*ph\n", __func__, 4, buf); /* no key pressed or signal from other ir remote */ if(buf[0] != 0x1 || buf[1] != 0xfe) @@ -204,7 +213,7 @@ static int get_key_knc1(struct IR_i2c *ir, enum rc_proto *protocol, /* poll IR chip */ if (1 != i2c_master_recv(ir->c, &b, 1)) { - dprintk(1,"read error\n"); + dev_dbg(&ir->rc->dev, "read error\n"); return -EIO; } @@ -212,7 +221,7 @@ static int get_key_knc1(struct IR_i2c *ir, enum rc_proto *protocol, down, while 0xff indicates that no button is hold down. 0xfe sequences are sometimes interrupted by 0xFF */ - dprintk(2,"key %02x\n", b); + dev_dbg(&ir->rc->dev, "key %02x\n", b); if (b == 0xff) return 0; @@ -237,7 +246,7 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir, enum rc_proto *protocol, .buf = &key, .len = 1} }; subaddr = 0x0d; if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { - dprintk(1, "read error\n"); + dev_dbg(&ir->rc->dev, "read error\n"); return -EIO; } @@ -247,18 +256,17 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir, enum rc_proto *protocol, subaddr = 0x0b; msg[1].buf = &keygroup; if (2 != i2c_transfer(ir->c->adapter, msg, 2)) { - dprintk(1, "read error\n"); + dev_dbg(&ir->rc->dev, "read error\n"); return -EIO; } if (keygroup == 0xff) return 0; - dprintk(1, "read key 0x%02x/0x%02x\n", key, keygroup); + dev_dbg(&ir->rc->dev, "read key 0x%02x/0x%02x\n", key, keygroup); if (keygroup < 2 || keygroup > 4) { - /* Only a warning */ - dprintk(1, "warning: invalid key group 0x%02x for key 0x%02x\n", - keygroup, key); + dev_warn(&ir->rc->dev, "warning: invalid key group 0x%02x for key 0x%02x\n", + keygroup, key); } key |= (keygroup & 1) << 6; @@ -279,15 +287,15 @@ static int ir_key_poll(struct IR_i2c *ir) u8 toggle; int rc; - dprintk(3, "%s\n", __func__); + dev_dbg(&ir->rc->dev, "%s\n", __func__); rc = ir->get_key(ir, &protocol, &scancode, &toggle); if (rc < 0) { - dprintk(2,"error\n"); + dev_warn(&ir->rc->dev, "error %d\n", rc); return rc; } if (rc) { - dprintk(1, "%s: proto = 0x%04x, scancode = 0x%08x\n", + dev_dbg(&ir->rc->dev, "%s: proto = 0x%04x, scancode = 0x%08x\n", __func__, protocol, scancode); rc_keydown(ir->rc, protocol, scancode, toggle); } @@ -299,17 +307,416 @@ static void ir_work(struct work_struct *work) int rc; struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work); - rc = ir_key_poll(ir); - if (rc == -ENODEV) { - rc_unregister_device(ir->rc); - ir->rc = NULL; - return; + /* + * If the transmit code is holding the lock, skip polling for + * IR, we'll get it to it next time round + */ + if (mutex_trylock(&ir->lock)) { + rc = ir_key_poll(ir); + mutex_unlock(&ir->lock); + if (rc == -ENODEV) { + rc_unregister_device(ir->rc); + ir->rc = NULL; + return; + } } schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling_interval)); } -/* ----------------------------------------------------------------------- */ +static int ir_open(struct rc_dev *dev) +{ + struct IR_i2c *ir = dev->priv; + + schedule_delayed_work(&ir->work, 0); + + return 0; +} + +static void ir_close(struct rc_dev *dev) +{ + struct IR_i2c *ir = dev->priv; + + cancel_delayed_work_sync(&ir->work); +} + +/* Zilog Transmit Interface */ +#define XTAL_FREQ 18432000 + +#define ZILOG_SEND 0x80 +#define ZILOG_UIR_END 0x40 +#define ZILOG_INIT_END 0x20 +#define ZILOG_LIR_END 0x10 + +#define ZILOG_STATUS_OK 0x80 +#define ZILOG_STATUS_TX 0x40 +#define ZILOG_STATUS_SET 0x20 + +/* + * As you can see here, very few different lengths of pulse and space + * can be encoded. This means that the hardware does not work well with + * recorded IR. It's best to work with generated IR, like from ir-ctl or + * the in-kernel encoders. + */ +struct code_block { + u8 length; + u16 pulse[7]; /* not aligned */ + u8 carrier_pulse; + u8 carrier_space; + u16 space[8]; /* not aligned */ + u8 codes[61]; + u8 csum[2]; +} __packed; + +static int send_data_block(struct IR_i2c *ir, int cmd, + struct code_block *code_block) +{ + int i, j, ret; + u8 buf[5], *p; + + p = &code_block->length; + for (i = 0; p < code_block->csum; i++) + code_block->csum[i & 1] ^= *p++; + + p = &code_block->length; + + for (i = 0; i < sizeof(*code_block);) { + int tosend = sizeof(*code_block) - i; + + if (tosend > 4) + tosend = 4; + buf[0] = i + 1; + for (j = 0; j < tosend; ++j) + buf[1 + j] = p[i + j]; + dev_dbg(&ir->rc->dev, "%*ph", tosend + 1, buf); + ret = i2c_master_send(ir->tx_c, buf, tosend + 1); + if (ret != tosend + 1) { + dev_dbg(&ir->rc->dev, + "i2c_master_send failed with %d\n", ret); + return ret < 0 ? ret : -EIO; + } + i += tosend; + } + + buf[0] = 0; + buf[1] = cmd; + ret = i2c_master_send(ir->tx_c, buf, 2); + if (ret != 2) { + dev_err(&ir->rc->dev, "i2c_master_send failed with %d\n", ret); + return ret < 0 ? ret : -EIO; + } + + usleep_range(2000, 5000); + + ret = i2c_master_send(ir->tx_c, buf, 1); + if (ret != 1) { + dev_err(&ir->rc->dev, "i2c_master_send failed with %d\n", ret); + return ret < 0 ? ret : -EIO; + } + + return 0; +} + +static int zilog_init(struct IR_i2c *ir) +{ + struct code_block code_block = { .length = sizeof(code_block) }; + u8 buf[4]; + int ret; + + put_unaligned_be16(0x1000, &code_block.pulse[3]); + + ret = send_data_block(ir, ZILOG_INIT_END, &code_block); + if (ret) + return ret; + + ret = i2c_master_recv(ir->tx_c, buf, 4); + if (ret != 4) { + dev_err(&ir->c->dev, "failed to retrieve firmware version: %d\n", + ret); + return ret < 0 ? ret : -EIO; + } + + dev_info(&ir->c->dev, "Zilog/Hauppauge IR blaster firmware version %d.%d.%d\n", + buf[1], buf[2], buf[3]); + + return 0; +} + +/* + * If the last slot for pulse is the same as the current slot for pulse, + * then use slot no 7. + */ +static void copy_codes(u8 *dst, u8 *src, unsigned int count) +{ + u8 c, last = 0xff; + + while (count--) { + c = *src++; + if ((c & 0xf0) == last) { + *dst++ = 0x70 | (c & 0xf); + } else { + *dst++ = c; + last = c & 0xf0; + } + } +} + +/* + * When looking for repeats, we don't care about the trailing space. This + * is set to the shortest possible anyway. + */ +static int cmp_no_trail(u8 *a, u8 *b, unsigned int count) +{ + while (--count) { + if (*a++ != *b++) + return 1; + } + + return (*a & 0xf0) - (*b & 0xf0); +} + +static int find_slot(u16 *array, unsigned int size, u16 val) +{ + int i; + + for (i = 0; i < size; i++) { + if (get_unaligned_be16(&array[i]) == val) { + return i; + } else if (!array[i]) { + put_unaligned_be16(val, &array[i]); + return i; + } + } + + return -1; +} + +static int zilog_ir_format(struct rc_dev *rcdev, unsigned int *txbuf, + unsigned int count, struct code_block *code_block) +{ + struct IR_i2c *ir = rcdev->priv; + int rep, i, l, p = 0, s, c = 0; + bool repeating; + u8 codes[174]; + + code_block->carrier_pulse = DIV_ROUND_CLOSEST( + ir->duty_cycle * XTAL_FREQ / 1000, ir->carrier); + code_block->carrier_space = DIV_ROUND_CLOSEST( + (100 - ir->duty_cycle) * XTAL_FREQ / 1000, ir->carrier); + + for (i = 0; i < count; i++) { + if (c >= ARRAY_SIZE(codes) - 1) { + dev_warn(&rcdev->dev, "IR too long, cannot transmit\n"); + return -EINVAL; + } + + /* + * Lengths more than 142220us cannot be encoded; also + * this checks for multiply overflow + */ + if (txbuf[i] > 142220) + return -EINVAL; + + l = DIV_ROUND_CLOSEST((XTAL_FREQ / 1000) * txbuf[i], 40000); + + if (i & 1) { + s = find_slot(code_block->space, + ARRAY_SIZE(code_block->space), l); + if (s == -1) { + dev_warn(&rcdev->dev, "Too many different lengths spaces, cannot transmit"); + return -EINVAL; + } + + /* We have a pulse and space */ + codes[c++] = (p << 4) | s; + } else { + p = find_slot(code_block->pulse, + ARRAY_SIZE(code_block->pulse), l); + if (p == -1) { + dev_warn(&rcdev->dev, "Too many different lengths pulses, cannot transmit"); + return -EINVAL; + } + } + } + + /* We have to encode the trailing pulse. Find the shortest space */ + s = 0; + for (i = 1; i < ARRAY_SIZE(code_block->space); i++) { + u16 d = get_unaligned_be16(&code_block->space[i]); + + if (get_unaligned_be16(&code_block->space[s]) > d) + s = i; + } + + codes[c++] = (p << 4) | s; + + dev_dbg(&rcdev->dev, "generated %d codes\n", c); + + /* + * Are the last N codes (so pulse + space) repeating 3 times? + * if so we can shorten the codes list and use code 0xc0 to repeat + * them. + */ + repeating = false; + + for (rep = c / 3; rep >= 1; rep--) { + if (!memcmp(&codes[c - rep * 3], &codes[c - rep * 2], rep) && + !cmp_no_trail(&codes[c - rep], &codes[c - rep * 2], rep)) { + repeating = true; + break; + } + } + + if (repeating) { + /* first copy any leading non-repeating */ + int leading = c - rep * 3; + + if (leading + rep >= ARRAY_SIZE(code_block->codes) - 3) { + dev_warn(&rcdev->dev, "IR too long, cannot transmit\n"); + return -EINVAL; + } + + dev_dbg(&rcdev->dev, "found trailing %d repeat\n", rep); + copy_codes(code_block->codes, codes, leading); + code_block->codes[leading] = 0x82; + copy_codes(code_block->codes + leading + 1, codes + leading, + rep); + c = leading + 1 + rep; + code_block->codes[c++] = 0xc0; + } else { + if (c >= ARRAY_SIZE(code_block->codes) - 3) { + dev_warn(&rcdev->dev, "IR too long, cannot transmit\n"); + return -EINVAL; + } + + dev_dbg(&rcdev->dev, "found no trailing repeat\n"); + code_block->codes[0] = 0x82; + copy_codes(code_block->codes + 1, codes, c); + c++; + code_block->codes[c++] = 0xc4; + } + + while (c < ARRAY_SIZE(code_block->codes)) + code_block->codes[c++] = 0x83; + + return 0; +} + +static int zilog_tx(struct rc_dev *rcdev, unsigned int *txbuf, + unsigned int count) +{ + struct IR_i2c *ir = rcdev->priv; + struct code_block code_block = { .length = sizeof(code_block) }; + u8 buf[2]; + int ret, i; + + ret = zilog_ir_format(rcdev, txbuf, count, &code_block); + if (ret) + return ret; + + ret = mutex_lock_interruptible(&ir->lock); + if (ret) + return ret; + + ret = send_data_block(ir, ZILOG_UIR_END, &code_block); + if (ret) + goto out_unlock; + + ret = i2c_master_recv(ir->tx_c, buf, 1); + if (ret != 1) { + dev_err(&ir->rc->dev, "i2c_master_recv failed with %d\n", ret); + goto out_unlock; + } + + dev_dbg(&ir->rc->dev, "code set status: %02x\n", buf[0]); + + if (buf[0] != (ZILOG_STATUS_OK | ZILOG_STATUS_SET)) { + dev_err(&ir->rc->dev, "unexpected IR TX response %02x\n", + buf[0]); + ret = -EIO; + goto out_unlock; + } + + buf[0] = 0x00; + buf[1] = ZILOG_SEND; + + ret = i2c_master_send(ir->tx_c, buf, 2); + if (ret != 2) { + dev_err(&ir->rc->dev, "i2c_master_send failed with %d\n", ret); + if (ret >= 0) + ret = -EIO; + goto out_unlock; + } + + dev_dbg(&ir->rc->dev, "send command sent\n"); + + /* + * This bit NAKs until the device is ready, so we retry it + * sleeping a bit each time. This seems to be what the windows + * driver does, approximately. + * Try for up to 1s. + */ + for (i = 0; i < 20; ++i) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(50)); + ret = i2c_master_send(ir->tx_c, buf, 1); + if (ret == 1) + break; + dev_dbg(&ir->rc->dev, + "NAK expected: i2c_master_send failed with %d (try %d)\n", + ret, i + 1); + } + + if (ret != 1) { + dev_err(&ir->rc->dev, + "IR TX chip never got ready: last i2c_master_send failed with %d\n", + ret); + if (ret >= 0) + ret = -EIO; + goto out_unlock; + } + + i = i2c_master_recv(ir->tx_c, buf, 1); + if (i != 1) { + dev_err(&ir->rc->dev, "i2c_master_recv failed with %d\n", ret); + ret = -EIO; + goto out_unlock; + } else if (buf[0] != ZILOG_STATUS_OK) { + dev_err(&ir->rc->dev, "unexpected IR TX response #2: %02x\n", + buf[0]); + ret = -EIO; + goto out_unlock; + } + dev_dbg(&ir->rc->dev, "transmit complete\n"); + + /* Oh good, it worked */ + ret = count; +out_unlock: + mutex_unlock(&ir->lock); + + return ret; +} + +static int zilog_tx_carrier(struct rc_dev *dev, u32 carrier) +{ + struct IR_i2c *ir = dev->priv; + + if (carrier > 500000 || carrier < 20000) + return -EINVAL; + + ir->carrier = carrier; + + return 0; +} + +static int zilog_tx_duty_cycle(struct rc_dev *dev, u32 duty_cycle) +{ + struct IR_i2c *ir = dev->priv; + + ir->duty_cycle = duty_cycle; + + return 0; +} static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -322,6 +729,11 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) unsigned short addr = client->addr; int err; + if ((id->driver_data & FLAG_HDPVR) && !enable_hdpvr) { + dev_err(&client->dev, "IR for HDPVR is known to cause problems during recording, use enable_hdpvr modparam to enable\n"); + return -ENODEV; + } + ir = devm_kzalloc(&client->dev, sizeof(*ir), GFP_KERNEL); if (!ir) return -ENOMEM; @@ -433,18 +845,15 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) /* Make sure we are all setup before going on */ if (!name || !ir->get_key || !rc_proto || !ir_codes) { - dprintk(1, ": Unsupported device at address 0x%02x\n", - addr); + dev_warn(&client->dev, "Unsupported device at address 0x%02x\n", + addr); err = -ENODEV; goto err_out_free; } - /* Sets name */ - snprintf(ir->name, sizeof(ir->name), "i2c IR (%s)", name); ir->ir_codes = ir_codes; - snprintf(ir->phys, sizeof(ir->phys), "%s/%s/ir0", - dev_name(&adap->dev), + snprintf(ir->phys, sizeof(ir->phys), "%s/%s", dev_name(&adap->dev), dev_name(&client->dev)); /* @@ -453,7 +862,11 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) */ rc->input_id.bustype = BUS_I2C; rc->input_phys = ir->phys; - rc->device_name = ir->name; + rc->device_name = name; + rc->dev.parent = &client->dev; + rc->priv = ir; + rc->open = ir_open; + rc->close = ir_close; /* * Initialize the other fields of rc_dev @@ -461,22 +874,35 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) rc->map_name = ir->ir_codes; rc->allowed_protocols = rc_proto; if (!rc->driver_name) - rc->driver_name = MODULE_NAME; + rc->driver_name = KBUILD_MODNAME; + + mutex_init(&ir->lock); + + INIT_DELAYED_WORK(&ir->work, ir_work); + + if (id->driver_data & FLAG_TX) { + ir->tx_c = i2c_new_dummy(client->adapter, 0x70); + if (!ir->tx_c) { + dev_err(&client->dev, "failed to setup tx i2c address"); + } else if (!zilog_init(ir)) { + ir->carrier = 38000; + ir->duty_cycle = 40; + rc->tx_ir = zilog_tx; + rc->s_tx_carrier = zilog_tx_carrier; + rc->s_tx_duty_cycle = zilog_tx_duty_cycle; + } + } err = rc_register_device(rc); if (err) goto err_out_free; - printk(MODULE_NAME ": %s detected at %s [%s]\n", - ir->name, ir->phys, adap->name); - - /* start polling via eventd */ - INIT_DELAYED_WORK(&ir->work, ir_work); - schedule_delayed_work(&ir->work, 0); - return 0; err_out_free: + if (ir->tx_c) + i2c_unregister_device(ir->tx_c); + /* Only frees rc if it were allocated internally */ rc_free_device(rc); return err; @@ -489,6 +915,9 @@ static int ir_remove(struct i2c_client *client) /* kill outstanding polls */ cancel_delayed_work_sync(&ir->work); + if (ir->tx_c) + i2c_unregister_device(ir->tx_c); + /* unregister device */ rc_unregister_device(ir->rc); @@ -500,10 +929,11 @@ static const struct i2c_device_id ir_kbd_id[] = { /* Generic entry for any IR receiver */ { "ir_video", 0 }, /* IR device specific entries should be added here */ - { "ir_rx_z8f0811_haup", 0 }, - { "ir_rx_z8f0811_hdpvr", 0 }, + { "ir_z8f0811_haup", FLAG_TX }, + { "ir_z8f0811_hdpvr", FLAG_TX | FLAG_HDPVR }, { } }; +MODULE_DEVICE_TABLE(i2c, ir_kbd_id); static struct i2c_driver ir_kbd_driver = { .driver = { diff --git a/drivers/media/i2c/ks0127.c b/drivers/media/i2c/ks0127.c index ab536c4a7115..5905ed6f8397 100644 --- a/drivers/media/i2c/ks0127.c +++ b/drivers/media/i2c/ks0127.c @@ -195,7 +195,7 @@ struct adjust { struct ks0127 { struct v4l2_subdev sd; v4l2_std_id norm; - u8 regs[256]; + u8 regs[256]; }; static inline struct ks0127 *to_ks0127(struct v4l2_subdev *sd) diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index b1665d97e0fd..efda1aa95ca0 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -92,6 +92,7 @@ */ #define MT9M111_OPER_MODE_CTRL 0x106 #define MT9M111_OUTPUT_FORMAT_CTRL 0x108 +#define MT9M111_TPG_CTRL 0x148 #define MT9M111_REDUCER_XZOOM_B 0x1a0 #define MT9M111_REDUCER_XSIZE_B 0x1a1 #define MT9M111_REDUCER_YZOOM_B 0x1a3 @@ -124,6 +125,7 @@ #define MT9M111_OUTFMT_AVG_CHROMA (1 << 2) #define MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN (1 << 1) #define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B (1 << 0) +#define MT9M111_TPG_SEL_MASK GENMASK(2, 0) /* * Camera control register addresses (0x200..0x2ff not implemented) @@ -215,6 +217,9 @@ struct mt9m111 { int power_count; const struct mt9m111_datafmt *fmt; int lastpage; /* PageMap cache value */ +#ifdef CONFIG_MEDIA_CONTROLLER + struct media_pad pad; +#endif }; /* Find a data format by a pixel code */ @@ -703,6 +708,25 @@ static int mt9m111_set_autowhitebalance(struct mt9m111 *mt9m111, int on) return reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOWHITEBAL_EN); } +static const char * const mt9m111_test_pattern_menu[] = { + "Disabled", + "Vertical monochrome gradient", + "Flat color type 1", + "Flat color type 2", + "Flat color type 3", + "Flat color type 4", + "Flat color type 5", + "Color bar", +}; + +static int mt9m111_set_test_pattern(struct mt9m111 *mt9m111, int val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev); + + return mt9m111_reg_mask(client, MT9M111_TPG_CTRL, val, + MT9M111_TPG_SEL_MASK); +} + static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl) { struct mt9m111 *mt9m111 = container_of(ctrl->handler, @@ -721,6 +745,8 @@ static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl) return mt9m111_set_autoexposure(mt9m111, ctrl->val); case V4L2_CID_AUTO_WHITE_BALANCE: return mt9m111_set_autowhitebalance(mt9m111, ctrl->val); + case V4L2_CID_TEST_PATTERN: + return mt9m111_set_test_pattern(mt9m111, ctrl->val); } return -EINVAL; @@ -951,6 +977,8 @@ static int mt9m111_probe(struct i2c_client *client, mt9m111->ctx = &context_b; v4l2_i2c_subdev_init(&mt9m111->subdev, client, &mt9m111_subdev_ops); + mt9m111->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + v4l2_ctrl_handler_init(&mt9m111->hdl, 5); v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); @@ -963,12 +991,24 @@ static int mt9m111_probe(struct i2c_client *client, v4l2_ctrl_new_std_menu(&mt9m111->hdl, &mt9m111_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_AUTO); + v4l2_ctrl_new_std_menu_items(&mt9m111->hdl, + &mt9m111_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(mt9m111_test_pattern_menu) - 1, 0, 0, + mt9m111_test_pattern_menu); mt9m111->subdev.ctrl_handler = &mt9m111->hdl; if (mt9m111->hdl.error) { ret = mt9m111->hdl.error; goto out_clkput; } +#ifdef CONFIG_MEDIA_CONTROLLER + mt9m111->pad.flags = MEDIA_PAD_FL_SOURCE; + mt9m111->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&mt9m111->subdev.entity, 1, &mt9m111->pad); + if (ret < 0) + goto out_hdlfree; +#endif + /* Second stage probe - when a capture adapter is there */ mt9m111->rect.left = MT9M111_MIN_DARK_COLS; mt9m111->rect.top = MT9M111_MIN_DARK_ROWS; @@ -980,16 +1020,20 @@ static int mt9m111_probe(struct i2c_client *client, ret = mt9m111_video_probe(client); if (ret < 0) - goto out_hdlfree; + goto out_entityclean; mt9m111->subdev.dev = &client->dev; ret = v4l2_async_register_subdev(&mt9m111->subdev); if (ret < 0) - goto out_hdlfree; + goto out_entityclean; return 0; +out_entityclean: +#ifdef CONFIG_MEDIA_CONTROLLER + media_entity_cleanup(&mt9m111->subdev.entity); out_hdlfree: +#endif v4l2_ctrl_handler_free(&mt9m111->hdl); out_clkput: v4l2_clk_put(mt9m111->clk); @@ -1002,6 +1046,7 @@ static int mt9m111_remove(struct i2c_client *client) struct mt9m111 *mt9m111 = to_mt9m111(client); v4l2_async_unregister_subdev(&mt9m111->subdev); + media_entity_cleanup(&mt9m111->subdev.entity); v4l2_clk_put(mt9m111->clk); v4l2_ctrl_handler_free(&mt9m111->hdl); diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c index 9ed1b26b6549..5e29064fae91 100644 --- a/drivers/media/i2c/mt9v011.c +++ b/drivers/media/i2c/mt9v011.c @@ -1,9 +1,8 @@ -/* - * mt9v011 -Micron 1/4-Inch VGA Digital Image Sensor - * - * Copyright (c) 2009 Mauro Carvalho Chehab - * This code is placed under the terms of the GNU General Public License v2 - */ +// SPDX-License-Identifier: GPL-2.0 +// +// mt9v011 -Micron 1/4-Inch VGA Digital Image Sensor +// +// Copyright (c) 2009 Mauro Carvalho Chehab <mchehab@kernel.org> #include <linux/i2c.h> #include <linux/slab.h> @@ -17,7 +16,7 @@ MODULE_DESCRIPTION("Micron mt9v011 sensor driver"); MODULE_AUTHOR("Mauro Carvalho Chehab"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); static int debug; module_param(debug, int, 0); diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index 8a430640c85d..4de63b2df334 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -294,14 +294,22 @@ static int mt9v032_power_on(struct mt9v032 *mt9v032) /* Reset the chip and stop data read out */ ret = regmap_write(map, MT9V032_RESET, 1); if (ret < 0) - return ret; + goto err; ret = regmap_write(map, MT9V032_RESET, 0); if (ret < 0) - return ret; + goto err; + + ret = regmap_write(map, MT9V032_CHIP_CONTROL, + MT9V032_CHIP_CONTROL_MASTER_MODE); + if (ret < 0) + goto err; + + return 0; - return regmap_write(map, MT9V032_CHIP_CONTROL, - MT9V032_CHIP_CONTROL_MASTER_MODE); +err: + clk_disable_unprepare(mt9v032->clk); + return ret; } static void mt9v032_power_off(struct mt9v032 *mt9v032) @@ -876,6 +884,9 @@ static int mt9v032_registered(struct v4l2_subdev *subdev) /* Read and check the sensor version */ ret = regmap_read(mt9v032->regmap, MT9V032_CHIP_VERSION, &version); + + mt9v032_power_off(mt9v032); + if (ret < 0) { dev_err(&client->dev, "Failed reading chip version\n"); return ret; @@ -894,8 +905,6 @@ static int mt9v032_registered(struct v4l2_subdev *subdev) return -ENODEV; } - mt9v032_power_off(mt9v032); - dev_info(&client->dev, "%s detected at address 0x%02x\n", mt9v032->version->name, client->addr); diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index 518868388d65..4c3b92763243 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -1147,9 +1147,7 @@ static int ov2640_probe(struct i2c_client *client, return 0; err_videoprobe: -#if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&priv->subdev.entity); -#endif err_hdl: v4l2_ctrl_handler_free(&priv->hdl); err_clk: @@ -1163,9 +1161,7 @@ static int ov2640_remove(struct i2c_client *client) v4l2_async_unregister_subdev(&priv->subdev); v4l2_ctrl_handler_free(&priv->hdl); -#if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&priv->subdev.entity); -#endif v4l2_device_unregister_subdev(&priv->subdev); clk_disable_unprepare(priv->clk); return 0; diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c index 122dd6c5eb38..4715edc8ca33 100644 --- a/drivers/media/i2c/ov2659.c +++ b/drivers/media/i2c/ov2659.c @@ -1474,9 +1474,7 @@ static int ov2659_probe(struct i2c_client *client, error: v4l2_ctrl_handler_free(&ov2659->ctrls); -#if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&sd->entity); -#endif mutex_destroy(&ov2659->lock); return ret; } @@ -1488,9 +1486,7 @@ static int ov2659_remove(struct i2c_client *client) v4l2_ctrl_handler_free(&ov2659->ctrls); v4l2_async_unregister_subdev(sd); -#if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&sd->entity); -#endif mutex_destroy(&ov2659->lock); return 0; diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index c89ed6609738..e2dd352224c7 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -34,13 +34,19 @@ #define OV5640_DEFAULT_SLAVE_ID 0x3c +#define OV5640_REG_SYS_CTRL0 0x3008 #define OV5640_REG_CHIP_ID 0x300a +#define OV5640_REG_IO_MIPI_CTRL00 0x300e +#define OV5640_REG_PAD_OUTPUT_ENABLE01 0x3017 +#define OV5640_REG_PAD_OUTPUT_ENABLE02 0x3018 #define OV5640_REG_PAD_OUTPUT00 0x3019 +#define OV5640_REG_SYSTEM_CONTROL1 0x302e #define OV5640_REG_SC_PLL_CTRL0 0x3034 #define OV5640_REG_SC_PLL_CTRL1 0x3035 #define OV5640_REG_SC_PLL_CTRL2 0x3036 #define OV5640_REG_SC_PLL_CTRL3 0x3037 #define OV5640_REG_SLAVE_ID 0x3100 +#define OV5640_REG_SCCB_SYS_CTRL1 0x3103 #define OV5640_REG_SYS_ROOT_DIVIDER 0x3108 #define OV5640_REG_AWB_R_GAIN 0x3400 #define OV5640_REG_AWB_G_GAIN 0x3402 @@ -70,8 +76,11 @@ #define OV5640_REG_HZ5060_CTRL01 0x3c01 #define OV5640_REG_SIGMADELTA_CTRL0C 0x3c0c #define OV5640_REG_FRAME_CTRL01 0x4202 +#define OV5640_REG_FORMAT_CONTROL00 0x4300 +#define OV5640_REG_POLARITY_CTRL00 0x4740 #define OV5640_REG_MIPI_CTRL00 0x4800 #define OV5640_REG_DEBUG_MODE 0x4814 +#define OV5640_REG_ISP_FORMAT_MUX_CTRL 0x501f #define OV5640_REG_PRE_ISP_TEST_SET1 0x503d #define OV5640_REG_SDE_CTRL0 0x5580 #define OV5640_REG_SDE_CTRL1 0x5581 @@ -99,6 +108,18 @@ enum ov5640_frame_rate { OV5640_NUM_FRAMERATES, }; +struct ov5640_pixfmt { + u32 code; + u32 colorspace; +}; + +static const struct ov5640_pixfmt ov5640_formats[] = { + { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB, }, + { MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB, }, +}; + /* * FIXME: remove this when a subdev API becomes available * to set the MIPI CSI-2 virtual channel. @@ -982,7 +1003,111 @@ static int ov5640_get_gain(struct ov5640_dev *sensor) return gain & 0x3ff; } -static int ov5640_set_stream(struct ov5640_dev *sensor, bool on) +static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on) +{ + int ret; + unsigned int flags = sensor->ep.bus.parallel.flags; + u8 pclk_pol = 0; + u8 hsync_pol = 0; + u8 vsync_pol = 0; + + /* + * Note about parallel port configuration. + * + * When configured in parallel mode, the OV5640 will + * output 10 bits data on DVP data lines [9:0]. + * If only 8 bits data are wanted, the 8 bits data lines + * of the camera interface must be physically connected + * on the DVP data lines [9:2]. + * + * Control lines polarity can be configured through + * devicetree endpoint control lines properties. + * If no endpoint control lines properties are set, + * polarity will be as below: + * - VSYNC: active high + * - HREF: active low + * - PCLK: active low + */ + + if (on) { + /* + * reset MIPI PCLK/SERCLK divider + * + * SC PLL CONTRL1 0 + * - [3..0]: MIPI PCLK/SERCLK divider + */ + ret = ov5640_mod_reg(sensor, OV5640_REG_SC_PLL_CTRL1, 0x0f, 0); + if (ret) + return ret; + + /* + * configure parallel port control lines polarity + * + * POLARITY CTRL0 + * - [5]: PCLK polarity (0: active low, 1: active high) + * - [1]: HREF polarity (0: active low, 1: active high) + * - [0]: VSYNC polarity (mismatch here between + * datasheet and hardware, 0 is active high + * and 1 is active low...) + */ + if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING) + pclk_pol = 1; + if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) + hsync_pol = 1; + if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + vsync_pol = 1; + + ret = ov5640_write_reg(sensor, + OV5640_REG_POLARITY_CTRL00, + (pclk_pol << 5) | + (hsync_pol << 1) | + vsync_pol); + + if (ret) + return ret; + } + + /* + * powerdown MIPI TX/RX PHY & disable MIPI + * + * MIPI CONTROL 00 + * 4: PWDN PHY TX + * 3: PWDN PHY RX + * 2: MIPI enable + */ + ret = ov5640_write_reg(sensor, + OV5640_REG_IO_MIPI_CTRL00, on ? 0x18 : 0); + if (ret) + return ret; + + /* + * enable VSYNC/HREF/PCLK DVP control lines + * & D[9:6] DVP data lines + * + * PAD OUTPUT ENABLE 01 + * - 6: VSYNC output enable + * - 5: HREF output enable + * - 4: PCLK output enable + * - [3:0]: D[9:6] output enable + */ + ret = ov5640_write_reg(sensor, + OV5640_REG_PAD_OUTPUT_ENABLE01, + on ? 0x7f : 0); + if (ret) + return ret; + + /* + * enable D[5:0] DVP data lines + * + * PAD OUTPUT ENABLE 02 + * - [7:2]: D[5:0] output enable + */ + return ov5640_write_reg(sensor, + OV5640_REG_PAD_OUTPUT_ENABLE02, + on ? 0xfc : 0); +} + +static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on) { int ret; @@ -1524,7 +1649,7 @@ static int ov5640_restore_mode(struct ov5640_dev *sensor) static void ov5640_power(struct ov5640_dev *sensor, bool enable) { - gpiod_set_value(sensor->pwdn_gpio, enable ? 0 : 1); + gpiod_set_value_cansleep(sensor->pwdn_gpio, enable ? 0 : 1); } static void ov5640_reset(struct ov5640_dev *sensor) @@ -1532,7 +1657,7 @@ static void ov5640_reset(struct ov5640_dev *sensor) if (!sensor->reset_gpio) return; - gpiod_set_value(sensor->reset_gpio, 0); + gpiod_set_value_cansleep(sensor->reset_gpio, 0); /* camera power cycle */ ov5640_power(sensor, false); @@ -1540,56 +1665,89 @@ static void ov5640_reset(struct ov5640_dev *sensor) ov5640_power(sensor, true); usleep_range(5000, 10000); - gpiod_set_value(sensor->reset_gpio, 1); + gpiod_set_value_cansleep(sensor->reset_gpio, 1); usleep_range(1000, 2000); - gpiod_set_value(sensor->reset_gpio, 0); + gpiod_set_value_cansleep(sensor->reset_gpio, 0); usleep_range(5000, 10000); } -static int ov5640_set_power(struct ov5640_dev *sensor, bool on) +static int ov5640_set_power_on(struct ov5640_dev *sensor) { - int ret = 0; + struct i2c_client *client = sensor->i2c_client; + int ret; - if (on) { - clk_prepare_enable(sensor->xclk); + ret = clk_prepare_enable(sensor->xclk); + if (ret) { + dev_err(&client->dev, "%s: failed to enable clock\n", + __func__); + return ret; + } - ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES, - sensor->supplies); - if (ret) - goto xclk_off; + ret = regulator_bulk_enable(OV5640_NUM_SUPPLIES, + sensor->supplies); + if (ret) { + dev_err(&client->dev, "%s: failed to enable regulators\n", + __func__); + goto xclk_off; + } + + ov5640_reset(sensor); + ov5640_power(sensor, true); - ov5640_reset(sensor); - ov5640_power(sensor, true); + ret = ov5640_init_slave_id(sensor); + if (ret) + goto power_off; - ret = ov5640_init_slave_id(sensor); + return 0; + +power_off: + ov5640_power(sensor, false); + regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies); +xclk_off: + clk_disable_unprepare(sensor->xclk); + return ret; +} + +static void ov5640_set_power_off(struct ov5640_dev *sensor) +{ + ov5640_power(sensor, false); + regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies); + clk_disable_unprepare(sensor->xclk); +} + +static int ov5640_set_power(struct ov5640_dev *sensor, bool on) +{ + int ret = 0; + + if (on) { + ret = ov5640_set_power_on(sensor); if (ret) - goto power_off; + return ret; ret = ov5640_restore_mode(sensor); if (ret) goto power_off; - /* - * start streaming briefly followed by stream off in - * order to coax the clock lane into LP-11 state. - */ - ret = ov5640_set_stream(sensor, true); - if (ret) - goto power_off; - usleep_range(1000, 2000); - ret = ov5640_set_stream(sensor, false); - if (ret) - goto power_off; + if (sensor->ep.bus_type == V4L2_MBUS_CSI2) { + /* + * start streaming briefly followed by stream off in + * order to coax the clock lane into LP-11 state. + */ + ret = ov5640_set_stream_mipi(sensor, true); + if (ret) + goto power_off; + usleep_range(1000, 2000); + ret = ov5640_set_stream_mipi(sensor, false); + if (ret) + goto power_off; + } return 0; } power_off: - ov5640_power(sensor, false); - regulator_bulk_disable(OV5640_NUM_SUPPLIES, sensor->supplies); -xclk_off: - clk_disable_unprepare(sensor->xclk); + ov5640_set_power_off(sensor); return ret; } @@ -1693,17 +1851,23 @@ static int ov5640_try_fmt_internal(struct v4l2_subdev *sd, { struct ov5640_dev *sensor = to_ov5640_dev(sd); const struct ov5640_mode_info *mode; + int i; mode = ov5640_find_mode(sensor, fr, fmt->width, fmt->height, true); if (!mode) return -EINVAL; - fmt->width = mode->width; fmt->height = mode->height; - fmt->code = sensor->fmt.code; if (new_mode) *new_mode = mode; + + for (i = 0; i < ARRAY_SIZE(ov5640_formats); i++) + if (ov5640_formats[i].code == fmt->code) + break; + if (i >= ARRAY_SIZE(ov5640_formats)) + fmt->code = ov5640_formats[0].code; + return 0; } @@ -1746,6 +1910,45 @@ out: return ret; } +static int ov5640_set_framefmt(struct ov5640_dev *sensor, + struct v4l2_mbus_framefmt *format) +{ + int ret = 0; + bool is_rgb = false; + u8 val; + + switch (format->code) { + case MEDIA_BUS_FMT_UYVY8_2X8: + /* YUV422, UYVY */ + val = 0x3f; + break; + case MEDIA_BUS_FMT_YUYV8_2X8: + /* YUV422, YUYV */ + val = 0x30; + break; + case MEDIA_BUS_FMT_RGB565_2X8_LE: + /* RGB565 {g[2:0],b[4:0]},{r[4:0],g[5:3]} */ + val = 0x6F; + is_rgb = true; + break; + case MEDIA_BUS_FMT_RGB565_2X8_BE: + /* RGB565 {r[4:0],g[5:3]},{g[2:0],b[4:0]} */ + val = 0x61; + is_rgb = true; + break; + default: + return -EINVAL; + } + + /* FORMAT CONTROL00: YUV and RGB formatting */ + ret = ov5640_write_reg(sensor, OV5640_REG_FORMAT_CONTROL00, val); + if (ret) + return ret; + + /* FORMAT MUX CONTROL: ISP YUV or RGB */ + return ov5640_write_reg(sensor, OV5640_REG_ISP_FORMAT_MUX_CTRL, + is_rgb ? 0x01 : 0x00); +} /* * Sensor Controls. @@ -1854,6 +2057,7 @@ static int ov5640_set_ctrl_exposure(struct ov5640_dev *sensor, int exp) if (ret < 0) return ret; max_exp += ret; + ret = 0; if (ctrls->exposure->val < max_exp) ret = ov5640_set_exposure(sensor, ctrls->exposure->val); @@ -2131,15 +2335,12 @@ static int ov5640_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { - struct ov5640_dev *sensor = to_ov5640_dev(sd); - if (code->pad != 0) return -EINVAL; - if (code->index != 0) + if (code->index >= ARRAY_SIZE(ov5640_formats)) return -EINVAL; - code->code = sensor->fmt.code; - + code->code = ov5640_formats[code->index].code; return 0; } @@ -2155,9 +2356,17 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable) ret = ov5640_set_mode(sensor, sensor->current_mode); if (ret) goto out; + + ret = ov5640_set_framefmt(sensor, &sensor->fmt); + if (ret) + goto out; } - ret = ov5640_set_stream(sensor, enable); + if (sensor->ep.bus_type == V4L2_MBUS_CSI2) + ret = ov5640_set_stream_mipi(sensor, enable); + else + ret = ov5640_set_stream_dvp(sensor, enable); + if (!ret) sensor->streaming = enable; } @@ -2202,6 +2411,34 @@ static int ov5640_get_regulators(struct ov5640_dev *sensor) sensor->supplies); } +static int ov5640_check_chip_id(struct ov5640_dev *sensor) +{ + struct i2c_client *client = sensor->i2c_client; + int ret = 0; + u16 chip_id; + + ret = ov5640_set_power_on(sensor); + if (ret) + return ret; + + ret = ov5640_read_reg16(sensor, OV5640_REG_CHIP_ID, &chip_id); + if (ret) { + dev_err(&client->dev, "%s: failed to read chip identifier\n", + __func__); + goto power_off; + } + + if (chip_id != 0x5640) { + dev_err(&client->dev, "%s: wrong chip identifier, expected 0x5640, got 0x%x\n", + __func__, chip_id); + ret = -ENXIO; + } + +power_off: + ov5640_set_power_off(sensor); + return ret; +} + static int ov5640_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -2242,11 +2479,6 @@ static int ov5640_probe(struct i2c_client *client, return ret; } - if (sensor->ep.bus_type != V4L2_MBUS_CSI2) { - dev_err(dev, "invalid bus type, must be MIPI CSI2\n"); - return -EINVAL; - } - /* get system clock (xclk) */ sensor->xclk = devm_clk_get(dev, "xclk"); if (IS_ERR(sensor->xclk)) { @@ -2284,6 +2516,10 @@ static int ov5640_probe(struct i2c_client *client, mutex_init(&sensor->lock); + ret = ov5640_check_chip_id(sensor); + if (ret) + goto entity_cleanup; + ret = ov5640_init_controls(sensor); if (ret) goto entity_cleanup; diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 950a0acf85fb..28571de1c2f6 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -163,6 +163,11 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); #define DBLV_X6 0x10 /* clock x6 */ #define DBLV_X8 0x11 /* clock x8 */ +#define REG_SCALING_XSC 0x70 /* Test pattern and horizontal scale factor */ +#define TEST_PATTTERN_0 0x80 +#define REG_SCALING_YSC 0x71 /* Test pattern and vertical scale factor */ +#define TEST_PATTTERN_1 0x80 + #define REG_REG76 0x76 /* OV's name */ #define R76_BLKPCOR 0x80 /* Black pixel correction enable */ #define R76_WHTPCOR 0x40 /* White pixel correction enable */ @@ -292,7 +297,8 @@ static struct regval_list ov7670_default_regs[] = { { REG_COM3, 0 }, { REG_COM14, 0 }, /* Mystery scaling numbers */ - { 0x70, 0x3a }, { 0x71, 0x35 }, + { REG_SCALING_XSC, 0x3a }, + { REG_SCALING_YSC, 0x35 }, { 0x72, 0x11 }, { 0x73, 0xf0 }, { 0xa2, 0x02 }, { REG_COM10, 0x0 }, @@ -406,12 +412,12 @@ static struct regval_list ov7670_fmt_yuv422[] = { { REG_COM1, 0 }, /* CCIR601 */ { REG_COM15, COM15_R00FF }, { REG_COM9, 0x48 }, /* 32x gain ceiling; 0x8 is reserved bit */ - { 0x4f, 0x80 }, /* "matrix coefficient 1" */ - { 0x50, 0x80 }, /* "matrix coefficient 2" */ + { 0x4f, 0x80 }, /* "matrix coefficient 1" */ + { 0x50, 0x80 }, /* "matrix coefficient 2" */ { 0x51, 0 }, /* vb */ - { 0x52, 0x22 }, /* "matrix coefficient 4" */ - { 0x53, 0x5e }, /* "matrix coefficient 5" */ - { 0x54, 0x80 }, /* "matrix coefficient 6" */ + { 0x52, 0x22 }, /* "matrix coefficient 4" */ + { 0x53, 0x5e }, /* "matrix coefficient 5" */ + { 0x54, 0x80 }, /* "matrix coefficient 6" */ { REG_COM13, COM13_GAMMA|COM13_UVSAT }, { 0xff, 0xff }, }; @@ -421,13 +427,13 @@ static struct regval_list ov7670_fmt_rgb565[] = { { REG_RGB444, 0 }, /* No RGB444 please */ { REG_COM1, 0x0 }, /* CCIR601 */ { REG_COM15, COM15_RGB565 }, - { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ - { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ - { 0x50, 0xb3 }, /* "matrix coefficient 2" */ + { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ + { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ + { 0x50, 0xb3 }, /* "matrix coefficient 2" */ { 0x51, 0 }, /* vb */ - { 0x52, 0x3d }, /* "matrix coefficient 4" */ - { 0x53, 0xa7 }, /* "matrix coefficient 5" */ - { 0x54, 0xe4 }, /* "matrix coefficient 6" */ + { 0x52, 0x3d }, /* "matrix coefficient 4" */ + { 0x53, 0xa7 }, /* "matrix coefficient 5" */ + { 0x54, 0xe4 }, /* "matrix coefficient 6" */ { REG_COM13, COM13_GAMMA|COM13_UVSAT }, { 0xff, 0xff }, }; @@ -437,13 +443,13 @@ static struct regval_list ov7670_fmt_rgb444[] = { { REG_RGB444, R444_ENABLE }, /* Enable xxxxrrrr ggggbbbb */ { REG_COM1, 0x0 }, /* CCIR601 */ { REG_COM15, COM15_R01FE|COM15_RGB565 }, /* Data range needed? */ - { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ - { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ - { 0x50, 0xb3 }, /* "matrix coefficient 2" */ + { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ + { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ + { 0x50, 0xb3 }, /* "matrix coefficient 2" */ { 0x51, 0 }, /* vb */ - { 0x52, 0x3d }, /* "matrix coefficient 4" */ - { 0x53, 0xa7 }, /* "matrix coefficient 5" */ - { 0x54, 0xe4 }, /* "matrix coefficient 6" */ + { 0x52, 0x3d }, /* "matrix coefficient 4" */ + { 0x53, 0xa7 }, /* "matrix coefficient 5" */ + { 0x54, 0xe4 }, /* "matrix coefficient 6" */ { REG_COM13, COM13_GAMMA|COM13_UVSAT|0x2 }, /* Magic rsvd bit */ { 0xff, 0xff }, }; @@ -568,6 +574,19 @@ static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg, return ov7670_write_i2c(sd, reg, value); } +static int ov7670_update_bits(struct v4l2_subdev *sd, unsigned char reg, + unsigned char mask, unsigned char value) +{ + unsigned char orig; + int ret; + + ret = ov7670_read(sd, reg, &orig); + if (ret) + return ret; + + return ov7670_write(sd, reg, (orig & ~mask) | (value & mask)); +} + /* * Write a list of register settings; ff/ff stops the process. */ @@ -648,7 +667,7 @@ static struct ov7670_format_struct { { .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .colorspace = V4L2_COLORSPACE_SRGB, - .regs = ov7670_fmt_yuv422, + .regs = ov7670_fmt_yuv422, .cmatrix = { 128, -128, 0, -34, -94, 128 }, }, { @@ -666,7 +685,7 @@ static struct ov7670_format_struct { { .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, .colorspace = V4L2_COLORSPACE_SRGB, - .regs = ov7670_fmt_raw, + .regs = ov7670_fmt_raw, .cmatrix = { 0, 0, 0, 0, 0, 0 }, }, }; @@ -1470,6 +1489,25 @@ static int ov7670_s_autoexp(struct v4l2_subdev *sd, return ret; } +static const char * const ov7670_test_pattern_menu[] = { + "No test output", + "Shifting \"1\"", + "8-bar color bar", + "Fade to gray color bar", +}; + +static int ov7670_s_test_pattern(struct v4l2_subdev *sd, int value) +{ + int ret; + + ret = ov7670_update_bits(sd, REG_SCALING_XSC, TEST_PATTTERN_0, + value & BIT(0) ? TEST_PATTTERN_0 : 0); + if (ret) + return ret; + + return ov7670_update_bits(sd, REG_SCALING_YSC, TEST_PATTTERN_1, + value & BIT(1) ? TEST_PATTTERN_1 : 0); +} static int ov7670_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { @@ -1516,6 +1554,8 @@ static int ov7670_s_ctrl(struct v4l2_ctrl *ctrl) return ov7670_s_exp(sd, info->exposure->val); } return ov7670_s_autoexp(sd, ctrl->val); + case V4L2_CID_TEST_PATTERN: + return ov7670_s_test_pattern(sd, ctrl->val); } return -EINVAL; } @@ -1770,6 +1810,10 @@ static int ov7670_probe(struct i2c_client *client, info->auto_exposure = v4l2_ctrl_new_std_menu(&info->hdl, &ov7670_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO); + v4l2_ctrl_new_std_menu_items(&info->hdl, &ov7670_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov7670_test_pattern_menu) - 1, 0, 0, + ov7670_test_pattern_menu); sd->ctrl_handler = &info->hdl; if (info->hdl.error) { ret = info->hdl.error; @@ -1802,9 +1846,7 @@ static int ov7670_probe(struct i2c_client *client, return 0; entity_cleanup: -#if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&info->sd.entity); -#endif hdl_free: v4l2_ctrl_handler_free(&info->hdl); power_off: @@ -1820,12 +1862,10 @@ static int ov7670_remove(struct i2c_client *client) struct v4l2_subdev *sd = i2c_get_clientdata(client); struct ov7670_info *info = to_state(sd); - v4l2_device_unregister_subdev(sd); + v4l2_async_unregister_subdev(sd); v4l2_ctrl_handler_free(&info->hdl); clk_disable_unprepare(info->clk); -#if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&info->sd.entity); -#endif ov7670_s_power(sd, 0); return 0; } diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c new file mode 100644 index 000000000000..fc9dbbcae56e --- /dev/null +++ b/drivers/media/i2c/ov7740.c @@ -0,0 +1,1214 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017 Microchip Corporation. + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> +#include <media/v4l2-image-sizes.h> +#include <media/v4l2-subdev.h> + +#define REG_OUTSIZE_LSB 0x34 + +/* OV7740 register tables */ +#define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */ +#define REG_BGAIN 0x01 /* blue gain */ +#define REG_RGAIN 0x02 /* red gain */ +#define REG_GGAIN 0x03 /* green gain */ +#define REG_REG04 0x04 /* analog setting, dont change*/ +#define REG_BAVG 0x05 /* b channel average */ +#define REG_GAVG 0x06 /* g channel average */ +#define REG_RAVG 0x07 /* r channel average */ + +#define REG_REG0C 0x0C /* filp enable */ +#define REG0C_IMG_FLIP 0x80 +#define REG0C_IMG_MIRROR 0x40 + +#define REG_REG0E 0x0E /* blc line */ +#define REG_HAEC 0x0F /* auto exposure cntrl */ +#define REG_AEC 0x10 /* auto exposure cntrl */ + +#define REG_CLK 0x11 /* Clock control */ +#define REG_REG55 0x55 /* Clock PLL DIV/PreDiv */ + +#define REG_REG12 0x12 + +#define REG_REG13 0x13 /* auto/manual AGC, AEC, Write Balance*/ +#define REG13_AEC_EN 0x01 +#define REG13_AGC_EN 0x04 + +#define REG_REG14 0x14 +#define REG_CTRL15 0x15 +#define REG15_GAIN_MSB 0x03 + +#define REG_REG16 0x16 + +#define REG_MIDH 0x1C /* manufacture id byte */ +#define REG_MIDL 0x1D /* manufacture id byre */ +#define REG_PIDH 0x0A /* Product ID MSB */ +#define REG_PIDL 0x0B /* Product ID LSB */ + +#define REG_84 0x84 /* lots of stuff */ +#define REG_REG38 0x38 /* sub-addr */ + +#define REG_AHSTART 0x17 /* Horiz start high bits */ +#define REG_AHSIZE 0x18 +#define REG_AVSTART 0x19 /* Vert start high bits */ +#define REG_AVSIZE 0x1A +#define REG_PSHFT 0x1b /* Pixel delay after HREF */ + +#define REG_HOUTSIZE 0x31 +#define REG_VOUTSIZE 0x32 +#define REG_HVSIZEOFF 0x33 +#define REG_REG34 0x34 /* DSP output size H/V LSB*/ + +#define REG_ISP_CTRL00 0x80 +#define ISPCTRL00_AWB_EN 0x10 +#define ISPCTRL00_AWB_GAIN_EN 0x04 + +#define REG_YGAIN 0xE2 /* ygain for contrast control */ + +#define REG_YBRIGHT 0xE3 +#define REG_SGNSET 0xE4 +#define SGNSET_YBRIGHT_MASK 0x08 + +#define REG_USAT 0xDD +#define REG_VSAT 0xDE + + +struct ov7740 { + struct v4l2_subdev subdev; +#if defined(CONFIG_MEDIA_CONTROLLER) + struct media_pad pad; +#endif + struct v4l2_mbus_framefmt format; + const struct ov7740_pixfmt *fmt; /* Current format */ + const struct ov7740_framesize *frmsize; + struct regmap *regmap; + struct clk *xvclk; + struct v4l2_ctrl_handler ctrl_handler; + struct { + /* gain cluster */ + struct v4l2_ctrl *auto_gain; + struct v4l2_ctrl *gain; + }; + struct { + struct v4l2_ctrl *auto_wb; + struct v4l2_ctrl *blue_balance; + struct v4l2_ctrl *red_balance; + }; + struct { + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + }; + struct { + /* exposure cluster */ + struct v4l2_ctrl *auto_exposure; + struct v4l2_ctrl *exposure; + }; + struct { + /* saturation/hue cluster */ + struct v4l2_ctrl *saturation; + struct v4l2_ctrl *hue; + }; + struct v4l2_ctrl *brightness; + struct v4l2_ctrl *contrast; + + struct mutex mutex; /* To serialize asynchronus callbacks */ + bool streaming; /* Streaming on/off */ + + struct gpio_desc *resetb_gpio; + struct gpio_desc *pwdn_gpio; +}; + +struct ov7740_pixfmt { + u32 mbus_code; + enum v4l2_colorspace colorspace; + const struct reg_sequence *regs; + u32 reg_num; +}; + +struct ov7740_framesize { + u16 width; + u16 height; + const struct reg_sequence *regs; + u32 reg_num; +}; + +static const struct reg_sequence ov7740_vga[] = { + {0x55, 0x40}, + {0x11, 0x02}, + + {0xd5, 0x10}, + {0x0c, 0x12}, + {0x0d, 0x34}, + {0x17, 0x25}, + {0x18, 0xa0}, + {0x19, 0x03}, + {0x1a, 0xf0}, + {0x1b, 0x89}, + {0x22, 0x03}, + {0x29, 0x18}, + {0x2b, 0xf8}, + {0x2c, 0x01}, + {REG_HOUTSIZE, 0xa0}, + {REG_VOUTSIZE, 0xf0}, + {0x33, 0xc4}, + {REG_OUTSIZE_LSB, 0x0}, + {0x35, 0x05}, + {0x04, 0x60}, + {0x27, 0x80}, + {0x3d, 0x0f}, + {0x3e, 0x80}, + {0x3f, 0x40}, + {0x40, 0x7f}, + {0x41, 0x6a}, + {0x42, 0x29}, + {0x44, 0x22}, + {0x45, 0x41}, + {0x47, 0x02}, + {0x49, 0x64}, + {0x4a, 0xa1}, + {0x4b, 0x40}, + {0x4c, 0x1a}, + {0x4d, 0x50}, + {0x4e, 0x13}, + {0x64, 0x00}, + {0x67, 0x88}, + {0x68, 0x1a}, + + {0x14, 0x28}, + {0x24, 0x3c}, + {0x25, 0x30}, + {0x26, 0x72}, + {0x50, 0x97}, + {0x51, 0x1f}, + {0x52, 0x00}, + {0x53, 0x00}, + {0x20, 0x00}, + {0x21, 0xcf}, + {0x50, 0x4b}, + {0x38, 0x14}, + {0xe9, 0x00}, + {0x56, 0x55}, + {0x57, 0xff}, + {0x58, 0xff}, + {0x59, 0xff}, + {0x5f, 0x04}, + {0xec, 0x00}, + {0x13, 0xff}, + + {0x81, 0x3f}, + {0x82, 0x32}, + {0x38, 0x11}, + {0x84, 0x70}, + {0x85, 0x00}, + {0x86, 0x03}, + {0x87, 0x01}, + {0x88, 0x05}, + {0x89, 0x30}, + {0x8d, 0x30}, + {0x8f, 0x85}, + {0x93, 0x30}, + {0x95, 0x85}, + {0x99, 0x30}, + {0x9b, 0x85}, + + {0x9c, 0x08}, + {0x9d, 0x12}, + {0x9e, 0x23}, + {0x9f, 0x45}, + {0xa0, 0x55}, + {0xa1, 0x64}, + {0xa2, 0x72}, + {0xa3, 0x7f}, + {0xa4, 0x8b}, + {0xa5, 0x95}, + {0xa6, 0xa7}, + {0xa7, 0xb5}, + {0xa8, 0xcb}, + {0xa9, 0xdd}, + {0xaa, 0xec}, + {0xab, 0x1a}, + + {0xce, 0x78}, + {0xcf, 0x6e}, + {0xd0, 0x0a}, + {0xd1, 0x0c}, + {0xd2, 0x84}, + {0xd3, 0x90}, + {0xd4, 0x1e}, + + {0x5a, 0x24}, + {0x5b, 0x1f}, + {0x5c, 0x88}, + {0x5d, 0x60}, + + {0xac, 0x6e}, + {0xbe, 0xff}, + {0xbf, 0x00}, + + {0x0f, 0x1d}, + {0x0f, 0x1f}, +}; + +static const struct ov7740_framesize ov7740_framesizes[] = { + { + .width = VGA_WIDTH, + .height = VGA_HEIGHT, + .regs = ov7740_vga, + .reg_num = ARRAY_SIZE(ov7740_vga), + }, +}; + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int ov7740_get_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); + struct regmap *regmap = ov7740->regmap; + unsigned int val = 0; + int ret; + + ret = regmap_read(regmap, reg->reg & 0xff, &val); + reg->val = val; + reg->size = 1; + + return 0; +} + +static int ov7740_set_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) +{ + struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); + struct regmap *regmap = ov7740->regmap; + + regmap_write(regmap, reg->reg & 0xff, reg->val & 0xff); + + return 0; +} +#endif + +static int ov7740_set_power(struct ov7740 *ov7740, int on) +{ + int ret; + + if (on) { + ret = clk_prepare_enable(ov7740->xvclk); + if (ret) + return ret; + + if (ov7740->pwdn_gpio) + gpiod_direction_output(ov7740->pwdn_gpio, 0); + + if (ov7740->resetb_gpio) { + gpiod_set_value(ov7740->resetb_gpio, 1); + usleep_range(500, 1000); + gpiod_set_value(ov7740->resetb_gpio, 0); + usleep_range(3000, 5000); + } + } else { + clk_disable_unprepare(ov7740->xvclk); + + if (ov7740->pwdn_gpio) + gpiod_direction_output(ov7740->pwdn_gpio, 0); + } + + return 0; +} + +static struct v4l2_subdev_core_ops ov7740_subdev_core_ops = { + .log_status = v4l2_ctrl_subdev_log_status, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = ov7740_get_register, + .s_register = ov7740_set_register, +#endif + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static int ov7740_set_white_balance(struct ov7740 *ov7740, int awb) +{ + struct regmap *regmap = ov7740->regmap; + unsigned int value; + int ret; + + ret = regmap_read(regmap, REG_ISP_CTRL00, &value); + if (!ret) { + if (awb) + value |= (ISPCTRL00_AWB_EN | ISPCTRL00_AWB_GAIN_EN); + else + value &= ~(ISPCTRL00_AWB_EN | ISPCTRL00_AWB_GAIN_EN); + ret = regmap_write(regmap, REG_ISP_CTRL00, value); + if (ret) + return ret; + } + + if (!awb) { + ret = regmap_write(regmap, REG_BGAIN, + ov7740->blue_balance->val); + if (ret) + return ret; + + ret = regmap_write(regmap, REG_RGAIN, ov7740->red_balance->val); + if (ret) + return ret; + } + + return 0; +} + +static int ov7740_set_saturation(struct regmap *regmap, int value) +{ + int ret; + + ret = regmap_write(regmap, REG_USAT, (unsigned char)value); + if (ret) + return ret; + + return regmap_write(regmap, REG_VSAT, (unsigned char)value); +} + +static int ov7740_set_gain(struct regmap *regmap, int value) +{ + int ret; + + ret = regmap_write(regmap, REG_GAIN, value & 0xff); + if (ret) + return ret; + + ret = regmap_update_bits(regmap, REG_CTRL15, + REG15_GAIN_MSB, (value >> 8) & 0x3); + if (!ret) + ret = regmap_update_bits(regmap, REG_REG13, REG13_AGC_EN, 0); + + return ret; +} + +static int ov7740_set_autogain(struct regmap *regmap, int value) +{ + unsigned int reg; + int ret; + + ret = regmap_read(regmap, REG_REG13, ®); + if (ret) + return ret; + if (value) + reg |= REG13_AGC_EN; + else + reg &= ~REG13_AGC_EN; + return regmap_write(regmap, REG_REG13, reg); +} + +static int ov7740_set_brightness(struct regmap *regmap, int value) +{ + /* Turn off AEC/AGC */ + regmap_update_bits(regmap, REG_REG13, REG13_AEC_EN, 0); + regmap_update_bits(regmap, REG_REG13, REG13_AGC_EN, 0); + + if (value >= 0) { + regmap_write(regmap, REG_YBRIGHT, (unsigned char)value); + regmap_update_bits(regmap, REG_SGNSET, SGNSET_YBRIGHT_MASK, 0); + } else{ + regmap_write(regmap, REG_YBRIGHT, (unsigned char)(-value)); + regmap_update_bits(regmap, REG_SGNSET, SGNSET_YBRIGHT_MASK, 1); + } + + return 0; +} + +static int ov7740_set_contrast(struct regmap *regmap, int value) +{ + return regmap_write(regmap, REG_YGAIN, (unsigned char)value); +} + +static int ov7740_get_gain(struct ov7740 *ov7740, struct v4l2_ctrl *ctrl) +{ + struct regmap *regmap = ov7740->regmap; + unsigned int value0, value1; + int ret; + + if (!ctrl->val) + return 0; + + ret = regmap_read(regmap, REG_GAIN, &value0); + if (ret) + return ret; + ret = regmap_read(regmap, REG_CTRL15, &value1); + if (ret) + return ret; + + ov7740->gain->val = (value1 << 8) | (value0 & 0xff); + + return 0; +} + +static int ov7740_set_exp(struct regmap *regmap, int value) +{ + int ret; + + /* Turn off AEC/AGC */ + ret = regmap_update_bits(regmap, REG_REG13, + REG13_AEC_EN | REG13_AGC_EN, 0); + if (ret) + return ret; + + ret = regmap_write(regmap, REG_AEC, (unsigned char)value); + if (ret) + return ret; + + return regmap_write(regmap, REG_HAEC, (unsigned char)(value >> 8)); +} + +static int ov7740_set_autoexp(struct regmap *regmap, + enum v4l2_exposure_auto_type value) +{ + unsigned int reg; + int ret; + + ret = regmap_read(regmap, REG_REG13, ®); + if (!ret) { + if (value == V4L2_EXPOSURE_AUTO) + reg |= (REG13_AEC_EN | REG13_AGC_EN); + else + reg &= ~(REG13_AEC_EN | REG13_AGC_EN); + ret = regmap_write(regmap, REG_REG13, reg); + } + + return ret; +} + + +static int ov7740_get_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov7740 *ov7740 = container_of(ctrl->handler, + struct ov7740, ctrl_handler); + int ret; + + switch (ctrl->id) { + case V4L2_CID_AUTOGAIN: + ret = ov7740_get_gain(ov7740, ctrl); + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int ov7740_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov7740 *ov7740 = container_of(ctrl->handler, + struct ov7740, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&ov7740->subdev); + struct regmap *regmap = ov7740->regmap; + int ret; + u8 val = 0; + + if (pm_runtime_get_if_in_use(&client->dev) <= 0) + return 0; + + switch (ctrl->id) { + case V4L2_CID_AUTO_WHITE_BALANCE: + ret = ov7740_set_white_balance(ov7740, ctrl->val); + break; + case V4L2_CID_SATURATION: + ret = ov7740_set_saturation(regmap, ctrl->val); + break; + case V4L2_CID_BRIGHTNESS: + ret = ov7740_set_brightness(regmap, ctrl->val); + break; + case V4L2_CID_CONTRAST: + ret = ov7740_set_contrast(regmap, ctrl->val); + break; + case V4L2_CID_VFLIP: + ret = regmap_update_bits(regmap, REG_REG0C, + REG0C_IMG_FLIP, val); + break; + case V4L2_CID_HFLIP: + val = ctrl->val ? REG0C_IMG_MIRROR : 0x00; + ret = regmap_update_bits(regmap, REG_REG0C, + REG0C_IMG_MIRROR, val); + break; + case V4L2_CID_AUTOGAIN: + if (!ctrl->val) + return ov7740_set_gain(regmap, ov7740->gain->val); + + ret = ov7740_set_autogain(regmap, ctrl->val); + break; + + case V4L2_CID_EXPOSURE_AUTO: + if (ctrl->val == V4L2_EXPOSURE_MANUAL) + return ov7740_set_exp(regmap, ov7740->exposure->val); + + ret = ov7740_set_autoexp(regmap, ctrl->val); + break; + default: + ret = -EINVAL; + break; + } + + pm_runtime_put(&client->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops ov7740_ctrl_ops = { + .g_volatile_ctrl = ov7740_get_volatile_ctrl, + .s_ctrl = ov7740_set_ctrl, +}; + +static int ov7740_start_streaming(struct ov7740 *ov7740) +{ + int ret; + + if (ov7740->fmt) { + ret = regmap_multi_reg_write(ov7740->regmap, + ov7740->fmt->regs, + ov7740->fmt->reg_num); + if (ret) + return ret; + } + + if (ov7740->frmsize) { + ret = regmap_multi_reg_write(ov7740->regmap, + ov7740->frmsize->regs, + ov7740->frmsize->reg_num); + if (ret) + return ret; + } + + return __v4l2_ctrl_handler_setup(ov7740->subdev.ctrl_handler); +} + +static int ov7740_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + mutex_lock(&ov7740->mutex); + if (ov7740->streaming == enable) { + mutex_unlock(&ov7740->mutex); + return 0; + } + + if (enable) { + ret = pm_runtime_get_sync(&client->dev); + if (ret < 0) { + pm_runtime_put_noidle(&client->dev); + goto err_unlock; + } + + ret = ov7740_start_streaming(ov7740); + if (ret) + goto err_rpm_put; + } else { + pm_runtime_put(&client->dev); + } + + ov7740->streaming = enable; + + mutex_unlock(&ov7740->mutex); + return ret; + +err_rpm_put: + pm_runtime_put(&client->dev); +err_unlock: + mutex_unlock(&ov7740->mutex); + return ret; +} + +static int ov7740_get_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *parms) +{ + struct v4l2_captureparm *cp = &parms->parm.capture; + struct v4l2_fract *tpf = &cp->timeperframe; + + if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + memset(cp, 0, sizeof(struct v4l2_captureparm)); + cp->capability = V4L2_CAP_TIMEPERFRAME; + + tpf->numerator = 1; + tpf->denominator = 60; + + return 0; +} + +static int ov7740_set_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *parms) +{ + struct v4l2_captureparm *cp = &parms->parm.capture; + struct v4l2_fract *tpf = &cp->timeperframe; + + if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (cp->extendedmode != 0) + return -EINVAL; + + cp->capability = V4L2_CAP_TIMEPERFRAME; + + tpf->numerator = 1; + tpf->denominator = 60; + + return 0; +} + +static struct v4l2_subdev_video_ops ov7740_subdev_video_ops = { + .s_stream = ov7740_set_stream, + .s_parm = ov7740_set_parm, + .g_parm = ov7740_get_parm, +}; + +static const struct reg_sequence ov7740_format_yuyv[] = { + {0x12, 0x00}, + {0x36, 0x3f}, + {0x80, 0x7f}, + {0x83, 0x01}, +}; + +static const struct reg_sequence ov7740_format_bggr8[] = { + {0x36, 0x2f}, + {0x80, 0x01}, + {0x83, 0x04}, +}; + +static const struct ov7740_pixfmt ov7740_formats[] = { + { + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .regs = ov7740_format_yuyv, + .reg_num = ARRAY_SIZE(ov7740_format_yuyv), + }, + { + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + .colorspace = V4L2_COLORSPACE_SRGB, + .regs = ov7740_format_bggr8, + .reg_num = ARRAY_SIZE(ov7740_format_bggr8), + } +}; +#define N_OV7740_FMTS ARRAY_SIZE(ov7740_formats) + +static int ov7740_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->pad || code->index >= N_OV7740_FMTS) + return -EINVAL; + + code->code = ov7740_formats[code->index].mbus_code; + + return 0; +} + +static int ov7740_enum_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_interval_enum *fie) +{ + if (fie->pad) + return -EINVAL; + + if (fie->index >= 1) + return -EINVAL; + + if ((fie->width != VGA_WIDTH) || (fie->height != VGA_HEIGHT)) + return -EINVAL; + + fie->interval.numerator = 1; + fie->interval.denominator = 60; + + return 0; +} + +static int ov7740_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->pad) + return -EINVAL; + + if (fse->index > 0) + return -EINVAL; + + fse->min_width = fse->max_width = VGA_WIDTH; + fse->min_height = fse->max_height = VGA_HEIGHT; + + return 0; +} + +static int ov7740_try_fmt_internal(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *fmt, + const struct ov7740_pixfmt **ret_fmt, + const struct ov7740_framesize **ret_frmsize) +{ + struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); + const struct ov7740_framesize *fsize = &ov7740_framesizes[0]; + int index, i; + + for (index = 0; index < N_OV7740_FMTS; index++) { + if (ov7740_formats[index].mbus_code == fmt->code) + break; + } + if (index >= N_OV7740_FMTS) { + /* default to first format */ + index = 0; + fmt->code = ov7740_formats[0].mbus_code; + } + if (ret_fmt != NULL) + *ret_fmt = ov7740_formats + index; + + for (i = 0; i < ARRAY_SIZE(ov7740_framesizes); i++) { + if ((fsize->width >= fmt->width) && + (fsize->height >= fmt->height)) { + fmt->width = fsize->width; + fmt->height = fsize->height; + break; + } + + fsize++; + } + + if (ret_frmsize != NULL) + *ret_frmsize = fsize; + + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = ov7740_formats[index].colorspace; + + ov7740->format = *fmt; + + return 0; +} + +static int ov7740_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); + const struct ov7740_pixfmt *ovfmt; + const struct ov7740_framesize *fsize; +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + struct v4l2_mbus_framefmt *mbus_fmt; +#endif + int ret; + + mutex_lock(&ov7740->mutex); + if (format->pad) { + ret = -EINVAL; + goto error; + } + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + ret = ov7740_try_fmt_internal(sd, &format->format, NULL, NULL); + if (ret) + goto error; +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); + *mbus_fmt = format->format; + + mutex_unlock(&ov7740->mutex); + return 0; +#else + ret = -ENOTTY; + goto error; +#endif + } + + ret = ov7740_try_fmt_internal(sd, &format->format, &ovfmt, &fsize); + if (ret) + goto error; + + ov7740->fmt = ovfmt; + ov7740->frmsize = fsize; + + mutex_unlock(&ov7740->mutex); + return 0; + +error: + mutex_unlock(&ov7740->mutex); + return ret; +} + +static int ov7740_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + struct v4l2_mbus_framefmt *mbus_fmt; +#endif + int ret = 0; + + mutex_lock(&ov7740->mutex); + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, 0); + format->format = *mbus_fmt; + ret = 0; +#else + ret = -ENOTTY; +#endif + } else { + format->format = ov7740->format; + } + mutex_unlock(&ov7740->mutex); + + return ret; +} + +static const struct v4l2_subdev_pad_ops ov7740_subdev_pad_ops = { + .enum_frame_interval = ov7740_enum_frame_interval, + .enum_frame_size = ov7740_enum_frame_size, + .enum_mbus_code = ov7740_enum_mbus_code, + .get_fmt = ov7740_get_fmt, + .set_fmt = ov7740_set_fmt, +}; + +static const struct v4l2_subdev_ops ov7740_subdev_ops = { + .core = &ov7740_subdev_core_ops, + .video = &ov7740_subdev_video_ops, + .pad = &ov7740_subdev_pad_ops, +}; + +static void ov7740_get_default_format(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *format) +{ + struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); + + format->width = ov7740->frmsize->width; + format->height = ov7740->frmsize->height; + format->colorspace = ov7740->fmt->colorspace; + format->code = ov7740->fmt->mbus_code; + format->field = V4L2_FIELD_NONE; +} + +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API +static int ov7740_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); + struct v4l2_mbus_framefmt *format = + v4l2_subdev_get_try_format(sd, fh->pad, 0); + + mutex_lock(&ov7740->mutex); + ov7740_get_default_format(sd, format); + mutex_unlock(&ov7740->mutex); + + return 0; +} + +static const struct v4l2_subdev_internal_ops ov7740_subdev_internal_ops = { + .open = ov7740_open, +}; +#endif + +static int ov7740_probe_dt(struct i2c_client *client, + struct ov7740 *ov7740) +{ + ov7740->resetb_gpio = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ov7740->resetb_gpio)) { + dev_info(&client->dev, "can't get %s GPIO\n", "reset"); + return PTR_ERR(ov7740->resetb_gpio); + } + + ov7740->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown", + GPIOD_OUT_LOW); + if (IS_ERR(ov7740->pwdn_gpio)) { + dev_info(&client->dev, "can't get %s GPIO\n", "powerdown"); + return PTR_ERR(ov7740->pwdn_gpio); + } + + return 0; +} + +static int ov7740_detect(struct ov7740 *ov7740) +{ + struct regmap *regmap = ov7740->regmap; + unsigned int midh, midl, pidh, pidl; + int ret; + + ret = regmap_read(regmap, REG_MIDH, &midh); + if (ret) + return ret; + if (midh != 0x7f) + return -ENODEV; + + ret = regmap_read(regmap, REG_MIDL, &midl); + if (ret) + return ret; + if (midl != 0xa2) + return -ENODEV; + + ret = regmap_read(regmap, REG_PIDH, &pidh); + if (ret) + return ret; + if (pidh != 0x77) + return -ENODEV; + + ret = regmap_read(regmap, REG_PIDL, &pidl); + if (ret) + return ret; + if ((pidl != 0x40) && (pidl != 0x41) && (pidl != 0x42)) + return -ENODEV; + + return 0; +} + +static int ov7740_init_controls(struct ov7740 *ov7740) +{ + struct i2c_client *client = v4l2_get_subdevdata(&ov7740->subdev); + struct v4l2_ctrl_handler *ctrl_hdlr = &ov7740->ctrl_handler; + int ret; + + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 2); + if (ret < 0) + return ret; + + ctrl_hdlr->lock = &ov7740->mutex; + ov7740->auto_wb = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, + V4L2_CID_AUTO_WHITE_BALANCE, + 0, 1, 1, 1); + ov7740->blue_balance = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, + V4L2_CID_BLUE_BALANCE, + 0, 0xff, 1, 0x80); + ov7740->red_balance = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, + V4L2_CID_RED_BALANCE, + 0, 0xff, 1, 0x80); + + ov7740->brightness = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, + V4L2_CID_BRIGHTNESS, + -255, 255, 1, 0); + ov7740->contrast = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, + V4L2_CID_CONTRAST, + 0, 127, 1, 0x20); + ov7740->saturation = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, + V4L2_CID_SATURATION, 0, 256, 1, 0x80); + ov7740->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, + 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); + 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); + 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); + + ret = v4l2_ctrl_handler_setup(ctrl_hdlr); + if (ret) { + dev_err(&client->dev, "%s control init failed (%d)\n", + __func__, ret); + goto error; + } + + ov7740->subdev.ctrl_handler = ctrl_hdlr; + return 0; + +error: + v4l2_ctrl_handler_free(ctrl_hdlr); + mutex_destroy(&ov7740->mutex); + return ret; +} + +static void ov7740_free_controls(struct ov7740 *ov7740) +{ + v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler); + mutex_destroy(&ov7740->mutex); +} + +#define OV7740_MAX_REGISTER 0xff +static const struct regmap_config ov7740_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = OV7740_MAX_REGISTER, +}; + +static int ov7740_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ov7740 *ov7740; + struct v4l2_subdev *sd; + int ret; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, + "OV7740: I2C-Adapter doesn't support SMBUS\n"); + return -EIO; + } + + ov7740 = devm_kzalloc(&client->dev, sizeof(*ov7740), GFP_KERNEL); + if (!ov7740) + return -ENOMEM; + + ov7740->xvclk = devm_clk_get(&client->dev, "xvclk"); + if (IS_ERR(ov7740->xvclk)) { + ret = PTR_ERR(ov7740->xvclk); + dev_err(&client->dev, + "OV7740: fail to get xvclk: %d\n", ret); + return ret; + } + + ret = ov7740_probe_dt(client, ov7740); + if (ret) + return ret; + + ov7740->regmap = devm_regmap_init_i2c(client, &ov7740_regmap_config); + if (IS_ERR(ov7740->regmap)) { + ret = PTR_ERR(ov7740->regmap); + dev_err(&client->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + sd = &ov7740->subdev; + client->flags |= I2C_CLIENT_SCCB; + v4l2_i2c_subdev_init(sd, client, &ov7740_subdev_ops); + +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + sd->internal_ops = &ov7740_subdev_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; +#endif + +#if defined(CONFIG_MEDIA_CONTROLLER) + ov7740->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sd->entity, 1, &ov7740->pad); + if (ret) + return ret; +#endif + + ret = ov7740_set_power(ov7740, 1); + if (ret) + return ret; + + ret = ov7740_detect(ov7740); + if (ret) + goto error_detect; + + mutex_init(&ov7740->mutex); + + ret = ov7740_init_controls(ov7740); + if (ret) + goto error_init_controls; + + v4l_info(client, "chip found @ 0x%02x (%s)\n", + client->addr << 1, client->adapter->name); + + ov7740->fmt = &ov7740_formats[0]; + ov7740->frmsize = &ov7740_framesizes[0]; + + ov7740_get_default_format(sd, &ov7740->format); + + ret = v4l2_async_register_subdev(sd); + if (ret) + goto error_async_register; + + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + pm_runtime_idle(&client->dev); + + return 0; + +error_async_register: + v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler); +error_init_controls: + ov7740_free_controls(ov7740); +error_detect: + ov7740_set_power(ov7740, 0); + media_entity_cleanup(&ov7740->subdev.entity); + + return ret; +} + +static int ov7740_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); + + mutex_destroy(&ov7740->mutex); + v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler); + media_entity_cleanup(&ov7740->subdev.entity); + v4l2_async_unregister_subdev(sd); + ov7740_free_controls(ov7740); + + pm_runtime_get_sync(&client->dev); + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + pm_runtime_put_noidle(&client->dev); + + ov7740_set_power(ov7740, 0); + return 0; +} + +static int __maybe_unused ov7740_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); + + ov7740_set_power(ov7740, 0); + + return 0; +} + +static int __maybe_unused ov7740_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev); + + return ov7740_set_power(ov7740, 1); +} + +static const struct i2c_device_id ov7740_id[] = { + { "ov7740", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, ov7740_id); + +static const struct dev_pm_ops ov7740_pm_ops = { + SET_RUNTIME_PM_OPS(ov7740_runtime_suspend, ov7740_runtime_resume, NULL) +}; + +static const struct of_device_id ov7740_of_match[] = { + {.compatible = "ovti,ov7740", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, ov7740_of_match); + +static struct i2c_driver ov7740_i2c_driver = { + .driver = { + .name = "ov7740", + .pm = &ov7740_pm_ops, + .of_match_table = of_match_ptr(ov7740_of_match), + }, + .probe = ov7740_probe, + .remove = ov7740_remove, + .id_table = ov7740_id, +}; +module_i2c_driver(ov7740_i2c_driver); + +MODULE_DESCRIPTION("The V4L2 driver for Omnivision 7740 sensor"); +MODULE_AUTHOR("Songjun Wu <songjun.wu@atmel.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index 69433e1e2533..e519f278d5f9 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -886,10 +886,12 @@ static int __g_volatile_ctrl(struct ov965x *ov965x, struct v4l2_ctrl *ctrl) if (ctrl->val == V4L2_EXPOSURE_MANUAL) return 0; ret = ov965x_read(client, REG_COM1, ®0); - if (!ret) - ret = ov965x_read(client, REG_AECH, ®1); - if (!ret) - ret = ov965x_read(client, REG_AECHM, ®2); + if (ret < 0) + return ret; + ret = ov965x_read(client, REG_AECH, ®1); + if (ret < 0) + return ret; + ret = ov965x_read(client, REG_AECHM, ®2); if (ret < 0) return ret; exposure = ((reg2 & 0x3f) << 10) | (reg1 << 2) | diff --git a/drivers/media/i2c/saa6752hs.c b/drivers/media/i2c/saa6752hs.c index 7202d3a3219a..170cc65c4f23 100644 --- a/drivers/media/i2c/saa6752hs.c +++ b/drivers/media/i2c/saa6752hs.c @@ -72,8 +72,8 @@ struct saa6752hs_mpeg_params { /* video */ enum v4l2_mpeg_video_aspect vi_aspect; enum v4l2_mpeg_video_bitrate_mode vi_bitrate_mode; - __u32 vi_bitrate; - __u32 vi_bitrate_peak; + __u32 vi_bitrate; + __u32 vi_bitrate_peak; }; static const struct v4l2_format v4l2_format_table[] = @@ -98,8 +98,8 @@ struct saa6752hs_state { struct v4l2_ctrl *video_bitrate; struct v4l2_ctrl *video_bitrate_peak; }; - u32 revision; - int has_ac3; + u32 revision; + int has_ac3; struct saa6752hs_mpeg_params params; enum saa6752hs_videoformat video_format; v4l2_std_id standard; diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index d863b04aa2a8..e216cd768409 100644 --- a/drivers/media/i2c/saa7115.c +++ b/drivers/media/i2c/saa7115.c @@ -1,37 +1,27 @@ -/* saa711x - Philips SAA711x video decoder driver - * This driver can work with saa7111, saa7111a, saa7113, saa7114, - * saa7115 and saa7118. - * - * Based on saa7114 driver by Maxim Yevtyushkin, which is based on - * the saa7111 driver by Dave Perks. - * - * Copyright (C) 1998 Dave Perks <dperks@ibm.net> - * Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com> - * - * Slight changes for video timing and attachment output by - * Wolfgang Scherr <scherr@net4you.net> - * - * Moved over to the linux >= 2.4.x i2c protocol (1/1/2003) - * by Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * Added saa7115 support by Kevin Thayer <nufan_wfk at yahoo.com> - * (2/17/2003) - * - * VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl> - * - * Copyright (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org> - * SAA7111, SAA7113 and SAA7118 support - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0+ +// saa711x - Philips SAA711x video decoder driver +// This driver can work with saa7111, saa7111a, saa7113, saa7114, +// saa7115 and saa7118. +// +// Based on saa7114 driver by Maxim Yevtyushkin, which is based on +// the saa7111 driver by Dave Perks. +// +// Copyright (C) 1998 Dave Perks <dperks@ibm.net> +// Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com> +// +// Slight changes for video timing and attachment output by +// Wolfgang Scherr <scherr@net4you.net> +// +// Moved over to the linux >= 2.4.x i2c protocol (1/1/2003) +// by Ronald Bultje <rbultje@ronald.bitfreak.net> +// +// Added saa7115 support by Kevin Thayer <nufan_wfk at yahoo.com> +// (2/17/2003) +// +// VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl> +// +// Copyright (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org> +// SAA7111, SAA7113 and SAA7118 support #include "saa711x_regs.h" @@ -758,7 +748,7 @@ static int saa711x_s_clock_freq(struct v4l2_subdev *sd, u32 freq) u32 acni; u32 hz; u64 f; - u8 acc = 0; /* reg 0x3a, audio clock control */ + u8 acc = 0; /* reg 0x3a, audio clock control */ /* Checks for chips that don't have audio clock (saa7111, saa7113) */ if (!saa711x_has_reg(state->ident, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD)) diff --git a/drivers/media/i2c/saa711x_regs.h b/drivers/media/i2c/saa711x_regs.h index 730ca90b30ac..a50d480e101a 100644 --- a/drivers/media/i2c/saa711x_regs.h +++ b/drivers/media/i2c/saa711x_regs.h @@ -1,16 +1,8 @@ -/* saa711x - Philips SAA711x video decoder register specifications +/* + * SPDX-License-Identifier: GPL-2.0+ + * saa711x - Philips SAA711x video decoder register specifications * * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #define R_00_CHIP_VERSION 0x00 diff --git a/drivers/media/i2c/saa7127.c b/drivers/media/i2c/saa7127.c index 01784d441ae6..e58a150cec5c 100644 --- a/drivers/media/i2c/saa7127.c +++ b/drivers/media/i2c/saa7127.c @@ -132,109 +132,109 @@ struct i2c_reg_value { }; static const struct i2c_reg_value saa7129_init_config_extra[] = { - { SAA7127_REG_OUTPUT_PORT_CONTROL, 0x38 }, - { SAA7127_REG_VTRIG, 0xfa }, + { SAA7127_REG_OUTPUT_PORT_CONTROL, 0x38 }, + { SAA7127_REG_VTRIG, 0xfa }, { 0, 0 } }; static const struct i2c_reg_value saa7127_init_config_common[] = { - { SAA7127_REG_WIDESCREEN_CONFIG, 0x0d }, - { SAA7127_REG_WIDESCREEN_ENABLE, 0x00 }, - { SAA7127_REG_COPYGEN_0, 0x77 }, - { SAA7127_REG_COPYGEN_1, 0x41 }, - { SAA7127_REG_COPYGEN_2, 0x00 }, /* Macrovision enable/disable */ - { SAA7127_REG_OUTPUT_PORT_CONTROL, 0xbf }, - { SAA7127_REG_GAIN_LUMINANCE_RGB, 0x00 }, - { SAA7127_REG_GAIN_COLORDIFF_RGB, 0x00 }, - { SAA7127_REG_INPUT_PORT_CONTROL_1, 0x80 }, /* for color bars */ - { SAA7127_REG_LINE_21_ODD_0, 0x77 }, - { SAA7127_REG_LINE_21_ODD_1, 0x41 }, - { SAA7127_REG_LINE_21_EVEN_0, 0x88 }, - { SAA7127_REG_LINE_21_EVEN_1, 0x41 }, - { SAA7127_REG_RCV_PORT_CONTROL, 0x12 }, - { SAA7127_REG_VTRIG, 0xf9 }, - { SAA7127_REG_HTRIG_HI, 0x00 }, - { SAA7127_REG_RCV2_OUTPUT_START, 0x41 }, - { SAA7127_REG_RCV2_OUTPUT_END, 0xc3 }, - { SAA7127_REG_RCV2_OUTPUT_MSBS, 0x00 }, - { SAA7127_REG_TTX_REQUEST_H_START, 0x3e }, - { SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH, 0xb8 }, - { SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT, 0x03 }, - { SAA7127_REG_TTX_ODD_REQ_VERT_START, 0x15 }, - { SAA7127_REG_TTX_ODD_REQ_VERT_END, 0x16 }, - { SAA7127_REG_TTX_EVEN_REQ_VERT_START, 0x15 }, - { SAA7127_REG_TTX_EVEN_REQ_VERT_END, 0x16 }, - { SAA7127_REG_FIRST_ACTIVE, 0x1a }, - { SAA7127_REG_LAST_ACTIVE, 0x01 }, - { SAA7127_REG_MSB_VERTICAL, 0xc0 }, - { SAA7127_REG_DISABLE_TTX_LINE_LO_0, 0x00 }, - { SAA7127_REG_DISABLE_TTX_LINE_LO_1, 0x00 }, + { SAA7127_REG_WIDESCREEN_CONFIG, 0x0d }, + { SAA7127_REG_WIDESCREEN_ENABLE, 0x00 }, + { SAA7127_REG_COPYGEN_0, 0x77 }, + { SAA7127_REG_COPYGEN_1, 0x41 }, + { SAA7127_REG_COPYGEN_2, 0x00 }, /* Macrovision enable/disable */ + { SAA7127_REG_OUTPUT_PORT_CONTROL, 0xbf }, + { SAA7127_REG_GAIN_LUMINANCE_RGB, 0x00 }, + { SAA7127_REG_GAIN_COLORDIFF_RGB, 0x00 }, + { SAA7127_REG_INPUT_PORT_CONTROL_1, 0x80 }, /* for color bars */ + { SAA7127_REG_LINE_21_ODD_0, 0x77 }, + { SAA7127_REG_LINE_21_ODD_1, 0x41 }, + { SAA7127_REG_LINE_21_EVEN_0, 0x88 }, + { SAA7127_REG_LINE_21_EVEN_1, 0x41 }, + { SAA7127_REG_RCV_PORT_CONTROL, 0x12 }, + { SAA7127_REG_VTRIG, 0xf9 }, + { SAA7127_REG_HTRIG_HI, 0x00 }, + { SAA7127_REG_RCV2_OUTPUT_START, 0x41 }, + { SAA7127_REG_RCV2_OUTPUT_END, 0xc3 }, + { SAA7127_REG_RCV2_OUTPUT_MSBS, 0x00 }, + { SAA7127_REG_TTX_REQUEST_H_START, 0x3e }, + { SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH, 0xb8 }, + { SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT, 0x03 }, + { SAA7127_REG_TTX_ODD_REQ_VERT_START, 0x15 }, + { SAA7127_REG_TTX_ODD_REQ_VERT_END, 0x16 }, + { SAA7127_REG_TTX_EVEN_REQ_VERT_START, 0x15 }, + { SAA7127_REG_TTX_EVEN_REQ_VERT_END, 0x16 }, + { SAA7127_REG_FIRST_ACTIVE, 0x1a }, + { SAA7127_REG_LAST_ACTIVE, 0x01 }, + { SAA7127_REG_MSB_VERTICAL, 0xc0 }, + { SAA7127_REG_DISABLE_TTX_LINE_LO_0, 0x00 }, + { SAA7127_REG_DISABLE_TTX_LINE_LO_1, 0x00 }, { 0, 0 } }; #define SAA7127_60HZ_DAC_CONTROL 0x15 static const struct i2c_reg_value saa7127_init_config_60hz[] = { - { SAA7127_REG_BURST_START, 0x19 }, + { SAA7127_REG_BURST_START, 0x19 }, /* BURST_END is also used as a chip ID in saa7127_probe */ - { SAA7127_REG_BURST_END, 0x1d }, - { SAA7127_REG_CHROMA_PHASE, 0xa3 }, - { SAA7127_REG_GAINU, 0x98 }, - { SAA7127_REG_GAINV, 0xd3 }, - { SAA7127_REG_BLACK_LEVEL, 0x39 }, - { SAA7127_REG_BLANKING_LEVEL, 0x2e }, - { SAA7127_REG_VBI_BLANKING, 0x2e }, - { SAA7127_REG_DAC_CONTROL, 0x15 }, - { SAA7127_REG_BURST_AMP, 0x4d }, - { SAA7127_REG_SUBC3, 0x1f }, - { SAA7127_REG_SUBC2, 0x7c }, - { SAA7127_REG_SUBC1, 0xf0 }, - { SAA7127_REG_SUBC0, 0x21 }, - { SAA7127_REG_MULTI, 0x90 }, - { SAA7127_REG_CLOSED_CAPTION, 0x11 }, + { SAA7127_REG_BURST_END, 0x1d }, + { SAA7127_REG_CHROMA_PHASE, 0xa3 }, + { SAA7127_REG_GAINU, 0x98 }, + { SAA7127_REG_GAINV, 0xd3 }, + { SAA7127_REG_BLACK_LEVEL, 0x39 }, + { SAA7127_REG_BLANKING_LEVEL, 0x2e }, + { SAA7127_REG_VBI_BLANKING, 0x2e }, + { SAA7127_REG_DAC_CONTROL, 0x15 }, + { SAA7127_REG_BURST_AMP, 0x4d }, + { SAA7127_REG_SUBC3, 0x1f }, + { SAA7127_REG_SUBC2, 0x7c }, + { SAA7127_REG_SUBC1, 0xf0 }, + { SAA7127_REG_SUBC0, 0x21 }, + { SAA7127_REG_MULTI, 0x90 }, + { SAA7127_REG_CLOSED_CAPTION, 0x11 }, { 0, 0 } }; #define SAA7127_50HZ_PAL_DAC_CONTROL 0x02 static struct i2c_reg_value saa7127_init_config_50hz_pal[] = { - { SAA7127_REG_BURST_START, 0x21 }, + { SAA7127_REG_BURST_START, 0x21 }, /* BURST_END is also used as a chip ID in saa7127_probe */ - { SAA7127_REG_BURST_END, 0x1d }, - { SAA7127_REG_CHROMA_PHASE, 0x3f }, - { SAA7127_REG_GAINU, 0x7d }, - { SAA7127_REG_GAINV, 0xaf }, - { SAA7127_REG_BLACK_LEVEL, 0x33 }, - { SAA7127_REG_BLANKING_LEVEL, 0x35 }, - { SAA7127_REG_VBI_BLANKING, 0x35 }, - { SAA7127_REG_DAC_CONTROL, 0x02 }, - { SAA7127_REG_BURST_AMP, 0x2f }, - { SAA7127_REG_SUBC3, 0xcb }, - { SAA7127_REG_SUBC2, 0x8a }, - { SAA7127_REG_SUBC1, 0x09 }, - { SAA7127_REG_SUBC0, 0x2a }, - { SAA7127_REG_MULTI, 0xa0 }, - { SAA7127_REG_CLOSED_CAPTION, 0x00 }, + { SAA7127_REG_BURST_END, 0x1d }, + { SAA7127_REG_CHROMA_PHASE, 0x3f }, + { SAA7127_REG_GAINU, 0x7d }, + { SAA7127_REG_GAINV, 0xaf }, + { SAA7127_REG_BLACK_LEVEL, 0x33 }, + { SAA7127_REG_BLANKING_LEVEL, 0x35 }, + { SAA7127_REG_VBI_BLANKING, 0x35 }, + { SAA7127_REG_DAC_CONTROL, 0x02 }, + { SAA7127_REG_BURST_AMP, 0x2f }, + { SAA7127_REG_SUBC3, 0xcb }, + { SAA7127_REG_SUBC2, 0x8a }, + { SAA7127_REG_SUBC1, 0x09 }, + { SAA7127_REG_SUBC0, 0x2a }, + { SAA7127_REG_MULTI, 0xa0 }, + { SAA7127_REG_CLOSED_CAPTION, 0x00 }, { 0, 0 } }; #define SAA7127_50HZ_SECAM_DAC_CONTROL 0x08 static struct i2c_reg_value saa7127_init_config_50hz_secam[] = { - { SAA7127_REG_BURST_START, 0x21 }, + { SAA7127_REG_BURST_START, 0x21 }, /* BURST_END is also used as a chip ID in saa7127_probe */ - { SAA7127_REG_BURST_END, 0x1d }, - { SAA7127_REG_CHROMA_PHASE, 0x3f }, - { SAA7127_REG_GAINU, 0x6a }, - { SAA7127_REG_GAINV, 0x81 }, - { SAA7127_REG_BLACK_LEVEL, 0x33 }, - { SAA7127_REG_BLANKING_LEVEL, 0x35 }, - { SAA7127_REG_VBI_BLANKING, 0x35 }, - { SAA7127_REG_DAC_CONTROL, 0x08 }, - { SAA7127_REG_BURST_AMP, 0x2f }, - { SAA7127_REG_SUBC3, 0xb2 }, - { SAA7127_REG_SUBC2, 0x3b }, - { SAA7127_REG_SUBC1, 0xa3 }, - { SAA7127_REG_SUBC0, 0x28 }, - { SAA7127_REG_MULTI, 0x90 }, - { SAA7127_REG_CLOSED_CAPTION, 0x00 }, + { SAA7127_REG_BURST_END, 0x1d }, + { SAA7127_REG_CHROMA_PHASE, 0x3f }, + { SAA7127_REG_GAINU, 0x6a }, + { SAA7127_REG_GAINV, 0x81 }, + { SAA7127_REG_BLACK_LEVEL, 0x33 }, + { SAA7127_REG_BLANKING_LEVEL, 0x35 }, + { SAA7127_REG_VBI_BLANKING, 0x35 }, + { SAA7127_REG_DAC_CONTROL, 0x08 }, + { SAA7127_REG_BURST_AMP, 0x2f }, + { SAA7127_REG_SUBC3, 0xb2 }, + { SAA7127_REG_SUBC2, 0x3b }, + { SAA7127_REG_SUBC1, 0xa3 }, + { SAA7127_REG_SUBC0, 0x28 }, + { SAA7127_REG_MULTI, 0x90 }, + { SAA7127_REG_CLOSED_CAPTION, 0x00 }, { 0, 0 } }; diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c index 102467e00fb3..668c39cc29e8 100644 --- a/drivers/media/i2c/saa717x.c +++ b/drivers/media/i2c/saa717x.c @@ -82,13 +82,13 @@ static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) /* ----------------------------------------------------------------------- */ /* for audio mode */ -#define TUNER_AUDIO_MONO 0 /* LL */ -#define TUNER_AUDIO_STEREO 1 /* LR */ -#define TUNER_AUDIO_LANG1 2 /* LL */ -#define TUNER_AUDIO_LANG2 3 /* RR */ +#define TUNER_AUDIO_MONO 0 /* LL */ +#define TUNER_AUDIO_STEREO 1 /* LR */ +#define TUNER_AUDIO_LANG1 2 /* LL */ +#define TUNER_AUDIO_LANG2 3 /* RR */ -#define SAA717X_NTSC_WIDTH (704) -#define SAA717X_NTSC_HEIGHT (480) +#define SAA717X_NTSC_WIDTH (704) +#define SAA717X_NTSC_HEIGHT (480) /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index e6b717b83b18..3b7ace395ee6 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -1791,7 +1791,7 @@ static int smiapp_set_format_source(struct v4l2_subdev *subdev, if (csi_format->compressed == old_csi_format->compressed) return 0; - valid_link_freqs = + valid_link_freqs = &sensor->valid_link_freqs[sensor->csi_format->compressed - sensor->compressed_min_bpp]; diff --git a/drivers/media/i2c/tda7432.c b/drivers/media/i2c/tda7432.c index d87168adee45..1c5c61d829d6 100644 --- a/drivers/media/i2c/tda7432.c +++ b/drivers/media/i2c/tda7432.c @@ -36,7 +36,6 @@ #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-ctrls.h> -#include <media/i2c-addr.h> #ifndef VIDEO_AUDIO_BALANCE # define VIDEO_AUDIO_BALANCE 32 diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c index 71a31352135c..8206bf7a5a8f 100644 --- a/drivers/media/i2c/ths7303.c +++ b/drivers/media/i2c/ths7303.c @@ -319,7 +319,7 @@ static const struct v4l2_subdev_core_ops ths7303_core_ops = { static const struct v4l2_subdev_ops ths7303_ops = { .core = &ths7303_core_ops, - .video = &ths7303_video_ops, + .video = &ths7303_video_ops, }; static int ths7303_probe(struct i2c_client *client, diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c index 16a1e08ce06c..772164b848ef 100644 --- a/drivers/media/i2c/tvaudio.c +++ b/drivers/media/i2c/tvaudio.c @@ -40,8 +40,6 @@ #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> -#include <media/i2c-addr.h> - /* ---------------------------------------------------------------------- */ /* insmod args */ @@ -136,7 +134,7 @@ struct CHIPSTATE { /* thread */ struct task_struct *thread; struct timer_list wt; - int audmode; + int audmode; }; static inline struct CHIPSTATE *to_state(struct v4l2_subdev *sd) diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index d575b3e7e835..8b0aa9297bde 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -1131,9 +1131,7 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id) done: if (ret < 0) { v4l2_ctrl_handler_free(&decoder->hdl); -#if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&decoder->sd.entity); -#endif } return ret; } @@ -1151,9 +1149,7 @@ static int tvp514x_remove(struct i2c_client *client) struct tvp514x_decoder *decoder = to_decoder(sd); v4l2_async_unregister_subdev(&decoder->sd); -#if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&decoder->sd.entity); -#endif v4l2_ctrl_handler_free(&decoder->hdl); return 0; } diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 7b79a7498751..3c1851984b90 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -1,9 +1,8 @@ -/* - * tvp5150 - Texas Instruments TVP5150A/AM1 and TVP5151 video decoder driver - * - * Copyright (c) 2005,2006 Mauro Carvalho Chehab (mchehab@infradead.org) - * This code is placed under the terms of the GNU General Public License v2 - */ +// SPDX-License-Identifier: GPL-2.0 +// +// tvp5150 - Texas Instruments TVP5150A/AM1 and TVP5151 video decoder driver +// +// Copyright (c) 2005,2006 Mauro Carvalho Chehab <mchehab@infradead.org> #include <dt-bindings/media/tvp5150.h> #include <linux/i2c.h> @@ -30,7 +29,7 @@ MODULE_DESCRIPTION("Texas Instruments TVP5150A/TVP5150AM1/TVP5151 video decoder driver"); MODULE_AUTHOR("Mauro Carvalho Chehab"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); static int debug; diff --git a/drivers/media/i2c/tvp5150_reg.h b/drivers/media/i2c/tvp5150_reg.h index 30a48c28d05a..c43b7b844021 100644 --- a/drivers/media/i2c/tvp5150_reg.h +++ b/drivers/media/i2c/tvp5150_reg.h @@ -1,8 +1,9 @@ /* + * SPDX-License-Identifier: GPL-2.0 + * * tvp5150 - Texas Instruments TVP5150A/AM1 video decoder registers * - * Copyright (c) 2005,2006 Mauro Carvalho Chehab (mchehab@infradead.org) - * This code is placed under the terms of the GNU General Public License v2 + * Copyright (c) 2005,2006 Mauro Carvalho Chehab <mchehab@infradead.org> */ #define TVP5150_VD_IN_SRC_SEL_1 0x00 /* Video input source selection #1 */ @@ -66,10 +67,10 @@ #define VIDEO_STD_NTSC_MJ_BIT_AS 0x01 #define VIDEO_STD_PAL_BDGHIN_BIT_AS 0x03 -#define VIDEO_STD_PAL_M_BIT_AS 0x05 +#define VIDEO_STD_PAL_M_BIT_AS 0x05 #define VIDEO_STD_PAL_COMBINATION_N_BIT_AS 0x07 #define VIDEO_STD_NTSC_4_43_BIT_AS 0x09 -#define VIDEO_STD_SECAM_BIT_AS 0x0b +#define VIDEO_STD_SECAM_BIT_AS 0x0b /* Reserved 29h-2bh */ diff --git a/drivers/media/i2c/tvp7002_reg.h b/drivers/media/i2c/tvp7002_reg.h index 933673561fa2..3c8c8b0a6a4c 100644 --- a/drivers/media/i2c/tvp7002_reg.h +++ b/drivers/media/i2c/tvp7002_reg.h @@ -109,15 +109,15 @@ #define TVP7002_L_FRAME_STAT_LSBS 0x37 #define TVP7002_L_FRAME_STAT_MSBS 0x38 #define TVP7002_CLK_L_STAT_LSBS 0x39 -#define TVP7002_CLK_L_STAT_MSBS 0x3a +#define TVP7002_CLK_L_STAT_MSBS 0x3a #define TVP7002_HSYNC_W 0x3b #define TVP7002_VSYNC_W 0x3c -#define TVP7002_L_LENGTH_TOL 0x3d +#define TVP7002_L_LENGTH_TOL 0x3d /* Reserved 0x3e */ #define TVP7002_VIDEO_BWTH_CTL 0x3f #define TVP7002_AVID_START_PIXEL_LSBS 0x40 #define TVP7002_AVID_START_PIXEL_MSBS 0x41 -#define TVP7002_AVID_STOP_PIXEL_LSBS 0x42 +#define TVP7002_AVID_STOP_PIXEL_LSBS 0x42 #define TVP7002_AVID_STOP_PIXEL_MSBS 0x43 #define TVP7002_VBLK_F_0_START_L_OFF 0x44 #define TVP7002_VBLK_F_1_START_L_OFF 0x45 diff --git a/drivers/media/i2c/vpx3220.c b/drivers/media/i2c/vpx3220.c index 67de79b2d550..c3549fa55b62 100644 --- a/drivers/media/i2c/vpx3220.c +++ b/drivers/media/i2c/vpx3220.c @@ -201,7 +201,7 @@ static const unsigned short init_pal[] = { * skipped by the VFE) */ 0x8b, 16, /* Horizontal begin */ 0x8c, 768, /* Horizontal length */ - 0x8d, 784, /* Number of pixels + 0x8d, 784, /* Number of pixels * Must be >= Horizontal begin + Horizontal length */ 0x8f, 0xc00, /* Disable window 2 */ 0xf0, 0x77, /* 13.5 MHz transport, Forced |