[go: nahoru, domu]

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