SPI转UART驱动(UART控制器)

kernel\drivers\tty\serial\n76e003-usart.c

/*
 * Copyright (C) Maxime Coquelin 2015
 * Author:  Maxime Coquelin <[email protected]>
 * License terms:  GNU General Public License (GPL), version 2
 *
 * Inspired by st-asc.c from STMicroelectronics (c)
 */
#if defined(CONFIG_SERIAL_N76E003_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/module.h>
#include <linux/serial.h>
#include <linux/console.h>
#include <linux/sysrq.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/spinlock.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/serial_core.h>
#include <linux/clk.h>
#include <linux/spi/spidev.h>

#define DRIVER_NAME "n76e003-usart"

/* Register offsets */
#define USART_SR		0x00
#define USART_DR		0x04
#define USART_BRR		0x08
#define USART_CR1		0x0c
#define USART_CR2		0x10
#define USART_CR3		0x14
#define USART_GTPR		0x18

/* USART_SR */
#define USART_SR_PE		BIT(0)
#define USART_SR_FE		BIT(1)
#define USART_SR_NF		BIT(2)
#define USART_SR_ORE		BIT(3)
#define USART_SR_IDLE		BIT(4)
#define USART_SR_RXNE		BIT(5)
#define USART_SR_TC		BIT(6)
#define USART_SR_TXE		BIT(7)
#define USART_SR_LBD		BIT(8)
#define USART_SR_CTS		BIT(9)
#define USART_SR_ERR_MASK	(USART_SR_LBD | USART_SR_ORE | \
				 USART_SR_FE | USART_SR_PE)
/* Dummy bits */
#define USART_SR_DUMMY_RX	BIT(16)

/* USART_DR */
#define USART_DR_MASK		GENMASK(8, 0)

/* USART_BRR */
#define USART_BRR_DIV_F_MASK	GENMASK(3, 0)
#define USART_BRR_DIV_M_MASK	GENMASK(15, 4)
#define USART_BRR_DIV_M_SHIFT	4

/* USART_CR1 */
#define USART_CR1_SBK		BIT(0)
#define USART_CR1_RWU		BIT(1)
#define USART_CR1_RE		BIT(2)
#define USART_CR1_TE		BIT(3)
#define USART_CR1_IDLEIE	BIT(4)
#define USART_CR1_RXNEIE	BIT(5)
#define USART_CR1_TCIE		BIT(6)
#define USART_CR1_TXEIE		BIT(7)
#define USART_CR1_PEIE		BIT(8)
#define USART_CR1_PS		BIT(9)
#define USART_CR1_PCE		BIT(10)
#define USART_CR1_WAKE		BIT(11)
#define USART_CR1_M		BIT(12)
#define USART_CR1_UE		BIT(13)
#define USART_CR1_OVER8		BIT(15)
#define USART_CR1_IE_MASK	GENMASK(8, 4)
#define PORT_N76E003     113

/* USART_CR2 */
#define USART_CR2_ADD_MASK	GENMASK(3, 0)
#define USART_CR2_LBDL		BIT(5)
#define USART_CR2_LBDIE		BIT(6)
#define USART_CR2_LBCL		BIT(8)
#define USART_CR2_CPHA		BIT(9)
#define USART_CR2_CPOL		BIT(10)
#define USART_CR2_CLKEN		BIT(11)
#define USART_CR2_STOP_2B	BIT(13)
#define USART_CR2_STOP_MASK	GENMASK(13, 12)
#define USART_CR2_LINEN		BIT(14)

/* USART_CR3 */
#define USART_CR3_EIE		BIT(0)
#define USART_CR3_IREN		BIT(1)
#define USART_CR3_IRLP		BIT(2)
#define USART_CR3_HDSEL		BIT(3)
#define USART_CR3_NACK		BIT(4)
#define USART_CR3_SCEN		BIT(5)
#define USART_CR3_DMAR		BIT(6)
#define USART_CR3_DMAT		BIT(7)
#define USART_CR3_RTSE		BIT(8)
#define USART_CR3_CTSE		BIT(9)
#define USART_CR3_CTSIE		BIT(10)
#define USART_CR3_ONEBIT	BIT(11)

