18f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad/* 28f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. 38f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * 48f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * This program is free software; you can redistribute it and/or modify it 58f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * under the terms and conditions of the GNU General Public License, 68f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * version 2, as published by the Free Software Foundation. 78f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * 88f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * This program is distributed in the hope it will be useful, but WITHOUT 98f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 108f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 118f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * more details. 128f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * 138f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * You should have received a copy of the GNU General Public License 148f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * along with this program. If not, see <http://www.gnu.org/licenses/>. 158f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad */ 168f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 178f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#include <linux/kernel.h> 188f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#include <linux/io.h> 198f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#include <linux/delay.h> 208f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#include <linux/err.h> 218f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#include <linux/slab.h> 228f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#include <linux/clk-provider.h> 238f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#include <linux/clk.h> 248f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 258f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#include "clk.h" 268f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 278f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#define SUPER_STATE_IDLE 0 288f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#define SUPER_STATE_RUN 1 298f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#define SUPER_STATE_IRQ 2 308f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#define SUPER_STATE_FIQ 3 318f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 328f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#define SUPER_STATE_SHIFT 28 338f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#define SUPER_STATE_MASK ((BIT(SUPER_STATE_IDLE) | BIT(SUPER_STATE_RUN) | \ 348f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad BIT(SUPER_STATE_IRQ) | BIT(SUPER_STATE_FIQ)) \ 358f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad << SUPER_STATE_SHIFT) 368f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 378f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#define SUPER_LP_DIV2_BYPASS (1 << 16) 388f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 398f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#define super_state(s) (BIT(s) << SUPER_STATE_SHIFT) 408f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#define super_state_to_src_shift(m, s) ((m->width * s)) 418f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad#define super_state_to_src_mask(m) (((1 << m->width) - 1)) 428f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 438f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwadstatic u8 clk_super_get_parent(struct clk_hw *hw) 448f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad{ 458f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad struct tegra_clk_super_mux *mux = to_clk_super_mux(hw); 468f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad u32 val, state; 478f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad u8 source, shift; 488f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 498f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad val = readl_relaxed(mux->reg); 508f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 518f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad state = val & SUPER_STATE_MASK; 528f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 538f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad BUG_ON((state != super_state(SUPER_STATE_RUN)) && 548f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad (state != super_state(SUPER_STATE_IDLE))); 558f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad shift = (state == super_state(SUPER_STATE_IDLE)) ? 568f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad super_state_to_src_shift(mux, SUPER_STATE_IDLE) : 578f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad super_state_to_src_shift(mux, SUPER_STATE_RUN); 588f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 598f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad source = (val >> shift) & super_state_to_src_mask(mux); 608f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 618f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad /* 628f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * If LP_DIV2_BYPASS is not set and PLLX is current parent then 638f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * PLLX/2 is the input source to CCLKLP. 648f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad */ 658f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if ((mux->flags & TEGRA_DIVIDER_2) && !(val & SUPER_LP_DIV2_BYPASS) && 668f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad (source == mux->pllx_index)) 678f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad source = mux->div2_index; 688f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 698f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad return source; 708f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad} 718f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 728f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwadstatic int clk_super_set_parent(struct clk_hw *hw, u8 index) 738f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad{ 748f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad struct tegra_clk_super_mux *mux = to_clk_super_mux(hw); 758f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad u32 val, state; 76c64c65d494ade53fa41fb0b980381807743b5095Peter De Schrijver int err = 0; 778f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad u8 parent_index, shift; 78c64c65d494ade53fa41fb0b980381807743b5095Peter De Schrijver unsigned long flags = 0; 79c64c65d494ade53fa41fb0b980381807743b5095Peter De Schrijver 80c64c65d494ade53fa41fb0b980381807743b5095Peter De Schrijver if (mux->lock) 81c64c65d494ade53fa41fb0b980381807743b5095Peter De Schrijver spin_lock_irqsave(mux->lock, flags); 828f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 838f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad val = readl_relaxed(mux->reg); 848f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad state = val & SUPER_STATE_MASK; 858f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad BUG_ON((state != super_state(SUPER_STATE_RUN)) && 868f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad (state != super_state(SUPER_STATE_IDLE))); 878f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad shift = (state == super_state(SUPER_STATE_IDLE)) ? 888f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad super_state_to_src_shift(mux, SUPER_STATE_IDLE) : 898f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad super_state_to_src_shift(mux, SUPER_STATE_RUN); 908f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 918f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad /* 928f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * For LP mode super-clock switch between PLLX direct 938f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * and divided-by-2 outputs is allowed only when other 948f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad * than PLLX clock source is current parent. 958f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad */ 968f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if ((mux->flags & TEGRA_DIVIDER_2) && ((index == mux->div2_index) || 978f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad (index == mux->pllx_index))) { 988f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad parent_index = clk_super_get_parent(hw); 998f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if ((parent_index == mux->div2_index) || 100c64c65d494ade53fa41fb0b980381807743b5095Peter De Schrijver (parent_index == mux->pllx_index)) { 101c64c65d494ade53fa41fb0b980381807743b5095Peter De Schrijver err = -EINVAL; 102c64c65d494ade53fa41fb0b980381807743b5095Peter De Schrijver goto out; 103c64c65d494ade53fa41fb0b980381807743b5095Peter De Schrijver } 1048f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1058f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad val ^= SUPER_LP_DIV2_BYPASS; 1068f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad writel_relaxed(val, mux->reg); 1078f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad udelay(2); 1088f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1098f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if (index == mux->div2_index) 1108f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad index = mux->pllx_index; 1118f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad } 1128f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad val &= ~((super_state_to_src_mask(mux)) << shift); 1138f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad val |= (index & (super_state_to_src_mask(mux))) << shift; 1148f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1158f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad writel_relaxed(val, mux->reg); 1168f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad udelay(2); 117c64c65d494ade53fa41fb0b980381807743b5095Peter De Schrijver 118c64c65d494ade53fa41fb0b980381807743b5095Peter De Schrijverout: 119c64c65d494ade53fa41fb0b980381807743b5095Peter De Schrijver if (mux->lock) 120c64c65d494ade53fa41fb0b980381807743b5095Peter De Schrijver spin_unlock_irqrestore(mux->lock, flags); 121c64c65d494ade53fa41fb0b980381807743b5095Peter De Schrijver 122c64c65d494ade53fa41fb0b980381807743b5095Peter De Schrijver return err; 1238f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad} 1248f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1258f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwadconst struct clk_ops tegra_clk_super_ops = { 1268f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad .get_parent = clk_super_get_parent, 1278f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad .set_parent = clk_super_set_parent, 1288f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad}; 1298f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1308f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwadstruct clk *tegra_clk_register_super_mux(const char *name, 1318f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad const char **parent_names, u8 num_parents, 1328f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad unsigned long flags, void __iomem *reg, u8 clk_super_flags, 1338f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad u8 width, u8 pllx_index, u8 div2_index, spinlock_t *lock) 1348f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad{ 1358f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad struct tegra_clk_super_mux *super; 1368f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad struct clk *clk; 1378f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad struct clk_init_data init; 1388f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1398f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad super = kzalloc(sizeof(*super), GFP_KERNEL); 1408f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if (!super) { 1418f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad pr_err("%s: could not allocate super clk\n", __func__); 1428f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad return ERR_PTR(-ENOMEM); 1438f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad } 1448f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1458f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad init.name = name; 1468f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad init.ops = &tegra_clk_super_ops; 1478f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad init.flags = flags; 1488f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad init.parent_names = parent_names; 1498f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad init.num_parents = num_parents; 1508f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1518f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad super->reg = reg; 1528f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad super->pllx_index = pllx_index; 1538f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad super->div2_index = div2_index; 1548f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad super->lock = lock; 1558f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad super->width = width; 1568f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad super->flags = clk_super_flags; 1578f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1588f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad /* Data in .init is copied by clk_register(), so stack variable OK */ 1598f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad super->hw.init = &init; 1608f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1618f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad clk = clk_register(NULL, &super->hw); 1628f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad if (IS_ERR(clk)) 1638f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad kfree(super); 1648f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad 1658f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad return clk; 1668f8f484bf355e546c62c47b8a8c8d19b28787798Prashant Gaikwad} 167