aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSrinivas Kandagatla <srinivas.kandagatla@linaro.org>2019-04-17 14:23:42 +0100
committerVinod Koul <vkoul@kernel.org>2020-04-13 12:30:35 +0530
commitda5cf02ca302c25ff06686c7ebf0563f1b62bd82 (patch)
tree86a1a6f1e8211cb1c4992871be6bb68cba06bc78
parent58bf70f8cf3f66804b8a40f0e7481a192f10479a (diff)
drm/bridge: lt9611: Add hdmi audio codec support
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
-rw-r--r--drivers/gpu/drm/bridge/Kconfig1
-rw-r--r--drivers/gpu/drm/bridge/lt9611.c120
2 files changed, 101 insertions, 20 deletions
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 52c1ac0da1b1..2dd87209120d 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -40,6 +40,7 @@ config DRM_DISPLAY_CONNECTOR
config DRM_LONTIUM_LT9611
tristate "Lontium LT9611 DSI/HDMI bridge"
+ select SND_SOC_HDMI_CODEC if SND_SOC
depends on OF
select DRM_PANEL_BRIDGE
select DRM_KMS_HELPER
diff --git a/drivers/gpu/drm/bridge/lt9611.c b/drivers/gpu/drm/bridge/lt9611.c
index 348ec76a3a3d..748ff21fcd17 100644
--- a/drivers/gpu/drm/bridge/lt9611.c
+++ b/drivers/gpu/drm/bridge/lt9611.c
@@ -19,6 +19,11 @@
#include <linux/regmap.h>
#include <linux/interrupt.h>
#include <linux/component.h>
+#include <sound/hdmi-codec.h>
+#include <sound/core.h>
+#include <sound/hdmi-codec.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
#include <linux/of_gpio.h>
#include <linux/of_graph.h>
#include <linux/of_irq.h>
@@ -46,6 +51,7 @@ struct lt9611 {
struct device_node *dsi1_node;
struct mipi_dsi_device *dsi0;
struct mipi_dsi_device *dsi1;
+ struct platform_device *audio_pdev;
bool ac_mode;
@@ -543,23 +549,6 @@ static int lt9611_power_off(struct lt9611 *lt9611)
return ret;
}
-static void lt9611_i2s_init(struct lt9611 *lt9611)
-{
- const struct reg_sequence init[] = {
- { 0xff, 0x82 },
- { 0xd6, 0x8c },
- { 0xd7, 0x04 },
-
- { 0xff, 0x84 },
- { 0x06, 0x08 },
- { 0x07, 0x10 },
-
- { 0x34, 0xd4 },
- };
-
- regmap_multi_reg_write(lt9611->regmap, init, ARRAY_SIZE(init));
-}
-
static void lt9611_reset(struct lt9611 *lt9611)
{
gpiod_set_value_cansleep(lt9611->reset_gpio, 1);
@@ -1034,6 +1023,98 @@ static int lt9611_read_device_rev(struct lt9611 *lt9611)
return ret;
}
+int lt9611_hdmi_hw_params(struct device *dev, void *data,
+ struct hdmi_codec_daifmt *fmt,
+ struct hdmi_codec_params *hparms)
+{
+ return 0;
+}
+
+static int lt9611_audio_startup(struct device *dev, void *data)
+{
+ struct lt9611 *lt9611 = data;
+ const struct reg_sequence init[] = {
+ { 0xff, 0x82 },
+ { 0xd6, 0x8c },
+ { 0xd7, 0x04 },
+
+ { 0xff, 0x84 },
+ { 0x06, 0x18 },
+ { 0x07, 0xf0 },
+
+ { 0x34, 0xd4 },
+ };
+
+ regmap_multi_reg_write(lt9611->regmap, init, ARRAY_SIZE(init));
+
+ return 0;
+}
+
+static void lt9611_audio_shutdown(struct device *dev, void *data)
+{
+ struct lt9611 *lt9611 = data;
+ const struct reg_sequence exit[] = {
+ { 0xff, 0x84 },
+ { 0x06, 0x00 },
+ { 0x07, 0x00 },
+ };
+
+ regmap_multi_reg_write(lt9611->regmap, exit, ARRAY_SIZE(exit));
+}
+
+static int lt9611_hdmi_i2s_get_dai_id(struct snd_soc_component *component,
+ struct device_node *endpoint)
+{
+ struct of_endpoint of_ep;
+ int ret;
+
+pr_err("DEBUG: %s: %d \n", __func__, __LINE__);
+ ret = of_graph_parse_endpoint(endpoint, &of_ep);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * HDMI sound should be located as reg = <2>
+ * Then, it is sound port 0
+ */
+ if (of_ep.port == 2)
+ return 0;
+
+ return -EINVAL;
+}
+
+static const struct hdmi_codec_ops lt9611_codec_ops = {
+ .hw_params = lt9611_hdmi_hw_params,
+ .audio_shutdown = lt9611_audio_shutdown,
+ .audio_startup = lt9611_audio_startup,
+ .get_dai_id = lt9611_hdmi_i2s_get_dai_id,
+};
+
+static struct hdmi_codec_pdata codec_data = {
+ .ops = &lt9611_codec_ops,
+ .max_i2s_channels = 8,
+ .i2s = 1,
+};
+
+int lt9611_audio_init(struct device *dev, struct lt9611 *lt9611)
+{
+ codec_data.data = lt9611;
+ lt9611->audio_pdev = platform_device_register_data(dev,
+ HDMI_CODEC_DRV_NAME,
+ PLATFORM_DEVID_AUTO,
+ &codec_data,
+ sizeof(codec_data));
+ return PTR_ERR_OR_ZERO(lt9611->audio_pdev);
+}
+
+void lt9611_audio_exit(struct lt9611 *lt9611)
+{
+ if (lt9611->audio_pdev) {
+ platform_device_unregister(lt9611->audio_pdev);
+ lt9611->audio_pdev = NULL;
+ }
+}
+
static int lt9611_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -1087,7 +1168,6 @@ static int lt9611_probe(struct i2c_client *client,
goto err_disable_regulators;
}
- lt9611_i2s_init(lt9611);
ret = devm_request_threaded_irq(dev, client->irq, NULL,
lt9611_irq_thread_handler,
@@ -1106,7 +1186,7 @@ static int lt9611_probe(struct i2c_client *client,
lt9611_enable_hpd_interrupts(lt9611);
- return 0;
+ return lt9611_audio_init(dev, lt9611);
err_disable_regulators:
regulator_bulk_disable(ARRAY_SIZE(lt9611->supplies), lt9611->supplies);
@@ -1122,7 +1202,7 @@ static int lt9611_remove(struct i2c_client *client)
struct lt9611 *lt9611 = i2c_get_clientdata(client);
disable_irq(client->irq);
-
+ lt9611_audio_exit(lt9611);
drm_bridge_remove(&lt9611->bridge);
regulator_bulk_disable(ARRAY_SIZE(lt9611->supplies), lt9611->supplies);