]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/bluetooth/hci_h4p/uart.c
67220fb46322c65e8dda69942bed4c7a05d124ac
[linux-2.6-omap-h63xx.git] / drivers / bluetooth / hci_h4p / uart.c
1 /*
2  * This file is part of hci_h4p bluetooth driver
3  *
4  * Copyright (C) 2005, 2006 Nokia Corporation.
5  *
6  * Contact: Ville Tervo <ville.tervo@nokia.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * version 2 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301 USA
21  *
22  */
23
24 #include <linux/serial_reg.h>
25 #include <linux/delay.h>
26 #include <linux/clk.h>
27
28 #include <asm/io.h>
29
30 #include "hci_h4p.h"
31
32 inline void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val)
33 {
34         outb(val, info->uart_base + (offset << 2));
35 }
36
37 inline u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset)
38 {
39         return inb(info->uart_base + (offset << 2));
40 }
41
42 void hci_h4p_set_rts(struct hci_h4p_info *info, int active)
43 {
44         u8 b;
45
46         b = hci_h4p_inb(info, UART_MCR);
47         if (active)
48                 b |= UART_MCR_RTS;
49         else
50                 b &= ~UART_MCR_RTS;
51         hci_h4p_outb(info, UART_MCR, b);
52 }
53
54 int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active,
55                          int timeout_ms)
56 {
57         int okay;
58         unsigned long timeout;
59
60         okay = 0;
61         timeout = jiffies + msecs_to_jiffies(timeout_ms);
62         for (;;) {
63                 int state;
64
65                 state = hci_h4p_inb(info, UART_MSR) & UART_MSR_CTS;
66                 if (active) {
67                         if (state)
68                                 return 0;
69                 } else {
70                         if (!state)
71                                 return 0;
72                 }
73                 if (time_after(jiffies, timeout))
74                         return -ETIMEDOUT;
75         }
76 }
77
78 void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
79 {
80         u8 lcr, b;
81
82         lcr = hci_h4p_inb(info, UART_LCR);
83         hci_h4p_outb(info, UART_LCR, 0xbf);
84         b = hci_h4p_inb(info, UART_EFR);
85         if (on)
86                 b |= which;
87         else
88                 b &= ~which;
89         hci_h4p_outb(info, UART_EFR, b);
90         hci_h4p_outb(info, UART_LCR, lcr);
91 }
92
93 void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed)
94 {
95         unsigned int divisor;
96         u8 lcr, mdr1;
97
98         NBT_DBG("Setting speed %lu\n", speed);
99
100         if (speed >= 460800) {
101                 divisor = UART_CLOCK / 13 / speed;
102                 mdr1 = 3;
103         } else {
104                 divisor = UART_CLOCK / 16 / speed;
105                 mdr1 = 0;
106         }
107
108         hci_h4p_outb(info, UART_OMAP_MDR1, 7); /* Make sure UART mode is disabled */
109         lcr = hci_h4p_inb(info, UART_LCR);
110         hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);     /* Set DLAB */
111         hci_h4p_outb(info, UART_DLL, divisor & 0xff);    /* Set speed */
112         hci_h4p_outb(info, UART_DLM, divisor >> 8);
113         hci_h4p_outb(info, UART_LCR, lcr);
114         hci_h4p_outb(info, UART_OMAP_MDR1, mdr1); /* Make sure UART mode is enabled */
115 }
116
117 int hci_h4p_reset_uart(struct hci_h4p_info *info)
118 {
119         int count = 0;
120
121         /* Reset the  UART */
122         hci_h4p_outb(info, UART_OMAP_SYSC, UART_SYSC_OMAP_RESET);
123         while (!(hci_h4p_inb(info, UART_OMAP_SYSS) & UART_SYSS_RESETDONE)) {
124                 if (count++ > 100) {
125                         dev_err(info->dev, "hci_h4p: UART reset timeout\n");
126                         return -ENODEV;
127                 }
128                 udelay(1);
129         }
130
131         return 0;
132 }
133
134 int hci_h4p_init_uart(struct hci_h4p_info *info)
135 {
136         int err;
137
138         err = hci_h4p_reset_uart(info);
139         if (err < 0)
140                 return err;
141
142         /* Enable and setup FIFO */
143         hci_h4p_outb(info, UART_LCR, UART_LCR_WLEN8);
144         hci_h4p_outb(info, UART_OMAP_MDR1, 0x00); /* Make sure UART mode is enabled */
145         hci_h4p_outb(info, UART_OMAP_SCR, 0x80);
146         hci_h4p_outb(info, UART_EFR, UART_EFR_ECB);
147         hci_h4p_outb(info, UART_MCR, UART_MCR_TCRTLR);
148         hci_h4p_outb(info, UART_TI752_TLR, 0x1f);
149         hci_h4p_outb(info, UART_TI752_TCR, 0xef);
150         hci_h4p_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
151                      UART_FCR_CLEAR_XMIT | UART_FCR_R_TRIG_00);
152         hci_h4p_outb(info, UART_IER, UART_IER_RDI);
153
154         return 0;
155 }