1a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul/*
2a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul * NXP PTN3460 DP/LVDS bridge driver
3a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul *
4a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul * Copyright (C) 2013 Google, Inc.
5a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul *
6a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul * This software is licensed under the terms of the GNU General Public
7a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul * License version 2, as published by the Free Software Foundation, and
8a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul * may be copied, distributed, and modified under those terms.
9a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul *
10a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul * This program is distributed in the hope that it will be useful,
11a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul * but WITHOUT ANY WARRANTY; without even the implied warranty of
12a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul * GNU General Public License for more details.
14a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul */
15a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
16a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul#include <linux/module.h>
17a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul#include <linux/of.h>
18a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul#include <linux/of_gpio.h>
19a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul#include <linux/i2c.h>
20a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul#include <linux/gpio.h>
21a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul#include <linux/delay.h>
22a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
23a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul#include "drmP.h"
24a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul#include "drm_edid.h"
25a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul#include "drm_crtc.h"
26a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul#include "drm_crtc_helper.h"
27a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
28a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul#include "bridge/ptn3460.h"
29a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
30a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul#define PTN3460_EDID_ADDR			0x0
31a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul#define PTN3460_EDID_EMULATION_ADDR		0x84
32a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul#define PTN3460_EDID_ENABLE_EMULATION		0
33a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul#define PTN3460_EDID_EMULATION_SELECTION	1
34a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul#define PTN3460_EDID_SRAM_LOAD_ADDR		0x85
35a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
36a9fe713d7d45c639604420b56c59ca5fd479731bSean Paulstruct ptn3460_bridge {
37a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	struct drm_connector connector;
38a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	struct i2c_client *client;
39a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	struct drm_encoder *encoder;
40a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	struct drm_bridge *bridge;
41a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	struct edid *edid;
42a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	int gpio_pd_n;
43a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	int gpio_rst_n;
44a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	u32 edid_emulation;
45a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	bool enabled;
46a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul};
47a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
48a9fe713d7d45c639604420b56c59ca5fd479731bSean Paulstatic int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr,
49a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		u8 *buf, int len)
50a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul{
51a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	int ret;
52a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
53a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ret = i2c_master_send(ptn_bridge->client, &addr, 1);
54a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (ret <= 0) {
55a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		DRM_ERROR("Failed to send i2c command, ret=%d\n", ret);
56a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		return ret;
57a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	}
58a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
59a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ret = i2c_master_recv(ptn_bridge->client, buf, len);
60a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (ret <= 0) {
61a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret);
62a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		return ret;
63a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	}
64a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
65a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	return 0;
66a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul}
67a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
68a9fe713d7d45c639604420b56c59ca5fd479731bSean Paulstatic int ptn3460_write_byte(struct ptn3460_bridge *ptn_bridge, char addr,
69a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		char val)
70a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul{
71a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	int ret;
72a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	char buf[2];
73a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
74a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	buf[0] = addr;
75a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	buf[1] = val;
76a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
77a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf));
78a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (ret <= 0) {
79a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		DRM_ERROR("Failed to send i2c command, ret=%d\n", ret);
80a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		return ret;
81a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	}
82a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
83a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	return 0;
84a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul}
85a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
86a9fe713d7d45c639604420b56c59ca5fd479731bSean Paulstatic int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge)
87a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul{
88a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	int ret;
89a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	char val;
90a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
91a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	/* Load the selected edid into SRAM (accessed at PTN3460_EDID_ADDR) */
92a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_SRAM_LOAD_ADDR,
93a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul			ptn_bridge->edid_emulation);
94a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (ret) {
95a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		DRM_ERROR("Failed to transfer edid to sram, ret=%d\n", ret);
96a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		return ret;
97a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	}
98a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
99a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	/* Enable EDID emulation and select the desired EDID */
100a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	val = 1 << PTN3460_EDID_ENABLE_EMULATION |
101a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		ptn_bridge->edid_emulation << PTN3460_EDID_EMULATION_SELECTION;
102a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
103a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val);
104a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (ret) {
105a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		DRM_ERROR("Failed to write edid value, ret=%d\n", ret);
106a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		return ret;
107a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	}
108a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
109a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	return 0;
110a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul}
111a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
112a9fe713d7d45c639604420b56c59ca5fd479731bSean Paulstatic void ptn3460_pre_enable(struct drm_bridge *bridge)
113a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul{
114a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
115a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	int ret;
116a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
117a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (ptn_bridge->enabled)
118a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		return;
119a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
120a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
121a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		gpio_set_value(ptn_bridge->gpio_pd_n, 1);
122a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
123a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
124a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		gpio_set_value(ptn_bridge->gpio_rst_n, 0);
125a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		udelay(10);
126a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		gpio_set_value(ptn_bridge->gpio_rst_n, 1);
127a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	}
128a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
129a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	/*
130a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	 * There's a bug in the PTN chip where it falsely asserts hotplug before
131a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	 * it is fully functional. We're forced to wait for the maximum start up
132a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	 * time specified in the chip's datasheet to make sure we're really up.
133a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	 */
134a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	msleep(90);
135a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
136a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ret = ptn3460_select_edid(ptn_bridge);
137a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (ret)
138a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		DRM_ERROR("Select edid failed ret=%d\n", ret);
139a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
140a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ptn_bridge->enabled = true;
141a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul}
142a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
143a9fe713d7d45c639604420b56c59ca5fd479731bSean Paulstatic void ptn3460_enable(struct drm_bridge *bridge)
144a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul{
145a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul}
146a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
147a9fe713d7d45c639604420b56c59ca5fd479731bSean Paulstatic void ptn3460_disable(struct drm_bridge *bridge)
148a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul{
149a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
150a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
151a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (!ptn_bridge->enabled)
152a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		return;
153a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
154a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ptn_bridge->enabled = false;
155a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
156a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (gpio_is_valid(ptn_bridge->gpio_rst_n))
157a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		gpio_set_value(ptn_bridge->gpio_rst_n, 1);
158a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
159a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
160a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		gpio_set_value(ptn_bridge->gpio_pd_n, 0);
161a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul}
162a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
163a9fe713d7d45c639604420b56c59ca5fd479731bSean Paulstatic void ptn3460_post_disable(struct drm_bridge *bridge)
164a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul{
165a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul}
166a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
167a9fe713d7d45c639604420b56c59ca5fd479731bSean Paulvoid ptn3460_bridge_destroy(struct drm_bridge *bridge)
168a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul{
169a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
170a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
171a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	drm_bridge_cleanup(bridge);
172a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
173a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		gpio_free(ptn_bridge->gpio_pd_n);
174a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (gpio_is_valid(ptn_bridge->gpio_rst_n))
175a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		gpio_free(ptn_bridge->gpio_rst_n);
176a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	/* Nothing else to free, we've got devm allocated memory */
177a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul}
178a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
179a9fe713d7d45c639604420b56c59ca5fd479731bSean Paulstruct drm_bridge_funcs ptn3460_bridge_funcs = {
180a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	.pre_enable = ptn3460_pre_enable,
181a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	.enable = ptn3460_enable,
182a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	.disable = ptn3460_disable,
183a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	.post_disable = ptn3460_post_disable,
184a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	.destroy = ptn3460_bridge_destroy,
185a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul};
186a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
187a9fe713d7d45c639604420b56c59ca5fd479731bSean Paulint ptn3460_get_modes(struct drm_connector *connector)
188a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul{
189a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	struct ptn3460_bridge *ptn_bridge;
190a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	u8 *edid;
191a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	int ret, num_modes;
192a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	bool power_off;
193a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
194a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ptn_bridge = container_of(connector, struct ptn3460_bridge, connector);
195a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
196a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (ptn_bridge->edid)
197a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		return drm_add_edid_modes(connector, ptn_bridge->edid);
198a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
199a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	power_off = !ptn_bridge->enabled;
200a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ptn3460_pre_enable(ptn_bridge->bridge);
201a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
202a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
203a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (!edid) {
204a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		DRM_ERROR("Failed to allocate edid\n");
205a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		return 0;
206a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	}
207a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
208a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid,
209a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul			EDID_LENGTH);
210a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (ret) {
211a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		kfree(edid);
212a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		num_modes = 0;
213a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		goto out;
214a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	}
215a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
216a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ptn_bridge->edid = (struct edid *)edid;
217a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	drm_mode_connector_update_edid_property(connector, ptn_bridge->edid);
218a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
219a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	num_modes = drm_add_edid_modes(connector, ptn_bridge->edid);
220a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
221a9fe713d7d45c639604420b56c59ca5fd479731bSean Paulout:
222a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (power_off)
223a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		ptn3460_disable(ptn_bridge->bridge);
224a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
225a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	return num_modes;
226a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul}
227a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
228a9fe713d7d45c639604420b56c59ca5fd479731bSean Paulstruct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector)
229a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul{
230a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	struct ptn3460_bridge *ptn_bridge;
231a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
232a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ptn_bridge = container_of(connector, struct ptn3460_bridge, connector);
233a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
234a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	return ptn_bridge->encoder;
235a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul}
236a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
237a9fe713d7d45c639604420b56c59ca5fd479731bSean Paulstruct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
238a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	.get_modes = ptn3460_get_modes,
239a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	.best_encoder = ptn3460_best_encoder,
240a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul};
241a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
242a9fe713d7d45c639604420b56c59ca5fd479731bSean Paulenum drm_connector_status ptn3460_detect(struct drm_connector *connector,
243a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		bool force)
244a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul{
245a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	return connector_status_connected;
246a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul}
247a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
248a9fe713d7d45c639604420b56c59ca5fd479731bSean Paulvoid ptn3460_connector_destroy(struct drm_connector *connector)
249a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul{
250a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	drm_connector_cleanup(connector);
251a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul}
252a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
253a9fe713d7d45c639604420b56c59ca5fd479731bSean Paulstruct drm_connector_funcs ptn3460_connector_funcs = {
254a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	.dpms = drm_helper_connector_dpms,
255a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	.fill_modes = drm_helper_probe_single_connector_modes,
256a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	.detect = ptn3460_detect,
257a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	.destroy = ptn3460_connector_destroy,
258a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul};
259a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
260a9fe713d7d45c639604420b56c59ca5fd479731bSean Paulint ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
261a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		struct i2c_client *client, struct device_node *node)
262a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul{
263a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	int ret;
264a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	struct drm_bridge *bridge;
265a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	struct ptn3460_bridge *ptn_bridge;
266a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
267a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	bridge = devm_kzalloc(dev->dev, sizeof(*bridge), GFP_KERNEL);
268a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (!bridge) {
269a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		DRM_ERROR("Failed to allocate drm bridge\n");
270a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		return -ENOMEM;
271a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	}
272a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
273a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ptn_bridge = devm_kzalloc(dev->dev, sizeof(*ptn_bridge), GFP_KERNEL);
274a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (!ptn_bridge) {
275a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		DRM_ERROR("Failed to allocate ptn bridge\n");
276a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		return -ENOMEM;
277a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	}
278a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
279a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ptn_bridge->client = client;
280a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ptn_bridge->encoder = encoder;
281a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ptn_bridge->bridge = bridge;
282a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ptn_bridge->gpio_pd_n = of_get_named_gpio(node, "powerdown-gpio", 0);
283a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (gpio_is_valid(ptn_bridge->gpio_pd_n)) {
284a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		ret = gpio_request_one(ptn_bridge->gpio_pd_n,
285a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul				GPIOF_OUT_INIT_HIGH, "PTN3460_PD_N");
286a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		if (ret) {
287a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul			DRM_ERROR("Request powerdown-gpio failed (%d)\n", ret);
288a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul			return ret;
289a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		}
290a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	}
291a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
292a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ptn_bridge->gpio_rst_n = of_get_named_gpio(node, "reset-gpio", 0);
293a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
294a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		/*
295a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		 * Request the reset pin low to avoid the bridge being
296a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		 * initialized prematurely
297a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		 */
298a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		ret = gpio_request_one(ptn_bridge->gpio_rst_n,
299a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul				GPIOF_OUT_INIT_LOW, "PTN3460_RST_N");
300a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		if (ret) {
301a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul			DRM_ERROR("Request reset-gpio failed (%d)\n", ret);
302a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul			gpio_free(ptn_bridge->gpio_pd_n);
303a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul			return ret;
304a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		}
305a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	}
306a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
307a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ret = of_property_read_u32(node, "edid-emulation",
308a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul			&ptn_bridge->edid_emulation);
309a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (ret) {
310a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		DRM_ERROR("Can't read edid emulation value\n");
311a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		goto err;
312a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	}
313a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
314a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ret = drm_bridge_init(dev, bridge, &ptn3460_bridge_funcs);
315a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (ret) {
316a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		DRM_ERROR("Failed to initialize bridge with drm\n");
317a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		goto err;
318a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	}
319a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
320a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	bridge->driver_private = ptn_bridge;
321a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	encoder->bridge = bridge;
322a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
323a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	ret = drm_connector_init(dev, &ptn_bridge->connector,
324a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul			&ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
325a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (ret) {
326a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		DRM_ERROR("Failed to initialize connector with drm\n");
327a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		goto err;
328a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	}
329a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	drm_connector_helper_add(&ptn_bridge->connector,
330a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul			&ptn3460_connector_helper_funcs);
33134ea3d386347cd6de4c2fa2491dd85c9e753e7e4Thomas Wood	drm_connector_register(&ptn_bridge->connector);
332a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder);
333a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
334a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	return 0;
335a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul
336a9fe713d7d45c639604420b56c59ca5fd479731bSean Paulerr:
337a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (gpio_is_valid(ptn_bridge->gpio_pd_n))
338a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		gpio_free(ptn_bridge->gpio_pd_n);
339a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	if (gpio_is_valid(ptn_bridge->gpio_rst_n))
340a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul		gpio_free(ptn_bridge->gpio_rst_n);
341a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul	return ret;
342a9fe713d7d45c639604420b56c59ca5fd479731bSean Paul}
34396e112c44477edea1c01fbb976205e751f4229b9Inki DaeEXPORT_SYMBOL(ptn3460_init);
344