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