]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/nokia_h4p/nokia_uart.c
Merge branch 'core-rcu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[karo-tx-linux.git] / drivers / staging / nokia_h4p / nokia_uart.c
1 /*
2  * This file is part of Nokia H4P bluetooth driver
3  *
4  * Copyright (C) 2005, 2006 Nokia Corporation.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * version 2 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18  * 02110-1301 USA
19  *
20  */
21
22 #include <linux/serial_reg.h>
23 #include <linux/delay.h>
24 #include <linux/clk.h>
25
26 #include <linux/io.h>
27
28 #include "hci_h4p.h"
29
30 inline void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val)
31 {
32         __raw_writeb(val, info->uart_base + (offset << 2));
33 }
34
35 inline u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset)
36 {
37         return __raw_readb(info->uart_base + (offset << 2));
38 }
39
40 void hci_h4p_set_rts(struct hci_h4p_info *info, int active)
41 {
42         u8 b;
43
44         b = hci_h4p_inb(info, UART_MCR);
45         if (active)
46                 b |= UART_MCR_RTS;
47         else
48                 b &= ~UART_MCR_RTS;
49         hci_h4p_outb(info, UART_MCR, b);
50 }
51
52 int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active,
53                          int timeout_ms)
54 {
55         unsigned long timeout;
56         int state;
57
58         timeout = jiffies + msecs_to_jiffies(timeout_ms);
59         for (;;) {
60                 state = hci_h4p_inb(info, UART_MSR) & UART_MSR_CTS;
61                 if (active) {
62                         if (state)
63                                 return 0;
64                 } else {
65                         if (!state)
66                                 return 0;
67                 }
68                 if (time_after(jiffies, timeout))
69                         return -ETIMEDOUT;
70                 msleep(1);
71         }
72 }
73
74 void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
75 {
76         u8 lcr, b;
77
78         lcr = hci_h4p_inb(info, UART_LCR);
79         hci_h4p_outb(info, UART_LCR, 0xbf);
80         b = hci_h4p_inb(info, UART_EFR);
81         if (on)
82                 b |= which;
83         else
84                 b &= ~which;
85         hci_h4p_outb(info, UART_EFR, b);
86         hci_h4p_outb(info, UART_LCR, lcr);
87 }
88
89 void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
90 {
91         unsigned long flags;
92
93         spin_lock_irqsave(&info->lock, flags);
94         __hci_h4p_set_auto_ctsrts(info, on, which);
95         spin_unlock_irqrestore(&info->lock, flags);
96 }
97
98 void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed)
99 {
100         unsigned int divisor;
101         u8 lcr, mdr1;
102
103         BT_DBG("Setting speed %lu", speed);
104
105         if (speed >= 460800) {
106                 divisor = UART_CLOCK / 13 / speed;
107                 mdr1 = 3;
108         } else {
109                 divisor = UART_CLOCK / 16 / speed;
110                 mdr1 = 0;
111         }
112
113         /* Make sure UART mode is disabled */
114         hci_h4p_outb(info, UART_OMAP_MDR1, 7);
115
116         lcr = hci_h4p_inb(info, UART_LCR);
117         hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);     /* Set DLAB */
118         hci_h4p_outb(info, UART_DLL, divisor & 0xff);    /* Set speed */
119         hci_h4p_outb(info, UART_DLM, divisor >> 8);
120         hci_h4p_outb(info, UART_LCR, lcr);
121
122         /* Make sure UART mode is enabled */
123         hci_h4p_outb(info, UART_OMAP_MDR1, mdr1);
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 void hci_h4p_store_regs(struct hci_h4p_info *info)
144 {
145         u16 lcr = 0;
146
147         lcr = hci_h4p_inb(info, UART_LCR);
148         hci_h4p_outb(info, UART_LCR, 0xBF);
149         info->dll = hci_h4p_inb(info, UART_DLL);
150         info->dlh = hci_h4p_inb(info, UART_DLM);
151         info->efr = hci_h4p_inb(info, UART_EFR);
152         hci_h4p_outb(info, UART_LCR, lcr);
153         info->mdr1 = hci_h4p_inb(info, UART_OMAP_MDR1);
154         info->ier = hci_h4p_inb(info, UART_IER);
155 }
156
157 void hci_h4p_restore_regs(struct hci_h4p_info *info)
158 {
159         u16 lcr = 0;
160
161         hci_h4p_init_uart(info);
162
163         hci_h4p_outb(info, UART_OMAP_MDR1, 7);
164         lcr = hci_h4p_inb(info, UART_LCR);
165         hci_h4p_outb(info, UART_LCR, 0xBF);
166         hci_h4p_outb(info, UART_DLL, info->dll);    /* Set speed */
167         hci_h4p_outb(info, UART_DLM, info->dlh);
168         hci_h4p_outb(info, UART_EFR, info->efr);
169         hci_h4p_outb(info, UART_LCR, lcr);
170         hci_h4p_outb(info, UART_OMAP_MDR1, info->mdr1);
171         hci_h4p_outb(info, UART_IER, info->ier);
172 }
173
174 void hci_h4p_init_uart(struct hci_h4p_info *info)
175 {
176         u8 mcr, efr;
177
178         /* Enable and setup FIFO */
179         hci_h4p_outb(info, UART_OMAP_MDR1, 0x00);
180
181         hci_h4p_outb(info, UART_LCR, 0xbf);
182         efr = hci_h4p_inb(info, UART_EFR);
183         hci_h4p_outb(info, UART_EFR, UART_EFR_ECB);
184         hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);
185         mcr = hci_h4p_inb(info, UART_MCR);
186         hci_h4p_outb(info, UART_MCR, UART_MCR_TCRTLR);
187         hci_h4p_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO |
188                         UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
189                         (3 << 6) | (0 << 4));
190         hci_h4p_outb(info, UART_LCR, 0xbf);
191         hci_h4p_outb(info, UART_TI752_TLR, 0xed);
192         hci_h4p_outb(info, UART_TI752_TCR, 0xef);
193         hci_h4p_outb(info, UART_EFR, efr);
194         hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);
195         hci_h4p_outb(info, UART_MCR, 0x00);
196         hci_h4p_outb(info, UART_LCR, UART_LCR_WLEN8);
197         hci_h4p_outb(info, UART_IER, UART_IER_RDI);
198         hci_h4p_outb(info, UART_OMAP_SYSC, (1 << 0) | (1 << 2) | (2 << 3));
199 }