1 /* 2 * linux/drivers/acorn/char/i2c.c 3 * 4 * Copyright (C) 2000 Russell King 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * ARM IOC/IOMD i2c driver. 11 * 12 * On Acorn machines, the following i2c devices are on the bus: 13 * - PCF8583 real time clock & static RAM 14 */ 15 #include <linux/init.h> 16 #include <linux/i2c.h> 17 #include <linux/i2c-algo-bit.h> 18 19 #include <asm/hardware.h> 20 #include <asm/io.h> 21 #include <asm/hardware/ioc.h> 22 #include <asm/system.h> 23 24 #define FORCE_ONES 0xdc 25 #define SCL 0x02 26 #define SDA 0x01 27 28 /* 29 * We must preserve all non-i2c output bits in IOC_CONTROL. 30 * Note also that we need to preserve the value of SCL and 31 * SDA outputs as well (which may be different from the 32 * values read back from IOC_CONTROL). 33 */ 34 static u_int force_ones; 35 36 static void ioc_setscl(void *data, int state) 37 { 38 u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA); 39 u_int ones = force_ones; 40 41 if (state) 42 ones |= SCL; 43 else 44 ones &= ~SCL; 45 46 force_ones = ones; 47 48 ioc_writeb(ioc_control | ones, IOC_CONTROL); 49 } 50 51 static void ioc_setsda(void *data, int state) 52 { 53 u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA); 54 u_int ones = force_ones; 55 56 if (state) 57 ones |= SDA; 58 else 59 ones &= ~SDA; 60 61 force_ones = ones; 62 63 ioc_writeb(ioc_control | ones, IOC_CONTROL); 64 } 65 66 static int ioc_getscl(void *data) 67 { 68 return (ioc_readb(IOC_CONTROL) & SCL) != 0; 69 } 70 71 static int ioc_getsda(void *data) 72 { 73 return (ioc_readb(IOC_CONTROL) & SDA) != 0; 74 } 75 76 static struct i2c_algo_bit_data ioc_data = { 77 .setsda = ioc_setsda, 78 .setscl = ioc_setscl, 79 .getsda = ioc_getsda, 80 .getscl = ioc_getscl, 81 .udelay = 80, 82 .timeout = 100 83 }; 84 85 static struct i2c_adapter ioc_ops = { 86 .id = I2C_HW_B_IOC, 87 .algo_data = &ioc_data, 88 }; 89 90 static int __init i2c_ioc_init(void) 91 { 92 force_ones = FORCE_ONES | SCL | SDA; 93 94 return i2c_bit_add_bus(&ioc_ops); 95 } 96 97 module_init(i2c_ioc_init); 98