blob: 95a7c7b8936ce71fbc367dd46c1f0c40ba745a3c [file] [log] [blame]
Harald Welte31f817c2017-02-03 22:21:32 +01001/* Code to control the PERST lines of attached modems
2 *
Kévin Redon9a12d682018-07-08 13:21:16 +02003 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
16 */
17/* Depending on the board this is running on, it might be possible
Harald Welte31f817c2017-02-03 22:21:32 +010018 * for the controller to set the status of the PERST input line of
19 * the cellular modem. If the board supports this, it sets the
20 * PIN_PERST1 and/or PIN_PERST2 defines in its board.h file.
21 */
Harald Welte31f817c2017-02-03 22:21:32 +010022#include "board.h"
Harald Welte0709d2d2017-05-11 00:06:00 +020023#include "trace.h"
Harald Welte31f817c2017-02-03 22:21:32 +010024#include "wwan_perst.h"
Harald Welte9d90d282018-06-29 22:25:42 +020025#include <osmocom/core/timer.h>
Harald Welte987f59a2017-02-04 12:34:35 +010026
Harald Weltecb093ce2017-05-08 22:28:41 +020027struct wwan_perst {
Harald Welte514c6d12017-11-03 20:40:56 +010028 uint8_t idx;
Harald Weltecb093ce2017-05-08 22:28:41 +020029 const Pin pin;
30 struct osmo_timer_list timer;
31};
Harald Welte31f817c2017-02-03 22:21:32 +010032
33#ifdef PIN_PERST1
Harald Weltecb093ce2017-05-08 22:28:41 +020034static struct wwan_perst perst1 = {
Harald Welte514c6d12017-11-03 20:40:56 +010035 .idx = 0,
Harald Weltecb093ce2017-05-08 22:28:41 +020036 .pin = PIN_PERST1,
37};
Harald Welte31f817c2017-02-03 22:21:32 +010038#endif
39
40#ifdef PIN_PERST2
Harald Weltecb093ce2017-05-08 22:28:41 +020041static struct wwan_perst perst2 = {
Harald Welte514c6d12017-11-03 20:40:56 +010042 .idx = 1,
Harald Weltecb093ce2017-05-08 22:28:41 +020043 .pin = PIN_PERST2,
44};
Harald Welte31f817c2017-02-03 22:21:32 +010045#endif
46
Harald Welte114e74d2017-05-09 06:45:27 +020047static int initialized = 0;
48
Harald Welte987f59a2017-02-04 12:34:35 +010049static void perst_tmr_cb(void *data)
50{
Harald Weltecb093ce2017-05-08 22:28:41 +020051 struct wwan_perst *perst = data;
Harald Welte987f59a2017-02-04 12:34:35 +010052 /* release the (low-active) reset */
Harald Welte514c6d12017-11-03 20:40:56 +010053 TRACE_INFO("%u: De-asserting modem reset\r\n", perst->idx);
Harald Weltecb093ce2017-05-08 22:28:41 +020054 PIO_Clear(&perst->pin);
Harald Welte987f59a2017-02-04 12:34:35 +010055}
56
Harald Weltecb093ce2017-05-08 22:28:41 +020057static struct wwan_perst *get_perst_for_modem(int modem_nr)
Harald Welte31f817c2017-02-03 22:21:32 +010058{
Harald Welte114e74d2017-05-09 06:45:27 +020059 if (!initialized) {
60 TRACE_ERROR("Somebody forgot to call wwan_perst_init()\r\n");
61 wwan_perst_init();
62 }
63
Harald Welte31f817c2017-02-03 22:21:32 +010064 switch (modem_nr) {
65#ifdef PIN_PERST1
Harald Welte44622df2017-05-11 00:04:50 +020066 case 0:
Harald Weltecb093ce2017-05-08 22:28:41 +020067 return &perst1;
Harald Welte31f817c2017-02-03 22:21:32 +010068#endif
69#ifdef PIN_PERST2
Harald Welte44622df2017-05-11 00:04:50 +020070 case 1:
Harald Weltecb093ce2017-05-08 22:28:41 +020071 return &perst2;
Harald Welte31f817c2017-02-03 22:21:32 +010072#endif
73 default:
Harald Weltecb093ce2017-05-08 22:28:41 +020074 return NULL;
Harald Welte31f817c2017-02-03 22:21:32 +010075 }
Harald Weltecb093ce2017-05-08 22:28:41 +020076}
77
78int wwan_perst_do_reset_pulse(int modem_nr, unsigned int duration_ms)
79{
80 struct wwan_perst *perst = get_perst_for_modem(modem_nr);
81 if (!perst)
82 return -1;
83
Harald Welte0709d2d2017-05-11 00:06:00 +020084 TRACE_INFO("%u: Asserting modem reset\r\n", modem_nr);
Harald Weltecb093ce2017-05-08 22:28:41 +020085 PIO_Set(&perst->pin);
86 osmo_timer_schedule(&perst->timer, duration_ms/1000, (duration_ms%1000)*1000);
87
88 return 0;
89}
90
91int wwan_perst_set(int modem_nr, int active)
92{
93 struct wwan_perst *perst = get_perst_for_modem(modem_nr);
94 if (!perst)
95 return -1;
96
97 osmo_timer_del(&perst->timer);
Harald Welte0709d2d2017-05-11 00:06:00 +020098 if (active) {
99 TRACE_INFO("%u: Asserting modem reset\r\n", modem_nr);
Harald Weltecb093ce2017-05-08 22:28:41 +0200100 PIO_Set(&perst->pin);
Harald Welte0709d2d2017-05-11 00:06:00 +0200101 } else {
102 TRACE_INFO("%u: De-asserting modem reset\r\n", modem_nr);
Harald Weltecb093ce2017-05-08 22:28:41 +0200103 PIO_Clear(&perst->pin);
Harald Welte0709d2d2017-05-11 00:06:00 +0200104 }
Harald Welte987f59a2017-02-04 12:34:35 +0100105
Harald Welte31f817c2017-02-03 22:21:32 +0100106 return 0;
107}
108
109int wwan_perst_init(void)
110{
111 int num_perst = 0;
112#ifdef PIN_PERST1
Harald Weltecb093ce2017-05-08 22:28:41 +0200113 PIO_Configure(&perst1.pin, 1);
114 perst1.timer.cb = perst_tmr_cb;
115 perst1.timer.data = (void *) &perst1;
Harald Welte31f817c2017-02-03 22:21:32 +0100116 num_perst++;
117#endif
118
119#ifdef PIN_PERST2
Harald Weltecb093ce2017-05-08 22:28:41 +0200120 PIO_Configure(&perst2.pin, 1);
121 perst2.timer.cb = perst_tmr_cb;
122 perst2.timer.data = (void *) &perst2;
Harald Welte31f817c2017-02-03 22:21:32 +0100123 num_perst++;
124#endif
Harald Welteeb50c9f2017-11-03 20:50:47 +0100125 initialized = 1;
Harald Welte31f817c2017-02-03 22:21:32 +0100126 return num_perst;
127}