| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * SuperH IrDA Driver | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2010 Renesas Solutions Corp. | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:37 +00:00
										 |  |  |  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Based on sh_sir.c | 
					
						
							|  |  |  |  * Copyright (C) 2009 Renesas Solutions Corp. | 
					
						
							|  |  |  |  * Copyright 2006-2009 Analog Devices Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * CAUTION | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This driver is very simple. | 
					
						
							|  |  |  |  * So, it doesn't have below support now | 
					
						
							|  |  |  |  *  - MIR/FIR support | 
					
						
							|  |  |  |  *  - DMA transfer support | 
					
						
							|  |  |  |  *  - FIFO mode support | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-08-10 23:25:42 +00:00
										 |  |  | #include <linux/io.h>
 | 
					
						
							|  |  |  | #include <linux/interrupt.h>
 | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | #include <linux/module.h>
 | 
					
						
							|  |  |  | #include <linux/platform_device.h>
 | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:48 +00:00
										 |  |  | #include <linux/pm_runtime.h>
 | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | #include <linux/clk.h>
 | 
					
						
							|  |  |  | #include <net/irda/wrapper.h>
 | 
					
						
							|  |  |  | #include <net/irda/irda_device.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define DRIVER_NAME "sh_irda"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define __IRDARAM_LEN	0x1039
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define IRTMR		0x1F00 /* Transfer mode */
 | 
					
						
							|  |  |  | #define IRCFR		0x1F02 /* Configuration */
 | 
					
						
							|  |  |  | #define IRCTR		0x1F04 /* IR control */
 | 
					
						
							|  |  |  | #define IRTFLR		0x1F20 /* Transmit frame length */
 | 
					
						
							|  |  |  | #define IRTCTR		0x1F22 /* Transmit control */
 | 
					
						
							|  |  |  | #define IRRFLR		0x1F40 /* Receive frame length */
 | 
					
						
							|  |  |  | #define IRRCTR		0x1F42 /* Receive control */
 | 
					
						
							|  |  |  | #define SIRISR		0x1F60 /* SIR-UART mode interrupt source */
 | 
					
						
							|  |  |  | #define SIRIMR		0x1F62 /* SIR-UART mode interrupt mask */
 | 
					
						
							|  |  |  | #define SIRICR		0x1F64 /* SIR-UART mode interrupt clear */
 | 
					
						
							|  |  |  | #define SIRBCR		0x1F68 /* SIR-UART mode baud rate count */
 | 
					
						
							|  |  |  | #define MFIRISR		0x1F70 /* MIR/FIR mode interrupt source */
 | 
					
						
							|  |  |  | #define MFIRIMR		0x1F72 /* MIR/FIR mode interrupt mask */
 | 
					
						
							|  |  |  | #define MFIRICR		0x1F74 /* MIR/FIR mode interrupt clear */
 | 
					
						
							|  |  |  | #define CRCCTR		0x1F80 /* CRC engine control */
 | 
					
						
							|  |  |  | #define CRCIR		0x1F86 /* CRC engine input data */
 | 
					
						
							|  |  |  | #define CRCCR		0x1F8A /* CRC engine calculation */
 | 
					
						
							|  |  |  | #define CRCOR		0x1F8E /* CRC engine output data */
 | 
					
						
							|  |  |  | #define FIFOCP		0x1FC0 /* FIFO current pointer */
 | 
					
						
							|  |  |  | #define FIFOFP		0x1FC2 /* FIFO follow pointer */
 | 
					
						
							|  |  |  | #define FIFORSMSK	0x1FC4 /* FIFO receive status mask */
 | 
					
						
							|  |  |  | #define FIFORSOR	0x1FC6 /* FIFO receive status OR */
 | 
					
						
							|  |  |  | #define FIFOSEL		0x1FC8 /* FIFO select */
 | 
					
						
							|  |  |  | #define FIFORS		0x1FCA /* FIFO receive status */
 | 
					
						
							|  |  |  | #define FIFORFL		0x1FCC /* FIFO receive frame length */
 | 
					
						
							|  |  |  | #define FIFORAMCP	0x1FCE /* FIFO RAM current pointer */
 | 
					
						
							|  |  |  | #define FIFORAMFP	0x1FD0 /* FIFO RAM follow pointer */
 | 
					
						
							|  |  |  | #define BIFCTL		0x1FD2 /* BUS interface control */
 | 
					
						
							|  |  |  | #define IRDARAM		0x0000 /* IrDA buffer RAM */
 | 
					
						
							|  |  |  | #define IRDARAM_LEN	__IRDARAM_LEN /* - 8/16/32 (read-only for 32) */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* IRTMR */ | 
					
						
							|  |  |  | #define TMD_MASK	(0x3 << 14) /* Transfer Mode */
 | 
					
						
							|  |  |  | #define TMD_SIR		(0x0 << 14)
 | 
					
						
							|  |  |  | #define TMD_MIR		(0x3 << 14)
 | 
					
						
							|  |  |  | #define TMD_FIR		(0x2 << 14)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define FIFORIM		(1 << 8) /* FIFO receive interrupt mask */
 | 
					
						
							|  |  |  | #define MIM		(1 << 4) /* MIR/FIR Interrupt Mask */
 | 
					
						
							|  |  |  | #define SIM		(1 << 0) /* SIR Interrupt Mask */
 | 
					
						
							|  |  |  | #define xIM_MASK	(FIFORIM | MIM | SIM)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* IRCFR */ | 
					
						
							|  |  |  | #define RTO_SHIFT	8 /* shift for Receive Timeout */
 | 
					
						
							|  |  |  | #define RTO		(0x3 << RTO_SHIFT)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* IRTCTR */ | 
					
						
							|  |  |  | #define ARMOD		(1 << 15) /* Auto-Receive Mode */
 | 
					
						
							|  |  |  | #define TE		(1 <<  0) /* Transmit Enable */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* IRRFLR */ | 
					
						
							|  |  |  | #define RFL_MASK	(0x1FFF) /* mask for Receive Frame Length */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* IRRCTR */ | 
					
						
							|  |  |  | #define RE		(1 <<  0) /* Receive Enable */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * SIRISR,  SIRIMR,  SIRICR, | 
					
						
							|  |  |  |  * MFIRISR, MFIRIMR, MFIRICR | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #define FRE		(1 << 15) /* Frame Receive End */
 | 
					
						
							|  |  |  | #define TROV		(1 << 11) /* Transfer Area Overflow */
 | 
					
						
							|  |  |  | #define xIR_9		(1 << 9)
 | 
					
						
							|  |  |  | #define TOT		xIR_9     /* for SIR     Timeout */
 | 
					
						
							|  |  |  | #define ABTD		xIR_9     /* for MIR/FIR Abort Detection */
 | 
					
						
							|  |  |  | #define xIR_8		(1 << 8)
 | 
					
						
							|  |  |  | #define FER		xIR_8     /* for SIR     Framing Error */
 | 
					
						
							|  |  |  | #define CRCER		xIR_8     /* for MIR/FIR CRC error */
 | 
					
						
							|  |  |  | #define FTE		(1 << 7)  /* Frame Transmit End */
 | 
					
						
							|  |  |  | #define xIR_MASK	(FRE | TROV | xIR_9 | xIR_8 | FTE)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* SIRBCR */ | 
					
						
							|  |  |  | #define BRC_MASK	(0x3F) /* mask for Baud Rate Count */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* CRCCTR */ | 
					
						
							|  |  |  | #define CRC_RST		(1 << 15) /* CRC Engine Reset */
 | 
					
						
							|  |  |  | #define CRC_CT_MASK	0x0FFF    /* mask for CRC Engine Input Data Count */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* CRCIR */ | 
					
						
							|  |  |  | #define CRC_IN_MASK	0x0FFF    /* mask for CRC Engine Input Data */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /************************************************************************
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			enum / structure | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ************************************************************************/ | 
					
						
							|  |  |  | enum sh_irda_mode { | 
					
						
							|  |  |  | 	SH_IRDA_NONE = 0, | 
					
						
							|  |  |  | 	SH_IRDA_SIR, | 
					
						
							|  |  |  | 	SH_IRDA_MIR, | 
					
						
							|  |  |  | 	SH_IRDA_FIR, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct sh_irda_self; | 
					
						
							|  |  |  | struct sh_irda_xir_func { | 
					
						
							|  |  |  | 	int (*xir_fre)	(struct sh_irda_self *self); | 
					
						
							|  |  |  | 	int (*xir_trov)	(struct sh_irda_self *self); | 
					
						
							|  |  |  | 	int (*xir_9)	(struct sh_irda_self *self); | 
					
						
							|  |  |  | 	int (*xir_8)	(struct sh_irda_self *self); | 
					
						
							|  |  |  | 	int (*xir_fte)	(struct sh_irda_self *self); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct sh_irda_self { | 
					
						
							|  |  |  | 	void __iomem		*membase; | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:37 +00:00
										 |  |  | 	unsigned int		irq; | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:48 +00:00
										 |  |  | 	struct platform_device	*pdev; | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	struct net_device	*ndev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	struct irlap_cb		*irlap; | 
					
						
							|  |  |  | 	struct qos_info		qos; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	iobuff_t		tx_buff; | 
					
						
							|  |  |  | 	iobuff_t		rx_buff; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	enum sh_irda_mode	mode; | 
					
						
							|  |  |  | 	spinlock_t		lock; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	struct sh_irda_xir_func	*xir_func; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /************************************************************************
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			common function | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ************************************************************************/ | 
					
						
							|  |  |  | static void sh_irda_write(struct sh_irda_self *self, u32 offset, u16 data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock_irqsave(&self->lock, flags); | 
					
						
							|  |  |  | 	iowrite16(data, self->membase + offset); | 
					
						
							|  |  |  | 	spin_unlock_irqrestore(&self->lock, flags); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static u16 sh_irda_read(struct sh_irda_self *self, u32 offset) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	u16 ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock_irqsave(&self->lock, flags); | 
					
						
							|  |  |  | 	ret = ioread16(self->membase + offset); | 
					
						
							|  |  |  | 	spin_unlock_irqrestore(&self->lock, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void sh_irda_update_bits(struct sh_irda_self *self, u32 offset, | 
					
						
							|  |  |  | 			       u16 mask, u16 data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 	u16 old, new; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock_irqsave(&self->lock, flags); | 
					
						
							|  |  |  | 	old = ioread16(self->membase + offset); | 
					
						
							|  |  |  | 	new = (old & ~mask) | data; | 
					
						
							|  |  |  | 	if (old != new) | 
					
						
							|  |  |  | 		iowrite16(data, self->membase + offset); | 
					
						
							|  |  |  | 	spin_unlock_irqrestore(&self->lock, flags); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /************************************************************************
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			mode function | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ************************************************************************/ | 
					
						
							|  |  |  | /*=====================================
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *		common | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *=====================================*/ | 
					
						
							|  |  |  | static void sh_irda_rcv_ctrl(struct sh_irda_self *self, int enable) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct device *dev = &self->ndev->dev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sh_irda_update_bits(self, IRRCTR, RE, enable ? RE : 0); | 
					
						
							|  |  |  | 	dev_dbg(dev, "recv %s\n", enable ? "enable" : "disable"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int sh_irda_set_timeout(struct sh_irda_self *self, int interval) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct device *dev = &self->ndev->dev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (SH_IRDA_SIR != self->mode) | 
					
						
							|  |  |  | 		interval = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (interval < 0 || interval > 2) { | 
					
						
							|  |  |  | 		dev_err(dev, "unsupported timeout interval\n"); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sh_irda_update_bits(self, IRCFR, RTO, interval << RTO_SHIFT); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int sh_irda_set_baudrate(struct sh_irda_self *self, int baudrate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct device *dev = &self->ndev->dev; | 
					
						
							|  |  |  | 	u16 val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (baudrate < 0) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (SH_IRDA_SIR != self->mode) { | 
					
						
							|  |  |  | 		dev_err(dev, "it is not SIR mode\n"); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Baud rate (bits/s) = | 
					
						
							|  |  |  | 	 *   (48 MHz / 26) / (baud rate counter value + 1) x 16 | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	val = (48000000 / 26 / 16 / baudrate) - 1; | 
					
						
							|  |  |  | 	dev_dbg(dev, "baudrate = %d,  val = 0x%02x\n", baudrate, val); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sh_irda_update_bits(self, SIRBCR, BRC_MASK, val); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:22 +00:00
										 |  |  | static int sh_irda_get_rcv_length(struct sh_irda_self *self) | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	return RFL_MASK & sh_irda_read(self, IRRFLR); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*=====================================
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *		NONE MODE | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *=====================================*/ | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:22 +00:00
										 |  |  | static int sh_irda_xir_fre(struct sh_irda_self *self) | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct device *dev = &self->ndev->dev; | 
					
						
							|  |  |  | 	dev_err(dev, "none mode: frame recv\n"); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:22 +00:00
										 |  |  | static int sh_irda_xir_trov(struct sh_irda_self *self) | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct device *dev = &self->ndev->dev; | 
					
						
							|  |  |  | 	dev_err(dev, "none mode: buffer ram over\n"); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:22 +00:00
										 |  |  | static int sh_irda_xir_9(struct sh_irda_self *self) | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct device *dev = &self->ndev->dev; | 
					
						
							|  |  |  | 	dev_err(dev, "none mode: time over\n"); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:22 +00:00
										 |  |  | static int sh_irda_xir_8(struct sh_irda_self *self) | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct device *dev = &self->ndev->dev; | 
					
						
							|  |  |  | 	dev_err(dev, "none mode: framing error\n"); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:22 +00:00
										 |  |  | static int sh_irda_xir_fte(struct sh_irda_self *self) | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct device *dev = &self->ndev->dev; | 
					
						
							|  |  |  | 	dev_err(dev, "none mode: frame transmit end\n"); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:22 +00:00
										 |  |  | static struct sh_irda_xir_func sh_irda_xir_func = { | 
					
						
							|  |  |  | 	.xir_fre	= sh_irda_xir_fre, | 
					
						
							|  |  |  | 	.xir_trov	= sh_irda_xir_trov, | 
					
						
							|  |  |  | 	.xir_9		= sh_irda_xir_9, | 
					
						
							|  |  |  | 	.xir_8		= sh_irda_xir_8, | 
					
						
							|  |  |  | 	.xir_fte	= sh_irda_xir_fte, | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*=====================================
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *		MIR/FIR MODE | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * MIR/FIR are not supported now | 
					
						
							|  |  |  |  *=====================================*/ | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:22 +00:00
										 |  |  | static struct sh_irda_xir_func sh_irda_mfir_func = { | 
					
						
							|  |  |  | 	.xir_fre	= sh_irda_xir_fre, | 
					
						
							|  |  |  | 	.xir_trov	= sh_irda_xir_trov, | 
					
						
							|  |  |  | 	.xir_9		= sh_irda_xir_9, | 
					
						
							|  |  |  | 	.xir_8		= sh_irda_xir_8, | 
					
						
							|  |  |  | 	.xir_fte	= sh_irda_xir_fte, | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*=====================================
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *		SIR MODE | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *=====================================*/ | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:22 +00:00
										 |  |  | static int sh_irda_sir_fre(struct sh_irda_self *self) | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct device *dev = &self->ndev->dev; | 
					
						
							|  |  |  | 	u16 data16; | 
					
						
							|  |  |  | 	u8  *data = (u8 *)&data16; | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:22 +00:00
										 |  |  | 	int len = sh_irda_get_rcv_length(self); | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | 	int i, j; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (len > IRDARAM_LEN) | 
					
						
							|  |  |  | 		len = IRDARAM_LEN; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_dbg(dev, "frame recv length = %d\n", len); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < len; i++) { | 
					
						
							|  |  |  | 		j = i % 2; | 
					
						
							|  |  |  | 		if (!j) | 
					
						
							|  |  |  | 			data16 = sh_irda_read(self, IRDARAM + i); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		async_unwrap_char(self->ndev, &self->ndev->stats, | 
					
						
							|  |  |  | 				  &self->rx_buff, data[j]); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	self->ndev->last_rx = jiffies; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sh_irda_rcv_ctrl(self, 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:22 +00:00
										 |  |  | static int sh_irda_sir_trov(struct sh_irda_self *self) | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct device *dev = &self->ndev->dev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_err(dev, "buffer ram over\n"); | 
					
						
							|  |  |  | 	sh_irda_rcv_ctrl(self, 1); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:22 +00:00
										 |  |  | static int sh_irda_sir_tot(struct sh_irda_self *self) | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct device *dev = &self->ndev->dev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_err(dev, "time over\n"); | 
					
						
							|  |  |  | 	sh_irda_set_baudrate(self, 9600); | 
					
						
							|  |  |  | 	sh_irda_rcv_ctrl(self, 1); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:22 +00:00
										 |  |  | static int sh_irda_sir_fer(struct sh_irda_self *self) | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct device *dev = &self->ndev->dev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_err(dev, "framing error\n"); | 
					
						
							|  |  |  | 	sh_irda_rcv_ctrl(self, 1); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:22 +00:00
										 |  |  | static int sh_irda_sir_fte(struct sh_irda_self *self) | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct device *dev = &self->ndev->dev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_dbg(dev, "frame transmit end\n"); | 
					
						
							|  |  |  | 	netif_wake_queue(self->ndev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:22 +00:00
										 |  |  | static struct sh_irda_xir_func sh_irda_sir_func = { | 
					
						
							|  |  |  | 	.xir_fre	= sh_irda_sir_fre, | 
					
						
							|  |  |  | 	.xir_trov	= sh_irda_sir_trov, | 
					
						
							|  |  |  | 	.xir_9		= sh_irda_sir_tot, | 
					
						
							|  |  |  | 	.xir_8		= sh_irda_sir_fer, | 
					
						
							|  |  |  | 	.xir_fte	= sh_irda_sir_fte, | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void sh_irda_set_mode(struct sh_irda_self *self, enum sh_irda_mode mode) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct device *dev = &self->ndev->dev; | 
					
						
							|  |  |  | 	struct sh_irda_xir_func	*func; | 
					
						
							|  |  |  | 	const char *name; | 
					
						
							|  |  |  | 	u16 data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (mode) { | 
					
						
							|  |  |  | 	case SH_IRDA_SIR: | 
					
						
							|  |  |  | 		name	= "SIR"; | 
					
						
							|  |  |  | 		data	= TMD_SIR; | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:22 +00:00
										 |  |  | 		func	= &sh_irda_sir_func; | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case SH_IRDA_MIR: | 
					
						
							|  |  |  | 		name	= "MIR"; | 
					
						
							|  |  |  | 		data	= TMD_MIR; | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:22 +00:00
										 |  |  | 		func	= &sh_irda_mfir_func; | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case SH_IRDA_FIR: | 
					
						
							|  |  |  | 		name	= "FIR"; | 
					
						
							|  |  |  | 		data	= TMD_FIR; | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:22 +00:00
										 |  |  | 		func	= &sh_irda_mfir_func; | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:37 +00:00
										 |  |  | 		name	= "NONE"; | 
					
						
							|  |  |  | 		data	= 0; | 
					
						
							|  |  |  | 		func	= &sh_irda_xir_func; | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	self->mode = mode; | 
					
						
							|  |  |  | 	self->xir_func = func; | 
					
						
							|  |  |  | 	sh_irda_update_bits(self, IRTMR, TMD_MASK, data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_dbg(dev, "switch to %s mode", name); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /************************************************************************
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			irq function | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ************************************************************************/ | 
					
						
							|  |  |  | static void sh_irda_set_irq_mask(struct sh_irda_self *self) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u16 tmr_hole; | 
					
						
							|  |  |  | 	u16 xir_reg; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* set all mask */ | 
					
						
							|  |  |  | 	sh_irda_update_bits(self, IRTMR,   xIM_MASK, xIM_MASK); | 
					
						
							|  |  |  | 	sh_irda_update_bits(self, SIRIMR,  xIR_MASK, xIR_MASK); | 
					
						
							|  |  |  | 	sh_irda_update_bits(self, MFIRIMR, xIR_MASK, xIR_MASK); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* clear irq */ | 
					
						
							|  |  |  | 	sh_irda_update_bits(self, SIRICR,  xIR_MASK, xIR_MASK); | 
					
						
							|  |  |  | 	sh_irda_update_bits(self, MFIRICR, xIR_MASK, xIR_MASK); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (self->mode) { | 
					
						
							|  |  |  | 	case SH_IRDA_SIR: | 
					
						
							|  |  |  | 		tmr_hole	= SIM; | 
					
						
							|  |  |  | 		xir_reg		= SIRIMR; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case SH_IRDA_MIR: | 
					
						
							|  |  |  | 	case SH_IRDA_FIR: | 
					
						
							|  |  |  | 		tmr_hole	= MIM; | 
					
						
							|  |  |  | 		xir_reg		= MFIRIMR; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		tmr_hole	= 0; | 
					
						
							|  |  |  | 		xir_reg		= 0; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* open mask */ | 
					
						
							|  |  |  | 	if (xir_reg) { | 
					
						
							|  |  |  | 		sh_irda_update_bits(self, IRTMR, tmr_hole, 0); | 
					
						
							|  |  |  | 		sh_irda_update_bits(self, xir_reg, xIR_MASK, 0); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static irqreturn_t sh_irda_irq(int irq, void *dev_id) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct sh_irda_self *self = dev_id; | 
					
						
							|  |  |  | 	struct sh_irda_xir_func	*func = self->xir_func; | 
					
						
							|  |  |  | 	u16 isr = sh_irda_read(self, SIRISR); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* clear irq */ | 
					
						
							|  |  |  | 	sh_irda_write(self, SIRICR, isr); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (isr & FRE) | 
					
						
							|  |  |  | 		func->xir_fre(self); | 
					
						
							|  |  |  | 	if (isr & TROV) | 
					
						
							|  |  |  | 		func->xir_trov(self); | 
					
						
							|  |  |  | 	if (isr & xIR_9) | 
					
						
							|  |  |  | 		func->xir_9(self); | 
					
						
							|  |  |  | 	if (isr & xIR_8) | 
					
						
							|  |  |  | 		func->xir_8(self); | 
					
						
							|  |  |  | 	if (isr & FTE) | 
					
						
							|  |  |  | 		func->xir_fte(self); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return IRQ_HANDLED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /************************************************************************
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			CRC function | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ************************************************************************/ | 
					
						
							|  |  |  | static void sh_irda_crc_reset(struct sh_irda_self *self) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	sh_irda_write(self, CRCCTR, CRC_RST); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void sh_irda_crc_add(struct sh_irda_self *self, u16 data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	sh_irda_write(self, CRCIR, data & CRC_IN_MASK); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static u16 sh_irda_crc_cnt(struct sh_irda_self *self) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return CRC_CT_MASK & sh_irda_read(self, CRCCTR); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static u16 sh_irda_crc_out(struct sh_irda_self *self) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return sh_irda_read(self, CRCOR); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int sh_irda_crc_init(struct sh_irda_self *self) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct device *dev = &self->ndev->dev; | 
					
						
							|  |  |  | 	int ret = -EIO; | 
					
						
							|  |  |  | 	u16 val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sh_irda_crc_reset(self); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sh_irda_crc_add(self, 0xCC); | 
					
						
							|  |  |  | 	sh_irda_crc_add(self, 0xF5); | 
					
						
							|  |  |  | 	sh_irda_crc_add(self, 0xF1); | 
					
						
							|  |  |  | 	sh_irda_crc_add(self, 0xA7); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	val = sh_irda_crc_cnt(self); | 
					
						
							|  |  |  | 	if (4 != val) { | 
					
						
							|  |  |  | 		dev_err(dev, "CRC count error %x\n", val); | 
					
						
							|  |  |  | 		goto crc_init_out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	val = sh_irda_crc_out(self); | 
					
						
							|  |  |  | 	if (0x51DF != val) { | 
					
						
							|  |  |  | 		dev_err(dev, "CRC result error%x\n", val); | 
					
						
							|  |  |  | 		goto crc_init_out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | crc_init_out: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sh_irda_crc_reset(self); | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /************************************************************************
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			iobuf function | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ************************************************************************/ | 
					
						
							|  |  |  | static void sh_irda_remove_iobuf(struct sh_irda_self *self) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	kfree(self->rx_buff.head); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	self->tx_buff.head = NULL; | 
					
						
							|  |  |  | 	self->tx_buff.data = NULL; | 
					
						
							|  |  |  | 	self->rx_buff.head = NULL; | 
					
						
							|  |  |  | 	self->rx_buff.data = NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int sh_irda_init_iobuf(struct sh_irda_self *self, int rxsize, int txsize) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (self->rx_buff.head || | 
					
						
							|  |  |  | 	    self->tx_buff.head) { | 
					
						
							|  |  |  | 		dev_err(&self->ndev->dev, "iobuff has already existed."); | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* rx_buff */ | 
					
						
							|  |  |  | 	self->rx_buff.head = kmalloc(rxsize, GFP_KERNEL); | 
					
						
							|  |  |  | 	if (!self->rx_buff.head) | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	self->rx_buff.truesize	= rxsize; | 
					
						
							|  |  |  | 	self->rx_buff.in_frame	= FALSE; | 
					
						
							|  |  |  | 	self->rx_buff.state	= OUTSIDE_FRAME; | 
					
						
							|  |  |  | 	self->rx_buff.data	= self->rx_buff.head; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* tx_buff */ | 
					
						
							|  |  |  | 	self->tx_buff.head	= self->membase + IRDARAM; | 
					
						
							|  |  |  | 	self->tx_buff.truesize	= IRDARAM_LEN; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /************************************************************************
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			net_device_ops function | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ************************************************************************/ | 
					
						
							|  |  |  | static int sh_irda_hard_xmit(struct sk_buff *skb, struct net_device *ndev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct sh_irda_self *self = netdev_priv(ndev); | 
					
						
							|  |  |  | 	struct device *dev = &self->ndev->dev; | 
					
						
							|  |  |  | 	int speed = irda_get_next_speed(skb); | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_dbg(dev, "hard xmit\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	netif_stop_queue(ndev); | 
					
						
							|  |  |  | 	sh_irda_rcv_ctrl(self, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = sh_irda_set_baudrate(self, speed); | 
					
						
							|  |  |  | 	if (ret < 0) | 
					
						
							| 
									
										
										
										
											2011-01-13 21:47:42 +00:00
										 |  |  | 		goto sh_irda_hard_xmit_end; | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	self->tx_buff.len = 0; | 
					
						
							|  |  |  | 	if (skb->len) { | 
					
						
							|  |  |  | 		unsigned long flags; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		spin_lock_irqsave(&self->lock, flags); | 
					
						
							|  |  |  | 		self->tx_buff.len = async_wrap_skb(skb, | 
					
						
							|  |  |  | 						   self->tx_buff.head, | 
					
						
							|  |  |  | 						   self->tx_buff.truesize); | 
					
						
							|  |  |  | 		spin_unlock_irqrestore(&self->lock, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (self->tx_buff.len > self->tx_buff.truesize) | 
					
						
							|  |  |  | 			self->tx_buff.len = self->tx_buff.truesize; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		sh_irda_write(self, IRTFLR, self->tx_buff.len); | 
					
						
							|  |  |  | 		sh_irda_write(self, IRTCTR, ARMOD | TE); | 
					
						
							| 
									
										
										
										
											2011-01-13 21:47:42 +00:00
										 |  |  | 	} else | 
					
						
							|  |  |  | 		goto sh_irda_hard_xmit_end; | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	dev_kfree_skb(skb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2011-01-13 21:47:42 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | sh_irda_hard_xmit_end: | 
					
						
							|  |  |  | 	sh_irda_set_baudrate(self, 9600); | 
					
						
							|  |  |  | 	netif_wake_queue(self->ndev); | 
					
						
							|  |  |  | 	sh_irda_rcv_ctrl(self, 1); | 
					
						
							|  |  |  | 	dev_kfree_skb(skb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int sh_irda_ioctl(struct net_device *ndev, struct ifreq *ifreq, int cmd) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * FIXME | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * This function is needed for irda framework. | 
					
						
							|  |  |  | 	 * But nothing to do now | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct net_device_stats *sh_irda_stats(struct net_device *ndev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct sh_irda_self *self = netdev_priv(ndev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return &self->ndev->stats; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int sh_irda_open(struct net_device *ndev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct sh_irda_self *self = netdev_priv(ndev); | 
					
						
							|  |  |  | 	int err; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:48 +00:00
										 |  |  | 	pm_runtime_get_sync(&self->pdev->dev); | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | 	err = sh_irda_crc_init(self); | 
					
						
							|  |  |  | 	if (err) | 
					
						
							|  |  |  | 		goto open_err; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sh_irda_set_mode(self, SH_IRDA_SIR); | 
					
						
							|  |  |  | 	sh_irda_set_timeout(self, 2); | 
					
						
							|  |  |  | 	sh_irda_set_baudrate(self, 9600); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	self->irlap = irlap_open(ndev, &self->qos, DRIVER_NAME); | 
					
						
							|  |  |  | 	if (!self->irlap) { | 
					
						
							|  |  |  | 		err = -ENODEV; | 
					
						
							|  |  |  | 		goto open_err; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	netif_start_queue(ndev); | 
					
						
							|  |  |  | 	sh_irda_rcv_ctrl(self, 1); | 
					
						
							|  |  |  | 	sh_irda_set_irq_mask(self); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_info(&ndev->dev, "opened\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | open_err: | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:48 +00:00
										 |  |  | 	pm_runtime_put_sync(&self->pdev->dev); | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int sh_irda_stop(struct net_device *ndev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct sh_irda_self *self = netdev_priv(ndev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Stop IrLAP */ | 
					
						
							|  |  |  | 	if (self->irlap) { | 
					
						
							|  |  |  | 		irlap_close(self->irlap); | 
					
						
							|  |  |  | 		self->irlap = NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	netif_stop_queue(ndev); | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:48 +00:00
										 |  |  | 	pm_runtime_put_sync(&self->pdev->dev); | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-13 04:33:20 +00:00
										 |  |  | 	dev_info(&ndev->dev, "stopped\n"); | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct net_device_ops sh_irda_ndo = { | 
					
						
							|  |  |  | 	.ndo_open		= sh_irda_open, | 
					
						
							|  |  |  | 	.ndo_stop		= sh_irda_stop, | 
					
						
							|  |  |  | 	.ndo_start_xmit		= sh_irda_hard_xmit, | 
					
						
							|  |  |  | 	.ndo_do_ioctl		= sh_irda_ioctl, | 
					
						
							|  |  |  | 	.ndo_get_stats		= sh_irda_stats, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /************************************************************************
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			platform_driver function | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ************************************************************************/ | 
					
						
							| 
									
										
										
										
											2012-12-03 09:24:13 -05:00
										 |  |  | static int sh_irda_probe(struct platform_device *pdev) | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct net_device *ndev; | 
					
						
							|  |  |  | 	struct sh_irda_self *self; | 
					
						
							|  |  |  | 	struct resource *res; | 
					
						
							| 
									
										
										
										
											2010-07-15 08:44:54 +00:00
										 |  |  | 	int irq; | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | 	int err = -ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 
					
						
							|  |  |  | 	irq = platform_get_irq(pdev, 0); | 
					
						
							|  |  |  | 	if (!res || irq < 0) { | 
					
						
							|  |  |  | 		dev_err(&pdev->dev, "Not enough platform resources.\n"); | 
					
						
							|  |  |  | 		goto exit; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ndev = alloc_irdadev(sizeof(*self)); | 
					
						
							|  |  |  | 	if (!ndev) | 
					
						
							|  |  |  | 		goto exit; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	self = netdev_priv(ndev); | 
					
						
							|  |  |  | 	self->membase = ioremap_nocache(res->start, resource_size(res)); | 
					
						
							|  |  |  | 	if (!self->membase) { | 
					
						
							|  |  |  | 		err = -ENXIO; | 
					
						
							|  |  |  | 		dev_err(&pdev->dev, "Unable to ioremap.\n"); | 
					
						
							|  |  |  | 		goto err_mem_1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = sh_irda_init_iobuf(self, IRDA_SKB_MAX_MTU, IRDA_SIR_MAX_FRAME); | 
					
						
							|  |  |  | 	if (err) | 
					
						
							|  |  |  | 		goto err_mem_2; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:48 +00:00
										 |  |  | 	self->pdev = pdev; | 
					
						
							|  |  |  | 	pm_runtime_enable(&pdev->dev); | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	irda_init_max_qos_capabilies(&self->qos); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ndev->netdev_ops	= &sh_irda_ndo; | 
					
						
							|  |  |  | 	ndev->irq		= irq; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	self->ndev			= ndev; | 
					
						
							|  |  |  | 	self->qos.baud_rate.bits	&= IR_9600; /* FIXME */ | 
					
						
							|  |  |  | 	self->qos.min_turn_time.bits	= 1; /* 10 ms or more */ | 
					
						
							|  |  |  | 	spin_lock_init(&self->lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	irda_qos_bits_to_value(&self->qos); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err = register_netdev(ndev); | 
					
						
							|  |  |  | 	if (err) | 
					
						
							|  |  |  | 		goto err_mem_4; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	platform_set_drvdata(pdev, ndev); | 
					
						
							| 
									
										
										
										
											2013-10-05 06:39:24 +02:00
										 |  |  | 	err = request_irq(irq, sh_irda_irq, 0, "sh_irda", self); | 
					
						
							| 
									
										
										
										
											2012-10-05 11:33:02 +00:00
										 |  |  | 	if (err) { | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | 		dev_warn(&pdev->dev, "Unable to attach sh_irda interrupt\n"); | 
					
						
							|  |  |  | 		goto err_mem_4; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dev_info(&pdev->dev, "SuperH IrDA probed\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	goto exit; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | err_mem_4: | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:48 +00:00
										 |  |  | 	pm_runtime_disable(&pdev->dev); | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | 	sh_irda_remove_iobuf(self); | 
					
						
							|  |  |  | err_mem_2: | 
					
						
							|  |  |  | 	iounmap(self->membase); | 
					
						
							|  |  |  | err_mem_1: | 
					
						
							|  |  |  | 	free_netdev(ndev); | 
					
						
							|  |  |  | exit: | 
					
						
							|  |  |  | 	return err; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-03 09:24:13 -05:00
										 |  |  | static int sh_irda_remove(struct platform_device *pdev) | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct net_device *ndev = platform_get_drvdata(pdev); | 
					
						
							|  |  |  | 	struct sh_irda_self *self = netdev_priv(ndev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!self) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	unregister_netdev(ndev); | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:48 +00:00
										 |  |  | 	pm_runtime_disable(&pdev->dev); | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | 	sh_irda_remove_iobuf(self); | 
					
						
							|  |  |  | 	iounmap(self->membase); | 
					
						
							|  |  |  | 	free_netdev(ndev); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:48 +00:00
										 |  |  | static int sh_irda_runtime_nop(struct device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* Runtime PM callback shared between ->runtime_suspend()
 | 
					
						
							|  |  |  | 	 * and ->runtime_resume(). Simply returns success. | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * This driver re-initializes all registers after | 
					
						
							|  |  |  | 	 * pm_runtime_get_sync() anyway so there is no need | 
					
						
							|  |  |  | 	 * to save and restore registers here. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct dev_pm_ops sh_irda_pm_ops = { | 
					
						
							|  |  |  | 	.runtime_suspend	= sh_irda_runtime_nop, | 
					
						
							|  |  |  | 	.runtime_resume		= sh_irda_runtime_nop, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | static struct platform_driver sh_irda_driver = { | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:37 +00:00
										 |  |  | 	.probe	= sh_irda_probe, | 
					
						
							| 
									
										
										
										
											2012-12-03 09:24:13 -05:00
										 |  |  | 	.remove	= sh_irda_remove, | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:37 +00:00
										 |  |  | 	.driver	= { | 
					
						
							|  |  |  | 		.name	= DRIVER_NAME, | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:48 +00:00
										 |  |  | 		.pm	= &sh_irda_pm_ops, | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | 	}, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-27 20:29:11 -05:00
										 |  |  | module_platform_driver(sh_irda_driver); | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-31 20:08:37 +00:00
										 |  |  | MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); | 
					
						
							| 
									
										
										
										
											2010-04-05 18:46:12 +00:00
										 |  |  | MODULE_DESCRIPTION("SuperH IrDA driver"); | 
					
						
							|  |  |  | MODULE_LICENSE("GPL"); |