File Index
Files and directories
Sign in
FILE

analogix-i2c-dptx.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/bridge/analogix/analogix-i2c-dptx.c C
  1/* SPDX-License-Identifier: GPL-2.0-only */
  2/*
  3 * Copyright(c) 2016, Analogix Semiconductor.
  4 *
  5 * Based on anx7808 driver obtained from chromeos with copyright:
  6 * Copyright(c) 2013, Google Inc.
  7 */
  8
  9#include <linux/export.h>
 10#include <linux/regmap.h>
 11
 12#include <drm/display/drm_dp_helper.h>
 13#include <drm/drm.h>
 14#include <drm/drm_print.h>
 15
 16#include "analogix-i2c-dptx.h"
 17
 18#define AUX_WAIT_TIMEOUT_MS	15
 19#define AUX_CH_BUFFER_SIZE	16
 20
 21static int anx_i2c_dp_clear_bits(struct regmap *map, u8 reg, u8 mask)
 22{
 23	return regmap_update_bits(map, reg, mask, 0);
 24}
 25
 26static bool anx_dp_aux_op_finished(struct regmap *map_dptx)
 27{
 28	unsigned int value;
 29	int err;
 30
 31	err = regmap_read(map_dptx, SP_DP_AUX_CH_CTRL2_REG, &value);
 32	if (err < 0)
 33		return false;
 34
 35	return (value & SP_AUX_EN) == 0;
 36}
 37
 38static int anx_dp_aux_wait(struct regmap *map_dptx)
 39{
 40	unsigned long timeout;
 41	unsigned int status;
 42	int err;
 43
 44	timeout = jiffies + msecs_to_jiffies(AUX_WAIT_TIMEOUT_MS) + 1;
 45
 46	while (!anx_dp_aux_op_finished(map_dptx)) {
 47		if (time_after(jiffies, timeout)) {
 48			if (!anx_dp_aux_op_finished(map_dptx)) {
 49				DRM_ERROR("Timed out waiting AUX to finish\n");
 50				return -ETIMEDOUT;
 51			}
 52
 53			break;
 54		}
 55
 56		usleep_range(1000, 2000);
 57	}
 58
 59	/* Read the AUX channel access status */
 60	err = regmap_read(map_dptx, SP_AUX_CH_STATUS_REG, &status);
 61	if (err < 0) {
 62		DRM_ERROR("Failed to read from AUX channel: %d\n", err);
 63		return err;
 64	}
 65
 66	if (status & SP_AUX_STATUS) {
 67		DRM_ERROR("Failed to wait for AUX channel (status: %02x)\n",
 68			  status);
 69		return -ETIMEDOUT;
 70	}
 71
 72	return 0;
 73}
 74
 75static int anx_dp_aux_address(struct regmap *map_dptx, unsigned int addr)
 76{
 77	int err;
 78
 79	err = regmap_write(map_dptx, SP_AUX_ADDR_7_0_REG, addr & 0xff);
 80	if (err)
 81		return err;
 82
 83	err = regmap_write(map_dptx, SP_AUX_ADDR_15_8_REG,
 84			   (addr & 0xff00) >> 8);
 85	if (err)
 86		return err;
 87
 88	/*
 89	 * DP AUX CH Address Register #2, only update bits[3:0]
 90	 * [7:4] RESERVED
 91	 * [3:0] AUX_ADDR[19:16], Register control AUX CH address.
 92	 */
 93	err = regmap_update_bits(map_dptx, SP_AUX_ADDR_19_16_REG,
 94				 SP_AUX_ADDR_19_16_MASK,
 95				 (addr & 0xf0000) >> 16);
 96
 97	if (err)
 98		return err;
 99
100	return 0;
101}
102
103ssize_t anx_dp_aux_transfer(struct regmap *map_dptx,
104				struct drm_dp_aux_msg *msg)
105{
106	u8 ctrl1 = msg->request;
107	u8 ctrl2 = SP_AUX_EN;
108	u8 *buffer = msg->buffer;
109	int err;
110
111	/* The DP AUX transmit and receive buffer has 16 bytes. */
112	if (WARN_ON(msg->size > AUX_CH_BUFFER_SIZE))
113		return -E2BIG;
114
115	/* Zero-sized messages specify address-only transactions. */
116	if (msg->size < 1)
117		ctrl2 |= SP_ADDR_ONLY;
118	else	/* For non-zero-sized set the length field. */
119		ctrl1 |= (msg->size - 1) << SP_AUX_LENGTH_SHIFT;
120
121	if ((msg->size > 0) && ((msg->request & DP_AUX_I2C_READ) == 0)) {
122		/* When WRITE | MOT write values to data buffer */
123		err = regmap_bulk_write(map_dptx,
124					SP_DP_BUF_DATA0_REG, buffer,
125					msg->size);
126		if (err)
127			return err;
128	}
129
130	/* Write address and request */
131	err = anx_dp_aux_address(map_dptx, msg->address);
132	if (err)
133		return err;
134
135	err = regmap_write(map_dptx, SP_DP_AUX_CH_CTRL1_REG, ctrl1);
136	if (err)
137		return err;
138
139	/* Start transaction */
140	err = regmap_update_bits(map_dptx, SP_DP_AUX_CH_CTRL2_REG,
141				 SP_ADDR_ONLY | SP_AUX_EN, ctrl2);
142	if (err)
143		return err;
144
145	err = anx_dp_aux_wait(map_dptx);
146	if (err)
147		return err;
148
149	msg->reply = DP_AUX_I2C_REPLY_ACK;
150
151	if ((msg->size > 0) && (msg->request & DP_AUX_I2C_READ)) {
152		/* Read values from data buffer */
153		err = regmap_bulk_read(map_dptx,
154				       SP_DP_BUF_DATA0_REG, buffer,
155				       msg->size);
156		if (err)
157			return err;
158	}
159
160	err = anx_i2c_dp_clear_bits(map_dptx, SP_DP_AUX_CH_CTRL2_REG,
161				    SP_ADDR_ONLY);
162	if (err)
163		return err;
164
165	return msg->size;
166}
167EXPORT_SYMBOL_GPL(anx_dp_aux_transfer);
~/ Read-only file preview.