10cbbd5b1SDmitry Baryshkov // SPDX-License-Identifier: GPL-2.0
20cbbd5b1SDmitry Baryshkov /*
30cbbd5b1SDmitry Baryshkov  * Copyright (c) 2018, The Linux Foundation. All rights reserved.
40cbbd5b1SDmitry Baryshkov  * Copyright (c) 2019-2020. Linaro Limited.
50cbbd5b1SDmitry Baryshkov  */
60cbbd5b1SDmitry Baryshkov 
70cbbd5b1SDmitry Baryshkov #include <linux/firmware.h>
80cbbd5b1SDmitry Baryshkov #include <linux/gpio/consumer.h>
9a204f974SVille Syrjälä #include <linux/i2c.h>
100cbbd5b1SDmitry Baryshkov #include <linux/interrupt.h>
110cbbd5b1SDmitry Baryshkov #include <linux/module.h>
120cbbd5b1SDmitry Baryshkov #include <linux/mutex.h>
130cbbd5b1SDmitry Baryshkov #include <linux/of_graph.h>
140cbbd5b1SDmitry Baryshkov #include <linux/platform_device.h>
150cbbd5b1SDmitry Baryshkov #include <linux/regmap.h>
160cbbd5b1SDmitry Baryshkov #include <linux/regulator/consumer.h>
170cbbd5b1SDmitry Baryshkov #include <linux/wait.h>
18bc6fa867SDmitry Baryshkov #include <linux/workqueue.h>
190cbbd5b1SDmitry Baryshkov 
200cbbd5b1SDmitry Baryshkov #include <sound/hdmi-codec.h>
210cbbd5b1SDmitry Baryshkov 
220cbbd5b1SDmitry Baryshkov #include <drm/drm_atomic_helper.h>
230cbbd5b1SDmitry Baryshkov #include <drm/drm_bridge.h>
24a05f7279SJani Nikula #include <drm/drm_edid.h>
250cbbd5b1SDmitry Baryshkov #include <drm/drm_mipi_dsi.h>
260cbbd5b1SDmitry Baryshkov #include <drm/drm_print.h>
270cbbd5b1SDmitry Baryshkov #include <drm/drm_probe_helper.h>
280cbbd5b1SDmitry Baryshkov 
290cbbd5b1SDmitry Baryshkov #define EDID_BLOCK_SIZE	128
300cbbd5b1SDmitry Baryshkov #define EDID_NUM_BLOCKS	2
310cbbd5b1SDmitry Baryshkov 
32354c0fb6SJuerg Haefliger #define FW_FILE "lt9611uxc_fw.bin"
33354c0fb6SJuerg Haefliger 
340cbbd5b1SDmitry Baryshkov struct lt9611uxc {
350cbbd5b1SDmitry Baryshkov 	struct device *dev;
360cbbd5b1SDmitry Baryshkov 	struct drm_bridge bridge;
370cbbd5b1SDmitry Baryshkov 	struct drm_connector connector;
380cbbd5b1SDmitry Baryshkov 
390cbbd5b1SDmitry Baryshkov 	struct regmap *regmap;
400cbbd5b1SDmitry Baryshkov 	/* Protects all accesses to registers by stopping the on-chip MCU */
410cbbd5b1SDmitry Baryshkov 	struct mutex ocm_lock;
420cbbd5b1SDmitry Baryshkov 
430cbbd5b1SDmitry Baryshkov 	struct wait_queue_head wq;
44bc6fa867SDmitry Baryshkov 	struct work_struct work;
450cbbd5b1SDmitry Baryshkov 
460cbbd5b1SDmitry Baryshkov 	struct device_node *dsi0_node;
470cbbd5b1SDmitry Baryshkov 	struct device_node *dsi1_node;
480cbbd5b1SDmitry Baryshkov 	struct mipi_dsi_device *dsi0;
490cbbd5b1SDmitry Baryshkov 	struct mipi_dsi_device *dsi1;
500cbbd5b1SDmitry Baryshkov 	struct platform_device *audio_pdev;
510cbbd5b1SDmitry Baryshkov 
520cbbd5b1SDmitry Baryshkov 	struct gpio_desc *reset_gpio;
530cbbd5b1SDmitry Baryshkov 	struct gpio_desc *enable_gpio;
540cbbd5b1SDmitry Baryshkov 
550cbbd5b1SDmitry Baryshkov 	struct regulator_bulk_data supplies[2];
560cbbd5b1SDmitry Baryshkov 
570cbbd5b1SDmitry Baryshkov 	struct i2c_client *client;
580cbbd5b1SDmitry Baryshkov 
590cbbd5b1SDmitry Baryshkov 	bool hpd_supported;
600cbbd5b1SDmitry Baryshkov 	bool edid_read;
61bc6fa867SDmitry Baryshkov 	/* can be accessed from different threads, so protect this with ocm_lock */
62bc6fa867SDmitry Baryshkov 	bool hdmi_connected;
630cbbd5b1SDmitry Baryshkov 	uint8_t fw_version;
640cbbd5b1SDmitry Baryshkov };
650cbbd5b1SDmitry Baryshkov 
660cbbd5b1SDmitry Baryshkov #define LT9611_PAGE_CONTROL	0xff
670cbbd5b1SDmitry Baryshkov 
680cbbd5b1SDmitry Baryshkov static const struct regmap_range_cfg lt9611uxc_ranges[] = {
690cbbd5b1SDmitry Baryshkov 	{
700cbbd5b1SDmitry Baryshkov 		.name = "register_range",
710cbbd5b1SDmitry Baryshkov 		.range_min =  0,
720cbbd5b1SDmitry Baryshkov 		.range_max = 0xd0ff,
730cbbd5b1SDmitry Baryshkov 		.selector_reg = LT9611_PAGE_CONTROL,
740cbbd5b1SDmitry Baryshkov 		.selector_mask = 0xff,
750cbbd5b1SDmitry Baryshkov 		.selector_shift = 0,
760cbbd5b1SDmitry Baryshkov 		.window_start = 0,
770cbbd5b1SDmitry Baryshkov 		.window_len = 0x100,
780cbbd5b1SDmitry Baryshkov 	},
790cbbd5b1SDmitry Baryshkov };
800cbbd5b1SDmitry Baryshkov 
810cbbd5b1SDmitry Baryshkov static const struct regmap_config lt9611uxc_regmap_config = {
820cbbd5b1SDmitry Baryshkov 	.reg_bits = 8,
830cbbd5b1SDmitry Baryshkov 	.val_bits = 8,
840cbbd5b1SDmitry Baryshkov 	.max_register = 0xffff,
850cbbd5b1SDmitry Baryshkov 	.ranges = lt9611uxc_ranges,
860cbbd5b1SDmitry Baryshkov 	.num_ranges = ARRAY_SIZE(lt9611uxc_ranges),
870cbbd5b1SDmitry Baryshkov };
880cbbd5b1SDmitry Baryshkov 
890cbbd5b1SDmitry Baryshkov struct lt9611uxc_mode {
900cbbd5b1SDmitry Baryshkov 	u16 hdisplay;
910cbbd5b1SDmitry Baryshkov 	u16 vdisplay;
920cbbd5b1SDmitry Baryshkov 	u8 vrefresh;
930cbbd5b1SDmitry Baryshkov };
940cbbd5b1SDmitry Baryshkov 
950cbbd5b1SDmitry Baryshkov /*
960cbbd5b1SDmitry Baryshkov  * This chip supports only a fixed set of modes.
970cbbd5b1SDmitry Baryshkov  * Enumerate them here to check whether the mode is supported.
980cbbd5b1SDmitry Baryshkov  */
990cbbd5b1SDmitry Baryshkov static struct lt9611uxc_mode lt9611uxc_modes[] = {
1000cbbd5b1SDmitry Baryshkov 	{ 1920, 1080, 60 },
1010cbbd5b1SDmitry Baryshkov 	{ 1920, 1080, 30 },
1020cbbd5b1SDmitry Baryshkov 	{ 1920, 1080, 25 },
1030cbbd5b1SDmitry Baryshkov 	{ 1366, 768, 60 },
1040cbbd5b1SDmitry Baryshkov 	{ 1360, 768, 60 },
1050cbbd5b1SDmitry Baryshkov 	{ 1280, 1024, 60 },
1060cbbd5b1SDmitry Baryshkov 	{ 1280, 800, 60 },
1070cbbd5b1SDmitry Baryshkov 	{ 1280, 720, 60 },
1080cbbd5b1SDmitry Baryshkov 	{ 1280, 720, 50 },
1090cbbd5b1SDmitry Baryshkov 	{ 1280, 720, 30 },
1100cbbd5b1SDmitry Baryshkov 	{ 1152, 864, 60 },
1110cbbd5b1SDmitry Baryshkov 	{ 1024, 768, 60 },
1120cbbd5b1SDmitry Baryshkov 	{ 800, 600, 60 },
1130cbbd5b1SDmitry Baryshkov 	{ 720, 576, 50 },
1140cbbd5b1SDmitry Baryshkov 	{ 720, 480, 60 },
1150cbbd5b1SDmitry Baryshkov 	{ 640, 480, 60 },
1160cbbd5b1SDmitry Baryshkov };
1170cbbd5b1SDmitry Baryshkov 
bridge_to_lt9611uxc(struct drm_bridge * bridge)1180cbbd5b1SDmitry Baryshkov static struct lt9611uxc *bridge_to_lt9611uxc(struct drm_bridge *bridge)
1190cbbd5b1SDmitry Baryshkov {
1200cbbd5b1SDmitry Baryshkov 	return container_of(bridge, struct lt9611uxc, bridge);
1210cbbd5b1SDmitry Baryshkov }
1220cbbd5b1SDmitry Baryshkov 
connector_to_lt9611uxc(struct drm_connector * connector)1230cbbd5b1SDmitry Baryshkov static struct lt9611uxc *connector_to_lt9611uxc(struct drm_connector *connector)
1240cbbd5b1SDmitry Baryshkov {
1250cbbd5b1SDmitry Baryshkov 	return container_of(connector, struct lt9611uxc, connector);
1260cbbd5b1SDmitry Baryshkov }
1270cbbd5b1SDmitry Baryshkov 
lt9611uxc_lock(struct lt9611uxc * lt9611uxc)1280cbbd5b1SDmitry Baryshkov static void lt9611uxc_lock(struct lt9611uxc *lt9611uxc)
1290cbbd5b1SDmitry Baryshkov {
1300cbbd5b1SDmitry Baryshkov 	mutex_lock(&lt9611uxc->ocm_lock);
1310cbbd5b1SDmitry Baryshkov 	regmap_write(lt9611uxc->regmap, 0x80ee, 0x01);
1320cbbd5b1SDmitry Baryshkov }
1330cbbd5b1SDmitry Baryshkov 
lt9611uxc_unlock(struct lt9611uxc * lt9611uxc)1340cbbd5b1SDmitry Baryshkov static void lt9611uxc_unlock(struct lt9611uxc *lt9611uxc)
1350cbbd5b1SDmitry Baryshkov {
1360cbbd5b1SDmitry Baryshkov 	regmap_write(lt9611uxc->regmap, 0x80ee, 0x00);
1370cbbd5b1SDmitry Baryshkov 	msleep(50);
1380cbbd5b1SDmitry Baryshkov 	mutex_unlock(&lt9611uxc->ocm_lock);
1390cbbd5b1SDmitry Baryshkov }
1400cbbd5b1SDmitry Baryshkov 
lt9611uxc_irq_thread_handler(int irq,void * dev_id)1410cbbd5b1SDmitry Baryshkov static irqreturn_t lt9611uxc_irq_thread_handler(int irq, void *dev_id)
1420cbbd5b1SDmitry Baryshkov {
1430cbbd5b1SDmitry Baryshkov 	struct lt9611uxc *lt9611uxc = dev_id;
1440cbbd5b1SDmitry Baryshkov 	unsigned int irq_status = 0;
1450cbbd5b1SDmitry Baryshkov 	unsigned int hpd_status = 0;
1460cbbd5b1SDmitry Baryshkov 
1470cbbd5b1SDmitry Baryshkov 	lt9611uxc_lock(lt9611uxc);
1480cbbd5b1SDmitry Baryshkov 
1490cbbd5b1SDmitry Baryshkov 	regmap_read(lt9611uxc->regmap, 0xb022, &irq_status);
1500cbbd5b1SDmitry Baryshkov 	regmap_read(lt9611uxc->regmap, 0xb023, &hpd_status);
1510cbbd5b1SDmitry Baryshkov 	if (irq_status)
1520cbbd5b1SDmitry Baryshkov 		regmap_write(lt9611uxc->regmap, 0xb022, 0);
1530cbbd5b1SDmitry Baryshkov 
154053b1b28SDmitry Baryshkov 	if (irq_status & BIT(0)) {
1550cbbd5b1SDmitry Baryshkov 		lt9611uxc->edid_read = !!(hpd_status & BIT(0));
156053b1b28SDmitry Baryshkov 		wake_up_all(&lt9611uxc->wq);
157053b1b28SDmitry Baryshkov 	}
1580cbbd5b1SDmitry Baryshkov 
1590cbbd5b1SDmitry Baryshkov 	if (irq_status & BIT(1)) {
160bc6fa867SDmitry Baryshkov 		lt9611uxc->hdmi_connected = hpd_status & BIT(1);
161bc6fa867SDmitry Baryshkov 		schedule_work(&lt9611uxc->work);
1620cbbd5b1SDmitry Baryshkov 	}
1630cbbd5b1SDmitry Baryshkov 
164bc6fa867SDmitry Baryshkov 	lt9611uxc_unlock(lt9611uxc);
165bc6fa867SDmitry Baryshkov 
1660cbbd5b1SDmitry Baryshkov 	return IRQ_HANDLED;
1670cbbd5b1SDmitry Baryshkov }
1680cbbd5b1SDmitry Baryshkov 
lt9611uxc_hpd_work(struct work_struct * work)169bc6fa867SDmitry Baryshkov static void lt9611uxc_hpd_work(struct work_struct *work)
170bc6fa867SDmitry Baryshkov {
171bc6fa867SDmitry Baryshkov 	struct lt9611uxc *lt9611uxc = container_of(work, struct lt9611uxc, work);
172bc6fa867SDmitry Baryshkov 	bool connected;
173bc6fa867SDmitry Baryshkov 
17415184965SDmitry Baryshkov 	if (lt9611uxc->connector.dev) {
17515184965SDmitry Baryshkov 		if (lt9611uxc->connector.dev->mode_config.funcs)
176bc6fa867SDmitry Baryshkov 			drm_kms_helper_hotplug_event(lt9611uxc->connector.dev);
17715184965SDmitry Baryshkov 	} else {
178bc6fa867SDmitry Baryshkov 
179bc6fa867SDmitry Baryshkov 		mutex_lock(&lt9611uxc->ocm_lock);
180bc6fa867SDmitry Baryshkov 		connected = lt9611uxc->hdmi_connected;
181bc6fa867SDmitry Baryshkov 		mutex_unlock(&lt9611uxc->ocm_lock);
182bc6fa867SDmitry Baryshkov 
183bc6fa867SDmitry Baryshkov 		drm_bridge_hpd_notify(&lt9611uxc->bridge,
184bc6fa867SDmitry Baryshkov 				      connected ?
185bc6fa867SDmitry Baryshkov 				      connector_status_connected :
186bc6fa867SDmitry Baryshkov 				      connector_status_disconnected);
187bc6fa867SDmitry Baryshkov 	}
188bc6fa867SDmitry Baryshkov }
189bc6fa867SDmitry Baryshkov 
lt9611uxc_reset(struct lt9611uxc * lt9611uxc)1900cbbd5b1SDmitry Baryshkov static void lt9611uxc_reset(struct lt9611uxc *lt9611uxc)
1910cbbd5b1SDmitry Baryshkov {
1920cbbd5b1SDmitry Baryshkov 	gpiod_set_value_cansleep(lt9611uxc->reset_gpio, 1);
1930cbbd5b1SDmitry Baryshkov 	msleep(20);
1940cbbd5b1SDmitry Baryshkov 
1950cbbd5b1SDmitry Baryshkov 	gpiod_set_value_cansleep(lt9611uxc->reset_gpio, 0);
1960cbbd5b1SDmitry Baryshkov 	msleep(20);
1970cbbd5b1SDmitry Baryshkov 
1980cbbd5b1SDmitry Baryshkov 	gpiod_set_value_cansleep(lt9611uxc->reset_gpio, 1);
1990cbbd5b1SDmitry Baryshkov 	msleep(300);
2000cbbd5b1SDmitry Baryshkov }
2010cbbd5b1SDmitry Baryshkov 
lt9611uxc_assert_5v(struct lt9611uxc * lt9611uxc)2020cbbd5b1SDmitry Baryshkov static void lt9611uxc_assert_5v(struct lt9611uxc *lt9611uxc)
2030cbbd5b1SDmitry Baryshkov {
2040cbbd5b1SDmitry Baryshkov 	if (!lt9611uxc->enable_gpio)
2050cbbd5b1SDmitry Baryshkov 		return;
2060cbbd5b1SDmitry Baryshkov 
2070cbbd5b1SDmitry Baryshkov 	gpiod_set_value_cansleep(lt9611uxc->enable_gpio, 1);
2080cbbd5b1SDmitry Baryshkov 	msleep(20);
2090cbbd5b1SDmitry Baryshkov }
2100cbbd5b1SDmitry Baryshkov 
lt9611uxc_regulator_init(struct lt9611uxc * lt9611uxc)2110cbbd5b1SDmitry Baryshkov static int lt9611uxc_regulator_init(struct lt9611uxc *lt9611uxc)
2120cbbd5b1SDmitry Baryshkov {
2130cbbd5b1SDmitry Baryshkov 	int ret;
2140cbbd5b1SDmitry Baryshkov 
2150cbbd5b1SDmitry Baryshkov 	lt9611uxc->supplies[0].supply = "vdd";
2160cbbd5b1SDmitry Baryshkov 	lt9611uxc->supplies[1].supply = "vcc";
2170cbbd5b1SDmitry Baryshkov 
2180cbbd5b1SDmitry Baryshkov 	ret = devm_regulator_bulk_get(lt9611uxc->dev, 2, lt9611uxc->supplies);
2190cbbd5b1SDmitry Baryshkov 	if (ret < 0)
2200cbbd5b1SDmitry Baryshkov 		return ret;
2210cbbd5b1SDmitry Baryshkov 
2220cbbd5b1SDmitry Baryshkov 	return regulator_set_load(lt9611uxc->supplies[0].consumer, 200000);
2230cbbd5b1SDmitry Baryshkov }
2240cbbd5b1SDmitry Baryshkov 
lt9611uxc_regulator_enable(struct lt9611uxc * lt9611uxc)2250cbbd5b1SDmitry Baryshkov static int lt9611uxc_regulator_enable(struct lt9611uxc *lt9611uxc)
2260cbbd5b1SDmitry Baryshkov {
2270cbbd5b1SDmitry Baryshkov 	int ret;
2280cbbd5b1SDmitry Baryshkov 
2290cbbd5b1SDmitry Baryshkov 	ret = regulator_enable(lt9611uxc->supplies[0].consumer);
2300cbbd5b1SDmitry Baryshkov 	if (ret < 0)
2310cbbd5b1SDmitry Baryshkov 		return ret;
2320cbbd5b1SDmitry Baryshkov 
2330cbbd5b1SDmitry Baryshkov 	usleep_range(1000, 10000); /* 50000 according to dtsi */
2340cbbd5b1SDmitry Baryshkov 
2350cbbd5b1SDmitry Baryshkov 	ret = regulator_enable(lt9611uxc->supplies[1].consumer);
2360cbbd5b1SDmitry Baryshkov 	if (ret < 0) {
2370cbbd5b1SDmitry Baryshkov 		regulator_disable(lt9611uxc->supplies[0].consumer);
2380cbbd5b1SDmitry Baryshkov 		return ret;
2390cbbd5b1SDmitry Baryshkov 	}
2400cbbd5b1SDmitry Baryshkov 
2410cbbd5b1SDmitry Baryshkov 	return 0;
2420cbbd5b1SDmitry Baryshkov }
2430cbbd5b1SDmitry Baryshkov 
lt9611uxc_find_mode(const struct drm_display_mode * mode)2440cbbd5b1SDmitry Baryshkov static struct lt9611uxc_mode *lt9611uxc_find_mode(const struct drm_display_mode *mode)
2450cbbd5b1SDmitry Baryshkov {
2460cbbd5b1SDmitry Baryshkov 	int i;
2470cbbd5b1SDmitry Baryshkov 
2480cbbd5b1SDmitry Baryshkov 	for (i = 0; i < ARRAY_SIZE(lt9611uxc_modes); i++) {
2490cbbd5b1SDmitry Baryshkov 		if (lt9611uxc_modes[i].hdisplay == mode->hdisplay &&
2500cbbd5b1SDmitry Baryshkov 		    lt9611uxc_modes[i].vdisplay == mode->vdisplay &&
2510cbbd5b1SDmitry Baryshkov 		    lt9611uxc_modes[i].vrefresh == drm_mode_vrefresh(mode)) {
2520cbbd5b1SDmitry Baryshkov 			return &lt9611uxc_modes[i];
2530cbbd5b1SDmitry Baryshkov 		}
2540cbbd5b1SDmitry Baryshkov 	}
2550cbbd5b1SDmitry Baryshkov 
2560cbbd5b1SDmitry Baryshkov 	return NULL;
2570cbbd5b1SDmitry Baryshkov }
2580cbbd5b1SDmitry Baryshkov 
lt9611uxc_attach_dsi(struct lt9611uxc * lt9611uxc,struct device_node * dsi_node)2590cbbd5b1SDmitry Baryshkov static struct mipi_dsi_device *lt9611uxc_attach_dsi(struct lt9611uxc *lt9611uxc,
2600cbbd5b1SDmitry Baryshkov 						    struct device_node *dsi_node)
2610cbbd5b1SDmitry Baryshkov {
2620cbbd5b1SDmitry Baryshkov 	const struct mipi_dsi_device_info info = { "lt9611uxc", 0, NULL };
2630cbbd5b1SDmitry Baryshkov 	struct mipi_dsi_device *dsi;
2640cbbd5b1SDmitry Baryshkov 	struct mipi_dsi_host *host;
265293ada7bSMaxime Ripard 	struct device *dev = lt9611uxc->dev;
2660cbbd5b1SDmitry Baryshkov 	int ret;
2670cbbd5b1SDmitry Baryshkov 
2680cbbd5b1SDmitry Baryshkov 	host = of_find_mipi_dsi_host_by_node(dsi_node);
269*6d9e877cSNícolas F. R. A. Prado 	if (!host)
270*6d9e877cSNícolas F. R. A. Prado 		return ERR_PTR(dev_err_probe(dev, -EPROBE_DEFER, "failed to find dsi host\n"));
2710cbbd5b1SDmitry Baryshkov 
272293ada7bSMaxime Ripard 	dsi = devm_mipi_dsi_device_register_full(dev, host, &info);
2730cbbd5b1SDmitry Baryshkov 	if (IS_ERR(dsi)) {
274293ada7bSMaxime Ripard 		dev_err(dev, "failed to create dsi device\n");
2750cbbd5b1SDmitry Baryshkov 		return dsi;
2760cbbd5b1SDmitry Baryshkov 	}
2770cbbd5b1SDmitry Baryshkov 
2780cbbd5b1SDmitry Baryshkov 	dsi->lanes = 4;
2790cbbd5b1SDmitry Baryshkov 	dsi->format = MIPI_DSI_FMT_RGB888;
2800cbbd5b1SDmitry Baryshkov 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
2810cbbd5b1SDmitry Baryshkov 			  MIPI_DSI_MODE_VIDEO_HSE;
2820cbbd5b1SDmitry Baryshkov 
283293ada7bSMaxime Ripard 	ret = devm_mipi_dsi_attach(dev, dsi);
2840cbbd5b1SDmitry Baryshkov 	if (ret < 0) {
285293ada7bSMaxime Ripard 		dev_err(dev, "failed to attach dsi to host\n");
2860cbbd5b1SDmitry Baryshkov 		return ERR_PTR(ret);
2870cbbd5b1SDmitry Baryshkov 	}
2880cbbd5b1SDmitry Baryshkov 
2890cbbd5b1SDmitry Baryshkov 	return dsi;
2900cbbd5b1SDmitry Baryshkov }
2910cbbd5b1SDmitry Baryshkov 
lt9611uxc_connector_get_modes(struct drm_connector * connector)2920cbbd5b1SDmitry Baryshkov static int lt9611uxc_connector_get_modes(struct drm_connector *connector)
2930cbbd5b1SDmitry Baryshkov {
2940cbbd5b1SDmitry Baryshkov 	struct lt9611uxc *lt9611uxc = connector_to_lt9611uxc(connector);
295392b6e9aSJani Nikula 	const struct drm_edid *drm_edid;
296b43a72c4SJani Nikula 	int count;
2970cbbd5b1SDmitry Baryshkov 
298392b6e9aSJani Nikula 	drm_edid = drm_bridge_edid_read(&lt9611uxc->bridge, connector);
299392b6e9aSJani Nikula 	drm_edid_connector_update(connector, drm_edid);
300392b6e9aSJani Nikula 	count = drm_edid_connector_add_modes(connector);
301392b6e9aSJani Nikula 	drm_edid_free(drm_edid);
3020cbbd5b1SDmitry Baryshkov 
3030cbbd5b1SDmitry Baryshkov 	return count;
3040cbbd5b1SDmitry Baryshkov }
3050cbbd5b1SDmitry Baryshkov 
lt9611uxc_connector_detect(struct drm_connector * connector,bool force)3060cbbd5b1SDmitry Baryshkov static enum drm_connector_status lt9611uxc_connector_detect(struct drm_connector *connector,
3070cbbd5b1SDmitry Baryshkov 							    bool force)
3080cbbd5b1SDmitry Baryshkov {
3090cbbd5b1SDmitry Baryshkov 	struct lt9611uxc *lt9611uxc = connector_to_lt9611uxc(connector);
3100cbbd5b1SDmitry Baryshkov 
3110cbbd5b1SDmitry Baryshkov 	return lt9611uxc->bridge.funcs->detect(&lt9611uxc->bridge);
3120cbbd5b1SDmitry Baryshkov }
3130cbbd5b1SDmitry Baryshkov 
lt9611uxc_connector_mode_valid(struct drm_connector * connector,struct drm_display_mode * mode)3140cbbd5b1SDmitry Baryshkov static enum drm_mode_status lt9611uxc_connector_mode_valid(struct drm_connector *connector,
3150cbbd5b1SDmitry Baryshkov 							   struct drm_display_mode *mode)
3160cbbd5b1SDmitry Baryshkov {
3170cbbd5b1SDmitry Baryshkov 	struct lt9611uxc_mode *lt9611uxc_mode = lt9611uxc_find_mode(mode);
3180cbbd5b1SDmitry Baryshkov 
3190cbbd5b1SDmitry Baryshkov 	return lt9611uxc_mode ? MODE_OK : MODE_BAD;
3200cbbd5b1SDmitry Baryshkov }
3210cbbd5b1SDmitry Baryshkov 
3220cbbd5b1SDmitry Baryshkov static const struct drm_connector_helper_funcs lt9611uxc_bridge_connector_helper_funcs = {
3230cbbd5b1SDmitry Baryshkov 	.get_modes = lt9611uxc_connector_get_modes,
3240cbbd5b1SDmitry Baryshkov 	.mode_valid = lt9611uxc_connector_mode_valid,
3250cbbd5b1SDmitry Baryshkov };
3260cbbd5b1SDmitry Baryshkov 
3270cbbd5b1SDmitry Baryshkov static const struct drm_connector_funcs lt9611uxc_bridge_connector_funcs = {
3280cbbd5b1SDmitry Baryshkov 	.fill_modes = drm_helper_probe_single_connector_modes,
3290cbbd5b1SDmitry Baryshkov 	.detect = lt9611uxc_connector_detect,
3300cbbd5b1SDmitry Baryshkov 	.destroy = drm_connector_cleanup,
3310cbbd5b1SDmitry Baryshkov 	.reset = drm_atomic_helper_connector_reset,
3320cbbd5b1SDmitry Baryshkov 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
3330cbbd5b1SDmitry Baryshkov 	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
3340cbbd5b1SDmitry Baryshkov };
3350cbbd5b1SDmitry Baryshkov 
lt9611uxc_connector_init(struct drm_bridge * bridge,struct lt9611uxc * lt9611uxc)3360cbbd5b1SDmitry Baryshkov static int lt9611uxc_connector_init(struct drm_bridge *bridge, struct lt9611uxc *lt9611uxc)
3370cbbd5b1SDmitry Baryshkov {
3380cbbd5b1SDmitry Baryshkov 	int ret;
3390cbbd5b1SDmitry Baryshkov 
3400cbbd5b1SDmitry Baryshkov 	if (!bridge->encoder) {
3410cbbd5b1SDmitry Baryshkov 		DRM_ERROR("Parent encoder object not found");
3420cbbd5b1SDmitry Baryshkov 		return -ENODEV;
3430cbbd5b1SDmitry Baryshkov 	}
3440cbbd5b1SDmitry Baryshkov 
34515184965SDmitry Baryshkov 	lt9611uxc->connector.polled = DRM_CONNECTOR_POLL_HPD;
34615184965SDmitry Baryshkov 
3470cbbd5b1SDmitry Baryshkov 	drm_connector_helper_add(&lt9611uxc->connector,
3480cbbd5b1SDmitry Baryshkov 				 &lt9611uxc_bridge_connector_helper_funcs);
3490cbbd5b1SDmitry Baryshkov 	ret = drm_connector_init(bridge->dev, &lt9611uxc->connector,
3500cbbd5b1SDmitry Baryshkov 				 &lt9611uxc_bridge_connector_funcs,
3510cbbd5b1SDmitry Baryshkov 				 DRM_MODE_CONNECTOR_HDMIA);
3520cbbd5b1SDmitry Baryshkov 	if (ret) {
3530cbbd5b1SDmitry Baryshkov 		DRM_ERROR("Failed to initialize connector with drm\n");
3540cbbd5b1SDmitry Baryshkov 		return ret;
3550cbbd5b1SDmitry Baryshkov 	}
3560cbbd5b1SDmitry Baryshkov 
3570cbbd5b1SDmitry Baryshkov 	return drm_connector_attach_encoder(&lt9611uxc->connector, bridge->encoder);
3580cbbd5b1SDmitry Baryshkov }
3590cbbd5b1SDmitry Baryshkov 
lt9611uxc_bridge_attach(struct drm_bridge * bridge,enum drm_bridge_attach_flags flags)3600cbbd5b1SDmitry Baryshkov static int lt9611uxc_bridge_attach(struct drm_bridge *bridge,
3610cbbd5b1SDmitry Baryshkov 				   enum drm_bridge_attach_flags flags)
3620cbbd5b1SDmitry Baryshkov {
3630cbbd5b1SDmitry Baryshkov 	struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
3640cbbd5b1SDmitry Baryshkov 	int ret;
3650cbbd5b1SDmitry Baryshkov 
3660cbbd5b1SDmitry Baryshkov 	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
3670cbbd5b1SDmitry Baryshkov 		ret = lt9611uxc_connector_init(bridge, lt9611uxc);
3680cbbd5b1SDmitry Baryshkov 		if (ret < 0)
3690cbbd5b1SDmitry Baryshkov 			return ret;
3700cbbd5b1SDmitry Baryshkov 	}
3710cbbd5b1SDmitry Baryshkov 
3720cbbd5b1SDmitry Baryshkov 	return 0;
3730cbbd5b1SDmitry Baryshkov }
3740cbbd5b1SDmitry Baryshkov 
3750cbbd5b1SDmitry Baryshkov static enum drm_mode_status
lt9611uxc_bridge_mode_valid(struct drm_bridge * bridge,const struct drm_display_info * info,const struct drm_display_mode * mode)3760cbbd5b1SDmitry Baryshkov lt9611uxc_bridge_mode_valid(struct drm_bridge *bridge,
3770cbbd5b1SDmitry Baryshkov 			    const struct drm_display_info *info,
3780cbbd5b1SDmitry Baryshkov 			    const struct drm_display_mode *mode)
3790cbbd5b1SDmitry Baryshkov {
3800cbbd5b1SDmitry Baryshkov 	struct lt9611uxc_mode *lt9611uxc_mode;
3810cbbd5b1SDmitry Baryshkov 
3820cbbd5b1SDmitry Baryshkov 	lt9611uxc_mode = lt9611uxc_find_mode(mode);
3830cbbd5b1SDmitry Baryshkov 
3840cbbd5b1SDmitry Baryshkov 	return lt9611uxc_mode ? MODE_OK : MODE_BAD;
3850cbbd5b1SDmitry Baryshkov }
3860cbbd5b1SDmitry Baryshkov 
lt9611uxc_video_setup(struct lt9611uxc * lt9611uxc,const struct drm_display_mode * mode)3870cbbd5b1SDmitry Baryshkov static void lt9611uxc_video_setup(struct lt9611uxc *lt9611uxc,
3880cbbd5b1SDmitry Baryshkov 				  const struct drm_display_mode *mode)
3890cbbd5b1SDmitry Baryshkov {
3900cbbd5b1SDmitry Baryshkov 	u32 h_total, hactive, hsync_len, hfront_porch;
3910cbbd5b1SDmitry Baryshkov 	u32 v_total, vactive, vsync_len, vfront_porch;
3920cbbd5b1SDmitry Baryshkov 
3930cbbd5b1SDmitry Baryshkov 	h_total = mode->htotal;
3940cbbd5b1SDmitry Baryshkov 	v_total = mode->vtotal;
3950cbbd5b1SDmitry Baryshkov 
3960cbbd5b1SDmitry Baryshkov 	hactive = mode->hdisplay;
3970cbbd5b1SDmitry Baryshkov 	hsync_len = mode->hsync_end - mode->hsync_start;
3980cbbd5b1SDmitry Baryshkov 	hfront_porch = mode->hsync_start - mode->hdisplay;
3990cbbd5b1SDmitry Baryshkov 
4000cbbd5b1SDmitry Baryshkov 	vactive = mode->vdisplay;
4010cbbd5b1SDmitry Baryshkov 	vsync_len = mode->vsync_end - mode->vsync_start;
4020cbbd5b1SDmitry Baryshkov 	vfront_porch = mode->vsync_start - mode->vdisplay;
4030cbbd5b1SDmitry Baryshkov 
4040cbbd5b1SDmitry Baryshkov 	regmap_write(lt9611uxc->regmap, 0xd00d, (u8)(v_total / 256));
4050cbbd5b1SDmitry Baryshkov 	regmap_write(lt9611uxc->regmap, 0xd00e, (u8)(v_total % 256));
4060cbbd5b1SDmitry Baryshkov 
4070cbbd5b1SDmitry Baryshkov 	regmap_write(lt9611uxc->regmap, 0xd00f, (u8)(vactive / 256));
4080cbbd5b1SDmitry Baryshkov 	regmap_write(lt9611uxc->regmap, 0xd010, (u8)(vactive % 256));
4090cbbd5b1SDmitry Baryshkov 
4100cbbd5b1SDmitry Baryshkov 	regmap_write(lt9611uxc->regmap, 0xd011, (u8)(h_total / 256));
4110cbbd5b1SDmitry Baryshkov 	regmap_write(lt9611uxc->regmap, 0xd012, (u8)(h_total % 256));
4120cbbd5b1SDmitry Baryshkov 
4130cbbd5b1SDmitry Baryshkov 	regmap_write(lt9611uxc->regmap, 0xd013, (u8)(hactive / 256));
4140cbbd5b1SDmitry Baryshkov 	regmap_write(lt9611uxc->regmap, 0xd014, (u8)(hactive % 256));
4150cbbd5b1SDmitry Baryshkov 
4160cbbd5b1SDmitry Baryshkov 	regmap_write(lt9611uxc->regmap, 0xd015, (u8)(vsync_len % 256));
4170cbbd5b1SDmitry Baryshkov 
4180cbbd5b1SDmitry Baryshkov 	regmap_update_bits(lt9611uxc->regmap, 0xd016, 0xf, (u8)(hsync_len / 256));
4190cbbd5b1SDmitry Baryshkov 	regmap_write(lt9611uxc->regmap, 0xd017, (u8)(hsync_len % 256));
4200cbbd5b1SDmitry Baryshkov 
4210cbbd5b1SDmitry Baryshkov 	regmap_update_bits(lt9611uxc->regmap, 0xd018, 0xf, (u8)(vfront_porch / 256));
4220cbbd5b1SDmitry Baryshkov 	regmap_write(lt9611uxc->regmap, 0xd019, (u8)(vfront_porch % 256));
4230cbbd5b1SDmitry Baryshkov 
4240cbbd5b1SDmitry Baryshkov 	regmap_update_bits(lt9611uxc->regmap, 0xd01a, 0xf, (u8)(hfront_porch / 256));
4250cbbd5b1SDmitry Baryshkov 	regmap_write(lt9611uxc->regmap, 0xd01b, (u8)(hfront_porch % 256));
4260cbbd5b1SDmitry Baryshkov }
4270cbbd5b1SDmitry Baryshkov 
lt9611uxc_bridge_mode_set(struct drm_bridge * bridge,const struct drm_display_mode * mode,const struct drm_display_mode * adj_mode)4280cbbd5b1SDmitry Baryshkov static void lt9611uxc_bridge_mode_set(struct drm_bridge *bridge,
4290cbbd5b1SDmitry Baryshkov 				      const struct drm_display_mode *mode,
4300cbbd5b1SDmitry Baryshkov 				      const struct drm_display_mode *adj_mode)
4310cbbd5b1SDmitry Baryshkov {
4320cbbd5b1SDmitry Baryshkov 	struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
4330cbbd5b1SDmitry Baryshkov 
4340cbbd5b1SDmitry Baryshkov 	lt9611uxc_lock(lt9611uxc);
4350cbbd5b1SDmitry Baryshkov 	lt9611uxc_video_setup(lt9611uxc, mode);
4360cbbd5b1SDmitry Baryshkov 	lt9611uxc_unlock(lt9611uxc);
4370cbbd5b1SDmitry Baryshkov }
4380cbbd5b1SDmitry Baryshkov 
lt9611uxc_bridge_detect(struct drm_bridge * bridge)4390cbbd5b1SDmitry Baryshkov static enum drm_connector_status lt9611uxc_bridge_detect(struct drm_bridge *bridge)
4400cbbd5b1SDmitry Baryshkov {
4410cbbd5b1SDmitry Baryshkov 	struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
4420cbbd5b1SDmitry Baryshkov 	unsigned int reg_val = 0;
4430cbbd5b1SDmitry Baryshkov 	int ret;
444bc6fa867SDmitry Baryshkov 	bool connected = true;
445bc6fa867SDmitry Baryshkov 
446bc6fa867SDmitry Baryshkov 	lt9611uxc_lock(lt9611uxc);
4470cbbd5b1SDmitry Baryshkov 
4480cbbd5b1SDmitry Baryshkov 	if (lt9611uxc->hpd_supported) {
4490cbbd5b1SDmitry Baryshkov 		ret = regmap_read(lt9611uxc->regmap, 0xb023, &reg_val);
4500cbbd5b1SDmitry Baryshkov 
4510cbbd5b1SDmitry Baryshkov 		if (ret)
4520cbbd5b1SDmitry Baryshkov 			dev_err(lt9611uxc->dev, "failed to read hpd status: %d\n", ret);
4530cbbd5b1SDmitry Baryshkov 		else
4540cbbd5b1SDmitry Baryshkov 			connected  = reg_val & BIT(1);
4550cbbd5b1SDmitry Baryshkov 	}
456bc6fa867SDmitry Baryshkov 	lt9611uxc->hdmi_connected = connected;
457bc6fa867SDmitry Baryshkov 
458bc6fa867SDmitry Baryshkov 	lt9611uxc_unlock(lt9611uxc);
4590cbbd5b1SDmitry Baryshkov 
4600cbbd5b1SDmitry Baryshkov 	return connected ?  connector_status_connected :
4610cbbd5b1SDmitry Baryshkov 				connector_status_disconnected;
4620cbbd5b1SDmitry Baryshkov }
4630cbbd5b1SDmitry Baryshkov 
lt9611uxc_wait_for_edid(struct lt9611uxc * lt9611uxc)4640cbbd5b1SDmitry Baryshkov static int lt9611uxc_wait_for_edid(struct lt9611uxc *lt9611uxc)
4650cbbd5b1SDmitry Baryshkov {
4660cbbd5b1SDmitry Baryshkov 	return wait_event_interruptible_timeout(lt9611uxc->wq, lt9611uxc->edid_read,
467053b1b28SDmitry Baryshkov 			msecs_to_jiffies(500));
4680cbbd5b1SDmitry Baryshkov }
4690cbbd5b1SDmitry Baryshkov 
lt9611uxc_get_edid_block(void * data,u8 * buf,unsigned int block,size_t len)4700cbbd5b1SDmitry Baryshkov static int lt9611uxc_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
4710cbbd5b1SDmitry Baryshkov {
4720cbbd5b1SDmitry Baryshkov 	struct lt9611uxc *lt9611uxc = data;
4730cbbd5b1SDmitry Baryshkov 	int ret;
4740cbbd5b1SDmitry Baryshkov 
4750cbbd5b1SDmitry Baryshkov 	if (len > EDID_BLOCK_SIZE)
4760cbbd5b1SDmitry Baryshkov 		return -EINVAL;
4770cbbd5b1SDmitry Baryshkov 
4780cbbd5b1SDmitry Baryshkov 	if (block >= EDID_NUM_BLOCKS)
4790cbbd5b1SDmitry Baryshkov 		return -EINVAL;
4800cbbd5b1SDmitry Baryshkov 
4810cbbd5b1SDmitry Baryshkov 	lt9611uxc_lock(lt9611uxc);
4820cbbd5b1SDmitry Baryshkov 
4830cbbd5b1SDmitry Baryshkov 	regmap_write(lt9611uxc->regmap, 0xb00b, 0x10);
4840cbbd5b1SDmitry Baryshkov 
4850cbbd5b1SDmitry Baryshkov 	regmap_write(lt9611uxc->regmap, 0xb00a, block * EDID_BLOCK_SIZE);
4860cbbd5b1SDmitry Baryshkov 
4870cbbd5b1SDmitry Baryshkov 	ret = regmap_noinc_read(lt9611uxc->regmap, 0xb0b0, buf, len);
4880cbbd5b1SDmitry Baryshkov 	if (ret)
4890cbbd5b1SDmitry Baryshkov 		dev_err(lt9611uxc->dev, "edid read failed: %d\n", ret);
4900cbbd5b1SDmitry Baryshkov 
4910cbbd5b1SDmitry Baryshkov 	lt9611uxc_unlock(lt9611uxc);
4920cbbd5b1SDmitry Baryshkov 
4930cbbd5b1SDmitry Baryshkov 	return 0;
4940cbbd5b1SDmitry Baryshkov };
4950cbbd5b1SDmitry Baryshkov 
lt9611uxc_bridge_edid_read(struct drm_bridge * bridge,struct drm_connector * connector)49626b2ddd8SJani Nikula static const struct drm_edid *lt9611uxc_bridge_edid_read(struct drm_bridge *bridge,
4970cbbd5b1SDmitry Baryshkov 							 struct drm_connector *connector)
4980cbbd5b1SDmitry Baryshkov {
4990cbbd5b1SDmitry Baryshkov 	struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
5000cbbd5b1SDmitry Baryshkov 	int ret;
5010cbbd5b1SDmitry Baryshkov 
5020cbbd5b1SDmitry Baryshkov 	ret = lt9611uxc_wait_for_edid(lt9611uxc);
5030cbbd5b1SDmitry Baryshkov 	if (ret < 0) {
5040cbbd5b1SDmitry Baryshkov 		dev_err(lt9611uxc->dev, "wait for EDID failed: %d\n", ret);
5051bb7ab40SDmitry Baryshkov 		return NULL;
5061bb7ab40SDmitry Baryshkov 	} else if (ret == 0) {
5071bb7ab40SDmitry Baryshkov 		dev_err(lt9611uxc->dev, "wait for EDID timeout\n");
5081bb7ab40SDmitry Baryshkov 		return NULL;
5090cbbd5b1SDmitry Baryshkov 	}
5100cbbd5b1SDmitry Baryshkov 
51126b2ddd8SJani Nikula 	return drm_edid_read_custom(connector, lt9611uxc_get_edid_block, lt9611uxc);
5120cbbd5b1SDmitry Baryshkov }
5130cbbd5b1SDmitry Baryshkov 
5140cbbd5b1SDmitry Baryshkov static const struct drm_bridge_funcs lt9611uxc_bridge_funcs = {
5150cbbd5b1SDmitry Baryshkov 	.attach = lt9611uxc_bridge_attach,
5160cbbd5b1SDmitry Baryshkov 	.mode_valid = lt9611uxc_bridge_mode_valid,
5170cbbd5b1SDmitry Baryshkov 	.mode_set = lt9611uxc_bridge_mode_set,
5180cbbd5b1SDmitry Baryshkov 	.detect = lt9611uxc_bridge_detect,
51926b2ddd8SJani Nikula 	.edid_read = lt9611uxc_bridge_edid_read,
5200cbbd5b1SDmitry Baryshkov };
5210cbbd5b1SDmitry Baryshkov 
lt9611uxc_parse_dt(struct device * dev,struct lt9611uxc * lt9611uxc)5220cbbd5b1SDmitry Baryshkov static int lt9611uxc_parse_dt(struct device *dev,
5230cbbd5b1SDmitry Baryshkov 			      struct lt9611uxc *lt9611uxc)
5240cbbd5b1SDmitry Baryshkov {
5250cbbd5b1SDmitry Baryshkov 	lt9611uxc->dsi0_node = of_graph_get_remote_node(dev->of_node, 0, -1);
5260cbbd5b1SDmitry Baryshkov 	if (!lt9611uxc->dsi0_node) {
5270cbbd5b1SDmitry Baryshkov 		dev_err(lt9611uxc->dev, "failed to get remote node for primary dsi\n");
5280cbbd5b1SDmitry Baryshkov 		return -ENODEV;
5290cbbd5b1SDmitry Baryshkov 	}
5300cbbd5b1SDmitry Baryshkov 
5310cbbd5b1SDmitry Baryshkov 	lt9611uxc->dsi1_node = of_graph_get_remote_node(dev->of_node, 1, -1);
5320cbbd5b1SDmitry Baryshkov 
5330cbbd5b1SDmitry Baryshkov 	return 0;
5340cbbd5b1SDmitry Baryshkov }
5350cbbd5b1SDmitry Baryshkov 
lt9611uxc_gpio_init(struct lt9611uxc * lt9611uxc)5360cbbd5b1SDmitry Baryshkov static int lt9611uxc_gpio_init(struct lt9611uxc *lt9611uxc)
5370cbbd5b1SDmitry Baryshkov {
5380cbbd5b1SDmitry Baryshkov 	struct device *dev = lt9611uxc->dev;
5390cbbd5b1SDmitry Baryshkov 
5400cbbd5b1SDmitry Baryshkov 	lt9611uxc->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
5410cbbd5b1SDmitry Baryshkov 	if (IS_ERR(lt9611uxc->reset_gpio)) {
5420cbbd5b1SDmitry Baryshkov 		dev_err(dev, "failed to acquire reset gpio\n");
5430cbbd5b1SDmitry Baryshkov 		return PTR_ERR(lt9611uxc->reset_gpio);
5440cbbd5b1SDmitry Baryshkov 	}
5450cbbd5b1SDmitry Baryshkov 
5460cbbd5b1SDmitry Baryshkov 	lt9611uxc->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW);
5470cbbd5b1SDmitry Baryshkov 	if (IS_ERR(lt9611uxc->enable_gpio)) {
5480cbbd5b1SDmitry Baryshkov 		dev_err(dev, "failed to acquire enable gpio\n");
5490cbbd5b1SDmitry Baryshkov 		return PTR_ERR(lt9611uxc->enable_gpio);
5500cbbd5b1SDmitry Baryshkov 	}
5510cbbd5b1SDmitry Baryshkov 
5520cbbd5b1SDmitry Baryshkov 	return 0;
5530cbbd5b1SDmitry Baryshkov }
5540cbbd5b1SDmitry Baryshkov 
lt9611uxc_read_device_rev(struct lt9611uxc * lt9611uxc)5550cbbd5b1SDmitry Baryshkov static int lt9611uxc_read_device_rev(struct lt9611uxc *lt9611uxc)
5560cbbd5b1SDmitry Baryshkov {
5570cbbd5b1SDmitry Baryshkov 	unsigned int rev0, rev1, rev2;
5580cbbd5b1SDmitry Baryshkov 	int ret;
5590cbbd5b1SDmitry Baryshkov 
5600cbbd5b1SDmitry Baryshkov 	lt9611uxc_lock(lt9611uxc);
5610cbbd5b1SDmitry Baryshkov 
5620cbbd5b1SDmitry Baryshkov 	ret = regmap_read(lt9611uxc->regmap, 0x8100, &rev0);
5630cbbd5b1SDmitry Baryshkov 	ret |= regmap_read(lt9611uxc->regmap, 0x8101, &rev1);
5640cbbd5b1SDmitry Baryshkov 	ret |= regmap_read(lt9611uxc->regmap, 0x8102, &rev2);
5650cbbd5b1SDmitry Baryshkov 	if (ret)
5660cbbd5b1SDmitry Baryshkov 		dev_err(lt9611uxc->dev, "failed to read revision: %d\n", ret);
5670cbbd5b1SDmitry Baryshkov 	else
5680cbbd5b1SDmitry Baryshkov 		dev_info(lt9611uxc->dev, "LT9611 revision: 0x%02x.%02x.%02x\n", rev0, rev1, rev2);
5690cbbd5b1SDmitry Baryshkov 
5700cbbd5b1SDmitry Baryshkov 	lt9611uxc_unlock(lt9611uxc);
5710cbbd5b1SDmitry Baryshkov 
5720cbbd5b1SDmitry Baryshkov 	return ret;
5730cbbd5b1SDmitry Baryshkov }
5740cbbd5b1SDmitry Baryshkov 
lt9611uxc_read_version(struct lt9611uxc * lt9611uxc)5750cbbd5b1SDmitry Baryshkov static int lt9611uxc_read_version(struct lt9611uxc *lt9611uxc)
5760cbbd5b1SDmitry Baryshkov {
5770cbbd5b1SDmitry Baryshkov 	unsigned int rev;
5780cbbd5b1SDmitry Baryshkov 	int ret;
5790cbbd5b1SDmitry Baryshkov 
5800cbbd5b1SDmitry Baryshkov 	lt9611uxc_lock(lt9611uxc);
5810cbbd5b1SDmitry Baryshkov 
5820cbbd5b1SDmitry Baryshkov 	ret = regmap_read(lt9611uxc->regmap, 0xb021, &rev);
5830cbbd5b1SDmitry Baryshkov 	if (ret)
5840cbbd5b1SDmitry Baryshkov 		dev_err(lt9611uxc->dev, "failed to read revision: %d\n", ret);
5850cbbd5b1SDmitry Baryshkov 	else
5860cbbd5b1SDmitry Baryshkov 		dev_info(lt9611uxc->dev, "LT9611 version: 0x%02x\n", rev);
5870cbbd5b1SDmitry Baryshkov 
5880cbbd5b1SDmitry Baryshkov 	lt9611uxc_unlock(lt9611uxc);
5890cbbd5b1SDmitry Baryshkov 
5900cbbd5b1SDmitry Baryshkov 	return ret < 0 ? ret : rev;
5910cbbd5b1SDmitry Baryshkov }
5920cbbd5b1SDmitry Baryshkov 
lt9611uxc_hdmi_hw_params(struct device * dev,void * data,struct hdmi_codec_daifmt * fmt,struct hdmi_codec_params * hparms)5930cbbd5b1SDmitry Baryshkov static int lt9611uxc_hdmi_hw_params(struct device *dev, void *data,
5940cbbd5b1SDmitry Baryshkov 				    struct hdmi_codec_daifmt *fmt,
5950cbbd5b1SDmitry Baryshkov 				    struct hdmi_codec_params *hparms)
5960cbbd5b1SDmitry Baryshkov {
5970cbbd5b1SDmitry Baryshkov 	/*
5980cbbd5b1SDmitry Baryshkov 	 * LT9611UXC will automatically detect rate and sample size, so no need
5990cbbd5b1SDmitry Baryshkov 	 * to setup anything here.
6000cbbd5b1SDmitry Baryshkov 	 */
6010cbbd5b1SDmitry Baryshkov 	return 0;
6020cbbd5b1SDmitry Baryshkov }
6030cbbd5b1SDmitry Baryshkov 
lt9611uxc_audio_shutdown(struct device * dev,void * data)6040cbbd5b1SDmitry Baryshkov static void lt9611uxc_audio_shutdown(struct device *dev, void *data)
6050cbbd5b1SDmitry Baryshkov {
6060cbbd5b1SDmitry Baryshkov }
6070cbbd5b1SDmitry Baryshkov 
lt9611uxc_hdmi_i2s_get_dai_id(struct snd_soc_component * component,struct device_node * endpoint)6080cbbd5b1SDmitry Baryshkov static int lt9611uxc_hdmi_i2s_get_dai_id(struct snd_soc_component *component,
6090cbbd5b1SDmitry Baryshkov 					 struct device_node *endpoint)
6100cbbd5b1SDmitry Baryshkov {
6110cbbd5b1SDmitry Baryshkov 	struct of_endpoint of_ep;
6120cbbd5b1SDmitry Baryshkov 	int ret;
6130cbbd5b1SDmitry Baryshkov 
6140cbbd5b1SDmitry Baryshkov 	ret = of_graph_parse_endpoint(endpoint, &of_ep);
6150cbbd5b1SDmitry Baryshkov 	if (ret < 0)
6160cbbd5b1SDmitry Baryshkov 		return ret;
6170cbbd5b1SDmitry Baryshkov 
6180cbbd5b1SDmitry Baryshkov 	/*
6190cbbd5b1SDmitry Baryshkov 	 * HDMI sound should be located as reg = <2>
6200cbbd5b1SDmitry Baryshkov 	 * Then, it is sound port 0
6210cbbd5b1SDmitry Baryshkov 	 */
6220cbbd5b1SDmitry Baryshkov 	if (of_ep.port == 2)
6230cbbd5b1SDmitry Baryshkov 		return 0;
6240cbbd5b1SDmitry Baryshkov 
6250cbbd5b1SDmitry Baryshkov 	return -EINVAL;
6260cbbd5b1SDmitry Baryshkov }
6270cbbd5b1SDmitry Baryshkov 
6280cbbd5b1SDmitry Baryshkov static const struct hdmi_codec_ops lt9611uxc_codec_ops = {
6290cbbd5b1SDmitry Baryshkov 	.hw_params	= lt9611uxc_hdmi_hw_params,
6300cbbd5b1SDmitry Baryshkov 	.audio_shutdown = lt9611uxc_audio_shutdown,
6310cbbd5b1SDmitry Baryshkov 	.get_dai_id	= lt9611uxc_hdmi_i2s_get_dai_id,
6320cbbd5b1SDmitry Baryshkov };
6330cbbd5b1SDmitry Baryshkov 
lt9611uxc_audio_init(struct device * dev,struct lt9611uxc * lt9611uxc)6340cbbd5b1SDmitry Baryshkov static int lt9611uxc_audio_init(struct device *dev, struct lt9611uxc *lt9611uxc)
6350cbbd5b1SDmitry Baryshkov {
6360cbbd5b1SDmitry Baryshkov 	struct hdmi_codec_pdata codec_data = {
6370cbbd5b1SDmitry Baryshkov 		.ops = &lt9611uxc_codec_ops,
6380cbbd5b1SDmitry Baryshkov 		.max_i2s_channels = 2,
6390cbbd5b1SDmitry Baryshkov 		.i2s = 1,
6400cbbd5b1SDmitry Baryshkov 		.data = lt9611uxc,
6410cbbd5b1SDmitry Baryshkov 	};
6420cbbd5b1SDmitry Baryshkov 
6430cbbd5b1SDmitry Baryshkov 	lt9611uxc->audio_pdev =
6440cbbd5b1SDmitry Baryshkov 		platform_device_register_data(dev, HDMI_CODEC_DRV_NAME,
6450cbbd5b1SDmitry Baryshkov 					      PLATFORM_DEVID_AUTO,
6460cbbd5b1SDmitry Baryshkov 					      &codec_data, sizeof(codec_data));
6470cbbd5b1SDmitry Baryshkov 
6480cbbd5b1SDmitry Baryshkov 	return PTR_ERR_OR_ZERO(lt9611uxc->audio_pdev);
6490cbbd5b1SDmitry Baryshkov }
6500cbbd5b1SDmitry Baryshkov 
lt9611uxc_audio_exit(struct lt9611uxc * lt9611uxc)6510cbbd5b1SDmitry Baryshkov static void lt9611uxc_audio_exit(struct lt9611uxc *lt9611uxc)
6520cbbd5b1SDmitry Baryshkov {
6530cbbd5b1SDmitry Baryshkov 	if (lt9611uxc->audio_pdev) {
6540cbbd5b1SDmitry Baryshkov 		platform_device_unregister(lt9611uxc->audio_pdev);
6550cbbd5b1SDmitry Baryshkov 		lt9611uxc->audio_pdev = NULL;
6560cbbd5b1SDmitry Baryshkov 	}
6570cbbd5b1SDmitry Baryshkov }
6580cbbd5b1SDmitry Baryshkov 
6590cbbd5b1SDmitry Baryshkov #define LT9611UXC_FW_PAGE_SIZE 32
lt9611uxc_firmware_write_page(struct lt9611uxc * lt9611uxc,u16 addr,const u8 * buf)6600cbbd5b1SDmitry Baryshkov static void lt9611uxc_firmware_write_page(struct lt9611uxc *lt9611uxc, u16 addr, const u8 *buf)
6610cbbd5b1SDmitry Baryshkov {
6620cbbd5b1SDmitry Baryshkov 	struct reg_sequence seq_write_prepare[] = {
6630cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805a, 0x04),
6640cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805a, 0x00),
6650cbbd5b1SDmitry Baryshkov 
6660cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805e, 0xdf),
6670cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805a, 0x20),
6680cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805a, 0x00),
6690cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x8058, 0x21),
6700cbbd5b1SDmitry Baryshkov 	};
6710cbbd5b1SDmitry Baryshkov 
6720cbbd5b1SDmitry Baryshkov 	struct reg_sequence seq_write_addr[] = {
6730cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805b, (addr >> 16) & 0xff),
6740cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805c, (addr >> 8) & 0xff),
6750cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805d, addr & 0xff),
6760cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805a, 0x10),
6770cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805a, 0x00),
6780cbbd5b1SDmitry Baryshkov 	};
6790cbbd5b1SDmitry Baryshkov 
6800cbbd5b1SDmitry Baryshkov 	regmap_write(lt9611uxc->regmap, 0x8108, 0xbf);
6810cbbd5b1SDmitry Baryshkov 	msleep(20);
6820cbbd5b1SDmitry Baryshkov 	regmap_write(lt9611uxc->regmap, 0x8108, 0xff);
6830cbbd5b1SDmitry Baryshkov 	msleep(20);
6840cbbd5b1SDmitry Baryshkov 	regmap_multi_reg_write(lt9611uxc->regmap, seq_write_prepare, ARRAY_SIZE(seq_write_prepare));
6850cbbd5b1SDmitry Baryshkov 	regmap_noinc_write(lt9611uxc->regmap, 0x8059, buf, LT9611UXC_FW_PAGE_SIZE);
6860cbbd5b1SDmitry Baryshkov 	regmap_multi_reg_write(lt9611uxc->regmap, seq_write_addr, ARRAY_SIZE(seq_write_addr));
6870cbbd5b1SDmitry Baryshkov 	msleep(20);
6880cbbd5b1SDmitry Baryshkov }
6890cbbd5b1SDmitry Baryshkov 
lt9611uxc_firmware_read_page(struct lt9611uxc * lt9611uxc,u16 addr,char * buf)6900cbbd5b1SDmitry Baryshkov static void lt9611uxc_firmware_read_page(struct lt9611uxc *lt9611uxc, u16 addr, char *buf)
6910cbbd5b1SDmitry Baryshkov {
6920cbbd5b1SDmitry Baryshkov 	struct reg_sequence seq_read_page[] = {
6930cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805a, 0xa0),
6940cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805a, 0x80),
6950cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805b, (addr >> 16) & 0xff),
6960cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805c, (addr >> 8) & 0xff),
6970cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805d, addr & 0xff),
6980cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805a, 0x90),
6990cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805a, 0x80),
7000cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x8058, 0x21),
7010cbbd5b1SDmitry Baryshkov 	};
7020cbbd5b1SDmitry Baryshkov 
7030cbbd5b1SDmitry Baryshkov 	regmap_multi_reg_write(lt9611uxc->regmap, seq_read_page, ARRAY_SIZE(seq_read_page));
7040cbbd5b1SDmitry Baryshkov 	regmap_noinc_read(lt9611uxc->regmap, 0x805f, buf, LT9611UXC_FW_PAGE_SIZE);
7050cbbd5b1SDmitry Baryshkov }
7060cbbd5b1SDmitry Baryshkov 
lt9611uxc_firmware_read(struct lt9611uxc * lt9611uxc,size_t size)7070cbbd5b1SDmitry Baryshkov static char *lt9611uxc_firmware_read(struct lt9611uxc *lt9611uxc, size_t size)
7080cbbd5b1SDmitry Baryshkov {
7090cbbd5b1SDmitry Baryshkov 	struct reg_sequence seq_read_setup[] = {
7100cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805a, 0x84),
7110cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805a, 0x80),
7120cbbd5b1SDmitry Baryshkov 	};
7130cbbd5b1SDmitry Baryshkov 
7140cbbd5b1SDmitry Baryshkov 	char *readbuf;
7150cbbd5b1SDmitry Baryshkov 	u16 offset;
7160cbbd5b1SDmitry Baryshkov 
7170cbbd5b1SDmitry Baryshkov 	readbuf = kzalloc(ALIGN(size, 32), GFP_KERNEL);
7180cbbd5b1SDmitry Baryshkov 	if (!readbuf)
7190cbbd5b1SDmitry Baryshkov 		return NULL;
7200cbbd5b1SDmitry Baryshkov 
7210cbbd5b1SDmitry Baryshkov 	regmap_multi_reg_write(lt9611uxc->regmap, seq_read_setup, ARRAY_SIZE(seq_read_setup));
7220cbbd5b1SDmitry Baryshkov 
7230cbbd5b1SDmitry Baryshkov 	for (offset = 0;
7240cbbd5b1SDmitry Baryshkov 	     offset < size;
7250cbbd5b1SDmitry Baryshkov 	     offset += LT9611UXC_FW_PAGE_SIZE)
7260cbbd5b1SDmitry Baryshkov 		lt9611uxc_firmware_read_page(lt9611uxc, offset, &readbuf[offset]);
7270cbbd5b1SDmitry Baryshkov 
7280cbbd5b1SDmitry Baryshkov 	return readbuf;
7290cbbd5b1SDmitry Baryshkov }
7300cbbd5b1SDmitry Baryshkov 
lt9611uxc_firmware_update(struct lt9611uxc * lt9611uxc)7310cbbd5b1SDmitry Baryshkov static int lt9611uxc_firmware_update(struct lt9611uxc *lt9611uxc)
7320cbbd5b1SDmitry Baryshkov {
7330cbbd5b1SDmitry Baryshkov 	int ret;
7340cbbd5b1SDmitry Baryshkov 	u16 offset;
7350cbbd5b1SDmitry Baryshkov 	size_t remain;
7360cbbd5b1SDmitry Baryshkov 	char *readbuf;
7370cbbd5b1SDmitry Baryshkov 	const struct firmware *fw;
7380cbbd5b1SDmitry Baryshkov 
7390cbbd5b1SDmitry Baryshkov 	struct reg_sequence seq_setup[] = {
7400cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805e, 0xdf),
7410cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x8058, 0x00),
7420cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x8059, 0x50),
7430cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805a, 0x10),
7440cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805a, 0x00),
7450cbbd5b1SDmitry Baryshkov 	};
7460cbbd5b1SDmitry Baryshkov 
7470cbbd5b1SDmitry Baryshkov 
7480cbbd5b1SDmitry Baryshkov 	struct reg_sequence seq_block_erase[] = {
7490cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805a, 0x04),
7500cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805a, 0x00),
7510cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805b, 0x00),
7520cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805c, 0x00),
7530cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805d, 0x00),
7540cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805a, 0x01),
7550cbbd5b1SDmitry Baryshkov 		REG_SEQ0(0x805a, 0x00),
7560cbbd5b1SDmitry Baryshkov 	};
7570cbbd5b1SDmitry Baryshkov 
758354c0fb6SJuerg Haefliger 	ret = request_firmware(&fw, FW_FILE, lt9611uxc->dev);
7590cbbd5b1SDmitry Baryshkov 	if (ret < 0)
7600cbbd5b1SDmitry Baryshkov 		return ret;
7610cbbd5b1SDmitry Baryshkov 
7620cbbd5b1SDmitry Baryshkov 	dev_info(lt9611uxc->dev, "Updating firmware\n");
7630cbbd5b1SDmitry Baryshkov 	lt9611uxc_lock(lt9611uxc);
7640cbbd5b1SDmitry Baryshkov 
7650cbbd5b1SDmitry Baryshkov 	regmap_multi_reg_write(lt9611uxc->regmap, seq_setup, ARRAY_SIZE(seq_setup));
7660cbbd5b1SDmitry Baryshkov 
7670cbbd5b1SDmitry Baryshkov 	/*
7680cbbd5b1SDmitry Baryshkov 	 * Need erase block 2 timess here. Sometimes, block erase can fail.
7690cbbd5b1SDmitry Baryshkov 	 * This is a workaroud.
7700cbbd5b1SDmitry Baryshkov 	 */
7710cbbd5b1SDmitry Baryshkov 	regmap_multi_reg_write(lt9611uxc->regmap, seq_block_erase, ARRAY_SIZE(seq_block_erase));
7720cbbd5b1SDmitry Baryshkov 	msleep(3000);
7730cbbd5b1SDmitry Baryshkov 	regmap_multi_reg_write(lt9611uxc->regmap, seq_block_erase, ARRAY_SIZE(seq_block_erase));
7740cbbd5b1SDmitry Baryshkov 	msleep(3000);
7750cbbd5b1SDmitry Baryshkov 
7760cbbd5b1SDmitry Baryshkov 	for (offset = 0, remain = fw->size;
7770cbbd5b1SDmitry Baryshkov 	     remain >= LT9611UXC_FW_PAGE_SIZE;
7780cbbd5b1SDmitry Baryshkov 	     offset += LT9611UXC_FW_PAGE_SIZE, remain -= LT9611UXC_FW_PAGE_SIZE)
7790cbbd5b1SDmitry Baryshkov 		lt9611uxc_firmware_write_page(lt9611uxc, offset, fw->data + offset);
7800cbbd5b1SDmitry Baryshkov 
7810cbbd5b1SDmitry Baryshkov 	if (remain > 0) {
7820cbbd5b1SDmitry Baryshkov 		char buf[LT9611UXC_FW_PAGE_SIZE];
7830cbbd5b1SDmitry Baryshkov 
7840cbbd5b1SDmitry Baryshkov 		memset(buf, 0xff, LT9611UXC_FW_PAGE_SIZE);
7850cbbd5b1SDmitry Baryshkov 		memcpy(buf, fw->data + offset, remain);
7860cbbd5b1SDmitry Baryshkov 		lt9611uxc_firmware_write_page(lt9611uxc, offset, buf);
7870cbbd5b1SDmitry Baryshkov 	}
7880cbbd5b1SDmitry Baryshkov 	msleep(20);
7890cbbd5b1SDmitry Baryshkov 
7900cbbd5b1SDmitry Baryshkov 	readbuf = lt9611uxc_firmware_read(lt9611uxc, fw->size);
7910cbbd5b1SDmitry Baryshkov 	if (!readbuf) {
7920cbbd5b1SDmitry Baryshkov 		ret = -ENOMEM;
7930cbbd5b1SDmitry Baryshkov 		goto out;
7940cbbd5b1SDmitry Baryshkov 	}
7950cbbd5b1SDmitry Baryshkov 
7960cbbd5b1SDmitry Baryshkov 	if (!memcmp(readbuf, fw->data, fw->size)) {
7970cbbd5b1SDmitry Baryshkov 		dev_err(lt9611uxc->dev, "Firmware update failed\n");
7980cbbd5b1SDmitry Baryshkov 		print_hex_dump(KERN_ERR, "fw: ", DUMP_PREFIX_OFFSET, 16, 1, readbuf, fw->size, false);
7990cbbd5b1SDmitry Baryshkov 		ret = -EINVAL;
8000cbbd5b1SDmitry Baryshkov 	} else {
8010cbbd5b1SDmitry Baryshkov 		dev_info(lt9611uxc->dev, "Firmware updates successfully\n");
8020cbbd5b1SDmitry Baryshkov 		ret = 0;
8030cbbd5b1SDmitry Baryshkov 	}
8040cbbd5b1SDmitry Baryshkov 	kfree(readbuf);
8050cbbd5b1SDmitry Baryshkov 
8060cbbd5b1SDmitry Baryshkov out:
8070cbbd5b1SDmitry Baryshkov 	lt9611uxc_unlock(lt9611uxc);
8080cbbd5b1SDmitry Baryshkov 	lt9611uxc_reset(lt9611uxc);
8090cbbd5b1SDmitry Baryshkov 	release_firmware(fw);
8100cbbd5b1SDmitry Baryshkov 
8110cbbd5b1SDmitry Baryshkov 	return ret;
8120cbbd5b1SDmitry Baryshkov }
8130cbbd5b1SDmitry Baryshkov 
lt9611uxc_firmware_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)8140cbbd5b1SDmitry Baryshkov static ssize_t lt9611uxc_firmware_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len)
8150cbbd5b1SDmitry Baryshkov {
8160cbbd5b1SDmitry Baryshkov 	struct lt9611uxc *lt9611uxc = dev_get_drvdata(dev);
8170cbbd5b1SDmitry Baryshkov 	int ret;
8180cbbd5b1SDmitry Baryshkov 
8190cbbd5b1SDmitry Baryshkov 	ret = lt9611uxc_firmware_update(lt9611uxc);
8200cbbd5b1SDmitry Baryshkov 	if (ret < 0)
8210cbbd5b1SDmitry Baryshkov 		return ret;
8220cbbd5b1SDmitry Baryshkov 	return len;
8230cbbd5b1SDmitry Baryshkov }
8240cbbd5b1SDmitry Baryshkov 
lt9611uxc_firmware_show(struct device * dev,struct device_attribute * attr,char * buf)8250cbbd5b1SDmitry Baryshkov static ssize_t lt9611uxc_firmware_show(struct device *dev, struct device_attribute *attr, char *buf)
8260cbbd5b1SDmitry Baryshkov {
8270cbbd5b1SDmitry Baryshkov 	struct lt9611uxc *lt9611uxc = dev_get_drvdata(dev);
8280cbbd5b1SDmitry Baryshkov 
829fffa69aaSJiapeng Chong 	return sysfs_emit(buf, "%02x\n", lt9611uxc->fw_version);
8300cbbd5b1SDmitry Baryshkov }
8310cbbd5b1SDmitry Baryshkov 
8320cbbd5b1SDmitry Baryshkov static DEVICE_ATTR_RW(lt9611uxc_firmware);
8330cbbd5b1SDmitry Baryshkov 
8340cbbd5b1SDmitry Baryshkov static struct attribute *lt9611uxc_attrs[] = {
8350cbbd5b1SDmitry Baryshkov 	&dev_attr_lt9611uxc_firmware.attr,
8360cbbd5b1SDmitry Baryshkov 	NULL,
8370cbbd5b1SDmitry Baryshkov };
8380cbbd5b1SDmitry Baryshkov 
8390cbbd5b1SDmitry Baryshkov static const struct attribute_group lt9611uxc_attr_group = {
8400cbbd5b1SDmitry Baryshkov 	.attrs = lt9611uxc_attrs,
8410cbbd5b1SDmitry Baryshkov };
8420cbbd5b1SDmitry Baryshkov 
8430cbbd5b1SDmitry Baryshkov static const struct attribute_group *lt9611uxc_attr_groups[] = {
8440cbbd5b1SDmitry Baryshkov 	&lt9611uxc_attr_group,
8450cbbd5b1SDmitry Baryshkov 	NULL,
8460cbbd5b1SDmitry Baryshkov };
8470cbbd5b1SDmitry Baryshkov 
lt9611uxc_probe(struct i2c_client * client)848cae75557SUwe Kleine-König static int lt9611uxc_probe(struct i2c_client *client)
8490cbbd5b1SDmitry Baryshkov {
8500cbbd5b1SDmitry Baryshkov 	struct lt9611uxc *lt9611uxc;
8510cbbd5b1SDmitry Baryshkov 	struct device *dev = &client->dev;
8520cbbd5b1SDmitry Baryshkov 	int ret;
8530cbbd5b1SDmitry Baryshkov 	bool fw_updated = false;
8540cbbd5b1SDmitry Baryshkov 
8550cbbd5b1SDmitry Baryshkov 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
8560cbbd5b1SDmitry Baryshkov 		dev_err(dev, "device doesn't support I2C\n");
8570cbbd5b1SDmitry Baryshkov 		return -ENODEV;
8580cbbd5b1SDmitry Baryshkov 	}
8590cbbd5b1SDmitry Baryshkov 
8600cbbd5b1SDmitry Baryshkov 	lt9611uxc = devm_kzalloc(dev, sizeof(*lt9611uxc), GFP_KERNEL);
8610cbbd5b1SDmitry Baryshkov 	if (!lt9611uxc)
8620cbbd5b1SDmitry Baryshkov 		return -ENOMEM;
8630cbbd5b1SDmitry Baryshkov 
864cc37b88bSZhiming Liu 	lt9611uxc->dev = dev;
8650cbbd5b1SDmitry Baryshkov 	lt9611uxc->client = client;
8660cbbd5b1SDmitry Baryshkov 	mutex_init(&lt9611uxc->ocm_lock);
8670cbbd5b1SDmitry Baryshkov 
8680cbbd5b1SDmitry Baryshkov 	lt9611uxc->regmap = devm_regmap_init_i2c(client, &lt9611uxc_regmap_config);
8690cbbd5b1SDmitry Baryshkov 	if (IS_ERR(lt9611uxc->regmap)) {
8700cbbd5b1SDmitry Baryshkov 		dev_err(lt9611uxc->dev, "regmap i2c init failed\n");
8710cbbd5b1SDmitry Baryshkov 		return PTR_ERR(lt9611uxc->regmap);
8720cbbd5b1SDmitry Baryshkov 	}
8730cbbd5b1SDmitry Baryshkov 
874cc37b88bSZhiming Liu 	ret = lt9611uxc_parse_dt(dev, lt9611uxc);
8750cbbd5b1SDmitry Baryshkov 	if (ret) {
8760cbbd5b1SDmitry Baryshkov 		dev_err(dev, "failed to parse device tree\n");
8770cbbd5b1SDmitry Baryshkov 		return ret;
8780cbbd5b1SDmitry Baryshkov 	}
8790cbbd5b1SDmitry Baryshkov 
8800cbbd5b1SDmitry Baryshkov 	ret = lt9611uxc_gpio_init(lt9611uxc);
8810cbbd5b1SDmitry Baryshkov 	if (ret < 0)
8820cbbd5b1SDmitry Baryshkov 		goto err_of_put;
8830cbbd5b1SDmitry Baryshkov 
8840cbbd5b1SDmitry Baryshkov 	ret = lt9611uxc_regulator_init(lt9611uxc);
8850cbbd5b1SDmitry Baryshkov 	if (ret < 0)
8860cbbd5b1SDmitry Baryshkov 		goto err_of_put;
8870cbbd5b1SDmitry Baryshkov 
8880cbbd5b1SDmitry Baryshkov 	lt9611uxc_assert_5v(lt9611uxc);
8890cbbd5b1SDmitry Baryshkov 
8900cbbd5b1SDmitry Baryshkov 	ret = lt9611uxc_regulator_enable(lt9611uxc);
8910cbbd5b1SDmitry Baryshkov 	if (ret)
8920cbbd5b1SDmitry Baryshkov 		goto err_of_put;
8930cbbd5b1SDmitry Baryshkov 
8940cbbd5b1SDmitry Baryshkov 	lt9611uxc_reset(lt9611uxc);
8950cbbd5b1SDmitry Baryshkov 
8960cbbd5b1SDmitry Baryshkov 	ret = lt9611uxc_read_device_rev(lt9611uxc);
8970cbbd5b1SDmitry Baryshkov 	if (ret) {
8980cbbd5b1SDmitry Baryshkov 		dev_err(dev, "failed to read chip rev\n");
8990cbbd5b1SDmitry Baryshkov 		goto err_disable_regulators;
9000cbbd5b1SDmitry Baryshkov 	}
9010cbbd5b1SDmitry Baryshkov 
9020cbbd5b1SDmitry Baryshkov retry:
9030cbbd5b1SDmitry Baryshkov 	ret = lt9611uxc_read_version(lt9611uxc);
9040cbbd5b1SDmitry Baryshkov 	if (ret < 0) {
9050cbbd5b1SDmitry Baryshkov 		dev_err(dev, "failed to read FW version\n");
9060cbbd5b1SDmitry Baryshkov 		goto err_disable_regulators;
9070cbbd5b1SDmitry Baryshkov 	} else if (ret == 0) {
9080cbbd5b1SDmitry Baryshkov 		if (!fw_updated) {
9090cbbd5b1SDmitry Baryshkov 			fw_updated = true;
9100cbbd5b1SDmitry Baryshkov 			dev_err(dev, "FW version 0, enforcing firmware update\n");
9110cbbd5b1SDmitry Baryshkov 			ret = lt9611uxc_firmware_update(lt9611uxc);
9120cbbd5b1SDmitry Baryshkov 			if (ret < 0)
9130cbbd5b1SDmitry Baryshkov 				goto err_disable_regulators;
9140cbbd5b1SDmitry Baryshkov 			else
9150cbbd5b1SDmitry Baryshkov 				goto retry;
9160cbbd5b1SDmitry Baryshkov 		} else {
9170cbbd5b1SDmitry Baryshkov 			dev_err(dev, "FW version 0, update failed\n");
9180cbbd5b1SDmitry Baryshkov 			ret = -EOPNOTSUPP;
9190cbbd5b1SDmitry Baryshkov 			goto err_disable_regulators;
9200cbbd5b1SDmitry Baryshkov 		}
9210cbbd5b1SDmitry Baryshkov 	} else if (ret < 0x40) {
9220cbbd5b1SDmitry Baryshkov 		dev_info(dev, "FW version 0x%x, HPD not supported\n", ret);
9230cbbd5b1SDmitry Baryshkov 	} else {
9240cbbd5b1SDmitry Baryshkov 		lt9611uxc->hpd_supported = true;
9250cbbd5b1SDmitry Baryshkov 	}
9260cbbd5b1SDmitry Baryshkov 	lt9611uxc->fw_version = ret;
9270cbbd5b1SDmitry Baryshkov 
9280cbbd5b1SDmitry Baryshkov 	init_waitqueue_head(&lt9611uxc->wq);
929bc6fa867SDmitry Baryshkov 	INIT_WORK(&lt9611uxc->work, lt9611uxc_hpd_work);
930bc6fa867SDmitry Baryshkov 
93115fe53beSDmitry Baryshkov 	ret = request_threaded_irq(client->irq, NULL,
9320cbbd5b1SDmitry Baryshkov 				   lt9611uxc_irq_thread_handler,
9330cbbd5b1SDmitry Baryshkov 				   IRQF_ONESHOT, "lt9611uxc", lt9611uxc);
9340cbbd5b1SDmitry Baryshkov 	if (ret) {
9350cbbd5b1SDmitry Baryshkov 		dev_err(dev, "failed to request irq\n");
9360cbbd5b1SDmitry Baryshkov 		goto err_disable_regulators;
9370cbbd5b1SDmitry Baryshkov 	}
9380cbbd5b1SDmitry Baryshkov 
9390cbbd5b1SDmitry Baryshkov 	i2c_set_clientdata(client, lt9611uxc);
9400cbbd5b1SDmitry Baryshkov 
9410cbbd5b1SDmitry Baryshkov 	lt9611uxc->bridge.funcs = &lt9611uxc_bridge_funcs;
9420cbbd5b1SDmitry Baryshkov 	lt9611uxc->bridge.of_node = client->dev.of_node;
9430cbbd5b1SDmitry Baryshkov 	lt9611uxc->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID;
9440cbbd5b1SDmitry Baryshkov 	if (lt9611uxc->hpd_supported)
9450cbbd5b1SDmitry Baryshkov 		lt9611uxc->bridge.ops |= DRM_BRIDGE_OP_HPD;
9460cbbd5b1SDmitry Baryshkov 	lt9611uxc->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
9470cbbd5b1SDmitry Baryshkov 
9480cbbd5b1SDmitry Baryshkov 	drm_bridge_add(&lt9611uxc->bridge);
9490cbbd5b1SDmitry Baryshkov 
9504a46ace5SMaxime Ripard 	/* Attach primary DSI */
9514a46ace5SMaxime Ripard 	lt9611uxc->dsi0 = lt9611uxc_attach_dsi(lt9611uxc, lt9611uxc->dsi0_node);
9524a46ace5SMaxime Ripard 	if (IS_ERR(lt9611uxc->dsi0)) {
9534a46ace5SMaxime Ripard 		ret = PTR_ERR(lt9611uxc->dsi0);
9544a46ace5SMaxime Ripard 		goto err_remove_bridge;
9554a46ace5SMaxime Ripard 	}
9564a46ace5SMaxime Ripard 
9574a46ace5SMaxime Ripard 	/* Attach secondary DSI, if specified */
9584a46ace5SMaxime Ripard 	if (lt9611uxc->dsi1_node) {
9594a46ace5SMaxime Ripard 		lt9611uxc->dsi1 = lt9611uxc_attach_dsi(lt9611uxc, lt9611uxc->dsi1_node);
9604a46ace5SMaxime Ripard 		if (IS_ERR(lt9611uxc->dsi1)) {
9614a46ace5SMaxime Ripard 			ret = PTR_ERR(lt9611uxc->dsi1);
9624a46ace5SMaxime Ripard 			goto err_remove_bridge;
9634a46ace5SMaxime Ripard 		}
9644a46ace5SMaxime Ripard 	}
9654a46ace5SMaxime Ripard 
9660cbbd5b1SDmitry Baryshkov 	return lt9611uxc_audio_init(dev, lt9611uxc);
9670cbbd5b1SDmitry Baryshkov 
9684a46ace5SMaxime Ripard err_remove_bridge:
96915fe53beSDmitry Baryshkov 	free_irq(client->irq, lt9611uxc);
97015fe53beSDmitry Baryshkov 	cancel_work_sync(&lt9611uxc->work);
9714a46ace5SMaxime Ripard 	drm_bridge_remove(&lt9611uxc->bridge);
9724a46ace5SMaxime Ripard 
9730cbbd5b1SDmitry Baryshkov err_disable_regulators:
9740cbbd5b1SDmitry Baryshkov 	regulator_bulk_disable(ARRAY_SIZE(lt9611uxc->supplies), lt9611uxc->supplies);
9750cbbd5b1SDmitry Baryshkov 
9760cbbd5b1SDmitry Baryshkov err_of_put:
9770cbbd5b1SDmitry Baryshkov 	of_node_put(lt9611uxc->dsi1_node);
9780cbbd5b1SDmitry Baryshkov 	of_node_put(lt9611uxc->dsi0_node);
9790cbbd5b1SDmitry Baryshkov 
9800cbbd5b1SDmitry Baryshkov 	return ret;
9810cbbd5b1SDmitry Baryshkov }
9820cbbd5b1SDmitry Baryshkov 
lt9611uxc_remove(struct i2c_client * client)983ed5c2f5fSUwe Kleine-König static void lt9611uxc_remove(struct i2c_client *client)
9840cbbd5b1SDmitry Baryshkov {
9850cbbd5b1SDmitry Baryshkov 	struct lt9611uxc *lt9611uxc = i2c_get_clientdata(client);
9860cbbd5b1SDmitry Baryshkov 
98715fe53beSDmitry Baryshkov 	free_irq(client->irq, lt9611uxc);
988dfa687bfSBjorn Andersson 	cancel_work_sync(&lt9611uxc->work);
9890cbbd5b1SDmitry Baryshkov 	lt9611uxc_audio_exit(lt9611uxc);
9900cbbd5b1SDmitry Baryshkov 	drm_bridge_remove(&lt9611uxc->bridge);
9910cbbd5b1SDmitry Baryshkov 
9920cbbd5b1SDmitry Baryshkov 	mutex_destroy(&lt9611uxc->ocm_lock);
9930cbbd5b1SDmitry Baryshkov 
9940cbbd5b1SDmitry Baryshkov 	regulator_bulk_disable(ARRAY_SIZE(lt9611uxc->supplies), lt9611uxc->supplies);
9950cbbd5b1SDmitry Baryshkov 
9960cbbd5b1SDmitry Baryshkov 	of_node_put(lt9611uxc->dsi1_node);
9970cbbd5b1SDmitry Baryshkov 	of_node_put(lt9611uxc->dsi0_node);
9980cbbd5b1SDmitry Baryshkov }
9990cbbd5b1SDmitry Baryshkov 
10000cbbd5b1SDmitry Baryshkov static struct i2c_device_id lt9611uxc_id[] = {
10010cbbd5b1SDmitry Baryshkov 	{ "lontium,lt9611uxc", 0 },
10020cbbd5b1SDmitry Baryshkov 	{ /* sentinel */ }
10030cbbd5b1SDmitry Baryshkov };
10040cbbd5b1SDmitry Baryshkov 
10050cbbd5b1SDmitry Baryshkov static const struct of_device_id lt9611uxc_match_table[] = {
10060cbbd5b1SDmitry Baryshkov 	{ .compatible = "lontium,lt9611uxc" },
10070cbbd5b1SDmitry Baryshkov 	{ /* sentinel */ }
10080cbbd5b1SDmitry Baryshkov };
10090cbbd5b1SDmitry Baryshkov MODULE_DEVICE_TABLE(of, lt9611uxc_match_table);
10100cbbd5b1SDmitry Baryshkov 
10110cbbd5b1SDmitry Baryshkov static struct i2c_driver lt9611uxc_driver = {
10120cbbd5b1SDmitry Baryshkov 	.driver = {
10130cbbd5b1SDmitry Baryshkov 		.name = "lt9611uxc",
10140cbbd5b1SDmitry Baryshkov 		.of_match_table = lt9611uxc_match_table,
10150cbbd5b1SDmitry Baryshkov 		.dev_groups = lt9611uxc_attr_groups,
10160cbbd5b1SDmitry Baryshkov 	},
1017332af828SUwe Kleine-König 	.probe = lt9611uxc_probe,
10180cbbd5b1SDmitry Baryshkov 	.remove = lt9611uxc_remove,
10190cbbd5b1SDmitry Baryshkov 	.id_table = lt9611uxc_id,
10200cbbd5b1SDmitry Baryshkov };
10210cbbd5b1SDmitry Baryshkov module_i2c_driver(lt9611uxc_driver);
10220cbbd5b1SDmitry Baryshkov 
10230cbbd5b1SDmitry Baryshkov MODULE_AUTHOR("Dmitry Baryshkov <dmitry.baryshkov@linaro.org>");
10240cbbd5b1SDmitry Baryshkov MODULE_LICENSE("GPL v2");
1025354c0fb6SJuerg Haefliger 
1026354c0fb6SJuerg Haefliger MODULE_FIRMWARE(FW_FILE);
1027