162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Atheros CARL9170 driver 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Basic HW register/memory/command access functions 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright 2008, Johannes Berg <johannes@sipsolutions.net> 762306a36Sopenharmony_ci * Copyright 2010, Christian Lamparter <chunkeey@googlemail.com> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 1062306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by 1162306a36Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 1262306a36Sopenharmony_ci * (at your option) any later version. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * This program is distributed in the hope that it will be useful, 1562306a36Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 1662306a36Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1762306a36Sopenharmony_ci * GNU General Public License for more details. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License 2062306a36Sopenharmony_ci * along with this program; see the file COPYING. If not, see 2162306a36Sopenharmony_ci * http://www.gnu.org/licenses/. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * This file incorporates work covered by the following copyright and 2462306a36Sopenharmony_ci * permission notice: 2562306a36Sopenharmony_ci * Copyright (c) 2007-2008 Atheros Communications, Inc. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 2862306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 2962306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 3262306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 3362306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 3462306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 3562306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 3662306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 3762306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_ci#ifndef __CMD_H 4062306a36Sopenharmony_ci#define __CMD_H 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#include "carl9170.h" 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* basic HW access */ 4562306a36Sopenharmony_ciint carl9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val); 4662306a36Sopenharmony_ciint carl9170_read_reg(struct ar9170 *ar, const u32 reg, u32 *val); 4762306a36Sopenharmony_ciint carl9170_read_mreg(struct ar9170 *ar, const int nregs, 4862306a36Sopenharmony_ci const u32 *regs, u32 *out); 4962306a36Sopenharmony_ciint carl9170_echo_test(struct ar9170 *ar, u32 v); 5062306a36Sopenharmony_ciint carl9170_reboot(struct ar9170 *ar); 5162306a36Sopenharmony_ciint carl9170_mac_reset(struct ar9170 *ar); 5262306a36Sopenharmony_ciint carl9170_powersave(struct ar9170 *ar, const bool power_on); 5362306a36Sopenharmony_ciint carl9170_collect_tally(struct ar9170 *ar); 5462306a36Sopenharmony_ciint carl9170_bcn_ctrl(struct ar9170 *ar, const unsigned int vif_id, 5562306a36Sopenharmony_ci const u32 mode, const u32 addr, const u32 len); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic inline int carl9170_flush_cab(struct ar9170 *ar, 5862306a36Sopenharmony_ci const unsigned int vif_id) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci return carl9170_bcn_ctrl(ar, vif_id, CARL9170_BCN_CTRL_DRAIN, 0, 0); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic inline int carl9170_rx_filter(struct ar9170 *ar, 6462306a36Sopenharmony_ci const unsigned int _rx_filter) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci __le32 rx_filter = cpu_to_le32(_rx_filter); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci return carl9170_exec_cmd(ar, CARL9170_CMD_RX_FILTER, 6962306a36Sopenharmony_ci sizeof(rx_filter), (u8 *)&rx_filter, 7062306a36Sopenharmony_ci 0, NULL); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistruct carl9170_cmd *carl9170_cmd_buf(struct ar9170 *ar, 7462306a36Sopenharmony_ci const enum carl9170_cmd_oids cmd, const unsigned int len); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* 7762306a36Sopenharmony_ci * Macros to facilitate writing multiple registers in a single 7862306a36Sopenharmony_ci * write-combining USB command. Note that when the first group 7962306a36Sopenharmony_ci * fails the whole thing will fail without any others attempted, 8062306a36Sopenharmony_ci * but you won't know which write in the group failed. 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_ci#define carl9170_regwrite_begin(ar) \ 8362306a36Sopenharmony_cido { \ 8462306a36Sopenharmony_ci int __nreg = 0, __err = 0; \ 8562306a36Sopenharmony_ci struct ar9170 *__ar = ar; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#define carl9170_regwrite(r, v) do { \ 8862306a36Sopenharmony_ci __ar->cmd_buf[2 * __nreg + 1] = cpu_to_le32(r); \ 8962306a36Sopenharmony_ci __ar->cmd_buf[2 * __nreg + 2] = cpu_to_le32(v); \ 9062306a36Sopenharmony_ci __nreg++; \ 9162306a36Sopenharmony_ci if ((__nreg >= PAYLOAD_MAX / 2)) { \ 9262306a36Sopenharmony_ci if (IS_ACCEPTING_CMD(__ar)) \ 9362306a36Sopenharmony_ci __err = carl9170_exec_cmd(__ar, \ 9462306a36Sopenharmony_ci CARL9170_CMD_WREG, 8 * __nreg, \ 9562306a36Sopenharmony_ci (u8 *) &__ar->cmd_buf[1], 0, NULL); \ 9662306a36Sopenharmony_ci else \ 9762306a36Sopenharmony_ci goto __regwrite_out; \ 9862306a36Sopenharmony_ci \ 9962306a36Sopenharmony_ci __nreg = 0; \ 10062306a36Sopenharmony_ci if (__err) \ 10162306a36Sopenharmony_ci goto __regwrite_out; \ 10262306a36Sopenharmony_ci } \ 10362306a36Sopenharmony_ci} while (0) 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci#define carl9170_regwrite_finish() \ 10662306a36Sopenharmony_ci__regwrite_out : \ 10762306a36Sopenharmony_ci if (__err == 0 && __nreg) { \ 10862306a36Sopenharmony_ci if (IS_ACCEPTING_CMD(__ar)) \ 10962306a36Sopenharmony_ci __err = carl9170_exec_cmd(__ar, \ 11062306a36Sopenharmony_ci CARL9170_CMD_WREG, 8 * __nreg, \ 11162306a36Sopenharmony_ci (u8 *) &__ar->cmd_buf[1], 0, NULL); \ 11262306a36Sopenharmony_ci __nreg = 0; \ 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci#define carl9170_regwrite_result() \ 11662306a36Sopenharmony_ci __err; \ 11762306a36Sopenharmony_ci} while (0) 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci#define carl9170_async_regwrite_get_buf() \ 12162306a36Sopenharmony_cido { \ 12262306a36Sopenharmony_ci __nreg = 0; \ 12362306a36Sopenharmony_ci __cmd = carl9170_cmd_buf(__carl, CARL9170_CMD_WREG_ASYNC, \ 12462306a36Sopenharmony_ci CARL9170_MAX_CMD_PAYLOAD_LEN); \ 12562306a36Sopenharmony_ci if (__cmd == NULL) { \ 12662306a36Sopenharmony_ci __err = -ENOMEM; \ 12762306a36Sopenharmony_ci goto __async_regwrite_out; \ 12862306a36Sopenharmony_ci } \ 12962306a36Sopenharmony_ci} while (0) 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci#define carl9170_async_regwrite_begin(carl) \ 13262306a36Sopenharmony_cido { \ 13362306a36Sopenharmony_ci struct ar9170 *__carl = carl; \ 13462306a36Sopenharmony_ci struct carl9170_cmd *__cmd; \ 13562306a36Sopenharmony_ci unsigned int __nreg; \ 13662306a36Sopenharmony_ci int __err = 0; \ 13762306a36Sopenharmony_ci carl9170_async_regwrite_get_buf(); \ 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci#define carl9170_async_regwrite_flush() \ 14062306a36Sopenharmony_cido { \ 14162306a36Sopenharmony_ci if (__cmd == NULL || __nreg == 0) \ 14262306a36Sopenharmony_ci break; \ 14362306a36Sopenharmony_ci \ 14462306a36Sopenharmony_ci if (IS_ACCEPTING_CMD(__carl) && __nreg) { \ 14562306a36Sopenharmony_ci __cmd->hdr.len = 8 * __nreg; \ 14662306a36Sopenharmony_ci __err = __carl9170_exec_cmd(__carl, __cmd, true); \ 14762306a36Sopenharmony_ci __cmd = NULL; \ 14862306a36Sopenharmony_ci break; \ 14962306a36Sopenharmony_ci } \ 15062306a36Sopenharmony_ci goto __async_regwrite_out; \ 15162306a36Sopenharmony_ci} while (0) 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci#define carl9170_async_regwrite(r, v) do { \ 15462306a36Sopenharmony_ci if (__cmd == NULL) \ 15562306a36Sopenharmony_ci carl9170_async_regwrite_get_buf(); \ 15662306a36Sopenharmony_ci __cmd->wreg.regs[__nreg].addr = cpu_to_le32(r); \ 15762306a36Sopenharmony_ci __cmd->wreg.regs[__nreg].val = cpu_to_le32(v); \ 15862306a36Sopenharmony_ci __nreg++; \ 15962306a36Sopenharmony_ci if ((__nreg >= PAYLOAD_MAX / 2)) \ 16062306a36Sopenharmony_ci carl9170_async_regwrite_flush(); \ 16162306a36Sopenharmony_ci} while (0) 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci#define carl9170_async_regwrite_finish() do { \ 16462306a36Sopenharmony_ci__async_regwrite_out: \ 16562306a36Sopenharmony_ci if (__cmd != NULL && __err == 0) \ 16662306a36Sopenharmony_ci carl9170_async_regwrite_flush(); \ 16762306a36Sopenharmony_ci kfree(__cmd); \ 16862306a36Sopenharmony_ci} while (0) \ 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci#define carl9170_async_regwrite_result() \ 17162306a36Sopenharmony_ci __err; \ 17262306a36Sopenharmony_ci} while (0) 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci#endif /* __CMD_H */ 175