blob: 7adeb607f6fb7413557b5d76f7899688732e3eef [file] [log] [blame]
Sean Paula9fe7132014-02-24 19:31:24 +09001/*
2 * NXP PTN3460 DP/LVDS bridge driver
3 *
4 * Copyright (C) 2013 Google, Inc.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
Ajay Kumar94d50d52015-01-20 22:08:42 +053016#include <linux/delay.h>
17#include <linux/gpio.h>
18#include <linux/i2c.h>
Sean Paula9fe7132014-02-24 19:31:24 +090019#include <linux/module.h>
20#include <linux/of.h>
21#include <linux/of_gpio.h>
Sean Paula9fe7132014-02-24 19:31:24 +090022
23#include "bridge/ptn3460.h"
24
Ajay Kumar94d50d52015-01-20 22:08:42 +053025#include "drm_crtc.h"
26#include "drm_crtc_helper.h"
27#include "drm_edid.h"
28#include "drmP.h"
29
Sean Paula9fe7132014-02-24 19:31:24 +090030#define PTN3460_EDID_ADDR 0x0
31#define PTN3460_EDID_EMULATION_ADDR 0x84
32#define PTN3460_EDID_ENABLE_EMULATION 0
33#define PTN3460_EDID_EMULATION_SELECTION 1
34#define PTN3460_EDID_SRAM_LOAD_ADDR 0x85
35
36struct ptn3460_bridge {
37 struct drm_connector connector;
38 struct i2c_client *client;
Ajay Kumar94d50d52015-01-20 22:08:42 +053039 struct drm_bridge bridge;
Sean Paula9fe7132014-02-24 19:31:24 +090040 struct edid *edid;
41 int gpio_pd_n;
42 int gpio_rst_n;
43 u32 edid_emulation;
44 bool enabled;
45};
46
Ajay Kumar94d50d52015-01-20 22:08:42 +053047static inline struct ptn3460_bridge *
48 bridge_to_ptn3460(struct drm_bridge *bridge)
49{
50 return container_of(bridge, struct ptn3460_bridge, bridge);
51}
52
53static inline struct ptn3460_bridge *
54 connector_to_ptn3460(struct drm_connector *connector)
55{
56 return container_of(connector, struct ptn3460_bridge, connector);
57}
58
Sean Paula9fe7132014-02-24 19:31:24 +090059static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr,
60 u8 *buf, int len)
61{
62 int ret;
63
64 ret = i2c_master_send(ptn_bridge->client, &addr, 1);
65 if (ret <= 0) {
66 DRM_ERROR("Failed to send i2c command, ret=%d\n", ret);
67 return ret;
68 }
69
70 ret = i2c_master_recv(ptn_bridge->client, buf, len);
71 if (ret <= 0) {
72 DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret);
73 return ret;
74 }
75
76 return 0;
77}
78
79static int ptn3460_write_byte(struct ptn3460_bridge *ptn_bridge, char addr,
80 char val)
81{
82 int ret;
83 char buf[2];
84
85 buf[0] = addr;
86 buf[1] = val;
87
88 ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf));
89 if (ret <= 0) {
90 DRM_ERROR("Failed to send i2c command, ret=%d\n", ret);
91 return ret;
92 }
93
94 return 0;
95}
96
97static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge)
98{
99 int ret;
100 char val;
101
102 /* Load the selected edid into SRAM (accessed at PTN3460_EDID_ADDR) */
103 ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_SRAM_LOAD_ADDR,
104 ptn_bridge->edid_emulation);
105 if (ret) {
Ajay Kumar94d50d52015-01-20 22:08:42 +0530106 DRM_ERROR("Failed to transfer EDID to sram, ret=%d\n", ret);
Sean Paula9fe7132014-02-24 19:31:24 +0900107 return ret;
108 }
109
110 /* Enable EDID emulation and select the desired EDID */
111 val = 1 << PTN3460_EDID_ENABLE_EMULATION |
112 ptn_bridge->edid_emulation << PTN3460_EDID_EMULATION_SELECTION;
113
114 ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val);
115 if (ret) {
Ajay Kumar94d50d52015-01-20 22:08:42 +0530116 DRM_ERROR("Failed to write EDID value, ret=%d\n", ret);
Sean Paula9fe7132014-02-24 19:31:24 +0900117 return ret;
118 }
119
120 return 0;
121}
122
123static void ptn3460_pre_enable(struct drm_bridge *bridge)
124{
Ajay Kumar94d50d52015-01-20 22:08:42 +0530125 struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
Sean Paula9fe7132014-02-24 19:31:24 +0900126 int ret;
127
128 if (ptn_bridge->enabled)
129 return;
130
131 if (gpio_is_valid(ptn_bridge->gpio_pd_n))
132 gpio_set_value(ptn_bridge->gpio_pd_n, 1);
133
134 if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
135 gpio_set_value(ptn_bridge->gpio_rst_n, 0);
Ajay Kumar94d50d52015-01-20 22:08:42 +0530136 usleep_range(10, 20);
Sean Paula9fe7132014-02-24 19:31:24 +0900137 gpio_set_value(ptn_bridge->gpio_rst_n, 1);
138 }
139
140 /*
141 * There's a bug in the PTN chip where it falsely asserts hotplug before
142 * it is fully functional. We're forced to wait for the maximum start up
143 * time specified in the chip's datasheet to make sure we're really up.
144 */
145 msleep(90);
146
147 ret = ptn3460_select_edid(ptn_bridge);
148 if (ret)
Ajay Kumar94d50d52015-01-20 22:08:42 +0530149 DRM_ERROR("Select EDID failed ret=%d\n", ret);
Sean Paula9fe7132014-02-24 19:31:24 +0900150
151 ptn_bridge->enabled = true;
152}
153
154static void ptn3460_enable(struct drm_bridge *bridge)
155{
156}
157
158static void ptn3460_disable(struct drm_bridge *bridge)
159{
Ajay Kumar94d50d52015-01-20 22:08:42 +0530160 struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
Sean Paula9fe7132014-02-24 19:31:24 +0900161
162 if (!ptn_bridge->enabled)
163 return;
164
165 ptn_bridge->enabled = false;
166
167 if (gpio_is_valid(ptn_bridge->gpio_rst_n))
168 gpio_set_value(ptn_bridge->gpio_rst_n, 1);
169
170 if (gpio_is_valid(ptn_bridge->gpio_pd_n))
171 gpio_set_value(ptn_bridge->gpio_pd_n, 0);
172}
173
174static void ptn3460_post_disable(struct drm_bridge *bridge)
175{
176}
177
Ajay Kumar94d50d52015-01-20 22:08:42 +0530178static int ptn3460_get_modes(struct drm_connector *connector)
Sean Paula9fe7132014-02-24 19:31:24 +0900179{
180 struct ptn3460_bridge *ptn_bridge;
181 u8 *edid;
Ajay Kumar94d50d52015-01-20 22:08:42 +0530182 int ret, num_modes = 0;
Sean Paula9fe7132014-02-24 19:31:24 +0900183 bool power_off;
184
Ajay Kumar94d50d52015-01-20 22:08:42 +0530185 ptn_bridge = connector_to_ptn3460(connector);
Sean Paula9fe7132014-02-24 19:31:24 +0900186
187 if (ptn_bridge->edid)
188 return drm_add_edid_modes(connector, ptn_bridge->edid);
189
190 power_off = !ptn_bridge->enabled;
Ajay Kumar94d50d52015-01-20 22:08:42 +0530191 ptn3460_pre_enable(&ptn_bridge->bridge);
Sean Paula9fe7132014-02-24 19:31:24 +0900192
193 edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
194 if (!edid) {
Ajay Kumar94d50d52015-01-20 22:08:42 +0530195 DRM_ERROR("Failed to allocate EDID\n");
Sean Paula9fe7132014-02-24 19:31:24 +0900196 return 0;
197 }
198
199 ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid,
200 EDID_LENGTH);
201 if (ret) {
202 kfree(edid);
Sean Paula9fe7132014-02-24 19:31:24 +0900203 goto out;
204 }
205
206 ptn_bridge->edid = (struct edid *)edid;
207 drm_mode_connector_update_edid_property(connector, ptn_bridge->edid);
208
209 num_modes = drm_add_edid_modes(connector, ptn_bridge->edid);
210
211out:
212 if (power_off)
Ajay Kumar94d50d52015-01-20 22:08:42 +0530213 ptn3460_disable(&ptn_bridge->bridge);
Sean Paula9fe7132014-02-24 19:31:24 +0900214
215 return num_modes;
216}
217
Ajay Kumar94d50d52015-01-20 22:08:42 +0530218static struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector)
Sean Paula9fe7132014-02-24 19:31:24 +0900219{
Ajay Kumar94d50d52015-01-20 22:08:42 +0530220 struct ptn3460_bridge *ptn_bridge = connector_to_ptn3460(connector);
Sean Paula9fe7132014-02-24 19:31:24 +0900221
Ajay Kumar6a1688a2015-01-20 22:08:45 +0530222 return ptn_bridge->bridge.encoder;
Sean Paula9fe7132014-02-24 19:31:24 +0900223}
224
Ajay Kumar94d50d52015-01-20 22:08:42 +0530225static struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
Sean Paula9fe7132014-02-24 19:31:24 +0900226 .get_modes = ptn3460_get_modes,
Sean Paula9fe7132014-02-24 19:31:24 +0900227 .best_encoder = ptn3460_best_encoder,
228};
229
Ajay Kumar94d50d52015-01-20 22:08:42 +0530230static enum drm_connector_status ptn3460_detect(struct drm_connector *connector,
Sean Paula9fe7132014-02-24 19:31:24 +0900231 bool force)
232{
233 return connector_status_connected;
234}
235
Ajay Kumar94d50d52015-01-20 22:08:42 +0530236static void ptn3460_connector_destroy(struct drm_connector *connector)
Sean Paula9fe7132014-02-24 19:31:24 +0900237{
238 drm_connector_cleanup(connector);
239}
240
Ajay Kumar94d50d52015-01-20 22:08:42 +0530241static struct drm_connector_funcs ptn3460_connector_funcs = {
Sean Paula9fe7132014-02-24 19:31:24 +0900242 .dpms = drm_helper_connector_dpms,
243 .fill_modes = drm_helper_probe_single_connector_modes,
244 .detect = ptn3460_detect,
245 .destroy = ptn3460_connector_destroy,
246};
247
Ajay Kumar6a1688a2015-01-20 22:08:45 +0530248int ptn3460_bridge_attach(struct drm_bridge *bridge)
Sean Paula9fe7132014-02-24 19:31:24 +0900249{
Ajay Kumar6a1688a2015-01-20 22:08:45 +0530250 struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
Sean Paula9fe7132014-02-24 19:31:24 +0900251 int ret;
Sean Paula9fe7132014-02-24 19:31:24 +0900252
Ajay Kumar6a1688a2015-01-20 22:08:45 +0530253 if (!bridge->encoder) {
254 DRM_ERROR("Parent encoder object not found");
255 return -ENODEV;
256 }
257
258 ret = drm_connector_init(bridge->dev, &ptn_bridge->connector,
259 &ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
260 if (ret) {
261 DRM_ERROR("Failed to initialize connector with drm\n");
262 return ret;
263 }
264 drm_connector_helper_add(&ptn_bridge->connector,
265 &ptn3460_connector_helper_funcs);
266 drm_connector_register(&ptn_bridge->connector);
267 drm_mode_connector_attach_encoder(&ptn_bridge->connector,
268 bridge->encoder);
269
270 return ret;
271}
272
273static struct drm_bridge_funcs ptn3460_bridge_funcs = {
274 .pre_enable = ptn3460_pre_enable,
275 .enable = ptn3460_enable,
276 .disable = ptn3460_disable,
277 .post_disable = ptn3460_post_disable,
278 .attach = ptn3460_bridge_attach,
279};
280
281static int ptn3460_probe(struct i2c_client *client,
282 const struct i2c_device_id *id)
283{
284 struct device *dev = &client->dev;
285 struct ptn3460_bridge *ptn_bridge;
286 int ret;
287
288 ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL);
Sean Paula9fe7132014-02-24 19:31:24 +0900289 if (!ptn_bridge) {
Sean Paula9fe7132014-02-24 19:31:24 +0900290 return -ENOMEM;
291 }
292
293 ptn_bridge->client = client;
Ajay Kumar6a1688a2015-01-20 22:08:45 +0530294 ptn_bridge->gpio_pd_n = of_get_named_gpio(dev->of_node,
295 "powerdown-gpio", 0);
Sean Paula9fe7132014-02-24 19:31:24 +0900296 if (gpio_is_valid(ptn_bridge->gpio_pd_n)) {
297 ret = gpio_request_one(ptn_bridge->gpio_pd_n,
298 GPIOF_OUT_INIT_HIGH, "PTN3460_PD_N");
299 if (ret) {
Ajay Kumar6a1688a2015-01-20 22:08:45 +0530300 dev_err(dev, "Request powerdown-gpio failed (%d)\n",
301 ret);
Sean Paula9fe7132014-02-24 19:31:24 +0900302 return ret;
303 }
304 }
305
Ajay Kumar6a1688a2015-01-20 22:08:45 +0530306 ptn_bridge->gpio_rst_n = of_get_named_gpio(dev->of_node,
307 "reset-gpio", 0);
Sean Paula9fe7132014-02-24 19:31:24 +0900308 if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
309 /*
310 * Request the reset pin low to avoid the bridge being
311 * initialized prematurely
312 */
313 ret = gpio_request_one(ptn_bridge->gpio_rst_n,
314 GPIOF_OUT_INIT_LOW, "PTN3460_RST_N");
315 if (ret) {
Ajay Kumar6a1688a2015-01-20 22:08:45 +0530316 dev_err(dev, "Request reset-gpio failed (%d)\n", ret);
Sean Paula9fe7132014-02-24 19:31:24 +0900317 gpio_free(ptn_bridge->gpio_pd_n);
318 return ret;
319 }
320 }
321
Ajay Kumar6a1688a2015-01-20 22:08:45 +0530322 ret = of_property_read_u32(dev->of_node, "edid-emulation",
Sean Paula9fe7132014-02-24 19:31:24 +0900323 &ptn_bridge->edid_emulation);
324 if (ret) {
Ajay Kumar6a1688a2015-01-20 22:08:45 +0530325 dev_err(dev, "Can't read EDID emulation value\n");
Sean Paula9fe7132014-02-24 19:31:24 +0900326 goto err;
327 }
328
Ajay Kumarb07b90f2015-01-20 22:08:43 +0530329 ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
Ajay Kumar6a1688a2015-01-20 22:08:45 +0530330 ret = drm_bridge_add(&ptn_bridge->bridge);
Sean Paula9fe7132014-02-24 19:31:24 +0900331 if (ret) {
Ajay Kumar6a1688a2015-01-20 22:08:45 +0530332 DRM_ERROR("Failed to add bridge\n");
Sean Paula9fe7132014-02-24 19:31:24 +0900333 goto err;
334 }
335
Ajay Kumar6a1688a2015-01-20 22:08:45 +0530336 i2c_set_clientdata(client, ptn_bridge);
Sean Paula9fe7132014-02-24 19:31:24 +0900337
338 return 0;
339
340err:
341 if (gpio_is_valid(ptn_bridge->gpio_pd_n))
342 gpio_free(ptn_bridge->gpio_pd_n);
343 if (gpio_is_valid(ptn_bridge->gpio_rst_n))
344 gpio_free(ptn_bridge->gpio_rst_n);
345 return ret;
346}
Ajay Kumar3d3f8b12015-01-20 22:08:44 +0530347
Ajay Kumar6a1688a2015-01-20 22:08:45 +0530348static int ptn3460_remove(struct i2c_client *client)
Ajay Kumar3d3f8b12015-01-20 22:08:44 +0530349{
Ajay Kumar6a1688a2015-01-20 22:08:45 +0530350 struct ptn3460_bridge *ptn_bridge = i2c_get_clientdata(client);
351
352 drm_bridge_remove(&ptn_bridge->bridge);
Ajay Kumar3d3f8b12015-01-20 22:08:44 +0530353
354 if (gpio_is_valid(ptn_bridge->gpio_pd_n))
355 gpio_free(ptn_bridge->gpio_pd_n);
356 if (gpio_is_valid(ptn_bridge->gpio_rst_n))
357 gpio_free(ptn_bridge->gpio_rst_n);
Ajay Kumar6a1688a2015-01-20 22:08:45 +0530358
359 return 0;
Ajay Kumar3d3f8b12015-01-20 22:08:44 +0530360}
Ajay Kumar6a1688a2015-01-20 22:08:45 +0530361
362static const struct i2c_device_id ptn3460_i2c_table[] = {
363 {"nxp,ptn3460", 0},
364 {},
365};
366MODULE_DEVICE_TABLE(i2c, ptn3460_i2c_table);
367
368static const struct of_device_id ptn3460_match[] = {
369 { .compatible = "nxp,ptn3460" },
370 {},
371};
372MODULE_DEVICE_TABLE(of, ptn3460_match);
373
374static struct i2c_driver ptn3460_driver = {
375 .id_table = ptn3460_i2c_table,
376 .probe = ptn3460_probe,
377 .remove = ptn3460_remove,
378 .driver = {
379 .name = "nxp,ptn3460",
380 .owner = THIS_MODULE,
381 .of_match_table = ptn3460_match,
382 },
383};
384module_i2c_driver(ptn3460_driver);
385
386MODULE_AUTHOR("Sean Paul <seanpaul@chromium.org>");
387MODULE_DESCRIPTION("NXP ptn3460 eDP-LVDS converter driver");
388MODULE_LICENSE("GPL v2");