1/* 2 * Wireless Host Controller (WHC) hardware access helpers. 3 * 4 * Copyright (C) 2007 Cambridge Silicon Radio Ltd. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License version 8 * 2 as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18#include <linux/kernel.h> 19#include <linux/dma-mapping.h> 20#include <linux/uwb/umc.h> 21 22#include "../../wusbcore/wusbhc.h" 23 24#include "whcd.h" 25 26void whc_write_wusbcmd(struct whc *whc, u32 mask, u32 val) 27{ 28 unsigned long flags; 29 u32 cmd; 30 31 spin_lock_irqsave(&whc->lock, flags); 32 33 cmd = le_readl(whc->base + WUSBCMD); 34 cmd = (cmd & ~mask) | val; 35 le_writel(cmd, whc->base + WUSBCMD); 36 37 spin_unlock_irqrestore(&whc->lock, flags); 38} 39 40/** 41 * whc_do_gencmd - start a generic command via the WUSBGENCMDSTS register 42 * @whc: the WHCI HC 43 * @cmd: command to start. 44 * @params: parameters for the command (the WUSBGENCMDPARAMS register value). 45 * @addr: pointer to any data for the command (may be NULL). 46 * @len: length of the data (if any). 47 */ 48int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len) 49{ 50 unsigned long flags; 51 dma_addr_t dma_addr; 52 int t; 53 int ret = 0; 54 55 mutex_lock(&whc->mutex); 56 57 /* Wait for previous command to complete. */ 58 t = wait_event_timeout(whc->cmd_wq, 59 (le_readl(whc->base + WUSBGENCMDSTS) & WUSBGENCMDSTS_ACTIVE) == 0, 60 WHC_GENCMD_TIMEOUT_MS); 61 if (t == 0) { 62 dev_err(&whc->umc->dev, "generic command timeout (%04x/%04x)\n", 63 le_readl(whc->base + WUSBGENCMDSTS), 64 le_readl(whc->base + WUSBGENCMDPARAMS)); 65 ret = -ETIMEDOUT; 66 goto out; 67 } 68 69 if (addr) { 70 memcpy(whc->gen_cmd_buf, addr, len); 71 dma_addr = whc->gen_cmd_buf_dma; 72 } else 73 dma_addr = 0; 74 75 /* Poke registers to start cmd. */ 76 spin_lock_irqsave(&whc->lock, flags); 77 78 le_writel(params, whc->base + WUSBGENCMDPARAMS); 79 le_writeq(dma_addr, whc->base + WUSBGENADDR); 80 81 le_writel(WUSBGENCMDSTS_ACTIVE | WUSBGENCMDSTS_IOC | cmd, 82 whc->base + WUSBGENCMDSTS); 83 84 spin_unlock_irqrestore(&whc->lock, flags); 85out: 86 mutex_unlock(&whc->mutex); 87 88 return ret; 89} 90 91/** 92 * whc_hw_error - recover from a hardware error 93 * @whc: the WHCI HC that broke. 94 * @reason: a description of the failure. 95 * 96 * Recover from broken hardware with a full reset. 97 */ 98void whc_hw_error(struct whc *whc, const char *reason) 99{ 100 struct wusbhc *wusbhc = &whc->wusbhc; 101 102 dev_err(&whc->umc->dev, "hardware error: %s\n", reason); 103 wusbhc_reset_all(wusbhc); 104} 105