radeon_i2c.c 3.9 KB
Newer Older
J
Jean Delvare 已提交
1 2
#include "radeonfb.h"

L
Linus Torvalds 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/fb.h>


#include <linux/i2c.h>
#include <linux/i2c-id.h>
#include <linux/i2c-algo-bit.h>

#include <asm/io.h>

#include <video/radeon.h>
#include "../edid.h"

static void radeon_gpio_setscl(void* data, int state)
{
	struct radeon_i2c_chan 	*chan = data;
	struct radeonfb_info	*rinfo = chan->rinfo;
	u32			val;
	
	val = INREG(chan->ddc_reg) & ~(VGA_DDC_CLK_OUT_EN);
	if (!state)
		val |= VGA_DDC_CLK_OUT_EN;

	OUTREG(chan->ddc_reg, val);
	(void)INREG(chan->ddc_reg);
}

static void radeon_gpio_setsda(void* data, int state)
{
	struct radeon_i2c_chan 	*chan = data;
	struct radeonfb_info	*rinfo = chan->rinfo;
	u32			val;
	
	val = INREG(chan->ddc_reg) & ~(VGA_DDC_DATA_OUT_EN);
	if (!state)
		val |= VGA_DDC_DATA_OUT_EN;

	OUTREG(chan->ddc_reg, val);
	(void)INREG(chan->ddc_reg);
}

static int radeon_gpio_getscl(void* data)
{
	struct radeon_i2c_chan 	*chan = data;
	struct radeonfb_info	*rinfo = chan->rinfo;
	u32			val;
	
	val = INREG(chan->ddc_reg);

	return (val & VGA_DDC_CLK_INPUT) ? 1 : 0;
}

static int radeon_gpio_getsda(void* data)
{
	struct radeon_i2c_chan 	*chan = data;
	struct radeonfb_info	*rinfo = chan->rinfo;
	u32			val;
	
	val = INREG(chan->ddc_reg);

	return (val & VGA_DDC_DATA_INPUT) ? 1 : 0;
}

static int radeon_setup_i2c_bus(struct radeon_i2c_chan *chan, const char *name)
{
	int rc;

72 73
	snprintf(chan->adapter.name, sizeof(chan->adapter.name),
		 "radeonfb %s", name);
L
Linus Torvalds 已提交
74 75 76 77 78 79 80
	chan->adapter.owner		= THIS_MODULE;
	chan->adapter.algo_data		= &chan->algo;
	chan->adapter.dev.parent	= &chan->rinfo->pdev->dev;
	chan->algo.setsda		= radeon_gpio_setsda;
	chan->algo.setscl		= radeon_gpio_setscl;
	chan->algo.getsda		= radeon_gpio_getsda;
	chan->algo.getscl		= radeon_gpio_getscl;
J
Jean Delvare 已提交
81
	chan->algo.udelay		= 10;
L
Linus Torvalds 已提交
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
	chan->algo.timeout		= 20;
	chan->algo.data 		= chan;	
	
	i2c_set_adapdata(&chan->adapter, chan);
	
	/* Raise SCL and SDA */
	radeon_gpio_setsda(chan, 1);
	radeon_gpio_setscl(chan, 1);
	udelay(20);

	rc = i2c_bit_add_bus(&chan->adapter);
	if (rc == 0)
		dev_dbg(&chan->rinfo->pdev->dev, "I2C bus %s registered.\n", name);
	else
		dev_warn(&chan->rinfo->pdev->dev, "Failed to register I2C bus %s.\n", name);
	return rc;
}

void radeon_create_i2c_busses(struct radeonfb_info *rinfo)
{
	rinfo->i2c[0].rinfo	= rinfo;
	rinfo->i2c[0].ddc_reg	= GPIO_MONID;
	radeon_setup_i2c_bus(&rinfo->i2c[0], "monid");

	rinfo->i2c[1].rinfo	= rinfo;
	rinfo->i2c[1].ddc_reg	= GPIO_DVI_DDC;
	radeon_setup_i2c_bus(&rinfo->i2c[1], "dvi");

	rinfo->i2c[2].rinfo	= rinfo;
	rinfo->i2c[2].ddc_reg	= GPIO_VGA_DDC;
	radeon_setup_i2c_bus(&rinfo->i2c[2], "vga");

	rinfo->i2c[3].rinfo	= rinfo;
	rinfo->i2c[3].ddc_reg	= GPIO_CRT2_DDC;
	radeon_setup_i2c_bus(&rinfo->i2c[3], "crt2");
}

void radeon_delete_i2c_busses(struct radeonfb_info *rinfo)
{
	if (rinfo->i2c[0].rinfo)
122
		i2c_del_adapter(&rinfo->i2c[0].adapter);
L
Linus Torvalds 已提交
123 124 125
	rinfo->i2c[0].rinfo = NULL;

	if (rinfo->i2c[1].rinfo)
126
		i2c_del_adapter(&rinfo->i2c[1].adapter);
L
Linus Torvalds 已提交
127 128 129
	rinfo->i2c[1].rinfo = NULL;

	if (rinfo->i2c[2].rinfo)
130
		i2c_del_adapter(&rinfo->i2c[2].adapter);
L
Linus Torvalds 已提交
131 132 133
	rinfo->i2c[2].rinfo = NULL;

	if (rinfo->i2c[3].rinfo)
134
		i2c_del_adapter(&rinfo->i2c[3].adapter);
L
Linus Torvalds 已提交
135 136 137
	rinfo->i2c[3].rinfo = NULL;
}

138 139
int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn,
			       u8 **out_edid)
L
Linus Torvalds 已提交
140
{
141 142 143
	u8 *edid;

	edid = fb_ddc_read(&rinfo->i2c[conn-1].adapter);
L
Linus Torvalds 已提交
144 145 146 147

	if (out_edid)
		*out_edid = edid;
	if (!edid) {
148
		pr_debug("radeonfb: I2C (port %d) ... not found\n", conn);
L
Linus Torvalds 已提交
149 150 151 152 153 154
		return MT_NONE;
	}
	if (edid[0x14] & 0x80) {
		/* Fix detection using BIOS tables */
		if (rinfo->is_mobility /*&& conn == ddc_dvi*/ &&
		    (INREG(LVDS_GEN_CNTL) & LVDS_ON)) {
155
			pr_debug("radeonfb: I2C (port %d) ... found LVDS panel\n", conn);
L
Linus Torvalds 已提交
156 157
			return MT_LCD;
		} else {
158
			pr_debug("radeonfb: I2C (port %d) ... found TMDS panel\n", conn);
L
Linus Torvalds 已提交
159 160 161
			return MT_DFP;
		}
	}
162
	pr_debug("radeonfb: I2C (port %d) ... found CRT display\n", conn);
L
Linus Torvalds 已提交
163 164 165
	return MT_CRT;
}