/*
* max3107.c - spi uart protocol driver for Maxim 3107
* Based on max3100.c
* by Christian Pellegrin <chripell@evolware.org>
* and max3110.c
* by Feng Tang <feng.tang@intel.com>
*
* Copyright (C) Aavamobile 2009
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
*/
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/freezer.h>
#include <linux/module.h>
#include "max3107.h"
static const struct baud_table brg26_ext[] = {
{ 300, MAX3107_BRG26_B300 },
{ 600, MAX3107_BRG26_B600 },
{ 1200, MAX3107_BRG26_B1200 },
{ 2400, MAX3107_BRG26_B2400 },
{ 4800, MAX3107_BRG26_B4800 },
{ 9600, MAX3107_BRG26_B9600 },
{ 19200, MAX3107_BRG26_B19200 },
{ 57600, MAX3107_BRG26_B57600 },
{ 115200, MAX3107_BRG26_B115200 },
{ 230400, MAX3107_BRG26_B230400 },
{ 460800, MAX3107_BRG26_B460800 },
{ 921600, MAX3107_BRG26_B921600 },
{ 0, 0 }
};
static const struct baud_table brg13_int[] = {
{ 300, MAX3107_BRG13_IB300 },
{ 600, MAX3107_BRG13_IB600 },
{ 1200, MAX3107_BRG13_IB1200 },
{ 2400, MAX3107_BRG13_IB2400 },
{ 4800, MAX3107_BRG13_IB4800 },
{ 9600, MAX3107_BRG13_IB9600 },
{ 19200, MAX3107_BRG13_IB19200 },
{ 57600, MAX3107_BRG13_IB57600 },
{ 115200, MAX3107_BRG13_IB115200 },
{ 230400, MAX3107_BRG13_IB230400 },
{ 460800, MAX3107_BRG13_IB460800 },
{ 921600, MAX3107_BRG13_IB921600 },
{ 0, 0 }
};
static u32 get_new_brg(int baud, struct max3107_port *s)
{
int i;
const struct baud_table *baud_tbl = s->baud_tbl;
for (i = 0; i < 13; i++) {
if (baud == baud_tbl[i].baud)
return baud_tbl[i].new_brg;
}
return 0;
}
/* Perform SPI transfer for write/read of device register(s) */
int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len)
{
struct spi_message spi_msg;
struct spi_transfer spi_xfer;
/* Initialize SPI ,message */
spi_message_init(&spi_msg);
/* Initialize SPI transfer */
memset(&spi_xfer, 0, sizeof spi_xfer);
spi_xfer.len = len;
spi_xfer.tx_buf = tx;
spi_xfer.rx_buf = rx;
spi_xfer.speed_hz = MAX3107_SPI_SPEED;
/* Add SPI transfer to SPI message */
spi_message_add_tail(&spi_xfer, &spi_msg);
#ifdef DBG_TRACE_SPI_DATA
{
int i;
pr_info("tx len %d:\n", spi_xfer.len);
for (i = 0 ; i < spi_xfer.len && i < 32 ; i++)
pr_info(" %x", ((u8 *)spi_xfer.tx_buf)[i]);
pr_info("\n");
}
#endif
/* Perform synchronous SPI transfer */
if (spi_sync(s->spi, &spi_msg)) {
dev_err(&s->spi->dev, "spi_sync failure\n");
return -EIO;
}
#ifdef DBG_TRACE_SPI_DATA
if (spi_xfer.rx_buf) {
int i;
pr_info("rx len %d:\n", spi_xfer.len);
for (i = 0 ; i < spi_xfer.len && i < 32 ; i++)
pr_info(" %x", ((u8 *)spi_xfer.rx_buf)[i]);
pr_info("\n");
}
#endif
return 0;
}
EXPORT_SYMBOL_GPL(max3107_rw);
/* Puts received data to circular buffer */
static void put_data_to_circ_buf(struct max3107_port *s, unsigned char *data,
int len)
{
struct uart_port *port = &s->port;
struct tty_struct *tty;
if (!port->state)
return;
tty = port->state->port.tty;
if (!tty)
return;
/* Insert received data */
tty_insert_flip_string(tty, data, len);
/* Update RX counter */
port->icount.rx += len;
}
/* Handle data receiving */
static void max3107_handlerx(struct max3107_port *s, u16 rxlvl)
{
int i;
int j;
int len; /* SPI transfer buffer length */
u16 *buf;
u8 *valid_str;
if (!s->rx_enabled)
/* RX is disabled */
return;
if (rxlvl == 0) {
/* RX fifo is empty */
return;
} else if (rxlvl >= MAX3107_RX_FIFO_SIZE) {
dev_warn(&s->spi->dev, "Possible RX FIFO overrun %d\n", rxlvl);
/* Ensure sanity of RX level */
rxlvl = MAX3107_RX_FIFO_SIZE;
}
if ((s->rxbuf == 0) || (s->rxstr == 0)) {
dev_warn(&s->spi->dev, "Rx buffer/str isn't ready\n");
return;
}
buf = s->rxbuf;
valid_str = s->rxstr;
while (rxlvl) {
pr_debug("rxlvl %d\n", rxlvl);
|