aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/sb105x/sb_ser_core.h
blob: c8fb9917329975fc2f89b45fefdb829282ce5701 (plain) (blame)
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
26
27
28
29
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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
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
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
#include <linux/wait.h>

#define UART_CONFIG_TYPE	(1 << 0)
#define UART_CONFIG_IRQ		(1 << 1)
#define UPIO_PORT		(0)
#define UPIO_HUB6		(1)
#define UPIO_MEM		(2)
#define UPIO_MEM32		(3)
#define UPIO_AU			(4)			/* Au1x00 type IO */
#define UPIO_TSI		(5)			/* Tsi108/109 type IO */
#define UPF_FOURPORT		(1 << 1)
#define UPF_SAK			(1 << 2)
#define UPF_SPD_MASK		(0x1030)
#define UPF_SPD_HI		(0x0010)
#define UPF_SPD_VHI		(0x0020)
#define UPF_SPD_CUST		(0x0030)
#define UPF_SPD_SHI		(0x1000)
#define UPF_SPD_WARP		(0x1010)
#define UPF_SKIP_TEST		(1 << 6)
#define UPF_AUTO_IRQ		(1 << 7)
#define UPF_HARDPPS_CD		(1 << 11)
#define UPF_LOW_LATENCY		(1 << 13)
#define UPF_BUGGY_UART		(1 << 14)
#define UPF_MAGIC_MULTIPLIER	(1 << 16)
#define UPF_CONS_FLOW		(1 << 23)
#define UPF_SHARE_IRQ		(1 << 24)
#define UPF_BOOT_AUTOCONF	(1 << 28)
#define UPF_DEAD		(1 << 30)
#define UPF_IOREMAP		(1 << 31)
#define UPF_CHANGE_MASK		(0x17fff)
#define UPF_USR_MASK		(UPF_SPD_MASK|UPF_LOW_LATENCY)
#define USF_CLOSING_WAIT_INF	(0)
#define USF_CLOSING_WAIT_NONE	(~0U)

#define UART_XMIT_SIZE	PAGE_SIZE

#define UIF_CHECK_CD		(1 << 25)
#define UIF_CTS_FLOW		(1 << 26)
#define UIF_NORMAL_ACTIVE	(1 << 29)
#define UIF_INITIALIZED		(1 << 31)
#define UIF_SUSPENDED		(1 << 30)

#define WAKEUP_CHARS		256

#define uart_circ_empty(circ)		((circ)->head == (circ)->tail)
#define uart_circ_clear(circ)		((circ)->head = (circ)->tail = 0)

#define uart_circ_chars_pending(circ)	\
	(CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE))

#define uart_circ_chars_free(circ)	\
	(CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE))

#define uart_tx_stopped(port)		\
	((port)->info->tty->stopped || (port)->info->tty->hw_stopped)

#define UART_ENABLE_MS(port,cflag)	((port)->flags & UPF_HARDPPS_CD || \
					 (cflag) & CRTSCTS || \
					 !((cflag) & CLOCAL))


struct sb_uart_port;
struct sb_uart_info;
struct serial_struct;
struct device;

struct sb_uart_ops {
	unsigned int	(*tx_empty)(struct sb_uart_port *);
	void		(*set_mctrl)(struct sb_uart_port *, unsigned int mctrl);
	unsigned int	(*get_mctrl)(struct sb_uart_port *);
	void		(*stop_tx)(struct sb_uart_port *);
	void		(*start_tx)(struct sb_uart_port *);
	void		(*send_xchar)(struct sb_uart_port *, char ch);
	void		(*stop_rx)(struct sb_uart_port *);
	void		(*enable_ms)(struct sb_uart_port *);
	void		(*break_ctl)(struct sb_uart_port *, int ctl);
	int		(*startup)(struct sb_uart_port *);
	void		(*shutdown)(struct sb_uart_port *);
	void		(*set_termios)(struct sb_uart_port *, struct MP_TERMIOS *new,
				       struct MP_TERMIOS *old);
	void		(*pm)(struct sb_uart_port *, unsigned int state,
			      unsigned int oldstate);
	int		(*set_wake)(struct sb_uart_port *, unsigned int state);