/* USART_GTPR */
#define USART_GTPR_PSC_MASK	GENMASK(7, 0)
#define USART_GTPR_GT_MASK	GENMASK(15, 8)


/*
 *			SPI2UART 
     BIT0         
 Data/Command    0:Data,1:Command
     BIT1         
 CSTOPB(1/2)     0:1   ,1:2
     BIT2         
 PARENB     	 0:not set   ,1:set 
	 BIT3		 
 PARODD			 0:not set	,1:set 
	 BIT4		
 CSIZE			 0:CS8  ,1: acording to second Byte
     BIT5 	   
 CRTSCTS		 0:not set  ,1:set 
     BIT6 	   
 BAUD		 	 0:not set  ,1:set,acording to second Byte
*/
#define COMMAND_BIT 0
#define CSTOPB_BIT 1
#define PARENB_BIT 2
#define PARODD_BIT 3
#define CSIZE_BIT 4
#define CRTSCTS_BIT 5
#define BAUD_BIT 6

#define DRIVER_NAME "n76e003-usart"
#define n76e003_SERIAL_NAME "ttyS"
#define n76e003_MAX_PORTS 6
static unsigned bufsiz = 4096;

#define MAX_SPI_DEV_NUM 6
#define SPI_MAX_SPEED_HZ	12000000

struct spi2uart_data {
	struct device	*dev;
	struct spi_device *spi;
	char *rx_buffer;
	int rx_len;
	char *tx_buffer;
	int tx_len;
	int speed_hz;
};

struct n76e003_port {
	struct uart_port port;
	bool hw_flow_control;
};

static struct n76e003_port n76e003_ports[n76e003_MAX_PORTS];
static struct uart_driver n76e003_usart_driver;
static struct spi2uart_data *spi2uart_data = NULL;

static void n76e003_stop_tx(struct uart_port *port);

static inline struct n76e003_port *to_n76e003_port(struct uart_port *port)
{
	return container_of(port, struct n76e003_port, port);
}

static void n76e003_receive_chars(struct uart_port *port,u8 buf)
{
	struct tty_port *tport = &port->state->port;
	u8 c;
	u32 sr = 0;
	char flag;

	if (port->irq_wake)
		pm_wakeup_event(tport->tty->dev, 0);
		sr = USART_SR_DUMMY_RX | USART_SR_RXNE;

		c = buf;

		flag = TTY_NORMAL;
		port->icount.rx++;
#if 0
		if (sr & USART_SR_ERR_MASK) {
			if (sr & USART_SR_LBD) {
				port->icount.brk++;
				if (uart_handle_break(port))
					continue;
			} else if (sr & USART_SR_ORE) {
				port->icount.overrun++;
			} else if (sr & USART_SR_PE) {
				port->icount.parity++;
			} else if (sr & USART_SR_FE) {
				port->icount.frame++;
			}

			sr &= port->read_status_mask;

			if (sr & USART_SR_LBD)
				flag = TTY_BREAK;
			else if (sr & USART_SR_PE)
				flag = TTY_PARITY;
			else if (sr & USART_SR_FE)
				flag = TTY_FRAME;
		}
#endif
		if (uart_handle_sysrq_char(port, c))
		{
			pr_err("sysrq char ,break");
			return;
		}
		uart_insert_char(port, sr, USART_SR_ORE, c, flag);

	tty_flip_buffer_push(tport);
}

static void n76e003_transmit_chars(struct uart_port *port)
{
	struct circ_buf *xmit = &port->state->xmit;
	if (port->x_char) {
		pr_err("xon/xoff char\n");
		port->x_char = 0;
		port->icount.tx++;
		return;
	}

	if (uart_tx_stopped(port)) {
		pr_err("tx stoped\n");
		n76e003_stop_tx(port);
		return;
	}

	if (uart_circ_empty(xmit)) {
		pr_err("tx empty\n");
		n76e003_stop_tx(port);
		return;
	}

	
	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
	port->icount.tx++;
	

	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
		uart_write_wakeup(port);
	
	

	if (uart_circ_empty(xmit))
		n76e003_stop_tx(port);
}

