linux/drivers/reset/reset-socfpga.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2018, Intel Corporation
   4 * Copied from reset-sunxi.c
   5 */
   6
   7#include <linux/err.h>
   8#include <linux/io.h>
   9#include <linux/init.h>
  10#include <linux/of.h>
  11#include <linux/of_address.h>
  12#include <linux/platform_device.h>
  13#include <linux/reset-controller.h>
  14#include <linux/reset/reset-simple.h>
  15#include <linux/reset/socfpga.h>
  16#include <linux/slab.h>
  17#include <linux/spinlock.h>
  18#include <linux/types.h>
  19
  20#define SOCFPGA_NR_BANKS        8
  21
  22static int a10_reset_init(struct device_node *np)
  23{
  24        struct reset_simple_data *data;
  25        struct resource res;
  26        resource_size_t size;
  27        int ret;
  28        u32 reg_offset = 0x10;
  29
  30        data = kzalloc(sizeof(*data), GFP_KERNEL);
  31        if (!data)
  32                return -ENOMEM;
  33
  34        ret = of_address_to_resource(np, 0, &res);
  35        if (ret)
  36                goto err_alloc;
  37
  38        size = resource_size(&res);
  39        if (!request_mem_region(res.start, size, np->name)) {
  40                ret = -EBUSY;
  41                goto err_alloc;
  42        }
  43
  44        data->membase = ioremap(res.start, size);
  45        if (!data->membase) {
  46                ret = -ENOMEM;
  47                goto release_region;
  48        }
  49
  50        if (of_property_read_u32(np, "altr,modrst-offset", &reg_offset))
  51                pr_warn("missing altr,modrst-offset property, assuming 0x10\n");
  52        data->membase += reg_offset;
  53
  54        spin_lock_init(&data->lock);
  55
  56        data->rcdev.owner = THIS_MODULE;
  57        data->rcdev.nr_resets = SOCFPGA_NR_BANKS * 32;
  58        data->rcdev.ops = &reset_simple_ops;
  59        data->rcdev.of_node = np;
  60        data->status_active_low = true;
  61
  62        ret = reset_controller_register(&data->rcdev);
  63        if (ret)
  64                pr_err("unable to register device\n");
  65
  66        return ret;
  67
  68release_region:
  69        release_mem_region(res.start, size);
  70
  71err_alloc:
  72        kfree(data);
  73        return ret;
  74};
  75
  76/*
  77 * These are the reset controller we need to initialize early on in
  78 * our system, before we can even think of using a regular device
  79 * driver for it.
  80 * The controllers that we can register through the regular device
  81 * model are handled by the simple reset driver directly.
  82 */
  83static const struct of_device_id socfpga_early_reset_dt_ids[] __initconst = {
  84        { .compatible = "altr,rst-mgr", },
  85        { /* sentinel */ },
  86};
  87
  88void __init socfpga_reset_init(void)
  89{
  90        struct device_node *np;
  91
  92        for_each_matching_node(np, socfpga_early_reset_dt_ids)
  93                a10_reset_init(np);
  94}
  95
  96/*
  97 * The early driver is problematic, because it doesn't register
  98 * itself as a driver. This causes certain device links to prevent
  99 * consumer devices from probing. The hacky solution is to register
 100 * an empty driver, whose only job is to attach itself to the reset
 101 * manager and call probe.
 102 */
 103static const struct of_device_id socfpga_reset_dt_ids[] = {
 104        { .compatible = "altr,rst-mgr", },
 105        { /* sentinel */ },
 106};
 107
 108static int reset_simple_probe(struct platform_device *pdev)
 109{
 110        return 0;
 111}
 112
 113static struct platform_driver reset_socfpga_driver = {
 114        .probe  = reset_simple_probe,
 115        .driver = {
 116                .name           = "socfpga-reset",
 117                .of_match_table = socfpga_reset_dt_ids,
 118        },
 119};
 120builtin_platform_driver(reset_socfpga_driver);
 121