blob: 47d54dbc79c96b748aaeb830e0110b4dd7e1e12e [file] [log] [blame]
Abhimanyu Kapurc75b2e12016-02-22 18:15:13 -08001/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include "esoc-mdm.h"
14
15/* This function can be called from atomic context. */
16static int mdm4x_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic)
17{
18 int soft_reset_direction_assert = 0,
19 soft_reset_direction_de_assert = 1;
20
21 if (mdm->soft_reset_inverted) {
22 soft_reset_direction_assert = 1;
23 soft_reset_direction_de_assert = 0;
24 }
25 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
26 soft_reset_direction_assert);
27 /*
28 * Allow PS hold assert to be detected
29 */
30 if (!atomic)
31 usleep_range(8000, 9000);
32 else
33 mdelay(6);
34 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
35 soft_reset_direction_de_assert);
36 return 0;
37}
38
39/* This function can be called from atomic context. */
40static int mdm9x55_toggle_soft_reset(struct mdm_ctrl *mdm, bool atomic)
41{
42 int soft_reset_direction_assert = 0,
43 soft_reset_direction_de_assert = 1;
44
45 if (mdm->soft_reset_inverted) {
46 soft_reset_direction_assert = 1;
47 soft_reset_direction_de_assert = 0;
48 }
49 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
50 soft_reset_direction_assert);
51 /*
52 * Allow PS hold assert to be detected
53 */
54 if (!atomic)
55 usleep_range(203000, 300000);
56 else
57 mdelay(203);
58 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
59 soft_reset_direction_de_assert);
60 return 0;
61}
62
63
64static int mdm4x_do_first_power_on(struct mdm_ctrl *mdm)
65{
66 int i;
67 int pblrdy;
68 struct device *dev = mdm->dev;
69
70 dev_dbg(dev, "Powering on modem for the first time\n");
71 mdm_toggle_soft_reset(mdm, false);
72 /* Add a delay to allow PON sequence to complete*/
73 mdelay(50);
74 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_STATUS), 1);
75 if (gpio_is_valid(MDM_GPIO(mdm, MDM2AP_PBLRDY))) {
76 for (i = 0; i < MDM_PBLRDY_CNT; i++) {
77 pblrdy = gpio_get_value(MDM_GPIO(mdm, MDM2AP_PBLRDY));
78 if (pblrdy)
79 break;
80 usleep_range(5000, 6000);
81 }
82 dev_dbg(dev, "pblrdy i:%d\n", i);
83 mdelay(200);
84 }
85 /*
86 * No PBLRDY gpio associated with this modem
87 * Send request for image. Let userspace confirm establishment of
88 * link to external modem.
89 */
90 else
91 esoc_clink_queue_request(ESOC_REQ_IMG, mdm->esoc);
92 return 0;
93}
94
95static int mdm4x_power_down(struct mdm_ctrl *mdm)
96{
97 struct device *dev = mdm->dev;
98 int soft_reset_direction = mdm->soft_reset_inverted ? 1 : 0;
99 /* Assert the soft reset line whether mdm2ap_status went low or not */
100 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
101 soft_reset_direction);
102 dev_dbg(dev, "Doing a hard reset\n");
103 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
104 soft_reset_direction);
105 /*
106 * Currently, there is a debounce timer on the charm PMIC. It is
107 * necessary to hold the PMIC RESET low for 400ms
108 * for the reset to fully take place. Sleep here to ensure the
109 * reset has occurred before the function exits.
110 */
111 mdelay(400);
112 return 0;
113}
114
115static int mdm9x55_power_down(struct mdm_ctrl *mdm)
116{
117 struct device *dev = mdm->dev;
118 int soft_reset_direction = mdm->soft_reset_inverted ? 1 : 0;
119 /* Assert the soft reset line whether mdm2ap_status went low or not */
120 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
121 soft_reset_direction);
122 dev_dbg(dev, "Doing a hard reset\n");
123 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
124 soft_reset_direction);
125 /*
126 * Currently, there is a debounce timer on the charm PMIC. It is
127 * necessary to hold the PMIC RESET low for 406ms
128 * for the reset to fully take place. Sleep here to ensure the
129 * reset has occurred before the function exits.
130 */
131 mdelay(406);
132 return 0;
133}
134
135static void mdm4x_cold_reset(struct mdm_ctrl *mdm)
136{
137 dev_dbg(mdm->dev, "Triggering mdm cold reset");
138 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
139 !!mdm->soft_reset_inverted);
140 mdelay(300);
141 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
142 !mdm->soft_reset_inverted);
143}
144
145static void mdm9x55_cold_reset(struct mdm_ctrl *mdm)
146{
147 dev_dbg(mdm->dev, "Triggering mdm cold reset");
148 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
149 !!mdm->soft_reset_inverted);
150 mdelay(334);
151 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
152 !mdm->soft_reset_inverted);
153}
154
155static int mdm4x_pon_dt_init(struct mdm_ctrl *mdm)
156{
157 int val;
158 struct device_node *node = mdm->dev->of_node;
159 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
160
161 val = of_get_named_gpio_flags(node, "qcom,ap2mdm-soft-reset-gpio",
162 0, &flags);
163 if (val >= 0) {
164 MDM_GPIO(mdm, AP2MDM_SOFT_RESET) = val;
165 if (flags & OF_GPIO_ACTIVE_LOW)
166 mdm->soft_reset_inverted = 1;
167 return 0;
168 } else
169 return -EIO;
170}
171
172static int mdm4x_pon_setup(struct mdm_ctrl *mdm)
173{
174 struct device *dev = mdm->dev;
175
176 if (gpio_is_valid(MDM_GPIO(mdm, AP2MDM_SOFT_RESET))) {
177 if (gpio_request(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
178 "AP2MDM_SOFT_RESET")) {
179 dev_err(dev, "Cannot config AP2MDM_SOFT_RESET gpio\n");
180 return -EIO;
181 }
182 }
183 return 0;
184}
185
186struct mdm_pon_ops mdm9x25_pon_ops = {
187 .pon = mdm4x_do_first_power_on,
188 .soft_reset = mdm4x_toggle_soft_reset,
189 .poff_force = mdm4x_power_down,
190 .cold_reset = mdm4x_cold_reset,
191 .dt_init = mdm4x_pon_dt_init,
192 .setup = mdm4x_pon_setup,
193};
194
195struct mdm_pon_ops mdm9x35_pon_ops = {
196 .pon = mdm4x_do_first_power_on,
197 .soft_reset = mdm4x_toggle_soft_reset,
198 .poff_force = mdm4x_power_down,
199 .cold_reset = mdm4x_cold_reset,
200 .dt_init = mdm4x_pon_dt_init,
201 .setup = mdm4x_pon_setup,
202};
203
204struct mdm_pon_ops mdm9x45_pon_ops = {
205 .pon = mdm4x_do_first_power_on,
206 .soft_reset = mdm4x_toggle_soft_reset,
207 .poff_force = mdm4x_power_down,
208 .cold_reset = mdm4x_cold_reset,
209 .dt_init = mdm4x_pon_dt_init,
210 .setup = mdm4x_pon_setup,
211};
212
213struct mdm_pon_ops mdm9x55_pon_ops = {
214 .pon = mdm4x_do_first_power_on,
215 .soft_reset = mdm9x55_toggle_soft_reset,
216 .poff_force = mdm9x55_power_down,
217 .cold_reset = mdm9x55_cold_reset,
218 .dt_init = mdm4x_pon_dt_init,
219 .setup = mdm4x_pon_setup,
220};