static irqreturn_t n76e003_interrupt(int irq, void *ptr)
{
	struct uart_port *port = ptr;
	u32 sr;

	spin_lock(&port->lock);

	sr = readl_relaxed(port->membase + USART_SR);

	if (sr & USART_SR_RXNE)
		n76e003_receive_chars(port,0);

	if (sr & USART_SR_TXE)
		n76e003_transmit_chars(port);

	spin_unlock(&port->lock);

	return IRQ_HANDLED;
}

static unsigned int n76e003_tx_empty(struct uart_port *port)
{

	return 0;
}

static void n76e003_set_mctrl(struct uart_port *port, unsigned int mctrl)
{

}

static unsigned int n76e003_get_mctrl(struct uart_port *port)
{
	/* This routine is used to get signals of: DCD, DSR, RI, and CTS */
	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
}

/* Transmit stop */
static void n76e003_stop_tx(struct uart_port *port)
{
	
}

static ssize_t
spidev_sync(struct spi2uart_data *spidev, struct spi_message *message)
{
	DECLARE_COMPLETION_ONSTACK(done);
	int status;
	struct spi_device *spi;

	spi = spidev->spi;

	if (spi == NULL)
		status = -ESHUTDOWN;
	else
		status = spi_sync(spi, message);

	if (status == 0)
		status = message->actual_length;

	return status;
}

static int spidev_message(struct spi2uart_data *spidev,
		struct spi_ioc_transfer *u_xfers, unsigned n_xfers)
{
	struct spi_message	msg;
	struct spi_transfer	*k_xfers;
	struct spi_transfer	*k_tmp;
	struct spi_ioc_transfer *u_tmp;
	unsigned		n, total, tx_total, rx_total;
	u8			*tx_buf, *rx_buf;
	int			status = -EFAULT;
	
	spi_message_init(&msg);
	k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL);
	if (k_xfers == NULL)
		return -ENOMEM;

	/* Construct spi_message, copying any tx data to bounce buffer.
	 * We walk the array of user-provided transfers, using each one
	 * to initialize a kernel version of the same transfer.
	 */
	tx_buf = spidev->tx_buffer;
	rx_buf = spidev->rx_buffer;
	total = 0;
	tx_total = 0;
	rx_total = 0;
	for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
			n > 0;
			n--, k_tmp++, u_tmp++) {
		k_tmp->len = u_tmp->len;

		total += k_tmp->len;
		/* Since the function returns the total length of transfers
		 * on success, restrict the total to positive int values to
		 * avoid the return value looking like an error.  Also check
		 * each transfer length to avoid arithmetic overflow.
		 */
		if (total > INT_MAX || k_tmp->len > INT_MAX) {
			status = -EMSGSIZE;
			goto done;
		}

		if (u_tmp->rx_buf) {
			/* this transfer needs space in RX bounce buffer */
			rx_total += k_tmp->len;
			if (rx_total > bufsiz) {
				status = -EMSGSIZE;
				goto done;
			}
			k_tmp->rx_buf = (void *)u_xfers->rx_buf;

			//rx_buf += k_tmp->len;
		}
		if (u_tmp->tx_buf) {
			/* this transfer needs space in TX bounce buffer */
			tx_total += k_tmp->len;
			if (tx_total > bufsiz) {
				status = -EMSGSIZE;
				goto done;
			}
			k_tmp->tx_buf = tx_buf;
			strncpy(tx_buf,(char *)u_tmp->tx_buf,u_tmp->len);
			tx_buf += k_tmp->len;
		}

		k_tmp->cs_change = !!u_tmp->cs_change;
		k_tmp->tx_nbits = u_tmp->tx_nbits;
		k_tmp->rx_nbits = u_tmp->rx_nbits;
		k_tmp->bits_per_word = u_tmp->bits_per_word;
		k_tmp->delay_usecs = u_tmp->delay_usecs;
		k_tmp->speed_hz = u_tmp->speed_hz;
		if (!k_tmp->speed_hz)
			k_tmp->speed_hz = spidev->speed_hz;
		
		spi_message_add_tail(k_tmp, &msg);
	}

	status = spidev_sync(spidev, &msg);
	if (status < 0)
	{
		printk("%s LINE = %d\n",__func__,__LINE__);
		goto done;
	}

	status = total;

