linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: Fw: about sc16is7x2 drivier
       [not found] <4D0F1B6A.0A69AA.31769@m50-133.163.com>
@ 2010-12-20  9:09 ` Manuel Stahl
  2010-12-20 10:03   ` Manuel Stahl
  0 siblings, 1 reply; 3+ messages in thread
From: Manuel Stahl @ 2010-12-20  9:09 UTC (permalink / raw)
  To: changgx; +Cc: hunterzhu, spi-devel-general, linux-serial

[-- Attachment #1: Type: text/plain, Size: 3950 bytes --]

Hello Kathy Chang,

thank you for your effort. Can you provide a patch for the sc16is7x2.c file?

Regards,
Manuel Stahl

On 20.12.2010 10:01, changgx wrote:
> hello,Manuel Stahl:
> 
> Sc16is7x2 driver has been successfully debugged.
> 
> In sc16is7x2.c,the control to the var .cs_change does not match with at91sam9260 driver.
> 
> 1、
> In function sc16is7x2_startup(),the spi chip select maintains low level after the setence cmds = sc16is7x2_alloc_spi_cmds(8).
> It caused a error about next SPI operation.
> 
> Improved method is to use 8 sc16is7x2_write_async() function to set sc16is7x2 reg.
> 
> 2、
> 
> In sc16is7x2_msg_add_fifo_tx() function, you need to take anti-cs_change variables.
> 
> 
> good luck!!!
> 
> 
> ======= 2010-12-14 11:52:00 您在来信中写道:=======
> 
>> Hello again,
>>
>> The commands in sc16is7x2_spi_async are sent async (as the name says),
>> so the first time you execute sc16is7x2_read(ts->spi, UART_IER,ch) the
>> async part was not yet completed, the second time it was completed and
>> has set UART_IER to 0.
>>
>> Regards,
>> Manuel
>>
>> On 13.12.2010 06:43, changgx wrote:
>>>      hello,manuel.stahl:
>>>
>>>      excuse me!!
>>>
>>>      I found the sc16is7x2.c driver provided by you on the internet the
>>>      other day. And I explante it to my board.
>>>
>>>      My develop environment is about :CPU for AT91SAM9260 and kennel for
>>>      linux-2.6.27.
>>>
>>>      But I found some questions in debugging.
>>>
>>>      In the function of sc16is7x2_startup( ), i add the sentence to read
>>>      register value after sc16is7x2_spi_async(ts->spi, cmds, 8) sentence
>>>      and i find that the return value is always 0xff.
>>>
>>>      for example:
>>>
>>>      int uier1,uier2;
>>>
>>>      uier1 = sc16is7x2_read(ts->spi, UART_IER,ch);
>>>      SC16_PRINTK("+++++++++++++++++++++>  s :d UART_IER = x
>>>      \n",__func__,__LINE__,uier1);
>>>      uier2 = sc16is7x2_read(ts->spi, UART_IER,ch);
>>>      SC16_PRINTK("+++++++++++++++++++++>  s :d UART_IER = x
>>>      \n",__func__,__LINE__,uier2);
>>>
>>>      the print result:
>>>
>>>      +++++++++++++++++++++>  sc16is7x2_startup : 512 UART_IER = ff
>>>      +++++++++++++++++++++>  sc16is7x2_startup : 515 UART_IER = 0
>>>
>>>      The results is that the first time is 0xff, the secend is 0.
>>>
>>>      And it is same to read other register.
>>>
>>>      please give me some advice for this question.
>>>
>>>      ps: thank you very much for your open souce and look forward to your
>>>      email.
>>>
>>>      thanks!
>>>
>>>      kathy chang
>>>
>>>      2010-12-13
>>>
>>>      ------------------------------------------------
>>>
>>>      Email:changgx@163.com<mailto:changgx@163.com>
>>>
>>>      ------------------------------------------------
>>>
>>>
>>>
>>> = = = = = = = = = = = = = = = = = = = =
>>>         致
>>> 礼!
>>> changgx
>>> changgx@163.com<mailto:changgx@163.com>
>>> 2010-12-13
>>>               
>>
>>
>> -- 
>> Manuel Stahl
>> Fraunhofer-Institut IIS
>> Leistungsoptimierte Systeme
>>
>> Nordostpark 93
>> D90411 Nürnberg
>> Telefon  +49 (0)911/58061-6419
>> Fax      +49 (0)911/58061-6398
>> E-Mail   manuel.stahl@iis.fraunhofer.de
>>
>> http://www.iis.fraunhofer.de
>> http://www.smart-power.fraunhofer.de
>>
>>
>>
>> __________ Information from ESET Smart Security, version of virus signature database 5563 (20101026) __________
>>
>> The message was checked by ESET Smart Security.
>>
>> http://www.eset.com
> 
> = = = = = = = = = = = = = = = = = = = =
> 			
> 
>         致
> 礼!
> 
> 				
>         changgx
>         changgx@163.com
>           2010-12-20
> 
> 
> 
> 


-- 
Manuel Stahl
Fraunhofer-Institut IIS
Leistungsoptimierte Systeme

Nordostpark 93
D90411 Nürnberg
Telefon  +49 (0)911/58061-6419
Fax      +49 (0)911/58061-6398
E-Mail   manuel.stahl@iis.fraunhofer.de

http://www.iis.fraunhofer.de
http://www.smart-power.fraunhofer.de

[-- Attachment #2: manuel_stahl.vcf --]
[-- Type: text/x-vcard, Size: 170 bytes --]

begin:vcard
fn:Manuel Stahl
n:Stahl;Manuel
email;internet:manuel.stahl@iis.fraunhofer.de
tel;work:+49 911 58061-6419
x-mozilla-html:FALSE
version:2.1
end:vcard


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: about sc16is7x2 drivier
  2010-12-20  9:09 ` Fw: about sc16is7x2 drivier Manuel Stahl
@ 2010-12-20 10:03   ` Manuel Stahl
  0 siblings, 0 replies; 3+ messages in thread
From: Manuel Stahl @ 2010-12-20 10:03 UTC (permalink / raw)
  To: changgx; +Cc: hunterzhu, spi-devel-general, linux-serial

[-- Attachment #1: Type: text/plain, Size: 6118 bytes --]

Hello Kathy Chang,

I will have a look at your changes. Please send your mails also to
spi-devel-general@lists.sourceforge.net and
spi-devel-general@lists.sourceforge.net (simply press reply-to-all).

Also remember that you should not simply remove existing copyright
notices when you modify driver!

Regards,
Manuel Stahl

> hello ,Manuel Stahl:
> 
> I deleted the part of the IO driver.And I compile the driver from the kernel independent.
> 
> Please refer to the attached source code.
> 
> kathy chang
> 
> 2010.12.20
> 	
> 
> ======= 2010-12-20 10:09:00 您在来信中写道:=======
> 
>> >Hello Kathy Chang,
>> >
>> >thank you for your effort. Can you provide a patch for the sc16is7x2.c file?
>> >
>> >Regards,
>> >Manuel Stahl
>> >
>> >On 20.12.2010 10:01, changgx wrote:
>>> >> hello,Manuel Stahl:
>>> >> 
>>> >> Sc16is7x2 driver has been successfully debugged.
>>> >> 
>>> >> In sc16is7x2.c,the control to the var .cs_change does not match with at91sam9260 driver.
>>> >> 
>>> >> 1、
>>> >> In function sc16is7x2_startup(),the spi chip select maintains low level after the setence cmds = sc16is7x2_alloc_spi_cmds(8).
>>> >> It caused a error about next SPI operation.
>>> >> 
>>> >> Improved method is to use 8 sc16is7x2_write_async() function to set sc16is7x2 reg.
>>> >> 
>>> >> 2、
>>> >> 
>>> >> In sc16is7x2_msg_add_fifo_tx() function, you need to take anti-cs_change variables.
>>> >> 
>>> >> 
>>> >> good luck!!!
>>> >> 
>>> >> 
>>> >> ======= 2010-12-14 11:52:00 您在来信中写道:=======
>>> >> 
>>>> >>> Hello again,
>>>> >>>
>>>> >>> The commands in sc16is7x2_spi_async are sent async (as the name says),
>>>> >>> so the first time you execute sc16is7x2_read(ts->spi, UART_IER,ch) the
>>>> >>> async part was not yet completed, the second time it was completed and
>>>> >>> has set UART_IER to 0.
>>>> >>>
>>>> >>> Regards,
>>>> >>> Manuel
>>>> >>>
>>>> >>> On 13.12.2010 06:43, changgx wrote:
>>>>> >>>>      hello,manuel.stahl:
>>>>> >>>>
>>>>> >>>>      excuse me!!
>>>>> >>>>
>>>>> >>>>      I found the sc16is7x2.c driver provided by you on the internet the
>>>>> >>>>      other day. And I explante it to my board.
>>>>> >>>>
>>>>> >>>>      My develop environment is about :CPU for AT91SAM9260 and kennel for
>>>>> >>>>      linux-2.6.27.
>>>>> >>>>
>>>>> >>>>      But I found some questions in debugging.
>>>>> >>>>
>>>>> >>>>      In the function of sc16is7x2_startup( ), i add the sentence to read
>>>>> >>>>      register value after sc16is7x2_spi_async(ts->spi, cmds, 8) sentence
>>>>> >>>>      and i find that the return value is always 0xff.
>>>>> >>>>
>>>>> >>>>      for example:
>>>>> >>>>
>>>>> >>>>      int uier1,uier2;
>>>>> >>>>
>>>>> >>>>      uier1 = sc16is7x2_read(ts->spi, UART_IER,ch);
>>>>> >>>>      SC16_PRINTK("+++++++++++++++++++++>  s :d UART_IER = x
>>>>> >>>>      \n",__func__,__LINE__,uier1);
>>>>> >>>>      uier2 = sc16is7x2_read(ts->spi, UART_IER,ch);
>>>>> >>>>      SC16_PRINTK("+++++++++++++++++++++>  s :d UART_IER = x
>>>>> >>>>      \n",__func__,__LINE__,uier2);
>>>>> >>>>
>>>>> >>>>      the print result:
>>>>> >>>>
>>>>> >>>>      +++++++++++++++++++++>  sc16is7x2_startup : 512 UART_IER = ff
>>>>> >>>>      +++++++++++++++++++++>  sc16is7x2_startup : 515 UART_IER = 0
>>>>> >>>>
>>>>> >>>>      The results is that the first time is 0xff, the secend is 0.
>>>>> >>>>
>>>>> >>>>      And it is same to read other register.
>>>>> >>>>
>>>>> >>>>      please give me some advice for this question.
>>>>> >>>>
>>>>> >>>>      ps: thank you very much for your open souce and look forward to your
>>>>> >>>>      email.
>>>>> >>>>
>>>>> >>>>      thanks!
>>>>> >>>>
>>>>> >>>>      kathy chang
>>>>> >>>>
>>>>> >>>>      2010-12-13
>>>>> >>>>
>>>>> >>>>      ------------------------------------------------
>>>>> >>>>
>>>>> >>>>      Email:changgx@163.com<mailto:changgx@163.com>
>>>>> >>>>
>>>>> >>>>      ------------------------------------------------
>>>>> >>>>
>>>>> >>>>
>>>>> >>>>
>>>>> >>>> = = = = = = = = = = = = = = = = = = = =
>>>>> >>>>         致
>>>>> >>>> 礼!
>>>>> >>>> changgx
>>>>> >>>> changgx@163.com<mailto:changgx@163.com>
>>>>> >>>> 2010-12-13
>>>>> >>>>               
>>>> >>>
>>>> >>>
>>>> >>> -- 
>>>> >>> Manuel Stahl
>>>> >>> Fraunhofer-Institut IIS
>>>> >>> Leistungsoptimierte Systeme
>>>> >>>
>>>> >>> Nordostpark 93
>>>> >>> D90411 Nürnberg
>>>> >>> Telefon  +49 (0)911/58061-6419
>>>> >>> Fax      +49 (0)911/58061-6398
>>>> >>> E-Mail   manuel.stahl@iis.fraunhofer.de
>>>> >>>
>>>> >>> http://www.iis.fraunhofer.de
>>>> >>> http://www.smart-power.fraunhofer.de
>>>> >>>
>>>> >>>
>>>> >>>
>>>> >>> __________ Information from ESET Smart Security, version of virus signature database 5563 (20101026) __________
>>>> >>>
>>>> >>> The message was checked by ESET Smart Security.
>>>> >>>
>>>> >>> http://www.eset.com
>>> >> 
>>> >> = = = = = = = = = = = = = = = = = = = =
>>> >> 			
>>> >> 
>>> >>         致
>>> >> 礼!
>>> >> 
>>> >> 				
>>> >>         changgx
>>> >>         changgx@163.com
>>> >>           2010-12-20
>>> >> 
>>> >> 
>>> >> 
>>> >> 
>> >
>> >
>> >-- 
>> >Manuel Stahl
>> >Fraunhofer-Institut IIS
>> >Leistungsoptimierte Systeme
>> >
>> >Nordostpark 93
>> >D90411 Nürnberg
>> >Telefon  +49 (0)911/58061-6419
>> >Fax      +49 (0)911/58061-6398
>> >E-Mail   manuel.stahl@iis.fraunhofer.de
>> >
>> >http://www.iis.fraunhofer.de
>> >http://www.smart-power.fraunhofer.de
>> >
>> >
>> >
>> >__________ Information from ESET Smart Security, version of virus signature database 5563 (20101026) __________
>> >
>> >The message was checked by ESET Smart Security.
>> >
>> >http://www.eset.com
> = = = = = = = = = = = = = = = = = = = =
> 			
> 
>         致
> 礼!
>  
> 				 
>         changgx
>         changgx@163.com
>           2010-12-20
> 
> 
> sa16is7x2.h
> 
> N\x18¬n‡r¥ªíÂ)emçhÂyhiם¢w^™©Ý
> 
> 
> sc16is7x2.c
> 
> N\x18¬n‡r¥ªíÂ)emçhÂyhiם¢w^™©Ý



[-- Attachment #2: Makefile --]
[-- Type: application/octet-stream, Size: 364 bytes --]

EXTRA_CFLAGS = -Wall -O2 -gstabs+
CROSS-COMPILE = arm-none-linux-gnueabi-
CC=$(CROSS-COMPILE)gcc
obj-m   := sc16is7x2.o
KDIR    := /home/at91sam9260ek/linux-2.6.27
PWD     := $(shell pwd) 
EXTRA_CFLAGS += -I$(obj)/../include
default: 
	$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
	rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.symvers test *.order

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: sa16is7x2.h --]
[-- Type: text/x-chdr; name="sa16is7x2.h", Size: 202 bytes --]

#ifndef LINUX_SPI_SC16IS752_H
#define LINUX_SPI_SC16IS752_H

struct sc16is7x2_platform_data {
	unsigned int	uartclk;
	/* uart line number of the first channel */
	unsigned	uart_base;
};

#endif

[-- Attachment #4: sc16is7x2.c --]
[-- Type: text/plain, Size: 35119 bytes --]

/**
 * drivers/serial/sc16is7x2.c
 *
 * Copyright (C) 2010 kathy chang changgx@163.com
 *
 * 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.
 *
 * The SC16IS7x2 device is a SPI driven dual UART with GPIOs.
 *
 * The driver exports two uarts .
 */

#define DEBUG 

#include <linux/irq.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/spi/spi.h>
#include <linux/freezer.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
#include <linux/gpio.h>
#include <linux/serial.h>

#include "sc16is7x2.h"

#define H_SPI_SPEED       (2*1000*1000)

#define SC16IS7X2_MAJOR		204
#define SC16IS7X2_MINOR		209
#define MAX_SC16IS7X2			2
#define FIFO_SIZE					64

#define PMC_PCER   0x10

#define DRIVER_NAME				"sc16is7x2"
#define TYPE_NAME					"SC16IS7x2"

#define REG_READ	0x80
#define REG_WRITE	0x00

/* Special registers */
#define REG_TXLVL	0x08	/* Transmitter FIFO Level register */
#define REG_RXLVL	0x09	/* Receiver FIFO Level register */
#define REG_IOD		0x0A	/* IO Direction register */
#define REG_IOS		0x0B	/* IO State register */
#define REG_IOI		0x0C	/* IO Interrupt Enable register */
#define REG_IOC		0x0E	/* IO Control register */

#define IOC_SRESET	0x08    /* Software reset */
#define IOC_GPIO30	0x04    /* GPIO 3:0 unset: as IO, set: as modem pins */
#define IOC_GPIO74	0x02    /* GPIO 7:4 unset: as IO, set: as modem pins */

#define IOC_IOLATCH 0x01 /* Unset: input unlatched, set: input latched */ 

/* Redefine some MCR bits */
#ifdef UART_MCR_TCRTLR
#undef UART_MCR_TCRTLR
#endif
#define UART_MCR_TCRTLR		0x04
#define UART_MCR_IRDA		0x40


#define WRITE_CMD(reg, ch) (REG_WRITE | (reg & 0xf) << 3 | (ch & 0x1) << 1)
#define READ_CMD(reg, ch)  (REG_READ  | (reg & 0xf) << 3 | (ch & 0x1) << 1)

static struct sc16is7x2_platform_data sc16is7x2_spi_data = {
	  .uartclk = 18432000,
	  .uart_base = 0,
};

/* 16bit SPI command to read or write a register */
struct sc16is7x2_spi_reg {
	u8 cmd;
	u8 value;
} __attribute__ ((packed));

struct sc16is7x2_chip;

/*
 * Some registers must be read back to modify.
 * To save time we cache them here in memory
 */
struct sc16is7x2_channel {
	struct sc16is7x2_chip	*chip;	/* back link */
	struct mutex		lock;
	struct uart_port 	uart;
	struct spi_transfer fifo_rx;
	struct spi_transfer fifo_tx[3];
	u8		iir;
	u8		lsr;
	u8		msr;
	u8		ier;		/* cache for IER register */
	u8		fcr;		/* cache for FCR register */
	u8		lcr;		/* cache for LCR register */
	u8		mcr;		/* cache for MCR register */
	u8		rxbuf[FIFO_SIZE+1];
	u8		write_fifo_cmd;
	u8		read_fifo_cmd;
	bool	active;
};

struct sc16is7x2_chip {
	struct spi_device *spi;

	struct mutex	 lock;
	struct sc16is7x2_channel channel[2];

	/* for handling irqs: need workqueue since we do spi_sync */
	struct workqueue_struct *workqueue;
	struct work_struct work;
	/* set to 1 to make the workhandler exit as soon as possible */
	int force_end_work;
	/* need to know we are suspending to avoid deadlock on workqueue */
	int suspending;

	struct spi_message fifo_message;

#define UART_BUG_TXEN	BIT(1)	/* UART has buggy TX IIR status */
#define UART_BUG_NOMSR	BIT(2)	/* UART has buggy MSR status bits (Au1x00) */
#define UART_BUG_THRE	BIT(3)	/* UART has buggy THRE reassertion */
	u16		bugs;		/* port bugs */

#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
	u8		lsr_saved_flags;
#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
	u8		msr_saved_flags;	
};


/* ******************************** SPI ********************************* */ 


/*
 * Reserve memory for command sequence
 * @param cnt number of commands
 */
static inline struct sc16is7x2_spi_reg *
sc16is7x2_alloc_spi_cmds(unsigned cnt)
{
	return kzalloc(sizeof(struct sc16is7x2_spi_reg)*cnt, GFP_KERNEL);
}

/*
 * sc16is7x2_add_write_cmd - Add write command to sequence
 */
static inline void sc16is7x2_add_write_cmd(struct sc16is7x2_spi_reg *cmd,
		u8 reg, u8 ch, u8 value)
{
	cmd->cmd = WRITE_CMD(reg, ch);
	cmd->value = value;
}

/*
 * sc16is7x2_add_read_cmd - Add read command to sequence
 */
static inline void sc16is7x2_add_read_cmd(struct sc16is7x2_spi_reg *cmd,
		u8 reg, u8 ch)
{
	cmd->cmd = READ_CMD(reg, ch);
	cmd->value = 0;
}

/*
 * sc16is7x2_complete - Completion handler for async SPI transfers
 */
static void sc16is7x2_complete(void *context)
{
	struct spi_message *m = context;
	u8 *tx_chain = m->state;
   
	kfree(tx_chain);
	kfree(m);
}

/*
 * sc16is7x2_spi_async - Send command sequence
 */
static int sc16is7x2_spi_async(struct spi_device *spi,
		struct sc16is7x2_spi_reg *cmds, unsigned len)
{
	
	struct spi_transfer *t;
	struct spi_message *m;

	m = spi_message_alloc(len, GFP_KERNEL);
	if (!m)
		return -ENOMEM;

	m->complete = sc16is7x2_complete;
	m->context = m;
	m->state = cmds;
	list_for_each_entry(t, &m->transfers, transfer_list) {
		t->tx_buf = (u8 *)cmds;
		t->len = 2;
		t->cs_change = false;
		//t->cs_change = true;
		cmds++;
	}
	
	return spi_async(spi, m);
}

/*
 * sc16is7x2_write_async - Write a new register content (async)
 */

static inline int sc16is7x2_write_async(struct spi_device *spi, u8 reg, u8 ch, 
		u8 value)
{
	struct sc16is7x2_spi_reg *cmd = sc16is7x2_alloc_spi_cmds(1);
	if (!cmd)
		return -ENOMEM;
	sc16is7x2_add_write_cmd(cmd, reg, ch, value);
	return sc16is7x2_spi_async(spi, cmd, 1);
}

/*
 * sc16is7x2_write - Write a new register content (sync)
 */
static int sc16is7x2_write(struct spi_device *spi, u8 reg, u8 ch, u8 val)
{
	u16 word = REG_WRITE | (reg & 0xf) << 3 | (ch & 0x3) << 1 | val << 8;
	return spi_write(spi, (const u8 *)&word, sizeof(word));
}

/**
 * sc16is7x2_read - Read back register content
 * @spi: The SPI device
 * @reg: Register offset
 *
 * Returns positive 8 bit value from device if successful or a
 * negative value on error
 */

static int sc16is7x2_read(struct spi_device *spi, unsigned reg, unsigned ch) 
{
	u8 cmd = REG_READ | (reg & 0xf) << 3 | (ch & 0x3) << 1;
	return spi_w8r8(spi, cmd);
}


/* ******************************** UART ********************************* */ 

/* Uart divisor latch write */

static inline void sc16is7x2_add_dl_write_cmd(struct sc16is7x2_spi_reg *cmd, 
		u8 ch, int value)
{
	sc16is7x2_add_write_cmd(&cmd[0], UART_DLL, ch, value & 0xff);
	sc16is7x2_add_write_cmd(&cmd[1], UART_DLM, ch, (value >> 8) & 0xff);	
}

static unsigned int sc16is7x2_tx_empty(struct uart_port *port)
{
	struct sc16is7x2_channel *chan =
			container_of(port, struct sc16is7x2_channel, uart);
	struct sc16is7x2_chip *ts = chan->chip;
	unsigned lsr;
  printk(KERN_DEBUG "---------> function call %s\n", __func__);
	dev_dbg(&ts->spi->dev, "%s\n", __func__);

	mutex_lock(&chan->lock);
	lsr = chan->lsr;
	mutex_unlock(&chan->lock);

	return lsr & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
}

static unsigned int sc16is7x2_get_mctrl(struct uart_port *port)
{
	struct sc16is7x2_channel *chan =
			container_of(port, struct sc16is7x2_channel, uart);
	struct sc16is7x2_chip *ts = chan->chip;
	unsigned int status;
	unsigned int ret;

	dev_dbg(&ts->spi->dev, "%s\n", __func__);
  printk(KERN_DEBUG "---------> function call %s\n", __func__);
	status = chan->msr;

	ret = 0;
	if (status & UART_MSR_DCD)
		ret |= TIOCM_CAR;
	if (status & UART_MSR_RI)
		ret |= TIOCM_RNG;
	if (status & UART_MSR_DSR)
		ret |= TIOCM_DSR;
	if (status & UART_MSR_CTS)
		ret |= TIOCM_CTS;
	return ret;
}

static unsigned int __set_mctrl(unsigned int mctrl)
{
	unsigned char mcr = 0;

	if (mctrl & TIOCM_RTS)
		mcr |= UART_MCR_RTS;
	if (mctrl & TIOCM_DTR)
		mcr |= UART_MCR_DTR;
	if (mctrl & TIOCM_LOOP)
		mcr |= UART_MCR_LOOP;

	return mcr;
}

static void sc16is7x2_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
	struct sc16is7x2_channel *chan =
			container_of(port, struct sc16is7x2_channel, uart);
	struct sc16is7x2_chip *ts = chan->chip;
	unsigned ch = port->line & 0x01;
  
  printk(KERN_DEBUG "---------> function call %s\n", __func__);
   
	dev_dbg(&ts->spi->dev, "%s\n", __func__);

  sc16is7x2_write_async(ts->spi, UART_MCR, ch, __set_mctrl(mctrl));
 
}

static inline void __stop_tx(struct sc16is7x2_channel *chan)
{
	struct sc16is7x2_chip *ts = chan->chip;
	unsigned ch = chan->uart.line & 0x01;
	if (chan->ier & UART_IER_THRI) {
		chan->ier &= ~UART_IER_THRI;
		sc16is7x2_write_async(ts->spi, UART_IER, ch, chan->ier);  
	}
}

static void sc16is7x2_stop_tx(struct uart_port *port)
{
	struct sc16is7x2_channel *chan =
			container_of(port, struct sc16is7x2_channel, uart);
	struct sc16is7x2_chip *ts = chan->chip;
  
  printk(KERN_DEBUG "---------> function call %s\n", __func__);
	dev_dbg(&ts->spi->dev, "%s\n", __func__);
	__stop_tx(chan);
}

/*
open
*/

static void sc16is7x2_start_tx(struct uart_port *port)
{
	struct sc16is7x2_channel *chan =
			container_of(port, struct sc16is7x2_channel, uart);
	struct sc16is7x2_chip *ts = chan->chip;
	unsigned ch = port->line & 0x01;
	
  printk(KERN_DEBUG "---------> function call %s\n", __func__);
	dev_dbg(&ts->spi->dev, "%s\n", __func__);

	if (!(chan->ier & UART_IER_THRI)) {
		chan->ier |= UART_IER_THRI;
   sc16is7x2_write_async(ts->spi, UART_IER, ch, chan->ier); 
	}
}

static void sc16is7x2_stop_rx(struct uart_port *port)
{
	struct sc16is7x2_channel *chan =
			container_of(port, struct sc16is7x2_channel, uart);
	struct sc16is7x2_chip *ts = chan->chip;
	unsigned ch = port->line & 0x01;
  
  printk(KERN_DEBUG "---------> function call %s\n", __func__);
	dev_dbg(&ts->spi->dev, "%s\n", __func__);

	chan->ier &= ~UART_IER_RLSI;
	chan->uart.read_status_mask &= ~UART_LSR_DR;
	sc16is7x2_write_async(ts->spi, UART_IER, ch, chan->ier);
}

static void sc16is7x2_enable_ms(struct uart_port *port)
{
	struct sc16is7x2_channel *chan =
			container_of(port, struct sc16is7x2_channel, uart);
	struct sc16is7x2_chip *ts = chan->chip;
	unsigned ch = port->line & 0x01;

	dev_dbg(&ts->spi->dev, "%s\n", __func__);
  printk(KERN_DEBUG "---------> function call %s\n", __func__);
	chan->ier |= UART_IER_MSI;
  sc16is7x2_write_async(ts->spi, UART_IER, ch, chan->ier);
}

static void sc16is7x2_break_ctl(struct uart_port *port, int break_state)
{
	struct sc16is7x2_channel *chan =
			container_of(port, struct sc16is7x2_channel, uart);
	struct sc16is7x2_chip *ts = chan->chip;
	unsigned ch = port->line & 0x01;
	unsigned long flags;
 
	dev_dbg(&ts->spi->dev, "%s\n", __func__);
  printk(KERN_DEBUG "---------> function call %s\n", __func__);
	spin_lock_irqsave(&chan->uart.lock, flags);
	if (break_state == -1)
		chan->lcr |= UART_LCR_SBC;
	else
		chan->lcr &= ~UART_LCR_SBC;
	spin_unlock_irqrestore(&chan->uart.lock, flags);

	sc16is7x2_write_async(ts->spi, UART_LCR, ch, chan->lcr);
}

static int sc16is7x2_startup(struct uart_port *port)
{
	struct sc16is7x2_channel *chan =
			container_of(port, struct sc16is7x2_channel, uart);
	struct sc16is7x2_chip *ts = chan->chip;
	unsigned ch = port->line & 0x01;
	unsigned long flags;
	
	dev_dbg(&ts->spi->dev, "%s (line %d)\n", __func__, port->line);	
	spin_lock_irqsave(&chan->uart.lock, flags);
	chan->lcr = UART_LCR_WLEN8;
	chan->mcr = __set_mctrl(chan->uart.mctrl);
	chan->fcr = 0;
	chan->ier = UART_IER_RLSI | UART_IER_RDI;
	spin_unlock_irqrestore(&chan->uart.lock, flags);

	{
	  u8 tmp;
	  sc16is7x2_write_async(ts->spi, UART_IER, ch,0);
	  tmp = sc16is7x2_read(ts->spi, UART_IIR, ch);
    tmp = sc16is7x2_read(ts->spi, UART_LSR, ch);
    tmp = sc16is7x2_read(ts->spi, UART_MSR, ch);
	  sc16is7x2_write_async(ts->spi, UART_FCR, ch,UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
	  sc16is7x2_write_async(ts->spi, UART_FCR, ch,chan->fcr);                                                       
	  sc16is7x2_write_async(ts->spi, UART_LCR, ch,chan->lcr);                                                       
	  sc16is7x2_write_async(ts->spi, UART_MCR, ch,chan->mcr);                                                      
	  
	}
	chan->active = true;
	return 0;
}

static void sc16is7x2_shutdown(struct uart_port *port)
{
	struct sc16is7x2_channel *chan =
			container_of(port, struct sc16is7x2_channel, uart);
	struct sc16is7x2_chip *ts = chan->chip;
	unsigned long flags;
	unsigned ch = port->line & 0x01;

	dev_dbg(&ts->spi->dev, "%s\n", __func__);

	BUG_ON(!chan);
	BUG_ON(!ts);

	if (ts->suspending)
		return;

	/* Disable interrupts from this port */
	chan->ier = 0;
	chan->active = false;
	sc16is7x2_write(ts->spi, UART_IER, ch, chan->ier);

	/* Wait for worker of this channel to finish */
	mutex_lock(&chan->lock);

	spin_lock_irqsave(&chan->uart.lock, flags);
	chan->mcr = __set_mctrl(chan->uart.mctrl);
	spin_unlock_irqrestore(&chan->uart.lock, flags);

	/* Disable break condition and FIFOs */
	chan->lcr &= ~UART_LCR_SBC;

	sc16is7x2_write(ts->spi, UART_MCR, ch, chan->mcr);
	sc16is7x2_write(ts->spi, UART_LCR, ch, chan->lcr);

	mutex_unlock(&chan->lock);
}

static void
sc16is7x2_set_termios(struct uart_port *port, struct ktermios *termios,
		       struct ktermios *old)
{
	struct sc16is7x2_channel *chan =
			container_of(port, struct sc16is7x2_channel, uart);
	struct sc16is7x2_chip *ts = chan->chip;
	unsigned ch = port->line & 0x01;
	unsigned long flags;
	unsigned int baud, quot;
	u8 ier, mcr, lcr, fcr = 0;
	u8 efr = UART_EFR_ECB;
	
  printk(KERN_DEBUG "---------> function call %s\n", __func__);
  
	/* set word length */
	switch (termios->c_cflag & CSIZE) {
	case CS5:
		lcr = UART_LCR_WLEN5;
		break;
	case CS6:
		lcr = UART_LCR_WLEN6;
		break;
	case CS7:
		lcr = UART_LCR_WLEN7;
		break;
	default:
	case CS8:
		lcr = UART_LCR_WLEN8;
		break;
	}

	if (termios->c_cflag & CSTOPB)
		lcr |= UART_LCR_STOP;
	if (termios->c_cflag & PARENB)
		lcr |= UART_LCR_PARITY;
	if (!(termios->c_cflag & PARODD))
		lcr |= UART_LCR_EPAR;
#ifdef CMSPAR
	if (termios->c_cflag & CMSPAR)
		lcr |= UART_LCR_SPAR;
#endif
   
	/* Ask the core to calculate the divisor for us. */
	baud = uart_get_baud_rate(port, termios, old,
				  port->uartclk / 16 / 0xffff,
				  port->uartclk / 16);  
	quot = uart_get_divisor(port, baud);

	dev_dbg(&ts->spi->dev, "%s (baud %u)\n", __func__, baud);


	/* configure the fifo */
	if (baud < 2400)
		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00;
	else
		fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_01;
		
	/*
	 * MCR-based auto flow control.  When AFE is enabled, RTS will be
	 * deasserted when the receive FIFO contains more characters than
	 * the trigger, or the MCR RTS bit is cleared.  In the case where
	 * the remote UART is not using CTS auto flow control, we must
	 * have sufficient FIFO entries for the latency of the remote
	 * UART to respond.  IOW, at least 32 bytes of FIFO.
	 */
	chan->mcr &= ~UART_MCR_AFE;
	if (termios->c_cflag & CRTSCTS)
		chan->mcr |= UART_MCR_AFE;

	/*
	 * Ok, we're now changing the port state.  Do it with
	 * interrupts disabled.
	 */
	spin_lock_irqsave(&chan->uart.lock, flags);

	/* we are sending char from a workqueue so enable */
//	chan->uart.state->port.tty->low_latency = 1;
   chan->uart.info->port.tty->low_latency = 1;
	/* Update the per-port timeout. */
	uart_update_timeout(port, termios->c_cflag, baud);

	chan->uart.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
	if (termios->c_iflag & INPCK)
		chan->uart.read_status_mask |= UART_LSR_FE | UART_LSR_PE;
	if (termios->c_iflag & (BRKINT | PARMRK))
		chan->uart.read_status_mask |= UART_LSR_BI;

	/* Characters to ignore */
	chan->uart.ignore_status_mask = 0;
	if (termios->c_iflag & IGNPAR)
		chan->uart.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;
	if (termios->c_iflag & IGNBRK) {
		chan->uart.ignore_status_mask |= UART_LSR_BI;
		/*
		 * If we're ignoring parity and break indicators,
		 * ignore overruns too (for real raw support).
		 */
		if (termios->c_iflag & IGNPAR)
			chan->uart.ignore_status_mask |= UART_LSR_OE;
	}

	/* ignore all characters if CREAD is not set */
	if ((termios->c_cflag & CREAD) == 0)
		chan->uart.ignore_status_mask |= UART_LSR_DR;

	/* CTS flow control flag and modem status interrupts */
	chan->ier &= ~UART_IER_MSI;
	if (UART_ENABLE_MS(&chan->uart, termios->c_cflag))
		chan->ier |= UART_IER_MSI;

	if (termios->c_cflag & CRTSCTS)
		efr |= UART_EFR_CTS | UART_EFR_RTS;

	mcr = __set_mctrl(chan->uart.mctrl);
	ier = chan->ier;
	chan->lcr = lcr;				/* Save LCR */
	chan->fcr = fcr;				/* Save FCR */
	chan->mcr = mcr;				/* Save MCR */

	fcr |= UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT;

	spin_unlock_irqrestore(&chan->uart.lock, flags);
  
  sc16is7x2_write_async(ts->spi, UART_LCR, ch,UART_LCR_DLAB);
  printk(KERN_DEBUG "+++++++++++++++++++> %s £º%d after write to read UART_LCR = %x \n",__func__,__LINE__,sc16is7x2_read(ts->spi, UART_LCR, ch));
  sc16is7x2_write_async(ts->spi, UART_DLL, ch,quot & 0xff);       
  sc16is7x2_write_async(ts->spi, UART_DLM, ch,(quot >> 8) & 0xff);
  sc16is7x2_write_async(ts->spi, UART_LCR, ch,0xBF);              
  sc16is7x2_write_async(ts->spi, UART_EFR, ch, efr);              
  sc16is7x2_write_async(ts->spi, UART_LCR, ch, lcr);              
  sc16is7x2_write_async(ts->spi, UART_FCR, ch, fcr);              
  sc16is7x2_write_async(ts->spi, UART_MCR, ch, mcr);              
  sc16is7x2_write_async(ts->spi, UART_IER, ch, ier); 
  
  #if 0 //for test
  {
    printk(KERN_DEBUG "+++++++++++++++++++> %s £º%d termios UART_LCR = %x lcr = %x\n",__func__,__LINE__,sc16is7x2_read(ts->spi, UART_LCR, ch),lcr);
    printk(KERN_DEBUG "+++++++++++++++++++> %s £º%d termios UART_LCR = %x lcr = %x\n",__func__,__LINE__,sc16is7x2_read(ts->spi, UART_LCR, ch),lcr);
    sc16is7x2_write(ts->spi, UART_LCR, ch,UART_LCR_DLAB);	  
	  printk(KERN_DEBUG "+++++++++++++++++++++> %s £º%d UART_LCR = %x  \n",__func__,__LINE__,sc16is7x2_read(ts->spi, UART_LCR,ch));
    printk(KERN_DEBUG "+++++++++++++++++++++> %s £º%d UART_DLL = %x  \n",__func__,__LINE__,sc16is7x2_read(ts->spi, UART_DLL,ch));
    printk(KERN_DEBUG "+++++++++++++++++++++> %s £º%d UART_DLM = %x  \n",__func__,__LINE__,sc16is7x2_read(ts->spi, UART_DLM,ch));
    
    printk(KERN_DEBUG "+++++++++++++++++++++> %s £º%d UART_MCR = %x  \n",__func__,__LINE__,sc16is7x2_read(ts->spi, UART_MCR,ch));
	  printk(KERN_DEBUG "+++++++++++++++++++++> %s £º%d UART_IER = %x  \n",__func__,__LINE__,sc16is7x2_read(ts->spi, UART_IER,ch));
    printk(KERN_DEBUG "+++++++++++++++++++++> %s £º%d UART_IIR = %x  \n",__func__,__LINE__,sc16is7x2_read(ts->spi, UART_IIR,ch));
    printk(KERN_DEBUG "+++++++++++++++++++++> %s £º%d UART_LSR = %x  \n",__func__,__LINE__,sc16is7x2_read(ts->spi, UART_LSR,ch));
    
    sc16is7x2_write(ts->spi, UART_LCR, ch,lcr);
    printk(KERN_DEBUG "+++++++++++++++++++++> %s £º%d after restore UART_LCR = %x  \n",__func__,__LINE__,sc16is7x2_read(ts->spi, UART_LCR,ch));
    
  }
  #endif

	/* Don't rewrite B0 */
	if (tty_termios_baud_rate(termios))
		tty_termios_encode_baud_rate(termios, baud, baud);

}

static const char *
sc16is7x2_type(struct uart_port *port)
{
	struct sc16is7x2_channel *chan =
			container_of(port, struct sc16is7x2_channel, uart);
	struct sc16is7x2_chip *ts = chan->chip;
	dev_dbg(&ts->spi->dev, "%s\n", __func__);
	return TYPE_NAME;
}

static void sc16is7x2_release_port(struct uart_port *port)
{
	struct sc16is7x2_channel *chan =
			container_of(port, struct sc16is7x2_channel, uart);
	struct sc16is7x2_chip *ts = chan->chip;
	dev_dbg(&ts->spi->dev, "%s\n", __func__);
	ts->force_end_work = 1;
}

static int sc16is7x2_request_port(struct uart_port *port)
{
	struct sc16is7x2_channel *chan =
			container_of(port, struct sc16is7x2_channel, uart);
	struct sc16is7x2_chip *ts = chan->chip;
	dev_dbg(&ts->spi->dev, "%s\n", __func__);
	return 0;
}

static void sc16is7x2_config_port(struct uart_port *port, int flags)
{
	struct sc16is7x2_channel *chan =
			container_of(port, struct sc16is7x2_channel, uart);
	struct sc16is7x2_chip *ts = chan->chip;
	dev_dbg(&ts->spi->dev, "%s\n", __func__);
	if (flags & UART_CONFIG_TYPE)
		chan->uart.type = PORT_SC16IS7X2;
}

static int
sc16is7x2_verify_port(struct uart_port *port, struct serial_struct *ser)
{
	struct sc16is7x2_channel *chan =
			container_of(port, struct sc16is7x2_channel, uart);
	struct sc16is7x2_chip *ts = chan->chip;
	dev_dbg(&ts->spi->dev, "%s\n", __func__);
	if (ser->irq < 0 || ser->baud_base < 9600 ||
			ser->type != PORT_SC16IS7X2)
		return -EINVAL;
	return 0;
}

static struct uart_ops sc16is7x2_uart_ops = {
	.tx_empty	= sc16is7x2_tx_empty,
	.set_mctrl	= sc16is7x2_set_mctrl, //open»áµ÷ÓÃ?????
	.get_mctrl	= sc16is7x2_get_mctrl,
	.stop_tx        = sc16is7x2_stop_tx,
	.start_tx	= sc16is7x2_start_tx,
	.stop_rx	= sc16is7x2_stop_rx,
	.enable_ms      = sc16is7x2_enable_ms,
	.break_ctl      = sc16is7x2_break_ctl,
	.startup	= sc16is7x2_startup,   //open µÄÈë¿Ú
	.shutdown	= sc16is7x2_shutdown,
	.set_termios	= sc16is7x2_set_termios, //open»áµ÷Óà tcgetattr 
	.type		= sc16is7x2_type,
	.release_port   = sc16is7x2_release_port,
	.request_port   = sc16is7x2_request_port,
	.config_port	= sc16is7x2_config_port,
	.verify_port	= sc16is7x2_verify_port,
};


#define MIN(a, b) ((a < b) ? (a) : (b))


/* ******************************** IRQ ********************************* */ 

static void sc16is7x2_handle_fifo_rx(struct sc16is7x2_channel *chan)
{
	struct uart_port *uart = &chan->uart;
	//struct tty_struct *tty = uart->state->port.tty;
	struct tty_struct *tty = uart->info->port.tty;
	u8 *rxbuf = chan->rxbuf;
	u8 lsr = chan->lsr;
	unsigned i, count = chan->fifo_rx.len;
	unsigned long flags;
	char flag = TTY_NORMAL;
  
  printk(KERN_DEBUG "---------> function call %s\n", __func__);
	spin_lock_irqsave(&uart->lock, flags);

	if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) {
		/*
		 * For statistics only
		 */
		if (lsr & UART_LSR_BI) {
			lsr &= ~(UART_LSR_FE | UART_LSR_PE);
			chan->uart.icount.brk++;
			/*
			 * We do the SysRQ and SAK checking
			 * here because otherwise the break
			 * may get masked by ignore_status_mask
			 * or read_status_mask.
			 */
			if (uart_handle_break(&chan->uart))
				goto ignore_char;
		} else if (lsr & UART_LSR_PE)
			chan->uart.icount.parity++;
		else if (lsr & UART_LSR_FE)
			chan->uart.icount.frame++;
		if (lsr & UART_LSR_OE)
			chan->uart.icount.overrun++;

		/*
		 * Mask off conditions which should be ignored.
		 */
		lsr &= chan->uart.read_status_mask;

		if (lsr & UART_LSR_BI)
			flag = TTY_BREAK;
		else if (lsr & UART_LSR_PE)
			flag = TTY_PARITY;
		else if (lsr & UART_LSR_FE)
			flag = TTY_FRAME;
	}

	for (i = 1; i < count; i++) {
		uart->icount.rx++;

		if (!uart_handle_sysrq_char(uart, rxbuf[i]))
			uart_insert_char(uart, lsr, UART_LSR_OE,
					rxbuf[i], flag);
	}

ignore_char:
	spin_unlock_irqrestore(&uart->lock, flags);

	if (count > 1)
		tty_flip_buffer_push(tty);
}

static void sc16is7x2_handle_fifo_tx(struct sc16is7x2_channel *chan)
{
	struct uart_port *uart = &chan->uart;
	//struct circ_buf *xmit = &uart->state->xmit;
	struct circ_buf *xmit = &uart->info->xmit;
	unsigned count = chan->fifo_tx[1].len + chan->fifo_tx[2].len;
	unsigned long flags;
 
	BUG_ON(!uart);
	BUG_ON(!xmit);  
  
	spin_lock_irqsave(&uart->lock, flags);

	uart->icount.tx += count;
	
	
	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
		uart_write_wakeup(uart);

	if (uart_circ_empty(xmit))
	{	
		__stop_tx(chan);
  }

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


static bool sc16is7x2_msg_add_fifo_rx(struct sc16is7x2_chip *ts, unsigned ch) 
{
	struct spi_message *m = &(ts->fifo_message);
	struct spi_transfer *t = &(ts->channel[ch].fifo_rx);
	int rxlvl = sc16is7x2_read(ts->spi, REG_RXLVL, ch);
	if (rxlvl > 0) {
		t->len = rxlvl + 1;
		spi_message_add_tail(t, m);
		return true;
	}
	return false;
}


static bool sc16is7x2_msg_add_fifo_tx(struct sc16is7x2_chip *ts, unsigned ch) 
{
	struct sc16is7x2_channel * const chan = &(ts->channel[ch]);
	struct uart_port *uart = &chan->uart;
	//struct circ_buf *xmit = &uart->state->xmit;
	struct circ_buf *xmit = &uart->info->xmit;
	unsigned count;
	bool split_transfer;
	u8 txlvl;
  printk(KERN_DEBUG "---------> function call %s\n", __func__);

	if (chan->uart.x_char && chan->lsr & UART_LSR_THRE) {
		dev_dbg(&ts->spi->dev, "tx: x-char\n");
		sc16is7x2_write(ts->spi, UART_TX, ch, uart->x_char);
		uart->icount.tx++;
		uart->x_char = 0;
		return false;
	}
	if (uart_tx_stopped(&chan->uart)) {
		dev_dbg(&ts->spi->dev, "tx: stopped!\n");
		sc16is7x2_stop_tx(uart);
		return false;
	}
	if (uart_circ_empty(xmit)) {
		__stop_tx(chan);
		return false;
	}

	txlvl = sc16is7x2_read(ts->spi, REG_TXLVL, ch);
	if (txlvl <= 0) {
		dev_dbg(&ts->spi->dev, " fifo full\n");
		return false;
	}

	/* number of bytes to transfer to the fifo */
	count = MIN(txlvl, uart_circ_chars_pending(xmit));  //uart_circ_chars_pending = ((head) - (tail)) & ((UART_XMIT_SIZE)-1)
  printk(KERN_DEBUG "+++++++++>kathy test%s:%d channel = %d bytes to transfer to the fifo = %d \n",__func__,__LINE__,ch,count);
	split_transfer = (UART_XMIT_SIZE - xmit->tail) <= count;
	/* add command transfer */
	spi_message_add_tail(&(chan->fifo_tx[0]), &(ts->fifo_message));
	/* add first fifo transfer */
	spi_message_add_tail(&(chan->fifo_tx[1]), &(ts->fifo_message));
  
	chan->fifo_tx[1].tx_buf = xmit->buf + xmit->tail;

	if (!split_transfer) {
		chan->fifo_tx[1].len = count;
		//chan->fifo_tx[1].cs_change = true;
		chan->fifo_tx[1].cs_change = false;

		chan->fifo_tx[2].len = 0;
	} else {
		chan->fifo_tx[1].len = (UART_XMIT_SIZE - 1) - xmit->tail;
//		chan->fifo_tx[1].cs_change = false;
    chan->fifo_tx[1].cs_change = true;

		chan->fifo_tx[2].tx_buf = xmit->buf;
	  chan->fifo_tx[2].cs_change = true;
//		chan->fifo_tx[2].cs_change = false;
		chan->fifo_tx[2].len = count - chan->fifo_tx[1].len;
		/* add second fifo transfer */
		spi_message_add_tail(&(chan->fifo_tx[2]), &(ts->fifo_message));
	}

	xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
	return true;
}
#if 0 //kathy chang delet 2010-11-22 10:14
static void sc16is7x2_handle_modem(struct sc16is7x2_chip *ts, unsigned ch)
{
	struct sc16is7x2_channel *chan = &(ts->channel[ch]);
	struct uart_port *uart = &chan->uart;

	if (chan->msr & UART_MSR_ANY_DELTA
			&& chan->ier & UART_IER_MSI
			&& uart->state != NULL) {
		if (chan->msr & UART_MSR_TERI)
			uart->icount.rng++;
		if (chan->msr & UART_MSR_DDSR)
			uart->icount.dsr++;
		if (chan->msr & UART_MSR_DDCD)
			uart_handle_dcd_change(uart, chan->msr & UART_MSR_DCD);
		if (chan->msr & UART_MSR_DCTS)
			uart_handle_cts_change(uart, chan->msr & UART_MSR_CTS);

		wake_up_interruptible(&uart->state->port.delta_msr_wait);
	}
}
#endif

static bool sc16is7x2_handle_channel(struct sc16is7x2_chip *ts, unsigned ch) 
{
	struct sc16is7x2_channel *chan = &(ts->channel[ch]);
	struct spi_message *m = &(ts->fifo_message);
	bool rx, tx;
  
  printk(KERN_DEBUG "---------> function call %s\n", __func__);
	dev_dbg(&ts->spi->dev, "%s (%i)\n", __func__, ch);

	chan->iir = sc16is7x2_read(ts->spi, UART_IIR, ch);
	chan->msr = sc16is7x2_read(ts->spi, UART_MSR, ch);
	chan->lsr = sc16is7x2_read(ts->spi, UART_LSR, ch);	

#if 0 //kathy chang delete 2010-11-22 10:13
	sc16is7x2_handle_modem(ts, ch);
#endif
	spi_message_init(m);
	rx = sc16is7x2_msg_add_fifo_rx(ts, ch);
	tx = sc16is7x2_msg_add_fifo_tx(ts, ch);
  printk(KERN_DEBUG "+++++++++>kathy test%s:%d rx %d tx =%d\n",__func__,__LINE__,rx,tx);
	if (rx || tx)
		spi_sync(ts->spi, m);
  
	if (rx)
		sc16is7x2_handle_fifo_rx(chan);
	if (tx)
		sc16is7x2_handle_fifo_tx(chan);

	dev_dbg(&ts->spi->dev, "%s finished (iir = 0x%02x)\n",
			__func__, chan->iir);

	return (chan->iir & UART_IIR_NO_INT) == 0x00; //
}

static void sc16is7x2_work(struct work_struct *w)
{
	struct sc16is7x2_chip *ts =
			container_of(w, struct sc16is7x2_chip, work);
	unsigned pending = 0;
	unsigned ch = 0;
  
  printk(KERN_DEBUG "---------> function call %s\n", __func__);
	dev_dbg(&ts->spi->dev, "%s\n", __func__);
	BUG_ON(!w);
	BUG_ON(!ts);


	if (ts->force_end_work) {
		dev_dbg(&ts->spi->dev, "%s: force end!\n", __func__);
		return;
	}

	if (ts->channel[0].active)
		pending |= BIT(0);
	if (ts->channel[1].active)
		pending |= BIT(1);

	do {
		mutex_lock(&(ts->channel[ch].lock));
		if (pending & BIT(ch) && ts->channel[ch].active) {
			if (!sc16is7x2_handle_channel(ts, ch))
				pending &= ~BIT(ch);
		}
		mutex_unlock(&(ts->channel[ch].lock));
		ch ^= 1;	/* switch channel */
	} while (!ts->force_end_work && !freezing(current) && pending);

	dev_dbg(&ts->spi->dev, "%s finished\n", __func__);
}

static irqreturn_t sc16is7x2_interrupt(int irq, void *dev_id)
{
	struct sc16is7x2_chip *ts = dev_id;
 
  printk(KERN_DEBUG "---------> sc16is7x2_interrupt function call %s\n", __func__);
  
	dev_dbg(&ts->spi->dev, "%s\n", __func__); 
	
	
	if (!ts->force_end_work && !work_pending(&ts->work) &&
	    !freezing(current) && !ts->suspending)
	{		
		queue_work(ts->workqueue, &ts->work);
	}
	
	return IRQ_HANDLED;
}


/* ******************************** INIT ********************************* */ 

static struct uart_driver sc16is7x2_uart_driver;


static int sc16is7x2_register_uart_port(struct sc16is7x2_chip *ts,
		struct sc16is7x2_platform_data *pdata, unsigned ch)
{
	struct sc16is7x2_channel *chan = &(ts->channel[ch]);
	struct uart_port *uart = &chan->uart;

	mutex_init(&chan->lock);
	chan->active = false;	/* will be set in startup */
	chan->chip = ts;

	chan->read_fifo_cmd = READ_CMD(UART_RX, ch);
	chan->fifo_rx.tx_buf = &(chan->read_fifo_cmd);
	chan->fifo_rx.rx_buf = chan->rxbuf;
//	chan->fifo_rx.cs_change = true;
  chan->fifo_rx.cs_change = false;

	chan->write_fifo_cmd = WRITE_CMD(UART_TX, ch);
	chan->fifo_tx[0].tx_buf = &(chan->write_fifo_cmd);
	chan->fifo_tx[0].rx_buf = NULL;
	chan->fifo_tx[0].len = 1;
	chan->fifo_tx[0].cs_change = false;
	chan->fifo_tx[1].rx_buf = NULL;
	chan->fifo_tx[2].rx_buf = NULL;

	uart->irq = ts->spi->irq;
	uart->uartclk = pdata->uartclk;
	uart->fifosize = FIFO_SIZE;
	uart->ops = &sc16is7x2_uart_ops;
	uart->flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
	uart->line = pdata->uart_base + ch;
	uart->type = PORT_SC16IS7X2;
	uart->dev = &ts->spi->dev;
 
	return uart_add_one_port(&sc16is7x2_uart_driver, uart);
}

static int __devinit sc16is7x2_probe(struct spi_device *spi)
{
	struct sc16is7x2_chip *ts;
	struct sc16is7x2_platform_data *pdata;
	int ret;
  printk(KERN_DEBUG "---------> function call %s\n", __func__);


  spi->max_speed_hz = H_SPI_SPEED; //can modify
	pdata = &sc16is7x2_spi_data;

	ret = spi_setup(spi);
	if (ret < 0)
		return ret;

	ts = kzalloc(sizeof(struct sc16is7x2_chip), GFP_KERNEL);
	if (!ts)
		return -ENOMEM;

	mutex_init(&ts->lock);
	dev_set_drvdata(&spi->dev, ts);
	ts->spi = spi;
	ts->force_end_work = 1;

	/* Reset the chip TODO: and disable IRQ output */
	sc16is7x2_write(spi, REG_IOC, 0, IOC_SRESET);
  
  at91_sys_write(AT91_PMC+PMC_PCER,1<<spi->irq);
	at91_set_gpio_input(AT91_PIN_PC12, 1);
  at91_set_A_periph(AT91_PIN_PC12, 1);

	at91_sys_write(AT91_AIC_SMR(spi->irq),(1<<5)|7);
	at91_sys_write(AT91_AIC_ICCR,1<<spi->irq);

  printk(KERN_DEBUG "+++++++++++++++++++++> %s £º%d  AT91_AIC_SMR(29) %x  \n",__func__,__LINE__,at91_sys_read(AT91_AIC_SMR(spi->irq)));
  
	ret = request_irq(spi->irq, sc16is7x2_interrupt,0, "sc16is7x2", ts);
	if (ret)
  {
    printk(KERN_INFO "ERROR: can't get assigned irq %d \n\r", spi->irq);         
  }  


	if (ret) {
		dev_warn(&ts->spi->dev, "cannot register interrupt\n");
		goto exit_destroy;
	}
  
	ret = sc16is7x2_register_uart_port(ts, pdata, 0);
	if (ret)
		goto exit_irq;
	 
	ret = sc16is7x2_register_uart_port(ts, pdata, 1);
	if (ret)
		goto exit_uart0;

	ts->workqueue = create_freezeable_workqueue(DRIVER_NAME);
	if (!ts->workqueue) {
		dev_warn(&ts->spi->dev, "cannot create workqueue\n");
		ret = -EBUSY;
    goto exit_uart1;
	}
	INIT_WORK(&ts->work, sc16is7x2_work);
	ts->force_end_work = 0;
  printk(KERN_INFO DRIVER_NAME " at CS%d (irq %d), 2 UARTs ttySC%d, ttySC%d is successful!!!!\n",
			spi->chip_select, spi->irq,pdata->uart_base, pdata->uart_base + 1);  
	return ret;

exit_uart1:
	uart_remove_one_port(&sc16is7x2_uart_driver, &ts->channel[1].uart);

exit_uart0:
	uart_remove_one_port(&sc16is7x2_uart_driver, &ts->channel[0].uart);

exit_irq:
	free_irq(spi->irq, ts);

exit_destroy:
	dev_set_drvdata(&spi->dev, NULL);
	mutex_destroy(&ts->lock);
	kfree(ts);
	return ret;
}

static int __devexit sc16is7x2_remove(struct spi_device *spi)
{
	struct sc16is7x2_chip *ts;
	int ret;

	ts = dev_get_drvdata(&spi->dev);
	
	if (ts == NULL)
		return -ENODEV;
	free_irq(spi->irq, ts);
	ts->force_end_work = 1;
	if (ts->workqueue) {
		flush_workqueue(ts->workqueue);
		destroy_workqueue(ts->workqueue);
		ts->workqueue = NULL;
	}
	dev_set_drvdata(&spi->dev, NULL);
	ret = uart_remove_one_port(&sc16is7x2_uart_driver,
			&ts->channel[0].uart);
	if (ret) {
		dev_err(&spi->dev, "Failed to remove the UART port 0: %d\n",
			ret);
		goto exit_error;
	}
	ret = uart_remove_one_port(&sc16is7x2_uart_driver,
			&ts->channel[1].uart);
	if (ret) {
		dev_err(&spi->dev, "Failed to remove the UART port 1: %d\n",
			ret);
		goto exit_error;
	}

	mutex_destroy(&ts->lock);
	kfree(ts);

exit_error:
	return ret;
}

static struct uart_driver sc16is7x2_uart_driver = {
	.owner          = THIS_MODULE,
	.driver_name    = DRIVER_NAME,
	.dev_name       = "ttySC",
	.major          = SC16IS7X2_MAJOR,
	.minor          = SC16IS7X2_MINOR,
	.nr             = MAX_SC16IS7X2,
};

static struct spi_driver sc16is7x2_spi_driver = {
	.driver = {
		.name		= DRIVER_NAME,
		.bus    = &spi_bus_type,
		.owner  = THIS_MODULE,
	},
	.probe		= sc16is7x2_probe,
	.remove		= __devexit_p(sc16is7x2_remove),
};

static int __init sc16is7x2_init(void)
{
	int ret;	
	
	ret = uart_register_driver(&sc16is7x2_uart_driver);
	if (ret) {
		printk(KERN_ERR "Couldn't register sc16is7x2 uart driver\n");
		return ret;
	}	
	return spi_register_driver(&sc16is7x2_spi_driver);
}

module_init(sc16is7x2_init);

static void __exit sc16is7x2_exit(void)
{	
	spi_unregister_driver(&sc16is7x2_spi_driver);	
	uart_unregister_driver(&sc16is7x2_uart_driver);
}
module_exit(sc16is7x2_exit);

MODULE_AUTHOR("kathy chang");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("SC16IS7x2 SPI based UART chip");
MODULE_ALIAS("spi:" DRIVER_NAME);

[-- Attachment #5: manuel_stahl.vcf --]
[-- Type: text/x-vcard, Size: 170 bytes --]

begin:vcard
fn:Manuel Stahl
n:Stahl;Manuel
email;internet:manuel.stahl@iis.fraunhofer.de
tel;work:+49 911 58061-6419
x-mozilla-html:FALSE
version:2.1
end:vcard


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: about sc16is7x2 drivier
       [not found] ` <4D05B269.1C890F.09519-Qw2Xm1po45t0mzObsfW3tA@public.gmane.org>
@ 2010-12-14 10:12   ` Manuel Stahl
  0 siblings, 0 replies; 3+ messages in thread
From: Manuel Stahl @ 2010-12-14 10:12 UTC (permalink / raw)
  To: changgx
  Cc: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f,
	linux-serial-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 2454 bytes --]

Hello Kathy,

this problem has been reported several times now. I'm still not sure
where the error is located. Please CC your mail related to sc16is7x2
also to the serial and spi kernel mailing lists.

Regards,
Manuel Stahl

On 13.12.2010 06:43, changgx wrote:
>     hello,manuel.stahl:
> 
>     excuse me!!
> 
>     I found the sc16is7x2.c driver provided by you on the internet the
>     other day. And I explante it to my board.
> 
>     My develop environment is about :CPU for AT91SAM9260 and kennel for
>     linux-2.6.27.
> 
>     But I found some questions in debugging.
> 
>     In the function of sc16is7x2_startup( ), i add the sentence to read
>     register value after sc16is7x2_spi_async(ts->spi, cmds, 8) sentence
>     and i find that the return value is always 0xff.
> 
>     for example:
> 
>     int uier1,uier2;
> 
>     uier1 = sc16is7x2_read(ts->spi, UART_IER,ch);
>     SC16_PRINTK("+++++++++++++++++++++> %s :%d UART_IER = %x
>     \n",__func__,__LINE__,uier1);
>     uier2 = sc16is7x2_read(ts->spi, UART_IER,ch);
>     SC16_PRINTK("+++++++++++++++++++++> %s :%d UART_IER = %x
>     \n",__func__,__LINE__,uier2);
> 
>     the print result:
> 
>     +++++++++++++++++++++> sc16is7x2_startup : 512 UART_IER = ff
>     +++++++++++++++++++++> sc16is7x2_startup : 515 UART_IER = 0
> 
>     The results is that the first time is 0xff, the secend is 0.
> 
>     And it is same to read other register.
> 
>     please give me some advice for this question.
> 
>     ps: thank you very much for your open souce and look forward to your
>     email.
> 
>     thanks!
> 
>     kathy chang
> 
>     2010-12-13
> 
>     ------------------------------------------------
> 
>     Email:changgx-9Onoh4P/yGk@public.gmane.org <mailto:changgx-9Onoh4P/yGk@public.gmane.org>
> 
>     ------------------------------------------------
> 
> 
> 
> = = = = = = = = = = = = = = = = = = = =
>         致
> 礼!
> changgx
> changgx-9Onoh4P/yGk@public.gmane.org <mailto:changgx-9Onoh4P/yGk@public.gmane.org>
> 2010-12-13
>               


-- 
Manuel Stahl
Fraunhofer-Institut IIS
Leistungsoptimierte Systeme

Nordostpark 93
D90411 Nürnberg
Telefon  +49 (0)911/58061-6419
Fax      +49 (0)911/58061-6398
E-Mail   manuel.stahl-GeUHRtUQU7nSyEMIgutvibNAH6kLmebB@public.gmane.org

http://www.iis.fraunhofer.de
http://www.smart-power.fraunhofer.de

[-- Attachment #2: Type: text/plain, Size: 290 bytes --]

------------------------------------------------------------------------------
Lotusphere 2011
Register now for Lotusphere 2011 and learn how
to connect the dots, take your collaborative environment
to the next level, and enter the era of Social Business.
http://p.sf.net/sfu/lotusphere-d2d

[-- Attachment #3: Type: text/plain, Size: 210 bytes --]

_______________________________________________
spi-devel-general mailing list
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/spi-devel-general

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2010-12-20 10:03 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <4D0F1B6A.0A69AA.31769@m50-133.163.com>
2010-12-20  9:09 ` Fw: about sc16is7x2 drivier Manuel Stahl
2010-12-20 10:03   ` Manuel Stahl
     [not found] <4D05B269.1C890F.09519@m12-11.163.com>
     [not found] ` <4D05B269.1C890F.09519-Qw2Xm1po45t0mzObsfW3tA@public.gmane.org>
2010-12-14 10:12   ` Manuel Stahl

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).