Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'socfpga-driver-update-for-3.16' of git://git.rocketboards.org/linux-socfpga-next into next/drivers

Merge "drivers: Add reset driver for SOCFPGA" from Dinh Nguyen:

Add a reset driver for the SOCFPGA platform.

* tag 'socfpga-driver-update-for-3.16' of git://git.rocketboards.org/linux-socfpga-next:
reset: add driver for socfpga

Signed-off-by: Olof Johansson <olof@lixom.net>

+147
+1
drivers/reset/Makefile
··· 1 1 obj-$(CONFIG_RESET_CONTROLLER) += core.o 2 + obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o 2 3 obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o 3 4 obj-$(CONFIG_ARCH_STI) += sti/
+146
drivers/reset/reset-socfpga.c
··· 1 + /* 2 + * Copyright 2014 Steffen Trumtrar <s.trumtrar@pengutronix.de> 3 + * 4 + * based on 5 + * Allwinner SoCs Reset Controller driver 6 + * 7 + * Copyright 2013 Maxime Ripard 8 + * 9 + * Maxime Ripard <maxime.ripard@free-electrons.com> 10 + * 11 + * This program is free software; you can redistribute it and/or modify 12 + * it under the terms of the GNU General Public License as published by 13 + * the Free Software Foundation; either version 2 of the License, or 14 + * (at your option) any later version. 15 + */ 16 + 17 + #include <linux/err.h> 18 + #include <linux/io.h> 19 + #include <linux/module.h> 20 + #include <linux/of.h> 21 + #include <linux/platform_device.h> 22 + #include <linux/reset-controller.h> 23 + #include <linux/spinlock.h> 24 + #include <linux/types.h> 25 + 26 + #define NR_BANKS 4 27 + #define OFFSET_MODRST 0x10 28 + 29 + struct socfpga_reset_data { 30 + spinlock_t lock; 31 + void __iomem *membase; 32 + struct reset_controller_dev rcdev; 33 + }; 34 + 35 + static int socfpga_reset_assert(struct reset_controller_dev *rcdev, 36 + unsigned long id) 37 + { 38 + struct socfpga_reset_data *data = container_of(rcdev, 39 + struct socfpga_reset_data, 40 + rcdev); 41 + int bank = id / BITS_PER_LONG; 42 + int offset = id % BITS_PER_LONG; 43 + unsigned long flags; 44 + u32 reg; 45 + 46 + spin_lock_irqsave(&data->lock, flags); 47 + 48 + reg = readl(data->membase + OFFSET_MODRST + (bank * NR_BANKS)); 49 + writel(reg | BIT(offset), data->membase + OFFSET_MODRST + 50 + (bank * NR_BANKS)); 51 + spin_unlock_irqrestore(&data->lock, flags); 52 + 53 + return 0; 54 + } 55 + 56 + static int socfpga_reset_deassert(struct reset_controller_dev *rcdev, 57 + unsigned long id) 58 + { 59 + struct socfpga_reset_data *data = container_of(rcdev, 60 + struct socfpga_reset_data, 61 + rcdev); 62 + 63 + int bank = id / BITS_PER_LONG; 64 + int offset = id % BITS_PER_LONG; 65 + unsigned long flags; 66 + u32 reg; 67 + 68 + spin_lock_irqsave(&data->lock, flags); 69 + 70 + reg = readl(data->membase + OFFSET_MODRST + (bank * NR_BANKS)); 71 + writel(reg & ~BIT(offset), data->membase + OFFSET_MODRST + 72 + (bank * NR_BANKS)); 73 + 74 + spin_unlock_irqrestore(&data->lock, flags); 75 + 76 + return 0; 77 + } 78 + 79 + static struct reset_control_ops socfpga_reset_ops = { 80 + .assert = socfpga_reset_assert, 81 + .deassert = socfpga_reset_deassert, 82 + }; 83 + 84 + static int socfpga_reset_probe(struct platform_device *pdev) 85 + { 86 + struct socfpga_reset_data *data; 87 + struct resource *res; 88 + 89 + /* 90 + * The binding was mainlined without the required property. 91 + * Do not continue, when we encounter an old DT. 92 + */ 93 + if (!of_find_property(pdev->dev.of_node, "#reset-cells", NULL)) { 94 + dev_err(&pdev->dev, "%s missing #reset-cells property\n", 95 + pdev->dev.of_node->full_name); 96 + return -EINVAL; 97 + } 98 + 99 + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 100 + if (!data) 101 + return -ENOMEM; 102 + 103 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 104 + data->membase = devm_ioremap_resource(&pdev->dev, res); 105 + if (IS_ERR(data->membase)) 106 + return PTR_ERR(data->membase); 107 + 108 + spin_lock_init(&data->lock); 109 + 110 + data->rcdev.owner = THIS_MODULE; 111 + data->rcdev.nr_resets = NR_BANKS * BITS_PER_LONG; 112 + data->rcdev.ops = &socfpga_reset_ops; 113 + data->rcdev.of_node = pdev->dev.of_node; 114 + reset_controller_register(&data->rcdev); 115 + 116 + return 0; 117 + } 118 + 119 + static int socfpga_reset_remove(struct platform_device *pdev) 120 + { 121 + struct socfpga_reset_data *data = platform_get_drvdata(pdev); 122 + 123 + reset_controller_unregister(&data->rcdev); 124 + 125 + return 0; 126 + } 127 + 128 + static const struct of_device_id socfpga_reset_dt_ids[] = { 129 + { .compatible = "altr,rst-mgr", }, 130 + { /* sentinel */ }, 131 + }; 132 + 133 + static struct platform_driver socfpga_reset_driver = { 134 + .probe = socfpga_reset_probe, 135 + .remove = socfpga_reset_remove, 136 + .driver = { 137 + .name = "socfpga-reset", 138 + .owner = THIS_MODULE, 139 + .of_match_table = socfpga_reset_dt_ids, 140 + }, 141 + }; 142 + module_platform_driver(socfpga_reset_driver); 143 + 144 + MODULE_AUTHOR("Steffen Trumtrar <s.trumtrar@pengutronix.de"); 145 + MODULE_DESCRIPTION("Socfpga Reset Controller Driver"); 146 + MODULE_LICENSE("GPL");