linux/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c
Uwe Kleine-König ed5c2f5fd1 i2c: Make remove callback return void
The value returned by an i2c driver's remove function is mostly ignored.
(Only an error message is printed if the value is non-zero that the
error is ignored.)

So change the prototype of the remove function to return no value. This
way driver authors are not tempted to assume that passing an error to
the upper layer is a good idea. All drivers are adapted accordingly.
There is no intended change of behaviour, all callbacks were prepared to
return 0 before.

Reviewed-by: Peter Senna Tschudin <peter.senna@gmail.com>
Reviewed-by: Jeremy Kerr <jk@codeconstruct.com.au>
Reviewed-by: Benjamin Mugnier <benjamin.mugnier@foss.st.com>
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Crt Mori <cmo@melexis.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-by: Marek Behún <kabel@kernel.org> # for leds-turris-omnia
Acked-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Reviewed-by: Petr Machata <petrm@nvidia.com> # for mlxsw
Reviewed-by: Maximilian Luz <luzmaximilian@gmail.com> # for surface3_power
Acked-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> # for bmc150-accel-i2c + kxcjk-1013
Reviewed-by: Hans Verkuil <hverkuil-cisco@xs4all.nl> # for media/* + staging/media/*
Acked-by: Miguel Ojeda <ojeda@kernel.org> # for auxdisplay/ht16k33 + auxdisplay/lcd2s
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com> # for versaclock5
Reviewed-by: Ajay Gupta <ajayg@nvidia.com> # for ucsi_ccg
Acked-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> # for iio
Acked-by: Peter Rosin <peda@axentia.se> # for i2c-mux-*, max9860
Acked-by: Adrien Grassein <adrien.grassein@gmail.com> # for lontium-lt8912b
Reviewed-by: Jean Delvare <jdelvare@suse.de> # for hwmon, i2c-core and i2c/muxes
Acked-by: Corey Minyard <cminyard@mvista.com> # for IPMI
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
Acked-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Acked-by: Sebastian Reichel <sebastian.reichel@collabora.com> # for drivers/power
Acked-by: Krzysztof Hałasa <khalasa@piap.pl>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Wolfram Sang <wsa@kernel.org>
2022-08-16 12:46:26 +02:00

829 lines
20 KiB
C

