X-Git-Url: http://git.rohieb.name/openwrt.git/blobdiff_plain/2743857121688903c2842429f967a5c58059fc9f..69776356230d6afbb5017945e4053f98cabf6496:/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c index 9fff2cc54..e48ca99ce 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c +++ b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef CONFIG_RTL8366S_PHY_DEBUG_FS #include @@ -23,11 +24,10 @@ #include "rtl8366_smi.h" #define RTL8366_SMI_ACK_RETRY_COUNT 5 -#define RTL8366_SMI_CLK_DELAY 10 /* nsec */ static inline void rtl8366_smi_clk_delay(struct rtl8366_smi *smi) { - ndelay(RTL8366_SMI_CLK_DELAY); + ndelay(smi->clk_delay); } static void rtl8366_smi_start(struct rtl8366_smi *smi) @@ -142,8 +142,10 @@ static int rtl8366_smi_wait_for_ack(struct rtl8366_smi *smi) if (ack == 0) break; - if (++retry_cnt > RTL8366_SMI_ACK_RETRY_COUNT) - return -EIO; + if (++retry_cnt > RTL8366_SMI_ACK_RETRY_COUNT) { + dev_err(smi->parent, "ACK timeout\n"); + return -ETIMEDOUT; + } } while (1); return 0; @@ -155,6 +157,12 @@ static int rtl8366_smi_write_byte(struct rtl8366_smi *smi, u8 data) return rtl8366_smi_wait_for_ack(smi); } +static int rtl8366_smi_write_byte_noack(struct rtl8366_smi *smi, u8 data) +{ + rtl8366_smi_write_bits(smi, data, 8); + return 0; +} + static int rtl8366_smi_read_byte0(struct rtl8366_smi *smi, u8 *data) { u32 t; @@ -195,7 +203,7 @@ int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data) rtl8366_smi_start(smi); /* send READ command */ - ret = rtl8366_smi_write_byte(smi, 0x0a << 4 | 0x04 << 1 | 0x01); + ret = rtl8366_smi_write_byte(smi, smi->cmd_read); if (ret) goto out; @@ -226,7 +234,8 @@ int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data) } EXPORT_SYMBOL_GPL(rtl8366_smi_read_reg); -int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data) +static int __rtl8366_smi_write_reg(struct rtl8366_smi *smi, + u32 addr, u32 data, bool ack) { unsigned long flags; int ret; @@ -236,7 +245,7 @@ int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data) rtl8366_smi_start(smi); /* send WRITE command */ - ret = rtl8366_smi_write_byte(smi, 0x0a << 4 | 0x04 << 1 | 0x00); + ret = rtl8366_smi_write_byte(smi, smi->cmd_write); if (ret) goto out; @@ -256,7 +265,10 @@ int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data) goto out; /* write DATA[15:8] */ - ret = rtl8366_smi_write_byte(smi, data >> 8); + if (ack) + ret = rtl8366_smi_write_byte(smi, data >> 8); + else + ret = rtl8366_smi_write_byte_noack(smi, data >> 8); if (ret) goto out; @@ -268,8 +280,19 @@ int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data) return ret; } + +int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data) +{ + return __rtl8366_smi_write_reg(smi, addr, data, true); +} EXPORT_SYMBOL_GPL(rtl8366_smi_write_reg); +int rtl8366_smi_write_reg_noack(struct rtl8366_smi *smi, u32 addr, u32 data) +{ + return __rtl8366_smi_write_reg(smi, addr, data, false); +} +EXPORT_SYMBOL_GPL(rtl8366_smi_write_reg_noack); + int rtl8366_smi_rmwr(struct rtl8366_smi *smi, u32 addr, u32 mask, u32 data) { u32 t; @@ -448,7 +471,7 @@ static int rtl8366_set_pvid(struct rtl8366_smi *smi, unsigned port, return -ENOSPC; } -static int rtl8366_enable_vlan(struct rtl8366_smi *smi, int enable) +int rtl8366_enable_vlan(struct rtl8366_smi *smi, int enable) { int err; @@ -465,6 +488,7 @@ static int rtl8366_enable_vlan(struct rtl8366_smi *smi, int enable) return err; } +EXPORT_SYMBOL_GPL(rtl8366_enable_vlan); static int rtl8366_enable_vlan4k(struct rtl8366_smi *smi, int enable) { @@ -486,6 +510,21 @@ static int rtl8366_enable_vlan4k(struct rtl8366_smi *smi, int enable) return 0; } +int rtl8366_enable_all_ports(struct rtl8366_smi *smi, int enable) +{ + int port; + int err; + + for (port = 0; port < smi->num_ports; port++) { + err = smi->ops->enable_port(smi, port, enable); + if (err) + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_enable_all_ports); + int rtl8366_reset_vlan(struct rtl8366_smi *smi) { struct rtl8366_vlan_mc vlanmc; @@ -507,25 +546,38 @@ int rtl8366_reset_vlan(struct rtl8366_smi *smi) return err; } - for (i = 0; i < smi->num_ports; i++) { - if (i == smi->cpu_port) - continue; + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_reset_vlan); + +static int rtl8366_init_vlan(struct rtl8366_smi *smi) +{ + int port; + int err; - err = rtl8366_set_vlan(smi, (i + 1), - (1 << i) | (1 << smi->cpu_port), - (1 << i) | (1 << smi->cpu_port), - 0); + err = rtl8366_reset_vlan(smi); + if (err) + return err; + + for (port = 0; port < smi->num_ports; port++) { + u32 mask; + + if (port == smi->cpu_port) + mask = (1 << smi->num_ports) - 1; + else + mask = (1 << port) | (1 << smi->cpu_port); + + err = rtl8366_set_vlan(smi, (port + 1), mask, mask, 0); if (err) return err; - err = rtl8366_set_pvid(smi, i, (i + 1)); + err = rtl8366_set_pvid(smi, port, (port + 1)); if (err) return err; } - return 0; + return rtl8366_enable_vlan(smi, 1); } -EXPORT_SYMBOL_GPL(rtl8366_reset_vlan); #ifdef CONFIG_RTL8366S_PHY_DEBUG_FS int rtl8366_debugfs_open(struct inode *inode, struct file *file) @@ -1131,27 +1183,89 @@ struct rtl8366_smi *rtl8366_smi_alloc(struct device *parent) } EXPORT_SYMBOL_GPL(rtl8366_smi_alloc); -int rtl8366_smi_init(struct rtl8366_smi *smi) +static int __rtl8366_smi_init(struct rtl8366_smi *smi, const char *name) { int err; - if (!smi->ops) - return -EINVAL; - - err = gpio_request(smi->gpio_sda, dev_name(smi->parent)); + err = gpio_request(smi->gpio_sda, name); if (err) { - dev_err(smi->parent, "gpio_request failed for %u, err=%d\n", + printk(KERN_ERR "rtl8366_smi: gpio_request failed for %u, err=%d\n", smi->gpio_sda, err); goto err_out; } - err = gpio_request(smi->gpio_sck, dev_name(smi->parent)); + err = gpio_request(smi->gpio_sck, name); if (err) { - dev_err(smi->parent, "gpio_request failed for %u, err=%d\n", + printk(KERN_ERR "rtl8366_smi: gpio_request failed for %u, err=%d\n", smi->gpio_sck, err); goto err_free_sda; } + spin_lock_init(&smi->lock); + return 0; + + err_free_sda: + gpio_free(smi->gpio_sda); + err_out: + return err; +} + +static void __rtl8366_smi_cleanup(struct rtl8366_smi *smi) +{ + gpio_free(smi->gpio_sck); + gpio_free(smi->gpio_sda); +} + +enum rtl8366_type rtl8366_smi_detect(struct rtl8366_platform_data *pdata) +{ + static struct rtl8366_smi smi; + enum rtl8366_type type = RTL8366_TYPE_UNKNOWN; + u32 reg = 0; + + memset(&smi, 0, sizeof(smi)); + smi.gpio_sda = pdata->gpio_sda; + smi.gpio_sck = pdata->gpio_sck; + smi.clk_delay = 10; + smi.cmd_read = 0xa9; + smi.cmd_write = 0xa8; + + if (__rtl8366_smi_init(&smi, "rtl8366")) + goto out; + + if (rtl8366_smi_read_reg(&smi, 0x5c, ®)) + goto cleanup; + + switch(reg) { + case 0x6027: + printk("Found an RTL8366S switch\n"); + type = RTL8366_TYPE_S; + break; + case 0x5937: + printk("Found an RTL8366RB switch\n"); + type = RTL8366_TYPE_RB; + break; + default: + printk("Found an Unknown RTL8366 switch (id=0x%04x)\n", reg); + break; + } + +cleanup: + __rtl8366_smi_cleanup(&smi); +out: + return type; +} + +int rtl8366_smi_init(struct rtl8366_smi *smi) +{ + int err; + + if (!smi->ops) + return -EINVAL; + + err = __rtl8366_smi_init(smi, dev_name(smi->parent)); + if (err) + goto err_out; + spin_lock_init(&smi->lock); dev_info(smi->parent, "using GPIO pins %u (SDA) and %u (SCK)\n", @@ -1169,6 +1283,17 @@ int rtl8366_smi_init(struct rtl8366_smi *smi) goto err_free_sck; } + err = rtl8366_init_vlan(smi); + if (err) { + dev_err(smi->parent, "VLAN initialization failed, err=%d\n", + err); + goto err_free_sck; + } + + err = rtl8366_enable_all_ports(smi, 1); + if (err) + goto err_free_sck; + err = rtl8366_smi_mii_init(smi); if (err) goto err_free_sck; @@ -1178,9 +1303,7 @@ int rtl8366_smi_init(struct rtl8366_smi *smi) return 0; err_free_sck: - gpio_free(smi->gpio_sck); - err_free_sda: - gpio_free(smi->gpio_sda); + __rtl8366_smi_cleanup(smi); err_out: return err; }