done:
	kfree(k_xfers);
	return status;
}

/* There are probably characters waiting to be transmitted. */
static void n76e003_start_tx(struct uart_port *port)
{
	struct circ_buf *xmit = &port->state->xmit;
	int ret = 0;
	int i = 0;
	u8 recevie_buf = 0x0;
	u8 send_buf = 0x0;
    struct spi_ioc_transfer tr = {
             .tx_buf = (unsigned long)&send_buf,   //定义发送缓冲区指针
             .rx_buf = (unsigned long)&recevie_buf,   //定义接收缓冲区指针
             .len = 1,                    
             .delay_usecs = 0,
             .speed_hz = 1000000,
             .bits_per_word = 8,
     };	
			 
	if (uart_circ_empty(xmit))
		return;
	
	for(i=xmit->tail;i<xmit->head;i++)
	{
		send_buf = xmit->buf[xmit->tail];
		ret = spidev_message(spi2uart_data,&tr,1);
		printk("recevie_buf = %x\n",recevie_buf);
		n76e003_transmit_chars(port);
		n76e003_receive_chars(port,recevie_buf);
	}
	
}

/* Throttle the remote when input buffer is about to overflow. */
static void n76e003_throttle(struct uart_port *port)
{
	unsigned long flags;

	spin_lock_irqsave(&port->lock, flags);

	spin_unlock_irqrestore(&port->lock, flags);
}

/* Unthrottle the remote, the input buffer can now accept data. */
static void n76e003_unthrottle(struct uart_port *port)
{
	unsigned long flags;

	spin_lock_irqsave(&port->lock, flags);

	spin_unlock_irqrestore(&port->lock, flags);
}

/* Receive stop */
static void n76e003_stop_rx(struct uart_port *port)
{

}

/* Handle breaks - ignored by us */
static void n76e003_break_ctl(struct uart_port *port, int break_state)
{

}

static int n76e003_startup(struct uart_port *port)
{
	const char *name = to_platform_device(port->dev)->name;
	u32 val;
	int ret;
	ret = request_irq(port->irq, n76e003_interrupt, 0, name, port);


	val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;

	return 0;
}

static void n76e003_shutdown(struct uart_port *port)
{
	u32 val;

	val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE;

	free_irq(port->irq, port);
}

int send_spi_head(u8 byte0,u8 byte1)
{
	return 0;
}
static void n76e003_set_termios(struct uart_port *port, struct ktermios *termios,
			    struct ktermios *old)
{
	struct n76e003_port *n76e003_port = to_n76e003_port(port);
	unsigned int baud;
	tcflag_t cflag = termios->c_cflag;
	unsigned long flags;
	int ret = 0;
	u8 byte0 = 0;  //type
	u8 byte1 = 0;  //baud size / cs size
	
	if (!n76e003_port->hw_flow_control)
		cflag &= ~CRTSCTS;
	

	baud = uart_get_baud_rate(port, termios, old, 0, 460800);

	spin_lock_irqsave(&port->lock, flags);

	byte0 = 1 << COMMAND_BIT;
	
	byte0 |= 1 << BAUD_BIT;
	
	/*set 2 stop bit*/
	if (cflag & CSTOPB)
	{
		byte0 |= 1 << CSTOPB_BIT;
	}

	if (cflag & PARENB) 
	{
		byte0 |= 1 << PARENB_BIT;
	}
	
	if ((cflag & CSIZE) == CS8)
	{
		byte0 |= 1 << CSIZE_BIT;
	}

