xref: /linux/drivers/gpu/drm/panel/panel-samsung-atna33xc20.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
132ce3b32SDouglas Anderson // SPDX-License-Identifier: GPL-2.0
232ce3b32SDouglas Anderson /*
332ce3b32SDouglas Anderson  * Copyright 2021 Google Inc.
432ce3b32SDouglas Anderson  *
532ce3b32SDouglas Anderson  * Panel driver for the Samsung ATNA33XC20 panel. This panel can't be handled
632ce3b32SDouglas Anderson  * by the DRM_PANEL_SIMPLE driver because its power sequencing is non-standard.
732ce3b32SDouglas Anderson  */
832ce3b32SDouglas Anderson 
932ce3b32SDouglas Anderson #include <linux/backlight.h>
1032ce3b32SDouglas Anderson #include <linux/delay.h>
1132ce3b32SDouglas Anderson #include <linux/gpio/consumer.h>
1232ce3b32SDouglas Anderson #include <linux/iopoll.h>
1332ce3b32SDouglas Anderson #include <linux/module.h>
1432ce3b32SDouglas Anderson #include <linux/pm_runtime.h>
1532ce3b32SDouglas Anderson #include <linux/regulator/consumer.h>
1632ce3b32SDouglas Anderson 
17da68386dSThomas Zimmermann #include <drm/display/drm_dp_aux_bus.h>
18da68386dSThomas Zimmermann #include <drm/display/drm_dp_helper.h>
1932ce3b32SDouglas Anderson #include <drm/drm_edid.h>
2032ce3b32SDouglas Anderson #include <drm/drm_panel.h>
2132ce3b32SDouglas Anderson 
223b5765dfSDouglas Anderson /* T3 VCC to HPD high is max 200 ms */
233b5765dfSDouglas Anderson #define HPD_MAX_MS	200
243b5765dfSDouglas Anderson #define HPD_MAX_US	(HPD_MAX_MS * 1000)
253b5765dfSDouglas Anderson 
2632ce3b32SDouglas Anderson struct atana33xc20_panel {
2732ce3b32SDouglas Anderson 	struct drm_panel base;
2832ce3b32SDouglas Anderson 	bool el3_was_on;
2932ce3b32SDouglas Anderson 
3032ce3b32SDouglas Anderson 	bool no_hpd;
3132ce3b32SDouglas Anderson 	struct gpio_desc *hpd_gpio;
3232ce3b32SDouglas Anderson 
3332ce3b32SDouglas Anderson 	struct regulator *supply;
3432ce3b32SDouglas Anderson 	struct gpio_desc *el_on3_gpio;
353b5765dfSDouglas Anderson 	struct drm_dp_aux *aux;
3632ce3b32SDouglas Anderson 
37*a9c428f1SJani Nikula 	const struct drm_edid *drm_edid;
3832ce3b32SDouglas Anderson 
3932ce3b32SDouglas Anderson 	ktime_t powered_off_time;
4032ce3b32SDouglas Anderson 	ktime_t powered_on_time;
4132ce3b32SDouglas Anderson 	ktime_t el_on3_off_time;
4232ce3b32SDouglas Anderson };
4332ce3b32SDouglas Anderson 
to_atana33xc20(struct drm_panel * panel)4432ce3b32SDouglas Anderson static inline struct atana33xc20_panel *to_atana33xc20(struct drm_panel *panel)
4532ce3b32SDouglas Anderson {
4632ce3b32SDouglas Anderson 	return container_of(panel, struct atana33xc20_panel, base);
4732ce3b32SDouglas Anderson }
4832ce3b32SDouglas Anderson 
atana33xc20_wait(ktime_t start_ktime,unsigned int min_ms)4932ce3b32SDouglas Anderson static void atana33xc20_wait(ktime_t start_ktime, unsigned int min_ms)
5032ce3b32SDouglas Anderson {
5132ce3b32SDouglas Anderson 	ktime_t now_ktime, min_ktime;
5232ce3b32SDouglas Anderson 
5332ce3b32SDouglas Anderson 	min_ktime = ktime_add(start_ktime, ms_to_ktime(min_ms));
5462e43673SDrew Davenport 	now_ktime = ktime_get_boottime();
5532ce3b32SDouglas Anderson 
5632ce3b32SDouglas Anderson 	if (ktime_before(now_ktime, min_ktime))
5732ce3b32SDouglas Anderson 		msleep(ktime_to_ms(ktime_sub(min_ktime, now_ktime)) + 1);
5832ce3b32SDouglas Anderson }
5932ce3b32SDouglas Anderson 
atana33xc20_suspend(struct device * dev)6032ce3b32SDouglas Anderson static int atana33xc20_suspend(struct device *dev)
6132ce3b32SDouglas Anderson {
6232ce3b32SDouglas Anderson 	struct atana33xc20_panel *p = dev_get_drvdata(dev);
6332ce3b32SDouglas Anderson 	int ret;
6432ce3b32SDouglas Anderson 
6532ce3b32SDouglas Anderson 	/*
6632ce3b32SDouglas Anderson 	 * Note 3 (Example of power off sequence in detail) in spec
6732ce3b32SDouglas Anderson 	 * specifies to wait 150 ms after deasserting EL3_ON before
6832ce3b32SDouglas Anderson 	 * powering off.
6932ce3b32SDouglas Anderson 	 */
7032ce3b32SDouglas Anderson 	if (p->el3_was_on)
7132ce3b32SDouglas Anderson 		atana33xc20_wait(p->el_on3_off_time, 150);
7232ce3b32SDouglas Anderson 
738df1ddb5SDouglas Anderson 	drm_dp_dpcd_set_powered(p->aux, false);
7432ce3b32SDouglas Anderson 	ret = regulator_disable(p->supply);
7532ce3b32SDouglas Anderson 	if (ret)
7632ce3b32SDouglas Anderson 		return ret;
7762e43673SDrew Davenport 	p->powered_off_time = ktime_get_boottime();
7832ce3b32SDouglas Anderson 	p->el3_was_on = false;
7932ce3b32SDouglas Anderson 
8032ce3b32SDouglas Anderson 	return 0;
8132ce3b32SDouglas Anderson }
8232ce3b32SDouglas Anderson 
atana33xc20_resume(struct device * dev)8332ce3b32SDouglas Anderson static int atana33xc20_resume(struct device *dev)
8432ce3b32SDouglas Anderson {
8532ce3b32SDouglas Anderson 	struct atana33xc20_panel *p = dev_get_drvdata(dev);
863b5765dfSDouglas Anderson 	int hpd_asserted;
8732ce3b32SDouglas Anderson 	int ret;
8832ce3b32SDouglas Anderson 
8932ce3b32SDouglas Anderson 	/* T12 (Power off time) is min 500 ms */
9032ce3b32SDouglas Anderson 	atana33xc20_wait(p->powered_off_time, 500);
9132ce3b32SDouglas Anderson 
9232ce3b32SDouglas Anderson 	ret = regulator_enable(p->supply);
9332ce3b32SDouglas Anderson 	if (ret)
9432ce3b32SDouglas Anderson 		return ret;
958df1ddb5SDouglas Anderson 	drm_dp_dpcd_set_powered(p->aux, true);
9662e43673SDrew Davenport 	p->powered_on_time = ktime_get_boottime();
9732ce3b32SDouglas Anderson 
9832ce3b32SDouglas Anderson 	if (p->no_hpd) {
993b5765dfSDouglas Anderson 		msleep(HPD_MAX_MS);
1003b5765dfSDouglas Anderson 		return 0;
10132ce3b32SDouglas Anderson 	}
10232ce3b32SDouglas Anderson 
1033b5765dfSDouglas Anderson 	if (p->hpd_gpio) {
1043b5765dfSDouglas Anderson 		ret = readx_poll_timeout(gpiod_get_value_cansleep, p->hpd_gpio,
1053b5765dfSDouglas Anderson 					 hpd_asserted, hpd_asserted,
1063b5765dfSDouglas Anderson 					 1000, HPD_MAX_US);
1073b5765dfSDouglas Anderson 		if (hpd_asserted < 0)
1083b5765dfSDouglas Anderson 			ret = hpd_asserted;
1093b5765dfSDouglas Anderson 
1105e842d55SDouglas Anderson 		if (ret) {
1113b5765dfSDouglas Anderson 			dev_warn(dev, "Error waiting for HPD GPIO: %d\n", ret);
1125e842d55SDouglas Anderson 			goto error;
1133b5765dfSDouglas Anderson 		}
1145e842d55SDouglas Anderson 	} else if (p->aux->wait_hpd_asserted) {
1153b5765dfSDouglas Anderson 		ret = p->aux->wait_hpd_asserted(p->aux, HPD_MAX_US);
1163b5765dfSDouglas Anderson 
1175e842d55SDouglas Anderson 		if (ret) {
1183b5765dfSDouglas Anderson 			dev_warn(dev, "Controller error waiting for HPD: %d\n", ret);
1195e842d55SDouglas Anderson 			goto error;
1205e842d55SDouglas Anderson 		}
1213b5765dfSDouglas Anderson 	}
1223b5765dfSDouglas Anderson 
1233b5765dfSDouglas Anderson 	/*
1243b5765dfSDouglas Anderson 	 * Note that it's possible that no_hpd is false, hpd_gpio is
1253b5765dfSDouglas Anderson 	 * NULL, and wait_hpd_asserted is NULL. This is because
1263b5765dfSDouglas Anderson 	 * wait_hpd_asserted() is optional even if HPD is hooked up to
1273b5765dfSDouglas Anderson 	 * a dedicated pin on the eDP controller. In this case we just
1283b5765dfSDouglas Anderson 	 * assume that the controller driver will wait for HPD at the
1293b5765dfSDouglas Anderson 	 * right times.
1303b5765dfSDouglas Anderson 	 */
13132ce3b32SDouglas Anderson 	return 0;
1325e842d55SDouglas Anderson 
1335e842d55SDouglas Anderson error:
1345e842d55SDouglas Anderson 	drm_dp_dpcd_set_powered(p->aux, false);
1355e842d55SDouglas Anderson 	regulator_disable(p->supply);
1365e842d55SDouglas Anderson 
1375e842d55SDouglas Anderson 	return ret;
13832ce3b32SDouglas Anderson }
13932ce3b32SDouglas Anderson 
atana33xc20_disable(struct drm_panel * panel)14032ce3b32SDouglas Anderson static int atana33xc20_disable(struct drm_panel *panel)
14132ce3b32SDouglas Anderson {
14232ce3b32SDouglas Anderson 	struct atana33xc20_panel *p = to_atana33xc20(panel);
14332ce3b32SDouglas Anderson 
14432ce3b32SDouglas Anderson 	gpiod_set_value_cansleep(p->el_on3_gpio, 0);
14562e43673SDrew Davenport 	p->el_on3_off_time = ktime_get_boottime();
14632ce3b32SDouglas Anderson 
14732ce3b32SDouglas Anderson 	/*
14832ce3b32SDouglas Anderson 	 * Keep track of the fact that EL_ON3 was on but we haven't power
14932ce3b32SDouglas Anderson 	 * cycled yet. This lets us know that "el_on3_off_time" is recent (we
15032ce3b32SDouglas Anderson 	 * don't need to worry about ktime wraparounds) and also makes it
15132ce3b32SDouglas Anderson 	 * obvious if we try to enable again without a power cycle (see the
15232ce3b32SDouglas Anderson 	 * warning in atana33xc20_enable()).
15332ce3b32SDouglas Anderson 	 */
15432ce3b32SDouglas Anderson 	p->el3_was_on = true;
15532ce3b32SDouglas Anderson 
15632ce3b32SDouglas Anderson 	/*
15732ce3b32SDouglas Anderson 	 * Sleeping 20 ms here (after setting the GPIO) avoids a glitch when
15832ce3b32SDouglas Anderson 	 * powering off.
15932ce3b32SDouglas Anderson 	 */
16032ce3b32SDouglas Anderson 	msleep(20);
16132ce3b32SDouglas Anderson 
16232ce3b32SDouglas Anderson 	return 0;
16332ce3b32SDouglas Anderson }
16432ce3b32SDouglas Anderson 
atana33xc20_enable(struct drm_panel * panel)16532ce3b32SDouglas Anderson static int atana33xc20_enable(struct drm_panel *panel)
16632ce3b32SDouglas Anderson {
16732ce3b32SDouglas Anderson 	struct atana33xc20_panel *p = to_atana33xc20(panel);
16832ce3b32SDouglas Anderson 
16932ce3b32SDouglas Anderson 	/*
17032ce3b32SDouglas Anderson 	 * Once EL_ON3 drops we absolutely need a power cycle before the next
17132ce3b32SDouglas Anderson 	 * enable or the backlight will never come on again. The code ensures
17232ce3b32SDouglas Anderson 	 * this because disable() is _always_ followed by unprepare() and
17332ce3b32SDouglas Anderson 	 * unprepare() forces a suspend with pm_runtime_put_sync_suspend(),
17432ce3b32SDouglas Anderson 	 * but let's track just to make sure since the requirement is so
17532ce3b32SDouglas Anderson 	 * non-obvious.
17632ce3b32SDouglas Anderson 	 */
17732ce3b32SDouglas Anderson 	if (WARN_ON(p->el3_was_on))
17832ce3b32SDouglas Anderson 		return -EIO;
17932ce3b32SDouglas Anderson 
18032ce3b32SDouglas Anderson 	/*
18132ce3b32SDouglas Anderson 	 * Note 2 (Example of power on sequence in detail) in spec specifies
18232ce3b32SDouglas Anderson 	 * to wait 400 ms after powering on before asserting EL3_on.
18332ce3b32SDouglas Anderson 	 */
18432ce3b32SDouglas Anderson 	atana33xc20_wait(p->powered_on_time, 400);
18532ce3b32SDouglas Anderson 
18632ce3b32SDouglas Anderson 	gpiod_set_value_cansleep(p->el_on3_gpio, 1);
18732ce3b32SDouglas Anderson 
18832ce3b32SDouglas Anderson 	return 0;
18932ce3b32SDouglas Anderson }
19032ce3b32SDouglas Anderson 
atana33xc20_unprepare(struct drm_panel * panel)19132ce3b32SDouglas Anderson static int atana33xc20_unprepare(struct drm_panel *panel)
19232ce3b32SDouglas Anderson {
19332ce3b32SDouglas Anderson 	int ret;
19432ce3b32SDouglas Anderson 
19532ce3b32SDouglas Anderson 	/*
19632ce3b32SDouglas Anderson 	 * Purposely do a put_sync, don't use autosuspend. The panel's tcon
19732ce3b32SDouglas Anderson 	 * seems to sometimes crash when you stop giving it data and this is
19832ce3b32SDouglas Anderson 	 * the best way to ensure it will come back.
19932ce3b32SDouglas Anderson 	 *
20032ce3b32SDouglas Anderson 	 * NOTE: we still want autosuspend for cases where we only turn on
20132ce3b32SDouglas Anderson 	 * to get the EDID or otherwise send DP AUX commands to the panel.
20232ce3b32SDouglas Anderson 	 */
20332ce3b32SDouglas Anderson 	ret = pm_runtime_put_sync_suspend(panel->dev);
20432ce3b32SDouglas Anderson 	if (ret < 0)
20532ce3b32SDouglas Anderson 		return ret;
20632ce3b32SDouglas Anderson 
20732ce3b32SDouglas Anderson 	return 0;
20832ce3b32SDouglas Anderson }
20932ce3b32SDouglas Anderson 
atana33xc20_prepare(struct drm_panel * panel)21032ce3b32SDouglas Anderson static int atana33xc20_prepare(struct drm_panel *panel)
21132ce3b32SDouglas Anderson {
21232ce3b32SDouglas Anderson 	int ret;
21332ce3b32SDouglas Anderson 
21432ce3b32SDouglas Anderson 	ret = pm_runtime_get_sync(panel->dev);
21532ce3b32SDouglas Anderson 	if (ret < 0) {
21632ce3b32SDouglas Anderson 		pm_runtime_put_autosuspend(panel->dev);
21732ce3b32SDouglas Anderson 		return ret;
21832ce3b32SDouglas Anderson 	}
21932ce3b32SDouglas Anderson 
22032ce3b32SDouglas Anderson 	return 0;
22132ce3b32SDouglas Anderson }
22232ce3b32SDouglas Anderson 
atana33xc20_get_modes(struct drm_panel * panel,struct drm_connector * connector)22332ce3b32SDouglas Anderson static int atana33xc20_get_modes(struct drm_panel *panel,
22432ce3b32SDouglas Anderson 				 struct drm_connector *connector)
22532ce3b32SDouglas Anderson {
22632ce3b32SDouglas Anderson 	struct atana33xc20_panel *p = to_atana33xc20(panel);
22732ce3b32SDouglas Anderson 	struct dp_aux_ep_device *aux_ep = to_dp_aux_ep_dev(panel->dev);
22832ce3b32SDouglas Anderson 	int num = 0;
22932ce3b32SDouglas Anderson 
23032ce3b32SDouglas Anderson 	pm_runtime_get_sync(panel->dev);
23132ce3b32SDouglas Anderson 
232*a9c428f1SJani Nikula 	if (!p->drm_edid)
233*a9c428f1SJani Nikula 		p->drm_edid = drm_edid_read_ddc(connector, &aux_ep->aux->ddc);
234*a9c428f1SJani Nikula 
235*a9c428f1SJani Nikula 	drm_edid_connector_update(connector, p->drm_edid);
236*a9c428f1SJani Nikula 
237*a9c428f1SJani Nikula 	num = drm_edid_connector_add_modes(connector);
23832ce3b32SDouglas Anderson 
23932ce3b32SDouglas Anderson 	pm_runtime_mark_last_busy(panel->dev);
24032ce3b32SDouglas Anderson 	pm_runtime_put_autosuspend(panel->dev);
24132ce3b32SDouglas Anderson 
24232ce3b32SDouglas Anderson 	return num;
24332ce3b32SDouglas Anderson }
24432ce3b32SDouglas Anderson 
24532ce3b32SDouglas Anderson static const struct drm_panel_funcs atana33xc20_funcs = {
24632ce3b32SDouglas Anderson 	.disable = atana33xc20_disable,
24732ce3b32SDouglas Anderson 	.enable = atana33xc20_enable,
24832ce3b32SDouglas Anderson 	.unprepare = atana33xc20_unprepare,
24932ce3b32SDouglas Anderson 	.prepare = atana33xc20_prepare,
25032ce3b32SDouglas Anderson 	.get_modes = atana33xc20_get_modes,
25132ce3b32SDouglas Anderson };
25232ce3b32SDouglas Anderson 
atana33xc20_runtime_disable(void * data)25332ce3b32SDouglas Anderson static void atana33xc20_runtime_disable(void *data)
25432ce3b32SDouglas Anderson {
25532ce3b32SDouglas Anderson 	pm_runtime_disable(data);
25632ce3b32SDouglas Anderson }
25732ce3b32SDouglas Anderson 
atana33xc20_dont_use_autosuspend(void * data)25832ce3b32SDouglas Anderson static void atana33xc20_dont_use_autosuspend(void *data)
25932ce3b32SDouglas Anderson {
26032ce3b32SDouglas Anderson 	pm_runtime_dont_use_autosuspend(data);
26132ce3b32SDouglas Anderson }
26232ce3b32SDouglas Anderson 
atana33xc20_probe(struct dp_aux_ep_device * aux_ep)26332ce3b32SDouglas Anderson static int atana33xc20_probe(struct dp_aux_ep_device *aux_ep)
26432ce3b32SDouglas Anderson {
26532ce3b32SDouglas Anderson 	struct atana33xc20_panel *panel;
26632ce3b32SDouglas Anderson 	struct device *dev = &aux_ep->dev;
26732ce3b32SDouglas Anderson 	int ret;
26832ce3b32SDouglas Anderson 
26932ce3b32SDouglas Anderson 	panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
27032ce3b32SDouglas Anderson 	if (!panel)
27132ce3b32SDouglas Anderson 		return -ENOMEM;
27232ce3b32SDouglas Anderson 	dev_set_drvdata(dev, panel);
27332ce3b32SDouglas Anderson 
2743b5765dfSDouglas Anderson 	panel->aux = aux_ep->aux;
2753b5765dfSDouglas Anderson 
27632ce3b32SDouglas Anderson 	panel->supply = devm_regulator_get(dev, "power");
27732ce3b32SDouglas Anderson 	if (IS_ERR(panel->supply))
27832ce3b32SDouglas Anderson 		return dev_err_probe(dev, PTR_ERR(panel->supply),
27932ce3b32SDouglas Anderson 				     "Failed to get power supply\n");
28032ce3b32SDouglas Anderson 
28132ce3b32SDouglas Anderson 	panel->el_on3_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
28232ce3b32SDouglas Anderson 	if (IS_ERR(panel->el_on3_gpio))
28332ce3b32SDouglas Anderson 		return dev_err_probe(dev, PTR_ERR(panel->el_on3_gpio),
28432ce3b32SDouglas Anderson 				     "Failed to get enable GPIO\n");
28532ce3b32SDouglas Anderson 
28632ce3b32SDouglas Anderson 	panel->no_hpd = of_property_read_bool(dev->of_node, "no-hpd");
28732ce3b32SDouglas Anderson 	if (!panel->no_hpd) {
28832ce3b32SDouglas Anderson 		panel->hpd_gpio = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN);
28932ce3b32SDouglas Anderson 		if (IS_ERR(panel->hpd_gpio))
29032ce3b32SDouglas Anderson 			return dev_err_probe(dev, PTR_ERR(panel->hpd_gpio),
29132ce3b32SDouglas Anderson 					     "Failed to get HPD GPIO\n");
29232ce3b32SDouglas Anderson 	}
29332ce3b32SDouglas Anderson 
29432ce3b32SDouglas Anderson 	pm_runtime_enable(dev);
29532ce3b32SDouglas Anderson 	ret = devm_add_action_or_reset(dev,  atana33xc20_runtime_disable, dev);
29632ce3b32SDouglas Anderson 	if (ret)
29732ce3b32SDouglas Anderson 		return ret;
2988d5d063fSDrew Davenport 	pm_runtime_set_autosuspend_delay(dev, 2000);
29932ce3b32SDouglas Anderson 	pm_runtime_use_autosuspend(dev);
30032ce3b32SDouglas Anderson 	ret = devm_add_action_or_reset(dev,  atana33xc20_dont_use_autosuspend, dev);
30132ce3b32SDouglas Anderson 	if (ret)
30232ce3b32SDouglas Anderson 		return ret;
30332ce3b32SDouglas Anderson 
30432ce3b32SDouglas Anderson 	drm_panel_init(&panel->base, dev, &atana33xc20_funcs, DRM_MODE_CONNECTOR_eDP);
30532ce3b32SDouglas Anderson 
30632ce3b32SDouglas Anderson 	pm_runtime_get_sync(dev);
30732ce3b32SDouglas Anderson 	ret = drm_panel_dp_aux_backlight(&panel->base, aux_ep->aux);
30832ce3b32SDouglas Anderson 	pm_runtime_mark_last_busy(dev);
30932ce3b32SDouglas Anderson 	pm_runtime_put_autosuspend(dev);
310b48ccb18SDouglas Anderson 
311b48ccb18SDouglas Anderson 	/*
312b48ccb18SDouglas Anderson 	 * Warn if we get an error, but don't consider it fatal. Having
313b48ccb18SDouglas Anderson 	 * a panel where we can't control the backlight is better than
314b48ccb18SDouglas Anderson 	 * no panel.
315b48ccb18SDouglas Anderson 	 */
31632ce3b32SDouglas Anderson 	if (ret)
317b48ccb18SDouglas Anderson 		dev_warn(dev, "failed to register dp aux backlight: %d\n", ret);
31832ce3b32SDouglas Anderson 
31932ce3b32SDouglas Anderson 	drm_panel_add(&panel->base);
32032ce3b32SDouglas Anderson 
32132ce3b32SDouglas Anderson 	return 0;
32232ce3b32SDouglas Anderson }
32332ce3b32SDouglas Anderson 
atana33xc20_remove(struct dp_aux_ep_device * aux_ep)32432ce3b32SDouglas Anderson static void atana33xc20_remove(struct dp_aux_ep_device *aux_ep)
32532ce3b32SDouglas Anderson {
32632ce3b32SDouglas Anderson 	struct device *dev = &aux_ep->dev;
32732ce3b32SDouglas Anderson 	struct atana33xc20_panel *panel = dev_get_drvdata(dev);
32832ce3b32SDouglas Anderson 
32932ce3b32SDouglas Anderson 	drm_panel_remove(&panel->base);
33032ce3b32SDouglas Anderson 
331*a9c428f1SJani Nikula 	drm_edid_free(panel->drm_edid);
33232ce3b32SDouglas Anderson }
33332ce3b32SDouglas Anderson 
33432ce3b32SDouglas Anderson static const struct of_device_id atana33xc20_dt_match[] = {
33532ce3b32SDouglas Anderson 	{ .compatible = "samsung,atna33xc20", },
33632ce3b32SDouglas Anderson 	{ /* sentinal */ }
33732ce3b32SDouglas Anderson };
33832ce3b32SDouglas Anderson MODULE_DEVICE_TABLE(of, atana33xc20_dt_match);
33932ce3b32SDouglas Anderson 
34032ce3b32SDouglas Anderson static const struct dev_pm_ops atana33xc20_pm_ops = {
34132ce3b32SDouglas Anderson 	SET_RUNTIME_PM_OPS(atana33xc20_suspend, atana33xc20_resume, NULL)
34232ce3b32SDouglas Anderson 	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
34332ce3b32SDouglas Anderson 				pm_runtime_force_resume)
34432ce3b32SDouglas Anderson };
34532ce3b32SDouglas Anderson 
34632ce3b32SDouglas Anderson static struct dp_aux_ep_driver atana33xc20_driver = {
34732ce3b32SDouglas Anderson 	.driver = {
34832ce3b32SDouglas Anderson 		.name		= "samsung_atana33xc20",
34932ce3b32SDouglas Anderson 		.of_match_table = atana33xc20_dt_match,
35032ce3b32SDouglas Anderson 		.pm		= &atana33xc20_pm_ops,
35132ce3b32SDouglas Anderson 	},
35232ce3b32SDouglas Anderson 	.probe = atana33xc20_probe,
35332ce3b32SDouglas Anderson 	.remove = atana33xc20_remove,
35432ce3b32SDouglas Anderson };
35532ce3b32SDouglas Anderson 
atana33xc20_init(void)35632ce3b32SDouglas Anderson static int __init atana33xc20_init(void)
35732ce3b32SDouglas Anderson {
35832ce3b32SDouglas Anderson 	return dp_aux_dp_driver_register(&atana33xc20_driver);
35932ce3b32SDouglas Anderson }
36032ce3b32SDouglas Anderson module_init(atana33xc20_init);
36132ce3b32SDouglas Anderson 
atana33xc20_exit(void)36232ce3b32SDouglas Anderson static void __exit atana33xc20_exit(void)
36332ce3b32SDouglas Anderson {
36432ce3b32SDouglas Anderson 	dp_aux_dp_driver_unregister(&atana33xc20_driver);
36532ce3b32SDouglas Anderson }
36632ce3b32SDouglas Anderson module_exit(atana33xc20_exit);
36732ce3b32SDouglas Anderson 
36832ce3b32SDouglas Anderson MODULE_DESCRIPTION("Samsung ATANA33XC20 Panel Driver");
36932ce3b32SDouglas Anderson MODULE_LICENSE("GPL v2");
370