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 100712eca9SIcenowy Zheng #include <drm/drm.h> 110712eca9SIcenowy Zheng #include <drm/drm_dp_helper.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 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 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 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 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 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 1190712eca9SIcenowy Zheng if ((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