summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/bridge/ite-it66121.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/bridge/ite-it66121.c')
-rw-r--r--drivers/gpu/drm/bridge/ite-it66121.c147
1 files changed, 74 insertions, 73 deletions
diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c
index 466641c77fe9..0185f61e6e59 100644
--- a/drivers/gpu/drm/bridge/ite-it66121.c
+++ b/drivers/gpu/drm/bridge/ite-it66121.c
@@ -287,6 +287,7 @@
enum chip_id {
ID_IT6610,
ID_IT66121,
+ ID_IT66122,
};
struct it66121_chip_info {
@@ -312,7 +313,7 @@ struct it66121_ctx {
u8 swl;
bool auto_cts;
} audio;
- const struct it66121_chip_info *info;
+ enum chip_id id;
};
static const struct regmap_range_cfg it66121_regmap_banks[] = {
@@ -402,7 +403,7 @@ static int it66121_configure_afe(struct it66121_ctx *ctx,
if (ret)
return ret;
- if (ctx->info->id == ID_IT66121) {
+ if (ctx->id == ID_IT66121 || ctx->id == ID_IT66122) {
ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG,
IT66121_AFE_IP_EC1, 0);
if (ret)
@@ -428,7 +429,7 @@ static int it66121_configure_afe(struct it66121_ctx *ctx,
if (ret)
return ret;
- if (ctx->info->id == ID_IT66121) {
+ if (ctx->id == ID_IT66121 || ctx->id == ID_IT66122) {
ret = regmap_write_bits(ctx->regmap, IT66121_AFE_IP_REG,
IT66121_AFE_IP_EC1,
IT66121_AFE_IP_EC1);
@@ -449,7 +450,7 @@ static int it66121_configure_afe(struct it66121_ctx *ctx,
if (ret)
return ret;
- if (ctx->info->id == ID_IT6610) {
+ if (ctx->id == ID_IT6610) {
ret = regmap_write_bits(ctx->regmap, IT66121_AFE_XP_REG,
IT6610_AFE_XP_BYPASS,
IT6610_AFE_XP_BYPASS);
@@ -586,6 +587,7 @@ static bool it66121_is_hpd_detect(struct it66121_ctx *ctx)
}
static int it66121_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
@@ -594,11 +596,11 @@ static int it66121_bridge_attach(struct drm_bridge *bridge,
if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
return -EINVAL;
- ret = drm_bridge_attach(bridge->encoder, ctx->next_bridge, bridge, flags);
+ ret = drm_bridge_attach(encoder, ctx->next_bridge, bridge, flags);
if (ret)
return ret;
- if (ctx->info->id == ID_IT66121) {
+ if (ctx->id == ID_IT66121 || ctx->id == ID_IT66122) {
ret = regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
IT66121_CLK_BANK_PWROFF_RCLK, 0);
if (ret)
@@ -721,10 +723,9 @@ static u32 *it66121_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
}
static void it66121_bridge_enable(struct drm_bridge *bridge,
- struct drm_bridge_state *bridge_state)
+ struct drm_atomic_state *state)
{
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
- struct drm_atomic_state *state = bridge_state->base.state;
ctx->connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
@@ -732,7 +733,7 @@ static void it66121_bridge_enable(struct drm_bridge *bridge,
}
static void it66121_bridge_disable(struct drm_bridge *bridge,
- struct drm_bridge_state *bridge_state)
+ struct drm_atomic_state *state)
{
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
@@ -748,7 +749,7 @@ static int it66121_bridge_check(struct drm_bridge *bridge,
{
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
- if (ctx->info->id == ID_IT6610) {
+ if (ctx->id == ID_IT6610) {
/* The IT6610 only supports these settings */
bridge_state->input_bus_cfg.flags |= DRM_BUS_FLAG_DE_HIGH |
DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE;
@@ -770,8 +771,6 @@ void it66121_bridge_mode_set(struct drm_bridge *bridge,
mutex_lock(&ctx->lock);
- hdmi_avi_infoframe_init(&ctx->hdmi_avi_infoframe);
-
ret = drm_hdmi_avi_infoframe_from_display_mode(&ctx->hdmi_avi_infoframe, ctx->connector,
adjusted_mode);
if (ret) {
@@ -804,7 +803,7 @@ void it66121_bridge_mode_set(struct drm_bridge *bridge,
if (regmap_write(ctx->regmap, IT66121_HDMI_MODE_REG, IT66121_HDMI_MODE_HDMI))
goto unlock;
- if (ctx->info->id == ID_IT66121 &&
+ if ((ctx->id == ID_IT66121 || ctx->id == ID_IT66122) &&
regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
IT66121_CLK_BANK_PWROFF_TXCLK,
IT66121_CLK_BANK_PWROFF_TXCLK)) {
@@ -817,7 +816,7 @@ void it66121_bridge_mode_set(struct drm_bridge *bridge,
if (it66121_configure_afe(ctx, adjusted_mode))
goto unlock;
- if (ctx->info->id == ID_IT66121 &&
+ if ((ctx->id == ID_IT66121 || ctx->id == ID_IT66122) &&
regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
IT66121_CLK_BANK_PWROFF_TXCLK, 0)) {
goto unlock;
@@ -845,7 +844,8 @@ static enum drm_mode_status it66121_bridge_mode_valid(struct drm_bridge *bridge,
return MODE_OK;
}
-static enum drm_connector_status it66121_bridge_detect(struct drm_bridge *bridge)
+static enum drm_connector_status
+it66121_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector)
{
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
@@ -874,33 +874,33 @@ static void it66121_bridge_hpd_disable(struct drm_bridge *bridge)
dev_err(ctx->dev, "failed to disable HPD IRQ\n");
}
-static struct edid *it66121_bridge_get_edid(struct drm_bridge *bridge,
- struct drm_connector *connector)
+static const struct drm_edid *it66121_bridge_edid_read(struct drm_bridge *bridge,
+ struct drm_connector *connector)
{
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
- struct edid *edid;
+ const struct drm_edid *drm_edid;
int ret;
mutex_lock(&ctx->lock);
ret = it66121_preamble_ddc(ctx);
if (ret) {
- edid = ERR_PTR(ret);
+ drm_edid = NULL;
goto out_unlock;
}
ret = regmap_write(ctx->regmap, IT66121_DDC_HEADER_REG,
IT66121_DDC_HEADER_EDID);
if (ret) {
- edid = ERR_PTR(ret);
+ drm_edid = NULL;
goto out_unlock;
}
- edid = drm_do_get_edid(connector, it66121_get_edid_block, ctx);
+ drm_edid = drm_edid_read_custom(connector, it66121_get_edid_block, ctx);
out_unlock:
mutex_unlock(&ctx->lock);
- return edid;
+ return drm_edid;
}
static const struct drm_bridge_funcs it66121_bridge_funcs = {
@@ -916,7 +916,7 @@ static const struct drm_bridge_funcs it66121_bridge_funcs = {
.mode_set = it66121_bridge_mode_set,
.mode_valid = it66121_bridge_mode_valid,
.detect = it66121_bridge_detect,
- .get_edid = it66121_bridge_get_edid,
+ .edid_read = it66121_bridge_edid_read,
.hpd_enable = it66121_bridge_hpd_enable,
.hpd_disable = it66121_bridge_hpd_disable,
};
@@ -1385,8 +1385,6 @@ static int it66121_audio_startup(struct device *dev, void *data)
int ret;
struct it66121_ctx *ctx = dev_get_drvdata(dev);
- dev_dbg(dev, "%s\n", __func__);
-
mutex_lock(&ctx->lock);
ret = it661221_audio_output_enable(ctx, true);
if (ret)
@@ -1402,8 +1400,6 @@ static void it66121_audio_shutdown(struct device *dev, void *data)
int ret;
struct it66121_ctx *ctx = dev_get_drvdata(dev);
- dev_dbg(dev, "%s\n", __func__);
-
mutex_lock(&ctx->lock);
ret = it661221_audio_output_enable(ctx, false);
if (ret)
@@ -1447,10 +1443,16 @@ static int it66121_audio_get_eld(struct device *dev, void *data,
struct it66121_ctx *ctx = dev_get_drvdata(dev);
mutex_lock(&ctx->lock);
-
- memcpy(buf, ctx->connector->eld,
- min(sizeof(ctx->connector->eld), len));
-
+ if (!ctx->connector) {
+ /* Pass en empty ELD if connector not available */
+ dev_dbg(dev, "No connector present, passing empty EDID data");
+ memset(buf, 0, len);
+ } else {
+ mutex_lock(&ctx->connector->eld_mutex);
+ memcpy(buf, ctx->connector->eld,
+ min(sizeof(ctx->connector->eld), len));
+ mutex_unlock(&ctx->connector->eld_mutex);
+ }
mutex_unlock(&ctx->lock);
return 0;
@@ -1462,7 +1464,6 @@ static const struct hdmi_codec_ops it66121_audio_codec_ops = {
.audio_shutdown = it66121_audio_shutdown,
.mute_stream = it66121_audio_mute,
.get_eld = it66121_audio_get_eld,
- .no_capture_mute = 1,
};
static int it66121_audio_codec_init(struct it66121_ctx *ctx, struct device *dev)
@@ -1472,11 +1473,10 @@ static int it66121_audio_codec_init(struct it66121_ctx *ctx, struct device *dev)
.i2s = 1, /* Only i2s support for now */
.spdif = 0,
.max_i2s_channels = 8,
+ .no_capture_mute = 1,
};
- dev_dbg(dev, "%s\n", __func__);
-
- if (!of_property_read_bool(dev->of_node, "#sound-dai-cells")) {
+ if (!of_property_present(dev->of_node, "#sound-dai-cells")) {
dev_info(dev, "No \"#sound-dai-cells\", no audio\n");
return 0;
}
@@ -1499,23 +1499,30 @@ static const char * const it66121_supplies[] = {
"vcn33", "vcn18", "vrf12"
};
+static const struct it66121_chip_info it66xx_chip_info[] = {
+ {.id = ID_IT6610, .vid = 0xca00, .pid = 0x0611 },
+ {.id = ID_IT66121, .vid = 0x4954, .pid = 0x0612 },
+ {.id = ID_IT66122, .vid = 0x4954, .pid = 0x0622 },
+};
+
static int it66121_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
u32 revision_id, vendor_ids[2] = { 0 }, device_ids[2] = { 0 };
struct device_node *ep;
- int ret;
+ int ret, i;
struct it66121_ctx *ctx;
struct device *dev = &client->dev;
+ const struct it66121_chip_info *chip_info;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(dev, "I2C check functionality failed.\n");
return -ENXIO;
}
- ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
- if (!ctx)
- return -ENOMEM;
+ ctx = devm_drm_bridge_alloc(dev, struct it66121_ctx, bridge,
+ &it66121_bridge_funcs);
+ if (IS_ERR(ctx))
+ return PTR_ERR(ctx);
ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0);
if (!ep)
@@ -1523,7 +1530,6 @@ static int it66121_probe(struct i2c_client *client)
ctx->dev = dev;
ctx->client = client;
- ctx->info = (const struct it66121_chip_info *) id->driver_data;
of_property_read_u32(ep, "bus-width", &ctx->bus_width);
of_node_put(ep);
@@ -1537,12 +1543,6 @@ static int it66121_probe(struct i2c_client *client)
return -EINVAL;
}
- if (!of_device_is_available(ep)) {
- of_node_put(ep);
- dev_err(ctx->dev, "The remote device is disabled\n");
- return -ENODEV;
- }
-
ctx->next_bridge = of_drm_find_bridge(ep);
of_node_put(ep);
if (!ctx->next_bridge) {
@@ -1575,21 +1575,32 @@ static int it66121_probe(struct i2c_client *client)
revision_id = FIELD_GET(IT66121_REVISION_MASK, device_ids[1]);
device_ids[1] &= IT66121_DEVICE_ID1_MASK;
- if ((vendor_ids[1] << 8 | vendor_ids[0]) != ctx->info->vid ||
- (device_ids[1] << 8 | device_ids[0]) != ctx->info->pid) {
- return -ENODEV;
+ for (i = 0; i < ARRAY_SIZE(it66xx_chip_info); i++) {
+ chip_info = &it66xx_chip_info[i];
+ if ((vendor_ids[1] << 8 | vendor_ids[0]) == chip_info->vid &&
+ (device_ids[1] << 8 | device_ids[0]) == chip_info->pid) {
+ ctx->id = chip_info->id;
+ break;
+ }
}
- ctx->bridge.funcs = &it66121_bridge_funcs;
+ if (i == ARRAY_SIZE(it66xx_chip_info))
+ return -ENODEV;
+
ctx->bridge.of_node = dev->of_node;
ctx->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
- ctx->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_HPD;
-
- ret = devm_request_threaded_irq(dev, client->irq, NULL, it66121_irq_threaded_handler,
- IRQF_ONESHOT, dev_name(dev), ctx);
- if (ret < 0) {
- dev_err(dev, "Failed to request irq %d:%d\n", client->irq, ret);
- return ret;
+ ctx->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID;
+ if (client->irq > 0) {
+ ctx->bridge.ops |= DRM_BRIDGE_OP_HPD;
+
+ ret = devm_request_threaded_irq(dev, client->irq, NULL,
+ it66121_irq_threaded_handler,
+ IRQF_ONESHOT, dev_name(dev),
+ ctx);
+ if (ret < 0) {
+ dev_err(dev, "Failed to request irq %d:%d\n", client->irq, ret);
+ return ret;
+ }
}
it66121_audio_codec_init(ctx, dev);
@@ -1610,27 +1621,17 @@ static void it66121_remove(struct i2c_client *client)
}
static const struct of_device_id it66121_dt_match[] = {
- { .compatible = "ite,it66121" },
{ .compatible = "ite,it6610" },
+ { .compatible = "ite,it66121" },
+ { .compatible = "ite,it66122" },
{ }
};
MODULE_DEVICE_TABLE(of, it66121_dt_match);
-static const struct it66121_chip_info it66121_chip_info = {
- .id = ID_IT66121,
- .vid = 0x4954,
- .pid = 0x0612,
-};
-
-static const struct it66121_chip_info it6610_chip_info = {
- .id = ID_IT6610,
- .vid = 0xca00,
- .pid = 0x0611,
-};
-
static const struct i2c_device_id it66121_id[] = {
- { "it66121", (kernel_ulong_t) &it66121_chip_info },
- { "it6610", (kernel_ulong_t) &it6610_chip_info },
+ { .name = "it6610" },
+ { .name = "it66121" },
+ { .name = "it66122" },
{ }
};
MODULE_DEVICE_TABLE(i2c, it66121_id);