linux/drivers/net/wireless/ath/ath5k/ahb.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2008-2009 Atheros Communications Inc.
   3 * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
   4 * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
   5 *
   6 * Permission to use, copy, modify, and/or distribute this software for any
   7 * purpose with or without fee is hereby granted, provided that the above
   8 * copyright notice and this permission notice appear in all copies.
   9 *
  10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17 */
  18
  19#include <linux/module.h>
  20#include <linux/nl80211.h>
  21#include <linux/platform_device.h>
  22#include <linux/etherdevice.h>
  23#include <ath25_platform.h>
  24#include "ath5k.h"
  25#include "debug.h"
  26#include "base.h"
  27#include "reg.h"
  28
  29/* return bus cachesize in 4B word units */
  30static void ath5k_ahb_read_cachesize(struct ath_common *common, int *csz)
  31{
  32        *csz = L1_CACHE_BYTES >> 2;
  33}
  34
  35static bool
  36ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
  37{
  38        struct ath5k_hw *ah = common->priv;
  39        struct platform_device *pdev = to_platform_device(ah->dev);
  40        struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
  41        u16 *eeprom, *eeprom_end;
  42
  43        eeprom = (u16 *) bcfg->radio;
  44        eeprom_end = ((void *) bcfg->config) + BOARD_CONFIG_BUFSZ;
  45
  46        eeprom += off;
  47        if (eeprom > eeprom_end)
  48                return false;
  49
  50        *data = *eeprom;
  51        return true;
  52}
  53
  54int ath5k_hw_read_srev(struct ath5k_hw *ah)
  55{
  56        struct platform_device *pdev = to_platform_device(ah->dev);
  57        struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
  58        ah->ah_mac_srev = bcfg->devid;
  59        return 0;
  60}
  61
  62static int ath5k_ahb_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
  63{
  64        struct platform_device *pdev = to_platform_device(ah->dev);
  65        struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
  66        u8 *cfg_mac;
  67
  68        if (to_platform_device(ah->dev)->id == 0)
  69                cfg_mac = bcfg->config->wlan0_mac;
  70        else
  71                cfg_mac = bcfg->config->wlan1_mac;
  72
  73        memcpy(mac, cfg_mac, ETH_ALEN);
  74        return 0;
  75}
  76
  77static const struct ath_bus_ops ath_ahb_bus_ops = {
  78        .ath_bus_type = ATH_AHB,
  79        .read_cachesize = ath5k_ahb_read_cachesize,
  80        .eeprom_read = ath5k_ahb_eeprom_read,
  81        .eeprom_read_mac = ath5k_ahb_eeprom_read_mac,
  82};
  83
  84/*Initialization*/
  85static int ath_ahb_probe(struct platform_device *pdev)
  86{
  87        struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
  88        struct ath5k_hw *ah;
  89        struct ieee80211_hw *hw;
  90        struct resource *res;
  91        void __iomem *mem;
  92        int irq;
  93        int ret = 0;
  94        u32 reg;
  95
  96        if (!dev_get_platdata(&pdev->dev)) {
  97                dev_err(&pdev->dev, "no platform data specified\n");
  98                ret = -EINVAL;
  99                goto err_out;
 100        }
 101
 102        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 103        if (res == NULL) {
 104                dev_err(&pdev->dev, "no memory resource found\n");
 105                ret = -ENXIO;
 106                goto err_out;
 107        }
 108
 109        mem = ioremap_nocache(res->start, resource_size(res));
 110        if (mem == NULL) {
 111                dev_err(&pdev->dev, "ioremap failed\n");
 112                ret = -ENOMEM;
 113                goto err_out;
 114        }
 115
 116        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 117        if (res == NULL) {
 118                dev_err(&pdev->dev, "no IRQ resource found\n");
 119                ret = -ENXIO;
 120                goto err_iounmap;
 121        }
 122
 123        irq = res->start;
 124
 125        hw = ieee80211_alloc_hw(sizeof(struct ath5k_hw), &ath5k_hw_ops);
 126        if (hw == NULL) {
 127                dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
 128                ret = -ENOMEM;
 129                goto err_iounmap;
 130        }
 131
 132        ah = hw->priv;
 133        ah->hw = hw;
 134        ah->dev = &pdev->dev;
 135        ah->iobase = mem;
 136        ah->irq = irq;
 137        ah->devid = bcfg->devid;
 138
 139        if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
 140                /* Enable WMAC AHB arbitration */
 141                reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
 142                reg |= AR5K_AR2315_AHB_ARB_CTL_WLAN;
 143                iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
 144
 145                /* Enable global WMAC swapping */
 146                reg = ioread32((void __iomem *) AR5K_AR2315_BYTESWAP);
 147                reg |= AR5K_AR2315_BYTESWAP_WMAC;
 148                iowrite32(reg, (void __iomem *) AR5K_AR2315_BYTESWAP);
 149        } else {
 150                /* Enable WMAC DMA access (assuming 5312 or 231x*/
 151                /* TODO: check other platforms */
 152                reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE);
 153                if (to_platform_device(ah->dev)->id == 0)
 154                        reg |= AR5K_AR5312_ENABLE_WLAN0;
 155                else
 156                        reg |= AR5K_AR5312_ENABLE_WLAN1;
 157                iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE);
 158
 159                /*
 160                 * On a dual-band AR5312, the multiband radio is only
 161                 * used as pass-through. Disable 2 GHz support in the
 162                 * driver for it
 163                 */
 164                if (to_platform_device(ah->dev)->id == 0 &&
 165                    (bcfg->config->flags & (BD_WLAN0 | BD_WLAN1)) ==
 166                     (BD_WLAN1 | BD_WLAN0))
 167                        ah->ah_capabilities.cap_needs_2GHz_ovr = true;
 168                else
 169                        ah->ah_capabilities.cap_needs_2GHz_ovr = false;
 170        }
 171
 172        ret = ath5k_init_ah(ah, &ath_ahb_bus_ops);
 173        if (ret != 0) {
 174                dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret);
 175                ret = -ENODEV;
 176                goto err_free_hw;
 177        }
 178
 179        platform_set_drvdata(pdev, hw);
 180
 181        return 0;
 182
 183 err_free_hw:
 184        ieee80211_free_hw(hw);
 185 err_iounmap:
 186        iounmap(mem);
 187 err_out:
 188        return ret;
 189}
 190
 191static int ath_ahb_remove(struct platform_device *pdev)
 192{
 193        struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
 194        struct ieee80211_hw *hw = platform_get_drvdata(pdev);
 195        struct ath5k_hw *ah;
 196        u32 reg;
 197
 198        if (!hw)
 199                return 0;
 200
 201        ah = hw->priv;
 202
 203        if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
 204                /* Disable WMAC AHB arbitration */
 205                reg = ioread32((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
 206                reg &= ~AR5K_AR2315_AHB_ARB_CTL_WLAN;
 207                iowrite32(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
 208        } else {
 209                /*Stop DMA access */
 210                reg = ioread32((void __iomem *) AR5K_AR5312_ENABLE);
 211                if (to_platform_device(ah->dev)->id == 0)
 212                        reg &= ~AR5K_AR5312_ENABLE_WLAN0;
 213                else
 214                        reg &= ~AR5K_AR5312_ENABLE_WLAN1;
 215                iowrite32(reg, (void __iomem *) AR5K_AR5312_ENABLE);
 216        }
 217
 218        ath5k_deinit_ah(ah);
 219        iounmap(ah->iobase);
 220        ieee80211_free_hw(hw);
 221
 222        return 0;
 223}
 224
 225static struct platform_driver ath_ahb_driver = {
 226        .probe      = ath_ahb_probe,
 227        .remove     = ath_ahb_remove,
 228        .driver         = {
 229                .name   = "ar231x-wmac",
 230        },
 231};
 232
 233module_platform_driver(ath_ahb_driver);
 234