Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1/*
  2 *  Copyright (C) 2002 Intersil Americas Inc.
  3 *  Copyright (C) 2003-2004 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>_
  4 *
  5 *  This program is free software; you can redistribute it and/or modify
  6 *  it under the terms of the GNU General Public License as published by
  7 *  the Free Software Foundation; either version 2 of the License
  8 *
  9 *  This program is distributed in the hope that it will be useful,
 10 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12 *  GNU General Public License for more details.
 13 *
 14 *  You should have received a copy of the GNU General Public License
 15 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
 16 *
 17 */
 18
 19#include <linux/module.h>
 20#include <linux/types.h>
 21#include <linux/delay.h>
 22
 23#include <asm/uaccess.h>
 24#include <asm/io.h>
 25
 26#include "prismcompat.h"
 27#include "isl_38xx.h"
 28#include "islpci_dev.h"
 29#include "islpci_mgt.h"
 30
 31/******************************************************************************
 32    Device Interface & Control functions
 33******************************************************************************/
 34
 35/**
 36 * isl38xx_disable_interrupts - disable all interrupts
 37 * @device: pci memory base address
 38 *
 39 *  Instructs the device to disable all interrupt reporting by asserting
 40 *  the IRQ line. New events may still show up in the interrupt identification
 41 *  register located at offset %ISL38XX_INT_IDENT_REG.
 42 */
 43void
 44isl38xx_disable_interrupts(void __iomem *device)
 45{
 46	isl38xx_w32_flush(device, 0x00000000, ISL38XX_INT_EN_REG);
 47	udelay(ISL38XX_WRITEIO_DELAY);
 48}
 49
 50void
 51isl38xx_handle_sleep_request(isl38xx_control_block *control_block,
 52			     int *powerstate, void __iomem *device_base)
 53{
 54	/* device requests to go into sleep mode
 55	 * check whether the transmit queues for data and management are empty */
 56	if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ))
 57		/* data tx queue not empty */
 58		return;
 59
 60	if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ))
 61		/* management tx queue not empty */
 62		return;
 63
 64	/* check also whether received frames are pending */
 65	if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_DATA_LQ))
 66		/* data rx queue not empty */
 67		return;
 68
 69	if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_MGMTQ))
 70		/* management rx queue not empty */
 71		return;
 72
 73#if VERBOSE > SHOW_ERROR_MESSAGES
 74	DEBUG(SHOW_TRACING, "Device going to sleep mode\n");
 75#endif
 76
 77	/* all queues are empty, allow the device to go into sleep mode */
 78	*powerstate = ISL38XX_PSM_POWERSAVE_STATE;
 79
 80	/* assert the Sleep interrupt in the Device Interrupt Register */
 81	isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_SLEEP,
 82			  ISL38XX_DEV_INT_REG);
 83	udelay(ISL38XX_WRITEIO_DELAY);
 84}
 85
 86void
 87isl38xx_handle_wakeup(isl38xx_control_block *control_block,
 88		      int *powerstate, void __iomem *device_base)
 89{
 90	/* device is in active state, update the powerstate flag */
 91	*powerstate = ISL38XX_PSM_ACTIVE_STATE;
 92
 93	/* now check whether there are frames pending for the card */
 94	if (!isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ)
 95	    && !isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ))
 96		return;
 97
 98#if VERBOSE > SHOW_ERROR_MESSAGES
 99	DEBUG(SHOW_ANYTHING, "Wake up handler trigger the device\n");
