rtl8366_smi: sanitize gpio values to a 0/1 boolean
[15.05/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");