/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright(c) 2016, Analogix Semiconductor.
* Copyright(c) 2017, Icenowy Zheng <icenowy@aosc.io>
*
* Based on anx7808 driver obtained from chromeos with copyright:
* Copyright(c) 2013, Google Inc.
*/
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/types.h>
#include <drm/display/drm_dp_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include "analogix-i2c-dptx.h"
#include "analogix-i2c-txcommon.h"
#define POLL_DELAY 50000 /* us */
#define POLL_TIMEOUT 5000000 /* us */
#define I2C_IDX_DPTX 0
#define I2C_IDX_TXCOM 1
static const u8 anx6345_i2c_addresses[] = {
[I2C_IDX_DPTX] = 0x70,
[I2C_IDX_TXCOM] = 0x72,
};
#define I2C_NUM_ADDRESSES ARRAY_SIZE(anx6345_i2c_addresses)
struct anx6345 {
struct drm_dp_aux aux;
struct drm_bridge bridge;
struct i2c_client *client;
struct edid *edid;
struct drm_connector connector;
struct drm_panel *panel;
struct regulator *dvdd12;
struct regulator *dvdd25;
struct gpio_desc *gpiod_reset;
struct mutex lock; /* protect EDID access */
/* I2C Slave addresses of ANX6345 are mapped as DPTX and SYS */
struct i2c_client *i2c_clients[I2C_NUM_ADDRESSES];
struct regmap *map[I2C_NUM_ADDRESSES];
u16 chipid;
u8 dpcd[DP_RECEIVER_CAP_SIZE];
bool powered;
};
static inline struct anx6345 *connector_to_anx6345(struct drm_connector *c)
{
return container_of(c, struct anx6345, connector);
}
static inline struct anx6345 *bridge_to_anx6345(struct drm_bridge *bridge)
{
return container_of(bridge, struct anx6345, bridge);
}
static int anx6345_set_bits(struct regmap *map, u8 reg, u8 mask)
{
return regmap_update_bits(map, reg, mask, mask);
}
static int anx6345_clear_bits(struct regmap *map, u8 reg, u8 mask)
{
return regmap_update_bits(map, reg, mask, 0);
}
static ssize_t anx6345_aux_transfer(struct drm_dp_aux *aux,
struct drm_dp_aux_msg *msg)
{
struct anx6345 *anx6345 = container_of(aux, struct anx6345, aux);
return anx_dp_aux_transfer(anx6345->map[I2C_IDX_DPTX], msg);
}
static int anx6345_dp_link_training(struct anx6345 *anx6345)
{
unsigned int value;
u8 dp_bw, dpcd[2];
int err;
err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM],
SP_POWERDOWN_CTRL_REG,
SP_TOTAL_PD);
if (err)
return err;
err = drm_dp_dpcd_readb(&anx6345->aux, DP_MAX_LINK_RATE, &dp_bw);
if (err < 0)
return err;
switch (dp_bw) {
case DP_LINK_BW_1_62:
case DP_LINK_BW_2_7:
break;
default:
DRM_DEBUG_KMS("DP bandwidth (%#02x) not supported\n", dp_bw);
return -EINVAL;
}
err = anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL1_REG,
SP_VIDEO_MUTE);
if (err)
return err;
err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM],
SP_VID_CTRL1_REG, SP_VIDEO_EN);
if (err)
return err;
/* Get DPCD info */
err = drm_dp_dpcd_read(&anx6345->aux, DP_DPCD_REV,
&anx6345->dpcd, DP_RECEIVER_CAP_SIZE);
if (err < 0) {
DRM_ERROR("Failed to read DPCD: %d\n", err);
return err;
}
/* Clear channel x SERDES power down */
err = anx6345_clear_bits(anx6345->map[I2C_IDX_DPTX],
SP_DP_ANALOG_POWER_DOWN_REG, SP_CH0_PD);
if (err)
return err;
/*
* Power up the sink (DP_SET_POWER register is only available on DPCD
* v1.1 and later).
*/
if (anx6345->dpcd[DP_DPCD_REV] >= 0x11) {
err = drm_dp_dpcd_readb(&anx6345->aux, DP_SET_POWER, &dpcd[0]);
if (err < 0) {
DRM_ERROR("Failed to read DP_SET_POWER register: %d\n",
err);
return err;
}
dpcd[0] &= ~DP_SET_POWER_MASK;
dpcd[0] |= DP_SET_POWER_D0;
err = drm_dp_dpcd_writeb(&anx6345->aux, DP_SET_POWER, dpcd[0]);
if (err < 0) {
DRM_ERROR("Failed to power up DisplayPort link: %d\n",
err);
return err;
}
/*
* According to the DP 1.1 specification, a "Sink Device must
* exit the power saving state within 1 ms" (Section 2.5.3.1,
* Table 5-52, "Sink Control Field" (register 0x600).
*/
usleep_range(1000, 2000);
}
/* Possibly enable downspread on the sink */
err = regmap_write(anx6345->map[I2C_IDX_DPTX],
SP_DP_DOWNSPREAD_CTRL1_REG, 0);
if (err)
return err;
if (anx6345->dpcd[DP_MAX_DOWNSPREAD] & DP_MAX_DOWNSPREAD_0_5) {
DRM_DEBUG("Enable downspread on the sink\n");
/* 4000PPM */
err = regmap_write(anx6345->map[I2C_IDX_DPTX],
SP_DP_DOWNSPREAD_CTRL1_REG, 8);
if (err)
return err;
err = drm_dp_dpcd_writeb(&anx6345->aux, DP_DOWNSPREAD_CTRL,
DP_SPREAD_AMP_0_5);
if (err < 0)
return err;
} else {
err = drm_dp_dpcd_writeb(&anx6345->aux, DP_DOWNSPREAD_CTRL, 0);
if (err < 0)
return err;
}
/* Set the lane count and the link rate on the sink */
if (drm_dp_enhanced_frame_cap(anx6345->dpcd))
err = anx6345_set_bits(anx6345->map[I2C_IDX_DPTX],
SP_DP_SYSTEM_CTRL_BASE + 4,
SP_ENHANCED_MODE);
else
err = anx6345_clear_bits(anx6345->map[I2C_IDX_DPTX],
SP_DP_SYSTEM_CTRL_BASE + 4,
SP_ENHANCED_MODE);
if (err)
return err;
dpcd[0] = dp_bw;
err = regmap_write(anx6345->map[I2C_IDX_DPTX],
SP_DP_MAIN_LINK_BW_SET_REG, dpcd[0]);
if (err)
return err;
dpcd[1] = drm_dp_max_lane_count(anx6345->dpcd);
err = regmap_write(anx6345->map[I2C_IDX_DPTX],
SP_DP_LANE_COUNT_SET_REG, dpcd[1]);
if (err)
return err;
if (drm_dp_enhanced_frame_cap(anx6345->dpcd))
dpcd[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
err = drm_dp_dpcd_write(&anx6345->aux, DP_LINK_BW_SET, dpcd,
sizeof(dpcd));
if (err < 0) {
DRM_ERROR("Failed to configure link: %d\n", err);
return err;
}
/* Start training on the source */
err = regmap_write(anx6345->map[I2C_IDX_DPTX], SP_DP_LT_CTRL_REG,
SP_LT_EN);
if (err)
return err;
return regmap_read_poll_timeout(anx6345->map[I2C_IDX_DPTX],
SP_DP_LT_CTRL_REG,
value, !(value & SP_DP_LT_INPROGRESS),
POLL_DELAY, POLL_TIMEOUT);
}
static int anx6345_tx_initialization(struct anx6345 *anx6345)
{
int err, i;
/* FIXME: colordepth is hardcoded for now */
err = regmap_write(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL2_REG,
SP_IN_BPC_6BIT << SP_IN_BPC_SHIFT);
if (err)
return err;
err = regmap_write(anx6345->map[I2C_IDX_DPTX], SP_DP_PLL_CTRL_REG, 0);
if (err)
return err;
err = regmap_write(anx6345->map[I2C_IDX_TXCOM],
SP_ANALOG_DEBUG1_REG, 0);
if (err)
return err;
err = regmap_write(anx6345->map[I2C_IDX_DPTX],
SP_DP_LINK_DEBUG_CTRL_REG,
SP_NEW_PRBS7 | SP_M_VID_DEBUG);
if (err)
return err;
err = regmap_write(anx6345->map[I2C_IDX_DPTX],
SP_DP_ANALOG_POWER_DOWN_REG, 0);
if (err)
return err;
/* Force HPD */
err = anx6345_set_bits(anx6345->map[I2C_IDX_DPTX],
SP_DP_SYSTEM_CTRL_BASE + 3,
SP_HPD_FORCE | SP_HPD_CTRL);
if (err)
return err;
for (i = 0; i < 4; i++) {
/* 4 lanes */
err = regmap_write(anx6345->map[I2C_IDX_DPTX],
SP_DP_LANE0_LT_CTRL_REG + i, 0);
if (err)
return err;
}
/* Reset AUX */
err = anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM],
SP_RESET_CTRL2_REG, SP_AUX_RST);
if (err)
return err;
return anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM],
SP_RESET_CTRL2_REG, SP_AUX_RST);
}
static void anx6345_poweron(struct anx6345 *anx6345)
{
int err;
/* Ensure reset is asserted before starting power on sequence */
gpiod_set_value_cansleep(anx6345->gpiod_reset, 1);
usleep_range(1000, 2000);
err = regulator_enable(anx6345->dvdd12);
if (err) {
DRM_ERROR("Failed to enable dvdd12 regulator: %d\n",
err);
return;
}
/* T1 - delay between VDD12 and VDD25 should be 0-2ms */
usleep_range(1000, 2000);
err = regulator_enable(anx6345->dvdd25);
if (err) {
DRM_ERROR("Failed to enable dvdd25 regulator: %d\n",
err);
return;
}
/* T2 - delay between RESETN and all power rail stable,
* should be 2-5ms
*/
usleep_range(2000, 5000);
gpiod_set_value_cansleep(anx6345->gpiod_reset, 0);
/* Power on registers module */
anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_POWERDOWN_CTRL_REG,
SP_HDCP_PD | SP_AUDIO_PD | SP_VIDEO_PD | SP_LINK_PD);
anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM], SP_POWERDOWN_CTRL_REG,
SP_REGISTER_PD | SP_TOTAL_PD);
if (anx6345->panel)
drm_panel_prepare(anx6345->panel);
anx6345->powered = true;
}
static void anx6345_poweroff(struct anx6345 *anx6345)
{
int err;
gpiod_set_value_cansleep(anx6345->gpiod_reset, 1);
usleep_range(1000, 2000);
if (anx6345->panel)
drm_panel_unprepare(anx6345->panel);
err = regulator_disable(anx6345->dvdd25);
if (err) {
DRM_ERROR("Failed to disable dvdd25 regulator: %d\n",
err);
return;
}
usleep_range(5000, 10000);
err = regulator_disable(anx6345->dvdd12);
if (err) {
DRM_ERROR("Failed to disable dvdd12 regulator: %d\n",
err);
return;
}
usleep_range(1000, 2000);
anx6345->powered = false;
}
static int anx6345_start(struct anx6345 *anx6345)
{
int err;
if (!anx6345->powered)
anx6345_poweron(anx6345);
/* Power on needed modules */
err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM],
SP_POWERDOWN_CTRL_REG,
SP_VIDEO_PD | SP_LINK_PD);
err = anx6345_tx_initialization(anx6345);
if (err) {
DRM_ERROR("Failed eDP transmitter initialization: %d\n", err);
anx6345_poweroff(anx6345);
return err;
}
err = anx6345_dp_link_training(anx6345);
if (err) {
DRM_ERROR("Failed link training: %d\n", err);
anx6345_poweroff(anx6345);
return err;
}
/*
* This delay seems to help keep the hardware in a good state. Without
* it, there are times where it fails silently.
*/
usleep_range(10000, 15000);
return 0;
}
static int anx6345_config_dp_output(struct anx6345 *anx6345)
{
int err;
err = anx6345_clear_bits(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL1_REG,
SP_VIDEO_MUTE);
if (err)
return err;
/* Enable DP output */
err = anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_VID_CTRL1_REG,
SP_VIDEO_EN);
if (err)
return err;
/* Force stream valid */
return anx6345_set_bits(anx6345->map[I2C_IDX_DPTX],
SP_DP_SYSTEM_CTRL_BASE + 3,
SP_STRM_FORCE | SP_STRM_CTRL);
}
static int anx6345_get_downstream_info(struct anx6345 *anx6345)
{
u8 value;
int err;
err = drm_dp_dpcd_readb(&anx6345->aux, DP_SINK_COUNT, &value);
if (err < 0) {
DRM_ERROR("Get sink count failed %d\n", err);
return err;
}
if (!DP_GET_SINK_COUNT(value)) {
DRM_ERROR("Downstream disconnected\n");
return -EIO;
}
return 0;
}
static int anx6345_get_modes(struct drm_connector *connector)
{
struct anx6345 *anx6345 = connector_to_anx6345(connector);
int err, num_modes = 0;
bool power_off = false;
mutex_lock(&anx6345->lock);
if (!anx6345->edid) {
if (!anx6345->powered) {
anx6345_poweron(anx6345);
power_off = true;
}
err = anx6345_get_downstream_info(anx6345);
if (err) {
DRM_ERROR("Failed to get downstream info: %d\n", err);
goto unlock;
}
anx6345->edid = drm_get_edid(connector, &anx6345->aux.ddc);
if (!anx6345->edid)
DRM_ERROR("Failed to read EDID from panel\n");
err = drm_connector_update_edid_property(connector,
anx6345->edid);
if (err) {
DRM_ERROR("Failed to update EDID property: %d\n", err);
goto unlock;
}
}
num_modes += drm_add_edid_modes(connector, anx6345->edid);
/* Driver currently supports only 6bpc */
connector->display_info.bpc = 6;
unlock:
if (power_off)
anx6345_poweroff(anx6345);
mutex_unlock(&anx6345->lock);
if (!num_modes && anx6345->panel)
num_modes += drm_panel_get_modes(anx6345->panel, connector);
return num_modes;
}
static const struct drm_connector_helper_funcs anx6345_connector_helper_funcs = {
.get_modes = anx6345_get_modes,
};
static void
anx6345_connector_destroy(struct drm_connector *connector)
{
drm_connector_cleanup(connector);
}
static const struct drm_connector_funcs anx6345_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = anx6345_connector_destroy,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static int anx6345_bridge_attach(struct drm_bridge *bridge,
enum drm_bridge_attach_flags flags)
{
struct anx6345 *anx6345 = bridge_to_anx6345(bridge);
int err;
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
DRM_ERROR("Fix bridge driver to make connector optional!");
return -EINVAL;
}
if (!bridge->encoder) {
DRM_ERROR("Parent encoder object not found");
return -ENODEV;
}
/* Register aux channel */
anx6345->aux.name = "DP-AUX";
anx6345->aux.dev = &anx6345->client->dev;
anx6345->aux.drm_dev = bridge->dev;
anx6345->aux.transfer = anx6345_aux_transfer;
err = drm_dp_aux_register(&anx6345->aux);
if (err < 0) {
DRM_ERROR("Failed to register aux channel: %d\n", err);
return err;
}
err = drm_connector_init(bridge->dev, &anx6345->connector,
&anx6345_connector_funcs,
DRM_MODE_CONNECTOR_eDP);
if (err) {
DRM_ERROR("Failed to initialize connector: %d\n", err);
goto aux_unregister;
}
drm_connector_helper_add(&anx6345->connector,
&anx6345_connector_helper_funcs);
anx6345->connector.polled = DRM_CONNECTOR_POLL_HPD;
err = drm_connector_attach_encoder(&anx6345->connector,
bridge->encoder);
if (err) {
DRM_ERROR("Failed to link up connector to encoder: %d\n", err);
goto connector_cleanup;
}
err = drm_connector_register(&anx6345->connector);
if (err) {
DRM_ERROR("Failed to register connector: %d\n", err);
goto connector_cleanup;
}
return 0;
connector_cleanup:
drm_connector_cleanup(&anx6345->connector);
aux_unregister:
drm_dp_aux_unregister(&anx6345->aux);
return err;
}
static void anx6345_bridge_detach(struct drm_bridge *bridge)
{
drm_dp_aux_unregister(&bridge_to_anx6345(bridge)->aux);
}
static enum drm_mode_status
anx6345_bridge_mode_valid(struct drm_bridge *bridge,
const struct drm_display_info *info,
const struct drm_display_mode *mode)
{
if (mode->flags & DRM_MODE_FLAG_INTERLACE)
return MODE_NO_INTERLACE;
/* Max 1200p at 5.4 Ghz, one lane */
if (mode->clock > 154000)
return MODE_CLOCK_HIGH;
return MODE_OK;
}
static void anx6345_bridge_disable(struct drm_bridge *bridge)
{
struct anx6345 *anx6345 = bridge_to_anx6345(bridge);
/* Power off all modules except configuration registers access */
anx6345_set_bits(anx6345->map[I2C_IDX_TXCOM], SP_POWERDOWN_CTRL_REG,
SP_HDCP_PD | SP_AUDIO_PD | SP_VIDEO_PD | SP_LINK_PD);
if (anx6345->panel)
drm_panel_disable(anx6345->panel);
if (anx6345->powered)
anx6345_poweroff(anx6345);
}
static void anx6345_bridge_enable(struct drm_bridge *bridge)
{
struct anx6345 *anx6345 = bridge_to_anx6345(bridge);
int err;
if (anx6345->panel)
drm_panel_enable(anx6345->panel);
err = anx6345_start(anx6345);
if (err) {
DRM_ERROR("Failed to initialize: %d\n", err);
return;
}
err = anx6345_config_dp_output(anx6345);
if (err)
DRM_ERROR("Failed to enable DP output: %d\n", err);
}
static const struct drm_bridge_funcs anx6345_bridge_funcs = {
.attach = anx6345_bridge_attach,
.detach = anx6345_bridge_detach,
.mode_valid = anx6345_bridge_mode_valid,
.disable = anx6345_bridge_disable,
.enable = anx6345_bridge_enable,
};
static void unregister_i2c_dummy_clients(struct anx6345 *anx6345)
{
unsigned int i;
for (i = 1; i < ARRAY_SIZE(anx6345->i2c_clients); i++)
if (anx6345->i2c_clients[i] &&
anx6345->i2c_clients[i]->addr != anx6345->client->addr)
i2c_unregister_device(anx6345->i2c_clients[i]);
}
static const struct regmap_config anx6345_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0xff,
.cache_type = REGCACHE_NONE,
};
static const u16 anx6345_chipid_list[] = {
0x6345,
};
static bool anx6345_get_chip_id(struct anx6345 *anx6345)
{
unsigned int i, idl, idh, version;
if (regmap_read(anx6345->map[I2C_IDX_TXCOM], SP_DEVICE_IDL_REG, &idl))
return false;
if (regmap_read(anx6345->map[I2C_IDX_TXCOM], SP_DEVICE_IDH_REG, &idh))
return false;
anx6345->chipid = (u8)idl | ((u8)idh << 8);
if (regmap_read(anx6345->map[I2C_IDX_TXCOM], SP_DEVICE_VERSION_REG,
&version))
return false;
for (i = 0; i < ARRAY_SIZE(anx6345_chipid_list); i++) {
if (anx6345->chipid == anx6345_chipid_list[i]) {
DRM_INFO("Found ANX%x (ver. %d) eDP Transmitter\n",
anx6345->chipid, version);
return true;
}
}
DRM_ERROR("ANX%x (ver. %d) not supported by this driver\n",
anx6345->chipid, version);
return false;
}
static int anx6345_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct anx6345 *anx6345;
struct device *dev;
int i, err;
anx6345 = devm_kzalloc(&client->dev, sizeof(*anx6345), GFP_KERNEL);
if (!anx6345)
return -ENOMEM;
mutex_init(&anx6345->lock);
anx6345->bridge.of_node = client->dev.of_node;
anx6345->client = client;
i2c_set_clientdata(client, anx6345);
dev = &anx6345->client->dev;
err = drm_of_find_panel_or_bridge(client->dev.of_node, 1, 0,
&anx6345->panel, NULL);
if (err == -EPROBE_DEFER)
return err;
if (err)
DRM_DEBUG("No panel found\n");
/* 1.2V digital core power regulator */
anx6345->dvdd12 = devm_regulator_get(dev, "dvdd12");
if (IS_ERR(anx6345->dvdd12)) {
if (PTR_ERR(anx6345->dvdd12) != -EPROBE_DEFER)
DRM_ERROR("Failed to get dvdd12 supply (%ld)\n",
PTR_ERR(anx6345->dvdd12));
return PTR_ERR(anx6345->dvdd12);
}
/* 2.5V digital core power regulator */
anx6345->dvdd25 = devm_regulator_get(dev, "dvdd25");
if (IS_ERR(anx6345->dvdd25)) {
if (PTR_ERR(anx6345->dvdd25) != -EPROBE_DEFER)
DRM_ERROR("Failed to get dvdd25 supply (%ld)\n",
PTR_ERR(anx6345->dvdd25));
return PTR_ERR(anx6345->dvdd25);
}
/* GPIO for chip reset */
anx6345->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(anx6345->gpiod_reset)) {
DRM_ERROR("Reset gpio not found\n");
return PTR_ERR(anx6345->gpiod_reset);
}
/* Map slave addresses of ANX6345 */
for (i = 0; i < I2C_NUM_ADDRESSES; i++) {
if (anx6345_i2c_addresses[i] >> 1 != client->addr)
anx6345->i2c_clients[i] = i2c_new_dummy_device(client->adapter,
anx6345_i2c_addresses[i] >> 1);
else
anx6345->i2c_clients[i] = client;
if (IS_ERR(anx6345->i2c_clients[i])) {
err = PTR_ERR(anx6345->i2c_clients[i]);
DRM_ERROR("Failed to reserve I2C bus %02x\n",
anx6345_i2c_addresses[i]);
goto err_unregister_i2c;
}
anx6345->map[i] = devm_regmap_init_i2c(anx6345->i2c_clients[i],
&anx6345_regmap_config);
if (IS_ERR(anx6345->map[i])) {
err = PTR_ERR(anx6345->map[i]);
DRM_ERROR("Failed regmap initialization %02x\n",
anx6345_i2c_addresses[i]);
goto err_unregister_i2c;
}
}
/* Look for supported chip ID */
anx6345_poweron(anx6345);
if (anx6345_get_chip_id(anx6345)) {
anx6345->bridge.funcs = &anx6345_bridge_funcs;
drm_bridge_add(&anx6345->bridge);
return 0;
} else {
anx6345_poweroff(anx6345);
err = -ENODEV;
}
err_unregister_i2c:
unregister_i2c_dummy_clients(anx6345);
return err;
}
static void anx6345_i2c_remove(struct i2c_client *client)
{
struct anx6345 *anx6345 = i2c_get_clientdata(client);
drm_bridge_remove(&anx6345->bridge);
unregister_i2c_dummy_clients(anx6345);
kfree(anx6345->edid);
mutex_destroy(&anx6345->lock);
}
static const struct i2c_device_id anx6345_id[] = {
{ "anx6345", 0 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, anx6345_id);
static const struct of_device_id anx6345_match_table[] = {
{ .compatible = "analogix,anx6345", },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, anx6345_match_table);
static struct i2c_driver anx6345_driver = {
.driver = {
.name = "anx6345",
.of_match_table = of_match_ptr(anx6345_match_table),
},
.probe = anx6345_i2c_probe,
.remove = anx6345_i2c_remove,
.id_table = anx6345_id,
};
module_i2c_driver(anx6345_driver);
MODULE_DESCRIPTION("ANX6345 eDP Transmitter driver");
MODULE_AUTHOR("Icenowy Zheng <icenowy@aosc.io>");
MODULE_LICENSE("GPL v2");