/*
* linux/drivers/net/irda/sa1100_ir.c
*
* Copyright (C) 2000-2001 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Infra-red driver for the StrongARM SA1100 embedded microprocessor
*
* Note that we don't have to worry about the SA1111's DMA bugs in here,
* so we use the straight forward dma_map_* functions with a null pointer.
*
* This driver takes one kernel command line parameter, sa1100ir=, with
* the following options:
* max_rate:baudrate - set the maximum baud rate
* power_leve:level - set the transmitter power level
* tx_lpm:0|1 - set transmit low power mode
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/slab.h>
#include <linux/rtnetlink.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <net/irda/irda.h>
#include <net/irda/wrapper.h>
#include <net/irda/irda_device.h>
#include <asm/irq.h>
#include <mach/dma.h>
#include <mach/hardware.h>
#include <asm/mach/irda.h>
static int power_level = 3;
static int tx_lpm;
static int max_rate = 4000000;
struct sa1100_irda {
unsigned char hscr0;
unsigned char utcr4;
unsigned char power;
unsigned char open;
int speed;
int newspeed;
struct sk_buff *txskb;
struct sk_buff *rxskb;
dma_addr_t txbuf_dma;
dma_addr_t rxbuf_dma;
dma_regs_t *txdma;
dma_regs_t *rxdma;
struct device *dev;
struct irda_platform_data *pdata;
struct irlap_cb *irlap;
struct qos_info qos;
iobuff_t tx_buff;
iobuff_t rx_buff;
};
#define IS_FIR(si) ((si)->speed >= 4000000)
#define HPSIR_MAX_RXLEN 2047
/*
* Allocate and map the receive buffer, unless it is already allocated.
*/
static int sa1100_irda_rx_alloc(struct sa1100_irda *si)
{
if (si->rxskb)
return 0;
si->rxskb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC);
if (!si->rxskb) {
printk(KERN_ERR "sa1100_ir: out of memory for RX SKB\n");
return -ENOMEM;
}
/*
* Align any IP headers that may be contained
* within the frame.
*/
skb_reserve(si->rxskb, 1);
si->rxbuf_dma = dma_map_single(si->dev, si->rxskb->data,
HPSIR_MAX_RXLEN,
DMA_FROM_DEVICE);
return 0;
}
/*
* We want to get here as soon as possible, and get the receiver setup.
* We use the existing buffer.
*/
static void sa1100_irda_rx_dma_start(struct sa1100_irda *si)
{
if (!si->rxskb) {
printk(KERN_ERR "sa1100_ir: rx buffer went missing\n");
return;
}
/*
* First empty receive FIFO
*/
Ser2HSCR0 = si->hscr0 | HSCR0_HSSP;
/*
* Enable the DMA, receiver and receive interrupt.
*/
sa1100_clear_dma(si->rxdma);
sa1100_start_dma(si->rxdma, si->rxbuf_dma, HPSIR_MAX_RXLEN);
Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_RXE;
}
/*
* Set the IrDA communications speed.
*/
static int sa1100_irda_set_speed(struct sa1100_irda *si, int speed)
{
unsigned long flags;
int brd, ret = -EINVAL;
switch (speed) {
case 9600: case 19200: case 38400:
case 57600: case 115200:
brd = 3686400 / (16 * speed) - 1;
/*
* Stop the receive DMA.
*/
if (IS_FIR(si))
sa1100_stop_dma(si->rxdma);
local_irq_save(flags);
Ser2UTCR3 = 0;
Ser2HSCR0 = HSCR0_UART;
Ser2UTCR1 = brd >> 8;
Ser2UTCR2 = brd;
/*
* Clear status register
*/
Ser2UTSR0 = UTSR0_REB | UTSR0_RBB | UTSR0_RID;
Ser2UTCR3 = UTCR3_RIE | UTCR3_RXE | UTCR3_TXE;
if (si->pdata->set_speed)
si->pdata->set_speed(si->dev, speed);
si->speed = speed;
local_irq_restore(flags);
ret = 0;
break;
case 4000000:
local_irq_save(flags);
si->hscr0 = 0;
Ser2HSSR0 = 0xff;
Ser2HSCR0 = si->hscr0 | HSCR0_HSSP;
Ser2UTCR3 = 0;
si->speed = speed;
if