18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Utility to set the DAVINCI MUX register from a table in mux.h 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Author: Vladimir Barinov, MontaVista Software, Inc. <source@mvista.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Based on linux/arch/arm/plat-omap/mux.c: 78c2ecf20Sopenharmony_ci * Copyright (C) 2003 - 2005 Nokia Corporation 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Written by Tony Lindgren 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * 2007 (c) MontaVista Software, Inc. This file is licensed under 128c2ecf20Sopenharmony_ci * the terms of the GNU General Public License version 2. This program 138c2ecf20Sopenharmony_ci * is licensed "as is" without any warranty of any kind, whether express 148c2ecf20Sopenharmony_ci * or implied. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Copyright (C) 2008 Texas Instruments. 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/io.h> 228c2ecf20Sopenharmony_ci#include <linux/module.h> 238c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include <mach/mux.h> 268c2ecf20Sopenharmony_ci#include <mach/common.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic void __iomem *pinmux_base; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* 318c2ecf20Sopenharmony_ci * Sets the DAVINCI MUX register based on the table 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ciint davinci_cfg_reg(const unsigned long index) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci static DEFINE_SPINLOCK(mux_spin_lock); 368c2ecf20Sopenharmony_ci struct davinci_soc_info *soc_info = &davinci_soc_info; 378c2ecf20Sopenharmony_ci unsigned long flags; 388c2ecf20Sopenharmony_ci const struct mux_config *cfg; 398c2ecf20Sopenharmony_ci unsigned int reg_orig = 0, reg = 0; 408c2ecf20Sopenharmony_ci unsigned int mask, warn = 0; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci if (WARN_ON(!soc_info->pinmux_pins)) 438c2ecf20Sopenharmony_ci return -ENODEV; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci if (!pinmux_base) { 468c2ecf20Sopenharmony_ci pinmux_base = ioremap(soc_info->pinmux_base, SZ_4K); 478c2ecf20Sopenharmony_ci if (WARN_ON(!pinmux_base)) 488c2ecf20Sopenharmony_ci return -ENOMEM; 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (index >= soc_info->pinmux_pins_num) { 528c2ecf20Sopenharmony_ci pr_err("Invalid pin mux index: %lu (%lu)\n", 538c2ecf20Sopenharmony_ci index, soc_info->pinmux_pins_num); 548c2ecf20Sopenharmony_ci dump_stack(); 558c2ecf20Sopenharmony_ci return -ENODEV; 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci cfg = &soc_info->pinmux_pins[index]; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci if (cfg->name == NULL) { 618c2ecf20Sopenharmony_ci pr_err("No entry for the specified index\n"); 628c2ecf20Sopenharmony_ci return -ENODEV; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* Update the mux register in question */ 668c2ecf20Sopenharmony_ci if (cfg->mask) { 678c2ecf20Sopenharmony_ci unsigned tmp1, tmp2; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci spin_lock_irqsave(&mux_spin_lock, flags); 708c2ecf20Sopenharmony_ci reg_orig = __raw_readl(pinmux_base + cfg->mux_reg); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci mask = (cfg->mask << cfg->mask_offset); 738c2ecf20Sopenharmony_ci tmp1 = reg_orig & mask; 748c2ecf20Sopenharmony_ci reg = reg_orig & ~mask; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci tmp2 = (cfg->mode << cfg->mask_offset); 778c2ecf20Sopenharmony_ci reg |= tmp2; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (tmp1 != tmp2) 808c2ecf20Sopenharmony_ci warn = 1; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci __raw_writel(reg, pinmux_base + cfg->mux_reg); 838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&mux_spin_lock, flags); 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (warn) { 878c2ecf20Sopenharmony_ci#ifdef CONFIG_DAVINCI_MUX_WARNINGS 888c2ecf20Sopenharmony_ci pr_warn("initialized %s\n", cfg->name); 898c2ecf20Sopenharmony_ci#endif 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#ifdef CONFIG_DAVINCI_MUX_DEBUG 938c2ecf20Sopenharmony_ci if (cfg->debug || warn) { 948c2ecf20Sopenharmony_ci pr_warn("Setting register %s\n", cfg->name); 958c2ecf20Sopenharmony_ci pr_warn(" %s (0x%08x) = 0x%08x -> 0x%08x\n", 968c2ecf20Sopenharmony_ci cfg->mux_reg_name, cfg->mux_reg, reg_orig, reg); 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci#endif 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ciEXPORT_SYMBOL(davinci_cfg_reg); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ciint davinci_cfg_reg_list(const short pins[]) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci int i, error = -EINVAL; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (pins) 1098c2ecf20Sopenharmony_ci for (i = 0; pins[i] >= 0; i++) { 1108c2ecf20Sopenharmony_ci error = davinci_cfg_reg(pins[i]); 1118c2ecf20Sopenharmony_ci if (error) 1128c2ecf20Sopenharmony_ci break; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci return error; 1168c2ecf20Sopenharmony_ci} 117