162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * TI TPS380x Supply Voltage Supervisor and Reset Controller Driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2022 Pengutronix, Marco Felsch <kernel@pengutronix.de> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Based on Simple Reset Controller Driver 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Copyright (C) 2017 Pengutronix, Philipp Zabel <kernel@pengutronix.de> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/of.h> 1662306a36Sopenharmony_ci#include <linux/platform_device.h> 1762306a36Sopenharmony_ci#include <linux/property.h> 1862306a36Sopenharmony_ci#include <linux/reset-controller.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistruct tps380x_reset { 2162306a36Sopenharmony_ci struct reset_controller_dev rcdev; 2262306a36Sopenharmony_ci struct gpio_desc *reset_gpio; 2362306a36Sopenharmony_ci unsigned int reset_ms; 2462306a36Sopenharmony_ci}; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct tps380x_reset_devdata { 2762306a36Sopenharmony_ci unsigned int min_reset_ms; 2862306a36Sopenharmony_ci unsigned int typ_reset_ms; 2962306a36Sopenharmony_ci unsigned int max_reset_ms; 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic inline 3362306a36Sopenharmony_cistruct tps380x_reset *to_tps380x_reset(struct reset_controller_dev *rcdev) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci return container_of(rcdev, struct tps380x_reset, rcdev); 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic int 3962306a36Sopenharmony_citps380x_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci struct tps380x_reset *tps380x = to_tps380x_reset(rcdev); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci gpiod_set_value_cansleep(tps380x->reset_gpio, 1); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci return 0; 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic int 4962306a36Sopenharmony_citps380x_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci struct tps380x_reset *tps380x = to_tps380x_reset(rcdev); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci gpiod_set_value_cansleep(tps380x->reset_gpio, 0); 5462306a36Sopenharmony_ci msleep(tps380x->reset_ms); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci return 0; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic const struct reset_control_ops reset_tps380x_ops = { 6062306a36Sopenharmony_ci .assert = tps380x_reset_assert, 6162306a36Sopenharmony_ci .deassert = tps380x_reset_deassert, 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic int tps380x_reset_of_xlate(struct reset_controller_dev *rcdev, 6562306a36Sopenharmony_ci const struct of_phandle_args *reset_spec) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci /* No special handling needed, we have only one reset line per device */ 6862306a36Sopenharmony_ci return 0; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic int tps380x_reset_probe(struct platform_device *pdev) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct device *dev = &pdev->dev; 7462306a36Sopenharmony_ci const struct tps380x_reset_devdata *devdata; 7562306a36Sopenharmony_ci struct tps380x_reset *tps380x; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci devdata = device_get_match_data(dev); 7862306a36Sopenharmony_ci if (!devdata) 7962306a36Sopenharmony_ci return -EINVAL; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci tps380x = devm_kzalloc(dev, sizeof(*tps380x), GFP_KERNEL); 8262306a36Sopenharmony_ci if (!tps380x) 8362306a36Sopenharmony_ci return -ENOMEM; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci tps380x->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 8662306a36Sopenharmony_ci if (IS_ERR(tps380x->reset_gpio)) 8762306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(tps380x->reset_gpio), 8862306a36Sopenharmony_ci "Failed to get GPIO\n"); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci tps380x->reset_ms = devdata->max_reset_ms; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci tps380x->rcdev.ops = &reset_tps380x_ops; 9362306a36Sopenharmony_ci tps380x->rcdev.owner = THIS_MODULE; 9462306a36Sopenharmony_ci tps380x->rcdev.dev = dev; 9562306a36Sopenharmony_ci tps380x->rcdev.of_node = dev->of_node; 9662306a36Sopenharmony_ci tps380x->rcdev.of_reset_n_cells = 0; 9762306a36Sopenharmony_ci tps380x->rcdev.of_xlate = tps380x_reset_of_xlate; 9862306a36Sopenharmony_ci tps380x->rcdev.nr_resets = 1; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci return devm_reset_controller_register(dev, &tps380x->rcdev); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic const struct tps380x_reset_devdata tps3801_reset_data = { 10462306a36Sopenharmony_ci .min_reset_ms = 120, 10562306a36Sopenharmony_ci .typ_reset_ms = 200, 10662306a36Sopenharmony_ci .max_reset_ms = 280, 10762306a36Sopenharmony_ci}; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic const struct of_device_id tps380x_reset_dt_ids[] = { 11062306a36Sopenharmony_ci { .compatible = "ti,tps3801", .data = &tps3801_reset_data }, 11162306a36Sopenharmony_ci { /* sentinel */ }, 11262306a36Sopenharmony_ci}; 11362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, tps380x_reset_dt_ids); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic struct platform_driver tps380x_reset_driver = { 11662306a36Sopenharmony_ci .probe = tps380x_reset_probe, 11762306a36Sopenharmony_ci .driver = { 11862306a36Sopenharmony_ci .name = "tps380x-reset", 11962306a36Sopenharmony_ci .of_match_table = tps380x_reset_dt_ids, 12062306a36Sopenharmony_ci }, 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_cimodule_platform_driver(tps380x_reset_driver); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ciMODULE_AUTHOR("Marco Felsch <kernel@pengutronix.de>"); 12562306a36Sopenharmony_ciMODULE_DESCRIPTION("TI TPS380x Supply Voltage Supervisor and Reset Driver"); 12662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 127