OpenWrt – Rev 1

Subversion Repositories:
Rev:
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -20,7 +20,15 @@
 #include <linux/platform_device.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
+#include <linux/of_device.h>
 #include "ath9k.h"
+#include <linux/ath9k_platform.h>
+
+#ifdef CONFIG_OF
+#include <asm/mach-ath79/ath79.h>
+#include <asm/mach-ath79/ar71xx_regs.h>
+#include <linux/mtd/mtd.h>
+#endif
 
 static const struct platform_device_id ath9k_platform_id_table[] = {
        {
@@ -69,6 +77,235 @@ static const struct ath_bus_ops ath_ahb_
        .eeprom_read = ath_ahb_eeprom_read,
 };
 
+#ifdef CONFIG_OF
+
+#define QCA955X_DDR_CTL_CONFIG          0x108
+#define QCA955X_DDR_CTL_CONFIG_ACT_WMAC BIT(23)
+
+static int of_get_wifi_cal(struct device_node *np, struct ath9k_platform_data *pdata)
+{
+#ifdef CONFIG_MTD
+       struct device_node *mtd_np = NULL;
+       size_t retlen;
+       int size, ret;
+       struct mtd_info *mtd;
+       const char *part;
+       const __be32 *list;
+       phandle phandle;
+
+       list = of_get_property(np, "mtd-cal-data", &size);
+       if (!list)
+               return 0;
+
+       if (size != (2 * sizeof(*list)))
+               return 1;
+
+       phandle = be32_to_cpup(list++);
+       if (phandle)
+               mtd_np = of_find_node_by_phandle(phandle);
+
+       if (!mtd_np)
+               return 1;
+
+       part = of_get_property(mtd_np, "label", NULL);
+       if (!part)
+               part = mtd_np->name;
+
+       mtd = get_mtd_device_nm(part);
+       if (IS_ERR(mtd))
+               return 1;
+
+       ret = mtd_read(mtd, be32_to_cpup(list), sizeof(pdata->eeprom_data),
+                       &retlen, (u8*)pdata->eeprom_data);
+       put_mtd_device(mtd);
+
+#endif
+       return 0;
+}
+
+static int ar913x_wmac_reset(void)
+{
+       ath79_device_reset_set(AR913X_RESET_AMBA2WMAC);
+       mdelay(10);
+
+       ath79_device_reset_clear(AR913X_RESET_AMBA2WMAC);
+       mdelay(10);
+
+       return 0;
+}
+
+static int ar933x_wmac_reset(void)
+{
+       int retries = 20;
+
+       ath79_device_reset_set(AR933X_RESET_WMAC);
+       ath79_device_reset_clear(AR933X_RESET_WMAC);
+
+       while (1) {
+               u32 bootstrap;
+
+               bootstrap = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP);
+               if ((bootstrap & AR933X_BOOTSTRAP_EEPBUSY) == 0)
+                       return 0;
+
+               if (retries-- == 0)
+                       break;
+
+               udelay(10000);
+       }
+
+       pr_err("ar933x: WMAC reset timed out");
+       return -ETIMEDOUT;
+}
+
+static int qca955x_wmac_reset(void)
+{
+       int i;
+
+       /* Try to wait for WMAC DDR activity to stop */
+       for (i = 0; i < 10; i++) {
+               if (!(__raw_readl(ath79_ddr_base + QCA955X_DDR_CTL_CONFIG) &
+                   QCA955X_DDR_CTL_CONFIG_ACT_WMAC))
+                       break;
+
+               udelay(10);
+       }
+
+       ath79_device_reset_set(QCA955X_RESET_RTC);
+       udelay(10);
+       ath79_device_reset_clear(QCA955X_RESET_RTC);
+       udelay(10);
+
+       return 0;
+}
+
+enum {
+       AR913X_WMAC = 0,
+       AR933X_WMAC,
+       AR934X_WMAC,
+       QCA953X_WMAC,
+       QCA955X_WMAC,
+       QCA956X_WMAC,
+};
+
+static int ar9330_get_soc_revision(void)
+{
+       if (ath79_soc_rev == 1)
+               return ath79_soc_rev;
+
+       return 0;
+}
+
+static int ath79_get_soc_revision(void)
+{
+       return ath79_soc_rev;
+}
+
+static const struct of_ath_ahb_data {
+       u16 dev_id;
+       u32 bootstrap_reg;
+       u32 bootstrap_ref;
+
+       int (*soc_revision)(void);
+       int (*wmac_reset)(void);
+} of_ath_ahb_data[] = {
+       [AR913X_WMAC] = {
+               .dev_id = AR5416_AR9100_DEVID,
+               .wmac_reset = ar913x_wmac_reset,
+
+       },
+       [AR933X_WMAC] = {
+               .dev_id = AR9300_DEVID_AR9330,
+               .bootstrap_reg = AR933X_RESET_REG_BOOTSTRAP,
+               .bootstrap_ref = AR933X_BOOTSTRAP_REF_CLK_40,
+               .soc_revision = ar9330_get_soc_revision,
+               .wmac_reset = ar933x_wmac_reset,
+       },
+       [AR934X_WMAC] = {
+               .dev_id = AR9300_DEVID_AR9340,
+               .bootstrap_reg = AR934X_RESET_REG_BOOTSTRAP,
+               .bootstrap_ref = AR934X_BOOTSTRAP_REF_CLK_40,
+               .soc_revision = ath79_get_soc_revision,
+       },
+       [QCA953X_WMAC] = {
+               .dev_id = AR9300_DEVID_AR953X,
+               .bootstrap_reg = QCA953X_RESET_REG_BOOTSTRAP,
+               .bootstrap_ref = QCA953X_BOOTSTRAP_REF_CLK_40,
+               .soc_revision = ath79_get_soc_revision,
+       },
+       [QCA955X_WMAC] = {
+               .dev_id = AR9300_DEVID_QCA955X,
+               .bootstrap_reg = QCA955X_RESET_REG_BOOTSTRAP,
+               .bootstrap_ref = QCA955X_BOOTSTRAP_REF_CLK_40,
+               .wmac_reset = qca955x_wmac_reset,
+       },
+       [QCA956X_WMAC] = {
+               .dev_id = AR9300_DEVID_QCA956X,
+               .bootstrap_reg = QCA956X_RESET_REG_BOOTSTRAP,
+               .bootstrap_ref = QCA956X_BOOTSTRAP_REF_CLK_40,
+               .soc_revision = ath79_get_soc_revision,
+       },
+};
+
+const struct of_device_id of_ath_ahb_match[] = {
+       { .compatible = "qca,ar9130-wmac", .data = &of_ath_ahb_data[AR913X_WMAC] },
+       { .compatible = "qca,ar9330-wmac", .data = &of_ath_ahb_data[AR933X_WMAC] },
+       { .compatible = "qca,ar9340-wmac", .data = &of_ath_ahb_data[AR934X_WMAC] },
+       { .compatible = "qca,qca9530-wmac", .data = &of_ath_ahb_data[QCA953X_WMAC] },
+       { .compatible = "qca,qca9550-wmac", .data = &of_ath_ahb_data[QCA955X_WMAC] },
+       { .compatible = "qca,qca9560-wmac", .data = &of_ath_ahb_data[QCA956X_WMAC] },
+       {},
+};
+MODULE_DEVICE_TABLE(of, of_ath_ahb_match);
+
+static int of_ath_ahb_probe(struct platform_device *pdev)
+{
+       struct ath9k_platform_data *pdata;
+       const struct of_device_id *match;
+       const struct of_ath_ahb_data *data;
+       u8 led_pin;
+
+       match = of_match_device(of_ath_ahb_match, &pdev->dev);
+       data = (const struct of_ath_ahb_data *)match->data;
+
+       pdata = dev_get_platdata(&pdev->dev);
+
+       if (!of_property_read_u8(pdev->dev.of_node, "qca,led-pin", &led_pin))
+               pdata->led_pin = led_pin;
+       else
+               pdata->led_pin = -1;
+
+       if (of_property_read_bool(pdev->dev.of_node, "qca,disable-2ghz"))
+               pdata->disable_2ghz = true;
+
+       if (of_property_read_bool(pdev->dev.of_node, "qca,disable-5ghz"))
+               pdata->disable_5ghz = true;
+
+       if (of_property_read_bool(pdev->dev.of_node, "qca,tx-gain-buffalo"))
+               pdata->tx_gain_buffalo = true;
+
+       if (data->wmac_reset) {
+               data->wmac_reset();
+               pdata->external_reset = data->wmac_reset;
+       }
+
+       if (data->bootstrap_reg && data->bootstrap_ref) {
+               u32 t = ath79_reset_rr(data->bootstrap_reg);
+               if (t & data->bootstrap_ref)
+                       pdata->is_clk_25mhz = false;
+               else
+                       pdata->is_clk_25mhz = true;
+       }
+
+       pdata->get_mac_revision = data->soc_revision;
+
+       if (of_get_wifi_cal(pdev->dev.of_node, pdata))
+               dev_err(&pdev->dev, "failed to load calibration data from mtd device\n");
+
+       return data->dev_id;
+}
+#endif
+
 static int ath_ahb_probe(struct platform_device *pdev)
 {
        void __iomem *mem;
@@ -80,6 +317,17 @@ static int ath_ahb_probe(struct platform
        int ret = 0;
        struct ath_hw *ah;
        char hw_name[64];
+       u16 dev_id;
+
+       if (id)
+               dev_id = id->driver_data;
+
+#ifdef CONFIG_OF
+       if (pdev->dev.of_node)
+               pdev->dev.platform_data = devm_kzalloc(&pdev->dev,
+                                       sizeof(struct ath9k_platform_data),
+                                       GFP_KERNEL);
+#endif
 
        if (!dev_get_platdata(&pdev->dev)) {
                dev_err(&pdev->dev, "no platform data specified\n");
@@ -122,13 +370,16 @@ static int ath_ahb_probe(struct platform
        sc->mem = mem;
        sc->irq = irq;
 
+#ifdef CONFIG_OF
+       dev_id = of_ath_ahb_probe(pdev);
+#endif
        ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc);
        if (ret) {
                dev_err(&pdev->dev, "request_irq failed\n");
                goto err_free_hw;
        }
 
-       ret = ath9k_init_device(id->driver_data, sc, &ath_ahb_bus_ops);
+       ret = ath9k_init_device(dev_id, sc, &ath_ahb_bus_ops);
        if (ret) {
                dev_err(&pdev->dev, "failed to initialize device\n");
                goto err_irq;
@@ -159,6 +410,9 @@ static int ath_ahb_remove(struct platfor
                free_irq(sc->irq, sc);
                ieee80211_free_hw(sc->hw);
        }
+#ifdef CONFIG_OF
+       pdev->dev.platform_data = NULL;
+#endif
 
        return 0;
 }
@@ -168,6 +422,9 @@ static struct platform_driver ath_ahb_dr
        .remove     = ath_ahb_remove,
        .driver         = {
                .name   = "ath9k",
+#ifdef CONFIG_OF
+               .of_match_table = of_ath_ahb_match,
+#endif
        },
        .id_table    = ath9k_platform_id_table,
 };
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -25,6 +25,7 @@
 #include <linux/time.h>
 #include <linux/hw_random.h>
 #include <linux/gpio/driver.h>
+#include <linux/reset.h>
 
 #include "common.h"
 #include "debug.h"
@@ -1023,6 +1024,9 @@ struct ath_softc {
        struct ath_hw *sc_ah;
        void __iomem *mem;
        int irq;
+#ifdef CONFIG_OF
+       struct reset_control *reset;
+#endif
        spinlock_t sc_serial_rw;
        spinlock_t sc_pm_lock;
        spinlock_t sc_pcu_lock;