drm/tegra: Remove remnants of the output midlayer
[deliverable/linux.git] / drivers / gpu / drm / tegra / output.c
CommitLineData
d8f4a9ed
TR
1/*
2 * Copyright (C) 2012 Avionic Design GmbH
3 * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9
d8f4a9ed 10#include <linux/of_gpio.h>
d8f4a9ed 11
9be7d864 12#include <drm/drm_panel.h>
d8f4a9ed
TR
13#include "drm.h"
14
132085d8 15int tegra_output_connector_get_modes(struct drm_connector *connector)
d8f4a9ed
TR
16{
17 struct tegra_output *output = connector_to_output(connector);
18 struct edid *edid = NULL;
19 int err = 0;
20
acde5413
TR
21 /*
22 * If the panel provides one or more modes, use them exclusively and
23 * ignore any other means of obtaining a mode.
24 */
9be7d864
TR
25 if (output->panel) {
26 err = output->panel->funcs->get_modes(output->panel);
27 if (err > 0)
28 return err;
29 }
30
d8f4a9ed
TR
31 if (output->edid)
32 edid = kmemdup(output->edid, sizeof(*edid), GFP_KERNEL);
33 else if (output->ddc)
34 edid = drm_get_edid(connector, output->ddc);
35
36 drm_mode_connector_update_edid_property(connector, edid);
37
38 if (edid) {
39 err = drm_add_edid_modes(connector, edid);
40 kfree(edid);
41 }
42
43 return err;
44}
45
132085d8
TR
46struct drm_encoder *
47tegra_output_connector_best_encoder(struct drm_connector *connector)
d8f4a9ed
TR
48{
49 struct tegra_output *output = connector_to_output(connector);
50
51 return &output->encoder;
52}
53
132085d8
TR
54enum drm_connector_status
55tegra_output_connector_detect(struct drm_connector *connector, bool force)
d8f4a9ed
TR
56{
57 struct tegra_output *output = connector_to_output(connector);
58 enum drm_connector_status status = connector_status_unknown;
59
60 if (gpio_is_valid(output->hpd_gpio)) {
61 if (gpio_get_value(output->hpd_gpio) == 0)
62 status = connector_status_disconnected;
63 else
64 status = connector_status_connected;
65 } else {
9be7d864
TR
66 if (!output->panel)
67 status = connector_status_disconnected;
68 else
69 status = connector_status_connected;
d8f4a9ed
TR
70 }
71
72 return status;
73}
74
132085d8 75void tegra_output_connector_destroy(struct drm_connector *connector)
d8f4a9ed 76{
34ea3d38 77 drm_connector_unregister(connector);
d8f4a9ed
TR
78 drm_connector_cleanup(connector);
79}
80
132085d8 81void tegra_output_encoder_destroy(struct drm_encoder *encoder)
d8f4a9ed
TR
82{
83 drm_encoder_cleanup(encoder);
84}
85
d8f4a9ed
TR
86static irqreturn_t hpd_irq(int irq, void *data)
87{
88 struct tegra_output *output = data;
89
8fc8f7da
TR
90 if (output->connector.dev)
91 drm_helper_hpd_irq_event(output->connector.dev);
d8f4a9ed
TR
92
93 return IRQ_HANDLED;
94}
95
59d29c0e 96int tegra_output_probe(struct tegra_output *output)
d8f4a9ed 97{
9be7d864 98 struct device_node *ddc, *panel;
d8f4a9ed 99 enum of_gpio_flags flags;
7236aa03 100 int err, size;
d8f4a9ed
TR
101
102 if (!output->of_node)
103 output->of_node = output->dev->of_node;
104
9be7d864
TR
105 panel = of_parse_phandle(output->of_node, "nvidia,panel", 0);
106 if (panel) {
107 output->panel = of_drm_find_panel(panel);
108 if (!output->panel)
109 return -EPROBE_DEFER;
110
111 of_node_put(panel);
112 }
113
d8f4a9ed
TR
114 output->edid = of_get_property(output->of_node, "nvidia,edid", &size);
115
116 ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0);
117 if (ddc) {
118 output->ddc = of_find_i2c_adapter_by_node(ddc);
119 if (!output->ddc) {
120 err = -EPROBE_DEFER;
121 of_node_put(ddc);
122 return err;
123 }
124
125 of_node_put(ddc);
126 }
127
d8f4a9ed
TR
128 output->hpd_gpio = of_get_named_gpio_flags(output->of_node,
129 "nvidia,hpd-gpio", 0,
130 &flags);
d8f4a9ed
TR
131 if (gpio_is_valid(output->hpd_gpio)) {
132 unsigned long flags;
133
134 err = gpio_request_one(output->hpd_gpio, GPIOF_DIR_IN,
135 "HDMI hotplug detect");
136 if (err < 0) {
137 dev_err(output->dev, "gpio_request_one(): %d\n", err);
138 return err;
139 }
140
141 err = gpio_to_irq(output->hpd_gpio);
142 if (err < 0) {
143 dev_err(output->dev, "gpio_to_irq(): %d\n", err);
59d29c0e
TR
144 gpio_free(output->hpd_gpio);
145 return err;
d8f4a9ed
TR
146 }
147
148 output->hpd_irq = err;
149
150 flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
151 IRQF_ONESHOT;
152
153 err = request_threaded_irq(output->hpd_irq, NULL, hpd_irq,
154 flags, "hpd", output);
155 if (err < 0) {
156 dev_err(output->dev, "failed to request IRQ#%u: %d\n",
157 output->hpd_irq, err);
59d29c0e
TR
158 gpio_free(output->hpd_gpio);
159 return err;
d8f4a9ed
TR
160 }
161
162 output->connector.polled = DRM_CONNECTOR_POLL_HPD;
8fc8f7da
TR
163
164 /*
165 * Disable the interrupt until the connector has been
166 * initialized to avoid a race in the hotplug interrupt
167 * handler.
168 */
169 disable_irq(output->hpd_irq);
d8f4a9ed
TR
170 }
171
59d29c0e
TR
172 return 0;
173}
174
175int tegra_output_remove(struct tegra_output *output)
176{
177 if (gpio_is_valid(output->hpd_gpio)) {
178 free_irq(output->hpd_irq, output);
179 gpio_free(output->hpd_gpio);
180 }
181
182 if (output->ddc)
183 put_device(&output->ddc->dev);
184
185 return 0;
186}
187
188int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
189{
ea130b24 190 int err;
d8f4a9ed 191
ea130b24
TR
192 if (output->panel) {
193 err = drm_panel_attach(output->panel, &output->connector);
194 if (err < 0)
195 return err;
196 }
d8f4a9ed 197
8fc8f7da
TR
198 /*
199 * The connector is now registered and ready to receive hotplug events
200 * so the hotplug interrupt can be enabled.
201 */
202 if (gpio_is_valid(output->hpd_gpio))
203 enable_irq(output->hpd_irq);
204
d8f4a9ed 205 return 0;
d8f4a9ed
TR
206}
207
208int tegra_output_exit(struct tegra_output *output)
209{
8fc8f7da
TR
210 /*
211 * The connector is going away, so the interrupt must be disabled to
212 * prevent the hotplug interrupt handler from potentially crashing.
213 */
214 if (gpio_is_valid(output->hpd_gpio))
215 disable_irq(output->hpd_irq);
216
9aaa0ceb
TR
217 if (output->panel)
218 drm_panel_detach(output->panel);
219
d8f4a9ed
TR
220 return 0;
221}
This page took 0.123838 seconds and 5 git commands to generate.