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