linux/drivers/reset/hisilicon/hi6220_reset.c
<<
>>
Prefs
   1/*
   2 * Hisilicon Hi6220 reset controller driver
   3 *
   4 * Copyright (c) 2015 Hisilicon Limited.
   5 *
   6 * Author: Feng Chen <puck.chen@hisilicon.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12
  13#include <linux/io.h>
  14#include <linux/init.h>
  15#include <linux/module.h>
  16#include <linux/bitops.h>
  17#include <linux/of.h>
  18#include <linux/reset-controller.h>
  19#include <linux/reset.h>
  20#include <linux/platform_device.h>
  21
  22#define ASSERT_OFFSET            0x300
  23#define DEASSERT_OFFSET          0x304
  24#define MAX_INDEX                0x509
  25
  26#define to_reset_data(x) container_of(x, struct hi6220_reset_data, rc_dev)
  27
  28struct hi6220_reset_data {
  29        void __iomem                    *assert_base;
  30        void __iomem                    *deassert_base;
  31        struct reset_controller_dev     rc_dev;
  32};
  33
  34static int hi6220_reset_assert(struct reset_controller_dev *rc_dev,
  35                               unsigned long idx)
  36{
  37        struct hi6220_reset_data *data = to_reset_data(rc_dev);
  38
  39        int bank = idx >> 8;
  40        int offset = idx & 0xff;
  41
  42        writel(BIT(offset), data->assert_base + (bank * 0x10));
  43
  44        return 0;
  45}
  46
  47static int hi6220_reset_deassert(struct reset_controller_dev *rc_dev,
  48                                 unsigned long idx)
  49{
  50        struct hi6220_reset_data *data = to_reset_data(rc_dev);
  51
  52        int bank = idx >> 8;
  53        int offset = idx & 0xff;
  54
  55        writel(BIT(offset), data->deassert_base + (bank * 0x10));
  56
  57        return 0;
  58}
  59
  60static const struct reset_control_ops hi6220_reset_ops = {
  61        .assert = hi6220_reset_assert,
  62        .deassert = hi6220_reset_deassert,
  63};
  64
  65static int hi6220_reset_probe(struct platform_device *pdev)
  66{
  67        struct hi6220_reset_data *data;
  68        struct resource *res;
  69        void __iomem *src_base;
  70
  71        data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
  72        if (!data)
  73                return -ENOMEM;
  74
  75        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  76        src_base = devm_ioremap_resource(&pdev->dev, res);
  77        if (IS_ERR(src_base))
  78                return PTR_ERR(src_base);
  79
  80        data->assert_base = src_base + ASSERT_OFFSET;
  81        data->deassert_base = src_base + DEASSERT_OFFSET;
  82        data->rc_dev.nr_resets = MAX_INDEX;
  83        data->rc_dev.ops = &hi6220_reset_ops;
  84        data->rc_dev.of_node = pdev->dev.of_node;
  85
  86        return reset_controller_register(&data->rc_dev);
  87}
  88
  89static const struct of_device_id hi6220_reset_match[] = {
  90        { .compatible = "hisilicon,hi6220-sysctrl" },
  91        { },
  92};
  93
  94static struct platform_driver hi6220_reset_driver = {
  95        .probe = hi6220_reset_probe,
  96        .driver = {
  97                .name = "reset-hi6220",
  98                .of_match_table = hi6220_reset_match,
  99        },
 100};
 101
 102static int __init hi6220_reset_init(void)
 103{
 104        return platform_driver_register(&hi6220_reset_driver);
 105}
 106
 107postcore_initcall(hi6220_reset_init);
 108