	if (cflag & PARODD)
	{
		byte0 |= 1 << PARODD_BIT;
	}

	port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS);
	if (cflag & CRTSCTS) {
		port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
		byte0 |= 1 << CRTSCTS_BIT;
	}

	uart_update_timeout(port, cflag, baud);

	port->read_status_mask = USART_SR_ORE;
	if (termios->c_iflag & INPCK)
		port->read_status_mask |= USART_SR_PE | USART_SR_FE;
	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
		port->read_status_mask |= USART_SR_LBD;

	/* Characters to ignore */
	port->ignore_status_mask = 0;
	if (termios->c_iflag & IGNPAR)
		port->ignore_status_mask = USART_SR_PE | USART_SR_FE;
	if (termios->c_iflag & IGNBRK) {
		port->ignore_status_mask |= USART_SR_LBD;
		/*
		 * If we're ignoring parity and break indicators,
		 * ignore overruns too (for real raw support).
		 */
		if (termios->c_iflag & IGNPAR)
			port->ignore_status_mask |= USART_SR_ORE;
	}

	/* Ignore all characters if CREAD is not set */
	if ((termios->c_cflag & CREAD) == 0)
		port->ignore_status_mask |= USART_SR_DUMMY_RX;

	spin_unlock_irqrestore(&port->lock, flags);
	ret = send_spi_head(byte0,byte1);
	if(ret < 0)
		pr_err("spi send head failed\n");
}

static const char *n76e003_type(struct uart_port *port)
{
	return (port->type == PORT_N76E003) ? DRIVER_NAME : NULL;
}

static void n76e003_release_port(struct uart_port *port)
{
}

static int n76e003_request_port(struct uart_port *port)
{
	return 0;
}

static void n76e003_config_port(struct uart_port *port, int flags)
{
		port->type = PORT_N76E003;
}

static int
n76e003_verify_port(struct uart_port *port, struct serial_struct *ser)
{
	/* No user changeable parameters */
	return 0;
}

static void n76e003_pm(struct uart_port *port, unsigned int state,
		unsigned int oldstate)
{

	unsigned long flags = 0;

	switch (state) {
	case UART_PM_STATE_ON:
		break;
	case UART_PM_STATE_OFF:
		spin_lock_irqsave(&port->lock, flags);

		spin_unlock_irqrestore(&port->lock, flags);
		break;
	}
}

static const struct uart_ops n76e003_uart_ops = {
	.tx_empty	= n76e003_tx_empty,
	.set_mctrl	= n76e003_set_mctrl,
	.get_mctrl	= n76e003_get_mctrl,
	.stop_tx	= n76e003_stop_tx,
	.start_tx	= n76e003_start_tx,
	.throttle	= n76e003_throttle,
	.unthrottle	= n76e003_unthrottle,
	.stop_rx	= n76e003_stop_rx,
	.break_ctl	= n76e003_break_ctl,
	.startup	= n76e003_startup,
	.shutdown	= n76e003_shutdown,
	.set_termios	= n76e003_set_termios,
	.pm		= n76e003_pm,
	.type		= n76e003_type,
	.release_port	= n76e003_release_port,
	.request_port	= n76e003_request_port,
	.config_port	= n76e003_config_port,
	.verify_port	= n76e003_verify_port,
};

static int n76e003_init_port(struct n76e003_port *n76e003port,
			  struct platform_device *pdev)
{
	struct uart_port *port = &n76e003port->port;


	port->iotype	= UPIO_MEM;
	port->flags	= UPF_BOOT_AUTOCONF;
	port->ops	= &n76e003_uart_ops;
	port->dev	= &pdev->dev;
	port->irq	= platform_get_irq(pdev, 0);
	port->iobase = 1;



	spin_lock_init(&port->lock);

	return 0;
}

