Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | /* * linux/arch/arm/kernel/iic.c * * Copyright (C) 1995, 1996 Russell King * * IIC is used to get the current time from the CMOS rtc. */ #include <linux/delay.h> #include <asm/system.h> #include <asm/io.h> #include <asm/hardware.h> /* * if delay loop has been calibrated then us that, * else use IOC timer 1. */ static void iic_delay (void) { extern unsigned long loops_per_sec; if (loops_per_sec != (1 << 12)) { udelay(10); return; } else { unsigned long flags; save_flags_cli(flags); outb(254, IOC_T1LTCHL); outb(255, IOC_T1LTCHH); outb(0, IOC_T1GO); outb(1<<6, IOC_IRQCLRA); /* clear T1 irq */ outb(4, IOC_T1LTCHL); outb(0, IOC_T1LTCHH); outb(0, IOC_T1GO); while ((inb(IOC_IRQSTATA) & (1<<6)) == 0); restore_flags(flags); } } static inline void iic_start (void) { unsigned char out; out = inb(IOC_CONTROL) | 0xc2; outb(out, IOC_CONTROL); iic_delay(); outb(out ^ 1, IOC_CONTROL); iic_delay(); } static inline void iic_stop (void) { unsigned char out; out = inb(IOC_CONTROL) | 0xc3; iic_delay(); outb(out ^ 1, IOC_CONTROL); iic_delay(); outb(out, IOC_CONTROL); } static int iic_sendbyte (unsigned char b) { unsigned char out, in; int i; out = (inb(IOC_CONTROL) & 0xfc) | 0xc0; outb(out, IOC_CONTROL); for (i = 7; i >= 0; i--) { unsigned char c; c = out | ((b & (1 << i)) ? 1 : 0); outb(c, IOC_CONTROL); iic_delay(); outb(c | 2, IOC_CONTROL); iic_delay(); outb(c, IOC_CONTROL); } outb(out | 1, IOC_CONTROL); iic_delay(); outb(out | 3, IOC_CONTROL); iic_delay(); in = inb(IOC_CONTROL) & 1; outb(out | 1, IOC_CONTROL); iic_delay(); outb(out, IOC_CONTROL); iic_delay(); if(in) { printk("No acknowledge from RTC\n"); return 1; } else return 0; } static unsigned char iic_recvbyte (void) { unsigned char out, in; int i; out = (inb(IOC_CONTROL) & 0xfc) | 0xc0; outb(out, IOC_CONTROL); in = 0; for (i = 7; i >= 0; i--) { outb(out | 1, IOC_CONTROL); iic_delay(); outb(out | 3, IOC_CONTROL); iic_delay(); in = (in << 1) | (inb(IOC_CONTROL) & 1); outb(out | 1, IOC_CONTROL); iic_delay(); } outb(out, IOC_CONTROL); iic_delay(); outb(out | 2, IOC_CONTROL); iic_delay(); return in; } void iic_control (unsigned char addr, unsigned char loc, unsigned char *buf, int len) { iic_start(); if (iic_sendbyte(addr & 0xfe)) goto error; if (iic_sendbyte(loc)) goto error; if (addr & 1) { int i; for (i = 0; i < len; i++) if (iic_sendbyte (buf[i])) break; } else { int i; iic_stop(); iic_start(); iic_sendbyte(addr|1); for (i = 0; i < len; i++) buf[i] = iic_recvbyte (); } error: iic_stop(); } |