2005-11-10 17:26:51 +03:00
/*
* linux / arch / arm / mach - omap2 / mux . c
*
2010-08-16 12:55:35 +04:00
* OMAP2 , OMAP3 and OMAP4 pin multiplexing configurations
2005-11-10 17:26:51 +03:00
*
2010-08-16 12:55:35 +04:00
* Copyright ( C ) 2004 - 2010 Texas Instruments Inc .
2008-01-25 04:24:15 +03:00
* Copyright ( C ) 2003 - 2008 Nokia Corporation
2005-11-10 17:26:51 +03:00
*
2008-01-25 04:24:15 +03:00
* Written by Tony Lindgren
2005-11-10 17:26:51 +03:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
*/
2010-10-08 21:40:20 +04:00
# include <linux/kernel.h>
2005-11-10 17:26:51 +03:00
# include <linux/init.h>
2008-09-06 15:10:45 +04:00
# include <linux/io.h>
2009-12-12 03:16:32 +03:00
# include <linux/list.h>
2010-10-08 21:40:20 +04:00
# include <linux/slab.h>
2009-12-12 03:16:32 +03:00
# include <linux/ctype.h>
# include <linux/debugfs.h>
# include <linux/seq_file.h>
# include <linux/uaccess.h>
2011-12-17 01:36:59 +04:00
# include <linux/irq.h>
# include <linux/interrupt.h>
2005-11-10 17:26:51 +03:00
2008-09-06 15:10:45 +04:00
2012-10-03 04:41:35 +04:00
# include "omap_hwmod.h"
2010-12-23 05:42:35 +03:00
2012-10-06 00:25:59 +04:00
# include "soc.h"
2010-10-08 21:40:20 +04:00
# include "control.h"
2009-12-12 03:16:32 +03:00
# include "mux.h"
2011-12-17 01:36:59 +04:00
# include "prm.h"
2012-06-17 22:00:58 +04:00
# include "common.h"
2005-11-10 17:26:51 +03:00
2009-12-12 03:16:31 +03:00
# define OMAP_MUX_BASE_OFFSET 0x30 /* Offset from CTRL_BASE */
# define OMAP_MUX_BASE_SZ 0x5ca
2009-12-12 03:16:32 +03:00
struct omap_mux_entry {
struct omap_mux mux ;
struct list_head node ;
} ;
2010-08-16 12:55:35 +04:00
static LIST_HEAD ( mux_partitions ) ;
static DEFINE_MUTEX ( muxmode_mutex ) ;
struct omap_mux_partition * omap_mux_get ( const char * name )
{
struct omap_mux_partition * partition ;
list_for_each_entry ( partition , & mux_partitions , node ) {
if ( ! strcmp ( name , partition - > name ) )
return partition ;
}
2009-12-12 03:16:31 +03:00
2010-08-16 12:55:35 +04:00
return NULL ;
}
u16 omap_mux_read ( struct omap_mux_partition * partition , u16 reg )
2009-12-12 03:16:31 +03:00
{
2010-08-16 12:55:35 +04:00
if ( partition - > flags & OMAP_MUX_REG_8BIT )
2014-04-15 21:37:46 +04:00
return readb_relaxed ( partition - > base + reg ) ;
2009-12-12 03:16:31 +03:00
else
2014-04-15 21:37:46 +04:00
return readw_relaxed ( partition - > base + reg ) ;
2009-12-12 03:16:31 +03:00
}
2010-08-16 12:55:35 +04:00
void omap_mux_write ( struct omap_mux_partition * partition , u16 val ,
u16 reg )
2009-12-12 03:16:31 +03:00
{
2010-08-16 12:55:35 +04:00
if ( partition - > flags & OMAP_MUX_REG_8BIT )
2014-04-15 21:37:46 +04:00
writeb_relaxed ( val , partition - > base + reg ) ;
2009-12-12 03:16:31 +03:00
else
2014-04-15 21:37:46 +04:00
writew_relaxed ( val , partition - > base + reg ) ;
2009-12-12 03:16:31 +03:00
}
2008-01-25 11:42:48 +03:00
2010-08-16 12:55:35 +04:00
void omap_mux_write_array ( struct omap_mux_partition * partition ,
struct omap_board_mux * board_mux )
2010-01-20 02:15:24 +03:00
{
2011-05-31 23:00:09 +04:00
if ( ! board_mux )
return ;
2010-08-16 12:55:35 +04:00
while ( board_mux - > reg_offset ! = OMAP_MUX_TERMINATOR ) {
omap_mux_write ( partition , board_mux - > value ,
board_mux - > reg_offset ) ;
2010-01-20 02:15:24 +03:00
board_mux + + ;
}
}
2009-12-12 03:16:32 +03:00
# ifdef CONFIG_OMAP_MUX
static char * omap_mux_options ;
2012-02-20 21:43:30 +04:00
static int __init _omap_mux_init_gpio ( struct omap_mux_partition * partition ,
int gpio , int val )
2009-12-12 03:16:32 +03:00
{
struct omap_mux_entry * e ;
2010-09-24 05:27:18 +04:00
struct omap_mux * gpio_mux = NULL ;
2010-08-02 14:18:28 +04:00
u16 old_mode ;
u16 mux_mode ;
2009-12-12 03:16:32 +03:00
int found = 0 ;
2010-08-16 12:55:35 +04:00
struct list_head * muxmodes = & partition - > muxmodes ;
2009-12-12 03:16:32 +03:00
if ( ! gpio )
return - EINVAL ;
2010-08-16 12:55:35 +04:00
list_for_each_entry ( e , muxmodes , node ) {
2009-12-12 03:16:32 +03:00
struct omap_mux * m = & e - > mux ;
if ( gpio = = m - > gpio ) {
2010-08-02 14:18:28 +04:00
gpio_mux = m ;
2009-12-12 03:16:32 +03:00
found + + ;
}
}
2010-08-02 14:18:28 +04:00
if ( found = = 0 ) {
2010-11-15 18:50:50 +03:00
pr_err ( " %s: Could not set gpio%i \n " , __func__ , gpio ) ;
2010-08-02 14:18:28 +04:00
return - ENODEV ;
}
2009-12-12 03:16:32 +03:00
if ( found > 1 ) {
2010-11-15 18:50:50 +03:00
pr_info ( " %s: Multiple gpio paths (%d) for gpio%i \n " , __func__ ,
2010-08-10 19:33:01 +04:00
found , gpio ) ;
2009-12-12 03:16:32 +03:00
return - EINVAL ;
}
2010-08-16 12:55:35 +04:00
old_mode = omap_mux_read ( partition , gpio_mux - > reg_offset ) ;
2010-08-02 14:18:28 +04:00
mux_mode = val & ~ ( OMAP_MUX_NR_MODES - 1 ) ;
2012-11-27 05:02:03 +04:00
mux_mode | = partition - > gpio ;
2010-11-15 18:50:50 +03:00
pr_debug ( " %s: Setting signal %s.gpio%i 0x%04x -> 0x%04x \n " , __func__ ,
2010-08-10 19:33:01 +04:00
gpio_mux - > muxnames [ 0 ] , gpio , old_mode , mux_mode ) ;
2010-08-16 12:55:35 +04:00
omap_mux_write ( partition , mux_mode , gpio_mux - > reg_offset ) ;
2009-12-12 03:16:32 +03:00
2010-08-02 14:18:28 +04:00
return 0 ;
2009-12-12 03:16:32 +03:00
}
2012-02-20 21:43:30 +04:00
int __init omap_mux_init_gpio ( int gpio , int val )
2010-08-16 12:55:35 +04:00
{
struct omap_mux_partition * partition ;
int ret ;
list_for_each_entry ( partition , & mux_partitions , node ) {
ret = _omap_mux_init_gpio ( partition , gpio , val ) ;
if ( ! ret )
return ret ;
}
return - ENODEV ;
}
2012-02-20 21:43:30 +04:00
static int __init _omap_mux_get_by_name ( struct omap_mux_partition * partition ,
const char * muxname ,
struct omap_mux * * found_mux )
2009-12-12 03:16:32 +03:00
{
2010-12-23 05:42:35 +03:00
struct omap_mux * mux = NULL ;
2009-12-12 03:16:32 +03:00
struct omap_mux_entry * e ;
2010-10-02 03:35:24 +04:00
const char * mode_name ;
2011-01-17 07:31:18 +03:00
int found = 0 , found_mode = 0 , mode0_len = 0 ;
2010-08-16 12:55:35 +04:00
struct list_head * muxmodes = & partition - > muxmodes ;
2009-12-12 03:16:32 +03:00
mode_name = strchr ( muxname , ' . ' ) ;
if ( mode_name ) {
2010-10-02 03:35:24 +04:00
mode0_len = strlen ( muxname ) - strlen ( mode_name ) ;
2009-12-12 03:16:32 +03:00
mode_name + + ;
} else {
mode_name = muxname ;
}
2010-08-16 12:55:35 +04:00
list_for_each_entry ( e , muxmodes , node ) {
2010-12-23 05:42:35 +03:00
char * m0_entry ;
2009-12-12 03:16:32 +03:00
int i ;
2010-12-23 05:42:35 +03:00
mux = & e - > mux ;
m0_entry = mux - > muxnames [ 0 ] ;
2010-10-02 03:35:24 +04:00
/* First check for full name in mode0.muxmode format */
ARM: OMAP2+: Fix parser-bug in platform muxing code
Fix a parser-bug in the omap2 muxing code where muxtable-entries will be
wrongly selected if the requested muxname is a *prefix* of their
m0-entry and they have a matching mN-entry. Fix by additionally checking
that the length of the m0_entry is equal.
For example muxing of "dss_data2.dss_data2" on omap32xx will fail
because the prefix "dss_data2" will match the mux-entries "dss_data2" as
well as "dss_data20", with the suffix "dss_data2" matching m0 (for
dss_data2) and m4 (for dss_data20). Thus both are recognized as signal
path candidates:
Relevant muxentries from mux34xx.c:
_OMAP3_MUXENTRY(DSS_DATA20, 90,
"dss_data20", NULL, "mcspi3_somi", "dss_data2",
"gpio_90", NULL, NULL, "safe_mode"),
_OMAP3_MUXENTRY(DSS_DATA2, 72,
"dss_data2", NULL, NULL, NULL,
"gpio_72", NULL, NULL, "safe_mode"),
This will result in a failure to mux the pin at all:
_omap_mux_get_by_name: Multiple signal paths (2) for dss_data2.dss_data2
Patch should apply to linus' latest master down to rather old linux-2.6
trees.
Signed-off-by: David R. Piegdon <lkml@p23q.org>
Cc: stable@vger.kernel.org
[tony@atomide.com: updated description to include full description]
Signed-off-by: Tony Lindgren <tony@atomide.com>
2014-06-17 03:42:51 +04:00
if ( mode0_len )
if ( strncmp ( muxname , m0_entry , mode0_len ) | |
( strlen ( m0_entry ) ! = mode0_len ) )
continue ;
2009-12-12 03:16:32 +03:00
2010-10-02 03:35:24 +04:00
/* Then check for muxmode only */
2009-12-12 03:16:32 +03:00
for ( i = 0 ; i < OMAP_MUX_NR_MODES ; i + + ) {
2010-12-23 05:42:35 +03:00
char * mode_cur = mux - > muxnames [ i ] ;
2009-12-12 03:16:32 +03:00
if ( ! mode_cur )
continue ;
if ( ! strcmp ( mode_name , mode_cur ) ) {
2010-12-23 05:42:35 +03:00
* found_mux = mux ;
2009-12-12 03:16:32 +03:00
found + + ;
2010-12-23 05:42:35 +03:00
found_mode = i ;
2009-12-12 03:16:32 +03:00
}
}
}
2010-12-23 05:42:35 +03:00
if ( found = = 1 ) {
return found_mode ;
}
2009-12-12 03:16:32 +03:00
if ( found > 1 ) {
2010-11-15 18:50:50 +03:00
pr_err ( " %s: Multiple signal paths (%i) for %s \n " , __func__ ,
2010-08-10 19:33:01 +04:00
found , muxname ) ;
2009-12-12 03:16:32 +03:00
return - EINVAL ;
}
return - ENODEV ;
}
2012-06-05 15:04:11 +04:00
int __init omap_mux_get_by_name ( const char * muxname ,
2010-12-23 05:42:35 +03:00
struct omap_mux_partition * * found_partition ,
struct omap_mux * * found_mux )
2010-08-16 12:55:35 +04:00
{
struct omap_mux_partition * partition ;
list_for_each_entry ( partition , & mux_partitions , node ) {
2010-12-23 05:42:35 +03:00
struct omap_mux * mux = NULL ;
int mux_mode = _omap_mux_get_by_name ( partition , muxname , & mux ) ;
if ( mux_mode < 0 )
continue ;
* found_partition = partition ;
* found_mux = mux ;
return mux_mode ;
2010-08-16 12:55:35 +04:00
}
2013-02-03 04:15:10 +04:00
pr_err ( " %s: Could not find signal %s \n " , __func__ , muxname ) ;
2010-08-16 12:55:35 +04:00
return - ENODEV ;
2010-12-23 05:42:35 +03:00
}
2010-08-16 12:55:35 +04:00
2012-02-20 21:43:30 +04:00
int __init omap_mux_init_signal ( const char * muxname , int val )
2010-12-23 05:42:35 +03:00
{
struct omap_mux_partition * partition = NULL ;
struct omap_mux * mux = NULL ;
u16 old_mode ;
int mux_mode ;
mux_mode = omap_mux_get_by_name ( muxname , & partition , & mux ) ;
2012-04-13 16:34:32 +04:00
if ( mux_mode < 0 | | ! mux )
2010-12-23 05:42:35 +03:00
return mux_mode ;
old_mode = omap_mux_read ( partition , mux - > reg_offset ) ;
mux_mode | = val ;
pr_debug ( " %s: Setting signal %s 0x%04x -> 0x%04x \n " ,
__func__ , muxname , old_mode , mux_mode ) ;
omap_mux_write ( partition , mux_mode , mux - > reg_offset ) ;
return 0 ;
2010-08-16 12:55:35 +04:00
}
2010-12-23 05:42:35 +03:00
struct omap_hwmod_mux_info * __init
omap_hwmod_mux_init ( struct omap_device_pad * bpads , int nr_pads )
{
struct omap_hwmod_mux_info * hmux ;
2011-03-11 22:32:25 +03:00
int i , nr_pads_dynamic = 0 ;
2010-12-23 05:42:35 +03:00
if ( ! bpads | | nr_pads < 1 )
return NULL ;
hmux = kzalloc ( sizeof ( struct omap_hwmod_mux_info ) , GFP_KERNEL ) ;
if ( ! hmux )
goto err1 ;
hmux - > nr_pads = nr_pads ;
hmux - > pads = kzalloc ( sizeof ( struct omap_device_pad ) *
nr_pads , GFP_KERNEL ) ;
if ( ! hmux - > pads )
goto err2 ;
for ( i = 0 ; i < hmux - > nr_pads ; i + + ) {
struct omap_mux_partition * partition ;
struct omap_device_pad * bpad = & bpads [ i ] , * pad = & hmux - > pads [ i ] ;
struct omap_mux * mux ;
int mux_mode ;
mux_mode = omap_mux_get_by_name ( bpad - > name , & partition , & mux ) ;
if ( mux_mode < 0 )
goto err3 ;
if ( ! pad - > partition )
pad - > partition = partition ;
if ( ! pad - > mux )
pad - > mux = mux ;
pad - > name = kzalloc ( strlen ( bpad - > name ) + 1 , GFP_KERNEL ) ;
if ( ! pad - > name ) {
int j ;
for ( j = i - 1 ; j > = 0 ; j - - )
kfree ( hmux - > pads [ j ] . name ) ;
goto err3 ;
}
strcpy ( pad - > name , bpad - > name ) ;
pad - > flags = bpad - > flags ;
pad - > enable = bpad - > enable ;
pad - > idle = bpad - > idle ;
pad - > off = bpad - > off ;
2011-03-11 22:32:25 +03:00
2011-12-17 01:36:57 +04:00
if ( pad - > flags &
( OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP ) )
2011-03-11 22:32:25 +03:00
nr_pads_dynamic + + ;
2010-12-23 05:42:35 +03:00
pr_debug ( " %s: Initialized %s \n " , __func__ , pad - > name ) ;
}
2011-03-11 22:32:25 +03:00
if ( ! nr_pads_dynamic )
return hmux ;
/*
* Add pads that need dynamic muxing into a separate list
*/
hmux - > nr_pads_dynamic = nr_pads_dynamic ;
hmux - > pads_dynamic = kzalloc ( sizeof ( struct omap_device_pad * ) *
nr_pads_dynamic , GFP_KERNEL ) ;
if ( ! hmux - > pads_dynamic ) {
pr_err ( " %s: Could not allocate dynamic pads \n " , __func__ ) ;
return hmux ;
}
nr_pads_dynamic = 0 ;
for ( i = 0 ; i < hmux - > nr_pads ; i + + ) {
struct omap_device_pad * pad = & hmux - > pads [ i ] ;
2011-12-17 01:36:57 +04:00
if ( pad - > flags &
( OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP ) ) {
2011-03-11 22:32:25 +03:00
pr_debug ( " %s: pad %s tagged dynamic \n " ,
__func__ , pad - > name ) ;
hmux - > pads_dynamic [ nr_pads_dynamic ] = pad ;
nr_pads_dynamic + + ;
}
}
2010-12-23 05:42:35 +03:00
return hmux ;
err3 :
kfree ( hmux - > pads ) ;
err2 :
kfree ( hmux ) ;
err1 :
pr_err ( " %s: Could not allocate device mux entry \n " , __func__ ) ;
return NULL ;
}
2011-12-17 01:36:59 +04:00
/**
* omap_hwmod_mux_scan_wakeups - omap hwmod scan wakeup pads
* @ hmux : Pads for a hwmod
* @ mpu_irqs : MPU irq array for a hwmod
*
* Scans the wakeup status of pads for a single hwmod . If an irq
* array is defined for this mux , the parser will call the registered
* ISRs for corresponding pads , otherwise the parser will stop at the
* first wakeup active pad and return . Returns true if there is a
* pending and non - served wakeup event for the mux , otherwise false .
*/
static bool omap_hwmod_mux_scan_wakeups ( struct omap_hwmod_mux_info * hmux ,
struct omap_hwmod_irq_info * mpu_irqs )
{
int i , irq ;
unsigned int val ;
u32 handled_irqs = 0 ;
for ( i = 0 ; i < hmux - > nr_pads_dynamic ; i + + ) {
struct omap_device_pad * pad = hmux - > pads_dynamic [ i ] ;
if ( ! ( pad - > flags & OMAP_DEVICE_PAD_WAKEUP ) | |
! ( pad - > idle & OMAP_WAKEUP_EN ) )
continue ;
val = omap_mux_read ( pad - > partition , pad - > mux - > reg_offset ) ;
if ( ! ( val & OMAP_WAKEUP_EVENT ) )
continue ;
if ( ! hmux - > irqs )
return true ;
irq = hmux - > irqs [ i ] ;
/* make sure we only handle each irq once */
if ( handled_irqs & 1 < < irq )
continue ;
handled_irqs | = 1 < < irq ;
generic_handle_irq ( mpu_irqs [ irq ] . irq ) ;
}
return false ;
}
/**
* _omap_hwmod_mux_handle_irq - Process wakeup events for a single hwmod
*
* Checks a single hwmod for every wakeup capable pad to see if there is an
* active wakeup event . If this is the case , call the corresponding ISR .
*/
static int _omap_hwmod_mux_handle_irq ( struct omap_hwmod * oh , void * data )
{
if ( ! oh - > mux | | ! oh - > mux - > enabled )
return 0 ;
if ( omap_hwmod_mux_scan_wakeups ( oh - > mux , oh - > mpu_irqs ) )
generic_handle_irq ( oh - > mpu_irqs [ 0 ] . irq ) ;
return 0 ;
}
/**
* omap_hwmod_mux_handle_irq - Process pad wakeup irqs .
*
* Calls a function for each registered omap_hwmod to check
* pad wakeup statuses .
*/
static irqreturn_t omap_hwmod_mux_handle_irq ( int irq , void * unused )
{
omap_hwmod_for_each ( _omap_hwmod_mux_handle_irq , NULL ) ;
return IRQ_HANDLED ;
}
2010-12-23 05:42:35 +03:00
/* Assumes the calling function takes care of locking */
void omap_hwmod_mux ( struct omap_hwmod_mux_info * hmux , u8 state )
{
int i ;
2011-03-11 22:32:25 +03:00
/* Runtime idling of dynamic pads */
if ( state = = _HWMOD_STATE_IDLE & & hmux - > enabled ) {
for ( i = 0 ; i < hmux - > nr_pads_dynamic ; i + + ) {
struct omap_device_pad * pad = hmux - > pads_dynamic [ i ] ;
int val = - EINVAL ;
val = pad - > idle ;
omap_mux_write ( pad - > partition , val ,
pad - > mux - > reg_offset ) ;
}
return ;
}
/* Runtime enabling of dynamic pads */
2011-03-11 22:32:25 +03:00
if ( ( state = = _HWMOD_STATE_ENABLED ) & & hmux - > pads_dynamic
& & hmux - > enabled ) {
2011-03-11 22:32:25 +03:00
for ( i = 0 ; i < hmux - > nr_pads_dynamic ; i + + ) {
struct omap_device_pad * pad = hmux - > pads_dynamic [ i ] ;
int val = - EINVAL ;
val = pad - > enable ;
omap_mux_write ( pad - > partition , val ,
pad - > mux - > reg_offset ) ;
}
2011-03-11 22:32:25 +03:00
return ;
2011-03-11 22:32:25 +03:00
}
/* Enabling or disabling of all pads */
2010-12-23 05:42:35 +03:00
for ( i = 0 ; i < hmux - > nr_pads ; i + + ) {
struct omap_device_pad * pad = & hmux - > pads [ i ] ;
int flags , val = - EINVAL ;
flags = pad - > flags ;
switch ( state ) {
case _HWMOD_STATE_ENABLED :
val = pad - > enable ;
pr_debug ( " %s: Enabling %s %x \n " , __func__ ,
pad - > name , val ) ;
break ;
case _HWMOD_STATE_DISABLED :
/* Use safe mode unless OMAP_DEVICE_PAD_REMUX */
if ( flags & OMAP_DEVICE_PAD_REMUX )
val = pad - > off ;
else
val = OMAP_MUX_MODE7 ;
pr_debug ( " %s: Disabling %s %x \n " , __func__ ,
pad - > name , val ) ;
2011-03-11 22:32:25 +03:00
break ;
default :
/* Nothing to be done */
break ;
2012-09-18 20:36:11 +04:00
}
2010-12-23 05:42:35 +03:00
if ( val > = 0 ) {
omap_mux_write ( pad - > partition , val ,
pad - > mux - > reg_offset ) ;
pad - > flags = flags ;
}
}
2011-03-11 22:32:25 +03:00
if ( state = = _HWMOD_STATE_ENABLED )
hmux - > enabled = true ;
else
hmux - > enabled = false ;
2010-12-23 05:42:35 +03:00
}
2009-12-12 03:16:32 +03:00
# ifdef CONFIG_DEBUG_FS
# define OMAP_MUX_MAX_NR_FLAGS 10
# define OMAP_MUX_TEST_FLAG(val, mask) \
if ( ( ( val ) & ( mask ) ) = = ( mask ) ) { \
i + + ; \
flags [ i ] = # mask ; \
}
/* REVISIT: Add checking for non-optimal mux settings */
static inline void omap_mux_decode ( struct seq_file * s , u16 val )
{
char * flags [ OMAP_MUX_MAX_NR_FLAGS ] ;
2010-02-02 00:03:42 +03:00
char mode [ sizeof ( " OMAP_MUX_MODE " ) + 1 ] ;
2009-12-12 03:16:32 +03:00
int i = - 1 ;
sprintf ( mode , " OMAP_MUX_MODE%d " , val & 0x7 ) ;
i + + ;
flags [ i ] = mode ;
OMAP_MUX_TEST_FLAG ( val , OMAP_PIN_OFF_WAKEUPENABLE ) ;
if ( val & OMAP_OFF_EN ) {
if ( ! ( val & OMAP_OFFOUT_EN ) ) {
if ( ! ( val & OMAP_OFF_PULL_UP ) ) {
OMAP_MUX_TEST_FLAG ( val ,
OMAP_PIN_OFF_INPUT_PULLDOWN ) ;
} else {
OMAP_MUX_TEST_FLAG ( val ,
OMAP_PIN_OFF_INPUT_PULLUP ) ;
}
} else {
if ( ! ( val & OMAP_OFFOUT_VAL ) ) {
OMAP_MUX_TEST_FLAG ( val ,
OMAP_PIN_OFF_OUTPUT_LOW ) ;
} else {
OMAP_MUX_TEST_FLAG ( val ,
OMAP_PIN_OFF_OUTPUT_HIGH ) ;
}
}
}
if ( val & OMAP_INPUT_EN ) {
if ( val & OMAP_PULL_ENA ) {
if ( ! ( val & OMAP_PULL_UP ) ) {
OMAP_MUX_TEST_FLAG ( val ,
OMAP_PIN_INPUT_PULLDOWN ) ;
} else {
OMAP_MUX_TEST_FLAG ( val , OMAP_PIN_INPUT_PULLUP ) ;
}
} else {
OMAP_MUX_TEST_FLAG ( val , OMAP_PIN_INPUT ) ;
}
} else {
i + + ;
flags [ i ] = " OMAP_PIN_OUTPUT " ;
}
do {
seq_printf ( s , " %s " , flags [ i ] ) ;
if ( i > 0 )
seq_printf ( s , " | " ) ;
} while ( i - - > 0 ) ;
}
2010-08-16 12:55:35 +04:00
# define OMAP_MUX_DEFNAME_LEN 32
2009-12-12 03:16:32 +03:00
static int omap_mux_dbg_board_show ( struct seq_file * s , void * unused )
{
2010-08-16 12:55:35 +04:00
struct omap_mux_partition * partition = s - > private ;
2009-12-12 03:16:32 +03:00
struct omap_mux_entry * e ;
2010-08-16 12:55:35 +04:00
u8 omap_gen = omap_rev ( ) > > 28 ;
2009-12-12 03:16:32 +03:00
2010-08-16 12:55:35 +04:00
list_for_each_entry ( e , & partition - > muxmodes , node ) {
2009-12-12 03:16:32 +03:00
struct omap_mux * m = & e - > mux ;
char m0_def [ OMAP_MUX_DEFNAME_LEN ] ;
char * m0_name = m - > muxnames [ 0 ] ;
u16 val ;
int i , mode ;
if ( ! m0_name )
continue ;
2010-02-02 00:03:42 +03:00
/* REVISIT: Needs to be updated if mode0 names get longer */
2009-12-12 03:16:32 +03:00
for ( i = 0 ; i < OMAP_MUX_DEFNAME_LEN ; i + + ) {
if ( m0_name [ i ] = = ' \0 ' ) {
m0_def [ i ] = m0_name [ i ] ;
break ;
}
m0_def [ i ] = toupper ( m0_name [ i ] ) ;
}
2010-08-16 12:55:35 +04:00
val = omap_mux_read ( partition , m - > reg_offset ) ;
2009-12-12 03:16:32 +03:00
mode = val & OMAP_MUX_MODE7 ;
2010-08-16 12:55:35 +04:00
if ( mode ! = 0 )
seq_printf ( s , " /* %s */ \n " , m - > muxnames [ mode ] ) ;
/*
2011-03-31 05:57:33 +04:00
* XXX : Might be revisited to support differences across
2010-08-16 12:55:35 +04:00
* same OMAP generation .
*/
seq_printf ( s , " OMAP%d_MUX(%s, " , omap_gen , m0_def ) ;
2009-12-12 03:16:32 +03:00
omap_mux_decode ( s , val ) ;
seq_printf ( s , " ), \n " ) ;
}
return 0 ;
}
static int omap_mux_dbg_board_open ( struct inode * inode , struct file * file )
{
2010-08-16 12:55:35 +04:00
return single_open ( file , omap_mux_dbg_board_show , inode - > i_private ) ;
2009-12-12 03:16:32 +03:00
}
static const struct file_operations omap_mux_dbg_board_fops = {
. open = omap_mux_dbg_board_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
} ;
2010-08-16 12:55:35 +04:00
static struct omap_mux_partition * omap_mux_get_partition ( struct omap_mux * mux )
{
struct omap_mux_partition * partition ;
list_for_each_entry ( partition , & mux_partitions , node ) {
struct list_head * muxmodes = & partition - > muxmodes ;
struct omap_mux_entry * e ;
list_for_each_entry ( e , muxmodes , node ) {
struct omap_mux * m = & e - > mux ;
if ( m = = mux )
return partition ;
}
}
return NULL ;
}
2009-12-12 03:16:32 +03:00
static int omap_mux_dbg_signal_show ( struct seq_file * s , void * unused )
{
struct omap_mux * m = s - > private ;
2010-08-16 12:55:35 +04:00
struct omap_mux_partition * partition ;
2009-12-12 03:16:32 +03:00
const char * none = " NA " ;
u16 val ;
int mode ;
2010-08-16 12:55:35 +04:00
partition = omap_mux_get_partition ( m ) ;
if ( ! partition )
return 0 ;
val = omap_mux_read ( partition , m - > reg_offset ) ;
2009-12-12 03:16:32 +03:00
mode = val & OMAP_MUX_MODE7 ;
2010-08-16 12:55:35 +04:00
seq_printf ( s , " name: %s.%s (0x%08x/0x%03x = 0x%04x), b %s, t %s \n " ,
2009-12-12 03:16:32 +03:00
m - > muxnames [ 0 ] , m - > muxnames [ mode ] ,
2010-08-16 12:55:35 +04:00
partition - > phys + m - > reg_offset , m - > reg_offset , val ,
2009-12-12 03:16:32 +03:00
m - > balls [ 0 ] ? m - > balls [ 0 ] : none ,
m - > balls [ 1 ] ? m - > balls [ 1 ] : none ) ;
seq_printf ( s , " mode: " ) ;
omap_mux_decode ( s , val ) ;
seq_printf ( s , " \n " ) ;
seq_printf ( s , " signals: %s | %s | %s | %s | %s | %s | %s | %s \n " ,
m - > muxnames [ 0 ] ? m - > muxnames [ 0 ] : none ,
m - > muxnames [ 1 ] ? m - > muxnames [ 1 ] : none ,
m - > muxnames [ 2 ] ? m - > muxnames [ 2 ] : none ,
m - > muxnames [ 3 ] ? m - > muxnames [ 3 ] : none ,
m - > muxnames [ 4 ] ? m - > muxnames [ 4 ] : none ,
m - > muxnames [ 5 ] ? m - > muxnames [ 5 ] : none ,
m - > muxnames [ 6 ] ? m - > muxnames [ 6 ] : none ,
m - > muxnames [ 7 ] ? m - > muxnames [ 7 ] : none ) ;
return 0 ;
}
# define OMAP_MUX_MAX_ARG_CHAR 7
static ssize_t omap_mux_dbg_signal_write ( struct file * file ,
2010-08-16 12:55:35 +04:00
const char __user * user_buf ,
size_t count , loff_t * ppos )
2009-12-12 03:16:32 +03:00
{
struct seq_file * seqf ;
struct omap_mux * m ;
2014-08-09 01:23:52 +04:00
u16 val ;
int ret ;
2010-08-16 12:55:35 +04:00
struct omap_mux_partition * partition ;
2009-12-12 03:16:32 +03:00
if ( count > OMAP_MUX_MAX_ARG_CHAR )
return - EINVAL ;
2014-08-09 01:23:52 +04:00
ret = kstrtou16_from_user ( user_buf , count , 0x10 , & val ) ;
2009-12-12 03:16:32 +03:00
if ( ret < 0 )
return ret ;
seqf = file - > private_data ;
m = seqf - > private ;
2010-08-16 12:55:35 +04:00
partition = omap_mux_get_partition ( m ) ;
if ( ! partition )
return - ENODEV ;
2014-08-09 01:23:52 +04:00
omap_mux_write ( partition , val , m - > reg_offset ) ;
2009-12-12 03:16:32 +03:00
* ppos + = count ;
return count ;
}
static int omap_mux_dbg_signal_open ( struct inode * inode , struct file * file )
{
return single_open ( file , omap_mux_dbg_signal_show , inode - > i_private ) ;
}
static const struct file_operations omap_mux_dbg_signal_fops = {
. open = omap_mux_dbg_signal_open ,
. read = seq_read ,
. write = omap_mux_dbg_signal_write ,
. llseek = seq_lseek ,
. release = single_release ,
} ;
static struct dentry * mux_dbg_dir ;
2010-08-16 12:55:35 +04:00
static void __init omap_mux_dbg_create_entry (
struct omap_mux_partition * partition ,
struct dentry * mux_dbg_dir )
2009-12-12 03:16:32 +03:00
{
struct omap_mux_entry * e ;
2010-08-16 12:55:35 +04:00
list_for_each_entry ( e , & partition - > muxmodes , node ) {
struct omap_mux * m = & e - > mux ;
2013-02-19 14:24:23 +04:00
( void ) debugfs_create_file ( m - > muxnames [ 0 ] , S_IWUSR | S_IRUGO ,
mux_dbg_dir , m ,
& omap_mux_dbg_signal_fops ) ;
2010-08-16 12:55:35 +04:00
}
}
static void __init omap_mux_dbg_init ( void )
{
struct omap_mux_partition * partition ;
static struct dentry * mux_dbg_board_dir ;
2009-12-12 03:16:32 +03:00
mux_dbg_dir = debugfs_create_dir ( " omap_mux " , NULL ) ;
if ( ! mux_dbg_dir )
return ;
2010-08-16 12:55:35 +04:00
mux_dbg_board_dir = debugfs_create_dir ( " board " , mux_dbg_dir ) ;
if ( ! mux_dbg_board_dir )
return ;
2009-12-12 03:16:32 +03:00
2010-08-16 12:55:35 +04:00
list_for_each_entry ( partition , & mux_partitions , node ) {
omap_mux_dbg_create_entry ( partition , mux_dbg_dir ) ;
( void ) debugfs_create_file ( partition - > name , S_IRUGO ,
mux_dbg_board_dir , partition ,
& omap_mux_dbg_board_fops ) ;
2009-12-12 03:16:32 +03:00
}
}
# else
static inline void omap_mux_dbg_init ( void )
{
}
# endif /* CONFIG_DEBUG_FS */
2009-12-12 03:16:32 +03:00
static void __init omap_mux_free_names ( struct omap_mux * m )
{
int i ;
for ( i = 0 ; i < OMAP_MUX_NR_MODES ; i + + )
kfree ( m - > muxnames [ i ] ) ;
# ifdef CONFIG_DEBUG_FS
for ( i = 0 ; i < OMAP_MUX_NR_SIDES ; i + + )
kfree ( m - > balls [ i ] ) ;
# endif
}
/* Free all data except for GPIO pins unless CONFIG_DEBUG_FS is set */
2012-04-26 12:06:50 +04:00
int __init omap_mux_late_init ( void )
2009-12-12 03:16:32 +03:00
{
2010-08-16 12:55:35 +04:00
struct omap_mux_partition * partition ;
2011-12-17 01:36:59 +04:00
int ret ;
2009-12-12 03:16:32 +03:00
2010-08-16 12:55:35 +04:00
list_for_each_entry ( partition , & mux_partitions , node ) {
struct omap_mux_entry * e , * tmp ;
list_for_each_entry_safe ( e , tmp , & partition - > muxmodes , node ) {
struct omap_mux * m = & e - > mux ;
u16 mode = omap_mux_read ( partition , m - > reg_offset ) ;
2009-12-12 03:16:32 +03:00
2012-11-27 05:02:03 +04:00
if ( OMAP_MODE_GPIO ( partition , mode ) )
2010-08-16 12:55:35 +04:00
continue ;
2009-12-12 03:16:32 +03:00
# ifndef CONFIG_DEBUG_FS
2010-08-16 12:55:35 +04:00
mutex_lock ( & muxmode_mutex ) ;
list_del ( & e - > node ) ;
mutex_unlock ( & muxmode_mutex ) ;
omap_mux_free_names ( m ) ;
kfree ( m ) ;
2005-11-10 17:26:51 +03:00
# endif
2010-08-16 12:55:35 +04:00
}
2009-12-12 03:16:32 +03:00
}
2013-10-11 02:45:13 +04:00
omap_mux_dbg_init ( ) ;
/* see pinctrl-single-omap for the wake-up interrupt handling */
if ( of_have_populated_dt ( ) )
return 0 ;
2011-12-17 01:36:59 +04:00
ret = request_irq ( omap_prcm_event_to_irq ( " io " ) ,
omap_hwmod_mux_handle_irq , IRQF_SHARED | IRQF_NO_SUSPEND ,
" hwmod_io " , omap_mux_late_init ) ;
if ( ret )
2014-09-13 22:31:16 +04:00
pr_warn ( " mux: Failed to setup hwmod io irq %d \n " , ret ) ;
2011-12-17 01:36:59 +04:00
2009-12-12 03:16:32 +03:00
return 0 ;
}
static void __init omap_mux_package_fixup ( struct omap_mux * p ,
struct omap_mux * superset )
{
while ( p - > reg_offset ! = OMAP_MUX_TERMINATOR ) {
struct omap_mux * s = superset ;
int found = 0 ;
while ( s - > reg_offset ! = OMAP_MUX_TERMINATOR ) {
if ( s - > reg_offset = = p - > reg_offset ) {
* s = * p ;
found + + ;
break ;
}
s + + ;
}
if ( ! found )
2010-11-15 18:50:50 +03:00
pr_err ( " %s: Unknown entry offset 0x%x \n " , __func__ ,
2010-08-10 19:33:01 +04:00
p - > reg_offset ) ;
2009-12-12 03:16:32 +03:00
p + + ;
}
}
# ifdef CONFIG_DEBUG_FS
static void __init omap_mux_package_init_balls ( struct omap_ball * b ,
struct omap_mux * superset )
{
while ( b - > reg_offset ! = OMAP_MUX_TERMINATOR ) {
struct omap_mux * s = superset ;
int found = 0 ;
while ( s - > reg_offset ! = OMAP_MUX_TERMINATOR ) {
if ( s - > reg_offset = = b - > reg_offset ) {
s - > balls [ 0 ] = b - > balls [ 0 ] ;
s - > balls [ 1 ] = b - > balls [ 1 ] ;
found + + ;
break ;
}
s + + ;
}
if ( ! found )
2010-11-15 18:50:50 +03:00
pr_err ( " %s: Unknown ball offset 0x%x \n " , __func__ ,
2010-08-10 19:33:01 +04:00
b - > reg_offset ) ;
2009-12-12 03:16:32 +03:00
b + + ;
}
}
# else /* CONFIG_DEBUG_FS */
static inline void omap_mux_package_init_balls ( struct omap_ball * b ,
struct omap_mux * superset )
{
}
# endif /* CONFIG_DEBUG_FS */
static int __init omap_mux_setup ( char * options )
{
if ( ! options )
return 0 ;
omap_mux_options = options ;
return 1 ;
}
__setup ( " omap_mux= " , omap_mux_setup ) ;
/*
* Note that the omap_mux = some . signal1 = 0x1234 , some . signal2 = 0x1234
* cmdline options only override the bootloader values .
* During development , please enable CONFIG_DEBUG_FS , and use the
* signal specific entries under debugfs .
*/
static void __init omap_mux_set_cmdline_signals ( void )
{
char * options , * next_opt , * token ;
if ( ! omap_mux_options )
return ;
2011-08-06 13:29:10 +04:00
options = kstrdup ( omap_mux_options , GFP_KERNEL ) ;
2009-12-12 03:16:32 +03:00
if ( ! options )
return ;
next_opt = options ;
while ( ( token = strsep ( & next_opt , " , " ) ) ! = NULL ) {
char * keyval , * name ;
2014-08-09 01:23:52 +04:00
u16 val ;
2009-12-12 03:16:32 +03:00
keyval = token ;
name = strsep ( & keyval , " = " ) ;
if ( name ) {
int res ;
2014-08-09 01:23:52 +04:00
res = kstrtou16 ( keyval , 0x10 , & val ) ;
2009-12-12 03:16:32 +03:00
if ( res < 0 )
continue ;
omap_mux_init_signal ( name , ( u16 ) val ) ;
}
}
kfree ( options ) ;
}
static int __init omap_mux_copy_names ( struct omap_mux * src ,
2010-08-16 12:55:35 +04:00
struct omap_mux * dst )
2009-12-12 03:16:32 +03:00
{
int i ;
for ( i = 0 ; i < OMAP_MUX_NR_MODES ; i + + ) {
if ( src - > muxnames [ i ] ) {
2011-08-06 13:29:10 +04:00
dst - > muxnames [ i ] = kstrdup ( src - > muxnames [ i ] ,
GFP_KERNEL ) ;
2009-12-12 03:16:32 +03:00
if ( ! dst - > muxnames [ i ] )
goto free ;
}
}
# ifdef CONFIG_DEBUG_FS
for ( i = 0 ; i < OMAP_MUX_NR_SIDES ; i + + ) {
if ( src - > balls [ i ] ) {
2011-08-06 13:29:10 +04:00
dst - > balls [ i ] = kstrdup ( src - > balls [ i ] , GFP_KERNEL ) ;
2009-12-12 03:16:32 +03:00
if ( ! dst - > balls [ i ] )
goto free ;
}
}
# endif
return 0 ;
free :
omap_mux_free_names ( dst ) ;
return - ENOMEM ;
}
# endif /* CONFIG_OMAP_MUX */
2010-08-16 12:55:35 +04:00
static struct omap_mux * omap_mux_get_by_gpio (
struct omap_mux_partition * partition ,
int gpio )
2009-12-12 03:16:32 +03:00
{
struct omap_mux_entry * e ;
2010-08-16 12:55:35 +04:00
struct omap_mux * ret = NULL ;
2009-12-12 03:16:32 +03:00
2010-08-16 12:55:35 +04:00
list_for_each_entry ( e , & partition - > muxmodes , node ) {
2009-12-12 03:16:32 +03:00
struct omap_mux * m = & e - > mux ;
if ( m - > gpio = = gpio ) {
2010-08-16 12:55:35 +04:00
ret = m ;
2009-12-12 03:16:32 +03:00
break ;
}
}
2010-08-16 12:55:35 +04:00
return ret ;
2009-12-12 03:16:32 +03:00
}
/* Needed for dynamic muxing of GPIO pins for off-idle */
u16 omap_mux_get_gpio ( int gpio )
{
2010-08-16 12:55:35 +04:00
struct omap_mux_partition * partition ;
2011-06-01 09:58:56 +04:00
struct omap_mux * m = NULL ;
2009-12-12 03:16:32 +03:00
2010-08-16 12:55:35 +04:00
list_for_each_entry ( partition , & mux_partitions , node ) {
m = omap_mux_get_by_gpio ( partition , gpio ) ;
if ( m )
return omap_mux_read ( partition , m - > reg_offset ) ;
2009-12-12 03:16:32 +03:00
}
2010-08-16 12:55:35 +04:00
if ( ! m | | m - > reg_offset = = OMAP_MUX_TERMINATOR )
2010-11-15 18:50:50 +03:00
pr_err ( " %s: Could not get gpio%i \n " , __func__ , gpio ) ;
2010-08-16 12:55:35 +04:00
return OMAP_MUX_TERMINATOR ;
2009-12-12 03:16:32 +03:00
}
/* Needed for dynamic muxing of GPIO pins for off-idle */
void omap_mux_set_gpio ( u16 val , int gpio )
{
2010-08-16 12:55:35 +04:00
struct omap_mux_partition * partition ;
struct omap_mux * m = NULL ;
2009-12-12 03:16:32 +03:00
2010-08-16 12:55:35 +04:00
list_for_each_entry ( partition , & mux_partitions , node ) {
m = omap_mux_get_by_gpio ( partition , gpio ) ;
if ( m ) {
omap_mux_write ( partition , val , m - > reg_offset ) ;
return ;
}
2009-12-12 03:16:32 +03:00
}
2010-08-16 12:55:35 +04:00
if ( ! m | | m - > reg_offset = = OMAP_MUX_TERMINATOR )
2010-11-15 18:50:50 +03:00
pr_err ( " %s: Could not set gpio%i \n " , __func__ , gpio ) ;
2009-12-12 03:16:32 +03:00
}
2010-08-16 12:55:35 +04:00
static struct omap_mux * __init omap_mux_list_add (
struct omap_mux_partition * partition ,
struct omap_mux * src )
2009-12-12 03:16:32 +03:00
{
struct omap_mux_entry * entry ;
struct omap_mux * m ;
entry = kzalloc ( sizeof ( struct omap_mux_entry ) , GFP_KERNEL ) ;
if ( ! entry )
return NULL ;
m = & entry - > mux ;
2011-01-07 06:49:28 +03:00
entry - > mux = * src ;
2009-12-12 03:16:32 +03:00
# ifdef CONFIG_OMAP_MUX
if ( omap_mux_copy_names ( src , m ) ) {
kfree ( entry ) ;
return NULL ;
}
# endif
mutex_lock ( & muxmode_mutex ) ;
2010-08-16 12:55:35 +04:00
list_add_tail ( & entry - > node , & partition - > muxmodes ) ;
2009-12-12 03:16:32 +03:00
mutex_unlock ( & muxmode_mutex ) ;
return m ;
}
/*
* Note if CONFIG_OMAP_MUX is not selected , we will only initialize
* the GPIO to mux offset mapping that is needed for dynamic muxing
* of GPIO pins for off - idle .
*/
2010-08-16 12:55:35 +04:00
static void __init omap_mux_init_list ( struct omap_mux_partition * partition ,
struct omap_mux * superset )
2009-12-12 03:16:32 +03:00
{
while ( superset - > reg_offset ! = OMAP_MUX_TERMINATOR ) {
struct omap_mux * entry ;
2010-02-17 20:17:01 +03:00
# ifdef CONFIG_OMAP_MUX
if ( ! superset - > muxnames | | ! superset - > muxnames [ 0 ] ) {
2009-12-12 03:16:32 +03:00
superset + + ;
continue ;
}
2010-02-17 20:17:01 +03:00
# else
/* Skip pins that are not muxed as GPIO by bootloader */
2012-11-27 05:02:03 +04:00
if ( ! OMAP_MODE_GPIO ( partition , omap_mux_read ( partition ,
2010-08-16 12:55:35 +04:00
superset - > reg_offset ) ) ) {
2010-02-01 22:22:54 +03:00
superset + + ;
continue ;
}
# endif
2010-08-16 12:55:35 +04:00
entry = omap_mux_list_add ( partition , superset ) ;
2009-12-12 03:16:32 +03:00
if ( ! entry ) {
2010-11-15 18:50:50 +03:00
pr_err ( " %s: Could not add entry \n " , __func__ ) ;
2009-12-12 03:16:32 +03:00
return ;
}
superset + + ;
}
}
2010-02-15 21:03:35 +03:00
# ifdef CONFIG_OMAP_MUX
static void omap_mux_init_package ( struct omap_mux * superset ,
struct omap_mux * package_subset ,
struct omap_ball * package_balls )
{
if ( package_subset )
omap_mux_package_fixup ( package_subset , superset ) ;
if ( package_balls )
omap_mux_package_init_balls ( package_balls , superset ) ;
}
2012-02-07 14:18:34 +04:00
static void __init omap_mux_init_signals ( struct omap_mux_partition * partition ,
struct omap_board_mux * board_mux )
2010-02-15 21:03:35 +03:00
{
omap_mux_set_cmdline_signals ( ) ;
2010-08-16 12:55:35 +04:00
omap_mux_write_array ( partition , board_mux ) ;
2010-02-15 21:03:35 +03:00
}
# else
static void omap_mux_init_package ( struct omap_mux * superset ,
struct omap_mux * package_subset ,
struct omap_ball * package_balls )
{
}
2012-02-07 14:18:34 +04:00
static void __init omap_mux_init_signals ( struct omap_mux_partition * partition ,
struct omap_board_mux * board_mux )
2010-02-15 21:03:35 +03:00
{
}
# endif
2010-08-16 12:55:35 +04:00
static u32 mux_partitions_cnt ;
2009-12-12 03:16:32 +03:00
2010-08-16 12:55:35 +04:00
int __init omap_mux_init ( const char * name , u32 flags ,
u32 mux_pbase , u32 mux_size ,
struct omap_mux * superset ,
struct omap_mux * package_subset ,
struct omap_board_mux * board_mux ,
struct omap_ball * package_balls )
{
struct omap_mux_partition * partition ;
partition = kzalloc ( sizeof ( struct omap_mux_partition ) , GFP_KERNEL ) ;
if ( ! partition )
return - ENOMEM ;
partition - > name = name ;
partition - > flags = flags ;
2012-11-27 05:02:03 +04:00
partition - > gpio = flags & OMAP_MUX_MODE7 ;
2010-08-16 12:55:35 +04:00
partition - > size = mux_size ;
partition - > phys = mux_pbase ;
partition - > base = ioremap ( mux_pbase , mux_size ) ;
if ( ! partition - > base ) {
2010-11-15 18:50:50 +03:00
pr_err ( " %s: Could not ioremap mux partition at 0x%08x \n " ,
__func__ , partition - > phys ) ;
2011-01-28 17:50:55 +03:00
kfree ( partition ) ;
2009-12-12 03:16:32 +03:00
return - ENODEV ;
}
2010-08-16 12:55:35 +04:00
INIT_LIST_HEAD ( & partition - > muxmodes ) ;
list_add_tail ( & partition - > node , & mux_partitions ) ;
mux_partitions_cnt + + ;
2010-11-15 18:50:50 +03:00
pr_info ( " %s: Add partition: #%d: %s, flags: %x \n " , __func__ ,
2010-08-16 12:55:35 +04:00
mux_partitions_cnt , partition - > name , partition - > flags ) ;
2010-07-05 17:31:35 +04:00
2010-02-15 21:03:35 +03:00
omap_mux_init_package ( superset , package_subset , package_balls ) ;
2010-08-16 12:55:35 +04:00
omap_mux_init_list ( partition , superset ) ;
omap_mux_init_signals ( partition , board_mux ) ;
2010-01-20 05:17:07 +03:00
2009-12-12 03:16:32 +03:00
return 0 ;
}