/*
* 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_level: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 <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_buf {
struct sk_buff *skb;
dma_addr_t dma;
dma_regs_t *regs;
};
struct sa1100_irda {
unsigned char hscr0;
unsigned char utcr4;
unsigned char power;
unsigned char open;
int speed;
int newspeed;
struct sa1100_buf dma_rx;
struct sa1100_buf dma_tx;
struct device *dev;
struct irda_platform_data *pdata;
struct irlap_cb *irlap;
struct qos_info qos;
iobuff_t tx_buff;
iobuff_t rx_buff;
int (*tx_start)(struct sk_buff *, struct net_device *, struct sa1100_irda *);
};
static int sa1100_irda_set_speed(struct sa1100_irda *, int);
#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->dma_rx.skb)
return 0;
si->dma_rx.skb = alloc_skb(HPSIR_MAX_RXLEN + 1, GFP_ATOMIC);
if (!si->dma_rx.skb) {
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->dma_rx.skb, 1);
si->dma_rx.dma = dma_map_single(si->dev, si->dma_rx.skb->data,
HPSIR_MAX_RXLEN,
DMA_FROM_DEVICE);
if (dma_mapping_error(si->dev, si->dma_rx.dma)) {
dev_kfree_skb_any(si->dma_rx.skb);
return -ENOMEM;
}
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->dma_rx.skb) {
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->dma_rx.regs);
sa1100_start_dma(si->dma_rx.regs, si->dma_rx.dma, HPSIR_MAX_RXLEN);
Ser2HSCR0 = si->hscr0 | HSCR0_HSSP | HSCR0_RXE;
}
static void sa1100_irda_check_speed(struct sa1100_irda *si)
{
if (si->newspeed) {
sa1100_irda_set_speed(si, si->newspeed);
si->newspeed = 0;
}
}
/*
* HP-SIR format support.
*/
static int sa1100_irda_sir_tx_start(struct sk_buff *skb, struct net_device *dev,
struct sa1100_irda *si)
{
si->tx_buff.data = si->tx_buff.head;
si->tx_buff.len = async_wrap_skb(skb, si->tx_buff.data,
si->tx_buff.truesize);
/*
* Set the transmit interrupt enable. This will fire off an
* interrupt immediately. Note that we disable the receiver
* so we won't get spurious characters received.
*/
Ser2UTCR3 = UTCR3_TIE