Merge current mainline tree into linux-omap tree
[pandora-kernel.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_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
94 {
95         unsigned long flags;
96
97         spin_lock_irqsave(&info->lock, flags);
98         __hci_h4p_set_auto_ctsrts(info, on, which);
99         spin_unlock_irqrestore(&info->lock, flags);
100 }
101
102 void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed)
103 {
104         unsigned int divisor;
105         u8 lcr, mdr1;
106
107         NBT_DBG("Setting speed %lu\n", speed);
108
109         if (speed >= 460800) {
110                 divisor = UART_CLOCK / 13 / speed;
111                 mdr1 = 3;
112         } else {
113                 divisor = UART_CLOCK / 16 / speed;
114                 mdr1 = 0;
115         }
116
117         hci_h4p_outb(info, UART_OMAP_MDR1, 7); /* Make sure UART mode is disabled */
118         lcr = hci_h4p_inb(info, UART_LCR);
119         hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);     /* Set DLAB */
120         hci_h4p_outb(info, UART_DLL, divisor & 0xff);    /* Set speed */
121         hci_h4p_outb(info, UART_DLM, divisor >> 8);
122         hci_h4p_outb(info, UART_LCR, lcr);
123         hci_h4p_outb(info, UART_OMAP_MDR1, mdr1); /* Make sure UART mode is enabled */
124 }
125
126 int hci_h4p_reset_uart(struct hci_h4p_info *info)
127 {
128         int count = 0;
129
130         /* Reset the  UART */
131         hci_h4p_outb(info, UART_OMAP_SYSC, UART_SYSC_OMAP_RESET);
132         while (!(hci_h4p_inb(info, UART_OMAP_SYSS) & UART_SYSS_RESETDONE)) {
133                 if (count++ > 100) {
134                         dev_err(info->dev, "hci_h4p: UART reset timeout\n");
135                         return -ENODEV;
136                 }
137                 udelay(1);
138         }
139
140         return 0;
141 }
142
143 int hci_h4p_init_uart(struct hci_h4p_info *info)
144 {
145         int err;
146
147         err = hci_h4p_reset_uart(info);
148         if (err < 0)
149                 return err;
150
151         /* Enable and setup FIFO */
152         hci_h4p_outb(info, UART_LCR, UART_LCR_WLEN8);
153         hci_h4p_outb(info, UART_OMAP_MDR1, 0x00); /* Make sure UART mode is enabled */
154         hci_h4p_outb(info, UART_OMAP_SCR, 0x80);
155         hci_h4p_outb(info, UART_EFR, UART_EFR_ECB);
156         hci_h4p_outb(info, UART_MCR, UART_MCR_TCRTLR);
157         hci_h4p_outb(info, UART_TI752_TLR, 0x1f);
158         hci_h4p_outb(info, UART_TI752_TCR, 0xef);
159         hci_h4p_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
160                      UART_FCR_CLEAR_XMIT | UART_FCR_R_TRIG_00);
161         hci_h4p_outb(info, UART_IER, UART_IER_RDI);
162
163         return 0;
164 }