diff options
Diffstat (limited to 'drivers/media/i2c')
| -rw-r--r-- | drivers/media/i2c/Kconfig | 24 | ||||
| -rw-r--r-- | drivers/media/i2c/adv7511.c | 445 | ||||
| -rw-r--r-- | drivers/media/i2c/adv7604.c | 439 | ||||
| -rw-r--r-- | drivers/media/i2c/adv7842.c | 413 | ||||
| -rw-r--r-- | drivers/media/i2c/cs53l32a.c | 7 | ||||
| -rw-r--r-- | drivers/media/i2c/cx25840/cx25840-core.c | 7 | ||||
| -rw-r--r-- | drivers/media/i2c/msp3400-driver.c | 7 | ||||
| -rw-r--r-- | drivers/media/i2c/mt9t001.c | 17 | ||||
| -rw-r--r-- | drivers/media/i2c/mt9v032.c | 279 | ||||
| -rw-r--r-- | drivers/media/i2c/saa7115.c | 7 | ||||
| -rw-r--r-- | drivers/media/i2c/smiapp/smiapp-core.c | 4 | ||||
| -rw-r--r-- | drivers/media/i2c/tc358743.c | 15 | ||||
| -rw-r--r-- | drivers/media/i2c/tvaudio.c | 7 | ||||
| -rw-r--r-- | drivers/media/i2c/wm8775.c | 7 | 
14 files changed, 1357 insertions, 321 deletions
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 993dc50c12db..ce9006e10a30 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -209,6 +209,7 @@ config VIDEO_ADV7604  	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API  	depends on GPIOLIB || COMPILE_TEST  	select HDMI +	select MEDIA_CEC_EDID  	---help---  	  Support for the Analog Devices ADV7604 video decoder. @@ -218,10 +219,18 @@ config VIDEO_ADV7604  	  To compile this driver as a module, choose M here: the  	  module will be called adv7604. +config VIDEO_ADV7604_CEC +	bool "Enable Analog Devices ADV7604 CEC support" +	depends on VIDEO_ADV7604 && MEDIA_CEC +	---help--- +	  When selected the adv7604 will support the optional +	  HDMI CEC feature. +  config VIDEO_ADV7842  	tristate "Analog Devices ADV7842 decoder"  	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API  	select HDMI +	select MEDIA_CEC_EDID  	---help---  	  Support for the Analog Devices ADV7842 video decoder. @@ -231,6 +240,13 @@ config VIDEO_ADV7842  	  To compile this driver as a module, choose M here: the  	  module will be called adv7842. +config VIDEO_ADV7842_CEC +	bool "Enable Analog Devices ADV7842 CEC support" +	depends on VIDEO_ADV7842 && MEDIA_CEC +	---help--- +	  When selected the adv7842 will support the optional +	  HDMI CEC feature. +  config VIDEO_BT819  	tristate "BT819A VideoStream decoder"  	depends on VIDEO_V4L2 && I2C @@ -447,6 +463,7 @@ config VIDEO_ADV7511  	tristate "Analog Devices ADV7511 encoder"  	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API  	select HDMI +	select MEDIA_CEC_EDID  	---help---  	  Support for the Analog Devices ADV7511 video encoder. @@ -455,6 +472,13 @@ config VIDEO_ADV7511  	  To compile this driver as a module, choose M here: the  	  module will be called adv7511. +config VIDEO_ADV7511_CEC +	bool "Enable Analog Devices ADV7511 CEC support" +	depends on VIDEO_ADV7511 && MEDIA_CEC +	---help--- +	  When selected the adv7511 will support the optional +	  HDMI CEC feature. +  config VIDEO_AD9389B  	tristate "Analog Devices AD9389B encoder"  	depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c index 39271c35da48..6d7cad54a65d 100644 --- a/drivers/media/i2c/adv7511.c +++ b/drivers/media/i2c/adv7511.c @@ -33,6 +33,7 @@  #include <media/v4l2-ctrls.h>  #include <media/v4l2-dv-timings.h>  #include <media/i2c/adv7511.h> +#include <media/cec.h>  static int debug;  module_param(debug, int, 0644); @@ -59,6 +60,8 @@ MODULE_LICENSE("GPL v2");  #define ADV7511_MIN_PIXELCLOCK 20000000  #define ADV7511_MAX_PIXELCLOCK 225000000 +#define ADV7511_MAX_ADDRS (3) +  /*  **********************************************************************  * @@ -90,12 +93,20 @@ struct adv7511_state {  	struct v4l2_ctrl_handler hdl;  	int chip_revision;  	u8 i2c_edid_addr; -	u8 i2c_cec_addr;  	u8 i2c_pktmem_addr; +	u8 i2c_cec_addr; + +	struct i2c_client *i2c_cec; +	struct cec_adapter *cec_adap; +	u8   cec_addr[ADV7511_MAX_ADDRS]; +	u8   cec_valid_addrs; +	bool cec_enabled_adap; +  	/* Is the adv7511 powered on? */  	bool power_on;  	/* Did we receive hotplug and rx-sense signals? */  	bool have_monitor; +	bool enabled_irq;  	/* timings from s_dv_timings */  	struct v4l2_dv_timings dv_timings;  	u32 fmt_code; @@ -227,7 +238,7 @@ static int adv_smbus_read_i2c_block_data(struct i2c_client *client,  	return ret;  } -static inline void adv7511_edid_rd(struct v4l2_subdev *sd, u16 len, u8 *buf) +static void adv7511_edid_rd(struct v4l2_subdev *sd, uint16_t len, uint8_t *buf)  {  	struct adv7511_state *state = get_adv7511_state(sd);  	int i; @@ -242,6 +253,34 @@ static inline void adv7511_edid_rd(struct v4l2_subdev *sd, u16 len, u8 *buf)  		v4l2_err(sd, "%s: i2c read error\n", __func__);  } +static inline int adv7511_cec_read(struct v4l2_subdev *sd, u8 reg) +{ +	struct adv7511_state *state = get_adv7511_state(sd); + +	return i2c_smbus_read_byte_data(state->i2c_cec, reg); +} + +static int adv7511_cec_write(struct v4l2_subdev *sd, u8 reg, u8 val) +{ +	struct adv7511_state *state = get_adv7511_state(sd); +	int ret; +	int i; + +	for (i = 0; i < 3; i++) { +		ret = i2c_smbus_write_byte_data(state->i2c_cec, reg, val); +		if (ret == 0) +			return 0; +	} +	v4l2_err(sd, "%s: I2C Write Problem\n", __func__); +	return ret; +} + +static inline int adv7511_cec_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, +				   u8 val) +{ +	return adv7511_cec_write(sd, reg, (adv7511_cec_read(sd, reg) & mask) | val); +} +  static int adv7511_pktmem_rd(struct v4l2_subdev *sd, u8 reg)  {  	struct adv7511_state *state = get_adv7511_state(sd); @@ -343,28 +382,20 @@ static void adv7511_csc_rgb_full2limit(struct v4l2_subdev *sd, bool enable)  	}  } -static void adv7511_set_IT_content_AVI_InfoFrame(struct v4l2_subdev *sd) +static void adv7511_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2_ctrl *ctrl)  {  	struct adv7511_state *state = get_adv7511_state(sd); -	if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) { -		/* CE format, not IT  */ -		adv7511_wr_and_or(sd, 0x57, 0x7f, 0x00); -	} else { -		/* IT format */ -		adv7511_wr_and_or(sd, 0x57, 0x7f, 0x80); + +	/* Only makes sense for RGB formats */ +	if (state->fmt_code != MEDIA_BUS_FMT_RGB888_1X24) { +		/* so just keep quantization */ +		adv7511_csc_rgb_full2limit(sd, false); +		return;  	} -} -static int adv7511_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2_ctrl *ctrl) -{  	switch (ctrl->val) { -	default: -		return -EINVAL; -		break; -	case V4L2_DV_RGB_RANGE_AUTO: { +	case V4L2_DV_RGB_RANGE_AUTO:  		/* automatic */ -		struct adv7511_state *state = get_adv7511_state(sd); -  		if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) {  			/* CE format, RGB limited range (16-235) */  			adv7511_csc_rgb_full2limit(sd, true); @@ -372,7 +403,6 @@ static int adv7511_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2  			/* not CE format, RGB full range (0-255) */  			adv7511_csc_rgb_full2limit(sd, false);  		} -	}  		break;  	case V4L2_DV_RGB_RANGE_LIMITED:  		/* RGB limited range (16-235) */ @@ -383,7 +413,6 @@ static int adv7511_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2  		adv7511_csc_rgb_full2limit(sd, false);  		break;  	} -	return 0;  }  /* ------------------------------ CTRL OPS ------------------------------ */ @@ -400,8 +429,10 @@ static int adv7511_s_ctrl(struct v4l2_ctrl *ctrl)  		adv7511_wr_and_or(sd, 0xaf, 0xfd, ctrl->val == V4L2_DV_TX_MODE_HDMI ? 0x02 : 0x00);  		return 0;  	} -	if (state->rgb_quantization_range_ctrl == ctrl) -		return adv7511_set_rgb_quantization_mode(sd, ctrl); +	if (state->rgb_quantization_range_ctrl == ctrl) { +		adv7511_set_rgb_quantization_mode(sd, ctrl); +		return 0; +	}  	if (state->content_type_ctrl == ctrl) {  		u8 itc, cn; @@ -425,16 +456,28 @@ static const struct v4l2_ctrl_ops adv7511_ctrl_ops = {  #ifdef CONFIG_VIDEO_ADV_DEBUG  static void adv7511_inv_register(struct v4l2_subdev *sd)  { +	struct adv7511_state *state = get_adv7511_state(sd); +  	v4l2_info(sd, "0x000-0x0ff: Main Map\n"); +	if (state->i2c_cec) +		v4l2_info(sd, "0x100-0x1ff: CEC Map\n");  }  static int adv7511_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)  { +	struct adv7511_state *state = get_adv7511_state(sd); +  	reg->size = 1;  	switch (reg->reg >> 8) {  	case 0:  		reg->val = adv7511_rd(sd, reg->reg & 0xff);  		break; +	case 1: +		if (state->i2c_cec) { +			reg->val = adv7511_cec_read(sd, reg->reg & 0xff); +			break; +		} +		/* fall through */  	default:  		v4l2_info(sd, "Register %03llx not supported\n", reg->reg);  		adv7511_inv_register(sd); @@ -445,10 +488,18 @@ static int adv7511_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *  static int adv7511_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)  { +	struct adv7511_state *state = get_adv7511_state(sd); +  	switch (reg->reg >> 8) {  	case 0:  		adv7511_wr(sd, reg->reg & 0xff, reg->val & 0xff);  		break; +	case 1: +		if (state->i2c_cec) { +			adv7511_cec_write(sd, reg->reg & 0xff, reg->val & 0xff); +			break; +		} +		/* fall through */  	default:  		v4l2_info(sd, "Register %03llx not supported\n", reg->reg);  		adv7511_inv_register(sd); @@ -536,6 +587,7 @@ static int adv7511_log_status(struct v4l2_subdev *sd)  {  	struct adv7511_state *state = get_adv7511_state(sd);  	struct adv7511_state_edid *edid = &state->edid; +	int i;  	static const char * const states[] = {  		"in reset", @@ -605,7 +657,23 @@ static int adv7511_log_status(struct v4l2_subdev *sd)  	else  		v4l2_info(sd, "no timings set\n");  	v4l2_info(sd, "i2c edid addr: 0x%x\n", state->i2c_edid_addr); + +	if (state->i2c_cec == NULL) +		return 0; +  	v4l2_info(sd, "i2c cec addr: 0x%x\n", state->i2c_cec_addr); + +	v4l2_info(sd, "CEC: %s\n", state->cec_enabled_adap ? +			"enabled" : "disabled"); +	if (state->cec_enabled_adap) { +		for (i = 0; i < ADV7511_MAX_ADDRS; i++) { +			bool is_valid = state->cec_valid_addrs & (1 << i); + +			if (is_valid) +				v4l2_info(sd, "CEC Logical Address: 0x%x\n", +					  state->cec_addr[i]); +		} +	}  	v4l2_info(sd, "i2c pktmem addr: 0x%x\n", state->i2c_pktmem_addr);  	return 0;  } @@ -663,15 +731,197 @@ static int adv7511_s_power(struct v4l2_subdev *sd, int on)  	return true;  } +#if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC) +static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable) +{ +	struct adv7511_state *state = adap->priv; +	struct v4l2_subdev *sd = &state->sd; + +	if (state->i2c_cec == NULL) +		return -EIO; + +	if (!state->cec_enabled_adap && enable) { +		/* power up cec section */ +		adv7511_cec_write_and_or(sd, 0x4e, 0xfc, 0x01); +		/* legacy mode and clear all rx buffers */ +		adv7511_cec_write(sd, 0x4a, 0x07); +		adv7511_cec_write(sd, 0x4a, 0); +		adv7511_cec_write_and_or(sd, 0x11, 0xfe, 0); /* initially disable tx */ +		/* enabled irqs: */ +		/* tx: ready */ +		/* tx: arbitration lost */ +		/* tx: retry timeout */ +		/* rx: ready 1 */ +		if (state->enabled_irq) +			adv7511_wr_and_or(sd, 0x95, 0xc0, 0x39); +	} else if (state->cec_enabled_adap && !enable) { +		if (state->enabled_irq) +			adv7511_wr_and_or(sd, 0x95, 0xc0, 0x00); +		/* disable address mask 1-3 */ +		adv7511_cec_write_and_or(sd, 0x4b, 0x8f, 0x00); +		/* power down cec section */ +		adv7511_cec_write_and_or(sd, 0x4e, 0xfc, 0x00); +		state->cec_valid_addrs = 0; +	} +	state->cec_enabled_adap = enable; +	return 0; +} + +static int adv7511_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) +{ +	struct adv7511_state *state = adap->priv; +	struct v4l2_subdev *sd = &state->sd; +	unsigned int i, free_idx = ADV7511_MAX_ADDRS; + +	if (!state->cec_enabled_adap) +		return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO; + +	if (addr == CEC_LOG_ADDR_INVALID) { +		adv7511_cec_write_and_or(sd, 0x4b, 0x8f, 0); +		state->cec_valid_addrs = 0; +		return 0; +	} + +	for (i = 0; i < ADV7511_MAX_ADDRS; i++) { +		bool is_valid = state->cec_valid_addrs & (1 << i); + +		if (free_idx == ADV7511_MAX_ADDRS && !is_valid) +			free_idx = i; +		if (is_valid && state->cec_addr[i] == addr) +			return 0; +	} +	if (i == ADV7511_MAX_ADDRS) { +		i = free_idx; +		if (i == ADV7511_MAX_ADDRS) +			return -ENXIO; +	} +	state->cec_addr[i] = addr; +	state->cec_valid_addrs |= 1 << i; + +	switch (i) { +	case 0: +		/* enable address mask 0 */ +		adv7511_cec_write_and_or(sd, 0x4b, 0xef, 0x10); +		/* set address for mask 0 */ +		adv7511_cec_write_and_or(sd, 0x4c, 0xf0, addr); +		break; +	case 1: +		/* enable address mask 1 */ +		adv7511_cec_write_and_or(sd, 0x4b, 0xdf, 0x20); +		/* set address for mask 1 */ +		adv7511_cec_write_and_or(sd, 0x4c, 0x0f, addr << 4); +		break; +	case 2: +		/* enable address mask 2 */ +		adv7511_cec_write_and_or(sd, 0x4b, 0xbf, 0x40); +		/* set address for mask 1 */ +		adv7511_cec_write_and_or(sd, 0x4d, 0xf0, addr); +		break; +	} +	return 0; +} + +static int adv7511_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, +				     u32 signal_free_time, struct cec_msg *msg) +{ +	struct adv7511_state *state = adap->priv; +	struct v4l2_subdev *sd = &state->sd; +	u8 len = msg->len; +	unsigned int i; + +	v4l2_dbg(1, debug, sd, "%s: len %d\n", __func__, len); + +	if (len > 16) { +		v4l2_err(sd, "%s: len exceeded 16 (%d)\n", __func__, len); +		return -EINVAL; +	} + +	/* +	 * The number of retries is the number of attempts - 1, but retry +	 * at least once. It's not clear if a value of 0 is allowed, so +	 * let's do at least one retry. +	 */ +	adv7511_cec_write_and_or(sd, 0x12, ~0x70, max(1, attempts - 1) << 4); + +	/* blocking, clear cec tx irq status */ +	adv7511_wr_and_or(sd, 0x97, 0xc7, 0x38); + +	/* write data */ +	for (i = 0; i < len; i++) +		adv7511_cec_write(sd, i, msg->msg[i]); + +	/* set length (data + header) */ +	adv7511_cec_write(sd, 0x10, len); +	/* start transmit, enable tx */ +	adv7511_cec_write(sd, 0x11, 0x01); +	return 0; +} + +static void adv_cec_tx_raw_status(struct v4l2_subdev *sd, u8 tx_raw_status) +{ +	struct adv7511_state *state = get_adv7511_state(sd); + +	if ((adv7511_cec_read(sd, 0x11) & 0x01) == 0) { +		v4l2_dbg(1, debug, sd, "%s: tx raw: tx disabled\n", __func__); +		return; +	} + +	if (tx_raw_status & 0x10) { +		v4l2_dbg(1, debug, sd, +			 "%s: tx raw: arbitration lost\n", __func__); +		cec_transmit_done(state->cec_adap, CEC_TX_STATUS_ARB_LOST, +				  1, 0, 0, 0); +		return; +	} +	if (tx_raw_status & 0x08) { +		u8 status; +		u8 nack_cnt; +		u8 low_drive_cnt; + +		v4l2_dbg(1, debug, sd, "%s: tx raw: retry failed\n", __func__); +		/* +		 * We set this status bit since this hardware performs +		 * retransmissions. +		 */ +		status = CEC_TX_STATUS_MAX_RETRIES; +		nack_cnt = adv7511_cec_read(sd, 0x14) & 0xf; +		if (nack_cnt) +			status |= CEC_TX_STATUS_NACK; +		low_drive_cnt = adv7511_cec_read(sd, 0x14) >> 4; +		if (low_drive_cnt) +			status |= CEC_TX_STATUS_LOW_DRIVE; +		cec_transmit_done(state->cec_adap, status, +				  0, nack_cnt, low_drive_cnt, 0); +		return; +	} +	if (tx_raw_status & 0x20) { +		v4l2_dbg(1, debug, sd, "%s: tx raw: ready ok\n", __func__); +		cec_transmit_done(state->cec_adap, CEC_TX_STATUS_OK, 0, 0, 0, 0); +		return; +	} +} + +static const struct cec_adap_ops adv7511_cec_adap_ops = { +	.adap_enable = adv7511_cec_adap_enable, +	.adap_log_addr = adv7511_cec_adap_log_addr, +	.adap_transmit = adv7511_cec_adap_transmit, +}; +#endif +  /* Enable interrupts */  static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable)  { +	struct adv7511_state *state = get_adv7511_state(sd);  	u8 irqs = MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT;  	u8 irqs_rd;  	int retries = 100;  	v4l2_dbg(2, debug, sd, "%s: %s\n", __func__, enable ? "enable" : "disable"); +	if (state->enabled_irq == enable) +		return; +	state->enabled_irq = enable; +  	/* The datasheet says that the EDID ready interrupt should be  	   disabled if there is no hotplug. */  	if (!enable) @@ -679,6 +929,9 @@ static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable)  	else if (adv7511_have_hotplug(sd))  		irqs |= MASK_ADV7511_EDID_RDY_INT; +	adv7511_wr_and_or(sd, 0x95, 0xc0, +			  (state->cec_enabled_adap && enable) ? 0x39 : 0x00); +  	/*  	 * This i2c write can fail (approx. 1 in 1000 writes). But it  	 * is essential that this register is correct, so retry it @@ -701,20 +954,53 @@ static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable)  static int adv7511_isr(struct v4l2_subdev *sd, u32 status, bool *handled)  {  	u8 irq_status; +	u8 cec_irq;  	/* disable interrupts to prevent a race condition */  	adv7511_set_isr(sd, false);  	irq_status = adv7511_rd(sd, 0x96); +	cec_irq = adv7511_rd(sd, 0x97);  	/* clear detected interrupts */  	adv7511_wr(sd, 0x96, irq_status); +	adv7511_wr(sd, 0x97, cec_irq); -	v4l2_dbg(1, debug, sd, "%s: irq 0x%x\n", __func__, irq_status); +	v4l2_dbg(1, debug, sd, "%s: irq 0x%x, cec-irq 0x%x\n", __func__, +		 irq_status, cec_irq);  	if (irq_status & (MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT))  		adv7511_check_monitor_present_status(sd);  	if (irq_status & MASK_ADV7511_EDID_RDY_INT)  		adv7511_check_edid_status(sd); +#if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC) +	if (cec_irq & 0x38) +		adv_cec_tx_raw_status(sd, cec_irq); + +	if (cec_irq & 1) { +		struct adv7511_state *state = get_adv7511_state(sd); +		struct cec_msg msg; + +		msg.len = adv7511_cec_read(sd, 0x25) & 0x1f; + +		v4l2_dbg(1, debug, sd, "%s: cec msg len %d\n", __func__, +			 msg.len); + +		if (msg.len > 16) +			msg.len = 16; + +		if (msg.len) { +			u8 i; + +			for (i = 0; i < msg.len; i++) +				msg.msg[i] = adv7511_cec_read(sd, i + 0x15); + +			adv7511_cec_write(sd, 0x4a, 1); /* toggle to re-enable rx 1 */ +			adv7511_cec_write(sd, 0x4a, 0); +			cec_received_msg(state->cec_adap, &msg); +		} +	} +#endif +  	/* enable interrupts */  	adv7511_set_isr(sd, true); @@ -771,12 +1057,14 @@ static int adv7511_s_dv_timings(struct v4l2_subdev *sd,  	/* save timings */  	state->dv_timings = *timings; +	/* set h/vsync polarities */ +	adv7511_wr_and_or(sd, 0x17, 0x9f, +		((timings->bt.polarities & V4L2_DV_VSYNC_POS_POL) ? 0 : 0x40) | +		((timings->bt.polarities & V4L2_DV_HSYNC_POS_POL) ? 0 : 0x20)); +  	/* update quantization range based on new dv_timings */  	adv7511_set_rgb_quantization_mode(sd, state->rgb_quantization_range_ctrl); -	/* update AVI infoframe */ -	adv7511_set_IT_content_AVI_InfoFrame(sd); -  	return 0;  } @@ -956,8 +1244,6 @@ static int adv7511_enum_mbus_code(struct v4l2_subdev *sd,  static void adv7511_fill_format(struct adv7511_state *state,  				struct v4l2_mbus_framefmt *format)  { -	memset(format, 0, sizeof(*format)); -  	format->width = state->dv_timings.bt.width;  	format->height = state->dv_timings.bt.height;  	format->field = V4L2_FIELD_NONE; @@ -972,6 +1258,7 @@ static int adv7511_get_fmt(struct v4l2_subdev *sd,  	if (format->pad != 0)  		return -EINVAL; +	memset(&format->format, 0, sizeof(format->format));  	adv7511_fill_format(state, &format->format);  	if (format->which == V4L2_SUBDEV_FORMAT_TRY) { @@ -1132,6 +1419,7 @@ static int adv7511_set_fmt(struct v4l2_subdev *sd,  	adv7511_wr_and_or(sd, 0x57, 0x83, (ec << 4) | (q << 2) | (itc << 7));  	adv7511_wr_and_or(sd, 0x59, 0x0f, (yq << 6) | (cn << 4));  	adv7511_wr_and_or(sd, 0x4a, 0xff, 1); +	adv7511_set_rgb_quantization_mode(sd, state->rgb_quantization_range_ctrl);  	return 0;  } @@ -1183,6 +1471,8 @@ static void adv7511_notify_no_edid(struct v4l2_subdev *sd)  	/* We failed to read the EDID, so send an event for this. */  	ed.present = false;  	ed.segment = adv7511_rd(sd, 0xc4); +	ed.phys_addr = CEC_PHYS_ADDR_INVALID; +	cec_s_phys_addr(state->cec_adap, ed.phys_addr, false);  	v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed);  	v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, 0x0);  } @@ -1406,13 +1696,16 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd)  		v4l2_dbg(1, debug, sd, "%s: edid complete with %d segment(s)\n", __func__, state->edid.segments);  		state->edid.complete = true; - +		ed.phys_addr = cec_get_edid_phys_addr(state->edid.data, +						      state->edid.segments * 256, +						      NULL);  		/* report when we have all segments  		   but report only for segment 0  		 */  		ed.present = true;  		ed.segment = 0;  		state->edid_detect_counter++; +		cec_s_phys_addr(state->cec_adap, ed.phys_addr, false);  		v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed);  		return ed.present;  	} @@ -1420,17 +1713,43 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd)  	return false;  } +static int adv7511_registered(struct v4l2_subdev *sd) +{ +	struct adv7511_state *state = get_adv7511_state(sd); +	int err; + +	err = cec_register_adapter(state->cec_adap); +	if (err) +		cec_delete_adapter(state->cec_adap); +	return err; +} + +static void adv7511_unregistered(struct v4l2_subdev *sd) +{ +	struct adv7511_state *state = get_adv7511_state(sd); + +	cec_unregister_adapter(state->cec_adap); +} + +static const struct v4l2_subdev_internal_ops adv7511_int_ops = { +	.registered = adv7511_registered, +	.unregistered = adv7511_unregistered, +}; +  /* ----------------------------------------------------------------------- */  /* Setup ADV7511 */  static void adv7511_init_setup(struct v4l2_subdev *sd)  {  	struct adv7511_state *state = get_adv7511_state(sd);  	struct adv7511_state_edid *edid = &state->edid; +	u32 cec_clk = state->pdata.cec_clk; +	u8 ratio;  	v4l2_dbg(1, debug, sd, "%s\n", __func__);  	/* clear all interrupts */  	adv7511_wr(sd, 0x96, 0xff); +	adv7511_wr(sd, 0x97, 0xff);  	/*  	 * Stop HPD from resetting a lot of registers.  	 * It might leave the chip in a partly un-initialized state, @@ -1442,6 +1761,25 @@ static void adv7511_init_setup(struct v4l2_subdev *sd)  	adv7511_set_isr(sd, false);  	adv7511_s_stream(sd, false);  	adv7511_s_audio_stream(sd, false); + +	if (state->i2c_cec == NULL) +		return; + +	v4l2_dbg(1, debug, sd, "%s: cec_clk %d\n", __func__, cec_clk); + +	/* cec soft reset */ +	adv7511_cec_write(sd, 0x50, 0x01); +	adv7511_cec_write(sd, 0x50, 0x00); + +	/* legacy mode */ +	adv7511_cec_write(sd, 0x4a, 0x00); + +	if (cec_clk % 750000 != 0) +		v4l2_err(sd, "%s: cec_clk %d, not multiple of 750 Khz\n", +			 __func__, cec_clk); + +	ratio = (cec_clk / 750000) - 1; +	adv7511_cec_write(sd, 0x4e, ratio << 2);  }  static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *id) @@ -1476,6 +1814,7 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *  			 client->addr << 1);  	v4l2_i2c_subdev_init(sd, client, &adv7511_ops); +	sd->internal_ops = &adv7511_int_ops;  	hdl = &state->hdl;  	v4l2_ctrl_handler_init(hdl, 10); @@ -1516,26 +1855,47 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *  	chip_id[0] = adv7511_rd(sd, 0xf5);  	chip_id[1] = adv7511_rd(sd, 0xf6);  	if (chip_id[0] != 0x75 || chip_id[1] != 0x11) { -		v4l2_err(sd, "chip_id != 0x7511, read 0x%02x%02x\n", chip_id[0], chip_id[1]); +		v4l2_err(sd, "chip_id != 0x7511, read 0x%02x%02x\n", chip_id[0], +			 chip_id[1]);  		err = -EIO;  		goto err_entity;  	} -	state->i2c_edid = i2c_new_dummy(client->adapter, state->i2c_edid_addr >> 1); +	state->i2c_edid = i2c_new_dummy(client->adapter, +					state->i2c_edid_addr >> 1);  	if (state->i2c_edid == NULL) {  		v4l2_err(sd, "failed to register edid i2c client\n");  		err = -ENOMEM;  		goto err_entity;  	} +	adv7511_wr(sd, 0xe1, state->i2c_cec_addr); +	if (state->pdata.cec_clk < 3000000 || +	    state->pdata.cec_clk > 100000000) { +		v4l2_err(sd, "%s: cec_clk %u outside range, disabling cec\n", +				__func__, state->pdata.cec_clk); +		state->pdata.cec_clk = 0; +	} + +	if (state->pdata.cec_clk) { +		state->i2c_cec = i2c_new_dummy(client->adapter, +					       state->i2c_cec_addr >> 1); +		if (state->i2c_cec == NULL) { +			v4l2_err(sd, "failed to register cec i2c client\n"); +			goto err_unreg_edid; +		} +		adv7511_wr(sd, 0xe2, 0x00); /* power up cec section */ +	} else { +		adv7511_wr(sd, 0xe2, 0x01); /* power down cec section */ +	} +  	state->i2c_pktmem = i2c_new_dummy(client->adapter, state->i2c_pktmem_addr >> 1);  	if (state->i2c_pktmem == NULL) {  		v4l2_err(sd, "failed to register pktmem i2c client\n");  		err = -ENOMEM; -		goto err_unreg_edid; +		goto err_unreg_cec;  	} -	adv7511_wr(sd, 0xe2, 0x01); /* power down cec section */  	state->work_queue = create_singlethread_workqueue(sd->name);  	if (state->work_queue == NULL) {  		v4l2_err(sd, "could not create workqueue\n"); @@ -1546,6 +1906,19 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *  	INIT_DELAYED_WORK(&state->edid_handler, adv7511_edid_handler);  	adv7511_init_setup(sd); + +#if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC) +	state->cec_adap = cec_allocate_adapter(&adv7511_cec_adap_ops, +		state, dev_name(&client->dev), CEC_CAP_TRANSMIT | +		CEC_CAP_LOG_ADDRS | CEC_CAP_PASSTHROUGH | CEC_CAP_RC, +		ADV7511_MAX_ADDRS, &client->dev); +	err = PTR_ERR_OR_ZERO(state->cec_adap); +	if (err) { +		destroy_workqueue(state->work_queue); +		goto err_unreg_pktmem; +	} +#endif +  	adv7511_set_isr(sd, true);  	adv7511_check_monitor_present_status(sd); @@ -1555,6 +1928,9 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *  err_unreg_pktmem:  	i2c_unregister_device(state->i2c_pktmem); +err_unreg_cec: +	if (state->i2c_cec) +		i2c_unregister_device(state->i2c_cec);  err_unreg_edid:  	i2c_unregister_device(state->i2c_edid);  err_entity: @@ -1576,9 +1952,12 @@ static int adv7511_remove(struct i2c_client *client)  	v4l2_dbg(1, debug, sd, "%s removed @ 0x%x (%s)\n", client->name,  		 client->addr << 1, client->adapter->name); +	adv7511_set_isr(sd, false);  	adv7511_init_setup(sd);  	cancel_delayed_work(&state->edid_handler);  	i2c_unregister_device(state->i2c_edid); +	if (state->i2c_cec) +		i2c_unregister_device(state->i2c_cec);  	i2c_unregister_device(state->i2c_pktmem);  	destroy_workqueue(state->work_queue);  	v4l2_device_unregister_subdev(sd); diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index beb2841ceae5..4003831de712 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -40,6 +40,7 @@  #include <linux/regmap.h>  #include <media/i2c/adv7604.h> +#include <media/cec.h>  #include <media/v4l2-ctrls.h>  #include <media/v4l2-device.h>  #include <media/v4l2-event.h> @@ -80,6 +81,8 @@ MODULE_LICENSE("GPL");  #define ADV76XX_OP_SWAP_CB_CR				(1 << 0) +#define ADV76XX_MAX_ADDRS (3) +  enum adv76xx_type {  	ADV7604,  	ADV7611, @@ -164,6 +167,7 @@ struct adv76xx_state {  	struct adv76xx_platform_data pdata;  	struct gpio_desc *hpd_gpio[4]; +	struct gpio_desc *reset_gpio;  	struct v4l2_subdev sd;  	struct media_pad pads[ADV76XX_PAD_MAX]; @@ -184,10 +188,15 @@ struct adv76xx_state {  	u16 spa_port_a[2];  	struct v4l2_fract aspect_ratio;  	u32 rgb_quantization_range; -	struct workqueue_struct *work_queues;  	struct delayed_work delayed_work_enable_hotplug;  	bool restart_stdi_once; +	/* CEC */ +	struct cec_adapter *cec_adap; +	u8   cec_addr[ADV76XX_MAX_ADDRS]; +	u8   cec_valid_addrs; +	bool cec_enabled_adap; +  	/* i2c clients */  	struct i2c_client *i2c_clients[ADV76XX_PAGE_MAX]; @@ -381,7 +390,8 @@ static inline int io_write(struct v4l2_subdev *sd, u8 reg, u8 val)  	return regmap_write(state->regmap[ADV76XX_PAGE_IO], reg, val);  } -static inline int io_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) +static inline int io_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, +				   u8 val)  {  	return io_write(sd, reg, (io_read(sd, reg) & ~mask) | val);  } @@ -414,6 +424,12 @@ static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val)  	return regmap_write(state->regmap[ADV76XX_PAGE_CEC], reg, val);  } +static inline int cec_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, +				   u8 val) +{ +	return cec_write(sd, reg, (cec_read(sd, reg) & ~mask) | val); +} +  static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg)  {  	struct adv76xx_state *state = to_state(sd); @@ -779,11 +795,31 @@ static const struct v4l2_dv_timings_cap adv76xx_timings_cap_digital = {  			V4L2_DV_BT_CAP_CUSTOM)  }; -static inline const struct v4l2_dv_timings_cap * -adv76xx_get_dv_timings_cap(struct v4l2_subdev *sd) +/* + * Return the DV timings capabilities for the requested sink pad. As a special + * case, pad value -1 returns the capabilities for the currently selected input. + */ +static const struct v4l2_dv_timings_cap * +adv76xx_get_dv_timings_cap(struct v4l2_subdev *sd, int pad)  { -	return is_digital_input(sd) ? &adv76xx_timings_cap_digital : -				      &adv7604_timings_cap_analog; +	if (pad == -1) { +		struct adv76xx_state *state = to_state(sd); + +		pad = state->selected_input; +	} + +	switch (pad) { +	case ADV76XX_PAD_HDMI_PORT_A: +	case ADV7604_PAD_HDMI_PORT_B: +	case ADV7604_PAD_HDMI_PORT_C: +	case ADV7604_PAD_HDMI_PORT_D: +		return &adv76xx_timings_cap_digital; + +	case ADV7604_PAD_VGA_RGB: +	case ADV7604_PAD_VGA_COMP: +	default: +		return &adv7604_timings_cap_analog; +	}  } @@ -872,9 +908,9 @@ static int adv76xx_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd)  {  	struct adv76xx_state *state = to_state(sd);  	const struct adv76xx_chip_info *info = state->info; +	u16 cable_det = info->read_cable_det(sd); -	return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, -				info->read_cable_det(sd)); +	return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, cable_det);  }  static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, @@ -1066,6 +1102,10 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)  	struct adv76xx_state *state = to_state(sd);  	bool rgb_output = io_read(sd, 0x02) & 0x02;  	bool hdmi_signal = hdmi_read(sd, 0x05) & 0x80; +	u8 y = HDMI_COLORSPACE_RGB; + +	if (hdmi_signal && (io_read(sd, 0x60) & 1)) +		y = infoframe_read(sd, 0x01) >> 5;  	v4l2_dbg(2, debug, sd, "%s: RGB quantization range: %d, RGB out: %d, HDMI: %d\n",  			__func__, state->rgb_quantization_range, @@ -1073,6 +1113,7 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)  	adv76xx_set_gain(sd, true, 0x0, 0x0, 0x0);  	adv76xx_set_offset(sd, true, 0x0, 0x0, 0x0); +	io_write_clr_set(sd, 0x02, 0x04, rgb_output ? 0 : 4);  	switch (state->rgb_quantization_range) {  	case V4L2_DV_RGB_RANGE_AUTO: @@ -1122,6 +1163,9 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)  			break;  		} +		if (y != HDMI_COLORSPACE_RGB) +			break; +  		/* RGB limited range (16-235) */  		io_write_clr_set(sd, 0x02, 0xf0, 0x00); @@ -1133,6 +1177,9 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)  			break;  		} +		if (y != HDMI_COLORSPACE_RGB) +			break; +  		/* RGB full range (0-255) */  		io_write_clr_set(sd, 0x02, 0xf0, 0x10); @@ -1329,7 +1376,7 @@ static int stdi2dv_timings(struct v4l2_subdev *sd,  		const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[i].bt;  		if (!v4l2_valid_dv_timings(&v4l2_dv_timings_presets[i], -					   adv76xx_get_dv_timings_cap(sd), +					   adv76xx_get_dv_timings_cap(sd, -1),  					   adv76xx_check_dv_timings, NULL))  			continue;  		if (vtotal(bt) != stdi->lcf + 1) @@ -1430,18 +1477,22 @@ static int adv76xx_enum_dv_timings(struct v4l2_subdev *sd,  		return -EINVAL;  	return v4l2_enum_dv_timings_cap(timings, -		adv76xx_get_dv_timings_cap(sd), adv76xx_check_dv_timings, NULL); +		adv76xx_get_dv_timings_cap(sd, timings->pad), +		adv76xx_check_dv_timings, NULL);  }  static int adv76xx_dv_timings_cap(struct v4l2_subdev *sd,  			struct v4l2_dv_timings_cap *cap)  {  	struct adv76xx_state *state = to_state(sd); +	unsigned int pad = cap->pad;  	if (cap->pad >= state->source_pad)  		return -EINVAL; -	*cap = *adv76xx_get_dv_timings_cap(sd); +	*cap = *adv76xx_get_dv_timings_cap(sd, pad); +	cap->pad = pad; +  	return 0;  } @@ -1450,9 +1501,9 @@ static int adv76xx_dv_timings_cap(struct v4l2_subdev *sd,  static void adv76xx_fill_optional_dv_timings_fields(struct v4l2_subdev *sd,  		struct v4l2_dv_timings *timings)  { -	v4l2_find_dv_timings_cap(timings, adv76xx_get_dv_timings_cap(sd), -			is_digital_input(sd) ? 250000 : 1000000, -			adv76xx_check_dv_timings, NULL); +	v4l2_find_dv_timings_cap(timings, adv76xx_get_dv_timings_cap(sd, -1), +				 is_digital_input(sd) ? 250000 : 1000000, +				 adv76xx_check_dv_timings, NULL);  }  static unsigned int adv7604_read_hdmi_pixelclock(struct v4l2_subdev *sd) @@ -1620,7 +1671,7 @@ static int adv76xx_s_dv_timings(struct v4l2_subdev *sd,  	bt = &timings->bt; -	if (!v4l2_valid_dv_timings(timings, adv76xx_get_dv_timings_cap(sd), +	if (!v4l2_valid_dv_timings(timings, adv76xx_get_dv_timings_cap(sd, -1),  				   adv76xx_check_dv_timings, NULL))  		return -ERANGE; @@ -1825,6 +1876,7 @@ static void adv76xx_setup_format(struct adv76xx_state *state)  	io_write_clr_set(sd, 0x04, 0xe0, adv76xx_op_ch_sel(state));  	io_write_clr_set(sd, 0x05, 0x01,  			state->format->swap_cb_cr ? ADV76XX_OP_SWAP_CB_CR : 0); +	set_rgb_quantization_range(sd);  }  static int adv76xx_get_format(struct v4l2_subdev *sd, @@ -1900,6 +1952,210 @@ static int adv76xx_set_format(struct v4l2_subdev *sd,  	return 0;  } +#if IS_ENABLED(CONFIG_VIDEO_ADV7604_CEC) +static void adv76xx_cec_tx_raw_status(struct v4l2_subdev *sd, u8 tx_raw_status) +{ +	struct adv76xx_state *state = to_state(sd); + +	if ((cec_read(sd, 0x11) & 0x01) == 0) { +		v4l2_dbg(1, debug, sd, "%s: tx raw: tx disabled\n", __func__); +		return; +	} + +	if (tx_raw_status & 0x02) { +		v4l2_dbg(1, debug, sd, "%s: tx raw: arbitration lost\n", +			 __func__); +		cec_transmit_done(state->cec_adap, CEC_TX_STATUS_ARB_LOST, +				  1, 0, 0, 0); +	} +	if (tx_raw_status & 0x04) { +		u8 status; +		u8 nack_cnt; +		u8 low_drive_cnt; + +		v4l2_dbg(1, debug, sd, "%s: tx raw: retry failed\n", __func__); +		/* +		 * We set this status bit since this hardware performs +		 * retransmissions. +		 */ +		status = CEC_TX_STATUS_MAX_RETRIES; +		nack_cnt = cec_read(sd, 0x14) & 0xf; +		if (nack_cnt) +			status |= CEC_TX_STATUS_NACK; +		low_drive_cnt = cec_read(sd, 0x14) >> 4; +		if (low_drive_cnt) +			status |= CEC_TX_STATUS_LOW_DRIVE; +		cec_transmit_done(state->cec_adap, status, +				  0, nack_cnt, low_drive_cnt, 0); +		return; +	} +	if (tx_raw_status & 0x01) { +		v4l2_dbg(1, debug, sd, "%s: tx raw: ready ok\n", __func__); +		cec_transmit_done(state->cec_adap, CEC_TX_STATUS_OK, 0, 0, 0, 0); +		return; +	} +} + +static void adv76xx_cec_isr(struct v4l2_subdev *sd, bool *handled) +{ +	struct adv76xx_state *state = to_state(sd); +	u8 cec_irq; + +	/* cec controller */ +	cec_irq = io_read(sd, 0x4d) & 0x0f; +	if (!cec_irq) +		return; + +	v4l2_dbg(1, debug, sd, "%s: cec: irq 0x%x\n", __func__, cec_irq); +	adv76xx_cec_tx_raw_status(sd, cec_irq); +	if (cec_irq & 0x08) { +		struct cec_msg msg; + +		msg.len = cec_read(sd, 0x25) & 0x1f; +		if (msg.len > 16) +			msg.len = 16; + +		if (msg.len) { +			u8 i; + +			for (i = 0; i < msg.len; i++) +				msg.msg[i] = cec_read(sd, i + 0x15); +			cec_write(sd, 0x26, 0x01); /* re-enable rx */ +			cec_received_msg(state->cec_adap, &msg); +		} +	} + +	/* note: the bit order is swapped between 0x4d and 0x4e */ +	cec_irq = ((cec_irq & 0x08) >> 3) | ((cec_irq & 0x04) >> 1) | +		  ((cec_irq & 0x02) << 1) | ((cec_irq & 0x01) << 3); +	io_write(sd, 0x4e, cec_irq); + +	if (handled) +		*handled = true; +} + +static int adv76xx_cec_adap_enable(struct cec_adapter *adap, bool enable) +{ +	struct adv76xx_state *state = adap->priv; +	struct v4l2_subdev *sd = &state->sd; + +	if (!state->cec_enabled_adap && enable) { +		cec_write_clr_set(sd, 0x2a, 0x01, 0x01); /* power up cec */ +		cec_write(sd, 0x2c, 0x01);	/* cec soft reset */ +		cec_write_clr_set(sd, 0x11, 0x01, 0); /* initially disable tx */ +		/* enabled irqs: */ +		/* tx: ready */ +		/* tx: arbitration lost */ +		/* tx: retry timeout */ +		/* rx: ready */ +		io_write_clr_set(sd, 0x50, 0x0f, 0x0f); +		cec_write(sd, 0x26, 0x01);            /* enable rx */ +	} else if (state->cec_enabled_adap && !enable) { +		/* disable cec interrupts */ +		io_write_clr_set(sd, 0x50, 0x0f, 0x00); +		/* disable address mask 1-3 */ +		cec_write_clr_set(sd, 0x27, 0x70, 0x00); +		/* power down cec section */ +		cec_write_clr_set(sd, 0x2a, 0x01, 0x00); +		state->cec_valid_addrs = 0; +	} +	state->cec_enabled_adap = enable; +	adv76xx_s_detect_tx_5v_ctrl(sd); +	return 0; +} + +static int adv76xx_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) +{ +	struct adv76xx_state *state = adap->priv; +	struct v4l2_subdev *sd = &state->sd; +	unsigned int i, free_idx = ADV76XX_MAX_ADDRS; + +	if (!state->cec_enabled_adap) +		return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO; + +	if (addr == CEC_LOG_ADDR_INVALID) { +		cec_write_clr_set(sd, 0x27, 0x70, 0); +		state->cec_valid_addrs = 0; +		return 0; +	} + +	for (i = 0; i < ADV76XX_MAX_ADDRS; i++) { +		bool is_valid = state->cec_valid_addrs & (1 << i); + +		if (free_idx == ADV76XX_MAX_ADDRS && !is_valid) +			free_idx = i; +		if (is_valid && state->cec_addr[i] == addr) +			return 0; +	} +	if (i == ADV76XX_MAX_ADDRS) { +		i = free_idx; +		if (i == ADV76XX_MAX_ADDRS) +			return -ENXIO; +	} +	state->cec_addr[i] = addr; +	state->cec_valid_addrs |= 1 << i; + +	switch (i) { +	case 0: +		/* enable address mask 0 */ +		cec_write_clr_set(sd, 0x27, 0x10, 0x10); +		/* set address for mask 0 */ +		cec_write_clr_set(sd, 0x28, 0x0f, addr); +		break; +	case 1: +		/* enable address mask 1 */ +		cec_write_clr_set(sd, 0x27, 0x20, 0x20); +		/* set address for mask 1 */ +		cec_write_clr_set(sd, 0x28, 0xf0, addr << 4); +		break; +	case 2: +		/* enable address mask 2 */ +		cec_write_clr_set(sd, 0x27, 0x40, 0x40); +		/* set address for mask 1 */ +		cec_write_clr_set(sd, 0x29, 0x0f, addr); +		break; +	} +	return 0; +} + +static int adv76xx_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, +				     u32 signal_free_time, struct cec_msg *msg) +{ +	struct adv76xx_state *state = adap->priv; +	struct v4l2_subdev *sd = &state->sd; +	u8 len = msg->len; +	unsigned int i; + +	/* +	 * The number of retries is the number of attempts - 1, but retry +	 * at least once. It's not clear if a value of 0 is allowed, so +	 * let's do at least one retry. +	 */ +	cec_write_clr_set(sd, 0x12, 0x70, max(1, attempts - 1) << 4); + +	if (len > 16) { +		v4l2_err(sd, "%s: len exceeded 16 (%d)\n", __func__, len); +		return -EINVAL; +	} + +	/* write data */ +	for (i = 0; i < len; i++) +		cec_write(sd, i, msg->msg[i]); + +	/* set length (data + header) */ +	cec_write(sd, 0x10, len); +	/* start transmit, enable tx */ +	cec_write(sd, 0x11, 0x01); +	return 0; +} + +static const struct cec_adap_ops adv76xx_cec_adap_ops = { +	.adap_enable = adv76xx_cec_adap_enable, +	.adap_log_addr = adv76xx_cec_adap_log_addr, +	.adap_transmit = adv76xx_cec_adap_transmit, +}; +#endif +  static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled)  {  	struct adv76xx_state *state = to_state(sd); @@ -1945,6 +2201,11 @@ static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled)  			*handled = true;  	} +#if IS_ENABLED(CONFIG_VIDEO_ADV7604_CEC) +	/* cec */ +	adv76xx_cec_isr(sd, handled); +#endif +  	/* tx 5v detect */  	tx_5v = irq_reg_0x70 & info->cable_det_mask;  	if (tx_5v) { @@ -1994,39 +2255,12 @@ static int adv76xx_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)  	return 0;  } -static int get_edid_spa_location(const u8 *edid) -{ -	u8 d; - -	if ((edid[0x7e] != 1) || -	    (edid[0x80] != 0x02) || -	    (edid[0x81] != 0x03)) { -		return -1; -	} - -	/* search Vendor Specific Data Block (tag 3) */ -	d = edid[0x82] & 0x7f; -	if (d > 4) { -		int i = 0x84; -		int end = 0x80 + d; - -		do { -			u8 tag = edid[i] >> 5; -			u8 len = edid[i] & 0x1f; - -			if ((tag == 3) && (len >= 5)) -				return i + 4; -			i += len + 1; -		} while (i < end); -	} -	return -1; -} -  static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)  {  	struct adv76xx_state *state = to_state(sd);  	const struct adv76xx_chip_info *info = state->info; -	int spa_loc; +	unsigned int spa_loc; +	u16 pa;  	int err;  	int i; @@ -2057,6 +2291,10 @@ static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)  		edid->blocks = 2;  		return -E2BIG;  	} +	pa = cec_get_edid_phys_addr(edid->edid, edid->blocks * 128, &spa_loc); +	err = cec_phys_addr_validate(pa, &pa, NULL); +	if (err) +		return err;  	v4l2_dbg(2, debug, sd, "%s: write EDID pad %d, edid.present = 0x%x\n",  			__func__, edid->pad, state->edid.present); @@ -2066,9 +2304,12 @@ static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)  	adv76xx_set_hpd(state, 0);  	rep_write_clr_set(sd, info->edid_enable_reg, 0x0f, 0x00); -	spa_loc = get_edid_spa_location(edid->edid); -	if (spa_loc < 0) -		spa_loc = 0xc0; /* Default value [REF_02, p. 116] */ +	/* +	 * Return an error if no location of the source physical address +	 * was found. +	 */ +	if (spa_loc == 0) +		return -EINVAL;  	switch (edid->pad) {  	case ADV76XX_PAD_HDMI_PORT_A: @@ -2128,10 +2369,10 @@ static int adv76xx_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)  		v4l2_err(sd, "error enabling edid (0x%x)\n", state->edid.present);  		return -EIO;  	} +	cec_s_phys_addr(state->cec_adap, pa, false);  	/* enable hotplug after 100 ms */ -	queue_delayed_work(state->work_queues, -			&state->delayed_work_enable_hotplug, HZ / 10); +	schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 10);  	return 0;  } @@ -2252,8 +2493,19 @@ static int adv76xx_log_status(struct v4l2_subdev *sd)  			((edid_enabled & 0x02) ? "Yes" : "No"),  			((edid_enabled & 0x04) ? "Yes" : "No"),  			((edid_enabled & 0x08) ? "Yes" : "No")); -	v4l2_info(sd, "CEC: %s\n", !!(cec_read(sd, 0x2a) & 0x01) ? +	v4l2_info(sd, "CEC: %s\n", state->cec_enabled_adap ?  			"enabled" : "disabled"); +	if (state->cec_enabled_adap) { +		int i; + +		for (i = 0; i < ADV76XX_MAX_ADDRS; i++) { +			bool is_valid = state->cec_valid_addrs & (1 << i); + +			if (is_valid) +				v4l2_info(sd, "CEC Logical Address: 0x%x\n", +					  state->cec_addr[i]); +		} +	}  	v4l2_info(sd, "-----Signal status-----\n");  	cable_det = info->read_cable_det(sd); @@ -2299,11 +2551,10 @@ static int adv76xx_log_status(struct v4l2_subdev *sd)  			rgb_quantization_range_txt[state->rgb_quantization_range]);  	v4l2_info(sd, "Input color space: %s\n",  			input_color_space_txt[reg_io_0x02 >> 4]); -	v4l2_info(sd, "Output color space: %s %s, saturator %s, alt-gamma %s\n", +	v4l2_info(sd, "Output color space: %s %s, alt-gamma %s\n",  			(reg_io_0x02 & 0x02) ? "RGB" : "YCbCr", -			(reg_io_0x02 & 0x04) ? "(16-235)" : "(0-255)",  			(((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ? -				"enabled" : "disabled", +				"(16-235)" : "(0-255)",  			(reg_io_0x02 & 0x08) ? "enabled" : "disabled");  	v4l2_info(sd, "Color space conversion: %s\n",  			csc_coeff_sel_rb[cp_read(sd, info->cp_csc) >> 4]); @@ -2363,6 +2614,24 @@ static int adv76xx_subscribe_event(struct v4l2_subdev *sd,  	}  } +static int adv76xx_registered(struct v4l2_subdev *sd) +{ +	struct adv76xx_state *state = to_state(sd); +	int err; + +	err = cec_register_adapter(state->cec_adap); +	if (err) +		cec_delete_adapter(state->cec_adap); +	return err; +} + +static void adv76xx_unregistered(struct v4l2_subdev *sd) +{ +	struct adv76xx_state *state = to_state(sd); + +	cec_unregister_adapter(state->cec_adap); +} +  /* ----------------------------------------------------------------------- */  static const struct v4l2_ctrl_ops adv76xx_ctrl_ops = { @@ -2406,6 +2675,11 @@ static const struct v4l2_subdev_ops adv76xx_ops = {  	.pad = &adv76xx_pad_ops,  }; +static const struct v4l2_subdev_internal_ops adv76xx_int_ops = { +	.registered = adv76xx_registered, +	.unregistered = adv76xx_unregistered, +}; +  /* -------------------------- custom ctrls ---------------------------------- */  static const struct v4l2_ctrl_config adv7604_ctrl_analog_sampling_phase = { @@ -2468,10 +2742,7 @@ static int adv76xx_core_init(struct v4l2_subdev *sd)  	cp_write(sd, 0xcf, 0x01);   /* Power down macrovision */  	/* video format */ -	io_write_clr_set(sd, 0x02, 0x0f, -			pdata->alt_gamma << 3 | -			pdata->op_656_range << 2 | -			pdata->alt_data_sat << 0); +	io_write_clr_set(sd, 0x02, 0x0f, pdata->alt_gamma << 3);  	io_write_clr_set(sd, 0x05, 0x0e, pdata->blank_data << 3 |  			pdata->insert_av_codes << 2 |  			pdata->replicate_av_codes << 1); @@ -2821,10 +3092,8 @@ static int adv76xx_parse_dt(struct adv76xx_state *state)  	if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)  		state->pdata.inv_llc_pol = 1; -	if (bus_cfg.bus_type == V4L2_MBUS_BT656) { +	if (bus_cfg.bus_type == V4L2_MBUS_BT656)  		state->pdata.insert_av_codes = 1; -		state->pdata.op_656_range = 1; -	}  	/* Disable the interrupt for now as no DT-based board uses it. */  	state->pdata.int1_config = ADV76XX_INT1_CONFIG_DISABLED; @@ -2847,7 +3116,6 @@ static int adv76xx_parse_dt(struct adv76xx_state *state)  	state->pdata.disable_pwrdnb = 0;  	state->pdata.disable_cable_det_rst = 0;  	state->pdata.blank_data = 1; -	state->pdata.alt_data_sat = 1;  	state->pdata.op_format_mode_sel = ADV7604_OP_FORMAT_MODE0;  	state->pdata.bus_order = ADV7604_BUS_ORDER_RGB; @@ -2996,6 +3264,19 @@ static int configure_regmaps(struct adv76xx_state *state)  	return 0;  } +static void adv76xx_reset(struct adv76xx_state *state) +{ +	if (state->reset_gpio) { +		/* ADV76XX can be reset by a low reset pulse of minimum 5 ms. */ +		gpiod_set_value_cansleep(state->reset_gpio, 0); +		usleep_range(5000, 10000); +		gpiod_set_value_cansleep(state->reset_gpio, 1); +		/* It is recommended to wait 5 ms after the low pulse before */ +		/* an I2C write is performed to the ADV76XX. */ +		usleep_range(5000, 10000); +	} +} +  static int adv76xx_probe(struct i2c_client *client,  			 const struct i2c_device_id *id)  { @@ -3059,6 +3340,12 @@ static int adv76xx_probe(struct i2c_client *client,  		if (state->hpd_gpio[i])  			v4l_info(client, "Handling HPD %u GPIO\n", i);  	} +	state->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", +								GPIOD_OUT_HIGH); +	if (IS_ERR(state->reset_gpio)) +		return PTR_ERR(state->reset_gpio); + +	adv76xx_reset(state);  	state->timings = cea640x480;  	state->format = adv76xx_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8); @@ -3069,6 +3356,7 @@ static int adv76xx_probe(struct i2c_client *client,  		id->name, i2c_adapter_id(client->adapter),  		client->addr);  	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; +	sd->internal_ops = &adv76xx_int_ops;  	/* Configure IO Regmap region */  	err = configure_regmap(state, ADV76XX_PAGE_IO); @@ -3182,14 +3470,6 @@ static int adv76xx_probe(struct i2c_client *client,  		}  	} -	/* work queues */ -	state->work_queues = create_singlethread_workqueue(client->name); -	if (!state->work_queues) { -		v4l2_err(sd, "Could not create work queue\n"); -		err = -ENOMEM; -		goto err_i2c; -	} -  	INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug,  			adv76xx_delayed_work_enable_hotplug); @@ -3212,6 +3492,18 @@ static int adv76xx_probe(struct i2c_client *client,  	err = adv76xx_core_init(sd);  	if (err)  		goto err_entity; + +#if IS_ENABLED(CONFIG_VIDEO_ADV7604_CEC) +	state->cec_adap = cec_allocate_adapter(&adv76xx_cec_adap_ops, +		state, dev_name(&client->dev), +		CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS | +		CEC_CAP_PASSTHROUGH | CEC_CAP_RC, ADV76XX_MAX_ADDRS, +		&client->dev); +	err = PTR_ERR_OR_ZERO(state->cec_adap); +	if (err) +		goto err_entity; +#endif +  	v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,  			client->addr << 1, client->adapter->name); @@ -3225,7 +3517,6 @@ err_entity:  	media_entity_cleanup(&sd->entity);  err_work_queues:  	cancel_delayed_work(&state->delayed_work_enable_hotplug); -	destroy_workqueue(state->work_queues);  err_i2c:  	adv76xx_unregister_clients(state);  err_hdl: @@ -3240,8 +3531,14 @@ static int adv76xx_remove(struct i2c_client *client)  	struct v4l2_subdev *sd = i2c_get_clientdata(client);  	struct adv76xx_state *state = to_state(sd); +	/* disable interrupts */ +	io_write(sd, 0x40, 0); +	io_write(sd, 0x41, 0); +	io_write(sd, 0x46, 0); +	io_write(sd, 0x6e, 0); +	io_write(sd, 0x73, 0); +  	cancel_delayed_work(&state->delayed_work_enable_hotplug); -	destroy_workqueue(state->work_queues);  	v4l2_async_unregister_subdev(sd);  	media_entity_cleanup(&sd->entity);  	adv76xx_unregister_clients(to_state(sd)); diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index ecaacb0a6fa1..8c2a52e280af 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -39,6 +39,7 @@  #include <linux/workqueue.h>  #include <linux/v4l2-dv-timings.h>  #include <linux/hdmi.h> +#include <media/cec.h>  #include <media/v4l2-device.h>  #include <media/v4l2-event.h>  #include <media/v4l2-ctrls.h> @@ -79,6 +80,8 @@ MODULE_LICENSE("GPL");  #define ADV7842_OP_SWAP_CB_CR				(1 << 0) +#define ADV7842_MAX_ADDRS (3) +  /*  **********************************************************************  * @@ -118,7 +121,6 @@ struct adv7842_state {  	struct v4l2_fract aspect_ratio;  	u32 rgb_quantization_range;  	bool is_cea_format; -	struct workqueue_struct *work_queues;  	struct delayed_work delayed_work_enable_hotplug;  	bool restart_stdi_once;  	bool hdmi_port_a; @@ -142,6 +144,11 @@ struct adv7842_state {  	struct v4l2_ctrl *free_run_color_ctrl_manual;  	struct v4l2_ctrl *free_run_color_ctrl;  	struct v4l2_ctrl *rgb_quantization_range_ctrl; + +	struct cec_adapter *cec_adap; +	u8   cec_addr[ADV7842_MAX_ADDRS]; +	u8   cec_valid_addrs; +	bool cec_enabled_adap;  };  /* Unsupported timings. This device cannot support 720p30. */ @@ -418,9 +425,9 @@ static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val)  	return adv_smbus_write_byte_data(state->i2c_cec, reg, val);  } -static inline int cec_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) +static inline int cec_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)  { -	return cec_write(sd, reg, (cec_read(sd, reg) & mask) | val); +	return cec_write(sd, reg, (cec_read(sd, reg) & ~mask) | val);  }  static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg) @@ -696,6 +703,18 @@ adv7842_get_dv_timings_cap(struct v4l2_subdev *sd)  /* ----------------------------------------------------------------------- */ +static u16 adv7842_read_cable_det(struct v4l2_subdev *sd) +{ +	u8 reg = io_read(sd, 0x6f); +	u16 val = 0; + +	if (reg & 0x02) +		val |= 1; /* port A */ +	if (reg & 0x01) +		val |= 2; /* port B */ +	return val; +} +  static void adv7842_delayed_work_enable_hotplug(struct work_struct *work)  {  	struct delayed_work *dwork = to_delayed_work(work); @@ -756,56 +775,23 @@ static int edid_write_vga_segment(struct v4l2_subdev *sd)  	}  	/* enable hotplug after 200 ms */ -	queue_delayed_work(state->work_queues, -			&state->delayed_work_enable_hotplug, HZ / 5); +	schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 5);  	return 0;  } -static int edid_spa_location(const u8 *edid) -{ -	u8 d; - -	/* -	 * TODO, improve and update for other CEA extensions -	 * currently only for 1 segment (256 bytes), -	 * i.e. 1 extension block and CEA revision 3. -	 */ -	if ((edid[0x7e] != 1) || -	    (edid[0x80] != 0x02) || -	    (edid[0x81] != 0x03)) { -		return -EINVAL; -	} -	/* -	 * search Vendor Specific Data Block (tag 3) -	 */ -	d = edid[0x82] & 0x7f; -	if (d > 4) { -		int i = 0x84; -		int end = 0x80 + d; -		do { -			u8 tag = edid[i]>>5; -			u8 len = edid[i] & 0x1f; - -			if ((tag == 3) && (len >= 5)) -				return i + 4; -			i += len + 1; -		} while (i < end); -	} -	return -EINVAL; -} -  static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port)  {  	struct i2c_client *client = v4l2_get_subdevdata(sd);  	struct adv7842_state *state = to_state(sd); -	const u8 *val = state->hdmi_edid.edid; -	int spa_loc = edid_spa_location(val); +	const u8 *edid = state->hdmi_edid.edid; +	int spa_loc; +	u16 pa;  	int err = 0;  	int i; -	v4l2_dbg(2, debug, sd, "%s: write EDID on port %c (spa at 0x%x)\n", -			__func__, (port == ADV7842_EDID_PORT_A) ? 'A' : 'B', spa_loc); +	v4l2_dbg(2, debug, sd, "%s: write EDID on port %c\n", +			__func__, (port == ADV7842_EDID_PORT_A) ? 'A' : 'B');  	/* HPA disable on port A and B */  	io_write_and_or(sd, 0x20, 0xcf, 0x00); @@ -816,24 +802,33 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port)  	if (!state->hdmi_edid.present)  		return 0; +	pa = cec_get_edid_phys_addr(edid, 256, &spa_loc); +	err = cec_phys_addr_validate(pa, &pa, NULL); +	if (err) +		return err; + +	/* +	 * Return an error if no location of the source physical address +	 * was found. +	 */ +	if (spa_loc == 0) +		return -EINVAL; +  	/* edid segment pointer '0' for HDMI ports */  	rep_write_and_or(sd, 0x77, 0xef, 0x00);  	for (i = 0; !err && i < 256; i += I2C_SMBUS_BLOCK_MAX)  		err = adv_smbus_write_i2c_block_data(state->i2c_edid, i, -						     I2C_SMBUS_BLOCK_MAX, val + i); +						     I2C_SMBUS_BLOCK_MAX, edid + i);  	if (err)  		return err; -	if (spa_loc < 0) -		spa_loc = 0xc0; /* Default value [REF_02, p. 199] */ -  	if (port == ADV7842_EDID_PORT_A) { -		rep_write(sd, 0x72, val[spa_loc]); -		rep_write(sd, 0x73, val[spa_loc + 1]); +		rep_write(sd, 0x72, edid[spa_loc]); +		rep_write(sd, 0x73, edid[spa_loc + 1]);  	} else { -		rep_write(sd, 0x74, val[spa_loc]); -		rep_write(sd, 0x75, val[spa_loc + 1]); +		rep_write(sd, 0x74, edid[spa_loc]); +		rep_write(sd, 0x75, edid[spa_loc + 1]);  	}  	rep_write(sd, 0x76, spa_loc & 0xff);  	rep_write_and_or(sd, 0x77, 0xbf, (spa_loc >> 2) & 0x40); @@ -853,10 +848,10 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port)  				(port == ADV7842_EDID_PORT_A) ? 'A' : 'B');  		return -EIO;  	} +	cec_s_phys_addr(state->cec_adap, pa, false);  	/* enable hotplug after 200 ms */ -	queue_delayed_work(state->work_queues, -			&state->delayed_work_enable_hotplug, HZ / 5); +	schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 5);  	return 0;  } @@ -983,20 +978,11 @@ static int adv7842_s_register(struct v4l2_subdev *sd,  static int adv7842_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd)  {  	struct adv7842_state *state = to_state(sd); -	int prev = v4l2_ctrl_g_ctrl(state->detect_tx_5v_ctrl); -	u8 reg_io_6f = io_read(sd, 0x6f); -	int val = 0; +	u16 cable_det = adv7842_read_cable_det(sd); -	if (reg_io_6f & 0x02) -		val |= 1; /* port A */ -	if (reg_io_6f & 0x01) -		val |= 2; /* port B */ - -	v4l2_dbg(1, debug, sd, "%s: 0x%x -> 0x%x\n", __func__, prev, val); +	v4l2_dbg(1, debug, sd, "%s: 0x%x\n", __func__, cable_det); -	if (val != prev) -		return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, val); -	return 0; +	return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, cable_det);  }  static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, @@ -1198,6 +1184,10 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)  	struct adv7842_state *state = to_state(sd);  	bool rgb_output = io_read(sd, 0x02) & 0x02;  	bool hdmi_signal = hdmi_read(sd, 0x05) & 0x80; +	u8 y = HDMI_COLORSPACE_RGB; + +	if (hdmi_signal && (io_read(sd, 0x60) & 1)) +		y = infoframe_read(sd, 0x01) >> 5;  	v4l2_dbg(2, debug, sd, "%s: RGB quantization range: %d, RGB out: %d, HDMI: %d\n",  			__func__, state->rgb_quantization_range, @@ -1205,6 +1195,7 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)  	adv7842_set_gain(sd, true, 0x0, 0x0, 0x0);  	adv7842_set_offset(sd, true, 0x0, 0x0, 0x0); +	io_write_clr_set(sd, 0x02, 0x04, rgb_output ? 0 : 4);  	switch (state->rgb_quantization_range) {  	case V4L2_DV_RGB_RANGE_AUTO: @@ -1254,6 +1245,9 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)  			break;  		} +		if (y != HDMI_COLORSPACE_RGB) +			break; +  		/* RGB limited range (16-235) */  		io_write_and_or(sd, 0x02, 0x0f, 0x00); @@ -1265,6 +1259,9 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)  			break;  		} +		if (y != HDMI_COLORSPACE_RGB) +			break; +  		/* RGB full range (0-255) */  		io_write_and_or(sd, 0x02, 0x0f, 0x10); @@ -2072,6 +2069,7 @@ static void adv7842_setup_format(struct adv7842_state *state)  	io_write_clr_set(sd, 0x04, 0xe0, adv7842_op_ch_sel(state));  	io_write_clr_set(sd, 0x05, 0x01,  			state->format->swap_cb_cr ? ADV7842_OP_SWAP_CB_CR : 0); +	set_rgb_quantization_range(sd);  }  static int adv7842_get_format(struct v4l2_subdev *sd, @@ -2170,6 +2168,207 @@ static void adv7842_irq_enable(struct v4l2_subdev *sd, bool enable)  	}  } +#if IS_ENABLED(CONFIG_VIDEO_ADV7842_CEC) +static void adv7842_cec_tx_raw_status(struct v4l2_subdev *sd, u8 tx_raw_status) +{ +	struct adv7842_state *state = to_state(sd); + +	if ((cec_read(sd, 0x11) & 0x01) == 0) { +		v4l2_dbg(1, debug, sd, "%s: tx raw: tx disabled\n", __func__); +		return; +	} + +	if (tx_raw_status & 0x02) { +		v4l2_dbg(1, debug, sd, "%s: tx raw: arbitration lost\n", +			 __func__); +		cec_transmit_done(state->cec_adap, CEC_TX_STATUS_ARB_LOST, +				  1, 0, 0, 0); +		return; +	} +	if (tx_raw_status & 0x04) { +		u8 status; +		u8 nack_cnt; +		u8 low_drive_cnt; + +		v4l2_dbg(1, debug, sd, "%s: tx raw: retry failed\n", __func__); +		/* +		 * We set this status bit since this hardware performs +		 * retransmissions. +		 */ +		status = CEC_TX_STATUS_MAX_RETRIES; +		nack_cnt = cec_read(sd, 0x14) & 0xf; +		if (nack_cnt) +			status |= CEC_TX_STATUS_NACK; +		low_drive_cnt = cec_read(sd, 0x14) >> 4; +		if (low_drive_cnt) +			status |= CEC_TX_STATUS_LOW_DRIVE; +		cec_transmit_done(state->cec_adap, status, +				  0, nack_cnt, low_drive_cnt, 0); +		return; +	} +	if (tx_raw_status & 0x01) { +		v4l2_dbg(1, debug, sd, "%s: tx raw: ready ok\n", __func__); +		cec_transmit_done(state->cec_adap, CEC_TX_STATUS_OK, 0, 0, 0, 0); +		return; +	} +} + +static void adv7842_cec_isr(struct v4l2_subdev *sd, bool *handled) +{ +	u8 cec_irq; + +	/* cec controller */ +	cec_irq = io_read(sd, 0x93) & 0x0f; +	if (!cec_irq) +		return; + +	v4l2_dbg(1, debug, sd, "%s: cec: irq 0x%x\n", __func__, cec_irq); +	adv7842_cec_tx_raw_status(sd, cec_irq); +	if (cec_irq & 0x08) { +		struct adv7842_state *state = to_state(sd); +		struct cec_msg msg; + +		msg.len = cec_read(sd, 0x25) & 0x1f; +		if (msg.len > 16) +			msg.len = 16; + +		if (msg.len) { +			u8 i; + +			for (i = 0; i < msg.len; i++) +				msg.msg[i] = cec_read(sd, i + 0x15); +			cec_write(sd, 0x26, 0x01); /* re-enable rx */ +			cec_received_msg(state->cec_adap, &msg); +		} +	} + +	io_write(sd, 0x94, cec_irq); + +	if (handled) +		*handled = true; +} + +static int adv7842_cec_adap_enable(struct cec_adapter *adap, bool enable) +{ +	struct adv7842_state *state = adap->priv; +	struct v4l2_subdev *sd = &state->sd; + +	if (!state->cec_enabled_adap && enable) { +		cec_write_clr_set(sd, 0x2a, 0x01, 0x01); /* power up cec */ +		cec_write(sd, 0x2c, 0x01);	/* cec soft reset */ +		cec_write_clr_set(sd, 0x11, 0x01, 0); /* initially disable tx */ +		/* enabled irqs: */ +		/* tx: ready */ +		/* tx: arbitration lost */ +		/* tx: retry timeout */ +		/* rx: ready */ +		io_write_clr_set(sd, 0x96, 0x0f, 0x0f); +		cec_write(sd, 0x26, 0x01);            /* enable rx */ +	} else if (state->cec_enabled_adap && !enable) { +		/* disable cec interrupts */ +		io_write_clr_set(sd, 0x96, 0x0f, 0x00); +		/* disable address mask 1-3 */ +		cec_write_clr_set(sd, 0x27, 0x70, 0x00); +		/* power down cec section */ +		cec_write_clr_set(sd, 0x2a, 0x01, 0x00); +		state->cec_valid_addrs = 0; +	} +	state->cec_enabled_adap = enable; +	return 0; +} + +static int adv7842_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) +{ +	struct adv7842_state *state = adap->priv; +	struct v4l2_subdev *sd = &state->sd; +	unsigned int i, free_idx = ADV7842_MAX_ADDRS; + +	if (!state->cec_enabled_adap) +		return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO; + +	if (addr == CEC_LOG_ADDR_INVALID) { +		cec_write_clr_set(sd, 0x27, 0x70, 0); +		state->cec_valid_addrs = 0; +		return 0; +	} + +	for (i = 0; i < ADV7842_MAX_ADDRS; i++) { +		bool is_valid = state->cec_valid_addrs & (1 << i); + +		if (free_idx == ADV7842_MAX_ADDRS && !is_valid) +			free_idx = i; +		if (is_valid && state->cec_addr[i] == addr) +			return 0; +	} +	if (i == ADV7842_MAX_ADDRS) { +		i = free_idx; +		if (i == ADV7842_MAX_ADDRS) +			return -ENXIO; +	} +	state->cec_addr[i] = addr; +	state->cec_valid_addrs |= 1 << i; + +	switch (i) { +	case 0: +		/* enable address mask 0 */ +		cec_write_clr_set(sd, 0x27, 0x10, 0x10); +		/* set address for mask 0 */ +		cec_write_clr_set(sd, 0x28, 0x0f, addr); +		break; +	case 1: +		/* enable address mask 1 */ +		cec_write_clr_set(sd, 0x27, 0x20, 0x20); +		/* set address for mask 1 */ +		cec_write_clr_set(sd, 0x28, 0xf0, addr << 4); +		break; +	case 2: +		/* enable address mask 2 */ +		cec_write_clr_set(sd, 0x27, 0x40, 0x40); +		/* set address for mask 1 */ +		cec_write_clr_set(sd, 0x29, 0x0f, addr); +		break; +	} +	return 0; +} + +static int adv7842_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, +				     u32 signal_free_time, struct cec_msg *msg) +{ +	struct adv7842_state *state = adap->priv; +	struct v4l2_subdev *sd = &state->sd; +	u8 len = msg->len; +	unsigned int i; + +	/* +	 * The number of retries is the number of attempts - 1, but retry +	 * at least once. It's not clear if a value of 0 is allowed, so +	 * let's do at least one retry. +	 */ +	cec_write_clr_set(sd, 0x12, 0x70, max(1, attempts - 1) << 4); + +	if (len > 16) { +		v4l2_err(sd, "%s: len exceeded 16 (%d)\n", __func__, len); +		return -EINVAL; +	} + +	/* write data */ +	for (i = 0; i < len; i++) +		cec_write(sd, i, msg->msg[i]); + +	/* set length (data + header) */ +	cec_write(sd, 0x10, len); +	/* start transmit, enable tx */ +	cec_write(sd, 0x11, 0x01); +	return 0; +} + +static const struct cec_adap_ops adv7842_cec_adap_ops = { +	.adap_enable = adv7842_cec_adap_enable, +	.adap_log_addr = adv7842_cec_adap_log_addr, +	.adap_transmit = adv7842_cec_adap_transmit, +}; +#endif +  static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled)  {  	struct adv7842_state *state = to_state(sd); @@ -2241,6 +2440,11 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled)  			*handled = true;  	} +#if IS_ENABLED(CONFIG_VIDEO_ADV7842_CEC) +	/* cec */ +	adv7842_cec_isr(sd, handled); +#endif +  	/* tx 5v detect */  	if (irq_status[2] & 0x3) {  		v4l2_dbg(1, debug, sd, "%s: irq tx_5v\n", __func__); @@ -2321,10 +2525,12 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)  	case ADV7842_EDID_PORT_A:  	case ADV7842_EDID_PORT_B:  		memset(&state->hdmi_edid.edid, 0, 256); -		if (e->blocks) +		if (e->blocks) {  			state->hdmi_edid.present |= 0x04 << e->pad; -		else +		} else {  			state->hdmi_edid.present &= ~(0x04 << e->pad); +			adv7842_s_detect_tx_5v_ctrl(sd); +		}  		memcpy(&state->hdmi_edid.edid, e->edid, 128 * e->blocks);  		err = edid_write_hdmi_segment(sd, e->pad);  		break; @@ -2397,6 +2603,8 @@ static void adv7842_log_infoframes(struct v4l2_subdev *sd)  		log_infoframe(sd, &cri[i]);  } +#if 0 +/* Let's keep it here for now, as it could be useful for debug */  static const char * const prim_mode_txt[] = {  	"SDP",  	"Component", @@ -2415,6 +2623,7 @@ static const char * const prim_mode_txt[] = {  	"Reserved",  	"Reserved",  }; +#endif  static int adv7842_sdp_log_status(struct v4l2_subdev *sd)  { @@ -2509,8 +2718,19 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd)  	v4l2_info(sd, "HPD A %s, B %s\n",  		  reg_io_0x21 & 0x02 ? "enabled" : "disabled",  		  reg_io_0x21 & 0x01 ? "enabled" : "disabled"); -	v4l2_info(sd, "CEC %s\n", !!(cec_read(sd, 0x2a) & 0x01) ? +	v4l2_info(sd, "CEC: %s\n", state->cec_enabled_adap ?  			"enabled" : "disabled"); +	if (state->cec_enabled_adap) { +		int i; + +		for (i = 0; i < ADV7842_MAX_ADDRS; i++) { +			bool is_valid = state->cec_valid_addrs & (1 << i); + +			if (is_valid) +				v4l2_info(sd, "CEC Logical Address: 0x%x\n", +					  state->cec_addr[i]); +		} +	}  	v4l2_info(sd, "-----Signal status-----\n");  	if (state->hdmi_port_a) { @@ -2569,11 +2789,11 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd)  		  rgb_quantization_range_txt[state->rgb_quantization_range]);  	v4l2_info(sd, "Input color space: %s\n",  		  input_color_space_txt[reg_io_0x02 >> 4]); -	v4l2_info(sd, "Output color space: %s %s, saturator %s\n", +	v4l2_info(sd, "Output color space: %s %s, alt-gamma %s\n",  		  (reg_io_0x02 & 0x02) ? "RGB" : "YCbCr", -		  (reg_io_0x02 & 0x04) ? "(16-235)" : "(0-255)", -		  ((reg_io_0x02 & 0x04) ^ (reg_io_0x02 & 0x01)) ? -					"enabled" : "disabled"); +		  (((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ? +			"(16-235)" : "(0-255)", +		  (reg_io_0x02 & 0x08) ? "enabled" : "disabled");  	v4l2_info(sd, "Color space conversion: %s\n",  		  csc_coeff_sel_rb[cp_read(sd, 0xf4) >> 4]); @@ -2777,11 +2997,7 @@ static int adv7842_core_init(struct v4l2_subdev *sd)  	io_write(sd, 0x15, 0x80);   /* Power up pads */  	/* video format */ -	io_write(sd, 0x02, -		 0xf0 | -		 pdata->alt_gamma << 3 | -		 pdata->op_656_range << 2 | -		 pdata->alt_data_sat << 0); +	io_write(sd, 0x02, 0xf0 | pdata->alt_gamma << 3);  	io_write_and_or(sd, 0x05, 0xf0, pdata->blank_data << 3 |  			pdata->insert_av_codes << 2 |  			pdata->replicate_av_codes << 1); @@ -3031,6 +3247,24 @@ static int adv7842_subscribe_event(struct v4l2_subdev *sd,  	}  } +static int adv7842_registered(struct v4l2_subdev *sd) +{ +	struct adv7842_state *state = to_state(sd); +	int err; + +	err = cec_register_adapter(state->cec_adap); +	if (err) +		cec_delete_adapter(state->cec_adap); +	return err; +} + +static void adv7842_unregistered(struct v4l2_subdev *sd) +{ +	struct adv7842_state *state = to_state(sd); + +	cec_unregister_adapter(state->cec_adap); +} +  /* ----------------------------------------------------------------------- */  static const struct v4l2_ctrl_ops adv7842_ctrl_ops = { @@ -3077,6 +3311,11 @@ static const struct v4l2_subdev_ops adv7842_ops = {  	.pad = &adv7842_pad_ops,  }; +static const struct v4l2_subdev_internal_ops adv7842_int_ops = { +	.registered = adv7842_registered, +	.unregistered = adv7842_unregistered, +}; +  /* -------------------------- custom ctrls ---------------------------------- */  static const struct v4l2_ctrl_config adv7842_ctrl_analog_sampling_phase = { @@ -3241,6 +3480,7 @@ static int adv7842_probe(struct i2c_client *client,  	sd = &state->sd;  	v4l2_i2c_subdev_init(sd, client, &adv7842_ops);  	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; +	sd->internal_ops = &adv7842_int_ops;  	state->mode = pdata->mode;  	state->hdmi_port_a = pdata->input == ADV7842_SELECT_HDMI_PORT_A; @@ -3311,13 +3551,6 @@ static int adv7842_probe(struct i2c_client *client,  		goto err_i2c;  	} -	/* work queues */ -	state->work_queues = create_singlethread_workqueue(client->name); -	if (!state->work_queues) { -		v4l2_err(sd, "Could not create work queue\n"); -		err = -ENOMEM; -		goto err_i2c; -	}  	INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug,  			adv7842_delayed_work_enable_hotplug); @@ -3331,6 +3564,17 @@ static int adv7842_probe(struct i2c_client *client,  	if (err)  		goto err_entity; +#if IS_ENABLED(CONFIG_VIDEO_ADV7842_CEC) +	state->cec_adap = cec_allocate_adapter(&adv7842_cec_adap_ops, +		state, dev_name(&client->dev), +		CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS | +		CEC_CAP_PASSTHROUGH | CEC_CAP_RC, ADV7842_MAX_ADDRS, +		&client->dev); +	err = PTR_ERR_OR_ZERO(state->cec_adap); +	if (err) +		goto err_entity; +#endif +  	v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,  		  client->addr << 1, client->adapter->name);  	return 0; @@ -3339,7 +3583,6 @@ err_entity:  	media_entity_cleanup(&sd->entity);  err_work_queues:  	cancel_delayed_work(&state->delayed_work_enable_hotplug); -	destroy_workqueue(state->work_queues);  err_i2c:  	adv7842_unregister_clients(sd);  err_hdl: @@ -3355,9 +3598,7 @@ static int adv7842_remove(struct i2c_client *client)  	struct adv7842_state *state = to_state(sd);  	adv7842_irq_enable(sd, false); -  	cancel_delayed_work(&state->delayed_work_enable_hotplug); -	destroy_workqueue(state->work_queues);  	v4l2_device_unregister_subdev(sd);  	media_entity_cleanup(&sd->entity);  	adv7842_unregister_clients(sd); diff --git a/drivers/media/i2c/cs53l32a.c b/drivers/media/i2c/cs53l32a.c index b7e87e38642a..e4b3cf49dd38 100644 --- a/drivers/media/i2c/cs53l32a.c +++ b/drivers/media/i2c/cs53l32a.c @@ -121,13 +121,6 @@ static const struct v4l2_ctrl_ops cs53l32a_ctrl_ops = {  static const struct v4l2_subdev_core_ops cs53l32a_core_ops = {  	.log_status = cs53l32a_log_status, -	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls, -	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls, -	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls, -	.g_ctrl = v4l2_subdev_g_ctrl, -	.s_ctrl = v4l2_subdev_s_ctrl, -	.queryctrl = v4l2_subdev_queryctrl, -	.querymenu = v4l2_subdev_querymenu,  };  static const struct v4l2_subdev_audio_ops cs53l32a_audio_ops = { diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 07a3e7173144..142ae28803bb 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -5042,13 +5042,6 @@ static const struct v4l2_ctrl_ops cx25840_ctrl_ops = {  static const struct v4l2_subdev_core_ops cx25840_core_ops = {  	.log_status = cx25840_log_status, -	.g_ctrl = v4l2_subdev_g_ctrl, -	.s_ctrl = v4l2_subdev_s_ctrl, -	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls, -	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls, -	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls, -	.queryctrl = v4l2_subdev_queryctrl, -	.querymenu = v4l2_subdev_querymenu,  	.reset = cx25840_reset,  	.load_fw = cx25840_load_fw,  	.s_io_pin_config = common_s_io_pin_config, diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c index e016626ebf89..503b7c4f0a9b 100644 --- a/drivers/media/i2c/msp3400-driver.c +++ b/drivers/media/i2c/msp3400-driver.c @@ -642,13 +642,6 @@ static const struct v4l2_ctrl_ops msp_ctrl_ops = {  static const struct v4l2_subdev_core_ops msp_core_ops = {  	.log_status = msp_log_status, -	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls, -	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls, -	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls, -	.g_ctrl = v4l2_subdev_g_ctrl, -	.s_ctrl = v4l2_subdev_s_ctrl, -	.queryctrl = v4l2_subdev_queryctrl, -	.querymenu = v4l2_subdev_querymenu,  };  static const struct v4l2_subdev_video_ops msp_video_ops = { diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c index 702d562f8e39..842017fa4aab 100644 --- a/drivers/media/i2c/mt9t001.c +++ b/drivers/media/i2c/mt9t001.c @@ -233,10 +233,21 @@ static int __mt9t001_set_power(struct mt9t001 *mt9t001, bool on)  	ret = mt9t001_reset(mt9t001);  	if (ret < 0) {  		dev_err(&client->dev, "Failed to reset the camera\n"); -		return ret; +		goto e_power;  	} -	return v4l2_ctrl_handler_setup(&mt9t001->ctrls); +	ret = v4l2_ctrl_handler_setup(&mt9t001->ctrls); +	if (ret < 0) { +		dev_err(&client->dev, "Failed to set up control handlers\n"); +		goto e_power; +	} + +	return 0; + +e_power: +	mt9t001_power_off(mt9t001); + +	return ret;  }  /* ----------------------------------------------------------------------------- @@ -834,7 +845,7 @@ static struct v4l2_subdev_ops mt9t001_subdev_ops = {  	.pad = &mt9t001_subdev_pad_ops,  }; -static struct v4l2_subdev_internal_ops mt9t001_subdev_internal_ops = { +static const struct v4l2_subdev_internal_ops mt9t001_subdev_internal_ops = {  	.registered = mt9t001_registered,  	.open = mt9t001_open,  	.close = mt9t001_close, diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index 501b37039449..58eb62f1ba21 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -19,7 +19,6 @@  #include <linux/log2.h>  #include <linux/mutex.h>  #include <linux/of.h> -#include <linux/of_gpio.h>  #include <linux/regmap.h>  #include <linux/slab.h>  #include <linux/videodev2.h> @@ -133,9 +132,16 @@  #define		MT9V032_TEST_PATTERN_GRAY_DIAGONAL	(3 << 11)  #define		MT9V032_TEST_PATTERN_ENABLE		(1 << 13)  #define		MT9V032_TEST_PATTERN_FLIP		(1 << 14) +#define MT9V032_AEGC_DESIRED_BIN			0xa5 +#define MT9V032_AEC_UPDATE_FREQUENCY			0xa6 +#define MT9V032_AEC_LPF					0xa8 +#define MT9V032_AGC_UPDATE_FREQUENCY			0xa9 +#define MT9V032_AGC_LPF					0xaa  #define MT9V032_AEC_AGC_ENABLE				0xaf  #define		MT9V032_AEC_ENABLE			(1 << 0)  #define		MT9V032_AGC_ENABLE			(1 << 1) +#define MT9V034_AEC_MAX_SHUTTER_WIDTH			0xad +#define MT9V032_AEC_MAX_SHUTTER_WIDTH			0xbd  #define MT9V032_THERMAL_INFO				0xc1  enum mt9v032_model { @@ -162,6 +168,8 @@ struct mt9v032_model_data {  	unsigned int min_shutter;  	unsigned int max_shutter;  	unsigned int pclk_reg; +	unsigned int aec_max_shutter_reg; +	const struct v4l2_ctrl_config * const aec_max_shutter_v4l2_ctrl;  };  struct mt9v032_model_info { @@ -175,63 +183,6 @@ static const struct mt9v032_model_version mt9v032_versions[] = {  	{ MT9V034_CHIP_ID_REV1, "MT9V024/MT9V034 rev1" },  }; -static const struct mt9v032_model_data mt9v032_model_data[] = { -	{ -		/* MT9V022, MT9V032 revisions 1/2/3 */ -		.min_row_time = 660, -		.min_hblank = MT9V032_HORIZONTAL_BLANKING_MIN, -		.min_vblank = MT9V032_VERTICAL_BLANKING_MIN, -		.max_vblank = MT9V032_VERTICAL_BLANKING_MAX, -		.min_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MIN, -		.max_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MAX, -		.pclk_reg = MT9V032_PIXEL_CLOCK, -	}, { -		/* MT9V024, MT9V034 */ -		.min_row_time = 690, -		.min_hblank = MT9V034_HORIZONTAL_BLANKING_MIN, -		.min_vblank = MT9V034_VERTICAL_BLANKING_MIN, -		.max_vblank = MT9V034_VERTICAL_BLANKING_MAX, -		.min_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MIN, -		.max_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MAX, -		.pclk_reg = MT9V034_PIXEL_CLOCK, -	}, -}; - -static const struct mt9v032_model_info mt9v032_models[] = { -	[MT9V032_MODEL_V022_COLOR] = { -		.data = &mt9v032_model_data[0], -		.color = true, -	}, -	[MT9V032_MODEL_V022_MONO] = { -		.data = &mt9v032_model_data[0], -		.color = false, -	}, -	[MT9V032_MODEL_V024_COLOR] = { -		.data = &mt9v032_model_data[1], -		.color = true, -	}, -	[MT9V032_MODEL_V024_MONO] = { -		.data = &mt9v032_model_data[1], -		.color = false, -	}, -	[MT9V032_MODEL_V032_COLOR] = { -		.data = &mt9v032_model_data[0], -		.color = true, -	}, -	[MT9V032_MODEL_V032_MONO] = { -		.data = &mt9v032_model_data[0], -		.color = false, -	}, -	[MT9V032_MODEL_V034_COLOR] = { -		.data = &mt9v032_model_data[1], -		.color = true, -	}, -	[MT9V032_MODEL_V034_MONO] = { -		.data = &mt9v032_model_data[1], -		.color = false, -	}, -}; -  struct mt9v032 {  	struct v4l2_subdev subdev;  	struct media_pad pad; @@ -349,7 +300,8 @@ static int mt9v032_power_on(struct mt9v032 *mt9v032)  	if (ret < 0)  		return ret; -	return regmap_write(map, MT9V032_CHIP_CONTROL, 0); +	return regmap_write(map, MT9V032_CHIP_CONTROL, +			    MT9V032_CHIP_CONTROL_MASTER_MODE);  }  static void mt9v032_power_off(struct mt9v032 *mt9v032) @@ -421,8 +373,7 @@ __mt9v032_get_pad_crop(struct mt9v032 *mt9v032, struct v4l2_subdev_pad_config *c  static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable)  { -	const u16 mode = MT9V032_CHIP_CONTROL_MASTER_MODE -		       | MT9V032_CHIP_CONTROL_DOUT_ENABLE +	const u16 mode = MT9V032_CHIP_CONTROL_DOUT_ENABLE  		       | MT9V032_CHIP_CONTROL_SEQUENTIAL;  	struct mt9v032 *mt9v032 = to_mt9v032(subdev);  	struct v4l2_rect *crop = &mt9v032->crop; @@ -647,6 +598,34 @@ static int mt9v032_set_selection(struct v4l2_subdev *subdev,   */  #define V4L2_CID_TEST_PATTERN_COLOR	(V4L2_CID_USER_BASE | 0x1001) +/* + * Value between 1 and 64 to set the desired bin. This is effectively a measure + * of how bright the image is supposed to be. Both AGC and AEC try to reach + * this. + */ +#define V4L2_CID_AEGC_DESIRED_BIN	(V4L2_CID_USER_BASE | 0x1002) +/* + * LPF is the low pass filter capability of the chip. Both AEC and AGC have + * this setting. This limits the speed in which AGC/AEC adjust their settings. + * Possible values are 0-2. 0 means no LPF. For 1 and 2 this equation is used: + * + * if |(calculated new exp - current exp)| > (current exp / 4) + *	next exp = calculated new exp + * else + *	next exp = current exp + ((calculated new exp - current exp) / 2^LPF) + */ +#define V4L2_CID_AEC_LPF		(V4L2_CID_USER_BASE | 0x1003) +#define V4L2_CID_AGC_LPF		(V4L2_CID_USER_BASE | 0x1004) +/* + * Value between 0 and 15. This is the number of frames being skipped before + * updating the auto exposure/gain. + */ +#define V4L2_CID_AEC_UPDATE_INTERVAL	(V4L2_CID_USER_BASE | 0x1005) +#define V4L2_CID_AGC_UPDATE_INTERVAL	(V4L2_CID_USER_BASE | 0x1006) +/* + * Maximum shutter width used for AEC. + */ +#define V4L2_CID_AEC_MAX_SHUTTER_WIDTH	(V4L2_CID_USER_BASE | 0x1007)  static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)  { @@ -716,6 +695,28 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)  			break;  		}  		return regmap_write(map, MT9V032_TEST_PATTERN, data); + +	case V4L2_CID_AEGC_DESIRED_BIN: +		return regmap_write(map, MT9V032_AEGC_DESIRED_BIN, ctrl->val); + +	case V4L2_CID_AEC_LPF: +		return regmap_write(map, MT9V032_AEC_LPF, ctrl->val); + +	case V4L2_CID_AGC_LPF: +		return regmap_write(map, MT9V032_AGC_LPF, ctrl->val); + +	case V4L2_CID_AEC_UPDATE_INTERVAL: +		return regmap_write(map, MT9V032_AEC_UPDATE_FREQUENCY, +				    ctrl->val); + +	case V4L2_CID_AGC_UPDATE_INTERVAL: +		return regmap_write(map, MT9V032_AGC_UPDATE_FREQUENCY, +				    ctrl->val); + +	case V4L2_CID_AEC_MAX_SHUTTER_WIDTH: +		return regmap_write(map, +				    mt9v032->model->data->aec_max_shutter_reg, +				    ctrl->val);  	}  	return 0; @@ -745,6 +746,84 @@ static const struct v4l2_ctrl_config mt9v032_test_pattern_color = {  	.flags		= 0,  }; +static const struct v4l2_ctrl_config mt9v032_aegc_controls[] = { +	{ +		.ops		= &mt9v032_ctrl_ops, +		.id		= V4L2_CID_AEGC_DESIRED_BIN, +		.type		= V4L2_CTRL_TYPE_INTEGER, +		.name		= "AEC/AGC Desired Bin", +		.min		= 1, +		.max		= 64, +		.step		= 1, +		.def		= 58, +		.flags		= 0, +	}, { +		.ops		= &mt9v032_ctrl_ops, +		.id		= V4L2_CID_AEC_LPF, +		.type		= V4L2_CTRL_TYPE_INTEGER, +		.name		= "AEC Low Pass Filter", +		.min		= 0, +		.max		= 2, +		.step		= 1, +		.def		= 0, +		.flags		= 0, +	}, { +		.ops		= &mt9v032_ctrl_ops, +		.id		= V4L2_CID_AGC_LPF, +		.type		= V4L2_CTRL_TYPE_INTEGER, +		.name		= "AGC Low Pass Filter", +		.min		= 0, +		.max		= 2, +		.step		= 1, +		.def		= 2, +		.flags		= 0, +	}, { +		.ops		= &mt9v032_ctrl_ops, +		.id		= V4L2_CID_AEC_UPDATE_INTERVAL, +		.type		= V4L2_CTRL_TYPE_INTEGER, +		.name		= "AEC Update Interval", +		.min		= 0, +		.max		= 16, +		.step		= 1, +		.def		= 2, +		.flags		= 0, +	}, { +		.ops		= &mt9v032_ctrl_ops, +		.id		= V4L2_CID_AGC_UPDATE_INTERVAL, +		.type		= V4L2_CTRL_TYPE_INTEGER, +		.name		= "AGC Update Interval", +		.min		= 0, +		.max		= 16, +		.step		= 1, +		.def		= 2, +		.flags		= 0, +	} +}; + +static const struct v4l2_ctrl_config mt9v032_aec_max_shutter_width = { +	.ops		= &mt9v032_ctrl_ops, +	.id		= V4L2_CID_AEC_MAX_SHUTTER_WIDTH, +	.type		= V4L2_CTRL_TYPE_INTEGER, +	.name		= "AEC Max Shutter Width", +	.min		= 1, +	.max		= 2047, +	.step		= 1, +	.def		= 480, +	.flags		= 0, +}; + +static const struct v4l2_ctrl_config mt9v034_aec_max_shutter_width = { +	.ops		= &mt9v032_ctrl_ops, +	.id		= V4L2_CID_AEC_MAX_SHUTTER_WIDTH, +	.type		= V4L2_CTRL_TYPE_INTEGER, +	.name		= "AEC Max Shutter Width", +	.min		= 1, +	.max		= 32765, +	.step		= 1, +	.def		= 480, +	.flags		= 0, +}; +  /* -----------------------------------------------------------------------------   * V4L2 subdev core operations   */ @@ -953,13 +1032,6 @@ static int mt9v032_probe(struct i2c_client *client,  	unsigned int i;  	int ret; -	if (!i2c_check_functionality(client->adapter, -				     I2C_FUNC_SMBUS_WORD_DATA)) { -		dev_warn(&client->adapter->dev, -			 "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); -		return -EIO; -	} -  	mt9v032 = devm_kzalloc(&client->dev, sizeof(*mt9v032), GFP_KERNEL);  	if (!mt9v032)  		return -ENOMEM; @@ -986,7 +1058,8 @@ static int mt9v032_probe(struct i2c_client *client,  	mt9v032->pdata = pdata;  	mt9v032->model = (const void *)did->driver_data; -	v4l2_ctrl_handler_init(&mt9v032->ctrls, 10); +	v4l2_ctrl_handler_init(&mt9v032->ctrls, 11 + +			       ARRAY_SIZE(mt9v032_aegc_controls));  	v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,  			  V4L2_CID_AUTOGAIN, 0, 1, 1, 1); @@ -1015,6 +1088,13 @@ static int mt9v032_probe(struct i2c_client *client,  	mt9v032->test_pattern_color = v4l2_ctrl_new_custom(&mt9v032->ctrls,  				      &mt9v032_test_pattern_color, NULL); +	v4l2_ctrl_new_custom(&mt9v032->ctrls, +			     mt9v032->model->data->aec_max_shutter_v4l2_ctrl, +			     NULL); +	for (i = 0; i < ARRAY_SIZE(mt9v032_aegc_controls); ++i) +		v4l2_ctrl_new_custom(&mt9v032->ctrls, &mt9v032_aegc_controls[i], +				     NULL); +  	v4l2_ctrl_cluster(2, &mt9v032->test_pattern);  	mt9v032->pixel_rate = @@ -1103,6 +1183,67 @@ static int mt9v032_remove(struct i2c_client *client)  	return 0;  } +static const struct mt9v032_model_data mt9v032_model_data[] = { +	{ +		/* MT9V022, MT9V032 revisions 1/2/3 */ +		.min_row_time = 660, +		.min_hblank = MT9V032_HORIZONTAL_BLANKING_MIN, +		.min_vblank = MT9V032_VERTICAL_BLANKING_MIN, +		.max_vblank = MT9V032_VERTICAL_BLANKING_MAX, +		.min_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MIN, +		.max_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MAX, +		.pclk_reg = MT9V032_PIXEL_CLOCK, +		.aec_max_shutter_reg = MT9V032_AEC_MAX_SHUTTER_WIDTH, +		.aec_max_shutter_v4l2_ctrl = &mt9v032_aec_max_shutter_width, +	}, { +		/* MT9V024, MT9V034 */ +		.min_row_time = 690, +		.min_hblank = MT9V034_HORIZONTAL_BLANKING_MIN, +		.min_vblank = MT9V034_VERTICAL_BLANKING_MIN, +		.max_vblank = MT9V034_VERTICAL_BLANKING_MAX, +		.min_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MIN, +		.max_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MAX, +		.pclk_reg = MT9V034_PIXEL_CLOCK, +		.aec_max_shutter_reg = MT9V034_AEC_MAX_SHUTTER_WIDTH, +		.aec_max_shutter_v4l2_ctrl = &mt9v034_aec_max_shutter_width, +	}, +}; + +static const struct mt9v032_model_info mt9v032_models[] = { +	[MT9V032_MODEL_V022_COLOR] = { +		.data = &mt9v032_model_data[0], +		.color = true, +	}, +	[MT9V032_MODEL_V022_MONO] = { +		.data = &mt9v032_model_data[0], +		.color = false, +	}, +	[MT9V032_MODEL_V024_COLOR] = { +		.data = &mt9v032_model_data[1], +		.color = true, +	}, +	[MT9V032_MODEL_V024_MONO] = { +		.data = &mt9v032_model_data[1], +		.color = false, +	}, +	[MT9V032_MODEL_V032_COLOR] = { +		.data = &mt9v032_model_data[0], +		.color = true, +	}, +	[MT9V032_MODEL_V032_MONO] = { +		.data = &mt9v032_model_data[0], +		.color = false, +	}, +	[MT9V032_MODEL_V034_COLOR] = { +		.data = &mt9v032_model_data[1], +		.color = true, +	}, +	[MT9V032_MODEL_V034_MONO] = { +		.data = &mt9v032_model_data[1], +		.color = false, +	}, +}; +  static const struct i2c_device_id mt9v032_id[] = {  	{ "mt9v022", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V022_COLOR] },  	{ "mt9v022m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V022_MONO] }, diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index bd3526bdd539..58062b41c923 100644 --- a/drivers/media/i2c/saa7115.c +++ b/drivers/media/i2c/saa7115.c @@ -1585,13 +1585,6 @@ static const struct v4l2_ctrl_ops saa711x_ctrl_ops = {  static const struct v4l2_subdev_core_ops saa711x_core_ops = {  	.log_status = saa711x_log_status, -	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls, -	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls, -	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls, -	.g_ctrl = v4l2_subdev_g_ctrl, -	.s_ctrl = v4l2_subdev_s_ctrl, -	.queryctrl = v4l2_subdev_queryctrl, -	.querymenu = v4l2_subdev_querymenu,  	.reset = saa711x_reset,  	.s_gpio = saa711x_s_gpio,  #ifdef CONFIG_VIDEO_ADV_DEBUG diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 3dfe387abf6e..d08ab6c8357c 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -3044,10 +3044,8 @@ static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev)  	pdata->op_sys_clock = devm_kcalloc(  		dev, bus_cfg->nr_of_link_frequencies + 1 /* guardian */,  		sizeof(*pdata->op_sys_clock), GFP_KERNEL); -	if (!pdata->op_sys_clock) { -		rval = -ENOMEM; +	if (!pdata->op_sys_clock)  		goto out_err; -	}  	for (i = 0; i < bus_cfg->nr_of_link_frequencies; i++) {  		pdata->op_sys_clock[i] = bus_cfg->link_frequencies[i]; diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 6cf6d06737a5..1e3a0dd2238c 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -89,8 +89,6 @@ struct tc358743_state {  	struct v4l2_ctrl *audio_sampling_rate_ctrl;  	struct v4l2_ctrl *audio_present_ctrl; -	/* work queues */ -	struct workqueue_struct *work_queues;  	struct delayed_work delayed_work_enable_hotplug;  	/* edid  */ @@ -425,8 +423,7 @@ static void tc358743_enable_edid(struct v4l2_subdev *sd)  	/* Enable hotplug after 100 ms. DDC access to EDID is also enabled when  	 * hotplug is enabled. See register DDC_CTL */ -	queue_delayed_work(state->work_queues, -			   &state->delayed_work_enable_hotplug, HZ / 10); +	schedule_delayed_work(&state->delayed_work_enable_hotplug, HZ / 10);  	tc358743_enable_interrupts(sd, true);  	tc358743_s_ctrl_detect_tx_5v(sd); @@ -1884,14 +1881,6 @@ static int tc358743_probe(struct i2c_client *client,  		goto err_hdl;  	} -	/* work queues */ -	state->work_queues = create_singlethread_workqueue(client->name); -	if (!state->work_queues) { -		v4l2_err(sd, "Could not create work queue\n"); -		err = -ENOMEM; -		goto err_hdl; -	} -  	state->pad.flags = MEDIA_PAD_FL_SOURCE;  	err = media_entity_pads_init(&sd->entity, 1, &state->pad);  	if (err < 0) @@ -1940,7 +1929,6 @@ static int tc358743_probe(struct i2c_client *client,  err_work_queues:  	cancel_delayed_work(&state->delayed_work_enable_hotplug); -	destroy_workqueue(state->work_queues);  	mutex_destroy(&state->confctl_mutex);  err_hdl:  	media_entity_cleanup(&sd->entity); @@ -1954,7 +1942,6 @@ static int tc358743_remove(struct i2c_client *client)  	struct tc358743_state *state = to_state(sd);  	cancel_delayed_work(&state->delayed_work_enable_hotplug); -	destroy_workqueue(state->work_queues);  	v4l2_async_unregister_subdev(sd);  	v4l2_device_unregister_subdev(sd);  	mutex_destroy(&state->confctl_mutex); diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c index fece2a4339a1..42d1e26e581c 100644 --- a/drivers/media/i2c/tvaudio.c +++ b/drivers/media/i2c/tvaudio.c @@ -1855,13 +1855,6 @@ static const struct v4l2_ctrl_ops tvaudio_ctrl_ops = {  static const struct v4l2_subdev_core_ops tvaudio_core_ops = {  	.log_status = tvaudio_log_status, -	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls, -	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls, -	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls, -	.g_ctrl = v4l2_subdev_g_ctrl, -	.s_ctrl = v4l2_subdev_s_ctrl, -	.queryctrl = v4l2_subdev_queryctrl, -	.querymenu = v4l2_subdev_querymenu,  };  static const struct v4l2_subdev_tuner_ops tvaudio_tuner_ops = { diff --git a/drivers/media/i2c/wm8775.c b/drivers/media/i2c/wm8775.c index 6e00f145b948..5581f4db02af 100644 --- a/drivers/media/i2c/wm8775.c +++ b/drivers/media/i2c/wm8775.c @@ -178,13 +178,6 @@ static const struct v4l2_ctrl_ops wm8775_ctrl_ops = {  static const struct v4l2_subdev_core_ops wm8775_core_ops = {  	.log_status = wm8775_log_status, -	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls, -	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls, -	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls, -	.g_ctrl = v4l2_subdev_g_ctrl, -	.s_ctrl = v4l2_subdev_s_ctrl, -	.queryctrl = v4l2_subdev_queryctrl, -	.querymenu = v4l2_subdev_querymenu,  };  static const struct v4l2_subdev_tuner_ops wm8775_tuner_ops = {  |