18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Atheros CARL9170 driver
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Basic HW register/memory/command access functions
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
78c2ecf20Sopenharmony_ci * Copyright 2010, Christian Lamparter <chunkeey@googlemail.com>
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
108c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by
118c2ecf20Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or
128c2ecf20Sopenharmony_ci * (at your option) any later version.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful,
158c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
168c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
178c2ecf20Sopenharmony_ci * GNU General Public License for more details.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * You should have received a copy of the GNU General Public License
208c2ecf20Sopenharmony_ci * along with this program; see the file COPYING.  If not, see
218c2ecf20Sopenharmony_ci * http://www.gnu.org/licenses/.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * This file incorporates work covered by the following copyright and
248c2ecf20Sopenharmony_ci * permission notice:
258c2ecf20Sopenharmony_ci *    Copyright (c) 2007-2008 Atheros Communications, Inc.
268c2ecf20Sopenharmony_ci *
278c2ecf20Sopenharmony_ci *    Permission to use, copy, modify, and/or distribute this software for any
288c2ecf20Sopenharmony_ci *    purpose with or without fee is hereby granted, provided that the above
298c2ecf20Sopenharmony_ci *    copyright notice and this permission notice appear in all copies.
308c2ecf20Sopenharmony_ci *
318c2ecf20Sopenharmony_ci *    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
328c2ecf20Sopenharmony_ci *    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
338c2ecf20Sopenharmony_ci *    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
348c2ecf20Sopenharmony_ci *    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
358c2ecf20Sopenharmony_ci *    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
368c2ecf20Sopenharmony_ci *    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
378c2ecf20Sopenharmony_ci *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
388c2ecf20Sopenharmony_ci */
398c2ecf20Sopenharmony_ci#ifndef __CMD_H
408c2ecf20Sopenharmony_ci#define __CMD_H
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#include "carl9170.h"
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/* basic HW access */
458c2ecf20Sopenharmony_ciint carl9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val);
468c2ecf20Sopenharmony_ciint carl9170_read_reg(struct ar9170 *ar, const u32 reg, u32 *val);
478c2ecf20Sopenharmony_ciint carl9170_read_mreg(struct ar9170 *ar, const int nregs,
488c2ecf20Sopenharmony_ci		       const u32 *regs, u32 *out);
498c2ecf20Sopenharmony_ciint carl9170_echo_test(struct ar9170 *ar, u32 v);
508c2ecf20Sopenharmony_ciint carl9170_reboot(struct ar9170 *ar);
518c2ecf20Sopenharmony_ciint carl9170_mac_reset(struct ar9170 *ar);
528c2ecf20Sopenharmony_ciint carl9170_powersave(struct ar9170 *ar, const bool power_on);
538c2ecf20Sopenharmony_ciint carl9170_collect_tally(struct ar9170 *ar);
548c2ecf20Sopenharmony_ciint carl9170_bcn_ctrl(struct ar9170 *ar, const unsigned int vif_id,
558c2ecf20Sopenharmony_ci		       const u32 mode, const u32 addr, const u32 len);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic inline int carl9170_flush_cab(struct ar9170 *ar,
588c2ecf20Sopenharmony_ci				     const unsigned int vif_id)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	return carl9170_bcn_ctrl(ar, vif_id, CARL9170_BCN_CTRL_DRAIN, 0, 0);
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic inline int carl9170_rx_filter(struct ar9170 *ar,
648c2ecf20Sopenharmony_ci				     const unsigned int _rx_filter)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	__le32 rx_filter = cpu_to_le32(_rx_filter);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	return carl9170_exec_cmd(ar, CARL9170_CMD_RX_FILTER,
698c2ecf20Sopenharmony_ci				sizeof(rx_filter), (u8 *)&rx_filter,
708c2ecf20Sopenharmony_ci				0, NULL);
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistruct carl9170_cmd *carl9170_cmd_buf(struct ar9170 *ar,
748c2ecf20Sopenharmony_ci	const enum carl9170_cmd_oids cmd, const unsigned int len);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci/*
778c2ecf20Sopenharmony_ci * Macros to facilitate writing multiple registers in a single
788c2ecf20Sopenharmony_ci * write-combining USB command. Note that when the first group
798c2ecf20Sopenharmony_ci * fails the whole thing will fail without any others attempted,
808c2ecf20Sopenharmony_ci * but you won't know which write in the group failed.
818c2ecf20Sopenharmony_ci */
828c2ecf20Sopenharmony_ci#define carl9170_regwrite_begin(ar)					\
838c2ecf20Sopenharmony_cido {									\
848c2ecf20Sopenharmony_ci	int __nreg = 0, __err = 0;					\
858c2ecf20Sopenharmony_ci	struct ar9170 *__ar = ar;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci#define carl9170_regwrite(r, v) do {					\
888c2ecf20Sopenharmony_ci	__ar->cmd_buf[2 * __nreg + 1] = cpu_to_le32(r);			\
898c2ecf20Sopenharmony_ci	__ar->cmd_buf[2 * __nreg + 2] = cpu_to_le32(v);			\
908c2ecf20Sopenharmony_ci	__nreg++;							\
918c2ecf20Sopenharmony_ci	if ((__nreg >= PAYLOAD_MAX / 2)) {				\
928c2ecf20Sopenharmony_ci		if (IS_ACCEPTING_CMD(__ar))				\
938c2ecf20Sopenharmony_ci			__err = carl9170_exec_cmd(__ar,			\
948c2ecf20Sopenharmony_ci				CARL9170_CMD_WREG, 8 * __nreg,		\
958c2ecf20Sopenharmony_ci				(u8 *) &__ar->cmd_buf[1], 0, NULL);	\
968c2ecf20Sopenharmony_ci		else							\
978c2ecf20Sopenharmony_ci			goto __regwrite_out;				\
988c2ecf20Sopenharmony_ci									\
998c2ecf20Sopenharmony_ci		__nreg = 0;						\
1008c2ecf20Sopenharmony_ci		if (__err)						\
1018c2ecf20Sopenharmony_ci			goto __regwrite_out;				\
1028c2ecf20Sopenharmony_ci	}								\
1038c2ecf20Sopenharmony_ci} while (0)
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci#define carl9170_regwrite_finish()					\
1068c2ecf20Sopenharmony_ci__regwrite_out :							\
1078c2ecf20Sopenharmony_ci	if (__err == 0 && __nreg) {					\
1088c2ecf20Sopenharmony_ci		if (IS_ACCEPTING_CMD(__ar))				\
1098c2ecf20Sopenharmony_ci			__err = carl9170_exec_cmd(__ar,			\
1108c2ecf20Sopenharmony_ci				CARL9170_CMD_WREG, 8 * __nreg,		\
1118c2ecf20Sopenharmony_ci				(u8 *) &__ar->cmd_buf[1], 0, NULL);	\
1128c2ecf20Sopenharmony_ci		__nreg = 0;						\
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci#define carl9170_regwrite_result()					\
1168c2ecf20Sopenharmony_ci	__err;								\
1178c2ecf20Sopenharmony_ci} while (0)
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci#define carl9170_async_regwrite_get_buf()				\
1218c2ecf20Sopenharmony_cido {									\
1228c2ecf20Sopenharmony_ci	__nreg = 0;							\
1238c2ecf20Sopenharmony_ci	__cmd = carl9170_cmd_buf(__carl, CARL9170_CMD_WREG_ASYNC,	\
1248c2ecf20Sopenharmony_ci				 CARL9170_MAX_CMD_PAYLOAD_LEN);		\
1258c2ecf20Sopenharmony_ci	if (__cmd == NULL) {						\
1268c2ecf20Sopenharmony_ci		__err = -ENOMEM;					\
1278c2ecf20Sopenharmony_ci		goto __async_regwrite_out;				\
1288c2ecf20Sopenharmony_ci	}								\
1298c2ecf20Sopenharmony_ci} while (0)
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci#define carl9170_async_regwrite_begin(carl)				\
1328c2ecf20Sopenharmony_cido {									\
1338c2ecf20Sopenharmony_ci	struct ar9170 *__carl = carl;					\
1348c2ecf20Sopenharmony_ci	struct carl9170_cmd *__cmd;					\
1358c2ecf20Sopenharmony_ci	unsigned int __nreg;						\
1368c2ecf20Sopenharmony_ci	int  __err = 0;							\
1378c2ecf20Sopenharmony_ci	carl9170_async_regwrite_get_buf();				\
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci#define carl9170_async_regwrite_flush()					\
1408c2ecf20Sopenharmony_cido {									\
1418c2ecf20Sopenharmony_ci	if (__cmd == NULL || __nreg == 0)				\
1428c2ecf20Sopenharmony_ci		break;							\
1438c2ecf20Sopenharmony_ci									\
1448c2ecf20Sopenharmony_ci	if (IS_ACCEPTING_CMD(__carl) && __nreg) {			\
1458c2ecf20Sopenharmony_ci		__cmd->hdr.len = 8 * __nreg;				\
1468c2ecf20Sopenharmony_ci		__err = __carl9170_exec_cmd(__carl, __cmd, true);	\
1478c2ecf20Sopenharmony_ci		__cmd = NULL;						\
1488c2ecf20Sopenharmony_ci		break;							\
1498c2ecf20Sopenharmony_ci	}								\
1508c2ecf20Sopenharmony_ci	goto __async_regwrite_out;					\
1518c2ecf20Sopenharmony_ci} while (0)
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci#define carl9170_async_regwrite(r, v) do {				\
1548c2ecf20Sopenharmony_ci	if (__cmd == NULL)						\
1558c2ecf20Sopenharmony_ci		carl9170_async_regwrite_get_buf();			\
1568c2ecf20Sopenharmony_ci	__cmd->wreg.regs[__nreg].addr = cpu_to_le32(r);			\
1578c2ecf20Sopenharmony_ci	__cmd->wreg.regs[__nreg].val = cpu_to_le32(v);			\
1588c2ecf20Sopenharmony_ci	__nreg++;							\
1598c2ecf20Sopenharmony_ci	if ((__nreg >= PAYLOAD_MAX / 2))				\
1608c2ecf20Sopenharmony_ci		carl9170_async_regwrite_flush();			\
1618c2ecf20Sopenharmony_ci} while (0)
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci#define carl9170_async_regwrite_finish() do {				\
1648c2ecf20Sopenharmony_ci__async_regwrite_out:							\
1658c2ecf20Sopenharmony_ci	if (__cmd != NULL && __err == 0)				\
1668c2ecf20Sopenharmony_ci		carl9170_async_regwrite_flush();			\
1678c2ecf20Sopenharmony_ci	kfree(__cmd);							\
1688c2ecf20Sopenharmony_ci} while (0)								\
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci#define carl9170_async_regwrite_result()				\
1718c2ecf20Sopenharmony_ci	__err;								\
1728c2ecf20Sopenharmony_ci} while (0)
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci#endif /* __CMD_H */
175