127 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * TI TPS380x Supply Voltage Supervisor and Reset Controller Driver4 *5 * Copyright (C) 2022 Pengutronix, Marco Felsch <kernel@pengutronix.de>6 *7 * Based on Simple Reset Controller Driver8 *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 20struct tps380x_reset {21 struct reset_controller_dev rcdev;22 struct gpio_desc *reset_gpio;23 unsigned int reset_ms;24};25 26struct tps380x_reset_devdata {27 unsigned int min_reset_ms;28 unsigned int typ_reset_ms;29 unsigned int max_reset_ms;30};31 32static inline33struct tps380x_reset *to_tps380x_reset(struct reset_controller_dev *rcdev)34{35 return container_of(rcdev, struct tps380x_reset, rcdev);36}37 38static int39tps380x_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 48static int49tps380x_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 59static const struct reset_control_ops reset_tps380x_ops = {60 .assert = tps380x_reset_assert,61 .deassert = tps380x_reset_deassert,62};63 64static 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 71static 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 103static 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 109static const struct of_device_id tps380x_reset_dt_ids[] = {110 { .compatible = "ti,tps3801", .data = &tps3801_reset_data },111 { /* sentinel */ },112};113MODULE_DEVICE_TABLE(of, tps380x_reset_dt_ids);114 115static 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};122module_platform_driver(tps380x_reset_driver);123 124MODULE_AUTHOR("Marco Felsch <kernel@pengutronix.de>");125MODULE_DESCRIPTION("TI TPS380x Supply Voltage Supervisor and Reset Driver");126MODULE_LICENSE("GPL v2");127