1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only 2*4882a593Smuzhiyun /* 3*4882a593Smuzhiyun * Copyright (c) 2017 Chen-Yu Tsai. All rights reserved. 4*4882a593Smuzhiyun */ 5*4882a593Smuzhiyun 6*4882a593Smuzhiyun #include <linux/clk-provider.h> 7*4882a593Smuzhiyun #include <linux/clk/sunxi-ng.h> 8*4882a593Smuzhiyun #include <linux/io.h> 9*4882a593Smuzhiyun 10*4882a593Smuzhiyun #include "ccu_common.h" 11*4882a593Smuzhiyun 12*4882a593Smuzhiyun /** 13*4882a593Smuzhiyun * sunxi_ccu_set_mmc_timing_mode: Configure the MMC clock timing mode 14*4882a593Smuzhiyun * @clk: clock to be configured 15*4882a593Smuzhiyun * @new_mode: true for new timing mode introduced in A83T and later 16*4882a593Smuzhiyun * 17*4882a593Smuzhiyun * Returns 0 on success, -ENOTSUPP if the clock does not support 18*4882a593Smuzhiyun * switching modes. 19*4882a593Smuzhiyun */ sunxi_ccu_set_mmc_timing_mode(struct clk * clk,bool new_mode)20*4882a593Smuzhiyunint sunxi_ccu_set_mmc_timing_mode(struct clk *clk, bool new_mode) 21*4882a593Smuzhiyun { 22*4882a593Smuzhiyun struct clk_hw *hw = __clk_get_hw(clk); 23*4882a593Smuzhiyun struct ccu_common *cm = hw_to_ccu_common(hw); 24*4882a593Smuzhiyun unsigned long flags; 25*4882a593Smuzhiyun u32 val; 26*4882a593Smuzhiyun 27*4882a593Smuzhiyun if (!(cm->features & CCU_FEATURE_MMC_TIMING_SWITCH)) 28*4882a593Smuzhiyun return -ENOTSUPP; 29*4882a593Smuzhiyun 30*4882a593Smuzhiyun spin_lock_irqsave(cm->lock, flags); 31*4882a593Smuzhiyun 32*4882a593Smuzhiyun val = readl(cm->base + cm->reg); 33*4882a593Smuzhiyun if (new_mode) 34*4882a593Smuzhiyun val |= CCU_MMC_NEW_TIMING_MODE; 35*4882a593Smuzhiyun else 36*4882a593Smuzhiyun val &= ~CCU_MMC_NEW_TIMING_MODE; 37*4882a593Smuzhiyun writel(val, cm->base + cm->reg); 38*4882a593Smuzhiyun 39*4882a593Smuzhiyun spin_unlock_irqrestore(cm->lock, flags); 40*4882a593Smuzhiyun 41*4882a593Smuzhiyun return 0; 42*4882a593Smuzhiyun } 43*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(sunxi_ccu_set_mmc_timing_mode); 44*4882a593Smuzhiyun 45*4882a593Smuzhiyun /** 46*4882a593Smuzhiyun * sunxi_ccu_set_mmc_timing_mode: Get the current MMC clock timing mode 47*4882a593Smuzhiyun * @clk: clock to query 48*4882a593Smuzhiyun * 49*4882a593Smuzhiyun * Returns 0 if the clock is in old timing mode, > 0 if it is in 50*4882a593Smuzhiyun * new timing mode, and -ENOTSUPP if the clock does not support 51*4882a593Smuzhiyun * this function. 52*4882a593Smuzhiyun */ sunxi_ccu_get_mmc_timing_mode(struct clk * clk)53*4882a593Smuzhiyunint sunxi_ccu_get_mmc_timing_mode(struct clk *clk) 54*4882a593Smuzhiyun { 55*4882a593Smuzhiyun struct clk_hw *hw = __clk_get_hw(clk); 56*4882a593Smuzhiyun struct ccu_common *cm = hw_to_ccu_common(hw); 57*4882a593Smuzhiyun 58*4882a593Smuzhiyun if (!(cm->features & CCU_FEATURE_MMC_TIMING_SWITCH)) 59*4882a593Smuzhiyun return -ENOTSUPP; 60*4882a593Smuzhiyun 61*4882a593Smuzhiyun return !!(readl(cm->base + cm->reg) & CCU_MMC_NEW_TIMING_MODE); 62*4882a593Smuzhiyun } 63*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(sunxi_ccu_get_mmc_timing_mode); 64