[package] base-files, ppp: fix interface shutdown
[openwrt.git] / target / linux / generic-2.6 / files / drivers / net / phy / rtl8366_smi.c
1 /*
2 * Realtek RTL8366 SMI interface driver
3 *
4 * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published
8 * by the Free Software Foundation.
9 */
10
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/device.h>
14 #include <linux/delay.h>
15 #include <linux/gpio.h>
16 #include <linux/spinlock.h>
17
18 #include "rtl8366_smi.h"
19
20 #define RTL8366_SMI_ACK_RETRY_COUNT 5
21 #define RTL8366_SMI_CLK_DELAY 10 /* nsec */
22
23 static inline void rtl8366_smi_clk_delay(struct rtl8366_smi *smi)
24 {
25 ndelay(RTL8366_SMI_CLK_DELAY);
26 }
27
28 static void rtl8366_smi_start(struct rtl8366_smi *smi)
29 {
30 unsigned int sda = smi->gpio_sda;
31 unsigned int sck = smi->gpio_sck;
32
33 /*
34 * Set GPIO pins to output mode, with initial state:
35 * SCK = 0, SDA = 1
36 */
37 gpio_direction_output(sck, 0);
38 gpio_direction_output(sda, 1);
39 rtl8366_smi_clk_delay(smi);
40
41 /* CLK 1: 0 -> 1, 1 -> 0 */
42 gpio_set_value(sck, 1);
43 rtl8366_smi_clk_delay(smi);
44 gpio_set_value(sck, 0);
45 rtl8366_smi_clk_delay(smi);
46
47 /* CLK 2: */
48 gpio_set_value(sck, 1);
49 rtl8366_smi_clk_delay(smi);
50 gpio_set_value(sda, 0);
51 rtl8366_smi_clk_delay(smi);
52 gpio_set_value(sck, 0);
53 rtl8366_smi_clk_delay(smi);
54 gpio_set_value(sda, 1);
55 }
56
57 static void rtl8366_smi_stop(struct rtl8366_smi *smi)
58 {
59 unsigned int sda = smi->gpio_sda;
60 unsigned int sck = smi->gpio_sck;
61
62 rtl8366_smi_clk_delay(smi);
63 gpio_set_value(sda, 0);
64 gpio_set_value(sck, 1);
65 rtl8366_smi_clk_delay(smi);
66 gpio_set_value(sda, 1);
67 rtl8366_smi_clk_delay(smi);
68 gpio_set_value(sck, 1);
69 rtl8366_smi_clk_delay(smi);
70 gpio_set_value(sck, 0);
71 rtl8366_smi_clk_delay(smi);
72 gpio_set_value(sck, 1);
73
74 /* add a click */
75 rtl8366_smi_clk_delay(smi);
76 gpio_set_value(sck, 0);
77 rtl8366_smi_clk_delay(smi);
78 gpio_set_value(sck, 1);
79
80 /* set GPIO pins to input mode */
81 gpio_direction_input(sda);
82 gpio_direction_input(sck);
83 }
84
85 static void rtl8366_smi_write_bits(struct rtl8366_smi *smi, u32 data, u32 len)
86 {
87 unsigned int sda = smi->gpio_sda;
88 unsigned int sck = smi->gpio_sck;
89
90 for (; len > 0; len--) {
91 rtl8366_smi_clk_delay(smi);
92
93 /* prepare data */
94 gpio_set_value(sda, !!(data & ( 1 << (len - 1))));
95 rtl8366_smi_clk_delay(smi);
96
97 /* clocking */
98 gpio_set_value(sck, 1);
99 rtl8366_smi_clk_delay(smi);
100 gpio_set_value(sck, 0);
101 }
102 }
103
104 static void rtl8366_smi_read_bits(struct rtl8366_smi *smi, u32 len, u32 *data)
105 {
106 unsigned int sda = smi->gpio_sda;
107 unsigned int sck = smi->gpio_sck;
108
109 gpio_direction_input(sda);
110
111 for (*data = 0; len > 0; len--) {
112 u32 u;
113
114 rtl8366_smi_clk_delay(smi);
115
116 /* clocking */
117 gpio_set_value(sck, 1);
118 rtl8366_smi_clk_delay(smi);
119 u = !!gpio_get_value(sda);
120 gpio_set_value(sck, 0);
121
122 *data |= (u << (len - 1));
123 }
124
125 gpio_direction_output(sda, 0);
126 }
127
128 static int rtl8366_smi_wait_for_ack(struct rtl8366_smi *smi)
129 {
130 int retry_cnt;
131
132 retry_cnt = 0;
133 do {
134 u32 ack;
135
136 rtl8366_smi_read_bits(smi, 1, &ack);
137 if (ack == 0)
138 break;
139
140 if (++retry_cnt > RTL8366_SMI_ACK_RETRY_COUNT)
141 return -EIO;
142 } while (1);
143
144 return 0;
145 }
146
147 static int rtl8366_smi_write_byte(struct rtl8366_smi *smi, u8 data)
148 {
149 rtl8366_smi_write_bits(smi, data, 8);
150 return rtl8366_smi_wait_for_ack(smi);
151 }
152
153 static int rtl8366_smi_read_byte0(struct rtl8366_smi *smi, u8 *data)
154 {
155 u32 t;
156
157 /* read data */
158 rtl8366_smi_read_bits(smi, 8, &t);
159 *data = (t & 0xff);
160
161 /* send an ACK */
162 rtl8366_smi_write_bits(smi, 0x00, 1);
163
164 return 0;
165 }
166
167 static int rtl8366_smi_read_byte1(struct rtl8366_smi *smi, u8 *data)
168 {
169 u32 t;
170
171 /* read data */
172 rtl8366_smi_read_bits(smi, 8, &t);
173 *data = (t & 0xff);
174
175 /* send an ACK */
176 rtl8366_smi_write_bits(smi, 0x01, 1);
177
178 return 0;
179 }
180
181 int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data)
182 {
183 unsigned long flags;
184 u8 lo = 0;
185 u8 hi = 0;
186 int ret;
187
188 spin_lock_irqsave(&smi->lock, flags);
189
190 rtl8366_smi_start(smi);
191
192 /* send READ command */
193 ret = rtl8366_smi_write_byte(smi, 0x0a << 4 | 0x04 << 1 | 0x01);
194 if (ret)
195 goto out;
196
197 /* set ADDR[7:0] */
198 ret = rtl8366_smi_write_byte(smi, addr & 0xff);
199 if (ret)
200 goto out;
201
202 /* set ADDR[15:8] */
203 ret = rtl8366_smi_write_byte(smi, addr >> 8);
204 if (ret)
205 goto out;
206
207 /* read DATA[7:0] */
208 rtl8366_smi_read_byte0(smi, &lo);
209 /* read DATA[15:8] */
210 rtl8366_smi_read_byte1(smi, &hi);
211
212 *data = ((u32) lo) | (((u32) hi) << 8);
213
214 ret = 0;
215
216 out:
217 rtl8366_smi_stop(smi);
218 spin_unlock_irqrestore(&smi->lock, flags);
219
220 return ret;
221 }
222 EXPORT_SYMBOL_GPL(rtl8366_smi_read_reg);
223
224 int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data)
225 {
226 unsigned long flags;
227 int ret;
228
229 spin_lock_irqsave(&smi->lock, flags);
230
231 rtl8366_smi_start(smi);
232
233 /* send WRITE command */
234 ret = rtl8366_smi_write_byte(smi, 0x0a << 4 | 0x04 << 1 | 0x00);
235 if (ret)
236 goto out;
237
238 /* set ADDR[7:0] */
239 ret = rtl8366_smi_write_byte(smi, addr & 0xff);
240 if (ret)
241 goto out;
242
243 /* set ADDR[15:8] */
244 ret = rtl8366_smi_write_byte(smi, addr >> 8);
245 if (ret)
246 goto out;
247
248 /* write DATA[7:0] */
249 ret = rtl8366_smi_write_byte(smi, data & 0xff);
250 if (ret)
251 goto out;
252
253 /* write DATA[15:8] */
254 ret = rtl8366_smi_write_byte(smi, data >> 8);
255 if (ret)
256 goto out;
257
258 ret = 0;
259
260 out:
261 rtl8366_smi_stop(smi);
262 spin_unlock_irqrestore(&smi->lock, flags);
263
264 return ret;
265 }
266 EXPORT_SYMBOL_GPL(rtl8366_smi_write_reg);
267
268 int rtl8366_smi_init(struct rtl8366_smi *smi)
269 {
270 int err;
271
272 if (!smi->parent)
273 return -EINVAL;
274
275 err = gpio_request(smi->gpio_sda, dev_name(smi->parent));
276 if (err) {
277 dev_err(smi->parent, "gpio_request failed for %u, err=%d\n",
278 smi->gpio_sda, err);
279 goto err_out;
280 }
281
282 err = gpio_request(smi->gpio_sck, dev_name(smi->parent));
283 if (err) {
284 dev_err(smi->parent, "gpio_request failed for %u, err=%d\n",
285 smi->gpio_sck, err);
286 goto err_free_sda;
287 }
288
289 spin_lock_init(&smi->lock);
290
291 dev_info(smi->parent, "using GPIO pins %u (SDA) and %u (SCK)\n",
292 smi->gpio_sda, smi->gpio_sck);
293
294 return 0;
295
296 err_free_sda:
297 gpio_free(smi->gpio_sda);
298 err_out:
299 return err;
300 }
301 EXPORT_SYMBOL_GPL(rtl8366_smi_init);
302
303 void rtl8366_smi_cleanup(struct rtl8366_smi *smi)
304 {
305 gpio_free(smi->gpio_sck);
306 gpio_free(smi->gpio_sda);
307 }
308 EXPORT_SYMBOL_GPL(rtl8366_smi_cleanup);
309
310 MODULE_DESCRIPTION("Realtek RTL8366 SMI interface driver");
311 MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
312 MODULE_LICENSE("GPL v2");
This page took 0.060934 seconds and 5 git commands to generate.