Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2008-2009 Atheros Communications Inc.
0003  * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
0004  * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
0005  *
0006  * Permission to use, copy, modify, and/or distribute this software for any
0007  * purpose with or without fee is hereby granted, provided that the above
0008  * copyright notice and this permission notice appear in all copies.
0009  *
0010  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0011  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0012  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0013  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0014  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0015  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0016  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0017  */
0018 
0019 #include <linux/module.h>
0020 #include <linux/nl80211.h>
0021 #include <linux/platform_device.h>
0022 #include <linux/etherdevice.h>
0023 #include <ath25_platform.h>
0024 #include "ath5k.h"
0025 #include "debug.h"
0026 #include "base.h"
0027 #include "reg.h"
0028 
0029 /* return bus cachesize in 4B word units */
0030 static void ath5k_ahb_read_cachesize(struct ath_common *common, int *csz)
0031 {
0032     *csz = L1_CACHE_BYTES >> 2;
0033 }
0034 
0035 static bool
0036 ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
0037 {
0038     struct ath5k_hw *ah = common->priv;
0039     struct platform_device *pdev = to_platform_device(ah->dev);
0040     struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
0041     u16 *eeprom, *eeprom_end;
0042 
0043     eeprom = (u16 *) bcfg->radio;
0044     eeprom_end = ((void *) bcfg->config) + BOARD_CONFIG_BUFSZ;
0045 
0046     eeprom += off;
0047     if (eeprom > eeprom_end)
0048         return false;
0049 
0050     *data = *eeprom;
0051     return true;
0052 }
0053 
0054 int ath5k_hw_read_srev(struct ath5k_hw *ah)
0055 {
0056     struct platform_device *pdev = to_platform_device(ah->dev);
0057     struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
0058     ah->ah_mac_srev = bcfg->devid;
0059     return 0;
0060 }
0061 
0062 static int ath5k_ahb_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
0063 {
0064     struct platform_device *pdev = to_platform_device(ah->dev);
0065     struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
0066     u8 *cfg_mac;
0067 
0068     if (to_platform_device(ah->dev)->id == 0)
0069         cfg_mac = bcfg->config->wlan0_mac;
0070     else
0071         cfg_mac = bcfg->config->wlan1_mac;
0072 
0073     memcpy(mac, cfg_mac, ETH_ALEN);
0074     return 0;
0075 }
0076 
0077 static const struct ath_bus_ops ath_ahb_bus_ops = {
0078     .ath_bus_type = ATH_AHB,
0079     .read_cachesize = ath5k_ahb_read_cachesize,
0080     .eeprom_read = ath5k_ahb_eeprom_read,
0081     .eeprom_read_mac = ath5k_ahb_eeprom_read_mac,
0082 };
0083 
0084 /*Initialization*/
0085 static int ath_ahb_probe(struct platform_device *pdev)
0086 {
0087     struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
0088     struct ath5k_hw *ah;
0089     struct ieee80211_hw *hw;
0090     struct resource *res;
0091     void __iomem *mem;
0092     int irq;
0093     int ret = 0;
0094     u32 reg;
0095 
0096     if (!dev_get_platdata(&pdev->dev)) {
0097         dev_err(&pdev->dev, "no platform data specified\n");
0098         ret = -EINVAL;
0099         goto err_out;
0100     }
0101 
0102     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0103     if (res == NULL) {
0104         dev_err(&pdev->dev, "no memory resource found\n");
0105         ret = -ENXIO;
0106         goto err_out;
0107     }
0108 
0109     mem = ioremap(res->start, resource_size(res));
0110     if (mem == NULL) {
0111         dev_err(&pdev->dev, "ioremap failed\n");
0112         ret = -ENOMEM;
0113         goto err_out;
0114     }
0115 
0116     res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
0117     if (res == NULL) {
0118         dev_err(&pdev->dev, "no IRQ resource found\n");
0119         ret = -ENXIO;
0120         goto err_iounmap;
0121     }
0122 
0123     irq = res->start;
0124 
0125     hw = ieee80211_alloc_hw(sizeof(struct ath5k_hw), &ath5k_hw_ops);
0126     if (hw == NULL) {
0127         dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
0128         ret = -ENOMEM;
0129         goto err_iounmap;
0130     }
0131 
0132     ah = hw->priv;
0133     ah->hw = hw;
0134     ah->dev = &pdev->dev;
0135     ah->iobase = mem;
0136     ah->irq = irq;
0137     ah->devid = bcfg->devid;
0138 
0139     if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
0140         /* Enable WMAC AHB arbitration */
0141         reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
0142         reg |= AR5K_AR2315_AHB_ARB_CTL_WLAN;
0143         iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
0144 
0145         /* Enable global WMAC swapping */
0146         reg = ioread32((void __iomem *) AR5K_AR2315_BYTESWAP);
0147         reg |= AR5K_AR2315_BYTESWAP_WMAC;
0148         iowrite32(reg, (void __iomem *) AR5K_AR2315_BYTESWAP);
0149     } else {
0150         /* Enable WMAC DMA access (assuming 5312 or 231x*/
0151         /* TODO: check other platforms */
0152         reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE);
0153         if (to_platform_device(ah->dev)->id == 0)
0154             reg |= AR5K_AR5312_ENABLE_WLAN0;
0155         else
0156             reg |= AR5K_AR5312_ENABLE_WLAN1;
0157         iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE);
0158 
0159         /*
0160          * On a dual-band AR5312, the multiband radio is only
0161          * used as pass-through. Disable 2 GHz support in the
0162          * driver for it
0163          */
0164         if (to_platform_device(ah->dev)->id == 0 &&
0165             (bcfg->config->flags & (BD_WLAN0 | BD_WLAN1)) ==
0166              (BD_WLAN1 | BD_WLAN0))
0167             ah->ah_capabilities.cap_needs_2GHz_ovr = true;
0168         else
0169             ah->ah_capabilities.cap_needs_2GHz_ovr = false;
0170     }
0171 
0172     ret = ath5k_init_ah(ah, &ath_ahb_bus_ops);
0173     if (ret != 0) {
0174         dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret);
0175         ret = -ENODEV;
0176         goto err_free_hw;
0177     }
0178 
0179     platform_set_drvdata(pdev, hw);
0180 
0181     return 0;
0182 
0183  err_free_hw:
0184     ieee80211_free_hw(hw);
0185  err_iounmap:
0186         iounmap(mem);
0187  err_out:
0188     return ret;
0189 }
0190 
0191 static int ath_ahb_remove(struct platform_device *pdev)
0192 {
0193     struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
0194     struct ieee80211_hw *hw = platform_get_drvdata(pdev);
0195     struct ath5k_hw *ah;
0196     u32 reg;
0197 
0198     if (!hw)
0199         return 0;
0200 
0201     ah = hw->priv;
0202 
0203     if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
0204         /* Disable WMAC AHB arbitration */
0205         reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
0206         reg &= ~AR5K_AR2315_AHB_ARB_CTL_WLAN;
0207         iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
0208     } else {
0209         /*Stop DMA access */
0210         reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE);
0211         if (to_platform_device(ah->dev)->id == 0)
0212             reg &= ~AR5K_AR5312_ENABLE_WLAN0;
0213         else
0214             reg &= ~AR5K_AR5312_ENABLE_WLAN1;
0215         iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE);
0216     }
0217 
0218     ath5k_deinit_ah(ah);
0219     iounmap(ah->iobase);
0220     ieee80211_free_hw(hw);
0221 
0222     return 0;
0223 }
0224 
0225 static struct platform_driver ath_ahb_driver = {
0226     .probe      = ath_ahb_probe,
0227     .remove     = ath_ahb_remove,
0228     .driver     = {
0229         .name   = "ar231x-wmac",
0230     },
0231 };
0232 
0233 module_platform_driver(ath_ahb_driver);