	const char *(*type)(struct sb_uart_port *);

	void		(*release_port)(struct sb_uart_port *);

	int		(*request_port)(struct sb_uart_port *);
	void		(*config_port)(struct sb_uart_port *, int);
	int		(*verify_port)(struct sb_uart_port *, struct serial_struct *);
	int		(*ioctl)(struct sb_uart_port *, unsigned int, unsigned long);
};


struct sb_uart_icount {
	__u32	cts;
	__u32	dsr;
	__u32	rng;
	__u32	dcd;
	__u32	rx;
	__u32	tx;
	__u32	frame;
	__u32	overrun;
	__u32	parity;
	__u32	brk;
	__u32	buf_overrun;
};
typedef unsigned int  upf_t;

struct sb_uart_port {
	spinlock_t		lock;			/* port lock */
	unsigned int		iobase;			/* in/out[bwl] */
	unsigned char __iomem	*membase;		/* read/write[bwl] */
	unsigned int		irq;			/* irq number */
	unsigned int		uartclk;		/* base uart clock */
	unsigned int		fifosize;		/* tx fifo size */
	unsigned char		x_char;			/* xon/xoff char */
	unsigned char		regshift;		/* reg offset shift */
	unsigned char		iotype;			/* io access style */
	unsigned char		unused1;


	unsigned int		read_status_mask;	/* driver specific */
	unsigned int		ignore_status_mask;	/* driver specific */
	struct sb_uart_info	*info;			/* pointer to parent info */
	struct sb_uart_icount	icount;			/* statistics */

	struct console		*cons;			/* struct console, if any */
#ifdef CONFIG_SERIAL_CORE_CONSOLE
	unsigned long		sysrq;			/* sysrq timeout */
#endif

	upf_t			flags;

	unsigned int		mctrl;			/* current modem ctrl settings */
	unsigned int		timeout;		/* character-based timeout */
	unsigned int		type;			/* port type */
	const struct sb_uart_ops	*ops;
	unsigned int		custom_divisor;
	unsigned int		line;			/* port index */
	unsigned long		mapbase;		/* for ioremap */
	struct device		*dev;			/* parent device */
	unsigned char		hub6;			/* this should be in the 8250 driver */
	unsigned char		unused[3];
};

#define mdmode			unused[2]
#define MDMODE_ADDR		0x1
#define MDMODE_ENABLE	0x2
#define MDMODE_AUTO		0x4
#define MDMODE_ADDRSEND	0x8

struct sb_uart_state {
	unsigned int		close_delay;		/* msec */
	unsigned int		closing_wait;		/* msec */


	int			count;
	int			pm_state;
	struct sb_uart_info	*info;
	struct sb_uart_port	*port;

	struct mutex		mutex;
};

typedef unsigned int  uif_t;

struct sb_uart_info {
	struct tty_struct	*tty;
	struct circ_buf		xmit;
	uif_t			flags;

	int			blocked_open;

	struct tasklet_struct	tlet;

	wait_queue_head_t	open_wait;
	wait_queue_head_t	delta_msr_wait;
};


struct module;
struct tty_driver;

struct uart_driver {
	struct module		*owner;
	const char		*driver_name;
	const char		*dev_name;
	int			 major;
	int			 minor;
	int			 nr;
	struct console		*cons;

	struct sb_uart_state	*state;
        struct tty_driver               *tty_driver;
};

void sb_uart_write_wakeup(struct sb_uart_port *port)
{
    struct sb_uart_info *info = port->info;
    tasklet_schedule(&info->tlet);
}

