Skip to content

Commit 114574a

Browse files
committed
driver: modem: gsm_ppp: Add support for Quectel
1 parent f1ad85d commit 114574a

File tree

5 files changed

+227
-0
lines changed

5 files changed

+227
-0
lines changed

drivers/console/Kconfig.gsm_mux

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ config GSM_MUX_PENDING_CMD_MAX
6060
config GSM_MUX_MRU_DEFAULT_LEN
6161
int "Default size of received user data (MRU)"
6262
default 127 if MODEM_GSM_SIMCOM
63+
default 127 if MODEM_GSM_QUECTEL
6364
default 31
6465
range 1 1509
6566
depends on GSM_MUX

drivers/modem/Kconfig.gsm

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ config MODEM_GSM_SIMCOM
2828
help
2929
Use this if you have SIMCOM based modem like SIM800 etc.
3030

31+
config MODEM_GSM_QUECTEL
32+
bool "Quectel modem"
33+
help
34+
Use this if you have Quectel based modem like EC21 etc.
35+
3136
endchoice
3237

3338

drivers/modem/gsm_ppp.c

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ LOG_MODULE_REGISTER(modem_gsm, CONFIG_MODEM_LOG_LEVEL);
3030
#include <time.h>
3131
#endif
3232

33+
#if (CONFIG_MODEM_GSM_QUECTEL)
34+
#include "quectel-mdm.h"
35+
#endif
36+
3337
#define GSM_UART_DEV_ID DT_INST_BUS(0)
3438
#define GSM_UART_DEV_NAME DT_INST_BUS_LABEL(0)
3539
#define GSM_CMD_READ_BUF 128
@@ -200,6 +204,15 @@ MODEM_CMD_DEFINE(gsm_cmd_error)
200204
return 0;
201205
}
202206

207+
#if CONFIG_MODEM_GSM_QUECTEL
208+
/* Handler: Modem ready. */
209+
MODEM_CMD_DEFINE(on_cmd_unsol_rdy)
210+
{
211+
k_sem_give(&gsm.sem_response);
212+
return 0;
213+
}
214+
#endif
215+
203216
static const struct modem_cmd response_cmds[] = {
204217
MODEM_CMD("OK", gsm_cmd_ok, 0U, ""),
205218
MODEM_CMD("ERROR", gsm_cmd_error, 0U, ""),
@@ -236,6 +249,12 @@ MODEM_CMD_DEFINE(on_cmd_atcmdinfo_cops)
236249
return 0;
237250
}
238251

252+
#if CONFIG_MODEM_GSM_QUECTEL
253+
static const struct modem_cmd unsol_cmds[] = {
254+
MODEM_CMD("RDY", on_cmd_unsol_rdy, 0U, ""),
255+
};
256+
#endif
257+
239258
#if defined(CONFIG_MODEM_INFO)
240259
#define MDM_MANUFACTURER_LENGTH 10
241260
#define MDM_MODEL_LENGTH 16
@@ -1016,6 +1035,19 @@ static int mux_enable(struct gsm_modem *gsm)
10161035
STRINGIFY(CONFIG_GSM_MUX_MRU_DEFAULT_LEN),
10171036
&gsm->sem_response,
10181037
GSM_CMD_AT_TIMEOUT);
1038+
#elif CONFIG_MODEM_GSM_QUECTEL
1039+
/* Quectel GSM modem */
1040+
ret = modem_cmd_send_nolock(&gsm->context.iface,
1041+
&gsm->context.cmd_handler,
1042+
&response_cmds[0],
1043+
ARRAY_SIZE(response_cmds),
1044+
"AT+CMUX=0,0,5,"
1045+
STRINGIFY(CONFIG_GSM_MUX_MRU_DEFAULT_LEN),
1046+
&gsm->sem_response,
1047+
GSM_CMD_AT_TIMEOUT);
1048+
1049+
/* Quectel requires some time to initialize the CMUX */
1050+
k_sleep(K_SECONDS(1));
10191051
#else
10201052
/* Generic GSM modem */
10211053
ret = modem_cmd_send_nolock(&gsm->context.iface,
@@ -1175,6 +1207,24 @@ static void gsm_configure(struct k_work *work)
11751207
gsm_configure_work);
11761208
int ret = -1;
11771209

1210+
#if CONFIG_MODEM_GSM_QUECTEL
1211+
enable_power(&gsm->context);
1212+
power_key_on(&gsm->context);
1213+
1214+
LOG_INF("Waiting for modem to boot up");
1215+
1216+
ret = k_sem_take(&gsm->sem_response, K_SECONDS(50));
1217+
1218+
if (ret == 0) {
1219+
LOG_INF("Modem RDY");
1220+
} else {
1221+
LOG_INF("Time out waiting for modem RDY");
1222+
(void)k_work_reschedule(&gsm->gsm_configure_work, K_NO_WAIT);
1223+
1224+
return;
1225+
}
1226+
#endif
1227+
11781228
LOG_DBG("Starting modem %p configuration", gsm);
11791229

