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