From cea30742926710164f1b6617b928b54dc21dc714 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 28 Dec 2006 16:10:51 +0000 Subject: [PATCH] Port the i2c-gpio driver to the 2.6 kernel SVN-Revision: 5916 --- target/linux/au1000-2.6/config | 55 ++- .../patches/009-pci_clear_errors.patch | 16 + .../patches/010-au100_gpio_i2c.patch | 456 ++++++++++++++++++ 3 files changed, 524 insertions(+), 3 deletions(-) create mode 100644 target/linux/au1000-2.6/patches/009-pci_clear_errors.patch create mode 100644 target/linux/au1000-2.6/patches/010-au100_gpio_i2c.patch diff --git a/target/linux/au1000-2.6/config b/target/linux/au1000-2.6/config index f90010309b..db9841e41a 100644 --- a/target/linux/au1000-2.6/config +++ b/target/linux/au1000-2.6/config @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.19 -# Thu Dec 14 00:45:45 2006 +# Linux kernel version: 2.6.19.1 +# Thu Dec 28 03:16:16 2006 # CONFIG_MIPS=y @@ -1142,7 +1142,56 @@ CONFIG_HW_RANDOM=y # # I2C support # -# CONFIG_I2C is not set +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=m + +# +# I2C Algorithms +# +CONFIG_I2C_ALGOBIT=m +CONFIG_I2C_ALGOPCF=m +CONFIG_I2C_ALGOPCA=m + +# +# I2C Hardware Bus support +# +# CONFIG_I2C_ALI1535 is not set +# CONFIG_I2C_ALI1563 is not set +# CONFIG_I2C_ALI15X3 is not set +# CONFIG_I2C_AMD756 is not set +# CONFIG_I2C_AMD8111 is not set +CONFIG_I2C_AU1X00GPIO=y +# CONFIG_I2C_I801 is not set +# CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set +# CONFIG_I2C_NFORCE2 is not set +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_PROSAVAGE is not set +# CONFIG_I2C_SAVAGE4 is not set +# CONFIG_I2C_SIS5595 is not set +# CONFIG_I2C_SIS630 is not set +# CONFIG_I2C_SIS96X is not set +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_VIA is not set +# CONFIG_I2C_VIAPRO is not set +# CONFIG_I2C_VOODOO3 is not set +# CONFIG_I2C_PCA_ISA is not set + +# +# Miscellaneous I2C Chip support +# +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +# CONFIG_SENSORS_EEPROM is not set +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_MAX6875 is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +# CONFIG_I2C_DEBUG_CHIP is not set # # SPI support diff --git a/target/linux/au1000-2.6/patches/009-pci_clear_errors.patch b/target/linux/au1000-2.6/patches/009-pci_clear_errors.patch new file mode 100644 index 0000000000..27282b27c1 --- /dev/null +++ b/target/linux/au1000-2.6/patches/009-pci_clear_errors.patch @@ -0,0 +1,16 @@ +diff -urN linux-2.6.19/arch/mips/pci/ops-au1000.c linux-2.6.19.new/arch/mips/pci/ops-au1000.c +--- linux-2.6.19/arch/mips/pci/ops-au1000.c 2006-11-29 22:57:37.000000000 +0100 ++++ linux-2.6.19.new/arch/mips/pci/ops-au1000.c 2006-12-28 03:02:42.000000000 +0100 +@@ -172,7 +172,11 @@ + error = -1; + DBG("Au1x Master Abort\n"); + } else if ((status >> 28) & 0xf) { +- DBG("PCI ERR detected: status %x\n", status); ++ DBG("PCI ERR detected: device %d, status %x\n", device, ((status >> 28) & 0xf)); ++ ++ /* clear errors */ ++ au_writel(status & 0xf000ffff, Au1500_PCI_STATCMD); ++ + *data = 0xffffffff; + error = -1; + } diff --git a/target/linux/au1000-2.6/patches/010-au100_gpio_i2c.patch b/target/linux/au1000-2.6/patches/010-au100_gpio_i2c.patch new file mode 100644 index 0000000000..aeb021a049 --- /dev/null +++ b/target/linux/au1000-2.6/patches/010-au100_gpio_i2c.patch @@ -0,0 +1,456 @@ +diff -urN linux-2.6.19/drivers/i2c/busses/Kconfig linux-2.6.19.new/drivers/i2c/busses/Kconfig +--- linux-2.6.19/drivers/i2c/busses/Kconfig 2006-11-29 22:57:37.000000000 +0100 ++++ linux-2.6.19.new/drivers/i2c/busses/Kconfig 2006-12-28 17:04:34.000000000 +0100 +@@ -84,6 +84,16 @@ + This driver can also be built as a module. If so, the module + will be called i2c-au1550. + ++config I2C_AU1X00GPIO ++ tristate "Au1x00 i2c using GPIO pins" ++ depends on I2C && MTX1 ++ help ++ If you say yest to this option, support will be included for the ++ Au1x00 GPIO interface. ++ ++ This driver can also be built as a module. If so, the module ++ will be called i2c-au1x00gpio. ++ + config I2C_ELEKTOR + tristate "Elektor ISA card" + depends on I2C && ISA && BROKEN_ON_SMP +diff -urN linux-2.6.19/drivers/i2c/busses/Makefile linux-2.6.19.new/drivers/i2c/busses/Makefile +--- linux-2.6.19/drivers/i2c/busses/Makefile 2006-11-29 22:57:37.000000000 +0100 ++++ linux-2.6.19.new/drivers/i2c/busses/Makefile 2006-12-28 03:07:37.000000000 +0100 +@@ -9,6 +9,7 @@ + obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o + obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o + obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o ++obj-$(CONFIG_I2C_AU1X00GPIO) += i2c-au1x00gpio.o + obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o + obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o + obj-$(CONFIG_I2C_I801) += i2c-i801.o +diff -urN linux-2.6.19/drivers/i2c/busses/i2c-au1x00gpio.c linux-2.6.19.new/drivers/i2c/busses/i2c-au1x00gpio.c +--- linux-2.6.19/drivers/i2c/busses/i2c-au1x00gpio.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.19.new/drivers/i2c/busses/i2c-au1x00gpio.c 2006-12-28 17:02:10.000000000 +0100 +@@ -0,0 +1,421 @@ ++/* ------------------------------------------------------------------------- */ ++/* i2c-au1x00gpio.c i2c-hw access for Au1x00 GPIO pins. */ ++/* ------------------------------------------------------------------------- */ ++/* Copyright (C) 1995-2000 Michael Stickel ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ ++/* ------------------------------------------------------------------------- */ ++ ++/* With some changes from Ky�stialkki and even ++ Frodo Looijaard ++ Simon G. Vogl ++*/ ++ ++/* $Id: i2c-au1x00gpio.c,v 1.1.1.2 2004/01/22 15:35:47 br1 Exp $ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++#ifndef __exit ++#define __exit __init ++#endif ++ ++ ++struct i2c_au1x00gpio ++{ ++ struct i2c_au1x00gpio *next; ++ ++ short scl_gpio; ++ short sda_gpio; ++ ++ unsigned long scl_mask; ++ unsigned long sda_mask; ++ ++ struct i2c_adapter adapter; ++ struct i2c_algo_bit_data bit_au1x00gpio_data; ++}; ++ ++static struct i2c_au1x00gpio *adapter_list; ++ ++ ++ ++/* ----- global defines ----------------------------------------------- */ ++#define DEB(x) /* should be reasonable open, close &c. */ ++#define DEB2(x) /* low level debugging - very slow */ ++#define DEBE(x) x /* error messages */ ++ ++/* ----- printer port defines ------------------------------------------*/ ++ ++/* ----- local functions ---------------------------------------------- */ ++ ++ ++//-- Primary GPIO ++static void bit_au1x00gpio_setscl(void *data, int state) ++{ ++ struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data; ++ if (state) ++ au_writel(adapter->scl_mask, SYS_TRIOUTCLR); // Disable Driver: Switch off Transistor => 1 ++ else ++ au_writel(adapter->scl_mask, SYS_OUTPUTCLR); // Clear Output and switch on Transistor => 0 ++} ++ ++ ++static void bit_au1x00gpio_setsda(void *data, int state) ++{ ++ struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data; ++ if (state) ++ au_writel(adapter->sda_mask, SYS_TRIOUTCLR); ++ else ++ au_writel(adapter->sda_mask, SYS_OUTPUTCLR); ++} ++ ++ ++static int bit_au1x00gpio_getscl(void *data) ++{ ++ struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data; ++ return (au_readl(SYS_PINSTATERD) & adapter->scl_mask) ? 1 : 0; ++} ++ ++ ++static int bit_au1x00gpio_getsda(void *data) ++{ ++ struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data; ++ return (au_readl(SYS_PINSTATERD) & adapter->sda_mask) ? 1 : 0; ++} ++ ++ ++ ++ ++/*-- ++ *-- Functions for accessing GPIO-2 ++ *-- ++ */ ++static void bit_au1x00gpio2_setscl(void *data, int state) ++{ ++ struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data; ++ if (state) ++ { ++ au_writel(au_readl(GPIO2_DIR) & ~adapter->scl_mask, GPIO2_DIR); ++ } ++ else ++ { ++ au_writel(au_readl(GPIO2_OUTPUT) & ~adapter->scl_mask, GPIO2_OUTPUT); ++ au_writel(au_readl(GPIO2_DIR) | adapter->scl_mask, GPIO2_DIR); ++ } ++} ++ ++static void bit_au1x00gpio2_setsda(void *data, int state) ++{ ++ struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data; ++ if (state) ++ { ++ au_writel(au_readl(GPIO2_DIR) & ~adapter->sda_mask, GPIO2_DIR); ++ } ++ else ++ { ++ au_writel(au_readl(GPIO2_OUTPUT) & ~adapter->sda_mask, GPIO2_OUTPUT); ++ au_writel(au_readl(GPIO2_DIR) | adapter->sda_mask, GPIO2_DIR); ++ } ++} ++ ++static int bit_au1x00gpio2_getscl(void *data) ++{ ++ struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data; ++ return (au_readl(GPIO2_PINSTATE) & adapter->scl_mask) ? 1 : 0; ++} ++ ++static int bit_au1x00gpio2_getsda(void *data) ++{ ++ struct i2c_au1x00gpio * adapter = (struct i2c_au1x00gpio *)data; ++ return (au_readl(GPIO2_PINSTATE) & adapter->sda_mask) ? 1 : 0; ++} ++ ++ ++ ++static int check_i2c_au1x00gpio_adapter(struct i2c_au1x00gpio *adapter) ++{ ++ int state = 0; ++ ++ adapter->bit_au1x00gpio_data.setsda (adapter, 1); ++ adapter->bit_au1x00gpio_data.setscl (adapter, 1); ++ ++ if (adapter->bit_au1x00gpio_data.getsda(adapter)==0) ++ { ++ printk ("i2c-au1x00gpio: sda line should read 1 but reads 0\n"); ++ state = -1; ++ } ++ if (adapter->bit_au1x00gpio_data.getscl(adapter)==0) ++ { ++ printk ("i2c-au1x00gpio: scl line should read 1 but reads 0\n"); ++ state = -1; ++ } ++ ++ ++ adapter->bit_au1x00gpio_data.setsda (adapter, 0); ++ adapter->bit_au1x00gpio_data.setscl (adapter, 0); ++ ++ if (adapter->bit_au1x00gpio_data.getsda(adapter)==1) ++ { ++ printk ("i2c-au1x00gpio: sda line should read 0 but reads 1\n"); ++ state = -1; ++ } ++ if (adapter->bit_au1x00gpio_data.getscl(adapter)==1) ++ { ++ printk ("i2c-au1x00gpio: scl line should read 0 but reads 1\n"); ++ state = -1; ++ } ++ ++ if (state==0) ++ printk ("i2c-au1x00gpio: adapter with scl=GPIO%d,sda=GPIO%d is working\n", ++ adapter->scl_gpio, adapter->sda_gpio ++ ); ++ return state; ++} ++ ++ ++ ++#if 0 ++static int bit_au1x00gpio_reg(struct i2c_client *client) ++{ ++ return 0; ++} ++ ++static int bit_au1x00gpio_unreg(struct i2c_client *client) ++{ ++ return 0; ++} ++ ++static void bit_au1x00gpio_inc_use(struct i2c_adapter *adap) ++{ ++ MOD_INC_USE_COUNT; ++} ++ ++static void bit_au1x00gpio_dec_use(struct i2c_adapter *adap) ++{ ++ MOD_DEC_USE_COUNT; ++} ++#endif ++ ++ ++ ++static struct i2c_algo_bit_data bit_au1x00gpio_data = { ++ .data = NULL, ++ .setsda = bit_au1x00gpio_setsda, ++ .setscl = bit_au1x00gpio_setscl, ++ .getsda = bit_au1x00gpio_getsda, ++ .getscl = bit_au1x00gpio_getscl, ++ .udelay = 80, ++ .timeout = HZ, ++}; ++ ++ ++static struct i2c_adapter bit_au1x00gpio_ops = { ++ .owner = THIS_MODULE, ++ .name = "Au1x00 GPIO I2C adapter", ++ .id = I2C_HW_B_AU1x00GPIO, ++}; ++ ++ ++ ++/* ++ * scl_gpio: ++ * 0..31 for primary GPIO's ++ * 200..215 for secondary GPIO's ++ * ++ * sda_gpio: ++ * 0..31 for primary GPIO's ++ * 200..215 for secondary GPIO's ++ * ++ * You can even mix primary and secondary GPIO's. ++ * E.g.: i2c_au1x00gpio_create(4,206); ++ */ ++ ++static int i2c_au1x00gpio_create (int scl_gpio, int sda_gpio) ++{ ++ if ((scl_gpio < 32 || (scl_gpio >= 200 && scl_gpio <= 215)) && ++ (scl_gpio < 32 || (scl_gpio >= 200 && scl_gpio <= 215))) ++ { ++ struct i2c_au1x00gpio *adapter = kmalloc(sizeof(struct i2c_au1x00gpio), ++ GFP_KERNEL); ++ if (!adapter) { ++ printk(KERN_ERR "i2c-au1x00-gpio: Unable to malloc.\n"); ++ return -1; ++ } ++ ++ printk(KERN_DEBUG "i2c-au1x00-gpio.o: attaching to SCL=GPIO%d, SDA=GPIO%d\n", ++ scl_gpio, sda_gpio); ++ ++ memset (adapter, 0, sizeof(struct i2c_au1x00gpio)); ++ ++ adapter->adapter = bit_au1x00gpio_ops; ++ ++ adapter->adapter.algo_data = &adapter->bit_au1x00gpio_data; ++ adapter->bit_au1x00gpio_data = bit_au1x00gpio_data; ++ adapter->bit_au1x00gpio_data.data = adapter; ++ ++ adapter->bit_au1x00gpio_data.data = adapter; ++ ++ adapter->scl_gpio = scl_gpio; ++ adapter->sda_gpio = sda_gpio; ++ ++ if (sda_gpio < 32) ++ { ++ adapter->bit_au1x00gpio_data.setsda = bit_au1x00gpio_setsda; ++ adapter->bit_au1x00gpio_data.getsda = bit_au1x00gpio_getsda; ++ adapter->sda_mask = 1<= 200 && sda_gpio <= 215) ++ { ++ adapter->bit_au1x00gpio_data.setsda = bit_au1x00gpio2_setsda; ++ adapter->bit_au1x00gpio_data.getsda = bit_au1x00gpio2_getsda; ++ adapter->sda_mask = 1<<(sda_gpio-200); ++ } ++ ++ ++ if (scl_gpio < 32) ++ { ++ adapter->bit_au1x00gpio_data.setscl = bit_au1x00gpio_setscl; ++ adapter->bit_au1x00gpio_data.getscl = bit_au1x00gpio_getscl; ++ adapter->scl_mask = 1<= 200 && scl_gpio <= 215) ++ { ++ adapter->bit_au1x00gpio_data.setscl = bit_au1x00gpio2_setscl; ++ adapter->bit_au1x00gpio_data.getscl = bit_au1x00gpio2_getscl; ++ adapter->scl_mask = 1<<(scl_gpio-200); ++ } ++ ++ au_writel(0L, SYS_PININPUTEN); ++ if (check_i2c_au1x00gpio_adapter(adapter)==0) ++ { ++ adapter->bit_au1x00gpio_data.setsda (adapter, 1); ++ adapter->bit_au1x00gpio_data.setscl (adapter, 1); ++ ++ if (i2c_bit_add_bus(&adapter->adapter) < 0) ++ { ++ printk(KERN_ERR "i2c-au1x00-gpio: Unable to register with I2C.\n"); ++ kfree(adapter); ++ return -1; /* No good */ ++ } ++ ++ adapter->next = adapter_list; ++ adapter_list = adapter; ++ return 0; ++ } ++ } ++ else ++ printk(KERN_ERR "i2c-au1x00-gpio: Invalid argument scl_gpio=%d, sda_gpio=%d.\n", scl_gpio, sda_gpio); ++ return -1; ++} ++ ++ ++ ++static void i2c_au1x00gpio_delete (int scl_gpio, int sda_gpio) ++{ ++ struct i2c_au1x00gpio *adapter, *prev = NULL; ++ ++ for (adapter = adapter_list; adapter; adapter = adapter->next) ++ { ++ if (adapter->scl_gpio == scl_gpio && ++ adapter->sda_gpio == sda_gpio) ++ { ++ i2c_bit_del_bus(&adapter->adapter); ++ if (prev) ++ prev->next = adapter->next; ++ else ++ adapter_list = adapter->next; ++ kfree(adapter); ++ return; ++ } ++ prev = adapter; ++ } ++} ++ ++ ++ ++ ++ ++#ifndef CONFIG_I2C_AU1X00GPIO_SCL ++#define CONFIG_I2C_AU1X00GPIO_SCL (216) ++#endif ++ ++#ifndef CONFIG_I2C_AU1X00GPIO_SDA ++#define CONFIG_I2C_AU1X00GPIO_SDA (217) ++#endif ++ ++static int au1x00gpiopin_scl = CONFIG_I2C_AU1X00GPIO_SCL; ++static int au1x00gpiopin_sda = CONFIG_I2C_AU1X00GPIO_SDA; ++ ++ ++ ++int __init i2c_bit_au1x00gpio_init(void) ++{ ++ printk(KERN_INFO "i2c-au1x00gpio.o: i2c Au1x00 GPIO adapter module version\n"); ++ ++ if (i2c_au1x00gpio_create (au1x00gpiopin_scl, au1x00gpiopin_sda) == 0) ++ { ++ printk(KERN_INFO "i2c-au1x00gpio.o: registered I2C-Bus for GPIO%d,GPIO%d\n", ++ au1x00gpiopin_scl, au1x00gpiopin_sda ++ ); ++ return 0; ++ } ++ printk(KERN_INFO "i2c-au1x00gpio.o: failed to register I2C-Bus for GPIO%d,GPIO%d\n", ++ au1x00gpiopin_scl, au1x00gpiopin_sda ++ ); ++ return -1; ++} ++ ++ ++void __exit i2c_bit_au1x00gpio_exit(void) ++{ ++ i2c_au1x00gpio_delete (au1x00gpiopin_scl, au1x00gpiopin_sda); ++} ++ ++module_param(au1x00gpiopin_scl, int, 0644); ++MODULE_PARM_DESC(au1x00gpiopin_scl, "GPIO pin number used for SCL pin."); ++ ++module_param(au1x00gpiopin_sda, int, 0644); ++MODULE_PARM_DESC(au1x00gpiopin_sda, "GPIO pin number used for SDA pin."); ++ ++MODULE_AUTHOR("Michael Stickel "); ++MODULE_DESCRIPTION("I2C-Bus adapter routines for Au1x00 GPIO adapter."); ++MODULE_LICENSE("GPL"); ++ ++ ++#ifdef MODULE ++int init_module(void) ++{ ++ return i2c_bit_au1x00gpio_init(); ++} ++ ++void cleanup_module(void) ++{ ++ i2c_bit_au1x00gpio_exit(); ++} ++#endif -- 2.25.1