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 Voltage Supervisor and Reset Driver"); 126 MODULE_LICENSE("GPL v2"); 127