100#endif
101
102	/* either data or management transmit queue has a frame pending
103	 * trigger the device by setting the Update bit in the Device Int reg */
104	isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE,
105			  ISL38XX_DEV_INT_REG);
106	udelay(ISL38XX_WRITEIO_DELAY);
107}
108
109void
110isl38xx_trigger_device(int asleep, void __iomem *device_base)
111{
112	u32 reg;
113
114#if VERBOSE > SHOW_ERROR_MESSAGES
115	u32 counter = 0;
116	struct timeval current_time;
117	DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n");
118#endif
119
120	/* check whether the device is in power save mode */
121	if (asleep) {
122		/* device is in powersave, trigger the device for wakeup */
123#if VERBOSE > SHOW_ERROR_MESSAGES
124		do_gettimeofday(&current_time);
125		DEBUG(SHOW_TRACING, "%08li.%08li Device wakeup triggered\n",
126		      current_time.tv_sec, (long)current_time.tv_usec);
127
128		DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n",
129		      current_time.tv_sec, (long)current_time.tv_usec,
130		      readl(device_base + ISL38XX_CTRL_STAT_REG));
131#endif
132
133		reg = readl(device_base + ISL38XX_INT_IDENT_REG);
134		if (reg == 0xabadface) {
135#if VERBOSE > SHOW_ERROR_MESSAGES
136			do_gettimeofday(&current_time);
137			DEBUG(SHOW_TRACING,
138			      "%08li.%08li Device register abadface\n",
139			      current_time.tv_sec, (long)current_time.tv_usec);
140#endif
141			/* read the Device Status Register until Sleepmode bit is set */
142			while (reg = readl(device_base + ISL38XX_CTRL_STAT_REG),
143			       (reg & ISL38XX_CTRL_STAT_SLEEPMODE) == 0) {
144				udelay(ISL38XX_WRITEIO_DELAY);
145#if VERBOSE > SHOW_ERROR_MESSAGES
146				counter++;
147#endif
148			}
149
150#if VERBOSE > SHOW_ERROR_MESSAGES
151			DEBUG(SHOW_TRACING,
152			      "%08li.%08li Device register read %08x\n",
153			      current_time.tv_sec, (long)current_time.tv_usec,
154			      readl(device_base + ISL38XX_CTRL_STAT_REG));
155			do_gettimeofday(&current_time);
156			DEBUG(SHOW_TRACING,
157			      "%08li.%08li Device asleep counter %i\n",
158			      current_time.tv_sec, (long)current_time.tv_usec,
159			      counter);
160#endif
161		}
162		/* assert the Wakeup interrupt in the Device Interrupt Register */
163		isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_WAKEUP,
164				  ISL38XX_DEV_INT_REG);
165
166#if VERBOSE > SHOW_ERROR_MESSAGES
167		udelay(ISL38XX_WRITEIO_DELAY);
168
169		/* perform another read on the Device Status Register */
170		reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
171		do_gettimeofday(&current_time);
172		DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n",
173		      current_time.tv_sec, (long)current_time.tv_usec, reg);
174#endif
175	} else {
176		/* device is (still) awake  */
177#if VERBOSE > SHOW_ERROR_MESSAGES
178		DEBUG(SHOW_TRACING, "Device is in active state\n");
179#endif
180		/* trigger the device by setting the Update bit in the Device Int reg */
181
182		isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE,
183				  ISL38XX_DEV_INT_REG);
184	}
185}
186
187void
188isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address)
189{
190#if VERBOSE > SHOW_ERROR_MESSAGES
191	DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset\n");
192#endif
193
194	/* load the address of the control block in the device */
195	isl38xx_w32_flush(device_base, host_address, ISL38XX_CTRL_BLK_BASE_REG);
196	udelay(ISL38XX_WRITEIO_DELAY);
197
198	/* set the reset bit in the Device Interrupt Register */
199	isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET, ISL38XX_DEV_INT_REG);
200	udelay(ISL38XX_WRITEIO_DELAY);
201
202	/* enable the interrupt for detecting initialization */
203
204	/* Note: Do not enable other interrupts here. We want the
205	 * device to have come up first 100% before allowing any other
206	 * interrupts. */
207	isl38xx_w32_flush(device_base, ISL38XX_INT_IDENT_INIT, ISL38XX_INT_EN_REG);
208	udelay(ISL38XX_WRITEIO_DELAY);  /* allow complete full reset */
209}
210
211void
212isl38xx_enable_common_interrupts(void __iomem *device_base)
213{
214	u32 reg;
215
216	reg = ISL38XX_INT_IDENT_UPDATE | ISL38XX_INT_IDENT_SLEEP |
217	      ISL38XX_INT_IDENT_WAKEUP;
218	isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG);
219	udelay(ISL38XX_WRITEIO_DELAY);
220}
221
222int
223isl38xx_in_queue(isl38xx_control_block *cb, int queue)
224{
225	const s32 delta = (le32_to_cpu(cb->driver_curr_frag[queue]) -
226			   le32_to_cpu(cb->device_curr_frag[queue]));
227
228	/* determine the amount of fragments in the queue depending on the type
229	 * of the queue, either transmit or receive */
230
231	BUG_ON(delta < 0);	/* driver ptr must be ahead of device ptr */
232
233	switch (queue) {
234		/* send queues */
235	case ISL38XX_CB_TX_MGMTQ:
236		BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE);
237
238	case ISL38XX_CB_TX_DATA_LQ:
239	case ISL38XX_CB_TX_DATA_HQ:
240		BUG_ON(delta > ISL38XX_CB_TX_QSIZE);
241		return delta;
242
243		/* receive queues */
244	case ISL38XX_CB_RX_MGMTQ:
245		BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE);
246		return ISL38XX_CB_MGMT_QSIZE - delta;
247
248	case ISL38XX_CB_RX_DATA_LQ:
249	case ISL38XX_CB_RX_DATA_HQ:
250		BUG_ON(delta > ISL38XX_CB_RX_QSIZE);
251		return ISL38XX_CB_RX_QSIZE - delta;
252	}
253	BUG();
254	return 0;
255}