diff options
Diffstat (limited to 'firmware/drivers/i2c-pp5020.c')
-rw-r--r-- | firmware/drivers/i2c-pp5020.c | 80 |
1 files changed, 52 insertions, 28 deletions
diff --git a/firmware/drivers/i2c-pp5020.c b/firmware/drivers/i2c-pp5020.c index 522ddbed77..77671e79d8 100644 --- a/firmware/drivers/i2c-pp5020.c +++ b/firmware/drivers/i2c-pp5020.c | |||
@@ -57,42 +57,48 @@ static int ipod_i2c_wait_not_busy(void) | |||
57 | if (!(inb(IPOD_I2C_STATUS) & IPOD_I2C_BUSY)) { | 57 | if (!(inb(IPOD_I2C_STATUS) & IPOD_I2C_BUSY)) { |
58 | return 0; | 58 | return 0; |
59 | } | 59 | } |
60 | yield(); | ||
60 | } | 61 | } |
61 | 62 | ||
62 | return -1; | 63 | return -1; |
63 | } | 64 | } |
64 | 65 | ||
65 | 66 | ||
66 | /* Public functions */ | 67 | static int ipod_i2c_read_byte(unsigned int addr, unsigned int *data) |
67 | |||
68 | int ipod_i2c_read_byte(unsigned int addr, unsigned int *data) | ||
69 | { | 68 | { |
70 | if (ipod_i2c_wait_not_busy() < 0) | 69 | if (ipod_i2c_wait_not_busy() < 0) |
71 | { | 70 | { |
72 | return -1; | 71 | return -1; |
73 | } | 72 | } |
74 | 73 | ||
75 | /* clear top 15 bits, left shift 1, or in 0x1 for a read */ | 74 | { |
76 | outb(((addr << 17) >> 16) | 0x1, IPOD_I2C_ADDR); | 75 | int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL); |
77 | 76 | ||
78 | outb(inb(IPOD_I2C_CTRL) | 0x20, IPOD_I2C_CTRL); | 77 | /* clear top 15 bits, left shift 1, or in 0x1 for a read */ |
78 | outb(((addr << 17) >> 16) | 0x1, IPOD_I2C_ADDR); | ||
79 | 79 | ||
80 | outb(inb(IPOD_I2C_CTRL) | IPOD_I2C_SEND, IPOD_I2C_CTRL); | 80 | outb(inb(IPOD_I2C_CTRL) | 0x20, IPOD_I2C_CTRL); |
81 | 81 | ||
82 | if (ipod_i2c_wait_not_busy() < 0) | 82 | outb(inb(IPOD_I2C_CTRL) | IPOD_I2C_SEND, IPOD_I2C_CTRL); |
83 | { | ||
84 | return -1; | ||
85 | } | ||
86 | 83 | ||
87 | if (data) | 84 | set_irq_level(old_irq_level); |
88 | { | 85 | |
89 | *data = inb(IPOD_I2C_DATA0); | 86 | if (data) |
87 | { | ||
88 | if (ipod_i2c_wait_not_busy() < 0) | ||
89 | { | ||
90 | return -1; | ||
91 | } | ||
92 | old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL); | ||
93 | *data = inb(IPOD_I2C_DATA0); | ||
94 | set_irq_level(old_irq_level); | ||
95 | } | ||
90 | } | 96 | } |
91 | 97 | ||
92 | return 0; | 98 | return 0; |
93 | } | 99 | } |
94 | 100 | ||
95 | int ipod_i2c_send_bytes(unsigned int addr, unsigned int len, unsigned char *data) | 101 | static int ipod_i2c_send_bytes(unsigned int addr, unsigned int len, unsigned char *data) |
96 | { | 102 | { |
97 | int data_addr; | 103 | int data_addr; |
98 | unsigned int i; | 104 | unsigned int i; |
@@ -107,26 +113,32 @@ int ipod_i2c_send_bytes(unsigned int addr, unsigned int len, unsigned char *data | |||
107 | return -2; | 113 | return -2; |
108 | } | 114 | } |
109 | 115 | ||
110 | /* clear top 15 bits, left shift 1 */ | 116 | { |
111 | outb((addr << 17) >> 16, IPOD_I2C_ADDR); | 117 | int old_irq_level = set_irq_level(HIGHEST_IRQ_LEVEL); |
112 | 118 | ||
113 | outb(inb(IPOD_I2C_CTRL) & ~0x20, IPOD_I2C_CTRL); | 119 | /* clear top 15 bits, left shift 1 */ |
120 | outb((addr << 17) >> 16, IPOD_I2C_ADDR); | ||
114 | 121 | ||
115 | data_addr = IPOD_I2C_DATA0; | 122 | outb(inb(IPOD_I2C_CTRL) & ~0x20, IPOD_I2C_CTRL); |
116 | for ( i = 0; i < len; i++ ) | 123 | |
117 | { | 124 | data_addr = IPOD_I2C_DATA0; |
118 | outb(*data++, data_addr); | 125 | for ( i = 0; i < len; i++ ) |
119 | data_addr += 4; | 126 | { |
120 | } | 127 | outb(*data++, data_addr); |
128 | data_addr += 4; | ||
129 | } | ||
121 | 130 | ||
122 | outb((inb(IPOD_I2C_CTRL) & ~0x26) | ((len-1) << 1), IPOD_I2C_CTRL); | 131 | outb((inb(IPOD_I2C_CTRL) & ~0x26) | ((len-1) << 1), IPOD_I2C_CTRL); |
123 | 132 | ||
124 | outb(inb(IPOD_I2C_CTRL) | IPOD_I2C_SEND, IPOD_I2C_CTRL); | 133 | outb(inb(IPOD_I2C_CTRL) | IPOD_I2C_SEND, IPOD_I2C_CTRL); |
134 | |||
135 | set_irq_level(old_irq_level); | ||
136 | } | ||
125 | 137 | ||
126 | return 0x0; | 138 | return 0x0; |
127 | } | 139 | } |
128 | 140 | ||
129 | int ipod_i2c_send_byte(unsigned int addr, int data0) | 141 | static int ipod_i2c_send_byte(unsigned int addr, int data0) |
130 | { | 142 | { |
131 | unsigned char data[1]; | 143 | unsigned char data[1]; |
132 | 144 | ||
@@ -135,25 +147,35 @@ int ipod_i2c_send_byte(unsigned int addr, int data0) | |||
135 | return ipod_i2c_send_bytes(addr, 1, data); | 147 | return ipod_i2c_send_bytes(addr, 1, data); |
136 | } | 148 | } |
137 | 149 | ||
150 | /* Public functions */ | ||
151 | static struct mutex i2c_mutex; | ||
138 | 152 | ||
139 | int i2c_readbyte(unsigned int dev_addr, int addr) | 153 | int i2c_readbyte(unsigned int dev_addr, int addr) |
140 | { | 154 | { |
155 | int retval; | ||
141 | int data; | 156 | int data; |
142 | 157 | ||
158 | mutex_lock(&i2c_mutex); | ||
143 | ipod_i2c_send_byte(dev_addr, addr); | 159 | ipod_i2c_send_byte(dev_addr, addr); |
144 | ipod_i2c_read_byte(dev_addr, &data); | 160 | ipod_i2c_read_byte(dev_addr, &data); |
161 | mutex_unlock(&i2c_mutex); | ||
145 | 162 | ||
146 | return data; | 163 | return data; |
147 | } | 164 | } |
148 | 165 | ||
149 | int ipod_i2c_send(unsigned int addr, int data0, int data1) | 166 | int ipod_i2c_send(unsigned int addr, int data0, int data1) |
150 | { | 167 | { |
168 | int retval; | ||
151 | unsigned char data[2]; | 169 | unsigned char data[2]; |
152 | 170 | ||
153 | data[0] = data0; | 171 | data[0] = data0; |
154 | data[1] = data1; | 172 | data[1] = data1; |
155 | 173 | ||
156 | return ipod_i2c_send_bytes(addr, 2, data); | 174 | mutex_lock(&i2c_mutex); |
175 | retval = ipod_i2c_send_bytes(addr, 2, data); | ||
176 | mutex_unlock(&i2c_mutex); | ||
177 | |||
178 | return retval; | ||
157 | } | 179 | } |
158 | 180 | ||
159 | void i2c_init(void) | 181 | void i2c_init(void) |
@@ -175,5 +197,7 @@ void i2c_init(void) | |||
175 | outl(0x0, 0x600060a4); | 197 | outl(0x0, 0x600060a4); |
176 | outl(0x80 | (0 << 8), 0x600060a4); | 198 | outl(0x80 | (0 << 8), 0x600060a4); |
177 | 199 | ||
200 | mutex_init(&i2c_mutex); | ||
201 | |||
178 | i2c_readbyte(0x8, 0); | 202 | i2c_readbyte(0x8, 0); |
179 | } | 203 | } |