r8a66597-udc.h 6.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * R8A66597 UDC
 *
 * Copyright (C) 2007-2009 Renesas Solutions Corp.
 *
 * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#ifndef __R8A66597_H__
#define __R8A66597_H__

26 27 28 29
#ifdef CONFIG_HAVE_CLK
#include <linux/clk.h>
#endif

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
#include <linux/usb/r8a66597.h>

#define R8A66597_MAX_SAMPLING	10

#define R8A66597_MAX_NUM_PIPE	8
#define R8A66597_MAX_NUM_BULK	3
#define R8A66597_MAX_NUM_ISOC	2
#define R8A66597_MAX_NUM_INT	2

#define R8A66597_BASE_PIPENUM_BULK	3
#define R8A66597_BASE_PIPENUM_ISOC	1
#define R8A66597_BASE_PIPENUM_INT	6

#define R8A66597_BASE_BUFNUM	6
#define R8A66597_MAX_BUFNUM	0x4F

#define is_bulk_pipe(pipenum)	\
	((pipenum >= R8A66597_BASE_PIPENUM_BULK) && \
	 (pipenum < (R8A66597_BASE_PIPENUM_BULK + R8A66597_MAX_NUM_BULK)))
#define is_interrupt_pipe(pipenum)	\
	((pipenum >= R8A66597_BASE_PIPENUM_INT) && \
	 (pipenum < (R8A66597_BASE_PIPENUM_INT + R8A66597_MAX_NUM_INT)))
#define is_isoc_pipe(pipenum)	\
	((pipenum >= R8A66597_BASE_PIPENUM_ISOC) && \
	 (pipenum < (R8A66597_BASE_PIPENUM_ISOC + R8A66597_MAX_NUM_ISOC)))

struct r8a66597_pipe_info {
	u16	pipe;
	u16	epnum;
	u16	maxpacket;
	u16	type;
	u16	interval;
	u16	dir_in;
};

struct r8a66597_request {
	struct usb_request	req;
	struct list_head	queue;
};

struct r8a66597_ep {
	struct usb_ep		ep;
	struct r8a66597		*r8a66597;

	struct list_head	queue;
	unsigned		busy:1;
76
	unsigned		wedge:1;
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
	unsigned		internal_ccpl:1;	/* use only control */

	/* this member can able to after r8a66597_enable */
	unsigned		use_dma:1;
	u16			pipenum;
	u16			type;
	const struct usb_endpoint_descriptor	*desc;
	/* register address */
	unsigned char		fifoaddr;
	unsigned char		fifosel;
	unsigned char		fifoctr;
	unsigned char		fifotrn;
	unsigned char		pipectr;
};

struct r8a66597 {
	spinlock_t		lock;
94
	void __iomem		*reg;
95

96 97 98
#ifdef CONFIG_HAVE_CLK
	struct clk *clk;
#endif
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
	struct r8a66597_platdata	*pdata;

	struct usb_gadget		gadget;
	struct usb_gadget_driver	*driver;

	struct r8a66597_ep	ep[R8A66597_MAX_NUM_PIPE];
	struct r8a66597_ep	*pipenum2ep[R8A66597_MAX_NUM_PIPE];
	struct r8a66597_ep	*epaddr2ep[16];

	struct timer_list	timer;
	struct usb_request	*ep0_req;	/* for internal request */
	u16			ep0_data;	/* for internal request */
	u16			old_vbus;
	u16			scount;
	u16			old_dvsq;

	/* pipe config */
	unsigned char bulk;
	unsigned char interrupt;
	unsigned char isochronous;
	unsigned char num_dma;

	unsigned irq_sense_low:1;
};

#define gadget_to_r8a66597(_gadget)	\
		container_of(_gadget, struct r8a66597, gadget)
#define r8a66597_to_gadget(r8a66597) (&r8a66597->gadget)

static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset)
{
130
	return ioread16(r8a66597->reg + offset);
131 132 133
}

static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
M
Magnus Damm 已提交
134 135
				      unsigned long offset,
				      unsigned char *buf,