11801230
ret = modem_cmd_send_nolock(&gsm->context.iface,
@@ -1248,6 +1298,33 @@ void gsm_ppp_stop(const struct device *dev)
12481298
struct gsm_modem *gsm = dev->data;
12491299
struct net_if *iface = gsm->iface;
12501300

1301+
#if (CONFIG_MODEM_GSM_QUECTEL)
1302+
1303+
int ret;
1304+
1305+
LOG_INF("Turning off modem...");
1306+
1307+
/* FIXME: According to EC21 DS, after sending AT+QPOWD, the modem will
1308+
* respond "OK" followed by "POWERED DOWN", then only we can
1309+
* turn off the power. However in my testing I didn't get the
1310+
* "POWERED DOWN".
1311+
*/
1312+
ret = modem_cmd_send_nolock(&gsm->context.iface,
1313+
&gsm->context.cmd_handler,
1314+
&response_cmds[0],
1315+
ARRAY_SIZE(response_cmds),
1316+
"AT+QPOWD=0",
1317+
&gsm->sem_response,
1318+
GSM_CMD_AT_TIMEOUT);
1319+
if (ret < 0) {
1320+
LOG_ERR("Modem took too long to power down normally");
1321+
}
1322+
1323+
disable_power(&gsm->context);
1324+
1325+
LOG_INF("Modem powered down!");
1326+
#endif
1327+
12511328
net_if_l2(iface)->enable(iface, false);
12521329

12531330
if (IS_ENABLED(CONFIG_GSM_MUX)) {
@@ -1274,6 +1351,10 @@ static int gsm_init(const struct device *dev)
12741351

12751352
gsm->cmd_handler_data.cmds[CMD_RESP] = response_cmds;
12761353
gsm->cmd_handler_data.cmds_len[CMD_RESP] = ARRAY_SIZE(response_cmds);
1354+
#if (CONFIG_MODEM_GSM_QUECTEL)
1355+
gsm->cmd_handler_data.cmds[CMD_UNSOL] = unsol_cmds;
1356+
gsm->cmd_handler_data.cmds_len[CMD_UNSOL] = ARRAY_SIZE(unsol_cmds);
1357+
#endif
12771358
gsm->cmd_handler_data.match_buf = &gsm->cmd_match_buf[0];
12781359
gsm->cmd_handler_data.match_buf_len = sizeof(gsm->cmd_match_buf);
12791360
gsm->cmd_handler_data.buf_pool = &gsm_recv_pool;
@@ -1302,6 +1383,12 @@ static int gsm_init(const struct device *dev)
13021383
#endif /* CONFIG_MODEM_INFO */
13031384

13041385
gsm->context.is_automatic_oper = false;
1386+
1387+
#if (CONFIG_MODEM_GSM_QUECTEL)
1388+
gsm->context.pins = modem_pins;
1389+
gsm->context.pins_len = ARRAY_SIZE(modem_pins);
1390+
#endif
1391+
13051392
gsm->gsm_data.rx_rb_buf = &gsm->gsm_rx_rb_buf[0];
13061393
gsm->gsm_data.rx_rb_buf_len = sizeof(gsm->gsm_rx_rb_buf);
13071394

drivers/modem/quectel-mdm.h

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright (c) 2021 G-Technologies Sdn. Bhd.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef QUECTEL_MDM_H
8+
#define QUECTEL_MDM_H
9+
10+
#include <device.h>
11+
12+
/* pin settings */
13+
enum mdm_control_pins {
14+
#if DT_INST_NODE_HAS_PROP(0, power_gpios)
15+
MDM_PWR,
16+
#endif
17+
#if DT_INST_NODE_HAS_PROP(0, power_key_gpios)
18+
MDM_PWR_KEY,
19+
#endif
20+
#if DT_INST_NODE_HAS_PROP(0, reset_gpios)
21+
MDM_RST,
22+
#endif
23+
#if DT_INST_NODE_HAS_PROP(0, dtr_gpios)
24+
MDM_DTR,
25+
#endif
26+
};
27+
28+
/* Modem pins - Power, Reset & others. */
29+
static struct modem_pin modem_pins[] = {
30+
#if DT_INST_NODE_HAS_PROP(0, power_gpios)
31+
/* MDM_POWER SUPPLY */
32+
MODEM_PIN(DT_INST_GPIO_LABEL(0, power_gpios),
33+
DT_INST_GPIO_PIN(0, power_gpios),
34+
DT_INST_GPIO_FLAGS(0, power_gpios) | GPIO_OUTPUT_LOW),
35+
#endif
36+
37+
#if DT_INST_NODE_HAS_PROP(0, power_key_gpios)
38+
/* MDM_POWER_KEY */
39+
MODEM_PIN(DT_INST_GPIO_LABEL(0, power_key_gpios),
40+
DT_INST_GPIO_PIN(0, power_key_gpios),
41+
DT_INST_GPIO_FLAGS(0, power_key_gpios) | GPIO_OUTPUT_LOW),
42+
#endif
43+
44+
#if DT_INST_NODE_HAS_PROP(0, reset_gpios)
45+
/* MDM_RESET */
46+
MODEM_PIN(DT_INST_GPIO_LABEL(0, reset_gpios),
47+
DT_INST_GPIO_PIN(0, reset_gpios),
48+
DT_INST_GPIO_FLAGS(0, reset_gpios) | GPIO_OUTPUT_LOW),
49+
#endif
50+
51+
#if DT_INST_NODE_HAS_PROP(0, dtr_gpios)
52+
/* MDM_DTR */
53+
MODEM_PIN(DT_INST_GPIO_LABEL(0, dtr_gpios),
54+
DT_INST_GPIO_PIN(0, dtr_gpios),
55+
DT_INST_GPIO_FLAGS(0, dtr_gpios) | GPIO_OUTPUT_LOW),
56+
#endif
57+
};
58+
59+
#if DT_INST_NODE_HAS_PROP(0, power_gpios)
60+
static void enable_power(struct modem_context *mctx)
61+
{
62+
/* Make sure the power is off before we turn it on */
63+
modem_pin_write(mctx, MDM_PWR, 0);
64+
k_sleep(K_SECONDS(2));
65+
66+
modem_pin_write(mctx, MDM_PWR, 1);
67+
68+
/* Wait for the power to stabilize */
69+
k_sleep(K_SECONDS(2));
70+
}
71+
72+
static void disable_power(struct modem_context *mctx)
73+
{
74+
modem_pin_write(mctx, MDM_PWR, 0);
75+
}
76+
#endif
77+
78+
#if DT_INST_NODE_HAS_PROP(0, power_key_gpios)
79+
static void press_power_key(struct modem_context *mctx, k_timeout_t dur)
80+
{
81+
modem_pin_write(mctx, MDM_PWR_KEY, 1);
82+
k_sleep(dur);
83+
modem_pin_write(mctx, MDM_PWR_KEY, 0);
84+
}
85+
86+
#if DT_INST_NODE_HAS_PROP(0, power_key_on_ms)
87+
#define power_key_on(mctx) press_power_key(mctx, K_MSEC(DT_INST_PROP(0, power_key_on_ms)))
88+
#endif
89+
#if DT_INST_NODE_HAS_PROP(0, power_key_off_ms)
90+
#define power_key_off(mctx) press_power_key(mctx, K_MSEC(DT_INST_PROP(0, power_key_off_ms)))
91+
#endif
92+
#endif /* DT_INST_NODE_HAS_PROP(0, power_key_gpios) */
93+
94+
#if DT_INST_NODE_HAS_PROP(0, dtr_gpios)
95+
#define hw_enable_sleep(mctx) modem_pin_write(mctx, MDM_DTR, 1)
96+
#define hw_disable_sleep(mctx) modem_pin_write(mctx, MDM_DTR, 0)
97+
#endif
98+
99+
#endif /* QUECTEL_MDM_H */

dts/bindings/modem/gsm-ppp.yaml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,38 @@ properties:
1111
label:
1212
required: true
1313

14+
power-gpios:
15+
type: phandle-array
16+
required: false
17+
description: |
18+
Pin to enable the power supply to the modem.
19+
20+
power-key-gpios:
21+
type: phandle-array
22+
required: false
23+
description: |
24+
Power key pin of the modem.
25+
26+
power-key-on-ms:
27+
type: int
28+
required: false
29+
description: |
30+
Duration required to hold the power key for the modem to turn on.
31+
32+
power-key-off-ms:
33+
type: int
34+
required: false
35+
description: |
36+
Duration required to hold the power key for the modem to turn off.
37+
38+
reset-gpios:
39+
type: phandle-array
40+
required: false
41+
description: |
42+
Reset pin of the modem.
43+
44+
dtr-gpios:
45+
type: phandle-array
46+
required: false
47+
description: |
48+
DTR pin of the modem.

0 commit comments

Comments
 (0)