Merge tag 'modules-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[deliverable/linux.git] / drivers / staging / nokia_h4p / nokia_uart.c
CommitLineData
91eef3e2
PM
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
30inline 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
35inline u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset)
36{
37 return __raw_readb(info->uart_base + (offset << 2));
38}
39
40void 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
52int 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
74void __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
89void 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
98void 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
126int 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
143void 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
157void 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
174void 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}
This page took 0.069871 seconds and 5 git commands to generate.