1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2016 Maxime Ripard 4 * Maxime Ripard <maxime.ripard@free-electrons.com> 5 */ 6 7 #include <linux/delay.h> 8 #include <linux/io.h> 9 #include <linux/reset-controller.h> 10 11 #include "ccu_reset.h" 12 13 static int ccu_reset_assert(struct reset_controller_dev *rcdev, 14 unsigned long id) 15 { 16 struct ccu_reset *ccu = rcdev_to_ccu_reset(rcdev); 17 const struct ccu_reset_map *map = &ccu->reset_map[id]; 18 unsigned long flags; 19 u32 reg; 20 21 spin_lock_irqsave(ccu->lock, flags); 22 23 reg = readl(ccu->base + map->reg); 24 writel(reg & ~map->bit, ccu->base + map->reg); 25 26 spin_unlock_irqrestore(ccu->lock, flags); 27 28 return 0; 29 } 30 31 static int ccu_reset_deassert(struct reset_controller_dev *rcdev, 32 unsigned long id) 33 { 34 struct ccu_reset *ccu = rcdev_to_ccu_reset(rcdev); 35 const struct ccu_reset_map *map = &ccu->reset_map[id]; 36 unsigned long flags; 37 u32 reg; 38 39 spin_lock_irqsave(ccu->lock, flags); 40 41 reg = readl(ccu->base + map->reg); 42 writel(reg | map->bit, ccu->base + map->reg); 43 44 spin_unlock_irqrestore(ccu->lock, flags); 45 46 return 0; 47 } 48 49 static int ccu_reset_reset(struct reset_controller_dev *rcdev, 50 unsigned long id) 51 { 52 ccu_reset_assert(rcdev, id); 53 udelay(10); 54 ccu_reset_deassert(rcdev, id); 55 56 return 0; 57 } 58 59 static int ccu_reset_status(struct reset_controller_dev *rcdev, 60 unsigned long id) 61 { 62 struct ccu_reset *ccu = rcdev_to_ccu_reset(rcdev); 63 const struct ccu_reset_map *map = &ccu->reset_map[id]; 64 65 /* 66 * The reset control API expects 0 if reset is not asserted, 67 * which is the opposite of what our hardware uses. 68 */ 69 return !(map->bit & readl(ccu->base + map->reg)); 70 } 71 72 const struct reset_control_ops ccu_reset_ops = { 73 .assert = ccu_reset_assert, 74 .deassert = ccu_reset_deassert, 75 .reset = ccu_reset_reset, 76 .status = ccu_reset_status, 77 }; 78