116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark/* 216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * Copyright (C) 2012 Texas Instruments 316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * Author: Rob Clark <robdclark@gmail.com> 416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * 516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * This program is free software; you can redistribute it and/or modify it 616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * under the terms of the GNU General Public License version 2 as published by 716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * the Free Software Foundation. 816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * 916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * This program is distributed in the hope that it will be useful, but WITHOUT 1016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 1216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * more details. 1316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * 1416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * You should have received a copy of the GNU General Public License along with 1516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * this program. If not, see <http://www.gnu.org/licenses/>. 1616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark */ 1716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 1816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#include <linux/i2c.h> 1916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#include <linux/gpio.h> 2016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#include <linux/of_gpio.h> 2116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#include <linux/pinctrl/pinmux.h> 2216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#include <linux/pinctrl/consumer.h> 2316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 2416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#include "tilcdc_drv.h" 2516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 2616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstruct tfp410_module { 2716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_module base; 2816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct i2c_adapter *i2c; 2916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark int gpio; 3016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark}; 3116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#define to_tfp410_module(x) container_of(x, struct tfp410_module, base) 3216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 3316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 3416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic const struct tilcdc_panel_info dvi_info = { 3516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .ac_bias = 255, 3616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .ac_bias_intrpt = 0, 3716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .dma_burst_sz = 16, 3816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .bpp = 16, 3916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .fdd = 0x80, 4016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .tft_alt_mode = 0, 4116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .sync_edge = 0, 4216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .sync_ctrl = 1, 4316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .raster_order = 0, 4416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark}; 4516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 4616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark/* 4716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * Encoder: 4816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark */ 4916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 5016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstruct tfp410_encoder { 5116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_encoder base; 5216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tfp410_module *mod; 5316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark int dpms; 5416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark}; 5516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#define to_tfp410_encoder(x) container_of(x, struct tfp410_encoder, base) 5616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 5716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 5816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic void tfp410_encoder_destroy(struct drm_encoder *encoder) 5916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 6016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tfp410_encoder *tfp410_encoder = to_tfp410_encoder(encoder); 6116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark drm_encoder_cleanup(encoder); 6216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark kfree(tfp410_encoder); 6316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 6416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 6516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic void tfp410_encoder_dpms(struct drm_encoder *encoder, int mode) 6616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 6716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tfp410_encoder *tfp410_encoder = to_tfp410_encoder(encoder); 6816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 6916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (tfp410_encoder->dpms == mode) 7016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return; 7116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 7216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (mode == DRM_MODE_DPMS_ON) { 7316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark DBG("Power on"); 7416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark gpio_direction_output(tfp410_encoder->mod->gpio, 1); 7516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } else { 7616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark DBG("Power off"); 7716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark gpio_direction_output(tfp410_encoder->mod->gpio, 0); 7816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 7916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 8016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tfp410_encoder->dpms = mode; 8116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 8216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 8316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic bool tfp410_encoder_mode_fixup(struct drm_encoder *encoder, 8416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark const struct drm_display_mode *mode, 8516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_display_mode *adjusted_mode) 8616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 8716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark /* nothing needed */ 8816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return true; 8916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 9016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 9116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic void tfp410_encoder_prepare(struct drm_encoder *encoder) 9216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 9316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tfp410_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); 9416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tilcdc_crtc_set_panel_info(encoder->crtc, &dvi_info); 9516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 9616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 9716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic void tfp410_encoder_commit(struct drm_encoder *encoder) 9816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 9916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tfp410_encoder_dpms(encoder, DRM_MODE_DPMS_ON); 10016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 10116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 10216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic void tfp410_encoder_mode_set(struct drm_encoder *encoder, 10316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_display_mode *mode, 10416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_display_mode *adjusted_mode) 10516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 10616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark /* nothing needed */ 10716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 10816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 10916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic const struct drm_encoder_funcs tfp410_encoder_funcs = { 11016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .destroy = tfp410_encoder_destroy, 11116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark}; 11216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 11316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic const struct drm_encoder_helper_funcs tfp410_encoder_helper_funcs = { 11416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .dpms = tfp410_encoder_dpms, 11516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .mode_fixup = tfp410_encoder_mode_fixup, 11616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .prepare = tfp410_encoder_prepare, 11716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .commit = tfp410_encoder_commit, 11816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .mode_set = tfp410_encoder_mode_set, 11916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark}; 12016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 12116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic struct drm_encoder *tfp410_encoder_create(struct drm_device *dev, 12216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tfp410_module *mod) 12316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 12416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tfp410_encoder *tfp410_encoder; 12516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_encoder *encoder; 12616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark int ret; 12716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 12816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tfp410_encoder = kzalloc(sizeof(*tfp410_encoder), GFP_KERNEL); 12916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (!tfp410_encoder) { 13016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_err(dev->dev, "allocation failed\n"); 13116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return NULL; 13216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 13316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 13416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tfp410_encoder->dpms = DRM_MODE_DPMS_OFF; 13516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tfp410_encoder->mod = mod; 13616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 13716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark encoder = &tfp410_encoder->base; 13816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark encoder->possible_crtcs = 1; 13916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 14016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark ret = drm_encoder_init(dev, encoder, &tfp410_encoder_funcs, 14116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark DRM_MODE_ENCODER_TMDS); 14216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (ret < 0) 14316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark goto fail; 14416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 14516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark drm_encoder_helper_add(encoder, &tfp410_encoder_helper_funcs); 14616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 14716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return encoder; 14816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 14916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkfail: 15016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tfp410_encoder_destroy(encoder); 15116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return NULL; 15216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 15316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 15416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark/* 15516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * Connector: 15616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark */ 15716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 15816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstruct tfp410_connector { 15916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_connector base; 16016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 16116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_encoder *encoder; /* our connected encoder */ 16216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tfp410_module *mod; 16316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark}; 16416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark#define to_tfp410_connector(x) container_of(x, struct tfp410_connector, base) 16516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 16616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 16716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic void tfp410_connector_destroy(struct drm_connector *connector) 16816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 16916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tfp410_connector *tfp410_connector = to_tfp410_connector(connector); 17062eb3e20f8f3ca9de4a17f87effe534d6a691176Sachin Kamat drm_connector_unregister(connector); 17116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark drm_connector_cleanup(connector); 17216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark kfree(tfp410_connector); 17316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 17416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 17516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic enum drm_connector_status tfp410_connector_detect( 17616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_connector *connector, 17716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark bool force) 17816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 17916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tfp410_connector *tfp410_connector = to_tfp410_connector(connector); 18016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 18116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (drm_probe_ddc(tfp410_connector->mod->i2c)) 18216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return connector_status_connected; 18316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 18416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return connector_status_unknown; 18516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 18616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 18716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic int tfp410_connector_get_modes(struct drm_connector *connector) 18816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 18916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tfp410_connector *tfp410_connector = to_tfp410_connector(connector); 19016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct edid *edid; 19116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark int ret = 0; 19216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 19316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark edid = drm_get_edid(connector, tfp410_connector->mod->i2c); 19416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 19516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark drm_mode_connector_update_edid_property(connector, edid); 19616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 19716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (edid) { 19816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark ret = drm_add_edid_modes(connector, edid); 19916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark kfree(edid); 20016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 20116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 20216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return ret; 20316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 20416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 20516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic int tfp410_connector_mode_valid(struct drm_connector *connector, 20616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_display_mode *mode) 20716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 20816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_drm_private *priv = connector->dev->dev_private; 20916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark /* our only constraints are what the crtc can generate: */ 21016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return tilcdc_crtc_mode_valid(priv->crtc, mode); 21116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 21216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 21316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic struct drm_encoder *tfp410_connector_best_encoder( 21416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_connector *connector) 21516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 21616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tfp410_connector *tfp410_connector = to_tfp410_connector(connector); 21716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return tfp410_connector->encoder; 21816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 21916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 22016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic const struct drm_connector_funcs tfp410_connector_funcs = { 22116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .destroy = tfp410_connector_destroy, 22216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .dpms = drm_helper_connector_dpms, 22316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .detect = tfp410_connector_detect, 22416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .fill_modes = drm_helper_probe_single_connector_modes, 22516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark}; 22616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 22716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic const struct drm_connector_helper_funcs tfp410_connector_helper_funcs = { 22816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .get_modes = tfp410_connector_get_modes, 22916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .mode_valid = tfp410_connector_mode_valid, 23016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .best_encoder = tfp410_connector_best_encoder, 23116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark}; 23216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 23316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic struct drm_connector *tfp410_connector_create(struct drm_device *dev, 23416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tfp410_module *mod, struct drm_encoder *encoder) 23516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 23616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tfp410_connector *tfp410_connector; 23716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_connector *connector; 23816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark int ret; 23916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 24016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tfp410_connector = kzalloc(sizeof(*tfp410_connector), GFP_KERNEL); 24116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (!tfp410_connector) { 24216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_err(dev->dev, "allocation failed\n"); 24316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return NULL; 24416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 24516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 24616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tfp410_connector->encoder = encoder; 24716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tfp410_connector->mod = mod; 24816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 24916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark connector = &tfp410_connector->base; 25016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 25116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark drm_connector_init(dev, connector, &tfp410_connector_funcs, 25216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark DRM_MODE_CONNECTOR_DVID); 25316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark drm_connector_helper_add(connector, &tfp410_connector_helper_funcs); 25416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 25516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark connector->polled = DRM_CONNECTOR_POLL_CONNECT | 25616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark DRM_CONNECTOR_POLL_DISCONNECT; 25716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 25816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark connector->interlace_allowed = 0; 25916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark connector->doublescan_allowed = 0; 26016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 26116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark ret = drm_mode_connector_attach_encoder(connector, encoder); 26216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (ret) 26316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark goto fail; 26416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 26534ea3d386347cd6de4c2fa2491dd85c9e753e7e4Thomas Wood drm_connector_register(connector); 26616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 26716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return connector; 26816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 26916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkfail: 27016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tfp410_connector_destroy(connector); 27116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return NULL; 27216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 27316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 27416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark/* 27516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * Module: 27616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark */ 27716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 27816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic int tfp410_modeset_init(struct tilcdc_module *mod, struct drm_device *dev) 27916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 28016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tfp410_module *tfp410_mod = to_tfp410_module(mod); 28116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_drm_private *priv = dev->dev_private; 28216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_encoder *encoder; 28316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct drm_connector *connector; 28416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 28516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark encoder = tfp410_encoder_create(dev, tfp410_mod); 28616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (!encoder) 28716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return -ENOMEM; 28816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 28916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark connector = tfp410_connector_create(dev, tfp410_mod, encoder); 29016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (!connector) 29116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return -ENOMEM; 29216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 29316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark priv->encoders[priv->num_encoders++] = encoder; 29416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark priv->connectors[priv->num_connectors++] = connector; 29516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 29616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return 0; 29716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 29816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 29916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic const struct tilcdc_module_ops tfp410_module_ops = { 30016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .modeset_init = tfp410_modeset_init, 30116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark}; 30216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 30316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark/* 30416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark * Device: 30516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark */ 30616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 30716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic struct of_device_id tfp410_of_match[]; 30816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 30916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic int tfp410_probe(struct platform_device *pdev) 31016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 31116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct device_node *node = pdev->dev.of_node; 31216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct device_node *i2c_node; 31316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tfp410_module *tfp410_mod; 31416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct tilcdc_module *mod; 31516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark struct pinctrl *pinctrl; 31616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark uint32_t i2c_phandle; 31716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark int ret = -EINVAL; 31816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 31916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark /* bail out early if no DT data: */ 32016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (!node) { 32116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_err(&pdev->dev, "device-tree data is missing\n"); 32216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return -ENXIO; 32316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 32416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 32516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tfp410_mod = kzalloc(sizeof(*tfp410_mod), GFP_KERNEL); 32616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (!tfp410_mod) 32716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return -ENOMEM; 32816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 32916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark mod = &tfp410_mod->base; 3307cdcce9f8b4c15dc55f880307b844a49127db86eGuido MartÃnez pdev->dev.platform_data = mod; 33116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 33216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tilcdc_module_init(mod, "tfp410", &tfp410_module_ops); 33316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 33416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark pinctrl = devm_pinctrl_get_select_default(&pdev->dev); 33516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (IS_ERR(pinctrl)) 33616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_warn(&pdev->dev, "pins are not configured\n"); 33716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 33816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (of_property_read_u32(node, "i2c", &i2c_phandle)) { 33916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_err(&pdev->dev, "could not get i2c bus phandle\n"); 34016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark goto fail; 34116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 34216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 343dc28aa072f502433b6adc5c9ae8f56955c07580aBenoit Parrot mod->preferred_bpp = dvi_info.bpp; 344dc28aa072f502433b6adc5c9ae8f56955c07580aBenoit Parrot 34516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark i2c_node = of_find_node_by_phandle(i2c_phandle); 34616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (!i2c_node) { 34716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_err(&pdev->dev, "could not get i2c bus node\n"); 34816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark goto fail; 34916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 35016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 35116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tfp410_mod->i2c = of_find_i2c_adapter_by_node(i2c_node); 35216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (!tfp410_mod->i2c) { 35316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_err(&pdev->dev, "could not get i2c\n"); 3547cdcce9f8b4c15dc55f880307b844a49127db86eGuido MartÃnez of_node_put(i2c_node); 35516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark goto fail; 35616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 35716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 35816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark of_node_put(i2c_node); 35916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 36016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark tfp410_mod->gpio = of_get_named_gpio_flags(node, "powerdn-gpio", 36116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 0, NULL); 36216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (IS_ERR_VALUE(tfp410_mod->gpio)) { 36316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_warn(&pdev->dev, "No power down GPIO\n"); 36416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } else { 36516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark ret = gpio_request(tfp410_mod->gpio, "DVI_PDn"); 36616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark if (ret) { 36716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark dev_err(&pdev->dev, "could not get DVI_PDn gpio\n"); 3687cdcce9f8b4c15dc55f880307b844a49127db86eGuido MartÃnez goto fail_adapter; 36916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 37016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark } 37116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 37216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return 0; 37316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 3747cdcce9f8b4c15dc55f880307b844a49127db86eGuido MartÃnezfail_adapter: 3757cdcce9f8b4c15dc55f880307b844a49127db86eGuido MartÃnez i2c_put_adapter(tfp410_mod->i2c); 3767cdcce9f8b4c15dc55f880307b844a49127db86eGuido MartÃnez 37716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkfail: 3787cdcce9f8b4c15dc55f880307b844a49127db86eGuido MartÃnez kfree(tfp410_mod); 3797cdcce9f8b4c15dc55f880307b844a49127db86eGuido MartÃnez tilcdc_module_cleanup(mod); 38016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return ret; 38116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 38216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 38316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic int tfp410_remove(struct platform_device *pdev) 38416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 3857cdcce9f8b4c15dc55f880307b844a49127db86eGuido MartÃnez struct tilcdc_module *mod = dev_get_platdata(&pdev->dev); 3867cdcce9f8b4c15dc55f880307b844a49127db86eGuido MartÃnez struct tfp410_module *tfp410_mod = to_tfp410_module(mod); 3877cdcce9f8b4c15dc55f880307b844a49127db86eGuido MartÃnez 3887cdcce9f8b4c15dc55f880307b844a49127db86eGuido MartÃnez i2c_put_adapter(tfp410_mod->i2c); 3897cdcce9f8b4c15dc55f880307b844a49127db86eGuido MartÃnez gpio_free(tfp410_mod->gpio); 3907cdcce9f8b4c15dc55f880307b844a49127db86eGuido MartÃnez 3917cdcce9f8b4c15dc55f880307b844a49127db86eGuido MartÃnez tilcdc_module_cleanup(mod); 3927cdcce9f8b4c15dc55f880307b844a49127db86eGuido MartÃnez kfree(tfp410_mod); 3937cdcce9f8b4c15dc55f880307b844a49127db86eGuido MartÃnez 39416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return 0; 39516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 39616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 39716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstatic struct of_device_id tfp410_of_match[] = { 39816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark { .compatible = "ti,tilcdc,tfp410", }, 39916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark { }, 40016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark}; 40116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 40216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkstruct platform_driver tfp410_driver = { 40316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .probe = tfp410_probe, 40416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .remove = tfp410_remove, 40516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .driver = { 40616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .owner = THIS_MODULE, 40716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .name = "tfp410", 40816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark .of_match_table = tfp410_of_match, 40916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark }, 41016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark}; 41116ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 41216ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkint __init tilcdc_tfp410_init(void) 41316ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 41416ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark return platform_driver_register(&tfp410_driver); 41516ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 41616ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark 41716ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clarkvoid __exit tilcdc_tfp410_fini(void) 41816ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark{ 41916ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark platform_driver_unregister(&tfp410_driver); 42016ea975eac671fa40a78594a116a44fef8e3f4a9Rob Clark} 421