136 137
				      int len)
{
138
	void __iomem *fifoaddr = r8a66597->reg + offset;
M
Magnus Damm 已提交
139 140 141
	unsigned int data;
	int i;

142
	if (r8a66597->pdata->on_chip) {
M
Magnus Damm 已提交
143 144 145 146
		/* 32-bit accesses for on_chip controllers */

		/* aligned buf case */
		if (len >= 4 && !((unsigned long)buf & 0x03)) {
147
			ioread32_rep(fifoaddr, buf, len / 4);
M
Magnus Damm 已提交
148 149 150 151 152 153 154
			buf += len & ~0x03;
			len &= 0x03;
		}

		/* unaligned buf case */
		for (i = 0; i < len; i++) {
			if (!(i & 0x03))
155
				data = ioread32(fifoaddr);
M
Magnus Damm 已提交
156 157

			buf[i] = (data >> ((i & 0x03) * 8)) & 0xff;
158 159
		}
	} else {
M
Magnus Damm 已提交
160 161 162 163
		/* 16-bit accesses for external controllers */

		/* aligned buf case */
		if (len >= 2 && !((unsigned long)buf & 0x01)) {
164
			ioread16_rep(fifoaddr, buf, len / 2);
M
Magnus Damm 已提交
165 166 167 168 169 170 171
			buf += len & ~0x01;
			len &= 0x01;
		}

		/* unaligned buf case */
		for (i = 0; i < len; i++) {
			if (!(i & 0x01))
172
				data = ioread16(fifoaddr);
M
Magnus Damm 已提交
173 174 175

			buf[i] = (data >> ((i & 0x01) * 8)) & 0xff;
		}
176 177 178 179 180 181
	}
}

static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
				  unsigned long offset)
{
182
	iowrite16(val, r8a66597->reg + offset);
183 184 185
}

static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
M
Magnus Damm 已提交
186 187
				       unsigned long offset,
				       unsigned char *buf,
188 189
				       int len)
{
190
	void __iomem *fifoaddr = r8a66597->reg + offset;
M
Magnus Damm 已提交
191 192
	int adj = 0;
	int i;
193 194

	if (r8a66597->pdata->on_chip) {
M
Magnus Damm 已提交
195 196
		/* 32-bit access only if buf is 32-bit aligned */
		if (len >= 4 && !((unsigned long)buf & 0x03)) {
197
			iowrite32_rep(fifoaddr, buf, len / 4);
M
Magnus Damm 已提交
198 199
			buf += len & ~0x03;
			len &= 0x03;
200 201
		}
	} else {
M
Magnus Damm 已提交
202 203
		/* 16-bit access only if buf is 16-bit aligned */
		if (len >= 2 && !((unsigned long)buf & 0x01)) {
204
			iowrite16_rep(fifoaddr, buf, len / 2);
M
Magnus Damm 已提交
205 206
			buf += len & ~0x01;
			len &= 0x01;
207 208
		}
	}
M
Magnus Damm 已提交
209 210 211 212 213 214 215 216 217 218

	/* adjust fifo address in the little endian case */
	if (!(r8a66597_read(r8a66597, CFIFOSEL) & BIGEND)) {
		if (r8a66597->pdata->on_chip)
			adj = 0x03; /* 32-bit wide */
		else
			adj = 0x01; /* 16-bit wide */
	}

	for (i = 0; i < len; i++)
219
		iowrite8(buf[i], fifoaddr + adj - (i & adj));
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
}

static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
				 u16 val, u16 pat, unsigned long offset)
{
	u16 tmp;
	tmp = r8a66597_read(r8a66597, offset);
	tmp = tmp & (~pat);
	tmp = tmp | val;
	r8a66597_write(r8a66597, tmp, offset);
}

static inline u16 get_xtal_from_pdata(struct r8a66597_platdata *pdata)
{
	u16 clock = 0;

	switch (pdata->xtal) {
	case R8A66597_PLATDATA_XTAL_12MHZ:
		clock = XTAL12;
		break;
	case R8A66597_PLATDATA_XTAL_24MHZ:
		clock = XTAL24;
		break;
	case R8A66597_PLATDATA_XTAL_48MHZ:
		clock = XTAL48;
		break;
	default:
		printk(KERN_ERR "r8a66597: platdata clock is wrong.\n");
		break;
	}

	return clock;
}

#define r8a66597_bclr(r8a66597, val, offset)	\
			r8a66597_mdfy(r8a66597, 0, val, offset)
#define r8a66597_bset(r8a66597, val, offset)	\
			r8a66597_mdfy(r8a66597, val, 0, offset)

#define get_pipectr_addr(pipenum)	(PIPE1CTR + (pipenum - 1) * 2)

#define enable_irq_ready(r8a66597, pipenum)	\
	enable_pipe_irq(r8a66597, pipenum, BRDYENB)
#define disable_irq_ready(r8a66597, pipenum)	\
	disable_pipe_irq(r8a66597, pipenum, BRDYENB)
#define enable_irq_empty(r8a66597, pipenum)	\
	enable_pipe_irq(r8a66597, pipenum, BEMPENB)
#define disable_irq_empty(r8a66597, pipenum)	\
	disable_pipe_irq(r8a66597, pipenum, BEMPENB)
#define enable_irq_nrdy(r8a66597, pipenum)	\
	enable_pipe_irq(r8a66597, pipenum, NRDYENB)
#define disable_irq_nrdy(r8a66597, pipenum)	\
	disable_pipe_irq(r8a66597, pipenum, NRDYENB)

#endif	/* __R8A66597_H__ */