162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Utility to set the DAVINCI MUX register from a table in mux.h 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: Vladimir Barinov, MontaVista Software, Inc. <source@mvista.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Based on linux/arch/arm/plat-omap/mux.c: 862306a36Sopenharmony_ci * Copyright (C) 2003 - 2005 Nokia Corporation 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Written by Tony Lindgren 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * 2007 (c) MontaVista Software, Inc. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Copyright (C) 2008 Texas Instruments. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/io.h> 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci#include <linux/spinlock.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "mux.h" 2462306a36Sopenharmony_ci#include "common.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic void __iomem *pinmux_base; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* 2962306a36Sopenharmony_ci * Sets the DAVINCI MUX register based on the table 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_ciint davinci_cfg_reg(const unsigned long index) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci static DEFINE_SPINLOCK(mux_spin_lock); 3462306a36Sopenharmony_ci struct davinci_soc_info *soc_info = &davinci_soc_info; 3562306a36Sopenharmony_ci unsigned long flags; 3662306a36Sopenharmony_ci const struct mux_config *cfg; 3762306a36Sopenharmony_ci unsigned int reg_orig = 0, reg = 0; 3862306a36Sopenharmony_ci unsigned int mask, warn = 0; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci if (WARN_ON(!soc_info->pinmux_pins)) 4162306a36Sopenharmony_ci return -ENODEV; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (!pinmux_base) { 4462306a36Sopenharmony_ci pinmux_base = ioremap(soc_info->pinmux_base, SZ_4K); 4562306a36Sopenharmony_ci if (WARN_ON(!pinmux_base)) 4662306a36Sopenharmony_ci return -ENOMEM; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (index >= soc_info->pinmux_pins_num) { 5062306a36Sopenharmony_ci pr_err("Invalid pin mux index: %lu (%lu)\n", 5162306a36Sopenharmony_ci index, soc_info->pinmux_pins_num); 5262306a36Sopenharmony_ci dump_stack(); 5362306a36Sopenharmony_ci return -ENODEV; 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci cfg = &soc_info->pinmux_pins[index]; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci if (cfg->name == NULL) { 5962306a36Sopenharmony_ci pr_err("No entry for the specified index\n"); 6062306a36Sopenharmony_ci return -ENODEV; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* Update the mux register in question */ 6462306a36Sopenharmony_ci if (cfg->mask) { 6562306a36Sopenharmony_ci unsigned tmp1, tmp2; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci spin_lock_irqsave(&mux_spin_lock, flags); 6862306a36Sopenharmony_ci reg_orig = __raw_readl(pinmux_base + cfg->mux_reg); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci mask = (cfg->mask << cfg->mask_offset); 7162306a36Sopenharmony_ci tmp1 = reg_orig & mask; 7262306a36Sopenharmony_ci reg = reg_orig & ~mask; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci tmp2 = (cfg->mode << cfg->mask_offset); 7562306a36Sopenharmony_ci reg |= tmp2; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (tmp1 != tmp2) 7862306a36Sopenharmony_ci warn = 1; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci __raw_writel(reg, pinmux_base + cfg->mux_reg); 8162306a36Sopenharmony_ci spin_unlock_irqrestore(&mux_spin_lock, flags); 8262306a36Sopenharmony_ci } 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci if (warn) { 8562306a36Sopenharmony_ci#ifdef CONFIG_DAVINCI_MUX_WARNINGS 8662306a36Sopenharmony_ci pr_warn("initialized %s\n", cfg->name); 8762306a36Sopenharmony_ci#endif 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci#ifdef CONFIG_DAVINCI_MUX_DEBUG 9162306a36Sopenharmony_ci if (cfg->debug || warn) { 9262306a36Sopenharmony_ci pr_warn("Setting register %s\n", cfg->name); 9362306a36Sopenharmony_ci pr_warn(" %s (0x%08x) = 0x%08x -> 0x%08x\n", 9462306a36Sopenharmony_ci cfg->mux_reg_name, cfg->mux_reg, reg_orig, reg); 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci#endif 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return 0; 9962306a36Sopenharmony_ci} 100