--- linux-2.4.32/drivers/i2c/i2c-adm5120_org.c 2006-12-12 14:40:33.000000000 +0100 +++ linux-2.4.32/drivers/i2c/i2c-adm5120.c 2007-01-03 22:24:00.000000000 +0100 @@ -18,7 +18,13 @@ 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. + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Dez/2006 : dl4huf + Modified for correct open collector emulation on gpio + Add support for all gpio0 to gpio7 + Add support for switch-led as gpio8 to gpio22 + */ #include @@ -39,67 +45,83 @@ static int sda = CONFIG_I2C_ADM5120_SDA; #define GPIO_PORT0 (*(unsigned long *)0xb20000b8) +#define REG_BASE (0xb2000000) -#if 1 -static void adm5120_gpio_set(int id, int state) -{ - unsigned long led_bit,led_bit_val; - if(id <= 3 && id >= 0) { - led_bit = 1 << (id); - led_bit_val = led_bit << 24; - - GPIO_PORT0 |= (led_bit << 16); // Output - if (state) - GPIO_PORT0 |= led_bit_val; - else - GPIO_PORT0 &= ~led_bit_val; - } - -} +typedef struct { + u32 reg_offset; + int bit_no; +} led_config_struct; + /* config for GPIO 8..22 */ +static led_config_struct led_config[] = /* same counting as led-driver */ +{ /* Registeraddress, led-number */ + {Port0_LED_REG + REG_BASE, 0}, + {Port0_LED_REG + REG_BASE, 1}, + {Port0_LED_REG + REG_BASE, 2}, + {Port1_LED_REG + REG_BASE, 0}, + {Port1_LED_REG + REG_BASE, 1}, + {Port1_LED_REG + REG_BASE, 2}, + {Port2_LED_REG + REG_BASE, 0}, + {Port2_LED_REG + REG_BASE, 1}, + {Port2_LED_REG + REG_BASE, 2}, + {Port3_LED_REG + REG_BASE, 0}, + {Port3_LED_REG + REG_BASE, 1}, + {Port3_LED_REG + REG_BASE, 2}, + {Port4_LED_REG + REG_BASE, 0}, + {Port4_LED_REG + REG_BASE, 1}, + {Port4_LED_REG + REG_BASE, 2}, +}; -static int adm5120_gpio_get(int id) +static void adm5120_gpio_set(int id, int state) { - unsigned long led_bit, val; - if(id <= 3 && id >= 0) { - led_bit = 1 << (id); - - GPIO_PORT0 &= ~(led_bit << 16); // Input - - val = (GPIO_PORT0 >> 8) & led_bit; - - GPIO_PORT0 |= (led_bit << 16); // ??? Can not stay in input mode - return val; + unsigned long led_bit; + if(id <= 7 && id >= 0) { + if (state) { + GPIO_PORT0 |= (1 << (id+24)); /* output high, obsolet ? */ + GPIO_PORT0 &= ~(1 << (id+16)); /* input, see below */ + } + else { + GPIO_PORT0 &= ~(1 << (id+24)); /* output low */ + GPIO_PORT0 |= (1 << (id+16)); /* output enable */ + } } - - return 0; + else { + id = id - 8; + u32* p_reg = (u32*)(led_config[id].reg_offset); + led_bit = *p_reg; /* read the current settings */ + led_bit &= ~(0xf << (led_config[id].bit_no * 4)); + /* clear the led bits */ + if (state) { + *p_reg = led_bit; /* i2c expect open collector with pullup + resitor for high level, so set to input-mode */ + } + else { + *p_reg = led_bit | (3 << (led_config[id].bit_no * 4)); + /* set output to low level */ + } + } } -#else -static void adm5120_gpio_set(int id, int state) -{ - unsigned long reg=0; - int shl = id*4; - - reg = ADM5120_SW_REG(Port2_LED_REG)&(~(0xf<>(12+id))&0x1; - - return val; -// return (ADM5120_SW_REG(Port2_LED_REG)>>(12+id))&0x1; + if(id <= 7 && id >= 0) { + GPIO_PORT0 &= ~(1 << (id+16)); /* set to input, obsolete ? */ + val = GPIO_PORT0 & (1 << (id+8)); /* read the input */ + } + else { + id = id - 8; + u32* p_reg = (u32*)(led_config[id].reg_offset); + *p_reg &= ~(0xf << (led_config[id].bit_no * 4)); + /* set to input mode (mode 0x00h) */ + val = *p_reg & (1 << (led_config[id].bit_no + 12)); + /* read the input */ + } + val = (val == 0)? 0:1; + return val; } -#endif static void bit_adm5120_setscl(void *data, int state) { @@ -152,12 +174,12 @@ bit_adm5120_setscl, bit_adm5120_getsda, bit_adm5120_getscl, - 10, 10, 100, /* waits, timeout */ + 5, 5, 100, /* waits, timeout, around 62,5KHz SCL-Clock */ }; static struct i2c_adapter bit_adm5120_ops = { - .name = "ADM5120 I2C", - .id = I2C_HW_B_VELLE, + .name = "ADM5120 I2C", + .id = I2C_HW_B_VELLE, .algo_data = &bit_adm5120_data, .inc_use = bit_adm5120_inc_use, .dec_use = bit_adm5120_dec_use, @@ -167,26 +189,23 @@ int i2c_bitadm5120_init(void) { - printk(KERN_INFO "i2c-adm5120.o: ADM5120 I2C Driver\n"); + printk(KERN_INFO "i2c-adm5120.o: %s Driver V1.1\n",bit_adm5120_ops.name); + printk(KERN_INFO "i2c-adm5120.o: SCL=GPIO-%02u, SDA=GPIO-%02u\n",scl,sda); - printk(KERN_INFO "i2c-adm5120.o: SCL=GPIO-%02u, SDA=GPIO-%02u\n", - scl, sda); - - if (scl < 0 || sda < 0 || scl == sda) { - printk(KERN_ERR "i2c-adm5120.o: scl and sda must be specified\n"); + if (scl < 0 || sda < 0 || scl == sda || scl > 22 || sda > 22) { + printk(KERN_ERR "i2c-adm5120.o: scl and sda must be specified between 0..22\n"); return -EINVAL; } - /* Configure GPIOs as open collector outputs */ - adm5120_gpio_set(scl, 0); - adm5120_gpio_set(sda, 0); - if (i2c_bit_add_bus(&bit_adm5120_ops) < 0) { - printk(KERN_ERR "i2c-adm5120.o: adapter %s registration failed\n", - bit_adm5120_ops.name); + printk(KERN_ERR "i2c-adm5120.o: adapter %s registration failed\n", + bit_adm5120_ops.name); return -ENODEV; } - + +/* Configure GPIOs as open collector outputs (input) */ + adm5120_gpio_set(scl, 1); + adm5120_gpio_set(sda, 1); return 0; } @@ -199,7 +218,7 @@ EXPORT_NO_SYMBOLS; #ifdef MODULE -MODULE_AUTHOR("Steve Tsai "); +MODULE_AUTHOR("Steve Tsai ,modified DL4HUF "); MODULE_DESCRIPTION("ADM5120 I2C Driver"); MODULE_LICENSE("GPL"); @@ -209,8 +228,6 @@ MODULE_PARM(sda, "i"); MODULE_PARM_DESC(sda, "GPIO line for SDA"); - - int init_module(void) { return i2c_bitadm5120_init();