2005-08-18 13:06:59 +04:00
/*
* linux / drivers / mfd / mcp - core . c
*
* Copyright ( C ) 2001 Russell King
*
* 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 .
*
* Generic MCP ( Multimedia Communications Port ) layer . All MCP locking
* is solely held within this file .
*/
# include <linux/module.h>
# include <linux/init.h>
# include <linux/errno.h>
# include <linux/smp.h>
# include <linux/device.h>
2005-11-07 11:59:43 +03:00
# include <linux/slab.h>
# include <linux/string.h>
2009-02-10 16:54:57 +03:00
# include <linux/mfd/mcp.h>
2005-08-18 13:06:59 +04:00
# define to_mcp(d) container_of(d, struct mcp, attached_device)
# define to_mcp_driver(d) container_of(d, struct mcp_driver, drv)
static int mcp_bus_match ( struct device * dev , struct device_driver * drv )
{
2012-01-20 21:38:58 +04:00
return 1 ;
2005-08-18 13:06:59 +04:00
}
static int mcp_bus_probe ( struct device * dev )
{
struct mcp * mcp = to_mcp ( dev ) ;
struct mcp_driver * drv = to_mcp_driver ( dev - > driver ) ;
return drv - > probe ( mcp ) ;
}
static int mcp_bus_remove ( struct device * dev )
{
struct mcp * mcp = to_mcp ( dev ) ;
struct mcp_driver * drv = to_mcp_driver ( dev - > driver ) ;
drv - > remove ( mcp ) ;
return 0 ;
}
static struct bus_type mcp_bus_type = {
. name = " mcp " ,
. match = mcp_bus_match ,
2006-01-05 17:39:56 +03:00
. probe = mcp_bus_probe ,
. remove = mcp_bus_remove ,
2005-08-18 13:06:59 +04:00
} ;
/**
* mcp_set_telecom_divisor - set the telecom divisor
* @ mcp : MCP interface structure
* @ div : SIB clock divisor
*
* Set the telecom divisor on the MCP interface . The resulting
* sample rate is SIBCLOCK / div .
*/
void mcp_set_telecom_divisor ( struct mcp * mcp , unsigned int div )
{
2012-01-14 12:49:46 +04:00
unsigned long flags ;
spin_lock_irqsave ( & mcp - > lock , flags ) ;
2005-08-18 13:06:59 +04:00
mcp - > ops - > set_telecom_divisor ( mcp , div ) ;
2012-01-14 12:49:46 +04:00
spin_unlock_irqrestore ( & mcp - > lock , flags ) ;
2005-08-18 13:06:59 +04:00
}
EXPORT_SYMBOL ( mcp_set_telecom_divisor ) ;
/**
* mcp_set_audio_divisor - set the audio divisor
* @ mcp : MCP interface structure
* @ div : SIB clock divisor
*
* Set the audio divisor on the MCP interface .
*/
void mcp_set_audio_divisor ( struct mcp * mcp , unsigned int div )
{
2012-01-14 12:49:46 +04:00
unsigned long flags ;
spin_lock_irqsave ( & mcp - > lock , flags ) ;
2005-08-18 13:06:59 +04:00
mcp - > ops - > set_audio_divisor ( mcp , div ) ;
2012-01-14 12:49:46 +04:00
spin_unlock_irqrestore ( & mcp - > lock , flags ) ;
2005-08-18 13:06:59 +04:00
}
EXPORT_SYMBOL ( mcp_set_audio_divisor ) ;
/**
* mcp_reg_write - write a device register
* @ mcp : MCP interface structure
* @ reg : 4 - bit register index
* @ val : 16 - bit data value
*
* Write a device register . The MCP interface must be enabled
* to prevent this function hanging .
*/
void mcp_reg_write ( struct mcp * mcp , unsigned int reg , unsigned int val )
{
unsigned long flags ;
spin_lock_irqsave ( & mcp - > lock , flags ) ;
mcp - > ops - > reg_write ( mcp , reg , val ) ;
spin_unlock_irqrestore ( & mcp - > lock , flags ) ;
}
EXPORT_SYMBOL ( mcp_reg_write ) ;
/**
* mcp_reg_read - read a device register
* @ mcp : MCP interface structure
* @ reg : 4 - bit register index
*
* Read a device register and return its value . The MCP interface
* must be enabled to prevent this function hanging .
*/
unsigned int mcp_reg_read ( struct mcp * mcp , unsigned int reg )
{
unsigned long flags ;
unsigned int val ;
spin_lock_irqsave ( & mcp - > lock , flags ) ;
val = mcp - > ops - > reg_read ( mcp , reg ) ;
spin_unlock_irqrestore ( & mcp - > lock , flags ) ;
return val ;
}
EXPORT_SYMBOL ( mcp_reg_read ) ;
/**
* mcp_enable - enable the MCP interface
* @ mcp : MCP interface to enable
*
* Enable the MCP interface . Each call to mcp_enable will need
* a corresponding call to mcp_disable to disable the interface .
*/
void mcp_enable ( struct mcp * mcp )
{
2012-01-14 12:49:46 +04:00
unsigned long flags ;
spin_lock_irqsave ( & mcp - > lock , flags ) ;
2005-08-18 13:06:59 +04:00
if ( mcp - > use_count + + = = 0 )
mcp - > ops - > enable ( mcp ) ;
2012-01-14 12:49:46 +04:00
spin_unlock_irqrestore ( & mcp - > lock , flags ) ;
2005-08-18 13:06:59 +04:00
}
EXPORT_SYMBOL ( mcp_enable ) ;
/**
* mcp_disable - disable the MCP interface
* @ mcp : MCP interface to disable
*
* Disable the MCP interface . The MCP interface will only be
* disabled once the number of calls to mcp_enable matches the
* number of calls to mcp_disable .
*/
void mcp_disable ( struct mcp * mcp )
{
unsigned long flags ;
spin_lock_irqsave ( & mcp - > lock , flags ) ;
if ( - - mcp - > use_count = = 0 )
mcp - > ops - > disable ( mcp ) ;
spin_unlock_irqrestore ( & mcp - > lock , flags ) ;
}
EXPORT_SYMBOL ( mcp_disable ) ;
static void mcp_release ( struct device * dev )
{
struct mcp * mcp = container_of ( dev , struct mcp , attached_device ) ;
kfree ( mcp ) ;
}
struct mcp * mcp_host_alloc ( struct device * parent , size_t size )
{
struct mcp * mcp ;
some kmalloc/memset ->kzalloc (tree wide)
Transform some calls to kmalloc/memset to a single kzalloc (or kcalloc).
Here is a short excerpt of the semantic patch performing
this transformation:
@@
type T2;
expression x;
identifier f,fld;
expression E;
expression E1,E2;
expression e1,e2,e3,y;
statement S;
@@
x =
- kmalloc
+ kzalloc
(E1,E2)
... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\)
- memset((T2)x,0,E1);
@@
expression E1,E2,E3;
@@
- kzalloc(E1 * E2,E3)
+ kcalloc(E1,E2,E3)
[akpm@linux-foundation.org: get kcalloc args the right way around]
Signed-off-by: Yoann Padioleau <padator@wanadoo.fr>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Acked-by: Russell King <rmk@arm.linux.org.uk>
Cc: Bryan Wu <bryan.wu@analog.com>
Acked-by: Jiri Slaby <jirislaby@gmail.com>
Cc: Dave Airlie <airlied@linux.ie>
Acked-by: Roland Dreier <rolandd@cisco.com>
Cc: Jiri Kosina <jkosina@suse.cz>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Acked-by: Pierre Ossman <drzeus-list@drzeus.cx>
Cc: Jeff Garzik <jeff@garzik.org>
Cc: "David S. Miller" <davem@davemloft.net>
Acked-by: Greg KH <greg@kroah.com>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 12:49:03 +04:00
mcp = kzalloc ( sizeof ( struct mcp ) + size , GFP_KERNEL ) ;
2005-08-18 13:06:59 +04:00
if ( mcp ) {
spin_lock_init ( & mcp - > lock ) ;
2012-01-21 02:51:07 +04:00
device_initialize ( & mcp - > attached_device ) ;
2005-08-18 13:06:59 +04:00
mcp - > attached_device . parent = parent ;
mcp - > attached_device . bus = & mcp_bus_type ;
mcp - > attached_device . dma_mask = parent - > dma_mask ;
mcp - > attached_device . release = mcp_release ;
}
return mcp ;
}
EXPORT_SYMBOL ( mcp_host_alloc ) ;
2012-01-21 02:13:52 +04:00
int mcp_host_add ( struct mcp * mcp , void * pdata )
2005-08-18 13:06:59 +04:00
{
2012-01-21 02:13:52 +04:00
mcp - > attached_device . platform_data = pdata ;
2009-03-25 02:38:23 +03:00
dev_set_name ( & mcp - > attached_device , " mcp0 " ) ;
2012-01-21 02:51:07 +04:00
return device_add ( & mcp - > attached_device ) ;
2005-08-18 13:06:59 +04:00
}
2012-01-21 02:51:07 +04:00
EXPORT_SYMBOL ( mcp_host_add ) ;
2005-08-18 13:06:59 +04:00
2012-01-21 02:51:07 +04:00
void mcp_host_del ( struct mcp * mcp )
2005-08-18 13:06:59 +04:00
{
2012-01-21 02:51:07 +04:00
device_del ( & mcp - > attached_device ) ;
2005-08-18 13:06:59 +04:00
}
2012-01-21 02:51:07 +04:00
EXPORT_SYMBOL ( mcp_host_del ) ;
void mcp_host_free ( struct mcp * mcp )
{
put_device ( & mcp - > attached_device ) ;
}
EXPORT_SYMBOL ( mcp_host_free ) ;
2005-08-18 13:06:59 +04:00
int mcp_driver_register ( struct mcp_driver * mcpdrv )
{
mcpdrv - > drv . bus = & mcp_bus_type ;
return driver_register ( & mcpdrv - > drv ) ;
}
EXPORT_SYMBOL ( mcp_driver_register ) ;
void mcp_driver_unregister ( struct mcp_driver * mcpdrv )
{
driver_unregister ( & mcpdrv - > drv ) ;
}
EXPORT_SYMBOL ( mcp_driver_unregister ) ;
static int __init mcp_init ( void )
{
return bus_register ( & mcp_bus_type ) ;
}
static void __exit mcp_exit ( void )
{
bus_unregister ( & mcp_bus_type ) ;
}
module_init ( mcp_init ) ;
module_exit ( mcp_exit ) ;
MODULE_AUTHOR ( " Russell King <rmk@arm.linux.org.uk> " ) ;
MODULE_DESCRIPTION ( " Core multimedia communications port driver " ) ;
MODULE_LICENSE ( " GPL " ) ;