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 ) ;
}
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
}
2010-05-11 13:14:18 +04:00
static int soc_camera_platform_fill_fmt ( struct v4l2_subdev * sd ,
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 ;
2010-05-11 13:14:18 +04:00
mf - > field = p - > format . field ;
2009-12-11 17:46:49 +03:00
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
}
2010-05-11 13:14:18 +04:00
static int soc_camera_platform_g_crop ( struct v4l2_subdev * sd ,
struct v4l2_crop * a )
{
struct soc_camera_platform_info * p = v4l2_get_subdevdata ( sd ) ;
a - > c . left = 0 ;
a - > c . top = 0 ;
a - > c . width = p - > format . width ;
a - > c . height = p - > format . height ;
a - > type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
return 0 ;
}
static int soc_camera_platform_cropcap ( struct v4l2_subdev * sd ,
struct v4l2_cropcap * a )
{
struct soc_camera_platform_info * p = v4l2_get_subdevdata ( sd ) ;
a - > bounds . left = 0 ;
a - > bounds . top = 0 ;
a - > bounds . width = p - > format . width ;
a - > bounds . height = p - > format . height ;
a - > defrect = a - > bounds ;
a - > type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
a - > pixelaspect . numerator = 1 ;
a - > pixelaspect . denominator = 1 ;
return 0 ;
}
2011-07-27 17:06:09 +04:00
static int soc_camera_platform_g_mbus_config ( struct v4l2_subdev * sd ,
struct v4l2_mbus_config * cfg )
{
struct soc_camera_platform_info * p = v4l2_get_subdevdata ( sd ) ;
cfg - > flags = p - > mbus_param ;
cfg - > type = p - > mbus_type ;
return 0 ;
}
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
. enum_mbus_fmt = soc_camera_platform_enum_fmt ,
2010-05-11 13:14:18 +04:00
. cropcap = soc_camera_platform_cropcap ,
. g_crop = soc_camera_platform_g_crop ,
. try_mbus_fmt = soc_camera_platform_fill_fmt ,
. g_mbus_fmt = soc_camera_platform_fill_fmt ,
. s_mbus_fmt = soc_camera_platform_fill_fmt ,
2011-07-27 17:06:09 +04:00
. g_mbus_config = soc_camera_platform_g_mbus_config ,
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 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 ;
2011-07-16 03:03:38 +04:00
if ( ! p - > icd ) {
2009-08-25 18:43:33 +04:00
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 ;
2011-07-16 03:03:38 +04:00
icd = p - > icd ;
2009-08-25 18:28:22 +04:00
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 */
2011-07-16 03:03:38 +04:00
icd - > control = & pdev - > dev ;
2009-08-25 18:43:33 +04:00
2011-07-16 03:03:38 +04:00
ici = to_soc_camera_host ( icd - > parent ) ;
2009-08-25 18:43:33 +04:00
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 :
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 ) ;
2011-09-05 20:50:27 +04:00
struct soc_camera_platform_info * p = v4l2_get_subdevdata ( & priv - > subdev ) ;
2008-07-17 06:02:08 +04:00
2011-09-05 20:50:27 +04:00
p - > icd - > control = NULL ;
2009-08-25 18:43:33 +04:00
v4l2_device_unregister_subdev ( & priv - > subdev ) ;
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 ,
} ;
2012-01-10 10:21:49 +04:00
module_platform_driver ( soc_camera_platform_driver ) ;
2008-07-17 06:02:08 +04:00
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 " ) ;