void sb_uart_update_timeout(struct sb_uart_port *port, unsigned int cflag,
			 unsigned int baud)
{
    unsigned int bits;

    switch (cflag & CSIZE)
    {
        case CS5:
            bits = 7;
            break;

        case CS6:
            bits = 8;
            break;

        case CS7:
            bits = 9;
            break;

        default:
            bits = 10;
            break;
    }

    if (cflag & CSTOPB)
    {
        bits++;
    }

    if (cflag & PARENB)
    {
        bits++;
    }

    bits = bits * port->fifosize;

    port->timeout = (HZ * bits) / baud + HZ/50;
}
unsigned int sb_uart_get_baud_rate(struct sb_uart_port *port, struct MP_TERMIOS *termios,
				struct MP_TERMIOS *old, unsigned int min,
				unsigned int max)
{
        unsigned int try, baud, altbaud = 38400;
        upf_t flags = port->flags & UPF_SPD_MASK;

        if (flags == UPF_SPD_HI)
                altbaud = 57600;
        if (flags == UPF_SPD_VHI)
                altbaud = 115200;
        if (flags == UPF_SPD_SHI)
                altbaud = 230400;
        if (flags == UPF_SPD_WARP)
                altbaud = 460800;

        for (try = 0; try < 2; try++) {

                switch (termios->c_cflag & (CBAUD | CBAUDEX))
                {
                	case B921600    : baud = 921600;    break;
                	case B460800    : baud = 460800;    break;
                	case B230400    : baud = 230400;    break;
                	case B115200    : baud = 115200;    break;
                	case B57600     : baud = 57600;     break;
                	case B38400     : baud = 38400;     break;
                	case B19200     : baud = 19200;     break;
                	case B9600      : baud = 9600;      break;
                	case B4800      : baud = 4800;      break;
                	case B2400      : baud = 2400;      break;
                	case B1800      : baud = 1800;      break;
                	case B1200      : baud = 1200;      break;
                	case B600       : baud = 600;       break;
                	case B300       : baud = 300;       break;
                        case B200       : baud = 200;       break;
                	case B150       : baud = 150;       break;
                	case B134       : baud = 134;       break;
                	case B110       : baud = 110;       break;
                	case B75        : baud = 75;        break;
                	case B50        : baud = 50;        break;
                	default         : baud = 9600;      break;
                }

                if (baud == 38400)
                        baud = altbaud;

                if (baud == 0)
                        baud = 9600;

                if (baud >= min && baud <= max)
                        return baud;

                termios->c_cflag &= ~CBAUD;
                if (old) {
                        termios->c_cflag |= old->c_cflag & CBAUD;
                        old = NULL;
                        continue;
                }

                termios->c_cflag |= B9600;
        }

        return 0;
}
unsigned int sb_uart_get_divisor(struct sb_uart_port *port, unsigned int baud)
{
        unsigned int quot;

        if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
                quot = port->custom_divisor;
        else
                quot = (port->uartclk + (8 * baud)) / (16 * baud);

        return quot;
}



static inline int sb_uart_handle_break(struct sb_uart_port *port)
{
	struct sb_uart_info *info = port->info;

	if (port->flags & UPF_SAK)
		do_SAK(info->tty);
	return 0;
}

static inline void sb_uart_handle_dcd_change(struct sb_uart_port *port, unsigned int status)
{
	struct sb_uart_info *info = port->info;

	port->icount.dcd++;

	if (info->flags & UIF_CHECK_CD) {
		if (status)
			wake_up_interruptible(&info->open_wait);
		else if (info->tty)
			tty_hangup(info->tty);
	}
}

static inline void sb_uart_handle_cts_change(struct sb_uart_port *port, unsigned int status)
{
	struct sb_uart_info *info = port->info;
	struct tty_struct *tty = info->tty;

	port->icount.cts++;

	if (info->flags & UIF_CTS_FLOW) {
		if (tty->hw_stopped) {
			if (status) {
				tty->hw_stopped = 0;
				port->ops->start_tx(port);
				sb_uart_write_wakeup(port);
			}
		} else {
			if (!status) {
				tty->hw_stopped = 1;
				port->ops->stop_tx(port);
			}
		}
	}
}