1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * nokia-modem.c 4 * 5 * HSI client driver for Nokia N900 modem. 6 * 7 * Copyright (C) 2014 Sebastian Reichel <sre@kernel.org> 8 */ 9 10 #include <linux/gpio/consumer.h> 11 #include <linux/hsi/hsi.h> 12 #include <linux/init.h> 13 #include <linux/interrupt.h> 14 #include <linux/of.h> 15 #include <linux/of_irq.h> 16 #include <linux/hsi/ssi_protocol.h> 17 18 static unsigned int pm = 1; 19 module_param(pm, int, 0400); 20 MODULE_PARM_DESC(pm, 21 "Enable power management (0=disabled, 1=userland based [default])"); 22 23 struct nokia_modem_gpio { 24 struct gpio_desc *gpio; 25 const char *name; 26 }; 27 28 struct nokia_modem_device { 29 struct tasklet_struct nokia_modem_rst_ind_tasklet; 30 int nokia_modem_rst_ind_irq; 31 struct device *device; 32 struct nokia_modem_gpio *gpios; 33 int gpio_amount; 34 struct hsi_client *ssi_protocol; 35 struct hsi_client *cmt_speech; 36 }; 37 38 static void do_nokia_modem_rst_ind_tasklet(unsigned long data) 39 { 40 struct nokia_modem_device *modem = (struct nokia_modem_device *)data; 41 42 if (!modem) 43 return; 44 45 dev_info(modem->device, "CMT rst line change detected\n"); 46 47 if (modem->ssi_protocol) 48 ssip_reset_event(modem->ssi_protocol); 49 } 50 51 static irqreturn_t nokia_modem_rst_ind_isr(int irq, void *data) 52 { 53 struct nokia_modem_device *modem = (struct nokia_modem_device *)data; 54 55 tasklet_schedule(&modem->nokia_modem_rst_ind_tasklet); 56 57 return IRQ_HANDLED; 58 } 59 60 static void nokia_modem_gpio_unexport(struct device *dev) 61 { 62 struct nokia_modem_device *modem = dev_get_drvdata(dev); 63 int i; 64 65 for (i = 0; i < modem->gpio_amount; i++) { 66 sysfs_remove_link(&dev->kobj, modem->gpios[i].name); 67 gpiod_unexport(modem->gpios[i].gpio); 68 } 69 } 70 71 static int nokia_modem_gpio_probe(struct device *dev) 72 { 73 struct device_node *np = dev->of_node; 74 struct nokia_modem_device *modem = dev_get_drvdata(dev); 75 int gpio_count, gpio_name_count, i, err; 76 77 gpio_count = gpiod_count(dev, NULL); 78 if (gpio_count < 0) { 79 dev_err(dev, "missing gpios: %d\n", gpio_count); 80 return gpio_count; 81 } 82 83 gpio_name_count = of_property_count_strings(np, "gpio-names"); 84 85 if (gpio_count != gpio_name_count) { 86 dev_err(dev, "number of gpios does not equal number of gpio names\n"); 87 return -EINVAL; 88 } 89 90 modem->gpios = devm_kcalloc(dev, gpio_count, sizeof(*modem->gpios), 91 GFP_KERNEL); 92 if (!modem->gpios) 93 return -ENOMEM; 94 95 modem->gpio_amount = gpio_count; 96 97 for (i = 0; i < gpio_count; i++) { 98 modem->gpios[i].gpio = devm_gpiod_get_index(dev, NULL, i, 99 GPIOD_OUT_LOW); 100 if (IS_ERR(modem->gpios[i].gpio)) { 101 dev_err(dev, "Could not get gpio %d\n", i); 102 return PTR_ERR(modem->gpios[i].gpio); 103 } 104 105 err = of_property_read_string_index(np, "gpio-names", i, 106 &(modem->gpios[i].name)); 107 if (err) { 108 dev_err(dev, "Could not get gpio name %d\n", i); 109 return err; 110 } 111 112 err = gpiod_export(modem->gpios[i].gpio, 0); 113 if (err) 114 return err; 115 116 err = gpiod_export_link(dev, modem->gpios[i].name, 117 modem->gpios[i].gpio); 118 if (err) 119 return err; 120 } 121 122 return 0; 123 } 124 125 static int nokia_modem_probe(struct device *dev) 126 { 127 struct device_node *np; 128 struct nokia_modem_device *modem; 129 struct hsi_client *cl = to_hsi_client(dev); 130 struct hsi_port *port = hsi_get_port(cl); 131 int irq, pflags, err; 132 struct hsi_board_info ssip; 133 struct hsi_board_info cmtspeech; 134 135 np = dev->of_node; 136 if (!np) { 137 dev_err(dev, "device tree node not found\n"); 138 return -ENXIO; 139 } 140 141 modem = devm_kzalloc(dev, sizeof(*modem), GFP_KERNEL); 142 if (!modem) 143 return -ENOMEM; 144 145 dev_set_drvdata(dev, modem); 146 modem->device = dev; 147 148 irq = irq_of_parse_and_map(np, 0); 149 if (!irq) { 150 dev_err(dev, "Invalid rst_ind interrupt (%d)\n", irq); 151 return -EINVAL; 152 } 153 modem->nokia_modem_rst_ind_irq = irq; 154 pflags = irq_get_trigger_type(irq); 155 156 tasklet_init(&modem->nokia_modem_rst_ind_tasklet, 157 do_nokia_modem_rst_ind_tasklet, (unsigned long)modem); 158 err = devm_request_irq(dev, irq, nokia_modem_rst_ind_isr, 159 pflags, "modem_rst_ind", modem); 160 if (err < 0) { 161 dev_err(dev, "Request rst_ind irq(%d) failed (flags %d)\n", 162 irq, pflags); 163 return err; 164 } 165 enable_irq_wake(irq); 166 167 if (pm) { 168 err = nokia_modem_gpio_probe(dev); 169 if (err < 0) { 170 dev_err(dev, "Could not probe GPIOs\n"); 171 goto error1; 172 } 173 } 174 175 ssip.name = "ssi-protocol"; 176 ssip.tx_cfg = cl->tx_cfg; 177 ssip.rx_cfg = cl->rx_cfg; 178 ssip.platform_data = NULL; 179 ssip.archdata = NULL; 180 181 modem->ssi_protocol = hsi_new_client(port, &ssip); 182 if (!modem->ssi_protocol) { 183 dev_err(dev, "Could not register ssi-protocol device\n"); 184 err = -ENOMEM; 185 goto error2; 186 } 187 188 err = device_attach(&modem->ssi_protocol->device); 189 if (err == 0) { 190 dev_dbg(dev, "Missing ssi-protocol driver\n"); 191 err = -EPROBE_DEFER; 192 goto error3; 193 } else if (err < 0) { 194 dev_err(dev, "Could not load ssi-protocol driver (%d)\n", err); 195 goto error3; 196 } 197 198 cmtspeech.name = "cmt-speech"; 199 cmtspeech.tx_cfg = cl->tx_cfg; 200 cmtspeech.rx_cfg = cl->rx_cfg; 201 cmtspeech.platform_data = NULL; 202 cmtspeech.archdata = NULL; 203 204 modem->cmt_speech = hsi_new_client(port, &cmtspeech); 205 if (!modem->cmt_speech) { 206 dev_err(dev, "Could not register cmt-speech device\n"); 207 err = -ENOMEM; 208 goto error3; 209 } 210 211 err = device_attach(&modem->cmt_speech->device); 212 if (err == 0) { 213 dev_dbg(dev, "Missing cmt-speech driver\n"); 214 err = -EPROBE_DEFER; 215 goto error4; 216 } else if (err < 0) { 217 dev_err(dev, "Could not load cmt-speech driver (%d)\n", err); 218 goto error4; 219 } 220 221 dev_info(dev, "Registered Nokia HSI modem\n"); 222 223 return 0; 224 225 error4: 226 hsi_remove_client(&modem->cmt_speech->device, NULL); 227 error3: 228 hsi_remove_client(&modem->ssi_protocol->device, NULL); 229 error2: 230 nokia_modem_gpio_unexport(dev); 231 error1: 232 disable_irq_wake(modem->nokia_modem_rst_ind_irq); 233 tasklet_kill(&modem->nokia_modem_rst_ind_tasklet); 234 235 return err; 236 } 237 238 static int nokia_modem_remove(struct device *dev) 239 { 240 struct nokia_modem_device *modem = dev_get_drvdata(dev); 241 242 if (!modem) 243 return 0; 244 245 if (modem->cmt_speech) { 246 hsi_remove_client(&modem->cmt_speech->device, NULL); 247 modem->cmt_speech = NULL; 248 } 249 250 if (modem->ssi_protocol) { 251 hsi_remove_client(&modem->ssi_protocol->device, NULL); 252 modem->ssi_protocol = NULL; 253 } 254 255 nokia_modem_gpio_unexport(dev); 256 dev_set_drvdata(dev, NULL); 257 disable_irq_wake(modem->nokia_modem_rst_ind_irq); 258 tasklet_kill(&modem->nokia_modem_rst_ind_tasklet); 259 260 return 0; 261 } 262 263 #ifdef CONFIG_OF 264 static const struct of_device_id nokia_modem_of_match[] = { 265 { .compatible = "nokia,n900-modem", }, 266 { .compatible = "nokia,n950-modem", }, 267 { .compatible = "nokia,n9-modem", }, 268 {}, 269 }; 270 MODULE_DEVICE_TABLE(of, nokia_modem_of_match); 271 #endif 272 273 static struct hsi_client_driver nokia_modem_driver = { 274 .driver = { 275 .name = "nokia-modem", 276 .owner = THIS_MODULE, 277 .probe = nokia_modem_probe, 278 .remove = nokia_modem_remove, 279 .of_match_table = of_match_ptr(nokia_modem_of_match), 280 }, 281 }; 282 283 static int __init nokia_modem_init(void) 284 { 285 return hsi_register_client_driver(&nokia_modem_driver); 286 } 287 module_init(nokia_modem_init); 288 289 static void __exit nokia_modem_exit(void) 290 { 291 hsi_unregister_client_driver(&nokia_modem_driver); 292 } 293 module_exit(nokia_modem_exit); 294 295 MODULE_ALIAS("hsi:nokia-modem"); 296 MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>"); 297 MODULE_DESCRIPTION("HSI driver module for Nokia N900 Modem"); 298 MODULE_LICENSE("GPL"); 299