brintos

brintos / linux-shallow public Read only

0
0
Text · 7.0 KiB · 97ba59e Raw
299 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * nokia-modem.c4 *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 18static unsigned int pm = 1;19module_param(pm, int, 0400);20MODULE_PARM_DESC(pm,21	"Enable power management (0=disabled, 1=userland based [default])");22 23struct nokia_modem_gpio {24	struct gpio_desc	*gpio;25	const char		*name;26};27 28struct 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 38static 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 51static 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 60static 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 71static 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 125static 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 225error4:226	hsi_remove_client(&modem->cmt_speech->device, NULL);227error3:228	hsi_remove_client(&modem->ssi_protocol->device, NULL);229error2:230	nokia_modem_gpio_unexport(dev);231error1: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 238static 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_OF264static 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};270MODULE_DEVICE_TABLE(of, nokia_modem_of_match);271#endif272 273static 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 283static int __init nokia_modem_init(void)284{285	return hsi_register_client_driver(&nokia_modem_driver);286}287module_init(nokia_modem_init);288 289static void __exit nokia_modem_exit(void)290{291	hsi_unregister_client_driver(&nokia_modem_driver);292}293module_exit(nokia_modem_exit);294 295MODULE_ALIAS("hsi:nokia-modem");296MODULE_AUTHOR("Sebastian Reichel <sre@kernel.org>");297MODULE_DESCRIPTION("HSI driver module for Nokia N900 Modem");298MODULE_LICENSE("GPL");299