diff options
author | David Phillips <david@yeah.nah.nz> | 2021-05-16 19:38:05 +1200 |
---|---|---|
committer | David Phillips <david@yeah.nah.nz> | 2021-05-16 19:38:05 +1200 |
commit | 50af9be8086dda5febc62f2e9f254720180a748b (patch) | |
tree | 20b469357acfa8da4572cf761c22c8201e508442 /cds9k-reset.c | |
parent | 9de30f1f92924be479dd3ed07a4638e46a83098b (diff) | |
download | cds9k-50af9be8086dda5febc62f2e9f254720180a748b.tar.xz |
Add reset driver and consumer for debugging it
Diffstat (limited to 'cds9k-reset.c')
-rw-r--r-- | cds9k-reset.c | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/cds9k-reset.c b/cds9k-reset.c new file mode 100644 index 0000000..d90ed7e --- /dev/null +++ b/cds9k-reset.c @@ -0,0 +1,91 @@ +#include <linux/device.h> +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/regmap.h> +#include <linux/reset-controller.h> + +#define RESET_REG_0 0x0 + +struct cds9k_reset_priv { + struct reset_controller_dev rcdev; + struct regmap *regmap; + u32 base; +}; + +static int cds9k_reset_reset(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct cds9k_reset_priv *priv = container_of(rcdev, struct cds9k_reset_priv, rcdev); + + /* reset sequence: put 0xDEAD into reg 0 for 250 ms */ + struct reg_sequence reset_sequence[] = { + { RESET_REG_0, 0xDEAD, 250000 }, + { RESET_REG_0, 0x0000 }, + }; + + if (id != 0) + return -EINVAL; + + return regmap_multi_reg_write(priv->regmap, reset_sequence, ARRAY_SIZE(reset_sequence)); +} + +static int cds9k_reset_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *spec) +{ + /* single reset */ + return 0; +} + +const struct reset_control_ops cds9k_reset_ops = { + .reset = cds9k_reset_reset, +}; + +static int cds9k_reset_probe(struct platform_device *pdev) +{ + struct cds9k_reset_priv *priv; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + + ret = device_property_read_u32(&pdev->dev, "reg", &priv->base); + if (ret) + return -EINVAL; + + if (!pdev->dev.parent) + return -ENODEV; + + priv->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!priv->regmap) + return -ENODEV; + + priv->rcdev.ops = &cds9k_reset_ops; + priv->rcdev.owner = pdev->dev.driver->owner; + priv->rcdev.of_node = pdev->dev.of_node; + priv->rcdev.nr_resets = 1; + priv->rcdev.of_reset_n_cells = 0; + priv->rcdev.of_xlate = cds9k_reset_xlate; + + return devm_reset_controller_register(&pdev->dev, &priv->rcdev); +} + +static struct of_device_id cds9k_reset_of_match[] = { + { .compatible = "david,cds9k-reset" }, + {} +}; +MODULE_DEVICE_TABLE(of, cds9k_reset_of_match); + +static struct platform_driver cds9k_reset = { + .driver = { + .name = "cds9k-reset", + .of_match_table = cds9k_reset_of_match, + }, + .probe = cds9k_reset_probe +}; +module_platform_driver(cds9k_reset); + +MODULE_AUTHOR("David Phillips <david@yeah.nah.nz>"); +MODULE_DESCRIPTION("Reset driver for the CDS9K board controller"); +MODULE_LICENSE("GPL v2"); |