static struct n76e003_port *n76e003_of_get_n76e003_port(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	int id;

	if (!np)
		return NULL;

	id = of_alias_get_id(np, "serial");
	if (id < 0)
		id = 0;

	if (WARN_ON(id >= n76e003_MAX_PORTS))
		return NULL;

	n76e003_ports[id].hw_flow_control = of_property_read_bool(np,
							"auto-flow-control");
	n76e003_ports[id].port.line = id;
	return &n76e003_ports[id];
}

#ifdef CONFIG_OF
static const struct of_device_id n76e003_match[] = {
	{ .compatible = "st,n76e003-usart", },
	{ .compatible = "st,n76e003-uart", },
	{},
};

MODULE_DEVICE_TABLE(of, n76e003_match);
#endif

static int n76e003_serial_probe(struct platform_device *pdev)
{
	int ret;
	struct n76e003_port *n76e003port;

	n76e003port = n76e003_of_get_n76e003_port(pdev);
	if (!n76e003port)
		return -ENODEV;

	ret = n76e003_init_port(n76e003port, pdev);
	if (ret)
		return ret;

	ret = uart_add_one_port(&n76e003_usart_driver, &n76e003port->port);
	if (ret)
		return ret;

	platform_set_drvdata(pdev, &n76e003port->port);

	return 0;
}

static int n76e003_serial_remove(struct platform_device *pdev)
{
	struct uart_port *port = platform_get_drvdata(pdev);

	return uart_remove_one_port(&n76e003_usart_driver, port);
}


#ifdef CONFIG_SERIAL_N76E003_CONSOLE
static void n76e003_console_putchar(struct uart_port *port, int ch)
{
	printk("%s LINE = %d\n",__func__,__LINE__);

}

static void n76e003_console_write(struct console *co, const char *s, unsigned cnt)
{
	struct uart_port *port = &n76e003_ports[co->index].port;
	unsigned long flags;
	u32 old_cr1, new_cr1;
	int locked = 1;

	local_irq_save(flags);
	if (port->sysrq)
		locked = 0;
	else if (oops_in_progress)
		locked = spin_trylock(&port->lock);
	else
		spin_lock(&port->lock);


	uart_console_write(port, s, cnt, n76e003_console_putchar);


	if (locked)
		spin_unlock(&port->lock);
	local_irq_restore(flags);
}

static int n76e003_console_setup(struct console *co, char *options)
{
	struct n76e003_port *n76e003port;
	int baud = 9600;
	int bits = 8;
	int parity = 'n';
	int flow = 'n';

	if (co->index >= n76e003_MAX_PORTS)
		return -ENODEV;

	n76e003port = &n76e003_ports[co->index];



	if (options)
		uart_parse_options(options, &baud, &parity, &bits, &flow);

	return uart_set_options(&n76e003port->port, co, baud, parity, bits, flow);
}

static struct console n76e003_console = {
	.name		= n76e003_SERIAL_NAME,
	.device		= uart_console_device,
	.write		= n76e003_console_write,
	.setup		= n76e003_console_setup,
	.flags		= CON_PRINTBUFFER,
	.index		= -1,
	.data		= &n76e003_usart_driver,
};

#define n76e003_SERIAL_CONSOLE (&n76e003_console)

#else
#define n76e003_SERIAL_CONSOLE NULL
#endif /* CONFIG_SERIAL_N76E003_CONSOLE */

static struct uart_driver n76e003_usart_driver = {
	.driver_name	= DRIVER_NAME,
	.dev_name	= n76e003_SERIAL_NAME,
	.major		= 0,
	.minor		= 0,
	.nr		= n76e003_MAX_PORTS,
	.cons		= n76e003_SERIAL_CONSOLE,
};

static struct platform_driver n76e003_serial_driver = {
	.probe		= n76e003_serial_probe,
	.remove		= n76e003_serial_remove,
	.driver	= {
		.name	= DRIVER_NAME,
		.of_match_table = of_match_ptr(n76e003_match),
	},
};
		
#ifdef CONFIG_OF
static const struct of_device_id spi2uart_dt_match[] = {
	{ .compatible = "sunmi_spi2uart", },
	{},
};
MODULE_DEVICE_TABLE(of, rockchip_spi_test_dt_match);

