aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-tegra/board-enterprise-baseband.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/board-enterprise-baseband.c')
-rw-r--r--arch/arm/mach-tegra/board-enterprise-baseband.c247
1 files changed, 247 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/board-enterprise-baseband.c b/arch/arm/mach-tegra/board-enterprise-baseband.c
new file mode 100644
index 00000000000..7552e287154
--- /dev/null
+++ b/arch/arm/mach-tegra/board-enterprise-baseband.c
@@ -0,0 +1,247 @@
1/*
2 * arch/arm/mach-tegra/board-enterprise-baseband.c
3 *
4 * Copyright (c) 2011, NVIDIA Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21#include <linux/resource.h>
22#include <linux/platform_device.h>
23#include <linux/delay.h>
24#include <linux/gpio.h>
25#include <linux/interrupt.h>
26#include <linux/irq.h>
27#include <linux/err.h>
28#include <linux/wakelock.h>
29#include <linux/platform_data/tegra_usb.h>
30#include <asm/mach-types.h>
31#include <asm/mach/arch.h>
32#include <mach/pinmux.h>
33#include <mach/usb_phy.h>
34#include <mach/tegra_usb_modem_power.h>
35#include "devices.h"
36#include "gpio-names.h"
37
38/* Tegra3 BB GPIO */
39#define MODEM_PWR_ON TEGRA_GPIO_PE0
40#define MODEM_RESET TEGRA_GPIO_PE1
41#define BB_RST_OUT TEGRA_GPIO_PV1
42
43/* Icera BB GPIO */
44#define AP2MDM_ACK TEGRA_GPIO_PE3
45#define MDM2AP_ACK TEGRA_GPIO_PU5
46#define AP2MDM_ACK2 TEGRA_GPIO_PE2
47#define MDM2AP_ACK2 TEGRA_GPIO_PV0
48
49/* ULPI GPIO */
50#define ULPI_STP TEGRA_GPIO_PY3
51#define ULPI_DIR TEGRA_GPIO_PY1
52#define ULPI_D0 TEGRA_GPIO_PO1
53#define ULPI_D1 TEGRA_GPIO_PO2
54
55static struct wake_lock mdm_wake_lock;
56
57static struct gpio modem_gpios[] = {
58 {MODEM_PWR_ON, GPIOF_OUT_INIT_LOW, "MODEM PWR ON"},
59 {MODEM_RESET, GPIOF_IN, "MODEM RESET"},
60 {BB_RST_OUT, GPIOF_IN, "BB RST OUT"},
61 {MDM2AP_ACK, GPIOF_IN, "MDM2AP_ACK"},
62 {AP2MDM_ACK2, GPIOF_OUT_INIT_HIGH, "AP2MDM ACK2"},
63 {AP2MDM_ACK, GPIOF_OUT_INIT_LOW, "AP2MDM ACK"},
64 {ULPI_STP, GPIOF_IN, "ULPI_STP"},
65 {ULPI_DIR, GPIOF_OUT_INIT_LOW, "ULPI_DIR"},
66 {ULPI_D0, GPIOF_OUT_INIT_LOW, "ULPI_D0"},
67 {ULPI_D1, GPIOF_OUT_INIT_LOW, "ULPI_D1"},
68};
69
70static int baseband_phy_on(void);
71static int baseband_phy_off(void);
72static void baseband_phy_restore_start(void);
73static void baseband_phy_restore_end(void);
74
75static struct tegra_ulpi_trimmer e1219_trimmer = { 10, 1, 1, 1 };
76
77static struct tegra_ulpi_config ehci2_null_ulpi_phy_config = {
78 .trimmer = &e1219_trimmer,
79 .post_phy_on = baseband_phy_on,
80 .pre_phy_off = baseband_phy_off,
81 .phy_restore_start = baseband_phy_restore_start,
82 .phy_restore_end = baseband_phy_restore_end,
83 .phy_restore_gpio = MDM2AP_ACK,
84 .ulpi_dir_gpio = ULPI_DIR,
85 .ulpi_d0_gpio = ULPI_D0,
86 .ulpi_d1_gpio = ULPI_D1,
87};
88
89static struct tegra_ehci_platform_data ehci2_null_ulpi_platform_data = {
90 .operating_mode = TEGRA_USB_HOST,
91 .power_down_on_bus_suspend = 0,
92 .phy_config = &ehci2_null_ulpi_phy_config,
93 .phy_type = TEGRA_USB_PHY_TYPE_NULL_ULPI,
94};
95
96static int __init tegra_null_ulpi_init(void)
97{
98 tegra_ehci2_device.dev.platform_data = &ehci2_null_ulpi_platform_data;
99 platform_device_register(&tegra_ehci2_device);
100 return 0;
101}
102
103static irqreturn_t mdm_start_thread(int irq, void *data)
104{
105 if (gpio_get_value(BB_RST_OUT)) {
106 pr_info("BB_RST_OUT high\n");
107 } else {
108 pr_info("BB_RST_OUT low\n");
109 }
110
111 /* hold wait lock to complete the enumeration */
112 wake_lock_timeout(&mdm_wake_lock, HZ * 10);
113
114 return IRQ_HANDLED;
115}
116
117static int baseband_phy_on(void)
118{
119 static bool phy_init = false;
120
121 if (!phy_init) {
122 /* set AP2MDM_ACK2 low */
123 gpio_set_value(AP2MDM_ACK2, 0);
124 phy_init = true;
125 }
126 pr_info("%s\n", __func__);
127 return 0;
128}
129
130static int baseband_phy_off(void)
131{
132 pr_info("%s\n", __func__);
133 return 0;
134}
135
136static void baseband_phy_restore_start(void)
137{
138 /* set AP2MDM_ACK2 high */
139 gpio_set_value(AP2MDM_ACK2, 1);
140}
141
142static void baseband_phy_restore_end(void)
143{
144 /* set AP2MDM_ACK2 low */
145 gpio_set_value(AP2MDM_ACK2, 0);
146}
147
148static void baseband_start(void)
149{
150 /*
151 * Leave baseband powered OFF.
152 * User-space daemons will take care of powering it up.
153 */
154 pr_info("%s\n", __func__);
155 gpio_set_value(MODEM_PWR_ON, 0);
156}
157
158static void baseband_reset(void)
159{
160 /* Initiate power cycle on baseband sub system */
161 pr_info("%s\n", __func__);
162 gpio_set_value(MODEM_PWR_ON, 0);
163 mdelay(200);
164 gpio_set_value(MODEM_PWR_ON, 1);
165}
166
167static int baseband_init(void)
168{
169 int irq;
170 int ret;
171
172 ret = gpio_request_array(modem_gpios, ARRAY_SIZE(modem_gpios));
173 if (ret)
174 return ret;
175
176 /* enable pull-up for ULPI STP */
177 tegra_pinmux_set_pullupdown(TEGRA_PINGROUP_ULPI_STP,
178 TEGRA_PUPD_PULL_UP);
179
180 /* enable pull-up for MDM2AP_ACK2 */
181 tegra_pinmux_set_pullupdown(TEGRA_PINGROUP_GPIO_PV0,
182 TEGRA_PUPD_PULL_UP);
183
184 tegra_gpio_enable(MODEM_PWR_ON);
185 tegra_gpio_enable(MODEM_RESET);
186 tegra_gpio_enable(AP2MDM_ACK2);
187 tegra_gpio_enable(BB_RST_OUT);
188 tegra_gpio_enable(AP2MDM_ACK);
189 tegra_gpio_enable(MDM2AP_ACK);
190 tegra_gpio_enable(TEGRA_GPIO_PY3);
191 tegra_gpio_enable(TEGRA_GPIO_PO1);
192 tegra_gpio_enable(TEGRA_GPIO_PO2);
193
194 /* export GPIO for user space access through sysfs */
195 gpio_export(MODEM_PWR_ON, false);
196
197 /* phy init */
198 tegra_null_ulpi_init();
199
200 wake_lock_init(&mdm_wake_lock, WAKE_LOCK_SUSPEND, "mdm_lock");
201
202 /* enable IRQ for BB_RST_OUT */
203 irq = gpio_to_irq(BB_RST_OUT);
204
205 ret = request_threaded_irq(irq, NULL, mdm_start_thread,
206 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
207 "mdm_start", NULL);
208 if (ret < 0) {
209 pr_err("%s: request_threaded_irq error\n", __func__);
210 return ret;
211 }
212
213 ret = enable_irq_wake(irq);
214 if (ret) {
215 pr_err("%s: enable_irq_wake error\n", __func__);
216 free_irq(irq, NULL);
217 return ret;
218 }
219
220 return 0;
221}
222
223static const struct tegra_modem_operations baseband_operations = {
224 .init = baseband_init,
225 .start = baseband_start,
226 .reset = baseband_reset,
227};
228
229static struct tegra_usb_modem_power_platform_data baseband_pdata = {
230 .ops = &baseband_operations,
231 .wake_gpio = MDM2AP_ACK2,
232 .flags = IRQF_TRIGGER_FALLING,
233};
234
235static struct platform_device icera_baseband_device = {
236 .name = "tegra_usb_modem_power",
237 .id = -1,
238 .dev = {
239 .platform_data = &baseband_pdata,
240 },
241};
242
243int __init enterprise_modem_init(void)
244{
245 platform_device_register(&icera_baseband_device);
246 return 0;
247}