/* Copyright (C) 2009 Bartlomiej Zolnierkiewicz Based on the original rt2800pci.c and rt2800usb.c: Copyright (C) 2004 - 2009 rt2x00 SourceForge Project This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Module: rt2800lib Abstract: rt2800 generic device routines. */ #include #include #include "rt2x00.h" #include "rt2800lib.h" #include "rt2800.h" MODULE_AUTHOR("Bartlomiej Zolnierkiewicz"); MODULE_DESCRIPTION("rt2800 library"); MODULE_LICENSE("GPL"); /* * Register access. * All access to the CSR registers will go through the methods * rt2800_register_read and rt2800_register_write. * BBP and RF register require indirect register access, * and use the CSR registers BBPCSR and RFCSR to achieve this. * These indirect registers work with busy bits, * and we will try maximal REGISTER_BUSY_COUNT times to access * the register while taking a REGISTER_BUSY_DELAY us delay * between each attampt. When the busy bit is still set at that time, * the access attempt is considered to have failed, * and we will print an error. * The _lock versions must be used if you already hold the csr_mutex */ #define WAIT_FOR_BBP(__dev, __reg) \ rt2800_regbusy_read((__dev), BBP_CSR_CFG, BBP_CSR_CFG_BUSY, (__reg)) #define WAIT_FOR_RFCSR(__dev, __reg) \ rt2800_regbusy_read((__dev), RF_CSR_CFG, RF_CSR_CFG_BUSY, (__reg)) #define WAIT_FOR_RF(__dev, __reg) \ rt2800_regbusy_read((__dev), RF_CSR_CFG0, RF_CSR_CFG0_BUSY, (__reg)) #define WAIT_FOR_MCU(__dev, __reg) \ rt2800_regbusy_read((__dev), H2M_MAILBOX_CSR, \ H2M_MAILBOX_CSR_OWNER, (__reg)) void rt2800_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { u32 reg; mutex_lock(&rt2x00dev->csr_mutex); /* * Wait until the BBP becomes available, afterwards we * can safely write the new data into the register. */ if (WAIT_FOR_BBP(rt2x00dev, ®)) { reg = 0; rt2x00_set_field32(®, BBP_CSR_CFG_VALUE, value); rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 0); if (rt2x00_intf_is_pci(rt2x00dev)) rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); } mutex_unlock(&rt2x00dev->csr_mutex); } EXPORT_SYMBOL_GPL(rt2800_bbp_write); void rt2800_bbp_read(struct rt2x00_dev *rt2x00dev, const unsigned int word, u8 *value) { u32 reg; mutex_lock(&rt2x00dev->csr_mutex); /* * Wait until the BBP becomes available, afterwards we * can safely write the read request into the register. * After the data has been written, we wait until hardware * returns the correct value, if at any time the register * doesn't become available in time, reg will be 0xffffffff * which means we return 0xff to the caller. */ if (WAIT_FOR_BBP(rt2x00dev, ®)) { reg = 0; rt2x00_set_field32(®, BBP_CSR_CFG_REGNUM, word); rt2x00_set_field32(®, BBP_CSR_CFG_BUSY, 1); rt2x00_set_field32(®, BBP_CSR_CFG_READ_CONTROL, 1); if (rt2x00_intf_is_pci(rt2x00dev)) rt2x00_set_field32(®, BBP_CSR_CFG_BBP_RW_MODE, 1); rt2800_register_write_lock(rt2x00dev, BBP_CSR_CFG, reg); WAIT_FOR_BBP(rt2x00dev, ®); } *value = rt2x00_get_field32(reg, BBP_CSR_CFG_VALUE); mutex_unlock(&rt2x00dev->csr_mutex); } EXPORT_SYMBOL_GPL(rt2800_bbp_read); void rt2800_rfcsr_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { u32 reg; mutex_lock(&rt2x00dev->csr_mutex); /* * Wait until the RFCSR becomes available, afterwards we * can safely write the new data into the register. */ if (WAIT_FOR_RFCSR(rt2x00dev, ®)) { reg = 0; rt2x00_set_field32(®, RF_CSR_CFG_DATA, value); rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 1); rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); } mutex_unlock(&rt2x00dev->csr_mutex); } EXPORT_SYMBOL_GPL(rt2800_rfcsr_write); void rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev, const unsigned int word, u8 *value) { u32 reg; mutex_lock(&rt2x00dev->csr_mutex); /* * Wait until the RFCSR becomes available, afterwards we * can safely write the read request into the register. * After the data has been written, we wait until hardware * returns the correct value, if at any time the register * doesn't become available in time, reg will be 0xffffffff * which means we return 0xff to the caller. */ if (WAIT_FOR_RFCSR(rt2x00dev, ®)) { reg = 0; rt2x00_set_field32(®, RF_CSR_CFG_REGNUM, word); rt2x00_set_field32(®, RF_CSR_CFG_WRITE, 0); rt2x00_set_field32(®, RF_CSR_CFG_BUSY, 1); rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG, reg); WAIT_FOR_RFCSR(rt2x00dev, ®); } *value = rt2x00_get_field32(reg, RF_CSR_CFG_DATA); mutex_unlock(&rt2x00dev->csr_mutex); } EXPORT_SYMBOL_GPL(rt2800_rfcsr_read); void rt2800_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u32 reg; mutex_lock(&rt2x00dev->csr_mutex); /* * Wait until the RF becomes available, afterwards we * can safely write the new data into the register. */ if (WAIT_FOR_RF(rt2x00dev, ®)) { reg = 0; rt2x00_set_field32(®, RF_CSR_CFG0_REG_VALUE_BW, value); rt2x00_set_field32(®, RF_CSR_CFG0_STANDBYMODE, 0); rt2x00_set_field32(®, RF_CSR_CFG0_SEL, 0); rt2x00_set_field32(®, RF_CSR_CFG0_BUSY, 1); rt2800_register_write_lock(rt2x00dev, RF_CSR_CFG0, reg); rt2x00_rf_write(rt2x00dev, word, value); } mutex_unlock(&rt2x00dev->csr_mutex); } EXPORT_SYMBOL_GPL(rt2800_rf_write); void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, const u8 command, const u8 token, const u8 arg0, const u8 arg1) { u32 reg; if (rt2x00_intf_is_pci(rt2x00dev)) { /* * RT2880 and RT3052 don't support MCU requests. */ if (rt2x00_rt(&rt2x00dev->chip, RT2880) || rt2x00_rt(&rt2x00dev->chip, RT3052)) return; } mutex_lock(&rt2x00dev->csr_mutex); /* * Wait until the MCU becomes available, afterwards we * can safely write the new data into the register. */ if (WAIT_FOR_MCU(rt2x00dev, ®)) { rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1); rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); rt2800_register_write_lock(rt2x00dev, H2M_MAILBOX_CSR, reg); reg = 0; rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); rt2800_register_write_lock(rt2x00dev, HOST_CMD_CSR, reg); } mutex_unlock(&rt2x00dev->csr_mutex); } EXPORT_SYMBOL_GPL(rt2800_mcu_request);