Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

reset: tps380x: Add TPS380x device driver supprt

The TI TPS380x family [1] is a voltage supervisor with a dedicated
manual reset (mr) line input and a reset output. The chip(s) have a
build in reset delay, depending on the chip partnumber. This simple
driver addresses this so the cosumer don't need to care about it.

[1] https://www.ti.com/product/TPS3801

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
[p.zabel@pengutronix.de: drop Todo comment about min/typ/max reset time]
Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Link: https://lore.kernel.org/r/20220530092226.748644-2-m.felsch@pengutronix.de

authored by

Marco Felsch and committed by
Philipp Zabel
8a4e6154 729a8a57

+135
+8
drivers/reset/Kconfig
··· 257 257 you wish to use the reset framework for such memory-mapped devices, 258 258 say Y here. Otherwise, say N. 259 259 260 + config RESET_TI_TPS380X 261 + tristate "TI TPS380x Reset Driver" 262 + select GPIOLIB 263 + help 264 + This enables the reset driver support for TI TPS380x devices. If 265 + you wish to use the reset framework for such devices, say Y here. 266 + Otherwise, say N. 267 + 260 268 config RESET_TN48M_CPLD 261 269 tristate "Delta Networks TN48M switch CPLD reset controller" 262 270 depends on MFD_TN48M_CPLD || COMPILE_TEST
+1
drivers/reset/Makefile
··· 33 33 obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o 34 34 obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o 35 35 obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o 36 + obj-$(CONFIG_RESET_TI_TPS380X) += reset-tps380x.o 36 37 obj-$(CONFIG_RESET_TN48M_CPLD) += reset-tn48m.o 37 38 obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o 38 39 obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o
+126
drivers/reset/reset-tps380x.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * TI TPS380x Supply Voltage Supervisor and Reset Controller Driver 4 + * 5 + * Copyright (C) 2022 Pengutronix, Marco Felsch <kernel@pengutronix.de> 6 + * 7 + * Based on Simple Reset Controller Driver 8 + * 9 + * Copyright (C) 2017 Pengutronix, Philipp Zabel <kernel@pengutronix.de> 10 + */ 11 + 12 + #include <linux/delay.h> 13 + #include <linux/gpio/consumer.h> 14 + #include <linux/module.h> 15 + #include <linux/of.h> 16 + #include <linux/platform_device.h> 17 + #include <linux/property.h> 18 + #include <linux/reset-controller.h> 19 + 20 + struct tps380x_reset { 21 + struct reset_controller_dev rcdev; 22 + struct gpio_desc *reset_gpio; 23 + unsigned int reset_ms; 24 + }; 25 + 26 + struct tps380x_reset_devdata { 27 + unsigned int min_reset_ms; 28 + unsigned int typ_reset_ms; 29 + unsigned int max_reset_ms; 30 + }; 31 + 32 + static inline 33 + struct tps380x_reset *to_tps380x_reset(struct reset_controller_dev *rcdev) 34 + { 35 + return container_of(rcdev, struct tps380x_reset, rcdev); 36 + } 37 + 38 + static int 39 + tps380x_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) 40 + { 41 + struct tps380x_reset *tps380x = to_tps380x_reset(rcdev); 42 + 43 + gpiod_set_value_cansleep(tps380x->reset_gpio, 1); 44 + 45 + return 0; 46 + } 47 + 48 + static int 49 + tps380x_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) 50 + { 51 + struct tps380x_reset *tps380x = to_tps380x_reset(rcdev); 52 + 53 + gpiod_set_value_cansleep(tps380x->reset_gpio, 0); 54 + msleep(tps380x->reset_ms); 55 + 56 + return 0; 57 + } 58 + 59 + static const struct reset_control_ops reset_tps380x_ops = { 60 + .assert = tps380x_reset_assert, 61 + .deassert = tps380x_reset_deassert, 62 + }; 63 + 64 + static int tps380x_reset_of_xlate(struct reset_controller_dev *rcdev, 65 + const struct of_phandle_args *reset_spec) 66 + { 67 + /* No special handling needed, we have only one reset line per device */ 68 + return 0; 69 + } 70 + 71 + static int tps380x_reset_probe(struct platform_device *pdev) 72 + { 73 + struct device *dev = &pdev->dev; 74 + const struct tps380x_reset_devdata *devdata; 75 + struct tps380x_reset *tps380x; 76 + 77 + devdata = device_get_match_data(dev); 78 + if (!devdata) 79 + return -EINVAL; 80 + 81 + tps380x = devm_kzalloc(dev, sizeof(*tps380x), GFP_KERNEL); 82 + if (!tps380x) 83 + return -ENOMEM; 84 + 85 + tps380x->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 86 + if (IS_ERR(tps380x->reset_gpio)) 87 + return dev_err_probe(dev, PTR_ERR(tps380x->reset_gpio), 88 + "Failed to get GPIO\n"); 89 + 90 + tps380x->reset_ms = devdata->max_reset_ms; 91 + 92 + tps380x->rcdev.ops = &reset_tps380x_ops; 93 + tps380x->rcdev.owner = THIS_MODULE; 94 + tps380x->rcdev.dev = dev; 95 + tps380x->rcdev.of_node = dev->of_node; 96 + tps380x->rcdev.of_reset_n_cells = 0; 97 + tps380x->rcdev.of_xlate = tps380x_reset_of_xlate; 98 + tps380x->rcdev.nr_resets = 1; 99 + 100 + return devm_reset_controller_register(dev, &tps380x->rcdev); 101 + } 102 + 103 + static const struct tps380x_reset_devdata tps3801_reset_data = { 104 + .min_reset_ms = 120, 105 + .typ_reset_ms = 200, 106 + .max_reset_ms = 280, 107 + }; 108 + 109 + static const struct of_device_id tps380x_reset_dt_ids[] = { 110 + { .compatible = "ti,tps3801", .data = &tps3801_reset_data }, 111 + { /* sentinel */ }, 112 + }; 113 + MODULE_DEVICE_TABLE(of, tps380x_reset_dt_ids); 114 + 115 + static struct platform_driver tps380x_reset_driver = { 116 + .probe = tps380x_reset_probe, 117 + .driver = { 118 + .name = "tps380x-reset", 119 + .of_match_table = tps380x_reset_dt_ids, 120 + }, 121 + }; 122 + module_platform_driver(tps380x_reset_driver); 123 + 124 + MODULE_AUTHOR("Marco Felsch <kernel@pengutronix.de>"); 125 + MODULE_DESCRIPTION("TI TPS380x Supply Voltags Supervisor and Reset Driver"); 126 + MODULE_LICENSE("GPL v2");