4 * HSI client driver for Nokia N900 modem.
6 * Copyright (C) 2014 Sebastian Reichel <sre@kernel.org>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * version 2 as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 #include <linux/gpio/consumer.h>
24 #include <linux/hsi/hsi.h>
25 #include <linux/init.h>
26 #include <linux/interrupt.h>
28 #include <linux/of_irq.h>
29 #include <linux/of_gpio.h>
30 #include <linux/hsi/ssi_protocol.h>
32 static unsigned int pm
= 1;
33 module_param(pm
, int, 0400);
35 "Enable power management (0=disabled, 1=userland based [default])");
37 struct nokia_modem_gpio
{
38 struct gpio_desc
*gpio
;
42 struct nokia_modem_device
{
43 struct tasklet_struct nokia_modem_rst_ind_tasklet
;
44 int nokia_modem_rst_ind_irq
;
45 struct device
*device
;
46 struct nokia_modem_gpio
*gpios
;
48 struct hsi_client
*ssi_protocol
;
49 struct hsi_client
*cmt_speech
;
52 static void do_nokia_modem_rst_ind_tasklet(unsigned long data
)
54 struct nokia_modem_device
*modem
= (struct nokia_modem_device
*)data
;
59 dev_info(modem
->device
, "CMT rst line change detected\n");
61 if (modem
->ssi_protocol
)
62 ssip_reset_event(modem
->ssi_protocol
);
65 static irqreturn_t
nokia_modem_rst_ind_isr(int irq
, void *data
)
67 struct nokia_modem_device
*modem
= (struct nokia_modem_device
*)data
;
69 tasklet_schedule(&modem
->nokia_modem_rst_ind_tasklet
);
74 static void nokia_modem_gpio_unexport(struct device
*dev
)
76 struct nokia_modem_device
*modem
= dev_get_drvdata(dev
);
79 for (i
= 0; i
< modem
->gpio_amount
; i
++) {
80 sysfs_remove_link(&dev
->kobj
, modem
->gpios
[i
].name
);
81 gpiod_unexport(modem
->gpios
[i
].gpio
);
85 static int nokia_modem_gpio_probe(struct device
*dev
)
87 struct device_node
*np
= dev
->of_node
;
88 struct nokia_modem_device
*modem
= dev_get_drvdata(dev
);
89 int gpio_count
, gpio_name_count
, i
, err
;
91 gpio_count
= of_gpio_count(np
);
94 dev_err(dev
, "missing gpios: %d\n", gpio_count
);
98 gpio_name_count
= of_property_count_strings(np
, "gpio-names");
100 if (gpio_count
!= gpio_name_count
) {
101 dev_err(dev
, "number of gpios does not equal number of gpio names\n");
105 modem
->gpios
= devm_kzalloc(dev
, gpio_count
*
106 sizeof(struct nokia_modem_gpio
), GFP_KERNEL
);
108 dev_err(dev
, "Could not allocate memory for gpios\n");
112 modem
->gpio_amount
= gpio_count
;
114 for (i
= 0; i
< gpio_count
; i
++) {
115 modem
->gpios
[i
].gpio
= devm_gpiod_get_index(dev
, NULL
, i
,
117 if (IS_ERR(modem
->gpios
[i
].gpio
)) {
118 dev_err(dev
, "Could not get gpio %d\n", i
);
119 return PTR_ERR(modem
->gpios
[i
].gpio
);
122 err
= of_property_read_string_index(np
, "gpio-names", i
,
123 &(modem
->gpios
[i
].name
));
125 dev_err(dev
, "Could not get gpio name %d\n", i
);
129 err
= gpiod_export(modem
->gpios
[i
].gpio
, 0);
133 err
= gpiod_export_link(dev
, modem
->gpios
[i
].name
,
134 modem
->gpios
[i
].gpio
);
142 static int nokia_modem_probe(struct device
*dev
)
144 struct device_node
*np
;
145 struct nokia_modem_device
*modem
;
146 struct hsi_client
*cl
= to_hsi_client(dev
);
147 struct hsi_port
*port
= hsi_get_port(cl
);
148 int irq
, pflags
, err
;
149 struct hsi_board_info ssip
;
150 struct hsi_board_info cmtspeech
;
154 dev_err(dev
, "device tree node not found\n");
158 modem
= devm_kzalloc(dev
, sizeof(*modem
), GFP_KERNEL
);
160 dev_err(dev
, "Could not allocate memory for nokia_modem_device\n");
163 dev_set_drvdata(dev
, modem
);
166 irq
= irq_of_parse_and_map(np
, 0);
168 dev_err(dev
, "Invalid rst_ind interrupt (%d)\n", irq
);
171 modem
->nokia_modem_rst_ind_irq
= irq
;
172 pflags
= irq_get_trigger_type(irq
);
174 tasklet_init(&modem
->nokia_modem_rst_ind_tasklet
,
175 do_nokia_modem_rst_ind_tasklet
, (unsigned long)modem
);
176 err
= devm_request_irq(dev
, irq
, nokia_modem_rst_ind_isr
,
177 pflags
, "modem_rst_ind", modem
);
179 dev_err(dev
, "Request rst_ind irq(%d) failed (flags %d)\n",
183 enable_irq_wake(irq
);
186 err
= nokia_modem_gpio_probe(dev
);
188 dev_err(dev
, "Could not probe GPIOs\n");
193 ssip
.name
= "ssi-protocol";
194 ssip
.tx_cfg
= cl
->tx_cfg
;
195 ssip
.rx_cfg
= cl
->rx_cfg
;
196 ssip
.platform_data
= NULL
;
197 ssip
.archdata
= NULL
;
199 modem
->ssi_protocol
= hsi_new_client(port
, &ssip
);
200 if (!modem
->ssi_protocol
) {
201 dev_err(dev
, "Could not register ssi-protocol device\n");
206 err
= device_attach(&modem
->ssi_protocol
->device
);
208 dev_dbg(dev
, "Missing ssi-protocol driver\n");
211 } else if (err
< 0) {
212 dev_err(dev
, "Could not load ssi-protocol driver (%d)\n", err
);
216 cmtspeech
.name
= "cmt-speech";
217 cmtspeech
.tx_cfg
= cl
->tx_cfg
;
218 cmtspeech
.rx_cfg
= cl
->rx_cfg
;
219 cmtspeech
.platform_data
= NULL
;
220 cmtspeech
.archdata
= NULL
;
222 modem
->cmt_speech
= hsi_new_client(port
, &cmtspeech
);
223 if (!modem
->cmt_speech
) {
224 dev_err(dev
, "Could not register cmt-speech device\n");
229 err
= device_attach(&modem
->cmt_speech
->device
);
231 dev_dbg(dev
, "Missing cmt-speech driver\n");
234 } else if (err
< 0) {
235 dev_err(dev
, "Could not load cmt-speech driver (%d)\n", err
);
239 dev_info(dev
, "Registered Nokia HSI modem\n");
244 hsi_remove_client(&modem
->cmt_speech
->device
, NULL
);
246 hsi_remove_client(&modem
->ssi_protocol
->device
, NULL
);
248 nokia_modem_gpio_unexport(dev
);
250 disable_irq_wake(modem
->nokia_modem_rst_ind_irq
);
251 tasklet_kill(&modem
->nokia_modem_rst_ind_tasklet
);
256 static int nokia_modem_remove(struct device
*dev
)
258 struct nokia_modem_device
*modem
= dev_get_drvdata(dev
);
263 if (modem
->cmt_speech
) {
264 hsi_remove_client(&modem
->cmt_speech
->device
, NULL
);
265 modem
->cmt_speech
= NULL
;
268 if (modem
->ssi_protocol
) {
269 hsi_remove_client(&modem
->ssi_protocol
->device
, NULL
);
270 modem
->ssi_protocol
= NULL
;
273 nokia_modem_gpio_unexport(dev
);
274 dev_set_drvdata(dev
, NULL
);
275 disable_irq_wake(modem
->nokia_modem_rst_ind_irq
);
276 tasklet_kill(&modem
->nokia_modem_rst_ind_tasklet
);
282 static const struct of_device_id nokia_modem_of_match
[] = {
283 { .compatible
= "nokia,n900-modem", },
284 { .compatible
= "nokia,n950-modem", },
285 { .compatible
= "nokia,n9-modem", },
288 MODULE_DEVICE_TABLE(of
, nokia_modem_of_match
);
291 static struct hsi_client_driver nokia_modem_driver
= {
293 .name
= "nokia-modem",
294 .owner
= THIS_MODULE
,
295 .probe
= nokia_modem_probe
,
296 .remove
= nokia_modem_remove
,
297 .of_match_table
= of_match_ptr(nokia_modem_of_match
),
301 static int __init
nokia_modem_init(void)
303 return hsi_register_client_driver(&nokia_modem_driver
);
305 module_init(nokia_modem_init
);
307 static void __exit
nokia_modem_exit(void)
309 hsi_unregister_client_driver(&nokia_modem_driver
);
311 module_exit(nokia_modem_exit
);
313 MODULE_ALIAS("hsi:nokia-modem");
314 MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>");
315 MODULE_DESCRIPTION("HSI driver module for Nokia N900 Modem");
316 MODULE_LICENSE("GPL");