blob: 0e85776bc84aa8e7c75d7f971ced4120f184a405 [file] [log] [blame]
Arun KS0cb73fd2017-01-16 17:47:03 +05301/* Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved.
Abhimanyu Kapurc75b2e12016-02-22 18:15:13 -08002 *
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");
Arun KS0cb73fd2017-01-16 17:47:03 +053071 if (mdm->esoc->auto_boot)
72 return 0;
73
Abhimanyu Kapurc75b2e12016-02-22 18:15:13 -080074 mdm_toggle_soft_reset(mdm, false);
75 /* Add a delay to allow PON sequence to complete*/
76 mdelay(50);
77 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_STATUS), 1);
78 if (gpio_is_valid(MDM_GPIO(mdm, MDM2AP_PBLRDY))) {
79 for (i = 0; i < MDM_PBLRDY_CNT; i++) {
80 pblrdy = gpio_get_value(MDM_GPIO(mdm, MDM2AP_PBLRDY));
81 if (pblrdy)
82 break;
83 usleep_range(5000, 6000);
84 }
85 dev_dbg(dev, "pblrdy i:%d\n", i);
86 mdelay(200);
87 }
88 /*
89 * No PBLRDY gpio associated with this modem
90 * Send request for image. Let userspace confirm establishment of
91 * link to external modem.
92 */
93 else
94 esoc_clink_queue_request(ESOC_REQ_IMG, mdm->esoc);
95 return 0;
96}
97
98static int mdm4x_power_down(struct mdm_ctrl *mdm)
99{
100 struct device *dev = mdm->dev;
101 int soft_reset_direction = mdm->soft_reset_inverted ? 1 : 0;
102 /* Assert the soft reset line whether mdm2ap_status went low or not */
103 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
104 soft_reset_direction);
105 dev_dbg(dev, "Doing a hard reset\n");
106 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
107 soft_reset_direction);
108 /*
109 * Currently, there is a debounce timer on the charm PMIC. It is
110 * necessary to hold the PMIC RESET low for 400ms
111 * for the reset to fully take place. Sleep here to ensure the
112 * reset has occurred before the function exits.
113 */
114 mdelay(400);
115 return 0;
116}
117
118static int mdm9x55_power_down(struct mdm_ctrl *mdm)
119{
120 struct device *dev = mdm->dev;
121 int soft_reset_direction = mdm->soft_reset_inverted ? 1 : 0;
122 /* Assert the soft reset line whether mdm2ap_status went low or not */
123 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
124 soft_reset_direction);
125 dev_dbg(dev, "Doing a hard reset\n");
126 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
127 soft_reset_direction);
128 /*
129 * Currently, there is a debounce timer on the charm PMIC. It is
130 * necessary to hold the PMIC RESET low for 406ms
131 * for the reset to fully take place. Sleep here to ensure the
132 * reset has occurred before the function exits.
133 */
134 mdelay(406);
135 return 0;
136}
137
138static void mdm4x_cold_reset(struct mdm_ctrl *mdm)
139{
Arun KS0cb73fd2017-01-16 17:47:03 +0530140 if (!gpio_is_valid(MDM_GPIO(mdm, AP2MDM_SOFT_RESET)))
141 return;
142
Abhimanyu Kapurc75b2e12016-02-22 18:15:13 -0800143 dev_dbg(mdm->dev, "Triggering mdm cold reset");
144 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
145 !!mdm->soft_reset_inverted);
146 mdelay(300);
147 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
148 !mdm->soft_reset_inverted);
149}
150
151static void mdm9x55_cold_reset(struct mdm_ctrl *mdm)
152{
153 dev_dbg(mdm->dev, "Triggering mdm cold reset");
154 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
155 !!mdm->soft_reset_inverted);
156 mdelay(334);
157 gpio_direction_output(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
158 !mdm->soft_reset_inverted);
159}
160
161static int mdm4x_pon_dt_init(struct mdm_ctrl *mdm)
162{
163 int val;
164 struct device_node *node = mdm->dev->of_node;
165 enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
166
167 val = of_get_named_gpio_flags(node, "qcom,ap2mdm-soft-reset-gpio",
168 0, &flags);
169 if (val >= 0) {
170 MDM_GPIO(mdm, AP2MDM_SOFT_RESET) = val;
171 if (flags & OF_GPIO_ACTIVE_LOW)
172 mdm->soft_reset_inverted = 1;
173 return 0;
174 } else
175 return -EIO;
176}
177
178static int mdm4x_pon_setup(struct mdm_ctrl *mdm)
179{
180 struct device *dev = mdm->dev;
181
182 if (gpio_is_valid(MDM_GPIO(mdm, AP2MDM_SOFT_RESET))) {
183 if (gpio_request(MDM_GPIO(mdm, AP2MDM_SOFT_RESET),
184 "AP2MDM_SOFT_RESET")) {
185 dev_err(dev, "Cannot config AP2MDM_SOFT_RESET gpio\n");
186 return -EIO;
187 }
188 }
189 return 0;
190}
191
192struct mdm_pon_ops mdm9x25_pon_ops = {
193 .pon = mdm4x_do_first_power_on,
194 .soft_reset = mdm4x_toggle_soft_reset,
195 .poff_force = mdm4x_power_down,
196 .cold_reset = mdm4x_cold_reset,
197 .dt_init = mdm4x_pon_dt_init,
198 .setup = mdm4x_pon_setup,
199};
200
201struct mdm_pon_ops mdm9x35_pon_ops = {
202 .pon = mdm4x_do_first_power_on,
203 .soft_reset = mdm4x_toggle_soft_reset,
204 .poff_force = mdm4x_power_down,
205 .cold_reset = mdm4x_cold_reset,
206 .dt_init = mdm4x_pon_dt_init,
207 .setup = mdm4x_pon_setup,
208};
209
Abhimanyu Kapurc75b2e12016-02-22 18:15:13 -0800210struct mdm_pon_ops mdm9x55_pon_ops = {
211 .pon = mdm4x_do_first_power_on,
212 .soft_reset = mdm9x55_toggle_soft_reset,
213 .poff_force = mdm9x55_power_down,
214 .cold_reset = mdm9x55_cold_reset,
215 .dt_init = mdm4x_pon_dt_init,
216 .setup = mdm4x_pon_setup,
217};