diff options
Diffstat (limited to 'drivers/media/usb/em28xx/em28xx-camera.c')
| -rw-r--r-- | drivers/media/usb/em28xx/em28xx-camera.c | 84 | 
1 files changed, 54 insertions, 30 deletions
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index 73cc50afa5e..12d4c0326e3 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -22,6 +22,7 @@  #include <linux/i2c.h>  #include <media/soc_camera.h>  #include <media/mt9v011.h> +#include <media/v4l2-clk.h>  #include <media/v4l2-common.h>  #include "em28xx.h" @@ -47,6 +48,7 @@ static struct soc_camera_link camlink = {  	.bus_id = 0,  	.flags = 0,  	.module_name = "em28xx", +	.unbalanced_power = true,  }; @@ -118,7 +120,7 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev)  		reg = 0x00;  		ret = i2c_master_send(&client, ®, 1);  		if (ret < 0) { -			if (ret != -ENODEV) +			if (ret != -ENXIO)  				em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",  					      client.addr << 1, ret);  			continue; @@ -216,7 +218,7 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev)  		reg = 0x1c;  		ret = i2c_smbus_read_byte_data(&client, reg);  		if (ret < 0) { -			if (ret != -ENODEV) +			if (ret != -ENXIO)  				em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n",  					      client.addr << 1, ret);  			continue; @@ -325,18 +327,30 @@ int em28xx_detect_sensor(struct em28xx *dev)  int em28xx_init_camera(struct em28xx *dev)  { +	char clk_name[V4L2_SUBDEV_NAME_SIZE]; +	struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus]; +	struct i2c_adapter *adap = &dev->i2c_adap[dev->def_i2c_bus]; +	struct em28xx_v4l2 *v4l2 = dev->v4l2; +	int ret = 0; + +	v4l2_clk_name_i2c(clk_name, sizeof(clk_name), +			  i2c_adapter_id(adap), client->addr); +	v4l2->clk = v4l2_clk_register_fixed(clk_name, "mclk", -EINVAL); +	if (IS_ERR(v4l2->clk)) +		return PTR_ERR(v4l2->clk); +  	switch (dev->em28xx_sensor) {  	case EM28XX_MT9V011:  	{  		struct mt9v011_platform_data pdata;  		struct i2c_board_info mt9v011_info = {  			.type = "mt9v011", -			.addr = dev->i2c_client[dev->def_i2c_bus].addr, +			.addr = client->addr,  			.platform_data = &pdata,  		}; -		dev->sensor_xres = 640; -		dev->sensor_yres = 480; +		v4l2->sensor_xres = 640; +		v4l2->sensor_yres = 480;  		/*  		 * FIXME: mt9v011 uses I2S speed as xtal clk - at least with @@ -349,40 +363,41 @@ int em28xx_init_camera(struct em28xx *dev)  		 */  		dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ;  		em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); -		dev->sensor_xtal = 4300000; -		pdata.xtal = dev->sensor_xtal; +		v4l2->sensor_xtal = 4300000; +		pdata.xtal = v4l2->sensor_xtal;  		if (NULL == -		    v4l2_i2c_new_subdev_board(&dev->v4l2_dev, -					      &dev->i2c_adap[dev->def_i2c_bus], -					      &mt9v011_info, NULL)) -			return -ENODEV; +		    v4l2_i2c_new_subdev_board(&dev->v4l2->v4l2_dev, adap, +					      &mt9v011_info, NULL)) { +			ret = -ENODEV; +			break; +		}  		/* probably means GRGB 16 bit bayer */ -		dev->vinmode = 0x0d; -		dev->vinctl = 0x00; +		v4l2->vinmode = 0x0d; +		v4l2->vinctl = 0x00;  		break;  	}  	case EM28XX_MT9M001: -		dev->sensor_xres = 1280; -		dev->sensor_yres = 1024; +		v4l2->sensor_xres = 1280; +		v4l2->sensor_yres = 1024;  		em28xx_initialize_mt9m001(dev);  		/* probably means BGGR 16 bit bayer */ -		dev->vinmode = 0x0c; -		dev->vinctl = 0x00; +		v4l2->vinmode = 0x0c; +		v4l2->vinctl = 0x00;  		break;  	case EM28XX_MT9M111: -		dev->sensor_xres = 640; -		dev->sensor_yres = 512; +		v4l2->sensor_xres = 640; +		v4l2->sensor_yres = 512;  		dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ;  		em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);  		em28xx_initialize_mt9m111(dev); -		dev->vinmode = 0x0a; -		dev->vinctl = 0x00; +		v4l2->vinmode = 0x0a; +		v4l2->vinctl = 0x00;  		break;  	case EM28XX_OV2640: @@ -391,7 +406,7 @@ int em28xx_init_camera(struct em28xx *dev)  		struct i2c_board_info ov2640_info = {  			.type = "ov2640",  			.flags = I2C_CLIENT_SCCB, -			.addr = dev->i2c_client[dev->def_i2c_bus].addr, +			.addr = client->addr,  			.platform_data = &camlink,  		};  		struct v4l2_mbus_framefmt fmt; @@ -404,13 +419,16 @@ int em28xx_init_camera(struct em28xx *dev)  		 * - adjust bridge xclk  		 * - disable 16 bit (12 bit) output formats on high resolutions  		 */ -		dev->sensor_xres = 640; -		dev->sensor_yres = 480; +		v4l2->sensor_xres = 640; +		v4l2->sensor_yres = 480;  		subdev = -		     v4l2_i2c_new_subdev_board(&dev->v4l2_dev, -					       &dev->i2c_adap[dev->def_i2c_bus], +		     v4l2_i2c_new_subdev_board(&dev->v4l2->v4l2_dev, adap,  					       &ov2640_info, NULL); +		if (NULL == subdev) { +			ret = -ENODEV; +			break; +		}  		fmt.code = V4L2_MBUS_FMT_YUYV8_2X8;  		fmt.width = 640; @@ -420,15 +438,21 @@ int em28xx_init_camera(struct em28xx *dev)  		/* NOTE: for UXGA=1600x1200 switch to 12MHz */  		dev->board.xclk = EM28XX_XCLK_FREQUENCY_24MHZ;  		em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); -		dev->vinmode = 0x08; -		dev->vinctl = 0x00; +		v4l2->vinmode = 0x08; +		v4l2->vinctl = 0x00;  		break;  	}  	case EM28XX_NOSENSOR:  	default: -		return -EINVAL; +		ret = -EINVAL;  	} -	return 0; +	if (ret < 0) { +		v4l2_clk_unregister_fixed(v4l2->clk); +		v4l2->clk = NULL; +	} + +	return ret;  } +EXPORT_SYMBOL_GPL(em28xx_init_camera);  | 
