/* ************************************************************** */ /* ************************************************************** */ /* FUNCTIONS PROTOTYPES */ /* ************************************************************** */ /* ************************************************************** */ int i2c_set_reg(struct hrt *hrtdev, int reg, unsigned char val); static int i2c_init(struct hrt *hrtdev, const unsigned char *init_regs); /* ************************************************************** */ /* ************************************************************** */ /* DR. BAKER’S I2C ROUTINES */ /* ************************************************************** */ /* ************************************************************** */ /* HRT_CONTROL_OFFSET is the offset of the I2C bus control port 0x2000 = 8192 = 2^13 */ #define HRT_CONTROL_OFFSET 0x2000 #define HRT_CONTROL(addr) (addr + HRT_CONTROL_OFFSET) /* bit 7 at 0x2000 (the HRT512-8 control register) tells whether the CPU is sending data across the I2C bus */ #define I2C_BUSY(addr) (!(readb(HRT_CONTROL(addr)) & 0x80)) /* 0x2001 = 8193 = 2^13+1 */ #define I2C_CONTROL_OFFSET 0x2001 /* The word at 0x2001 provides access to the i2c bus of the HRT512-8 bit 0 = i2c clock signal ("scl" for short) bit 1 = i2c data/address signal ("sda" for short) bit 2 = "go" signal for hardware to generate a clock pulse, once data is ready. This is a write-only bit. It is cleared by hardware a few microseconds after the software sets it high. */ #define I2C_CONTROL(addr) (addr + I2C_CONTROL_OFFSET) #define I2C_POKE(addr,data) { writeb(data,I2C_CONTROL(addr)); udelay(10); wmb(); } #define I2C_PEEK(addr) (readb(I2C_CONTROL(addr))) #define I2C_00(addr) { writeb(0,I2C_CONTROL(addr)); udelay(10); wmb(); } #define I2C_10(addr) { writeb(1,I2C_CONTROL(addr)); udelay(10); wmb(); } #define I2C_01(addr) { writeb(2,I2C_CONTROL(addr)); udelay(10); wmb(); } #define I2C_11(addr) { writeb(3,I2C_CONTROL(addr)); udelay(10); wmb(); } /** * i2c_start - sends 'start' command onto i2c bus to be recieved by all * devices on bus. (The HRT512-8 only has the on A/D on the i2c bus.) * This tells all devices on the i2c bus to prepare for an address * phase, i.e., that one of them will be addressed next. * The parameter is the mapped I/O base address of a device. */ static inline void i2c_start(unsigned long addr) { I2C_00(addr); I2C_01(addr); I2C_11(addr); I2C_10(addr); I2C_00(addr); } /** * i2c_stop - tells the selected device (A/D) that transmission has * completed and the bus is free. * The parameter is the mapped I/O base address of a device. */ static inline void i2c_stop(unsigned long addr) { I2C_00(addr); I2C_10(addr); I2C_11(addr); I2C_01(addr); I2C_11(addr); } /** * i2c_send_byte - sends a byte to the A/D. * The parameter addr is the mapped I/O base address of a device. */ static inline int i2c_send_byte(unsigned long addr, unsigned char data) { char bitpos; unsigned char sda, sda_slc; unsigned long timeout; for (bitpos = 7; bitpos >= 0; bitpos--) { /* send a bit to the A/D device; clock must be low at this time. first, get the next bit from data value */ sda = (data & (1 << bitpos)) >> bitpos; sda_slc = sda << 1; /* put data bit on bus and take clock low (b0=0) */ I2C_POKE(addr, sda_slc); /* send the go signal to initiate clock pulse */ I2C_POKE(addr, sda_slc + 4); if (I2C_BUSY(addr)) { timeout = jiffies + HZ / 10; while (I2C_BUSY(addr)) { /* spin */ if (jiffies > timeout) { hrt_printk("I2C bus timeout\n"); goto failure; } } } } I2C_01(addr); /* leave the sda line at high impedance (bit0=0 clock, bit1=1 data/high impedance) */ /* check for ack from A/D after each byte has been sent */ I2C_11(addr); if ((I2C_PEEK(addr) & 2) == 2) { /* error: no ACK after Data Byte transmision */ hrt_printk("No I2C ACK\n"); goto failure; } I2C_01(addr); /* return the bus to high impediance */ return 0; failure: /* This is only a gesture toward cleaning up; if there is a failure we probably have a broken device. */ I2C_01(addr); /* return the bus to high impedance */ i2c_stop(addr); return -1; } /** * i2c_init - set initial register values for the * SAA7110 A/D converter (digitizer), which is on an * I2C bus. If an array of values is given, use it; * otherwise, use the default set of values. See the * comment on the declaration of saa7110_default_init_regs * for the format of the argument. * The parameter addr is the mapped I/O base address of a device. * * NB that the first byte of the array should be the size of the array. */ /*static int i2c_init(struct hrt *hrtdev, unsigned long addr, const unsigned char *init_regs)*/ static int i2c_init(struct hrt *hrtdev, const unsigned char *init_regs) { int i, lastreg, len; unsigned long addr = hrtdev->virtaddr; if (!init_regs) init_regs = saa7110_default_init_regs; /* The length of the array is contained in the first byte */ len = init_regs[0]; init_regs++; i2c_start(addr); /* Tell the digitizer that it has been selected for data transmission. */ if (i2c_send_byte(addr, HRT_AD_DEVICE_ID)) { return -1; } /* Set the selected device's internal address register pointer to zero. Each subsequent data write will autoincrement the device's address register pointer. */ if (i2c_send_byte(addr, 0)) { return -1; } lastreg = 0; for (i = 0; i < len; i += 2) { if (init_regs[i] > HRT_NUMREGS) { hrt_printk("Register number 0x%x out of range!\n", init_regs[i]); return -1; } if (init_regs[i] != lastreg) { /* there is a gap in the sequence */ i2c_stop(addr); i2c_start(addr); /* resend device address byte */ if (i2c_send_byte(addr, HRT_AD_DEVICE_ID)) { return -1; } lastreg = init_regs[i]; /* send new register address byte */ if (i2c_send_byte(addr, init_regs[i])) { return -1; } } lastreg++; /* send register value */ if (i2c_send_byte(addr, init_regs[i + 1])) { return -1; } /* Keep track of the values in the registers */ hrtdev->regvals[init_regs[i]] = init_regs[i + 1]; } i2c_stop(addr); return 0; } /** * i2c_set_reg - set an I2C register, reg, to value val */ int i2c_set_reg(struct hrt *hrtdev, int reg, unsigned char val) { unsigned long addr = hrtdev->virtaddr; i2c_start(addr); i2c_send_byte(addr, HRT_AD_DEVICE_ID); i2c_send_byte(addr, reg); i2c_send_byte(addr, val); i2c_stop(addr); hrtdev->regvals[reg] = val; return val; }