#endif /* CONFIG_OF */

static int spi2uart_probe(struct spi_device *spi)
{
	int ret;
	int id = 0;

	if (!spi)
		return -ENOMEM;

	if (!spi->dev.of_node)
		return -ENOMEM;

	spi2uart_data = (struct spi2uart_data *)kzalloc(sizeof(struct spi2uart_data), GFP_KERNEL);
	if (!spi2uart_data) {
		dev_err(&spi->dev, "ERR: no memory for spi_test_data\n");
		return -ENOMEM;
	}
	
	spi->bits_per_word = 8;
	spi->mode = SPI_MODE_0;//SPI_MODE_0;

	spi2uart_data->spi = spi;
	spi2uart_data->dev = &spi->dev;
	spi2uart_data->speed_hz = 1000000;
	
	
	spi2uart_data->tx_buffer = kmalloc(bufsiz, GFP_KERNEL);
	if (!spi2uart_data->tx_buffer) {
		dev_err(&spi2uart_data->spi->dev, "open/ENOMEM\n");
		ret = -ENOMEM;
	}

	spi2uart_data->rx_buffer = kmalloc(bufsiz, GFP_KERNEL);
	if (!spi2uart_data->rx_buffer) {
		dev_err(&spi2uart_data->spi->dev, "open/ENOMEM\n");
		ret = -ENOMEM;
	}

	ret = spi_setup(spi);
	if (ret < 0) {
		dev_err(spi2uart_data->dev, "ERR: fail to setup spi\n");
		return -1;
	}

	if (of_property_read_u32(spi->dev.of_node, "id", &id)) {
		dev_warn(&spi->dev, "fail to get id, default set 0\n");
		id = 0;
	}

	printk("%s:name=%s,bus_num=%d,cs=%d,mode=%d,speed=%d\n", __func__, spi->modalias, spi->master->bus_num, spi->chip_select, spi->mode, spi->max_speed_hz);

	return 0;
}

static int spi2uart_remove(struct spi_device *spi)
{
	printk("%s\n", __func__);
	return 0;
}

static struct spi_driver spi2uart_driver = {
	.driver = {
		.name	= "spi2uart",
		.owner = THIS_MODULE,
		.of_match_table = of_match_ptr(spi2uart_dt_match),
	},
	.probe = spi2uart_probe,
	.remove = spi2uart_remove,
};

static int __init usart_init(void)
{
	static char banner[] __initdata = "n76e003 USART driver initialized";
	int ret;

	pr_info("%s\n", banner);
	ret = spi_register_driver(&spi2uart_driver);
	if (ret)
		return ret;
	
	ret = uart_register_driver(&n76e003_usart_driver);
	if (ret)
		return ret;

	ret = platform_driver_register(&n76e003_serial_driver);
	if (ret)
		uart_unregister_driver(&n76e003_usart_driver);


	return ret;
}

static void __exit usart_exit(void)
{
	platform_driver_unregister(&n76e003_serial_driver);
	uart_unregister_driver(&n76e003_usart_driver);
}

module_init(usart_init);
module_exit(usart_exit);

MODULE_ALIAS("platform:" DRIVER_NAME);
MODULE_DESCRIPTION("sunmi n76e003 serial port driver");
MODULE_LICENSE("GPL v2");

kernel\arch\arm64\boot\dts\rockchip\rk3399-sapphire-excavator-edp.dts

n76e003 {
		status = "okay";
		compatible = "st,n76e003-uart";
	};
									  ..........
&spi2{
	status = "okay";
	max-freq = <48000000>;
	pinctrl-names = "default";
    pinctrl-0 = <&spi2_clk &spi2_tx &spi2_rx &spi2_cs0>;
	spi2uart@0 {
		compatible ="sunmi_spi2uart"; 
		reg = <0>;
		spi-max-frequency = <1000000>;	   
		status = "okay"; 
	};
};

猜你喜欢

转载自blog.csdn.net/zhuyong006/article/details/82804136