10712eca9SIcenowy Zheng /* SPDX-License-Identifier: GPL-2.0-only */
20712eca9SIcenowy Zheng /*
30712eca9SIcenowy Zheng  * Copyright(c) 2016, Analogix Semiconductor.
40712eca9SIcenowy Zheng  *
50712eca9SIcenowy Zheng  * Based on anx7808 driver obtained from chromeos with copyright:
60712eca9SIcenowy Zheng  * Copyright(c) 2013, Google Inc.
70712eca9SIcenowy Zheng  */
80712eca9SIcenowy Zheng #include <linux/regmap.h>
90712eca9SIcenowy Zheng 
10*da68386dSThomas Zimmermann #include <drm/display/drm_dp_helper.h>
110712eca9SIcenowy Zheng #include <drm/drm.h>
120712eca9SIcenowy Zheng #include <drm/drm_print.h>
130712eca9SIcenowy Zheng 
140712eca9SIcenowy Zheng #include "analogix-i2c-dptx.h"
150712eca9SIcenowy Zheng 
160712eca9SIcenowy Zheng #define AUX_WAIT_TIMEOUT_MS	15
170712eca9SIcenowy Zheng #define AUX_CH_BUFFER_SIZE	16
180712eca9SIcenowy Zheng 
anx_i2c_dp_clear_bits(struct regmap * map,u8 reg,u8 mask)190712eca9SIcenowy Zheng static int anx_i2c_dp_clear_bits(struct regmap *map, u8 reg, u8 mask)
200712eca9SIcenowy Zheng {
210712eca9SIcenowy Zheng 	return regmap_update_bits(map, reg, mask, 0);
220712eca9SIcenowy Zheng }
230712eca9SIcenowy Zheng 
anx_dp_aux_op_finished(struct regmap * map_dptx)240712eca9SIcenowy Zheng static bool anx_dp_aux_op_finished(struct regmap *map_dptx)
250712eca9SIcenowy Zheng {
260712eca9SIcenowy Zheng 	unsigned int value;
270712eca9SIcenowy Zheng 	int err;
280712eca9SIcenowy Zheng 
290712eca9SIcenowy Zheng 	err = regmap_read(map_dptx, SP_DP_AUX_CH_CTRL2_REG, &value);
300712eca9SIcenowy Zheng 	if (err < 0)
310712eca9SIcenowy Zheng 		return false;
320712eca9SIcenowy Zheng 
330712eca9SIcenowy Zheng 	return (value & SP_AUX_EN) == 0;
340712eca9SIcenowy Zheng }
350712eca9SIcenowy Zheng 
anx_dp_aux_wait(struct regmap * map_dptx)360712eca9SIcenowy Zheng static int anx_dp_aux_wait(struct regmap *map_dptx)
370712eca9SIcenowy Zheng {
380712eca9SIcenowy Zheng 	unsigned long timeout;
390712eca9SIcenowy Zheng 	unsigned int status;
400712eca9SIcenowy Zheng 	int err;
410712eca9SIcenowy Zheng 
420712eca9SIcenowy Zheng 	timeout = jiffies + msecs_to_jiffies(AUX_WAIT_TIMEOUT_MS) + 1;
430712eca9SIcenowy Zheng 
440712eca9SIcenowy Zheng 	while (!anx_dp_aux_op_finished(map_dptx)) {
450712eca9SIcenowy Zheng 		if (time_after(jiffies, timeout)) {
460712eca9SIcenowy Zheng 			if (!anx_dp_aux_op_finished(map_dptx)) {
470712eca9SIcenowy Zheng 				DRM_ERROR("Timed out waiting AUX to finish\n");
480712eca9SIcenowy Zheng 				return -ETIMEDOUT;
490712eca9SIcenowy Zheng 			}
500712eca9SIcenowy Zheng 
510712eca9SIcenowy Zheng 			break;
520712eca9SIcenowy Zheng 		}
530712eca9SIcenowy Zheng 
540712eca9SIcenowy Zheng 		usleep_range(1000, 2000);
550712eca9SIcenowy Zheng 	}
560712eca9SIcenowy Zheng 
570712eca9SIcenowy Zheng 	/* Read the AUX channel access status */
580712eca9SIcenowy Zheng 	err = regmap_read(map_dptx, SP_AUX_CH_STATUS_REG, &status);
590712eca9SIcenowy Zheng 	if (err < 0) {
600712eca9SIcenowy Zheng 		DRM_ERROR("Failed to read from AUX channel: %d\n", err);
610712eca9SIcenowy Zheng 		return err;
620712eca9SIcenowy Zheng 	}
630712eca9SIcenowy Zheng 
640712eca9SIcenowy Zheng 	if (status & SP_AUX_STATUS) {
650712eca9SIcenowy Zheng 		DRM_ERROR("Failed to wait for AUX channel (status: %02x)\n",
660712eca9SIcenowy Zheng 			  status);
670712eca9SIcenowy Zheng 		return -ETIMEDOUT;
680712eca9SIcenowy Zheng 	}
690712eca9SIcenowy Zheng 
700712eca9SIcenowy Zheng 	return 0;
710712eca9SIcenowy Zheng }
720712eca9SIcenowy Zheng 
anx_dp_aux_address(struct regmap * map_dptx,unsigned int addr)730712eca9SIcenowy Zheng static int anx_dp_aux_address(struct regmap *map_dptx, unsigned int addr)
740712eca9SIcenowy Zheng {
750712eca9SIcenowy Zheng 	int err;
760712eca9SIcenowy Zheng 
770712eca9SIcenowy Zheng 	err = regmap_write(map_dptx, SP_AUX_ADDR_7_0_REG, addr & 0xff);
780712eca9SIcenowy Zheng 	if (err)
790712eca9SIcenowy Zheng 		return err;
800712eca9SIcenowy Zheng 
810712eca9SIcenowy Zheng 	err = regmap_write(map_dptx, SP_AUX_ADDR_15_8_REG,
820712eca9SIcenowy Zheng 			   (addr & 0xff00) >> 8);
830712eca9SIcenowy Zheng 	if (err)
840712eca9SIcenowy Zheng 		return err;
850712eca9SIcenowy Zheng 
860712eca9SIcenowy Zheng 	/*
870712eca9SIcenowy Zheng 	 * DP AUX CH Address Register #2, only update bits[3:0]
880712eca9SIcenowy Zheng 	 * [7:4] RESERVED
890712eca9SIcenowy Zheng 	 * [3:0] AUX_ADDR[19:16], Register control AUX CH address.
900712eca9SIcenowy Zheng 	 */
910712eca9SIcenowy Zheng 	err = regmap_update_bits(map_dptx, SP_AUX_ADDR_19_16_REG,
920712eca9SIcenowy Zheng 				 SP_AUX_ADDR_19_16_MASK,
930712eca9SIcenowy Zheng 				 (addr & 0xf0000) >> 16);
940712eca9SIcenowy Zheng 
950712eca9SIcenowy Zheng 	if (err)
960712eca9SIcenowy Zheng 		return err;
970712eca9SIcenowy Zheng 
980712eca9SIcenowy Zheng 	return 0;
990712eca9SIcenowy Zheng }
1000712eca9SIcenowy Zheng 
anx_dp_aux_transfer(struct regmap * map_dptx,struct drm_dp_aux_msg * msg)1010712eca9SIcenowy Zheng ssize_t anx_dp_aux_transfer(struct regmap *map_dptx,
1020712eca9SIcenowy Zheng 				struct drm_dp_aux_msg *msg)
1030712eca9SIcenowy Zheng {
1040712eca9SIcenowy Zheng 	u8 ctrl1 = msg->request;
1050712eca9SIcenowy Zheng 	u8 ctrl2 = SP_AUX_EN;
1060712eca9SIcenowy Zheng 	u8 *buffer = msg->buffer;
1070712eca9SIcenowy Zheng 	int err;
1080712eca9SIcenowy Zheng 
1090712eca9SIcenowy Zheng 	/* The DP AUX transmit and receive buffer has 16 bytes. */
1100712eca9SIcenowy Zheng 	if (WARN_ON(msg->size > AUX_CH_BUFFER_SIZE))
1110712eca9SIcenowy Zheng 		return -E2BIG;
1120712eca9SIcenowy Zheng 
1130712eca9SIcenowy Zheng 	/* Zero-sized messages specify address-only transactions. */
1140712eca9SIcenowy Zheng 	if (msg->size < 1)
1150712eca9SIcenowy Zheng 		ctrl2 |= SP_ADDR_ONLY;
1160712eca9SIcenowy Zheng 	else	/* For non-zero-sized set the length field. */
1170712eca9SIcenowy Zheng 		ctrl1 |= (msg->size - 1) << SP_AUX_LENGTH_SHIFT;
1180712eca9SIcenowy Zheng 
119dea73d61STorsten Duwe 	if ((msg->size > 0) && ((msg->request & DP_AUX_I2C_READ) == 0)) {
1200712eca9SIcenowy Zheng 		/* When WRITE | MOT write values to data buffer */
1210712eca9SIcenowy Zheng 		err = regmap_bulk_write(map_dptx,
1220712eca9SIcenowy Zheng 					SP_DP_BUF_DATA0_REG, buffer,
1230712eca9SIcenowy Zheng 					msg->size);
1240712eca9SIcenowy Zheng 		if (err)
1250712eca9SIcenowy Zheng 			return err;
1260712eca9SIcenowy Zheng 	}
1270712eca9SIcenowy Zheng 
1280712eca9SIcenowy Zheng 	/* Write address and request */
1290712eca9SIcenowy Zheng 	err = anx_dp_aux_address(map_dptx, msg->address);
1300712eca9SIcenowy Zheng 	if (err)
1310712eca9SIcenowy Zheng 		return err;
1320712eca9SIcenowy Zheng 
1330712eca9SIcenowy Zheng 	err = regmap_write(map_dptx, SP_DP_AUX_CH_CTRL1_REG, ctrl1);
1340712eca9SIcenowy Zheng 	if (err)
1350712eca9SIcenowy Zheng 		return err;
1360712eca9SIcenowy Zheng 
1370712eca9SIcenowy Zheng 	/* Start transaction */
1380712eca9SIcenowy Zheng 	err = regmap_update_bits(map_dptx, SP_DP_AUX_CH_CTRL2_REG,
1390712eca9SIcenowy Zheng 				 SP_ADDR_ONLY | SP_AUX_EN, ctrl2);
1400712eca9SIcenowy Zheng 	if (err)
1410712eca9SIcenowy Zheng 		return err;
1420712eca9SIcenowy Zheng 
1430712eca9SIcenowy Zheng 	err = anx_dp_aux_wait(map_dptx);
1440712eca9SIcenowy Zheng 	if (err)
1450712eca9SIcenowy Zheng 		return err;
1460712eca9SIcenowy Zheng 
1470712eca9SIcenowy Zheng 	msg->reply = DP_AUX_I2C_REPLY_ACK;
1480712eca9SIcenowy Zheng 
1490712eca9SIcenowy Zheng 	if ((msg->size > 0) && (msg->request & DP_AUX_I2C_READ)) {
1500712eca9SIcenowy Zheng 		/* Read values from data buffer */
1510712eca9SIcenowy Zheng 		err = regmap_bulk_read(map_dptx,
1520712eca9SIcenowy Zheng 				       SP_DP_BUF_DATA0_REG, buffer,
1530712eca9SIcenowy Zheng 				       msg->size);
1540712eca9SIcenowy Zheng 		if (err)
1550712eca9SIcenowy Zheng 			return err;
1560712eca9SIcenowy Zheng 	}
1570712eca9SIcenowy Zheng 
1580712eca9SIcenowy Zheng 	err = anx_i2c_dp_clear_bits(map_dptx, SP_DP_AUX_CH_CTRL2_REG,
1590712eca9SIcenowy Zheng 				    SP_ADDR_ONLY);
1600712eca9SIcenowy Zheng 	if (err)
1610712eca9SIcenowy Zheng 		return err;
1620712eca9SIcenowy Zheng 
1630712eca9SIcenowy Zheng 	return msg->size;
1640712eca9SIcenowy Zheng }
1650712eca9SIcenowy Zheng EXPORT_SYMBOL_GPL(anx_dp_aux_transfer);
166