i810-i2c.c revision 5a0e3ad6af8660be21ca98a971cd00f331318c05
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
485fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	i810_writel(mmio, chan->ddc_base, (state ? SCL_VAL_OUT : 0) | SCL_DIR |
4974f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas		    SCL_DIR_MASK | SCL_VAL_MASK);
505fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	i810_readl(mmio, chan->ddc_base);	/* flush posted write */
5174f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas}
5274f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
5374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplasstatic void i810i2c_setsda(void *data, int state)
5474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas{
555fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas        struct i810fb_i2c_chan    *chan = data;
5674f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        struct i810fb_par         *par = chan->par;
57be88ec74cb48d1f60d0c0f059843f846f4481d87Al Viro	u8                        __iomem *mmio = par->mmio_start_virtual;
5874f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
595fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas 	i810_writel(mmio, chan->ddc_base, (state ? SDA_VAL_OUT : 0) | SDA_DIR |
6074f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas		    SDA_DIR_MASK | SDA_VAL_MASK);
615fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	i810_readl(mmio, chan->ddc_base);	/* flush posted write */
6274f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas}
6374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
6474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplasstatic int i810i2c_getscl(void *data)
6574f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas{
665fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas        struct i810fb_i2c_chan    *chan = data;
6774f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        struct i810fb_par         *par = chan->par;
68be88ec74cb48d1f60d0c0f059843f846f4481d87Al Viro	u8                        __iomem *mmio = par->mmio_start_virtual;
6974f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
705fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	i810_writel(mmio, chan->ddc_base, SCL_DIR_MASK);
715fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	i810_writel(mmio, chan->ddc_base, 0);
725fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	return ((i810_readl(mmio, chan->ddc_base) & SCL_VAL_IN) != 0);
7374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas}
7474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
7574f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplasstatic int i810i2c_getsda(void *data)
7674f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas{
775fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas        struct i810fb_i2c_chan    *chan = data;
7874f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        struct i810fb_par         *par = chan->par;
79be88ec74cb48d1f60d0c0f059843f846f4481d87Al Viro	u8                        __iomem *mmio = par->mmio_start_virtual;
8074f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
815fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	i810_writel(mmio, chan->ddc_base, SDA_DIR_MASK);
825fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	i810_writel(mmio, chan->ddc_base, 0);
835fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	return ((i810_readl(mmio, chan->ddc_base) & SDA_VAL_IN) != 0);
8474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas}
8574f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
865fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplasstatic int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name)
8774f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas{
8874f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        int rc;
8974f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
9074f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        strcpy(chan->adapter.name, name);
9174f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        chan->adapter.owner             = THIS_MODULE;
9274f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        chan->adapter.algo_data         = &chan->algo;
9374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        chan->adapter.dev.parent        = &chan->par->dev->dev;
945fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	chan->algo.setsda               = i810i2c_setsda;
955fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	chan->algo.setscl               = i810i2c_setscl;
965fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	chan->algo.getsda               = i810i2c_getsda;
975fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	chan->algo.getscl               = i810i2c_getscl;
9874f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas	chan->algo.udelay               = 10;
9974f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        chan->algo.timeout              = (HZ/2);
10074f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        chan->algo.data                 = chan;
10174f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
10274f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        i2c_set_adapdata(&chan->adapter, chan);
10374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
10474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        /* Raise SCL and SDA */
10574f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        chan->algo.setsda(chan, 1);
10674f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        chan->algo.setscl(chan, 1);
10774f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        udelay(20);
10874f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
10974f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        rc = i2c_bit_add_bus(&chan->adapter);
1105fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas
11174f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        if (rc == 0)
11274f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas                dev_dbg(&chan->par->dev->dev, "I2C bus %s registered.\n",name);
1135fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas        else {
11474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas                dev_warn(&chan->par->dev->dev, "Failed to register I2C bus "
11574f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas			 "%s.\n", name);
1165fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas		chan->par = NULL;
1175fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	}
1185fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas
11974f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        return rc;
12074f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas}
12174f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
12274f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplasvoid i810_create_i2c_busses(struct i810fb_par *par)
12374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas{
12474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        par->chan[0].par        = par;
12574f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas	par->chan[1].par        = par;
1265fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	par->chan[2].par        = par;
1275fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas
1285fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	par->chan[0].ddc_base = GPIOA;
1295fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	i810_setup_i2c_bus(&par->chan[0], "I810-DDC");
1305fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	par->chan[1].ddc_base = GPIOB;
1315fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	i810_setup_i2c_bus(&par->chan[1], "I810-I2C");
1325fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	par->chan[2].ddc_base = GPIOC;
1335fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	i810_setup_i2c_bus(&par->chan[2], "I810-GPIOC");
13474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas}
13574f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
13674f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplasvoid i810_delete_i2c_busses(struct i810fb_par *par)
13774f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas{
13874f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        if (par->chan[0].par)
1393269711b76ba27b78862c48398b0d313ccaa99c2Jean Delvare		i2c_del_adapter(&par->chan[0].adapter);
14074f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        par->chan[0].par = NULL;
1415fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas
14274f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas	if (par->chan[1].par)
1433269711b76ba27b78862c48398b0d313ccaa99c2Jean Delvare		i2c_del_adapter(&par->chan[1].adapter);
14474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas	par->chan[1].par = NULL;
1455fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas
1465fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	if (par->chan[2].par)
1473269711b76ba27b78862c48398b0d313ccaa99c2Jean Delvare		i2c_del_adapter(&par->chan[2].adapter);
1485fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas	par->chan[2].par = NULL;
14974f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas}
15074f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
15174f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplasint i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, int conn)
15274f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas{
15374f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas	struct i810fb_par *par = info->par;
15474f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        u8 *edid = NULL;
15574f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
15600d340b94f6df17d5dc478521e4ee1cfb30c53acManuel Lauss	DPRINTK("i810-i2c: Probe DDC%i Bus\n", conn+1);
15700d340b94f6df17d5dc478521e4ee1cfb30c53acManuel Lauss	if (conn < par->ddc_num) {
158e80987f8db7b9c33089bb395ed54cb96d55eae04Antonino A. Daplas		edid = fb_ddc_read(&par->chan[conn].adapter);
15974f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas	} else {
1605fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas		const u8 *e = fb_firmware_edid(info->device);
1615fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas
1625fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas		if (e != NULL) {
1635fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas			DPRINTK("i810-i2c: Getting EDID from BIOS\n");
164bfba7b3793f59adedfde5fb07dee565c5cc15ab8Alexey Dobriyan			edid = kmemdup(e, EDID_LENGTH, GFP_KERNEL);
1655fab851ea15206cc375582ad0db79f7827325098Antonino A. Daplas		}
16674f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas	}
16774f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
1687c518eb84ce75d4c8e8799f4fcad59837f6d1894Antonino A. Daplas	*out_edid = edid;
16974f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas
17074f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas        return (edid) ? 0 : 1;
17174f6ae84b2315c2fa8a4110b09a1c0f3dca92674Antonino A. Daplas}
172