174f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas /*-*- linux-c -*-
274f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas *  linux/drivers/video/i810-i2c.c -- Intel 810/815 I2C support
374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas *
474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas *      Copyright (C) 2004 Antonino Daplas<adaplas@pol.net>
574f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas *      All Rights Reserved
674f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas *
774f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas *  This file is subject to the terms and conditions of the GNU General Public
874f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas *  License. See the file COPYING in the main directory of this archive for
974f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas *  more details.
1074f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas */
1174f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#include <linux/module.h>
1274f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#include <linux/kernel.h>
1374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#include <linux/delay.h>
145a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
1574f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#include <linux/pci.h>
1674f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#include <linux/fb.h>
1774f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#include "i810.h"
1874f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#include "i810_regs.h"
19a0aa7d0639277f375989071fb52a7ce78beeef97Adrian Bunk#include "i810_main.h"
2074f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#include "../edid.h"
2174f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
2274f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas/* bit locations in the registers */
2374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#define SCL_DIR_MASK		0x0001
2474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#define SCL_DIR			0x0002
2574f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#define SCL_VAL_MASK		0x0004
2674f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#define SCL_VAL_OUT		0x0008
2774f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#define SCL_VAL_IN		0x0010
2874f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#define SDA_DIR_MASK		0x0100
2974f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#define SDA_DIR			0x0200
3074f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#define SDA_VAL_MASK		0x0400
3174f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#define SDA_VAL_OUT		0x0800
3274f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#define SDA_VAL_IN		0x1000
3374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
3474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#define DEBUG  /* define this for verbose EDID parsing output */
3574f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
3674f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#ifdef DEBUG
3774f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#define DPRINTK(fmt, args...) printk(fmt,## args)
3874f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#else
3974f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#define DPRINTK(fmt, args...)
4074f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas#endif
4174f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
4274f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplasstatic void i810i2c_setscl(void *data, int state)
4374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas{
44c019c0ec97548d545c42961e960cbe2e8a6aabe9Antonino A. Daplas        struct i810fb_i2c_chan    *chan = data;
4574f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        struct i810fb_par         *par = chan->par;
46be88ec74cb48d1f60d0c0f059843f846f4481d87Al Viro	u8                        __iomem *mmio = par->mmio_start_virtual;
4774f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
48748103e7235892bf9a3ee568d7d4dd7e5a3beeceStefani Seibold	if (state)
49748103e7235892bf9a3ee568d7d4dd7e5a3beeceStefani Seibold		i810_writel(mmio, chan->ddc_base, SCL_DIR_MASK | SCL_VAL_MASK);
50748103e7235892bf9a3ee568d7d4dd7e5a3beeceStefani Seibold	else
51748103e7235892bf9a3ee568d7d4dd7e5a3beeceStefani Seibold		i810_writel(mmio, chan->ddc_base, SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK);
525fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	i810_readl(mmio, chan->ddc_base);	/* flush posted write */
5374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas}
5474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
5574f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplasstatic void i810i2c_setsda(void *data, int state)
5674f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas{
575fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas        struct i810fb_i2c_chan    *chan = data;
5874f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        struct i810fb_par         *par = chan->par;
59be88ec74cb48d1f60d0c0f059843f846f4481d87Al Viro	u8                        __iomem *mmio = par->mmio_start_virtual;
6074f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
61748103e7235892bf9a3ee568d7d4dd7e5a3beeceStefani Seibold	if (state)
62748103e7235892bf9a3ee568d7d4dd7e5a3beeceStefani Seibold		i810_writel(mmio, chan->ddc_base, SDA_DIR_MASK | SDA_VAL_MASK);
63748103e7235892bf9a3ee568d7d4dd7e5a3beeceStefani Seibold	else
64748103e7235892bf9a3ee568d7d4dd7e5a3beeceStefani Seibold		i810_writel(mmio, chan->ddc_base, SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK);
655fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	i810_readl(mmio, chan->ddc_base);	/* flush posted write */
6674f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas}
6774f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
6874f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplasstatic int i810i2c_getscl(void *data)
6974f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas{
705fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas        struct i810fb_i2c_chan    *chan = data;
7174f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        struct i810fb_par         *par = chan->par;
72be88ec74cb48d1f60d0c0f059843f846f4481d87Al Viro	u8                        __iomem *mmio = par->mmio_start_virtual;
7374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
745fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	i810_writel(mmio, chan->ddc_base, SCL_DIR_MASK);
755fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	i810_writel(mmio, chan->ddc_base, 0);
765fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	return ((i810_readl(mmio, chan->ddc_base) & SCL_VAL_IN) != 0);
7774f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas}
7874f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
7974f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplasstatic int i810i2c_getsda(void *data)
8074f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas{
815fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas        struct i810fb_i2c_chan    *chan = data;
8274f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        struct i810fb_par         *par = chan->par;
83be88ec74cb48d1f60d0c0f059843f846f4481d87Al Viro	u8                        __iomem *mmio = par->mmio_start_virtual;
8474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
855fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	i810_writel(mmio, chan->ddc_base, SDA_DIR_MASK);
865fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	i810_writel(mmio, chan->ddc_base, 0);
875fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	return ((i810_readl(mmio, chan->ddc_base) & SDA_VAL_IN) != 0);
8874f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas}
8974f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
905fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplasstatic int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name)
9174f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas{
9274f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        int rc;
9374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
9474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        strcpy(chan->adapter.name, name);
9574f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        chan->adapter.owner             = THIS_MODULE;
9674f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        chan->adapter.algo_data         = &chan->algo;
9774f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        chan->adapter.dev.parent        = &chan->par->dev->dev;
985fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	chan->algo.setsda               = i810i2c_setsda;
995fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	chan->algo.setscl               = i810i2c_setscl;
1005fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	chan->algo.getsda               = i810i2c_getsda;
1015fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	chan->algo.getscl               = i810i2c_getscl;
10274f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas	chan->algo.udelay               = 10;
10374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        chan->algo.timeout              = (HZ/2);
10474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        chan->algo.data                 = chan;
10574f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
10674f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        i2c_set_adapdata(&chan->adapter, chan);
10774f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
10874f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        /* Raise SCL and SDA */
10974f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        chan->algo.setsda(chan, 1);
11074f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        chan->algo.setscl(chan, 1);
11174f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        udelay(20);
11274f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
11374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        rc = i2c_bit_add_bus(&chan->adapter);
1145fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas
11574f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        if (rc == 0)
11674f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas                dev_dbg(&chan->par->dev->dev, "I2C bus %s registered.\n",name);
1175fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas        else {
11874f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas                dev_warn(&chan->par->dev->dev, "Failed to register I2C bus "
11974f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas			 "%s.\n", name);
1205fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas		chan->par = NULL;
1215fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	}
1225fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas
12374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        return rc;
12474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas}
12574f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
12674f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplasvoid i810_create_i2c_busses(struct i810fb_par *par)
12774f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas{
12874f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        par->chan[0].par        = par;
12974f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas	par->chan[1].par        = par;
1305fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	par->chan[2].par        = par;
1315fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas
1325fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	par->chan[0].ddc_base = GPIOA;
1335fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	i810_setup_i2c_bus(&par->chan[0], "I810-DDC");
1345fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	par->chan[1].ddc_base = GPIOB;
1355fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	i810_setup_i2c_bus(&par->chan[1], "I810-I2C");
1365fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	par->chan[2].ddc_base = GPIOC;
1375fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	i810_setup_i2c_bus(&par->chan[2], "I810-GPIOC");
13874f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas}
13974f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
14074f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplasvoid i810_delete_i2c_busses(struct i810fb_par *par)
14174f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas{
14274f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        if (par->chan[0].par)
1433269711b76ba27b78862c48398b0d313ccaa99c2Jean Delvare		i2c_del_adapter(&par->chan[0].adapter);
14474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        par->chan[0].par = NULL;
1455fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas
14674f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas	if (par->chan[1].par)
1473269711b76ba27b78862c48398b0d313ccaa99c2Jean Delvare		i2c_del_adapter(&par->chan[1].adapter);
14874f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas	par->chan[1].par = NULL;
1495fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas
1505fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	if (par->chan[2].par)
1513269711b76ba27b78862c48398b0d313ccaa99c2Jean Delvare		i2c_del_adapter(&par->chan[2].adapter);
1525fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	par->chan[2].par = NULL;
15374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas}
15474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
15574f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplasint i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, int conn)
15674f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas{
15774f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas	struct i810fb_par *par = info->par;
15874f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        u8 *edid = NULL;
15974f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
16000d340b94f6df17d5dc478521e4ee1cfb30c53acManuel Lauss	DPRINTK("i810-i2c: Probe DDC%i Bus\n", conn+1);
16100d340b94f6df17d5dc478521e4ee1cfb30c53acManuel Lauss	if (conn < par->ddc_num) {
162e80987f8db7b9c33089bb395ed54cb96d55eae04Antonino A. Daplas		edid = fb_ddc_read(&par->chan[conn].adapter);
16374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas	} else {
1645fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas		const u8 *e = fb_firmware_edid(info->device);
1655fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas
1665fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas		if (e != NULL) {
1675fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas			DPRINTK("i810-i2c: Getting EDID from BIOS\n");
168bfba7b3793f59adedfde5fb07dee565c5cc15ab8Alexey Dobriyan			edid = kmemdup(e, EDID_LENGTH, GFP_KERNEL);
1695fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas		}
17074f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas	}
17174f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
1727c518eb84ce75d4c8e8799f4fcad59837f6d1894Antonino A. Daplas	*out_edid = edid;
17374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
17474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        return (edid) ? 0 : 1;
17574f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas}
176