18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2016 Maxime Ripard 48c2ecf20Sopenharmony_ci * Maxime Ripard <maxime.ripard@free-electrons.com> 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/delay.h> 88c2ecf20Sopenharmony_ci#include <linux/io.h> 98c2ecf20Sopenharmony_ci#include <linux/reset-controller.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "ccu_reset.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistatic int ccu_reset_assert(struct reset_controller_dev *rcdev, 148c2ecf20Sopenharmony_ci unsigned long id) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci struct ccu_reset *ccu = rcdev_to_ccu_reset(rcdev); 178c2ecf20Sopenharmony_ci const struct ccu_reset_map *map = &ccu->reset_map[id]; 188c2ecf20Sopenharmony_ci unsigned long flags; 198c2ecf20Sopenharmony_ci u32 reg; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci spin_lock_irqsave(ccu->lock, flags); 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci reg = readl(ccu->base + map->reg); 248c2ecf20Sopenharmony_ci writel(reg & ~map->bit, ccu->base + map->reg); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ccu->lock, flags); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci return 0; 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic int ccu_reset_deassert(struct reset_controller_dev *rcdev, 328c2ecf20Sopenharmony_ci unsigned long id) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct ccu_reset *ccu = rcdev_to_ccu_reset(rcdev); 358c2ecf20Sopenharmony_ci const struct ccu_reset_map *map = &ccu->reset_map[id]; 368c2ecf20Sopenharmony_ci unsigned long flags; 378c2ecf20Sopenharmony_ci u32 reg; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci spin_lock_irqsave(ccu->lock, flags); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci reg = readl(ccu->base + map->reg); 428c2ecf20Sopenharmony_ci writel(reg | map->bit, ccu->base + map->reg); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci spin_unlock_irqrestore(ccu->lock, flags); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci return 0; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic int ccu_reset_reset(struct reset_controller_dev *rcdev, 508c2ecf20Sopenharmony_ci unsigned long id) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci ccu_reset_assert(rcdev, id); 538c2ecf20Sopenharmony_ci udelay(10); 548c2ecf20Sopenharmony_ci ccu_reset_deassert(rcdev, id); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci return 0; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic int ccu_reset_status(struct reset_controller_dev *rcdev, 608c2ecf20Sopenharmony_ci unsigned long id) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci struct ccu_reset *ccu = rcdev_to_ccu_reset(rcdev); 638c2ecf20Sopenharmony_ci const struct ccu_reset_map *map = &ccu->reset_map[id]; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* 668c2ecf20Sopenharmony_ci * The reset control API expects 0 if reset is not asserted, 678c2ecf20Sopenharmony_ci * which is the opposite of what our hardware uses. 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_ci return !(map->bit & readl(ccu->base + map->reg)); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ciconst struct reset_control_ops ccu_reset_ops = { 738c2ecf20Sopenharmony_ci .assert = ccu_reset_assert, 748c2ecf20Sopenharmony_ci .deassert = ccu_reset_deassert, 758c2ecf20Sopenharmony_ci .reset = ccu_reset_reset, 768c2ecf20Sopenharmony_ci .status = ccu_reset_status, 778c2ecf20Sopenharmony_ci}; 78