2008-07-17 06:02:08 +04:00
/*
* Generic Platform Camera Driver
*
* Copyright ( C ) 2008 Magnus Damm
* Based on mt9m001 driver ,
* Copyright ( C ) 2008 , Guennadi Liakhovetski < kernel @ pengutronix . de >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/delay.h>
# include <linux/platform_device.h>
# include <linux/videodev2.h>
2009-08-25 18:43:33 +04:00
# include <media/v4l2-subdev.h>
2008-07-17 06:02:08 +04:00
# include <media/soc_camera.h>
2008-10-17 02:49:27 +04:00
# include <media/soc_camera_platform.h>
2008-07-17 06:02:08 +04:00
struct soc_camera_platform_priv {
2009-08-25 18:43:33 +04:00
struct v4l2_subdev subdev ;
2008-07-17 06:02:08 +04:00
} ;
2009-08-25 18:46:54 +04:00
static struct soc_camera_platform_priv * get_priv ( struct platform_device * pdev )
2008-07-17 06:02:08 +04:00
{
2009-08-25 18:46:54 +04:00
struct v4l2_subdev * subdev = platform_get_drvdata ( pdev ) ;
return container_of ( subdev , struct soc_camera_platform_priv , subdev ) ;
}
static struct soc_camera_platform_info * get_info ( struct soc_camera_device * icd )
{
2009-08-25 18:53:23 +04:00
struct platform_device * pdev =
to_platform_device ( to_soc_camera_control ( icd ) ) ;
2009-08-25 18:28:22 +04:00
return pdev - > dev . platform_data ;
2008-07-17 06:02:08 +04:00
}
2009-08-25 18:43:33 +04:00
static int soc_camera_platform_s_stream ( struct v4l2_subdev * sd , int enable )
2008-07-17 06:02:08 +04:00
{
2009-08-25 18:43:33 +04:00
struct soc_camera_platform_info * p = v4l2_get_subdevdata ( sd ) ;
return p - > set_capture ( p , enable ) ;
2008-07-17 06:02:08 +04:00
}
static int soc_camera_platform_set_bus_param ( struct soc_camera_device * icd ,
unsigned long flags )
{
return 0 ;
}
static unsigned long
soc_camera_platform_query_bus_param ( struct soc_camera_device * icd )
{
2009-08-25 18:46:54 +04:00
struct soc_camera_platform_info * p = get_info ( icd ) ;
2008-07-17 06:02:08 +04:00
return p - > bus_param ;
}
2009-08-25 18:43:33 +04:00
static int soc_camera_platform_try_fmt ( struct v4l2_subdev * sd ,
2009-12-11 17:46:49 +03:00
struct v4l2_mbus_framefmt * mf )
2008-07-17 06:02:08 +04:00
{
2009-08-25 18:43:33 +04:00
struct soc_camera_platform_info * p = v4l2_get_subdevdata ( sd ) ;
2008-07-17 06:02:08 +04:00
2009-12-11 17:46:49 +03:00
mf - > width = p - > format . width ;
mf - > height = p - > format . height ;
mf - > code = p - > format . code ;
mf - > colorspace = p - > format . colorspace ;
2008-07-17 06:02:08 +04:00
return 0 ;
}
2009-12-11 17:46:49 +03:00
static struct v4l2_subdev_core_ops platform_subdev_core_ops ;
2010-05-09 00:55:00 +04:00
static int soc_camera_platform_enum_fmt ( struct v4l2_subdev * sd , unsigned int index ,
2009-12-11 17:46:49 +03:00
enum v4l2_mbus_pixelcode * code )
2008-07-17 06:02:08 +04:00
{
2009-12-11 17:46:49 +03:00
struct soc_camera_platform_info * p = v4l2_get_subdevdata ( sd ) ;
2008-07-17 06:02:08 +04:00
2009-12-11 17:46:49 +03:00
if ( index )
return - EINVAL ;
2008-07-17 06:02:08 +04:00
2009-12-11 17:46:49 +03:00
* code = p - > format . code ;
return 0 ;
2008-07-17 06:02:08 +04:00
}
2009-08-25 18:43:33 +04:00
static struct v4l2_subdev_video_ops platform_subdev_video_ops = {
. s_stream = soc_camera_platform_s_stream ,
2009-12-11 17:46:49 +03:00
. try_mbus_fmt = soc_camera_platform_try_fmt ,
. enum_mbus_fmt = soc_camera_platform_enum_fmt ,
2009-08-25 18:43:33 +04:00
} ;
static struct v4l2_subdev_ops platform_subdev_ops = {
. core = & platform_subdev_core_ops ,
. video = & platform_subdev_video_ops ,
} ;
2008-07-17 06:02:08 +04:00
static struct soc_camera_ops soc_camera_platform_ops = {
. set_bus_param = soc_camera_platform_set_bus_param ,
. query_bus_param = soc_camera_platform_query_bus_param ,
} ;
static int soc_camera_platform_probe ( struct platform_device * pdev )
{
2009-08-25 18:43:33 +04:00
struct soc_camera_host * ici ;
2008-07-17 06:02:08 +04:00
struct soc_camera_platform_priv * priv ;
2009-08-25 18:28:22 +04:00
struct soc_camera_platform_info * p = pdev - > dev . platform_data ;
2008-07-17 06:02:08 +04:00
struct soc_camera_device * icd ;
int ret ;
if ( ! p )
return - EINVAL ;
2009-08-25 18:43:33 +04:00
if ( ! p - > dev ) {
dev_err ( & pdev - > dev ,
" Platform has not set soc_camera_device pointer! \n " ) ;
return - EINVAL ;
}
2008-07-17 06:02:08 +04:00
priv = kzalloc ( sizeof ( * priv ) , GFP_KERNEL ) ;
if ( ! priv )
return - ENOMEM ;
2009-08-25 18:28:22 +04:00
icd = to_soc_camera_dev ( p - > dev ) ;
2009-08-25 18:46:54 +04:00
/* soc-camera convention: control's drvdata points to the subdev */
platform_set_drvdata ( pdev , & priv - > subdev ) ;
/* Set the control device reference */
2009-08-25 18:28:22 +04:00
dev_set_drvdata ( & icd - > dev , & pdev - > dev ) ;
2009-08-25 18:43:33 +04:00
2009-12-11 17:46:49 +03:00
icd - > ops = & soc_camera_platform_ops ;
2008-07-17 06:02:08 +04:00
2009-08-25 18:43:33 +04:00
ici = to_soc_camera_host ( icd - > dev . parent ) ;
v4l2_subdev_init ( & priv - > subdev , & platform_subdev_ops ) ;
v4l2_set_subdevdata ( & priv - > subdev , p ) ;
strncpy ( priv - > subdev . name , dev_name ( & pdev - > dev ) , V4L2_SUBDEV_NAME_SIZE ) ;
ret = v4l2_device_register_subdev ( & ici - > v4l2_dev , & priv - > subdev ) ;
if ( ret )
goto evdrs ;
2008-07-17 06:02:08 +04:00
return ret ;
2009-08-25 18:28:22 +04:00
2009-08-25 18:43:33 +04:00
evdrs :
icd - > ops = NULL ;
platform_set_drvdata ( pdev , NULL ) ;
2009-08-25 18:28:22 +04:00
kfree ( priv ) ;
2009-08-25 18:43:33 +04:00
return ret ;
2008-07-17 06:02:08 +04:00
}
static int soc_camera_platform_remove ( struct platform_device * pdev )
{
2009-08-25 18:46:54 +04:00
struct soc_camera_platform_priv * priv = get_priv ( pdev ) ;
2009-08-25 18:28:22 +04:00
struct soc_camera_platform_info * p = pdev - > dev . platform_data ;
struct soc_camera_device * icd = to_soc_camera_dev ( p - > dev ) ;
2008-07-17 06:02:08 +04:00
2009-08-25 18:43:33 +04:00
v4l2_device_unregister_subdev ( & priv - > subdev ) ;
2009-08-25 18:28:22 +04:00
icd - > ops = NULL ;
2009-08-25 18:43:33 +04:00
platform_set_drvdata ( pdev , NULL ) ;
2008-07-17 06:02:08 +04:00
kfree ( priv ) ;
return 0 ;
}
static struct platform_driver soc_camera_platform_driver = {
. driver = {
. name = " soc_camera_platform " ,
2009-08-25 18:43:33 +04:00
. owner = THIS_MODULE ,
2008-07-17 06:02:08 +04:00
} ,
. probe = soc_camera_platform_probe ,
. remove = soc_camera_platform_remove ,
} ;
static int __init soc_camera_platform_module_init ( void )
{
return platform_driver_register ( & soc_camera_platform_driver ) ;
}
static void __exit soc_camera_platform_module_exit ( void )
{
2008-08-02 02:48:51 +04:00
platform_driver_unregister ( & soc_camera_platform_driver ) ;
2008-07-17 06:02:08 +04:00
}
module_init ( soc_camera_platform_module_init ) ;
module_exit ( soc_camera_platform_module_exit ) ;
MODULE_DESCRIPTION ( " SoC Camera Platform driver " ) ;
MODULE_AUTHOR ( " Magnus Damm " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
2009-08-25 18:28:22 +04:00
MODULE_ALIAS ( " platform:soc_camera_platform " ) ;