1/*
2 * Atheros CARL9170 driver
3 *
4 * Basic HW register/memory/command access functions
5 *
6 * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; see the file COPYING.  If not, see
20 * http://www.gnu.org/licenses/.
21 *
22 * This file incorporates work covered by the following copyright and
23 * permission notice:
24 *    Copyright (c) 2007-2008 Atheros Communications, Inc.
25 *
26 *    Permission to use, copy, modify, and/or distribute this software for any
27 *    purpose with or without fee is hereby granted, provided that the above
28 *    copyright notice and this permission notice appear in all copies.
29 *
30 *    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
31 *    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
32 *    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
33 *    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
34 *    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
35 *    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
36 *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
37 */
38
39#include <asm/div64.h>
40#include "carl9170.h"
41#include "cmd.h"
42
43int carl9170_write_reg(struct ar9170 *ar, const u32 reg, const u32 val)
44{
45	const __le32 buf[2] = {
46		cpu_to_le32(reg),
47		cpu_to_le32(val),
48	};
49	int err;
50
51	err = carl9170_exec_cmd(ar, CARL9170_CMD_WREG, sizeof(buf),
52				(u8 *) buf, 0, NULL);
53	if (err) {
54		if (net_ratelimit()) {
55			wiphy_err(ar->hw->wiphy, "writing reg %#x "
56				"(val %#x) failed (%d)\n", reg, val, err);
57		}
58	}
59	return err;
60}
61
62int carl9170_read_mreg(struct ar9170 *ar, const int nregs,
63		       const u32 *regs, u32 *out)
64{
65	int i, err;
66	__le32 *offs, *res;
67
68	/* abuse "out" for the register offsets, must be same length */
69	offs = (__le32 *)out;
70	for (i = 0; i < nregs; i++)
71		offs[i] = cpu_to_le32(regs[i]);
72
73	/* also use the same buffer for the input */
74	res = (__le32 *)out;
75
76	err = carl9170_exec_cmd(ar, CARL9170_CMD_RREG,
77				4 * nregs, (u8 *)offs,
78				4 * nregs, (u8 *)res);
79	if (err) {
80		if (net_ratelimit()) {
81			wiphy_err(ar->hw->wiphy, "reading regs failed (%d)\n",
82				  err);
83		}
84		return err;
85	}
86
87	/* convert result to cpu endian */
88	for (i = 0; i < nregs; i++)
89		out[i] = le32_to_cpu(res[i]);
90
91	return 0;
92}
93
94int carl9170_read_reg(struct ar9170 *ar, u32 reg, u32 *val)
95{
96	return carl9170_read_mreg(ar, 1, &reg, val);
97}
98
99int carl9170_echo_test(struct ar9170 *ar, const u32 v)
100{
101	u32 echores;
102	int err;
103
104	err = carl9170_exec_cmd(ar, CARL9170_CMD_ECHO,
105				4, (u8 *)&v,
106				4, (u8 *)&echores);
107	if (err)
108		return err;
109
110	if (v != echores) {
111		wiphy_info(ar->hw->wiphy, "wrong echo %x != %x", v, echores);
112		return -EINVAL;
113	}
114
115	return 0;
116}
117
118struct carl9170_cmd *carl9170_cmd_buf(struct ar9170 *ar,
119	const enum carl9170_cmd_oids cmd, const unsigned int len)
120{
121	struct carl9170_cmd *tmp;
122
123	tmp = kzalloc(sizeof(struct carl9170_cmd_head) + len, GFP_ATOMIC);
124	if (tmp) {
125		tmp->hdr.cmd = cmd;
126		tmp->hdr.len = len;
127	}
128
129	return tmp;
130}
131
132int carl9170_reboot(struct ar9170 *ar)
133{
134	struct carl9170_cmd *cmd;
135	int err;
136
137	cmd = carl9170_cmd_buf(ar, CARL9170_CMD_REBOOT_ASYNC, 0);
138	if (!cmd)
139		return -ENOMEM;
140
141	err = __carl9170_exec_cmd(ar, (struct carl9170_cmd *)cmd, true);
142	return err;
143}
144
145int carl9170_mac_reset(struct ar9170 *ar)
146{
147	return carl9170_exec_cmd(ar, CARL9170_CMD_SWRST,
148				 0, NULL, 0, NULL);
149}
150
151int carl9170_bcn_ctrl(struct ar9170 *ar, const unsigned int vif_id,
152		       const u32 mode, const u32 addr, const u32 len)
153{
154	struct carl9170_cmd *cmd;
155
156	cmd = carl9170_cmd_buf(ar, CARL9170_CMD_BCN_CTRL_ASYNC,
157			       sizeof(struct carl9170_bcn_ctrl_cmd));
158	if (!cmd)
159		return -ENOMEM;
160
161	cmd->bcn_ctrl.vif_id = cpu_to_le32(vif_id);
162	cmd->bcn_ctrl.mode = cpu_to_le32(mode);
163	cmd->bcn_ctrl.bcn_addr = cpu_to_le32(addr);
164	cmd->bcn_ctrl.bcn_len = cpu_to_le32(len);
165
166	return __carl9170_exec_cmd(ar, cmd, true);
167}
168
169int carl9170_collect_tally(struct ar9170 *ar)
170{
171	struct carl9170_tally_rsp tally;
172	struct survey_info *info;
173	unsigned int tick;
174	int err;
175
176	err = carl9170_exec_cmd(ar, CARL9170_CMD_TALLY, 0, NULL,
177				sizeof(tally), (u8 *)&tally);
178	if (err)
179		return err;
180
181	tick = le32_to_cpu(tally.tick);
182	if (tick) {
183		ar->tally.active += le32_to_cpu(tally.active) / tick;
184		ar->tally.cca += le32_to_cpu(tally.cca) / tick;
185		ar->tally.tx_time += le32_to_cpu(tally.tx_time) / tick;
186		ar->tally.rx_total += le32_to_cpu(tally.rx_total);
187		ar->tally.rx_overrun += le32_to_cpu(tally.rx_overrun);
188
189		if (ar->channel) {
190			info = &ar->survey[ar->channel->hw_value];
191			info->channel_time = ar->tally.active;
192			info->channel_time_busy = ar->tally.cca;
193			info->channel_time_tx = ar->tally.tx_time;
194			do_div(info->channel_time, 1000);
195			do_div(info->channel_time_busy, 1000);
196			do_div(info->channel_time_tx, 1000);
197		}
198	}
199	return 0;
200}
201
202int carl9170_powersave(struct ar9170 *ar, const bool ps)
203{
204	struct carl9170_cmd *cmd;
205	u32 state;
206
207	cmd = carl9170_cmd_buf(ar, CARL9170_CMD_PSM_ASYNC,
208			       sizeof(struct carl9170_psm));
209	if (!cmd)
210		return -ENOMEM;
211
212	if (ps) {
213		/* Sleep until next TBTT */
214		state = CARL9170_PSM_SLEEP | 1;
215	} else {
216		/* wake up immediately */
217		state = 1;
218	}
219
220	cmd->psm.state = cpu_to_le32(state);
221	return __carl9170_exec_cmd(ar, cmd, true);
222}
223