2 * Realtek RTL8366 SMI interface driver
4 * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org>
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.
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 #include <linux/skbuff.h>
19 #include "rtl8366_smi.h"
21 #define RTL8366_SMI_ACK_RETRY_COUNT 5
22 #define RTL8366_SMI_CLK_DELAY 10 /* nsec */
24 static inline void rtl8366_smi_clk_delay(struct rtl8366_smi
*smi
)
26 ndelay(RTL8366_SMI_CLK_DELAY
);
29 static void rtl8366_smi_start(struct rtl8366_smi
*smi
)
31 unsigned int sda
= smi
->gpio_sda
;
32 unsigned int sck
= smi
->gpio_sck
;
35 * Set GPIO pins to output mode, with initial state:
38 gpio_direction_output(sck
, 0);
39 gpio_direction_output(sda
, 1);
40 rtl8366_smi_clk_delay(smi
);
42 /* CLK 1: 0 -> 1, 1 -> 0 */
43 gpio_set_value(sck
, 1);
44 rtl8366_smi_clk_delay(smi
);
45 gpio_set_value(sck
, 0);
46 rtl8366_smi_clk_delay(smi
);
49 gpio_set_value(sck
, 1);
50 rtl8366_smi_clk_delay(smi
);
51 gpio_set_value(sda
, 0);
52 rtl8366_smi_clk_delay(smi
);
53 gpio_set_value(sck
, 0);
54 rtl8366_smi_clk_delay(smi
);
55 gpio_set_value(sda
, 1);
58 static void rtl8366_smi_stop(struct rtl8366_smi
*smi
)
60 unsigned int sda
= smi
->gpio_sda
;
61 unsigned int sck
= smi
->gpio_sck
;
63 rtl8366_smi_clk_delay(smi
);
64 gpio_set_value(sda
, 0);
65 gpio_set_value(sck
, 1);
66 rtl8366_smi_clk_delay(smi
);
67 gpio_set_value(sda
, 1);
68 rtl8366_smi_clk_delay(smi
);
69 gpio_set_value(sck
, 1);
70 rtl8366_smi_clk_delay(smi
);
71 gpio_set_value(sck
, 0);
72 rtl8366_smi_clk_delay(smi
);
73 gpio_set_value(sck
, 1);
76 rtl8366_smi_clk_delay(smi
);
77 gpio_set_value(sck
, 0);
78 rtl8366_smi_clk_delay(smi
);
79 gpio_set_value(sck
, 1);
81 /* set GPIO pins to input mode */
82 gpio_direction_input(sda
);
83 gpio_direction_input(sck
);
86 static void rtl8366_smi_write_bits(struct rtl8366_smi
*smi
, u32 data
, u32 len
)
88 unsigned int sda
= smi
->gpio_sda
;
89 unsigned int sck
= smi
->gpio_sck
;
91 for (; len
> 0; len
--) {
92 rtl8366_smi_clk_delay(smi
);
95 gpio_set_value(sda
, !!(data
& ( 1 << (len
- 1))));
96 rtl8366_smi_clk_delay(smi
);
99 gpio_set_value(sck
, 1);
100 rtl8366_smi_clk_delay(smi
);
101 gpio_set_value(sck
, 0);
105 static void rtl8366_smi_read_bits(struct rtl8366_smi
*smi
, u32 len
, u32
*data
)
107 unsigned int sda
= smi
->gpio_sda
;
108 unsigned int sck
= smi
->gpio_sck
;
110 gpio_direction_input(sda
);
112 for (*data
= 0; len
> 0; len
--) {
115 rtl8366_smi_clk_delay(smi
);
118 gpio_set_value(sck
, 1);
119 rtl8366_smi_clk_delay(smi
);
120 u
= !!gpio_get_value(sda
);
121 gpio_set_value(sck
, 0);
123 *data
|= (u
<< (len
- 1));
126 gpio_direction_output(sda
, 0);
129 static int rtl8366_smi_wait_for_ack(struct rtl8366_smi
*smi
)
137 rtl8366_smi_read_bits(smi
, 1, &ack
);
141 if (++retry_cnt
> RTL8366_SMI_ACK_RETRY_COUNT
)
148 static int rtl8366_smi_write_byte(struct rtl8366_smi
*smi
, u8 data
)
150 rtl8366_smi_write_bits(smi
, data
, 8);
151 return rtl8366_smi_wait_for_ack(smi
);
154 static int rtl8366_smi_read_byte0(struct rtl8366_smi
*smi
, u8
*data
)
159 rtl8366_smi_read_bits(smi
, 8, &t
);
163 rtl8366_smi_write_bits(smi
, 0x00, 1);
168 static int rtl8366_smi_read_byte1(struct rtl8366_smi
*smi
, u8
*data
)
173 rtl8366_smi_read_bits(smi
, 8, &t
);
177 rtl8366_smi_write_bits(smi
, 0x01, 1);
182 int rtl8366_smi_read_reg(struct rtl8366_smi
*smi
, u32 addr
, u32
*data
)
189 spin_lock_irqsave(&smi
->lock
, flags
);
191 rtl8366_smi_start(smi
);
193 /* send READ command */
194 ret
= rtl8366_smi_write_byte(smi
, 0x0a << 4 | 0x04 << 1 | 0x01);
199 ret
= rtl8366_smi_write_byte(smi
, addr
& 0xff);
204 ret
= rtl8366_smi_write_byte(smi
, addr
>> 8);
209 rtl8366_smi_read_byte0(smi
, &lo
);
210 /* read DATA[15:8] */
211 rtl8366_smi_read_byte1(smi
, &hi
);
213 *data
= ((u32
) lo
) | (((u32
) hi
) << 8);
218 rtl8366_smi_stop(smi
);
219 spin_unlock_irqrestore(&smi
->lock
, flags
);
223 EXPORT_SYMBOL_GPL(rtl8366_smi_read_reg
);
225 int rtl8366_smi_write_reg(struct rtl8366_smi
*smi
, u32 addr
, u32 data
)
230 spin_lock_irqsave(&smi
->lock
, flags
);
232 rtl8366_smi_start(smi
);
234 /* send WRITE command */
235 ret
= rtl8366_smi_write_byte(smi
, 0x0a << 4 | 0x04 << 1 | 0x00);
240 ret
= rtl8366_smi_write_byte(smi
, addr
& 0xff);
245 ret
= rtl8366_smi_write_byte(smi
, addr
>> 8);
249 /* write DATA[7:0] */
250 ret
= rtl8366_smi_write_byte(smi
, data
& 0xff);
254 /* write DATA[15:8] */
255 ret
= rtl8366_smi_write_byte(smi
, data
>> 8);
262 rtl8366_smi_stop(smi
);
263 spin_unlock_irqrestore(&smi
->lock
, flags
);
267 EXPORT_SYMBOL_GPL(rtl8366_smi_write_reg
);
269 int rtl8366_smi_rmwr(struct rtl8366_smi
*smi
, u32 addr
, u32 mask
, u32 data
)
274 err
= rtl8366_smi_read_reg(smi
, addr
, &t
);
278 err
= rtl8366_smi_write_reg(smi
, addr
, (t
& ~mask
) | data
);
282 EXPORT_SYMBOL_GPL(rtl8366_smi_rmwr
);
284 static int rtl8366_mc_is_used(struct rtl8366_smi
*smi
, int mc_index
, int *used
)
290 for (i
= 0; i
< smi
->num_ports
; i
++) {
293 err
= smi
->ops
->get_mc_index(smi
, i
, &index
);
297 if (mc_index
== index
) {
306 int rtl8366_set_vlan(struct rtl8366_smi
*smi
, int vid
, u32 member
, u32 untag
,
309 struct rtl8366_vlan_4k vlan4k
;
313 /* Update the 4K table */
314 err
= smi
->ops
->get_vlan_4k(smi
, vid
, &vlan4k
);
318 vlan4k
.member
= member
;
319 vlan4k
.untag
= untag
;
321 err
= smi
->ops
->set_vlan_4k(smi
, &vlan4k
);
325 /* Try to find an existing MC entry for this VID */
326 for (i
= 0; i
< smi
->num_vlan_mc
; i
++) {
327 struct rtl8366_vlan_mc vlanmc
;
329 err
= smi
->ops
->get_vlan_mc(smi
, i
, &vlanmc
);
333 if (vid
== vlanmc
.vid
) {
334 /* update the MC entry */
335 vlanmc
.member
= member
;
336 vlanmc
.untag
= untag
;
339 err
= smi
->ops
->set_vlan_mc(smi
, i
, &vlanmc
);
346 EXPORT_SYMBOL_GPL(rtl8366_set_vlan
);
348 int rtl8366_reset_vlan(struct rtl8366_smi
*smi
)
350 struct rtl8366_vlan_mc vlanmc
;
354 /* clear VLAN member configurations */
360 for (i
= 0; i
< smi
->num_vlan_mc
; i
++) {
361 err
= smi
->ops
->set_vlan_mc(smi
, i
, &vlanmc
);
366 for (i
= 0; i
< smi
->num_ports
; i
++) {
367 if (i
== smi
->cpu_port
)
370 err
= rtl8366_set_vlan(smi
, (i
+ 1),
371 (1 << i
) | (1 << smi
->cpu_port
),
372 (1 << i
) | (1 << smi
->cpu_port
),
377 err
= rtl8366_set_pvid(smi
, i
, (i
+ 1));
384 EXPORT_SYMBOL_GPL(rtl8366_reset_vlan
);
386 int rtl8366_get_pvid(struct rtl8366_smi
*smi
, int port
, int *val
)
388 struct rtl8366_vlan_mc vlanmc
;
392 err
= smi
->ops
->get_mc_index(smi
, port
, &index
);
396 err
= smi
->ops
->get_vlan_mc(smi
, index
, &vlanmc
);
403 EXPORT_SYMBOL_GPL(rtl8366_get_pvid
);
405 int rtl8366_set_pvid(struct rtl8366_smi
*smi
, unsigned port
, unsigned vid
)
407 struct rtl8366_vlan_mc vlanmc
;
408 struct rtl8366_vlan_4k vlan4k
;
412 /* Try to find an existing MC entry for this VID */
413 for (i
= 0; i
< smi
->num_vlan_mc
; i
++) {
414 err
= smi
->ops
->get_vlan_mc(smi
, i
, &vlanmc
);
418 if (vid
== vlanmc
.vid
) {
419 err
= smi
->ops
->set_vlan_mc(smi
, i
, &vlanmc
);
423 err
= smi
->ops
->set_mc_index(smi
, port
, i
);
428 /* We have no MC entry for this VID, try to find an empty one */
429 for (i
= 0; i
< smi
->num_vlan_mc
; i
++) {
430 err
= smi
->ops
->get_vlan_mc(smi
, i
, &vlanmc
);
434 if (vlanmc
.vid
== 0 && vlanmc
.member
== 0) {
435 /* Update the entry from the 4K table */
436 err
= smi
->ops
->get_vlan_4k(smi
, vid
, &vlan4k
);
441 vlanmc
.member
= vlan4k
.member
;
442 vlanmc
.untag
= vlan4k
.untag
;
443 vlanmc
.fid
= vlan4k
.fid
;
444 err
= smi
->ops
->set_vlan_mc(smi
, i
, &vlanmc
);
448 err
= smi
->ops
->set_mc_index(smi
, port
, i
);
453 /* MC table is full, try to find an unused entry and replace it */
454 for (i
= 0; i
< smi
->num_vlan_mc
; i
++) {
457 err
= rtl8366_mc_is_used(smi
, i
, &used
);
462 /* Update the entry from the 4K table */
463 err
= smi
->ops
->get_vlan_4k(smi
, vid
, &vlan4k
);
468 vlanmc
.member
= vlan4k
.member
;
469 vlanmc
.untag
= vlan4k
.untag
;
470 vlanmc
.fid
= vlan4k
.fid
;
471 err
= smi
->ops
->set_vlan_mc(smi
, i
, &vlanmc
);
475 err
= smi
->ops
->set_mc_index(smi
, port
, i
);
481 "all VLAN member configurations are in use\n");
485 EXPORT_SYMBOL_GPL(rtl8366_set_pvid
);
487 static int rtl8366_smi_mii_init(struct rtl8366_smi
*smi
)
492 smi
->mii_bus
= mdiobus_alloc();
493 if (smi
->mii_bus
== NULL
) {
498 smi
->mii_bus
->priv
= (void *) smi
;
499 smi
->mii_bus
->name
= dev_name(smi
->parent
);
500 smi
->mii_bus
->read
= smi
->ops
->mii_read
;
501 smi
->mii_bus
->write
= smi
->ops
->mii_write
;
502 snprintf(smi
->mii_bus
->id
, MII_BUS_ID_SIZE
, "%s",
503 dev_name(smi
->parent
));
504 smi
->mii_bus
->parent
= smi
->parent
;
505 smi
->mii_bus
->phy_mask
= ~(0x1f);
506 smi
->mii_bus
->irq
= smi
->mii_irq
;
507 for (i
= 0; i
< PHY_MAX_ADDR
; i
++)
508 smi
->mii_irq
[i
] = PHY_POLL
;
510 ret
= mdiobus_register(smi
->mii_bus
);
517 mdiobus_free(smi
->mii_bus
);
522 static void rtl8366_smi_mii_cleanup(struct rtl8366_smi
*smi
)
524 mdiobus_unregister(smi
->mii_bus
);
525 mdiobus_free(smi
->mii_bus
);
528 int rtl8366_smi_init(struct rtl8366_smi
*smi
)
538 err
= gpio_request(smi
->gpio_sda
, dev_name(smi
->parent
));
540 dev_err(smi
->parent
, "gpio_request failed for %u, err=%d\n",
545 err
= gpio_request(smi
->gpio_sck
, dev_name(smi
->parent
));
547 dev_err(smi
->parent
, "gpio_request failed for %u, err=%d\n",
552 spin_lock_init(&smi
->lock
);
554 dev_info(smi
->parent
, "using GPIO pins %u (SDA) and %u (SCK)\n",
555 smi
->gpio_sda
, smi
->gpio_sck
);
557 err
= smi
->ops
->detect(smi
);
559 dev_err(smi
->parent
, "chip detection failed, err=%d\n", err
);
563 err
= rtl8366_smi_mii_init(smi
);
570 gpio_free(smi
->gpio_sck
);
572 gpio_free(smi
->gpio_sda
);
576 EXPORT_SYMBOL_GPL(rtl8366_smi_init
);
578 void rtl8366_smi_cleanup(struct rtl8366_smi
*smi
)
580 rtl8366_smi_mii_cleanup(smi
);
581 gpio_free(smi
->gpio_sck
);
582 gpio_free(smi
->gpio_sda
);
584 EXPORT_SYMBOL_GPL(rtl8366_smi_cleanup
);
586 MODULE_DESCRIPTION("Realtek RTL8366 SMI interface driver");
587 MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
588 MODULE_LICENSE("GPL v2");