diff options
33 files changed, 3750 insertions, 195 deletions
diff --git a/Documentation/DocBook/dvb/dvbproperty.xml b/Documentation/DocBook/dvb/dvbproperty.xml index 52d5e3c7cf6c..b5365f61d69b 100644 --- a/Documentation/DocBook/dvb/dvbproperty.xml +++ b/Documentation/DocBook/dvb/dvbproperty.xml | |||
| @@ -141,13 +141,15 @@ struct dtv_properties { | |||
| 141 | </row></tbody></tgroup></informaltable> | 141 | </row></tbody></tgroup></informaltable> |
| 142 | </section> | 142 | </section> |
| 143 | 143 | ||
| 144 | <section> | ||
| 145 | <title>Property types</title> | ||
| 144 | <para> | 146 | <para> |
| 145 | On <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>/<link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>, | 147 | On <link linkend="FE_GET_PROPERTY">FE_GET_PROPERTY</link>/<link linkend="FE_SET_PROPERTY">FE_SET_PROPERTY</link>, |
| 146 | the actual action is determined by the dtv_property cmd/data pairs. With one single ioctl, is possible to | 148 | the actual action is determined by the dtv_property cmd/data pairs. With one single ioctl, is possible to |
| 147 | get/set up to 64 properties. The actual meaning of each property is described on the next sections. | 149 | get/set up to 64 properties. The actual meaning of each property is described on the next sections. |
| 148 | </para> | 150 | </para> |
| 149 | 151 | ||
| 150 | <para>The Available frontend property types are:</para> | 152 | <para>The available frontend property types are:</para> |
| 151 | <programlisting> | 153 | <programlisting> |
| 152 | #define DTV_UNDEFINED 0 | 154 | #define DTV_UNDEFINED 0 |
| 153 | #define DTV_TUNE 1 | 155 | #define DTV_TUNE 1 |
| @@ -193,6 +195,7 @@ get/set up to 64 properties. The actual meaning of each property is described on | |||
| 193 | #define DTV_ISDBT_LAYER_ENABLED 41 | 195 | #define DTV_ISDBT_LAYER_ENABLED 41 |
| 194 | #define DTV_ISDBS_TS_ID 42 | 196 | #define DTV_ISDBS_TS_ID 42 |
| 195 | </programlisting> | 197 | </programlisting> |
| 198 | </section> | ||
| 196 | 199 | ||
| 197 | <section id="fe_property_common"> | 200 | <section id="fe_property_common"> |
| 198 | <title>Parameters that are common to all Digital TV standards</title> | 201 | <title>Parameters that are common to all Digital TV standards</title> |
diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl index c8abb23ef1e7..e5fe09430fd9 100644 --- a/Documentation/DocBook/media-entities.tmpl +++ b/Documentation/DocBook/media-entities.tmpl | |||
| @@ -293,6 +293,7 @@ | |||
| 293 | <!ENTITY sub-yuyv SYSTEM "v4l/pixfmt-yuyv.xml"> | 293 | <!ENTITY sub-yuyv SYSTEM "v4l/pixfmt-yuyv.xml"> |
| 294 | <!ENTITY sub-yvyu SYSTEM "v4l/pixfmt-yvyu.xml"> | 294 | <!ENTITY sub-yvyu SYSTEM "v4l/pixfmt-yvyu.xml"> |
| 295 | <!ENTITY sub-srggb10 SYSTEM "v4l/pixfmt-srggb10.xml"> | 295 | <!ENTITY sub-srggb10 SYSTEM "v4l/pixfmt-srggb10.xml"> |
| 296 | <!ENTITY sub-srggb12 SYSTEM "v4l/pixfmt-srggb12.xml"> | ||
| 296 | <!ENTITY sub-srggb8 SYSTEM "v4l/pixfmt-srggb8.xml"> | 297 | <!ENTITY sub-srggb8 SYSTEM "v4l/pixfmt-srggb8.xml"> |
| 297 | <!ENTITY sub-y10 SYSTEM "v4l/pixfmt-y10.xml"> | 298 | <!ENTITY sub-y10 SYSTEM "v4l/pixfmt-y10.xml"> |
| 298 | <!ENTITY sub-y12 SYSTEM "v4l/pixfmt-y12.xml"> | 299 | <!ENTITY sub-y12 SYSTEM "v4l/pixfmt-y12.xml"> |
| @@ -373,9 +374,9 @@ | |||
| 373 | <!ENTITY sub-media-indices SYSTEM "media-indices.tmpl"> | 374 | <!ENTITY sub-media-indices SYSTEM "media-indices.tmpl"> |
| 374 | 375 | ||
| 375 | <!ENTITY sub-media-controller SYSTEM "v4l/media-controller.xml"> | 376 | <!ENTITY sub-media-controller SYSTEM "v4l/media-controller.xml"> |
| 376 | <!ENTITY sub-media-open SYSTEM "v4l/media-func-open.xml"> | 377 | <!ENTITY sub-media-func-open SYSTEM "v4l/media-func-open.xml"> |
| 377 | <!ENTITY sub-media-close SYSTEM "v4l/media-func-close.xml"> | 378 | <!ENTITY sub-media-func-close SYSTEM "v4l/media-func-close.xml"> |
| 378 | <!ENTITY sub-media-ioctl SYSTEM "v4l/media-func-ioctl.xml"> | 379 | <!ENTITY sub-media-func-ioctl SYSTEM "v4l/media-func-ioctl.xml"> |
| 379 | <!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml"> | 380 | <!ENTITY sub-media-ioc-device-info SYSTEM "v4l/media-ioc-device-info.xml"> |
| 380 | <!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml"> | 381 | <!ENTITY sub-media-ioc-enum-entities SYSTEM "v4l/media-ioc-enum-entities.xml"> |
| 381 | <!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml"> | 382 | <!ENTITY sub-media-ioc-enum-links SYSTEM "v4l/media-ioc-enum-links.xml"> |
diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml index 2dc25e1d4089..873ac3a621f0 100644 --- a/Documentation/DocBook/v4l/media-controller.xml +++ b/Documentation/DocBook/v4l/media-controller.xml | |||
| @@ -78,9 +78,9 @@ | |||
| 78 | <appendix id="media-user-func"> | 78 | <appendix id="media-user-func"> |
| 79 | <title>Function Reference</title> | 79 | <title>Function Reference</title> |
| 80 | <!-- Keep this alphabetically sorted. --> | 80 | <!-- Keep this alphabetically sorted. --> |
| 81 | &sub-media-open; | 81 | &sub-media-func-open; |
| 82 | &sub-media-close; | 82 | &sub-media-func-close; |
| 83 | &sub-media-ioctl; | 83 | &sub-media-func-ioctl; |
| 84 | <!-- All ioctls go here. --> | 84 | <!-- All ioctls go here. --> |
| 85 | &sub-media-ioc-device-info; | 85 | &sub-media-ioc-device-info; |
| 86 | &sub-media-ioc-enum-entities; | 86 | &sub-media-ioc-enum-entities; |
diff --git a/Documentation/DocBook/v4l/pixfmt.xml b/Documentation/DocBook/v4l/pixfmt.xml index dbfe3b08435f..deb660207f94 100644 --- a/Documentation/DocBook/v4l/pixfmt.xml +++ b/Documentation/DocBook/v4l/pixfmt.xml | |||
| @@ -673,6 +673,7 @@ access the palette, this must be done with ioctls of the Linux framebuffer API.< | |||
| 673 | &sub-srggb8; | 673 | &sub-srggb8; |
| 674 | &sub-sbggr16; | 674 | &sub-sbggr16; |
| 675 | &sub-srggb10; | 675 | &sub-srggb10; |
| 676 | &sub-srggb12; | ||
| 676 | </section> | 677 | </section> |
| 677 | 678 | ||
| 678 | <section id="yuv-formats"> | 679 | <section id="yuv-formats"> |
diff --git a/Documentation/DocBook/v4l/subdev-formats.xml b/Documentation/DocBook/v4l/subdev-formats.xml index a26b10c07857..8d3409d2c632 100644 --- a/Documentation/DocBook/v4l/subdev-formats.xml +++ b/Documentation/DocBook/v4l/subdev-formats.xml | |||
| @@ -2531,13 +2531,13 @@ | |||
| 2531 | <constant>_JPEG</constant> prefix the format code is made of | 2531 | <constant>_JPEG</constant> prefix the format code is made of |
| 2532 | the following information. | 2532 | the following information. |
| 2533 | <itemizedlist> | 2533 | <itemizedlist> |
| 2534 | <listitem>The number of bus samples per entropy encoded byte.</listitem> | 2534 | <listitem><para>The number of bus samples per entropy encoded byte.</para></listitem> |
| 2535 | <listitem>The bus width.</listitem> | 2535 | <listitem><para>The bus width.</para></listitem> |
| 2536 | </itemizedlist> | 2536 | </itemizedlist> |
| 2537 | </para> | ||
| 2537 | 2538 | ||
| 2538 | <para>For instance, for a JPEG baseline process and an 8-bit bus width | 2539 | <para>For instance, for a JPEG baseline process and an 8-bit bus width |
| 2539 | the format will be named <constant>V4L2_MBUS_FMT_JPEG_1X8</constant>. | 2540 | the format will be named <constant>V4L2_MBUS_FMT_JPEG_1X8</constant>. |
| 2540 | </para> | ||
| 2541 | </para> | 2541 | </para> |
| 2542 | 2542 | ||
| 2543 | <para>The following table lists existing JPEG compressed formats.</para> | 2543 | <para>The following table lists existing JPEG compressed formats.</para> |
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c index 2d8b4044be36..b2b0c45f32a9 100644 --- a/drivers/media/dvb/dm1105/dm1105.c +++ b/drivers/media/dvb/dm1105/dm1105.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | */ | 20 | */ |
| 21 | 21 | ||
| 22 | #include <linux/i2c.h> | 22 | #include <linux/i2c.h> |
| 23 | #include <linux/i2c-algo-bit.h> | ||
| 23 | #include <linux/init.h> | 24 | #include <linux/init.h> |
| 24 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
| 25 | #include <linux/module.h> | 26 | #include <linux/module.h> |
| @@ -49,11 +50,12 @@ | |||
| 49 | 50 | ||
| 50 | #define UNSET (-1U) | 51 | #define UNSET (-1U) |
| 51 | 52 | ||
| 52 | #define DM1105_BOARD_NOAUTO UNSET | 53 | #define DM1105_BOARD_NOAUTO UNSET |
| 53 | #define DM1105_BOARD_UNKNOWN 0 | 54 | #define DM1105_BOARD_UNKNOWN 0 |
| 54 | #define DM1105_BOARD_DVBWORLD_2002 1 | 55 | #define DM1105_BOARD_DVBWORLD_2002 1 |
| 55 | #define DM1105_BOARD_DVBWORLD_2004 2 | 56 | #define DM1105_BOARD_DVBWORLD_2004 2 |
| 56 | #define DM1105_BOARD_AXESS_DM05 3 | 57 | #define DM1105_BOARD_AXESS_DM05 3 |
| 58 | #define DM1105_BOARD_UNBRANDED_I2C_ON_GPIO 4 | ||
| 57 | 59 | ||
| 58 | /* ----------------------------------------------- */ | 60 | /* ----------------------------------------------- */ |
| 59 | /* | 61 | /* |
| @@ -157,22 +159,38 @@ | |||
| 157 | #define DM1105_MAX 0x04 | 159 | #define DM1105_MAX 0x04 |
| 158 | 160 | ||
| 159 | #define DRIVER_NAME "dm1105" | 161 | #define DRIVER_NAME "dm1105" |
| 162 | #define DM1105_I2C_GPIO_NAME "dm1105-gpio" | ||
| 160 | 163 | ||
| 161 | #define DM1105_DMA_PACKETS 47 | 164 | #define DM1105_DMA_PACKETS 47 |
| 162 | #define DM1105_DMA_PACKET_LENGTH (128*4) | 165 | #define DM1105_DMA_PACKET_LENGTH (128*4) |
| 163 | #define DM1105_DMA_BYTES (128 * 4 * DM1105_DMA_PACKETS) | 166 | #define DM1105_DMA_BYTES (128 * 4 * DM1105_DMA_PACKETS) |
| 164 | 167 | ||
| 168 | /* */ | ||
| 169 | #define GPIO08 (1 << 8) | ||
| 170 | #define GPIO13 (1 << 13) | ||
| 171 | #define GPIO14 (1 << 14) | ||
| 172 | #define GPIO15 (1 << 15) | ||
| 173 | #define GPIO16 (1 << 16) | ||
| 174 | #define GPIO17 (1 << 17) | ||
| 175 | #define GPIO_ALL 0x03ffff | ||
| 176 | |||
| 165 | /* GPIO's for LNB power control */ | 177 | /* GPIO's for LNB power control */ |
| 166 | #define DM1105_LNB_MASK 0x00000000 | 178 | #define DM1105_LNB_MASK (GPIO_ALL & ~(GPIO14 | GPIO13)) |
| 167 | #define DM1105_LNB_OFF 0x00020000 | 179 | #define DM1105_LNB_OFF GPIO17 |
| 168 | #define DM1105_LNB_13V 0x00010100 | 180 | #define DM1105_LNB_13V (GPIO16 | GPIO08) |
| 169 | #define DM1105_LNB_18V 0x00000100 | 181 | #define DM1105_LNB_18V GPIO08 |
| 170 | 182 | ||
| 171 | /* GPIO's for LNB power control for Axess DM05 */ | 183 | /* GPIO's for LNB power control for Axess DM05 */ |
| 172 | #define DM05_LNB_MASK 0x00000000 | 184 | #define DM05_LNB_MASK (GPIO_ALL & ~(GPIO14 | GPIO13)) |
| 173 | #define DM05_LNB_OFF 0x00020000/* actually 13v */ | 185 | #define DM05_LNB_OFF GPIO17/* actually 13v */ |
| 174 | #define DM05_LNB_13V 0x00020000 | 186 | #define DM05_LNB_13V GPIO17 |
| 175 | #define DM05_LNB_18V 0x00030000 | 187 | #define DM05_LNB_18V (GPIO17 | GPIO16) |
| 188 | |||
| 189 | /* GPIO's for LNB power control for unbranded with I2C on GPIO */ | ||
| 190 | #define UNBR_LNB_MASK (GPIO17 | GPIO16) | ||
| 191 | #define UNBR_LNB_OFF 0 | ||
| 192 | #define UNBR_LNB_13V GPIO17 | ||
| 193 | #define UNBR_LNB_18V (GPIO17 | GPIO16) | ||
| 176 | 194 | ||
| 177 | static unsigned int card[] = {[0 ... 3] = UNSET }; | 195 | static unsigned int card[] = {[0 ... 3] = UNSET }; |
| 178 | module_param_array(card, int, NULL, 0444); | 196 | module_param_array(card, int, NULL, 0444); |
| @@ -187,7 +205,11 @@ static unsigned int dm1105_devcount; | |||
| 187 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | 205 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
| 188 | 206 | ||
| 189 | struct dm1105_board { | 207 | struct dm1105_board { |
| 190 | char *name; | 208 | char *name; |
| 209 | struct { | ||
| 210 | u32 mask, off, v13, v18; | ||
| 211 | } lnb; | ||
| 212 | u32 gpio_scl, gpio_sda; | ||
| 191 | }; | 213 | }; |
| 192 | 214 | ||
| 193 | struct dm1105_subid { | 215 | struct dm1105_subid { |
| @@ -199,15 +221,50 @@ struct dm1105_subid { | |||
| 199 | static const struct dm1105_board dm1105_boards[] = { | 221 | static const struct dm1105_board dm1105_boards[] = { |
| 200 | [DM1105_BOARD_UNKNOWN] = { | 222 | [DM1105_BOARD_UNKNOWN] = { |
| 201 | .name = "UNKNOWN/GENERIC", | 223 | .name = "UNKNOWN/GENERIC", |
| 224 | .lnb = { | ||
| 225 | .mask = DM1105_LNB_MASK, | ||
| 226 | .off = DM1105_LNB_OFF, | ||
| 227 | .v13 = DM1105_LNB_13V, | ||
| 228 | .v18 = DM1105_LNB_18V, | ||
| 229 | }, | ||
| 202 | }, | 230 | }, |
| 203 | [DM1105_BOARD_DVBWORLD_2002] = { | 231 | [DM1105_BOARD_DVBWORLD_2002] = { |
| 204 | .name = "DVBWorld PCI 2002", | 232 | .name = "DVBWorld PCI 2002", |
| 233 | .lnb = { | ||
| 234 | .mask = DM1105_LNB_MASK, | ||
| 235 | .off = DM1105_LNB_OFF, | ||
| 236 | .v13 = DM1105_LNB_13V, | ||
| 237 | .v18 = DM1105_LNB_18V, | ||
| 238 | }, | ||
| 205 | }, | 239 | }, |
| 206 | [DM1105_BOARD_DVBWORLD_2004] = { | 240 | [DM1105_BOARD_DVBWORLD_2004] = { |
| 207 | .name = "DVBWorld PCI 2004", | 241 | .name = "DVBWorld PCI 2004", |
| 242 | .lnb = { | ||
| 243 | .mask = DM1105_LNB_MASK, | ||
| 244 | .off = DM1105_LNB_OFF, | ||
| 245 | .v13 = DM1105_LNB_13V, | ||
| 246 | .v18 = DM1105_LNB_18V, | ||
| 247 | }, | ||
| 208 | }, | 248 | }, |
| 209 | [DM1105_BOARD_AXESS_DM05] = { | 249 | [DM1105_BOARD_AXESS_DM05] = { |
| 210 | .name = "Axess/EasyTv DM05", | 250 | .name = "Axess/EasyTv DM05", |
| 251 | .lnb = { | ||
| 252 | .mask = DM05_LNB_MASK, | ||
| 253 | .off = DM05_LNB_OFF, | ||
| 254 | .v13 = DM05_LNB_13V, | ||
| 255 | .v18 = DM05_LNB_18V, | ||
| 256 | }, | ||
| 257 | }, | ||
| 258 | [DM1105_BOARD_UNBRANDED_I2C_ON_GPIO] = { | ||
| 259 | .name = "Unbranded DM1105 with i2c on GPIOs", | ||
| 260 | .lnb = { | ||
| 261 | .mask = UNBR_LNB_MASK, | ||
| 262 | .off = UNBR_LNB_OFF, | ||
| 263 | .v13 = UNBR_LNB_13V, | ||
| 264 | .v18 = UNBR_LNB_18V, | ||
| 265 | }, | ||
| 266 | .gpio_scl = GPIO14, | ||
| 267 | .gpio_sda = GPIO13, | ||
| 211 | }, | 268 | }, |
| 212 | }; | 269 | }; |
| 213 | 270 | ||
| @@ -293,6 +350,8 @@ struct dm1105_dev { | |||
| 293 | 350 | ||
| 294 | /* i2c */ | 351 | /* i2c */ |
| 295 | struct i2c_adapter i2c_adap; | 352 | struct i2c_adapter i2c_adap; |
| 353 | struct i2c_adapter i2c_bb_adap; | ||
| 354 | struct i2c_algo_bit_data i2c_bit; | ||
| 296 | 355 | ||
| 297 | /* irq */ | 356 | /* irq */ |
| 298 | struct work_struct work; | 357 | struct work_struct work; |
| @@ -328,6 +387,103 @@ struct dm1105_dev { | |||
| 328 | #define dm_setl(reg, bit) dm_andorl((reg), (bit), (bit)) | 387 | #define dm_setl(reg, bit) dm_andorl((reg), (bit), (bit)) |
| 329 | #define dm_clearl(reg, bit) dm_andorl((reg), (bit), 0) | 388 | #define dm_clearl(reg, bit) dm_andorl((reg), (bit), 0) |
| 330 | 389 | ||
| 390 | /* The chip has 18 GPIOs. In HOST mode GPIO's used as 15 bit address lines, | ||
| 391 | so we can use only 3 GPIO's from GPIO15 to GPIO17. | ||
| 392 | Here I don't check whether HOST is enebled as it is not implemented yet. | ||
| 393 | */ | ||
| 394 | static void dm1105_gpio_set(struct dm1105_dev *dev, u32 mask) | ||
| 395 | { | ||
| 396 | if (mask & 0xfffc0000) | ||
| 397 | printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__); | ||
| 398 | |||
| 399 | if (mask & 0x0003ffff) | ||
| 400 | dm_setl(DM1105_GPIOVAL, mask & 0x0003ffff); | ||
| 401 | |||
| 402 | } | ||
| 403 | |||
| 404 | static void dm1105_gpio_clear(struct dm1105_dev *dev, u32 mask) | ||
| 405 | { | ||
| 406 | if (mask & 0xfffc0000) | ||
| 407 | printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__); | ||
| 408 | |||
| 409 | if (mask & 0x0003ffff) | ||
| 410 | dm_clearl(DM1105_GPIOVAL, mask & 0x0003ffff); | ||
| 411 | |||
| 412 | } | ||
| 413 | |||
| 414 | static void dm1105_gpio_andor(struct dm1105_dev *dev, u32 mask, u32 val) | ||
| 415 | { | ||
| 416 | if (mask & 0xfffc0000) | ||
| 417 | printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__); | ||
| 418 | |||
| 419 | if (mask & 0x0003ffff) | ||
| 420 | dm_andorl(DM1105_GPIOVAL, mask & 0x0003ffff, val); | ||
| 421 | |||
| 422 | } | ||
| 423 | |||
| 424 | static u32 dm1105_gpio_get(struct dm1105_dev *dev, u32 mask) | ||
| 425 | { | ||
| 426 | if (mask & 0xfffc0000) | ||
| 427 | printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__); | ||
| 428 | |||
| 429 | if (mask & 0x0003ffff) | ||
| 430 | return dm_readl(DM1105_GPIOVAL) & mask & 0x0003ffff; | ||
| 431 | |||
| 432 | return 0; | ||
| 433 | } | ||
| 434 | |||
| 435 | static void dm1105_gpio_enable(struct dm1105_dev *dev, u32 mask, int asoutput) | ||
| 436 | { | ||
| 437 | if (mask & 0xfffc0000) | ||
| 438 | printk(KERN_ERR "%s: Only 18 GPIO's are allowed\n", __func__); | ||
| 439 | |||
| 440 | if ((mask & 0x0003ffff) && asoutput) | ||
| 441 | dm_clearl(DM1105_GPIOCTR, mask & 0x0003ffff); | ||
| 442 | else if ((mask & 0x0003ffff) && !asoutput) | ||
| 443 | dm_setl(DM1105_GPIOCTR, mask & 0x0003ffff); | ||
| 444 | |||
| 445 | } | ||
| 446 | |||
| 447 | static void dm1105_setline(struct dm1105_dev *dev, u32 line, int state) | ||
| 448 | { | ||
| 449 | if (state) | ||
| 450 | dm1105_gpio_enable(dev, line, 0); | ||
| 451 | else { | ||
| 452 | dm1105_gpio_enable(dev, line, 1); | ||
| 453 | dm1105_gpio_clear(dev, line); | ||
| 454 | } | ||
| 455 | } | ||
| 456 | |||
| 457 | static void dm1105_setsda(void *data, int state) | ||
| 458 | { | ||
| 459 | struct dm1105_dev *dev = data; | ||
| 460 | |||
| 461 | dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_sda, state); | ||
| 462 | } | ||
| 463 | |||
| 464 | static void dm1105_setscl(void *data, int state) | ||
| 465 | { | ||
| 466 | struct dm1105_dev *dev = data; | ||
| 467 | |||
| 468 | dm1105_setline(dev, dm1105_boards[dev->boardnr].gpio_scl, state); | ||
| 469 | } | ||
| 470 | |||
| 471 | static int dm1105_getsda(void *data) | ||
| 472 | { | ||
| 473 | struct dm1105_dev *dev = data; | ||
| 474 | |||
| 475 | return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_sda) | ||
| 476 | ? 1 : 0; | ||
| 477 | } | ||
| 478 | |||
| 479 | static int dm1105_getscl(void *data) | ||
| 480 | { | ||
| 481 | struct dm1105_dev *dev = data; | ||
| 482 | |||
| 483 | return dm1105_gpio_get(dev, dm1105_boards[dev->boardnr].gpio_scl) | ||
| 484 | ? 1 : 0; | ||
| 485 | } | ||
| 486 | |||
| 331 | static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap, | 487 | static int dm1105_i2c_xfer(struct i2c_adapter *i2c_adap, |
| 332 | struct i2c_msg *msgs, int num) | 488 | struct i2c_msg *msgs, int num) |
| 333 | { | 489 | { |
| @@ -436,31 +592,20 @@ static inline struct dm1105_dev *frontend_to_dm1105_dev(struct dvb_frontend *fe) | |||
| 436 | static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) | 592 | static int dm1105_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) |
| 437 | { | 593 | { |
| 438 | struct dm1105_dev *dev = frontend_to_dm1105_dev(fe); | 594 | struct dm1105_dev *dev = frontend_to_dm1105_dev(fe); |
| 439 | u32 lnb_mask, lnb_13v, lnb_18v, lnb_off; | ||
| 440 | 595 | ||
| 441 | switch (dev->boardnr) { | 596 | dm1105_gpio_enable(dev, dm1105_boards[dev->boardnr].lnb.mask, 1); |
| 442 | case DM1105_BOARD_AXESS_DM05: | ||
| 443 | lnb_mask = DM05_LNB_MASK; | ||
| 444 | lnb_off = DM05_LNB_OFF; | ||
| 445 | lnb_13v = DM05_LNB_13V; | ||
| 446 | lnb_18v = DM05_LNB_18V; | ||
| 447 | break; | ||
| 448 | case DM1105_BOARD_DVBWORLD_2002: | ||
| 449 | case DM1105_BOARD_DVBWORLD_2004: | ||
| 450 | default: | ||
| 451 | lnb_mask = DM1105_LNB_MASK; | ||
| 452 | lnb_off = DM1105_LNB_OFF; | ||
| 453 | lnb_13v = DM1105_LNB_13V; | ||
| 454 | lnb_18v = DM1105_LNB_18V; | ||
| 455 | } | ||
| 456 | |||
| 457 | dm_writel(DM1105_GPIOCTR, lnb_mask); | ||
| 458 | if (voltage == SEC_VOLTAGE_18) | 597 | if (voltage == SEC_VOLTAGE_18) |
| 459 | dm_writel(DM1105_GPIOVAL, lnb_18v); | 598 | dm1105_gpio_andor(dev, |
| 599 | dm1105_boards[dev->boardnr].lnb.mask, | ||
| 600 | dm1105_boards[dev->boardnr].lnb.v18); | ||
| 460 | else if (voltage == SEC_VOLTAGE_13) | 601 | else if (voltage == SEC_VOLTAGE_13) |
| 461 | dm_writel(DM1105_GPIOVAL, lnb_13v); | 602 | dm1105_gpio_andor(dev, |
| 603 | dm1105_boards[dev->boardnr].lnb.mask, | ||
| 604 | dm1105_boards[dev->boardnr].lnb.v13); | ||
| 462 | else | 605 | else |
| 463 | dm_writel(DM1105_GPIOVAL, lnb_off); | 606 | dm1105_gpio_andor(dev, |
| 607 | dm1105_boards[dev->boardnr].lnb.mask, | ||
| 608 | dm1105_boards[dev->boardnr].lnb.off); | ||
| 464 | 609 | ||
| 465 | return 0; | 610 | return 0; |
| 466 | } | 611 | } |
| @@ -708,6 +853,38 @@ static int __devinit frontend_init(struct dm1105_dev *dev) | |||
| 708 | int ret; | 853 | int ret; |
| 709 | 854 | ||
| 710 | switch (dev->boardnr) { | 855 | switch (dev->boardnr) { |
| 856 | case DM1105_BOARD_UNBRANDED_I2C_ON_GPIO: | ||
| 857 | dm1105_gpio_enable(dev, GPIO15, 1); | ||
| 858 | dm1105_gpio_clear(dev, GPIO15); | ||
| 859 | msleep(100); | ||
| 860 | dm1105_gpio_set(dev, GPIO15); | ||
| 861 | msleep(200); | ||
| 862 | dev->fe = dvb_attach( | ||
| 863 | stv0299_attach, &sharp_z0194a_config, | ||
| 864 | &dev->i2c_bb_adap); | ||
| 865 | if (dev->fe) { | ||
| 866 | dev->fe->ops.set_voltage = dm1105_set_voltage; | ||
| 867 | dvb_attach(dvb_pll_attach, dev->fe, 0x60, | ||
| 868 | &dev->i2c_bb_adap, DVB_PLL_OPERA1); | ||
| 869 | break; | ||
| 870 | } | ||
| 871 | |||
| 872 | dev->fe = dvb_attach( | ||
| 873 | stv0288_attach, &earda_config, | ||
| 874 | &dev->i2c_bb_adap); | ||
| 875 | if (dev->fe) { | ||
| 876 | dev->fe->ops.set_voltage = dm1105_set_voltage; | ||
| 877 | dvb_attach(stb6000_attach, dev->fe, 0x61, | ||
| 878 | &dev->i2c_bb_adap); | ||
| 879 | break; | ||
| 880 | } | ||
| 881 | |||
| 882 | dev->fe = dvb_attach( | ||
| 883 | si21xx_attach, &serit_config, | ||
| 884 | &dev->i2c_bb_adap); | ||
| 885 | if (dev->fe) | ||
| 886 | dev->fe->ops.set_voltage = dm1105_set_voltage; | ||
| 887 | break; | ||
| 711 | case DM1105_BOARD_DVBWORLD_2004: | 888 | case DM1105_BOARD_DVBWORLD_2004: |
| 712 | dev->fe = dvb_attach( | 889 | dev->fe = dvb_attach( |
| 713 | cx24116_attach, &serit_sp2633_config, | 890 | cx24116_attach, &serit_sp2633_config, |
| @@ -870,11 +1047,32 @@ static int __devinit dm1105_probe(struct pci_dev *pdev, | |||
| 870 | if (ret < 0) | 1047 | if (ret < 0) |
| 871 | goto err_dm1105_hw_exit; | 1048 | goto err_dm1105_hw_exit; |
| 872 | 1049 | ||
| 1050 | i2c_set_adapdata(&dev->i2c_bb_adap, dev); | ||
| 1051 | strcpy(dev->i2c_bb_adap.name, DM1105_I2C_GPIO_NAME); | ||
| 1052 | dev->i2c_bb_adap.owner = THIS_MODULE; | ||
| 1053 | dev->i2c_bb_adap.dev.parent = &pdev->dev; | ||
| 1054 | dev->i2c_bb_adap.algo_data = &dev->i2c_bit; | ||
| 1055 | dev->i2c_bit.data = dev; | ||
| 1056 | dev->i2c_bit.setsda = dm1105_setsda; | ||
| 1057 | dev->i2c_bit.setscl = dm1105_setscl; | ||
| 1058 | dev->i2c_bit.getsda = dm1105_getsda; | ||
| 1059 | dev->i2c_bit.getscl = dm1105_getscl; | ||
| 1060 | dev->i2c_bit.udelay = 10; | ||
| 1061 | dev->i2c_bit.timeout = 10; | ||
| 1062 | |||
| 1063 | /* Raise SCL and SDA */ | ||
| 1064 | dm1105_setsda(dev, 1); | ||
| 1065 | dm1105_setscl(dev, 1); | ||
| 1066 | |||
| 1067 | ret = i2c_bit_add_bus(&dev->i2c_bb_adap); | ||
| 1068 | if (ret < 0) | ||
| 1069 | goto err_i2c_del_adapter; | ||
| 1070 | |||
| 873 | /* dvb */ | 1071 | /* dvb */ |
| 874 | ret = dvb_register_adapter(&dev->dvb_adapter, DRIVER_NAME, | 1072 | ret = dvb_register_adapter(&dev->dvb_adapter, DRIVER_NAME, |
| 875 | THIS_MODULE, &pdev->dev, adapter_nr); | 1073 | THIS_MODULE, &pdev->dev, adapter_nr); |
| 876 | if (ret < 0) | 1074 | if (ret < 0) |
| 877 | goto err_i2c_del_adapter; | 1075 | goto err_i2c_del_adapters; |
| 878 | 1076 | ||
| 879 | dvb_adapter = &dev->dvb_adapter; | 1077 | dvb_adapter = &dev->dvb_adapter; |
| 880 | 1078 | ||
| @@ -952,6 +1150,8 @@ err_dvb_dmx_release: | |||
| 952 | dvb_dmx_release(dvbdemux); | 1150 | dvb_dmx_release(dvbdemux); |
| 953 | err_dvb_unregister_adapter: | 1151 | err_dvb_unregister_adapter: |
| 954 | dvb_unregister_adapter(dvb_adapter); | 1152 | dvb_unregister_adapter(dvb_adapter); |
| 1153 | err_i2c_del_adapters: | ||
| 1154 | i2c_del_adapter(&dev->i2c_bb_adap); | ||
| 955 | err_i2c_del_adapter: | 1155 | err_i2c_del_adapter: |
| 956 | i2c_del_adapter(&dev->i2c_adap); | 1156 | i2c_del_adapter(&dev->i2c_adap); |
| 957 | err_dm1105_hw_exit: | 1157 | err_dm1105_hw_exit: |
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c index f36f471deae2..37b146961ae2 100644 --- a/drivers/media/dvb/dvb-usb/lmedm04.c +++ b/drivers/media/dvb/dvb-usb/lmedm04.c | |||
| @@ -207,17 +207,6 @@ static int lme2510_stream_restart(struct dvb_usb_device *d) | |||
| 207 | rbuff, sizeof(rbuff)); | 207 | rbuff, sizeof(rbuff)); |
| 208 | return ret; | 208 | return ret; |
| 209 | } | 209 | } |
| 210 | static int lme2510_remote_keypress(struct dvb_usb_adapter *adap, u32 keypress) | ||
| 211 | { | ||
| 212 | struct dvb_usb_device *d = adap->dev; | ||
| 213 | |||
| 214 | deb_info(1, "INT Key Keypress =%04x", keypress); | ||
| 215 | |||
| 216 | if (keypress > 0) | ||
| 217 | rc_keydown(d->rc_dev, keypress, 0); | ||
| 218 | |||
| 219 | return 0; | ||
| 220 | } | ||
| 221 | 210 | ||
| 222 | static int lme2510_enable_pid(struct dvb_usb_device *d, u8 index, u16 pid_out) | 211 | static int lme2510_enable_pid(struct dvb_usb_device *d, u8 index, u16 pid_out) |
| 223 | { | 212 | { |
| @@ -256,6 +245,7 @@ static void lme2510_int_response(struct urb *lme_urb) | |||
| 256 | struct lme2510_state *st = adap->dev->priv; | 245 | struct lme2510_state *st = adap->dev->priv; |
| 257 | static u8 *ibuf, *rbuf; | 246 | static u8 *ibuf, *rbuf; |
| 258 | int i = 0, offset; | 247 | int i = 0, offset; |
| 248 | u32 key; | ||
| 259 | 249 | ||
| 260 | switch (lme_urb->status) { | 250 | switch (lme_urb->status) { |
| 261 | case 0: | 251 | case 0: |
| @@ -282,10 +272,16 @@ static void lme2510_int_response(struct urb *lme_urb) | |||
| 282 | 272 | ||
| 283 | switch (ibuf[0]) { | 273 | switch (ibuf[0]) { |
| 284 | case 0xaa: | 274 | case 0xaa: |
| 285 | debug_data_snipet(1, "INT Remote data snipet in", ibuf); | 275 | debug_data_snipet(1, "INT Remote data snipet", ibuf); |
| 286 | lme2510_remote_keypress(adap, | 276 | if ((ibuf[4] + ibuf[5]) == 0xff) { |
| 287 | (u32)(ibuf[2] << 24) + (ibuf[3] << 16) + | 277 | key = ibuf[5]; |
| 288 | (ibuf[4] << 8) + ibuf[5]); | 278 | key += (ibuf[3] > 0) |
| 279 | ? (ibuf[3] ^ 0xff) << 8 : 0; | ||
| 280 | key += (ibuf[2] ^ 0xff) << 16; | ||
| 281 | deb_info(1, "INT Key =%08x", key); | ||
| 282 | if (adap->dev->rc_dev != NULL) | ||
| 283 | rc_keydown(adap->dev->rc_dev, key, 0); | ||
| 284 | } | ||
| 289 | break; | 285 | break; |
| 290 | case 0xbb: | 286 | case 0xbb: |
| 291 | switch (st->tuner_config) { | 287 | switch (st->tuner_config) { |
| @@ -691,45 +687,6 @@ static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | |||
| 691 | return (ret < 0) ? -ENODEV : 0; | 687 | return (ret < 0) ? -ENODEV : 0; |
| 692 | } | 688 | } |
| 693 | 689 | ||
| 694 | static int lme2510_int_service(struct dvb_usb_adapter *adap) | ||
| 695 | { | ||
| 696 | struct dvb_usb_device *d = adap->dev; | ||
| 697 | struct rc_dev *rc; | ||
| 698 | int ret; | ||
| 699 | |||
| 700 | info("STA Configuring Remote"); | ||
| 701 | |||
| 702 | rc = rc_allocate_device(); | ||
| 703 | if (!rc) | ||
| 704 | return -ENOMEM; | ||
| 705 | |||
| 706 | usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys)); | ||
| 707 | strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys)); | ||
| 708 | |||
| 709 | rc->input_name = "LME2510 Remote Control"; | ||
| 710 | rc->input_phys = d->rc_phys; | ||
| 711 | rc->map_name = RC_MAP_LME2510; | ||
| 712 | rc->driver_name = "LME 2510"; | ||
| 713 | usb_to_input_id(d->udev, &rc->input_id); | ||
| 714 | |||
| 715 | ret = rc_register_device(rc); | ||
| 716 | if (ret) { | ||
| 717 | rc_free_device(rc); | ||
| 718 | return ret; | ||
| 719 | } | ||
| 720 | d->rc_dev = rc; | ||
| 721 | |||
| 722 | /* Start the Interrupt */ | ||
| 723 | ret = lme2510_int_read(adap); | ||
| 724 | if (ret < 0) { | ||
| 725 | rc_unregister_device(rc); | ||
| 726 | info("INT Unable to start Interrupt Service"); | ||
| 727 | return -ENODEV; | ||
| 728 | } | ||
| 729 | |||
| 730 | return 0; | ||
| 731 | } | ||
| 732 | |||
| 733 | static u8 check_sum(u8 *p, u8 len) | 690 | static u8 check_sum(u8 *p, u8 len) |
| 734 | { | 691 | { |
| 735 | u8 sum = 0; | 692 | u8 sum = 0; |
| @@ -831,7 +788,7 @@ static int lme_firmware_switch(struct usb_device *udev, int cold) | |||
| 831 | 788 | ||
| 832 | cold_fw = !cold; | 789 | cold_fw = !cold; |
| 833 | 790 | ||
| 834 | if (udev->descriptor.idProduct == 0x1122) { | 791 | if (le16_to_cpu(udev->descriptor.idProduct) == 0x1122) { |
| 835 | switch (dvb_usb_lme2510_firmware) { | 792 | switch (dvb_usb_lme2510_firmware) { |
| 836 | default: | 793 | default: |
| 837 | dvb_usb_lme2510_firmware = TUNER_S0194; | 794 | dvb_usb_lme2510_firmware = TUNER_S0194; |
| @@ -1053,8 +1010,11 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap) | |||
| 1053 | 1010 | ||
| 1054 | 1011 | ||
| 1055 | end: if (ret) { | 1012 | end: if (ret) { |
| 1056 | kfree(adap->fe); | 1013 | if (adap->fe) { |
| 1057 | adap->fe = NULL; | 1014 | dvb_frontend_detach(adap->fe); |
| 1015 | adap->fe = NULL; | ||
| 1016 | } | ||
| 1017 | adap->dev->props.rc.core.rc_codes = NULL; | ||
| 1058 | return -ENODEV; | 1018 | return -ENODEV; |
| 1059 | } | 1019 | } |
| 1060 | 1020 | ||
| @@ -1097,8 +1057,12 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap) | |||
| 1097 | return -ENODEV; | 1057 | return -ENODEV; |
| 1098 | } | 1058 | } |
| 1099 | 1059 | ||
| 1100 | /* Start the Interrupt & Remote*/ | 1060 | /* Start the Interrupt*/ |
| 1101 | ret = lme2510_int_service(adap); | 1061 | ret = lme2510_int_read(adap); |
| 1062 | if (ret < 0) { | ||
| 1063 | info("INT Unable to start Interrupt Service"); | ||
| 1064 | return -ENODEV; | ||
| 1065 | } | ||
| 1102 | 1066 | ||
| 1103 | return ret; | 1067 | return ret; |
| 1104 | } | 1068 | } |
| @@ -1204,6 +1168,12 @@ static struct dvb_usb_device_properties lme2510_properties = { | |||
| 1204 | } | 1168 | } |
| 1205 | } | 1169 | } |
| 1206 | }, | 1170 | }, |
| 1171 | .rc.core = { | ||
| 1172 | .protocol = RC_TYPE_NEC, | ||
| 1173 | .module_name = "LME2510 Remote Control", | ||
| 1174 | .allowed_protos = RC_TYPE_NEC, | ||
| 1175 | .rc_codes = RC_MAP_LME2510, | ||
| 1176 | }, | ||
| 1207 | .power_ctrl = lme2510_powerup, | 1177 | .power_ctrl = lme2510_powerup, |
| 1208 | .identify_state = lme2510_identify_state, | 1178 | .identify_state = lme2510_identify_state, |
| 1209 | .i2c_algo = &lme2510_i2c_algo, | 1179 | .i2c_algo = &lme2510_i2c_algo, |
| @@ -1246,6 +1216,12 @@ static struct dvb_usb_device_properties lme2510c_properties = { | |||
| 1246 | } | 1216 | } |
| 1247 | } | 1217 | } |
| 1248 | }, | 1218 | }, |
| 1219 | .rc.core = { | ||
| 1220 | .protocol = RC_TYPE_NEC, | ||
| 1221 | .module_name = "LME2510 Remote Control", | ||
| 1222 | .allowed_protos = RC_TYPE_NEC, | ||
| 1223 | .rc_codes = RC_MAP_LME2510, | ||
| 1224 | }, | ||
| 1249 | .power_ctrl = lme2510_powerup, | 1225 | .power_ctrl = lme2510_powerup, |
| 1250 | .identify_state = lme2510_identify_state, | 1226 | .identify_state = lme2510_identify_state, |
| 1251 | .i2c_algo = &lme2510_i2c_algo, | 1227 | .i2c_algo = &lme2510_i2c_algo, |
| @@ -1269,19 +1245,21 @@ static void *lme2510_exit_int(struct dvb_usb_device *d) | |||
| 1269 | adap->feedcount = 0; | 1245 | adap->feedcount = 0; |
| 1270 | } | 1246 | } |
| 1271 | 1247 | ||
| 1272 | if (st->lme_urb != NULL) { | 1248 | if (st->usb_buffer != NULL) { |
| 1273 | st->i2c_talk_onoff = 1; | 1249 | st->i2c_talk_onoff = 1; |
| 1274 | st->signal_lock = 0; | 1250 | st->signal_lock = 0; |
| 1275 | st->signal_level = 0; | 1251 | st->signal_level = 0; |
| 1276 | st->signal_sn = 0; | 1252 | st->signal_sn = 0; |
| 1277 | buffer = st->usb_buffer; | 1253 | buffer = st->usb_buffer; |
| 1254 | } | ||
| 1255 | |||
| 1256 | if (st->lme_urb != NULL) { | ||
| 1278 | usb_kill_urb(st->lme_urb); | 1257 | usb_kill_urb(st->lme_urb); |
| 1279 | usb_free_coherent(d->udev, 5000, st->buffer, | 1258 | usb_free_coherent(d->udev, 5000, st->buffer, |
| 1280 | st->lme_urb->transfer_dma); | 1259 | st->lme_urb->transfer_dma); |
| 1281 | info("Interrupt Service Stopped"); | 1260 | info("Interrupt Service Stopped"); |
| 1282 | rc_unregister_device(d->rc_dev); | ||
| 1283 | info("Remote Stopped"); | ||
| 1284 | } | 1261 | } |
| 1262 | |||
| 1285 | return buffer; | 1263 | return buffer; |
| 1286 | } | 1264 | } |
| 1287 | 1265 | ||
| @@ -1293,7 +1271,8 @@ static void lme2510_exit(struct usb_interface *intf) | |||
| 1293 | if (d != NULL) { | 1271 | if (d != NULL) { |
| 1294 | usb_buffer = lme2510_exit_int(d); | 1272 | usb_buffer = lme2510_exit_int(d); |
| 1295 | dvb_usb_device_exit(intf); | 1273 | dvb_usb_device_exit(intf); |
| 1296 | kfree(usb_buffer); | 1274 | if (usb_buffer != NULL) |
| 1275 | kfree(usb_buffer); | ||
| 1297 | } | 1276 | } |
| 1298 | } | 1277 | } |
| 1299 | 1278 | ||
| @@ -1327,5 +1306,5 @@ module_exit(lme2510_module_exit); | |||
| 1327 | 1306 | ||
| 1328 | MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>"); | 1307 | MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>"); |
| 1329 | MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); | 1308 | MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); |
| 1330 | MODULE_VERSION("1.86"); | 1309 | MODULE_VERSION("1.88"); |
| 1331 | MODULE_LICENSE("GPL"); | 1310 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/media/dvb/frontends/stb0899_algo.c b/drivers/media/dvb/frontends/stb0899_algo.c index 2da55ec20392..d70eee00f33a 100644 --- a/drivers/media/dvb/frontends/stb0899_algo.c +++ b/drivers/media/dvb/frontends/stb0899_algo.c | |||
| @@ -23,7 +23,7 @@ | |||
| 23 | #include "stb0899_priv.h" | 23 | #include "stb0899_priv.h" |
| 24 | #include "stb0899_reg.h" | 24 | #include "stb0899_reg.h" |
| 25 | 25 | ||
| 26 | inline u32 stb0899_do_div(u64 n, u32 d) | 26 | static inline u32 stb0899_do_div(u64 n, u32 d) |
| 27 | { | 27 | { |
| 28 | /* wrap do_div() for ease of use */ | 28 | /* wrap do_div() for ease of use */ |
| 29 | 29 | ||
diff --git a/drivers/media/dvb/frontends/tda8261.c b/drivers/media/dvb/frontends/tda8261.c index 1742056a34e8..53c7d8f1df28 100644 --- a/drivers/media/dvb/frontends/tda8261.c +++ b/drivers/media/dvb/frontends/tda8261.c | |||
| @@ -224,7 +224,6 @@ exit: | |||
| 224 | } | 224 | } |
| 225 | 225 | ||
| 226 | EXPORT_SYMBOL(tda8261_attach); | 226 | EXPORT_SYMBOL(tda8261_attach); |
| 227 | MODULE_PARM_DESC(verbose, "Set verbosity level"); | ||
| 228 | 227 | ||
| 229 | MODULE_AUTHOR("Manu Abraham"); | 228 | MODULE_AUTHOR("Manu Abraham"); |
| 230 | MODULE_DESCRIPTION("TDA8261 8PSK/QPSK Tuner"); | 229 | MODULE_DESCRIPTION("TDA8261 8PSK/QPSK Tuner"); |
diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index 46cacf845049..459f7272d326 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c | |||
| @@ -1382,7 +1382,7 @@ static int wl1273_fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | |||
| 1382 | 1382 | ||
| 1383 | switch (ctrl->id) { | 1383 | switch (ctrl->id) { |
| 1384 | case V4L2_CID_TUNE_ANTENNA_CAPACITOR: | 1384 | case V4L2_CID_TUNE_ANTENNA_CAPACITOR: |
| 1385 | ctrl->val = wl1273_fm_get_tx_ctune(radio); | 1385 | ctrl->cur.val = wl1273_fm_get_tx_ctune(radio); |
| 1386 | break; | 1386 | break; |
| 1387 | 1387 | ||
| 1388 | default: | 1388 | default: |
diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c index d50e5ac75ab6..87010724f914 100644 --- a/drivers/media/radio/wl128x/fmdrv_v4l2.c +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c | |||
| @@ -191,7 +191,7 @@ static int fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | |||
| 191 | 191 | ||
| 192 | switch (ctrl->id) { | 192 | switch (ctrl->id) { |
| 193 | case V4L2_CID_TUNE_ANTENNA_CAPACITOR: | 193 | case V4L2_CID_TUNE_ANTENNA_CAPACITOR: |
| 194 | ctrl->val = fm_tx_get_tune_cap_val(fmdev); | 194 | ctrl->cur.val = fm_tx_get_tune_cap_val(fmdev); |
| 195 | break; | 195 | break; |
| 196 | default: | 196 | default: |
| 197 | fmwarn("%s: Unknown IOCTL: %d\n", __func__, ctrl->id); | 197 | fmwarn("%s: Unknown IOCTL: %d\n", __func__, ctrl->id); |
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 154c337f00fd..7d4bbc226d06 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig | |||
| @@ -148,6 +148,18 @@ config IR_ITE_CIR | |||
| 148 | To compile this driver as a module, choose M here: the | 148 | To compile this driver as a module, choose M here: the |
| 149 | module will be called ite-cir. | 149 | module will be called ite-cir. |
| 150 | 150 | ||
| 151 | config IR_FINTEK | ||
| 152 | tristate "Fintek Consumer Infrared Transceiver" | ||
| 153 | depends on PNP | ||
| 154 | depends on RC_CORE | ||
| 155 | ---help--- | ||
| 156 | Say Y here to enable support for integrated infrared receiver | ||
| 157 | /transciever made by Fintek. This chip is found on assorted | ||
| 158 | Jetway motherboards (and of course, possibly others). | ||
| 159 | |||
| 160 | To compile this driver as a module, choose M here: the | ||
| 161 | module will be called fintek-cir. | ||
| 162 | |||
| 151 | config IR_NUVOTON | 163 | config IR_NUVOTON |
| 152 | tristate "Nuvoton w836x7hg Consumer Infrared Transceiver" | 164 | tristate "Nuvoton w836x7hg Consumer Infrared Transceiver" |
| 153 | depends on PNP | 165 | depends on PNP |
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 1f90a219a162..52830e5f4eaa 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile | |||
| @@ -16,6 +16,7 @@ obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o | |||
| 16 | obj-$(CONFIG_IR_IMON) += imon.o | 16 | obj-$(CONFIG_IR_IMON) += imon.o |
| 17 | obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o | 17 | obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o |
| 18 | obj-$(CONFIG_IR_MCEUSB) += mceusb.o | 18 | obj-$(CONFIG_IR_MCEUSB) += mceusb.o |
| 19 | obj-$(CONFIG_IR_FINTEK) += fintek-cir.o | ||
| 19 | obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o | 20 | obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o |
| 20 | obj-$(CONFIG_IR_ENE) += ene_ir.o | 21 | obj-$(CONFIG_IR_ENE) += ene_ir.o |
| 21 | obj-$(CONFIG_IR_REDRAT3) += redrat3.o | 22 | obj-$(CONFIG_IR_REDRAT3) += redrat3.o |
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c new file mode 100644 index 000000000000..8fa539dde1b4 --- /dev/null +++ b/drivers/media/rc/fintek-cir.c | |||
| @@ -0,0 +1,684 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Feature Integration Technology Inc. (aka Fintek) LPC CIR | ||
| 3 | * | ||
| 4 | * Copyright (C) 2011 Jarod Wilson <jarod@redhat.com> | ||
| 5 | * | ||
| 6 | * Special thanks to Fintek for providing hardware and spec sheets. | ||
| 7 | * This driver is based upon the nuvoton, ite and ene drivers for | ||
| 8 | * similar hardware. | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or | ||
| 11 | * modify it under the terms of the GNU General Public License as | ||
| 12 | * published by the Free Software Foundation; either version 2 of the | ||
| 13 | * License, or (at your option) any later version. | ||
| 14 | * | ||
| 15 | * This program is distributed in the hope that it will be useful, but | ||
| 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 18 | * General Public License for more details. | ||
| 19 | * | ||
| 20 | * You should have received a copy of the GNU General Public License | ||
| 21 | * along with this program; if not, write to the Free Software | ||
| 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
| 23 | * USA | ||
| 24 | */ | ||
| 25 | |||
| 26 | #include <linux/kernel.h> | ||
| 27 | #include <linux/module.h> | ||
| 28 | #include <linux/pnp.h> | ||
| 29 | #include <linux/io.h> | ||
| 30 | #include <linux/interrupt.h> | ||
| 31 | #include <linux/sched.h> | ||
| 32 | #include <linux/slab.h> | ||
| 33 | #include <media/rc-core.h> | ||
| 34 | #include <linux/pci_ids.h> | ||
| 35 | |||
| 36 | #include "fintek-cir.h" | ||
| 37 | |||
| 38 | /* write val to config reg */ | ||
| 39 | static inline void fintek_cr_write(struct fintek_dev *fintek, u8 val, u8 reg) | ||
| 40 | { | ||
| 41 | fit_dbg("%s: reg 0x%02x, val 0x%02x (ip/dp: %02x/%02x)", | ||
| 42 | __func__, reg, val, fintek->cr_ip, fintek->cr_dp); | ||
| 43 | outb(reg, fintek->cr_ip); | ||
| 44 | outb(val, fintek->cr_dp); | ||
| 45 | } | ||
| 46 | |||
| 47 | /* read val from config reg */ | ||
| 48 | static inline u8 fintek_cr_read(struct fintek_dev *fintek, u8 reg) | ||
| 49 | { | ||
| 50 | u8 val; | ||
| 51 | |||
| 52 | outb(reg, fintek->cr_ip); | ||
| 53 | val = inb(fintek->cr_dp); | ||
| 54 | |||
| 55 | fit_dbg("%s: reg 0x%02x, val 0x%02x (ip/dp: %02x/%02x)", | ||
| 56 | __func__, reg, val, fintek->cr_ip, fintek->cr_dp); | ||
| 57 | return val; | ||
| 58 | } | ||
| 59 | |||
| 60 | /* update config register bit without changing other bits */ | ||
| 61 | static inline void fintek_set_reg_bit(struct fintek_dev *fintek, u8 val, u8 reg) | ||
| 62 | { | ||
| 63 | u8 tmp = fintek_cr_read(fintek, reg) | val; | ||
| 64 | fintek_cr_write(fintek, tmp, reg); | ||
| 65 | } | ||
| 66 | |||
| 67 | /* clear config register bit without changing other bits */ | ||
| 68 | static inline void fintek_clear_reg_bit(struct fintek_dev *fintek, u8 val, u8 reg) | ||
| 69 | { | ||
| 70 | u8 tmp = fintek_cr_read(fintek, reg) & ~val; | ||
| 71 | fintek_cr_write(fintek, tmp, reg); | ||
| 72 | } | ||
| 73 | |||
| 74 | /* enter config mode */ | ||
| 75 | static inline void fintek_config_mode_enable(struct fintek_dev *fintek) | ||
| 76 | { | ||
| 77 | /* Enabling Config Mode explicitly requires writing 2x */ | ||
| 78 | outb(CONFIG_REG_ENABLE, fintek->cr_ip); | ||
| 79 | outb(CONFIG_REG_ENABLE, fintek->cr_ip); | ||
| 80 | } | ||
| 81 | |||
| 82 | /* exit config mode */ | ||
| 83 | static inline void fintek_config_mode_disable(struct fintek_dev *fintek) | ||
| 84 | { | ||
| 85 | outb(CONFIG_REG_DISABLE, fintek->cr_ip); | ||
| 86 | } | ||
| 87 | |||
| 88 | /* | ||
| 89 | * When you want to address a specific logical device, write its logical | ||
| 90 | * device number to GCR_LOGICAL_DEV_NO | ||
| 91 | */ | ||
| 92 | static inline void fintek_select_logical_dev(struct fintek_dev *fintek, u8 ldev) | ||
| 93 | { | ||
| 94 | fintek_cr_write(fintek, ldev, GCR_LOGICAL_DEV_NO); | ||
| 95 | } | ||
| 96 | |||
| 97 | /* write val to cir config register */ | ||
| 98 | static inline void fintek_cir_reg_write(struct fintek_dev *fintek, u8 val, u8 offset) | ||
| 99 | { | ||
| 100 | outb(val, fintek->cir_addr + offset); | ||
| 101 | } | ||
| 102 | |||
| 103 | /* read val from cir config register */ | ||
| 104 | static u8 fintek_cir_reg_read(struct fintek_dev *fintek, u8 offset) | ||
| 105 | { | ||
| 106 | u8 val; | ||
| 107 | |||
| 108 | val = inb(fintek->cir_addr + offset); | ||
| 109 | |||
| 110 | return val; | ||
| 111 | } | ||
| 112 | |||
| 113 | #define pr_reg(text, ...) \ | ||
| 114 | printk(KERN_INFO KBUILD_MODNAME ": " text, ## __VA_ARGS__) | ||
| 115 | |||
| 116 | /* dump current cir register contents */ | ||
| 117 | static void cir_dump_regs(struct fintek_dev *fintek) | ||
| 118 | { | ||
| 119 | fintek_config_mode_enable(fintek); | ||
| 120 | fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); | ||
| 121 | |||
| 122 | pr_reg("%s: Dump CIR logical device registers:\n", FINTEK_DRIVER_NAME); | ||
| 123 | pr_reg(" * CR CIR BASE ADDR: 0x%x\n", | ||
| 124 | (fintek_cr_read(fintek, CIR_CR_BASE_ADDR_HI) << 8) | | ||
| 125 | fintek_cr_read(fintek, CIR_CR_BASE_ADDR_LO)); | ||
| 126 | pr_reg(" * CR CIR IRQ NUM: 0x%x\n", | ||
| 127 | fintek_cr_read(fintek, CIR_CR_IRQ_SEL)); | ||
| 128 | |||
| 129 | fintek_config_mode_disable(fintek); | ||
| 130 | |||
| 131 | pr_reg("%s: Dump CIR registers:\n", FINTEK_DRIVER_NAME); | ||
| 132 | pr_reg(" * STATUS: 0x%x\n", fintek_cir_reg_read(fintek, CIR_STATUS)); | ||
| 133 | pr_reg(" * CONTROL: 0x%x\n", fintek_cir_reg_read(fintek, CIR_CONTROL)); | ||
| 134 | pr_reg(" * RX_DATA: 0x%x\n", fintek_cir_reg_read(fintek, CIR_RX_DATA)); | ||
| 135 | pr_reg(" * TX_CONTROL: 0x%x\n", fintek_cir_reg_read(fintek, CIR_TX_CONTROL)); | ||
| 136 | pr_reg(" * TX_DATA: 0x%x\n", fintek_cir_reg_read(fintek, CIR_TX_DATA)); | ||
| 137 | } | ||
| 138 | |||
| 139 | /* detect hardware features */ | ||
| 140 | static int fintek_hw_detect(struct fintek_dev *fintek) | ||
| 141 | { | ||
| 142 | unsigned long flags; | ||
| 143 | u8 chip_major, chip_minor; | ||
| 144 | u8 vendor_major, vendor_minor; | ||
| 145 | u8 portsel, ir_class; | ||
| 146 | u16 vendor; | ||
| 147 | int ret = 0; | ||
| 148 | |||
| 149 | fintek_config_mode_enable(fintek); | ||
| 150 | |||
| 151 | /* Check if we're using config port 0x4e or 0x2e */ | ||
| 152 | portsel = fintek_cr_read(fintek, GCR_CONFIG_PORT_SEL); | ||
| 153 | if (portsel == 0xff) { | ||
| 154 | fit_pr(KERN_INFO, "first portsel read was bunk, trying alt"); | ||
| 155 | fintek_config_mode_disable(fintek); | ||
| 156 | fintek->cr_ip = CR_INDEX_PORT2; | ||
| 157 | fintek->cr_dp = CR_DATA_PORT2; | ||
| 158 | fintek_config_mode_enable(fintek); | ||
| 159 | portsel = fintek_cr_read(fintek, GCR_CONFIG_PORT_SEL); | ||
| 160 | } | ||
| 161 | fit_dbg("portsel reg: 0x%02x", portsel); | ||
| 162 | |||
| 163 | ir_class = fintek_cir_reg_read(fintek, CIR_CR_CLASS); | ||
| 164 | fit_dbg("ir_class reg: 0x%02x", ir_class); | ||
| 165 | |||
| 166 | switch (ir_class) { | ||
| 167 | case CLASS_RX_2TX: | ||
| 168 | case CLASS_RX_1TX: | ||
| 169 | fintek->hw_tx_capable = true; | ||
| 170 | break; | ||
| 171 | case CLASS_RX_ONLY: | ||
| 172 | default: | ||
| 173 | fintek->hw_tx_capable = false; | ||
| 174 | break; | ||
| 175 | } | ||
| 176 | |||
| 177 | chip_major = fintek_cr_read(fintek, GCR_CHIP_ID_HI); | ||
| 178 | chip_minor = fintek_cr_read(fintek, GCR_CHIP_ID_LO); | ||
| 179 | |||
| 180 | vendor_major = fintek_cr_read(fintek, GCR_VENDOR_ID_HI); | ||
| 181 | vendor_minor = fintek_cr_read(fintek, GCR_VENDOR_ID_LO); | ||
| 182 | vendor = vendor_major << 8 | vendor_minor; | ||
| 183 | |||
| 184 | if (vendor != VENDOR_ID_FINTEK) | ||
| 185 | fit_pr(KERN_WARNING, "Unknown vendor ID: 0x%04x", vendor); | ||
| 186 | else | ||
| 187 | fit_dbg("Read Fintek vendor ID from chip"); | ||
| 188 | |||
| 189 | fintek_config_mode_disable(fintek); | ||
| 190 | |||
| 191 | spin_lock_irqsave(&fintek->fintek_lock, flags); | ||
| 192 | fintek->chip_major = chip_major; | ||
| 193 | fintek->chip_minor = chip_minor; | ||
| 194 | fintek->chip_vendor = vendor; | ||
| 195 | spin_unlock_irqrestore(&fintek->fintek_lock, flags); | ||
| 196 | |||
| 197 | return ret; | ||
| 198 | } | ||
| 199 | |||
| 200 | static void fintek_cir_ldev_init(struct fintek_dev *fintek) | ||
| 201 | { | ||
| 202 | /* Select CIR logical device and enable */ | ||
| 203 | fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); | ||
| 204 | fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN); | ||
| 205 | |||
| 206 | /* Write allocated CIR address and IRQ information to hardware */ | ||
| 207 | fintek_cr_write(fintek, fintek->cir_addr >> 8, CIR_CR_BASE_ADDR_HI); | ||
| 208 | fintek_cr_write(fintek, fintek->cir_addr & 0xff, CIR_CR_BASE_ADDR_LO); | ||
| 209 | |||
| 210 | fintek_cr_write(fintek, fintek->cir_irq, CIR_CR_IRQ_SEL); | ||
| 211 | |||
| 212 | fit_dbg("CIR initialized, base io address: 0x%lx, irq: %d (len: %d)", | ||
| 213 | fintek->cir_addr, fintek->cir_irq, fintek->cir_port_len); | ||
| 214 | } | ||
| 215 | |||
| 216 | /* enable CIR interrupts */ | ||
| 217 | static void fintek_enable_cir_irq(struct fintek_dev *fintek) | ||
| 218 | { | ||
| 219 | fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_EN, CIR_STATUS); | ||
| 220 | } | ||
| 221 | |||
| 222 | static void fintek_cir_regs_init(struct fintek_dev *fintek) | ||
| 223 | { | ||
| 224 | /* clear any and all stray interrupts */ | ||
| 225 | fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS); | ||
| 226 | |||
| 227 | /* and finally, enable interrupts */ | ||
| 228 | fintek_enable_cir_irq(fintek); | ||
| 229 | } | ||
| 230 | |||
| 231 | static void fintek_enable_wake(struct fintek_dev *fintek) | ||
| 232 | { | ||
| 233 | fintek_config_mode_enable(fintek); | ||
| 234 | fintek_select_logical_dev(fintek, LOGICAL_DEV_ACPI); | ||
| 235 | |||
| 236 | /* Allow CIR PME's to wake system */ | ||
| 237 | fintek_set_reg_bit(fintek, ACPI_WAKE_EN_CIR_BIT, LDEV_ACPI_WAKE_EN_REG); | ||
| 238 | /* Enable CIR PME's */ | ||
| 239 | fintek_set_reg_bit(fintek, ACPI_PME_CIR_BIT, LDEV_ACPI_PME_EN_REG); | ||
| 240 | /* Clear CIR PME status register */ | ||
| 241 | fintek_set_reg_bit(fintek, ACPI_PME_CIR_BIT, LDEV_ACPI_PME_CLR_REG); | ||
| 242 | /* Save state */ | ||
| 243 | fintek_set_reg_bit(fintek, ACPI_STATE_CIR_BIT, LDEV_ACPI_STATE_REG); | ||
| 244 | |||
| 245 | fintek_config_mode_disable(fintek); | ||
| 246 | } | ||
| 247 | |||
| 248 | static int fintek_cmdsize(u8 cmd, u8 subcmd) | ||
| 249 | { | ||
| 250 | int datasize = 0; | ||
| 251 | |||
| 252 | switch (cmd) { | ||
| 253 | case BUF_COMMAND_NULL: | ||
| 254 | if (subcmd == BUF_HW_CMD_HEADER) | ||
| 255 | datasize = 1; | ||
| 256 | break; | ||
| 257 | case BUF_HW_CMD_HEADER: | ||
| 258 | if (subcmd == BUF_CMD_G_REVISION) | ||
| 259 | datasize = 2; | ||
| 260 | break; | ||
| 261 | case BUF_COMMAND_HEADER: | ||
| 262 | switch (subcmd) { | ||
| 263 | case BUF_CMD_S_CARRIER: | ||
| 264 | case BUF_CMD_S_TIMEOUT: | ||
| 265 | case BUF_RSP_PULSE_COUNT: | ||
| 266 | datasize = 2; | ||
| 267 | break; | ||
| 268 | case BUF_CMD_SIG_END: | ||
| 269 | case BUF_CMD_S_TXMASK: | ||
| 270 | case BUF_CMD_S_RXSENSOR: | ||
| 271 | datasize = 1; | ||
| 272 | break; | ||
| 273 | } | ||
| 274 | } | ||
| 275 | |||
| 276 | return datasize; | ||
| 277 | } | ||
| 278 | |||
| 279 | /* process ir data stored in driver buffer */ | ||
| 280 | static void fintek_process_rx_ir_data(struct fintek_dev *fintek) | ||
| 281 | { | ||
| 282 | DEFINE_IR_RAW_EVENT(rawir); | ||
| 283 | u8 sample; | ||
| 284 | int i; | ||
| 285 | |||
| 286 | for (i = 0; i < fintek->pkts; i++) { | ||
| 287 | sample = fintek->buf[i]; | ||
| 288 | switch (fintek->parser_state) { | ||
| 289 | case CMD_HEADER: | ||
| 290 | fintek->cmd = sample; | ||
| 291 | if ((fintek->cmd == BUF_COMMAND_HEADER) || | ||
| 292 | ((fintek->cmd & BUF_COMMAND_MASK) != | ||
| 293 | BUF_PULSE_BIT)) { | ||
| 294 | fintek->parser_state = SUBCMD; | ||
| 295 | continue; | ||
| 296 | } | ||
| 297 | fintek->rem = (fintek->cmd & BUF_LEN_MASK); | ||
| 298 | fit_dbg("%s: rem: 0x%02x", __func__, fintek->rem); | ||
| 299 | if (fintek->rem) | ||
| 300 | fintek->parser_state = PARSE_IRDATA; | ||
| 301 | else | ||
| 302 | ir_raw_event_reset(fintek->rdev); | ||
| 303 | break; | ||
| 304 | case SUBCMD: | ||
| 305 | fintek->rem = fintek_cmdsize(fintek->cmd, sample); | ||
| 306 | fintek->parser_state = CMD_DATA; | ||
| 307 | break; | ||
| 308 | case CMD_DATA: | ||
| 309 | fintek->rem--; | ||
| 310 | break; | ||
| 311 | case PARSE_IRDATA: | ||
| 312 | fintek->rem--; | ||
| 313 | init_ir_raw_event(&rawir); | ||
| 314 | rawir.pulse = ((sample & BUF_PULSE_BIT) != 0); | ||
| 315 | rawir.duration = US_TO_NS((sample & BUF_SAMPLE_MASK) | ||
| 316 | * CIR_SAMPLE_PERIOD); | ||
| 317 | |||
| 318 | fit_dbg("Storing %s with duration %d", | ||
| 319 | rawir.pulse ? "pulse" : "space", | ||
| 320 | rawir.duration); | ||
| 321 | ir_raw_event_store_with_filter(fintek->rdev, &rawir); | ||
| 322 | break; | ||
| 323 | } | ||
| 324 | |||
| 325 | if ((fintek->parser_state != CMD_HEADER) && !fintek->rem) | ||
| 326 | fintek->parser_state = CMD_HEADER; | ||
| 327 | } | ||
| 328 | |||
| 329 | fintek->pkts = 0; | ||
| 330 | |||
| 331 | fit_dbg("Calling ir_raw_event_handle"); | ||
| 332 | ir_raw_event_handle(fintek->rdev); | ||
| 333 | } | ||
| 334 | |||
| 335 | /* copy data from hardware rx register into driver buffer */ | ||
| 336 | static void fintek_get_rx_ir_data(struct fintek_dev *fintek, u8 rx_irqs) | ||
| 337 | { | ||
| 338 | unsigned long flags; | ||
| 339 | u8 sample, status; | ||
| 340 | |||
| 341 | spin_lock_irqsave(&fintek->fintek_lock, flags); | ||
| 342 | |||
| 343 | /* | ||
| 344 | * We must read data from CIR_RX_DATA until the hardware IR buffer | ||
| 345 | * is empty and clears the RX_TIMEOUT and/or RX_RECEIVE flags in | ||
| 346 | * the CIR_STATUS register | ||
| 347 | */ | ||
| 348 | do { | ||
| 349 | sample = fintek_cir_reg_read(fintek, CIR_RX_DATA); | ||
| 350 | fit_dbg("%s: sample: 0x%02x", __func__, sample); | ||
| 351 | |||
| 352 | fintek->buf[fintek->pkts] = sample; | ||
| 353 | fintek->pkts++; | ||
| 354 | |||
| 355 | status = fintek_cir_reg_read(fintek, CIR_STATUS); | ||
| 356 | if (!(status & CIR_STATUS_IRQ_EN)) | ||
| 357 | break; | ||
| 358 | } while (status & rx_irqs); | ||
| 359 | |||
| 360 | fintek_process_rx_ir_data(fintek); | ||
| 361 | |||
| 362 | spin_unlock_irqrestore(&fintek->fintek_lock, flags); | ||
| 363 | } | ||
| 364 | |||
| 365 | static void fintek_cir_log_irqs(u8 status) | ||
| 366 | { | ||
| 367 | fit_pr(KERN_INFO, "IRQ 0x%02x:%s%s%s%s%s", status, | ||
| 368 | status & CIR_STATUS_IRQ_EN ? " IRQEN" : "", | ||
| 369 | status & CIR_STATUS_TX_FINISH ? " TXF" : "", | ||
| 370 | status & CIR_STATUS_TX_UNDERRUN ? " TXU" : "", | ||
| 371 | status & CIR_STATUS_RX_TIMEOUT ? " RXTO" : "", | ||
| 372 | status & CIR_STATUS_RX_RECEIVE ? " RXOK" : ""); | ||
| 373 | } | ||
| 374 | |||
| 375 | /* interrupt service routine for incoming and outgoing CIR data */ | ||
| 376 | static irqreturn_t fintek_cir_isr(int irq, void *data) | ||
| 377 | { | ||
| 378 | struct fintek_dev *fintek = data; | ||
| 379 | u8 status, rx_irqs; | ||
| 380 | |||
| 381 | fit_dbg_verbose("%s firing", __func__); | ||
| 382 | |||
| 383 | fintek_config_mode_enable(fintek); | ||
| 384 | fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); | ||
| 385 | fintek_config_mode_disable(fintek); | ||
| 386 | |||
| 387 | /* | ||
| 388 | * Get IR Status register contents. Write 1 to ack/clear | ||
| 389 | * | ||
| 390 | * bit: reg name - description | ||
| 391 | * 3: TX_FINISH - TX is finished | ||
| 392 | * 2: TX_UNDERRUN - TX underrun | ||
| 393 | * 1: RX_TIMEOUT - RX data timeout | ||
| 394 | * 0: RX_RECEIVE - RX data received | ||
| 395 | */ | ||
| 396 | status = fintek_cir_reg_read(fintek, CIR_STATUS); | ||
| 397 | if (!(status & CIR_STATUS_IRQ_MASK) || status == 0xff) { | ||
| 398 | fit_dbg_verbose("%s exiting, IRSTS 0x%02x", __func__, status); | ||
| 399 | fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS); | ||
| 400 | return IRQ_RETVAL(IRQ_NONE); | ||
| 401 | } | ||
| 402 | |||
| 403 | if (debug) | ||
| 404 | fintek_cir_log_irqs(status); | ||
| 405 | |||
| 406 | rx_irqs = status & (CIR_STATUS_RX_RECEIVE | CIR_STATUS_RX_TIMEOUT); | ||
| 407 | if (rx_irqs) | ||
| 408 | fintek_get_rx_ir_data(fintek, rx_irqs); | ||
| 409 | |||
| 410 | /* ack/clear all irq flags we've got */ | ||
| 411 | fintek_cir_reg_write(fintek, status, CIR_STATUS); | ||
| 412 | |||
| 413 | fit_dbg_verbose("%s done", __func__); | ||
| 414 | return IRQ_RETVAL(IRQ_HANDLED); | ||
| 415 | } | ||
| 416 | |||
| 417 | static void fintek_enable_cir(struct fintek_dev *fintek) | ||
| 418 | { | ||
| 419 | /* set IRQ enabled */ | ||
| 420 | fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_EN, CIR_STATUS); | ||
| 421 | |||
| 422 | fintek_config_mode_enable(fintek); | ||
| 423 | |||
| 424 | /* enable the CIR logical device */ | ||
| 425 | fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); | ||
| 426 | fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN); | ||
| 427 | |||
| 428 | fintek_config_mode_disable(fintek); | ||
| 429 | |||
| 430 | /* clear all pending interrupts */ | ||
| 431 | fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS); | ||
| 432 | |||
| 433 | /* enable interrupts */ | ||
| 434 | fintek_enable_cir_irq(fintek); | ||
| 435 | } | ||
| 436 | |||
| 437 | static void fintek_disable_cir(struct fintek_dev *fintek) | ||
| 438 | { | ||
| 439 | fintek_config_mode_enable(fintek); | ||
| 440 | |||
| 441 | /* disable the CIR logical device */ | ||
| 442 | fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); | ||
| 443 | fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN); | ||
| 444 | |||
| 445 | fintek_config_mode_disable(fintek); | ||
| 446 | } | ||
| 447 | |||
| 448 | static int fintek_open(struct rc_dev *dev) | ||
| 449 | { | ||
| 450 | struct fintek_dev *fintek = dev->priv; | ||
| 451 | unsigned long flags; | ||
| 452 | |||
| 453 | spin_lock_irqsave(&fintek->fintek_lock, flags); | ||
| 454 | fintek_enable_cir(fintek); | ||
| 455 | spin_unlock_irqrestore(&fintek->fintek_lock, flags); | ||
| 456 | |||
| 457 | return 0; | ||
| 458 | } | ||
| 459 | |||
| 460 | static void fintek_close(struct rc_dev *dev) | ||
| 461 | { | ||
| 462 | struct fintek_dev *fintek = dev->priv; | ||
| 463 | unsigned long flags; | ||
| 464 | |||
| 465 | spin_lock_irqsave(&fintek->fintek_lock, flags); | ||
| 466 | fintek_disable_cir(fintek); | ||
| 467 | spin_unlock_irqrestore(&fintek->fintek_lock, flags); | ||
| 468 | } | ||
| 469 | |||
| 470 | /* Allocate memory, probe hardware, and initialize everything */ | ||
| 471 | static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) | ||
| 472 | { | ||
| 473 | struct fintek_dev *fintek; | ||
| 474 | struct rc_dev *rdev; | ||
| 475 | int ret = -ENOMEM; | ||
| 476 | |||
| 477 | fintek = kzalloc(sizeof(struct fintek_dev), GFP_KERNEL); | ||
| 478 | if (!fintek) | ||
| 479 | return ret; | ||
| 480 | |||
| 481 | /* input device for IR remote (and tx) */ | ||
| 482 | rdev = rc_allocate_device(); | ||
| 483 | if (!rdev) | ||
| 484 | goto failure; | ||
| 485 | |||
| 486 | ret = -ENODEV; | ||
| 487 | /* validate pnp resources */ | ||
| 488 | if (!pnp_port_valid(pdev, 0)) { | ||
| 489 | dev_err(&pdev->dev, "IR PNP Port not valid!\n"); | ||
| 490 | goto failure; | ||
| 491 | } | ||
| 492 | |||
| 493 | if (!pnp_irq_valid(pdev, 0)) { | ||
| 494 | dev_err(&pdev->dev, "IR PNP IRQ not valid!\n"); | ||
| 495 | goto failure; | ||
| 496 | } | ||
| 497 | |||
| 498 | fintek->cir_addr = pnp_port_start(pdev, 0); | ||
| 499 | fintek->cir_irq = pnp_irq(pdev, 0); | ||
| 500 | fintek->cir_port_len = pnp_port_len(pdev, 0); | ||
| 501 | |||
| 502 | fintek->cr_ip = CR_INDEX_PORT; | ||
| 503 | fintek->cr_dp = CR_DATA_PORT; | ||
| 504 | |||
| 505 | spin_lock_init(&fintek->fintek_lock); | ||
| 506 | |||
| 507 | ret = -EBUSY; | ||
| 508 | /* now claim resources */ | ||
| 509 | if (!request_region(fintek->cir_addr, | ||
| 510 | fintek->cir_port_len, FINTEK_DRIVER_NAME)) | ||
| 511 | goto failure; | ||
| 512 | |||
| 513 | if (request_irq(fintek->cir_irq, fintek_cir_isr, IRQF_SHARED, | ||
| 514 | FINTEK_DRIVER_NAME, (void *)fintek)) | ||
| 515 | goto failure; | ||
| 516 | |||
| 517 | pnp_set_drvdata(pdev, fintek); | ||
| 518 | fintek->pdev = pdev; | ||
| 519 | |||
| 520 | ret = fintek_hw_detect(fintek); | ||
| 521 | if (ret) | ||
| 522 | goto failure; | ||
| 523 | |||
| 524 | /* Initialize CIR & CIR Wake Logical Devices */ | ||
| 525 | fintek_config_mode_enable(fintek); | ||
| 526 | fintek_cir_ldev_init(fintek); | ||
| 527 | fintek_config_mode_disable(fintek); | ||
| 528 | |||
| 529 | /* Initialize CIR & CIR Wake Config Registers */ | ||
| 530 | fintek_cir_regs_init(fintek); | ||
| 531 | |||
| 532 | /* Set up the rc device */ | ||
| 533 | rdev->priv = fintek; | ||
| 534 | rdev->driver_type = RC_DRIVER_IR_RAW; | ||
| 535 | rdev->allowed_protos = RC_TYPE_ALL; | ||
| 536 | rdev->open = fintek_open; | ||
| 537 | rdev->close = fintek_close; | ||
| 538 | rdev->input_name = FINTEK_DESCRIPTION; | ||
| 539 | rdev->input_phys = "fintek/cir0"; | ||
| 540 | rdev->input_id.bustype = BUS_HOST; | ||
| 541 | rdev->input_id.vendor = VENDOR_ID_FINTEK; | ||
| 542 | rdev->input_id.product = fintek->chip_major; | ||
| 543 | rdev->input_id.version = fintek->chip_minor; | ||
| 544 | rdev->dev.parent = &pdev->dev; | ||
| 545 | rdev->driver_name = FINTEK_DRIVER_NAME; | ||
| 546 | rdev->map_name = RC_MAP_RC6_MCE; | ||
| 547 | rdev->timeout = US_TO_NS(1000); | ||
| 548 | /* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */ | ||
| 549 | rdev->rx_resolution = US_TO_NS(CIR_SAMPLE_PERIOD); | ||
| 550 | |||
| 551 | ret = rc_register_device(rdev); | ||
| 552 | if (ret) | ||
| 553 | goto failure; | ||
| 554 | |||
| 555 | device_init_wakeup(&pdev->dev, true); | ||
| 556 | fintek->rdev = rdev; | ||
| 557 | fit_pr(KERN_NOTICE, "driver has been successfully loaded\n"); | ||
| 558 | if (debug) | ||
| 559 | cir_dump_regs(fintek); | ||
| 560 | |||
| 561 | return 0; | ||
| 562 | |||
| 563 | failure: | ||
| 564 | if (fintek->cir_irq) | ||
| 565 | free_irq(fintek->cir_irq, fintek); | ||
| 566 | if (fintek->cir_addr) | ||
| 567 | release_region(fintek->cir_addr, fintek->cir_port_len); | ||
| 568 | |||
| 569 | rc_free_device(rdev); | ||
| 570 | kfree(fintek); | ||
| 571 | |||
| 572 | return ret; | ||
| 573 | } | ||
| 574 | |||
| 575 | static void __devexit fintek_remove(struct pnp_dev *pdev) | ||
| 576 | { | ||
| 577 | struct fintek_dev *fintek = pnp_get_drvdata(pdev); | ||
| 578 | unsigned long flags; | ||
| 579 | |||
| 580 | spin_lock_irqsave(&fintek->fintek_lock, flags); | ||
| 581 | /* disable CIR */ | ||
| 582 | fintek_disable_cir(fintek); | ||
| 583 | fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS); | ||
| 584 | /* enable CIR Wake (for IR power-on) */ | ||
| 585 | fintek_enable_wake(fintek); | ||
| 586 | spin_unlock_irqrestore(&fintek->fintek_lock, flags); | ||
| 587 | |||
| 588 | /* free resources */ | ||
| 589 | free_irq(fintek->cir_irq, fintek); | ||
| 590 | release_region(fintek->cir_addr, fintek->cir_port_len); | ||
| 591 | |||
| 592 | rc_unregister_device(fintek->rdev); | ||
| 593 | |||
| 594 | kfree(fintek); | ||
| 595 | } | ||
| 596 | |||
| 597 | static int fintek_suspend(struct pnp_dev *pdev, pm_message_t state) | ||
| 598 | { | ||
| 599 | struct fintek_dev *fintek = pnp_get_drvdata(pdev); | ||
| 600 | |||
| 601 | fit_dbg("%s called", __func__); | ||
| 602 | |||
| 603 | /* disable all CIR interrupts */ | ||
| 604 | fintek_cir_reg_write(fintek, CIR_STATUS_IRQ_MASK, CIR_STATUS); | ||
| 605 | |||
| 606 | fintek_config_mode_enable(fintek); | ||
| 607 | |||
| 608 | /* disable cir logical dev */ | ||
| 609 | fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); | ||
| 610 | fintek_cr_write(fintek, LOGICAL_DEV_DISABLE, CIR_CR_DEV_EN); | ||
| 611 | |||
| 612 | fintek_config_mode_disable(fintek); | ||
| 613 | |||
| 614 | /* make sure wake is enabled */ | ||
| 615 | fintek_enable_wake(fintek); | ||
| 616 | |||
| 617 | return 0; | ||
| 618 | } | ||
| 619 | |||
| 620 | static int fintek_resume(struct pnp_dev *pdev) | ||
| 621 | { | ||
| 622 | int ret = 0; | ||
| 623 | struct fintek_dev *fintek = pnp_get_drvdata(pdev); | ||
| 624 | |||
| 625 | fit_dbg("%s called", __func__); | ||
| 626 | |||
| 627 | /* open interrupt */ | ||
| 628 | fintek_enable_cir_irq(fintek); | ||
| 629 | |||
| 630 | /* Enable CIR logical device */ | ||
| 631 | fintek_config_mode_enable(fintek); | ||
| 632 | fintek_select_logical_dev(fintek, LOGICAL_DEV_CIR); | ||
| 633 | fintek_cr_write(fintek, LOGICAL_DEV_ENABLE, CIR_CR_DEV_EN); | ||
| 634 | |||
| 635 | fintek_config_mode_disable(fintek); | ||
| 636 | |||
| 637 | fintek_cir_regs_init(fintek); | ||
| 638 | |||
| 639 | return ret; | ||
| 640 | } | ||
| 641 | |||
| 642 | static void fintek_shutdown(struct pnp_dev *pdev) | ||
| 643 | { | ||
| 644 | struct fintek_dev *fintek = pnp_get_drvdata(pdev); | ||
| 645 | fintek_enable_wake(fintek); | ||
| 646 | } | ||
| 647 | |||
| 648 | static const struct pnp_device_id fintek_ids[] = { | ||
| 649 | { "FIT0002", 0 }, /* CIR */ | ||
| 650 | { "", 0 }, | ||
| 651 | }; | ||
| 652 | |||
| 653 | static struct pnp_driver fintek_driver = { | ||
| 654 | .name = FINTEK_DRIVER_NAME, | ||
| 655 | .id_table = fintek_ids, | ||
| 656 | .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, | ||
| 657 | .probe = fintek_probe, | ||
| 658 | .remove = __devexit_p(fintek_remove), | ||
| 659 | .suspend = fintek_suspend, | ||
| 660 | .resume = fintek_resume, | ||
| 661 | .shutdown = fintek_shutdown, | ||
| 662 | }; | ||
| 663 | |||
| 664 | int fintek_init(void) | ||
| 665 | { | ||
| 666 | return pnp_register_driver(&fintek_driver); | ||
| 667 | } | ||
| 668 | |||
| 669 | void fintek_exit(void) | ||
| 670 | { | ||
| 671 | pnp_unregister_driver(&fintek_driver); | ||
| 672 | } | ||
| 673 | |||
| 674 | module_param(debug, int, S_IRUGO | S_IWUSR); | ||
| 675 | MODULE_PARM_DESC(debug, "Enable debugging output"); | ||
| 676 | |||
| 677 | MODULE_DEVICE_TABLE(pnp, fintek_ids); | ||
| 678 | MODULE_DESCRIPTION(FINTEK_DESCRIPTION " driver"); | ||
| 679 | |||
| 680 | MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>"); | ||
| 681 | MODULE_LICENSE("GPL"); | ||
| 682 | |||
| 683 | module_init(fintek_init); | ||
| 684 | module_exit(fintek_exit); | ||
diff --git a/drivers/media/rc/fintek-cir.h b/drivers/media/rc/fintek-cir.h new file mode 100644 index 000000000000..1b10b2011f5e --- /dev/null +++ b/drivers/media/rc/fintek-cir.h | |||
| @@ -0,0 +1,243 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Feature Integration Technology Inc. (aka Fintek) LPC CIR | ||
| 3 | * | ||
| 4 | * Copyright (C) 2011 Jarod Wilson <jarod@redhat.com> | ||
| 5 | * | ||
| 6 | * Special thanks to Fintek for providing hardware and spec sheets. | ||
| 7 | * This driver is based upon the nuvoton, ite and ene drivers for | ||
| 8 | * similar hardware. | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or | ||
| 11 | * modify it under the terms of the GNU General Public License as | ||
| 12 | * published by the Free Software Foundation; either version 2 of the | ||
| 13 | * License, or (at your option) any later version. | ||
| 14 | * | ||
| 15 | * This program is distributed in the hope that it will be useful, but | ||
| 16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 18 | * General Public License for more details. | ||
| 19 | * | ||
| 20 | * You should have received a copy of the GNU General Public License | ||
| 21 | * along with this program; if not, write to the Free Software | ||
| 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
| 23 | * USA | ||
| 24 | */ | ||
| 25 | |||
| 26 | #include <linux/spinlock.h> | ||
| 27 | #include <linux/ioctl.h> | ||
| 28 | |||
| 29 | /* platform driver name to register */ | ||
| 30 | #define FINTEK_DRIVER_NAME "fintek-cir" | ||
| 31 | #define FINTEK_DESCRIPTION "Fintek LPC SuperIO Consumer IR Transceiver" | ||
| 32 | #define VENDOR_ID_FINTEK 0x1934 | ||
| 33 | |||
| 34 | |||
| 35 | /* debugging module parameter */ | ||
| 36 | static int debug; | ||
| 37 | |||
| 38 | #define fit_pr(level, text, ...) \ | ||
| 39 | printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__) | ||
| 40 | |||
| 41 | #define fit_dbg(text, ...) \ | ||
| 42 | if (debug) \ | ||
| 43 | printk(KERN_DEBUG \ | ||
| 44 | KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__) | ||
| 45 | |||
| 46 | #define fit_dbg_verbose(text, ...) \ | ||
| 47 | if (debug > 1) \ | ||
| 48 | printk(KERN_DEBUG \ | ||
| 49 | KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__) | ||
| 50 | |||
| 51 | #define fit_dbg_wake(text, ...) \ | ||
| 52 | if (debug > 2) \ | ||
| 53 | printk(KERN_DEBUG \ | ||
| 54 | KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__) | ||
| 55 | |||
| 56 | |||
| 57 | #define TX_BUF_LEN 256 | ||
| 58 | #define RX_BUF_LEN 32 | ||
| 59 | |||
| 60 | struct fintek_dev { | ||
| 61 | struct pnp_dev *pdev; | ||
| 62 | struct rc_dev *rdev; | ||
| 63 | |||
| 64 | spinlock_t fintek_lock; | ||
| 65 | |||
| 66 | /* for rx */ | ||
| 67 | u8 buf[RX_BUF_LEN]; | ||
| 68 | unsigned int pkts; | ||
| 69 | |||
| 70 | struct { | ||
| 71 | spinlock_t lock; | ||
| 72 | u8 buf[TX_BUF_LEN]; | ||
| 73 | unsigned int buf_count; | ||
| 74 | unsigned int cur_buf_num; | ||
| 75 | wait_queue_head_t queue; | ||
| 76 | } tx; | ||
| 77 | |||
| 78 | /* Config register index/data port pair */ | ||
| 79 | u8 cr_ip; | ||
| 80 | u8 cr_dp; | ||
| 81 | |||
| 82 | /* hardware I/O settings */ | ||
| 83 | unsigned long cir_addr; | ||
| 84 | int cir_irq; | ||
| 85 | int cir_port_len; | ||
| 86 | |||
| 87 | /* hardware id */ | ||
| 88 | u8 chip_major; | ||
| 89 | u8 chip_minor; | ||
| 90 | u16 chip_vendor; | ||
| 91 | |||
| 92 | /* hardware features */ | ||
| 93 | bool hw_learning_capable; | ||
| 94 | bool hw_tx_capable; | ||
| 95 | |||
| 96 | /* rx settings */ | ||
| 97 | bool learning_enabled; | ||
| 98 | bool carrier_detect_enabled; | ||
| 99 | |||
| 100 | enum { | ||
| 101 | CMD_HEADER = 0, | ||
| 102 | SUBCMD, | ||
| 103 | CMD_DATA, | ||
| 104 | PARSE_IRDATA, | ||
| 105 | } parser_state; | ||
| 106 | |||
| 107 | u8 cmd, rem; | ||
| 108 | |||
| 109 | /* carrier period = 1 / frequency */ | ||
| 110 | u32 carrier; | ||
| 111 | }; | ||
| 112 | |||
| 113 | /* buffer packet constants, largely identical to mceusb.c */ | ||
| 114 | #define BUF_PULSE_BIT 0x80 | ||
| 115 | #define BUF_LEN_MASK 0x1f | ||
| 116 | #define BUF_SAMPLE_MASK 0x7f | ||
| 117 | |||
| 118 | #define BUF_COMMAND_HEADER 0x9f | ||
| 119 | #define BUF_COMMAND_MASK 0xe0 | ||
| 120 | #define BUF_COMMAND_NULL 0x00 | ||
| 121 | #define BUF_HW_CMD_HEADER 0xff | ||
| 122 | #define BUF_CMD_G_REVISION 0x0b | ||
| 123 | #define BUF_CMD_S_CARRIER 0x06 | ||
| 124 | #define BUF_CMD_S_TIMEOUT 0x0c | ||
| 125 | #define BUF_CMD_SIG_END 0x01 | ||
| 126 | #define BUF_CMD_S_TXMASK 0x08 | ||
| 127 | #define BUF_CMD_S_RXSENSOR 0x14 | ||
| 128 | #define BUF_RSP_PULSE_COUNT 0x15 | ||
| 129 | |||
| 130 | #define CIR_SAMPLE_PERIOD 50 | ||
| 131 | |||
| 132 | /* | ||
| 133 | * Configuration Register: | ||
| 134 | * Index Port | ||
| 135 | * Data Port | ||
| 136 | */ | ||
| 137 | #define CR_INDEX_PORT 0x2e | ||
| 138 | #define CR_DATA_PORT 0x2f | ||
| 139 | |||
| 140 | /* Possible alternate values, depends on how the chip is wired */ | ||
| 141 | #define CR_INDEX_PORT2 0x4e | ||
| 142 | #define CR_DATA_PORT2 0x4f | ||
| 143 | |||
| 144 | /* | ||
| 145 | * GCR_CONFIG_PORT_SEL bit 4 specifies which Index Port value is | ||
| 146 | * active. 1 = 0x4e, 0 = 0x2e | ||
| 147 | */ | ||
| 148 | #define PORT_SEL_PORT_4E_EN 0x10 | ||
| 149 | |||
| 150 | /* Extended Function Mode enable/disable magic values */ | ||
| 151 | #define CONFIG_REG_ENABLE 0x87 | ||
| 152 | #define CONFIG_REG_DISABLE 0xaa | ||
| 153 | |||
| 154 | /* Chip IDs found in CR_CHIP_ID_{HI,LO} */ | ||
| 155 | #define CHIP_ID_HIGH_F71809U 0x04 | ||
| 156 | #define CHIP_ID_LOW_F71809U 0x08 | ||
| 157 | |||
| 158 | /* | ||
| 159 | * Global control regs we need to care about: | ||
| 160 | * Global Control def. | ||
| 161 | * Register name addr val. */ | ||
| 162 | #define GCR_SOFTWARE_RESET 0x02 /* 0x00 */ | ||
| 163 | #define GCR_LOGICAL_DEV_NO 0x07 /* 0x00 */ | ||
| 164 | #define GCR_CHIP_ID_HI 0x20 /* 0x04 */ | ||
| 165 | #define GCR_CHIP_ID_LO 0x21 /* 0x08 */ | ||
| 166 | #define GCR_VENDOR_ID_HI 0x23 /* 0x19 */ | ||
| 167 | #define GCR_VENDOR_ID_LO 0x24 /* 0x34 */ | ||
| 168 | #define GCR_CONFIG_PORT_SEL 0x25 /* 0x01 */ | ||
| 169 | #define GCR_KBMOUSE_WAKEUP 0x27 | ||
| 170 | |||
| 171 | #define LOGICAL_DEV_DISABLE 0x00 | ||
| 172 | #define LOGICAL_DEV_ENABLE 0x01 | ||
| 173 | |||
| 174 | /* Logical device number of the CIR function */ | ||
| 175 | #define LOGICAL_DEV_CIR 0x05 | ||
| 176 | |||
| 177 | /* CIR Logical Device (LDN 0x08) config registers */ | ||
| 178 | #define CIR_CR_COMMAND_INDEX 0x04 | ||
| 179 | #define CIR_CR_IRCS 0x05 /* Before host writes command to IR, host | ||
| 180 | must set to 1. When host finshes write | ||
| 181 | command to IR, host must clear to 0. */ | ||
| 182 | #define CIR_CR_COMMAND_DATA 0x06 /* Host read or write comand data */ | ||
| 183 | #define CIR_CR_CLASS 0x07 /* 0xff = rx-only, 0x66 = rx + 2 tx, | ||
| 184 | 0x33 = rx + 1 tx */ | ||
| 185 | #define CIR_CR_DEV_EN 0x30 /* bit0 = 1 enables CIR */ | ||
| 186 | #define CIR_CR_BASE_ADDR_HI 0x60 /* MSB of CIR IO base addr */ | ||
| 187 | #define CIR_CR_BASE_ADDR_LO 0x61 /* LSB of CIR IO base addr */ | ||
| 188 | #define CIR_CR_IRQ_SEL 0x70 /* bits3-0 store CIR IRQ */ | ||
| 189 | #define CIR_CR_PSOUT_STATUS 0xf1 | ||
| 190 | #define CIR_CR_WAKE_KEY3_ADDR 0xf8 | ||
| 191 | #define CIR_CR_WAKE_KEY3_CODE 0xf9 | ||
| 192 | #define CIR_CR_WAKE_KEY3_DC 0xfa | ||
| 193 | #define CIR_CR_WAKE_CONTROL 0xfb | ||
| 194 | #define CIR_CR_WAKE_KEY12_ADDR 0xfc | ||
| 195 | #define CIR_CR_WAKE_KEY4_ADDR 0xfd | ||
| 196 | #define CIR_CR_WAKE_KEY5_ADDR 0xfe | ||
| 197 | |||
| 198 | #define CLASS_RX_ONLY 0xff | ||
| 199 | #define CLASS_RX_2TX 0x66 | ||
| 200 | #define CLASS_RX_1TX 0x33 | ||
| 201 | |||
| 202 | /* CIR device registers */ | ||
| 203 | #define CIR_STATUS 0x00 | ||
| 204 | #define CIR_RX_DATA 0x01 | ||
| 205 | #define CIR_TX_CONTROL 0x02 | ||
| 206 | #define CIR_TX_DATA 0x03 | ||
| 207 | #define CIR_CONTROL 0x04 | ||
| 208 | |||
| 209 | /* Bits to enable CIR wake */ | ||
| 210 | #define LOGICAL_DEV_ACPI 0x01 | ||
| 211 | #define LDEV_ACPI_WAKE_EN_REG 0xe8 | ||
| 212 | #define ACPI_WAKE_EN_CIR_BIT 0x04 | ||
| 213 | |||
| 214 | #define LDEV_ACPI_PME_EN_REG 0xf0 | ||
| 215 | #define LDEV_ACPI_PME_CLR_REG 0xf1 | ||
| 216 | #define ACPI_PME_CIR_BIT 0x02 | ||
| 217 | |||
| 218 | #define LDEV_ACPI_STATE_REG 0xf4 | ||
| 219 | #define ACPI_STATE_CIR_BIT 0x20 | ||
| 220 | |||
| 221 | /* | ||
| 222 | * CIR status register (0x00): | ||
| 223 | * 7 - CIR_IRQ_EN (1 = enable CIR IRQ, 0 = disable) | ||
| 224 | * 3 - TX_FINISH (1 when TX finished, write 1 to clear) | ||
| 225 | * 2 - TX_UNDERRUN (1 on TX underrun, write 1 to clear) | ||
| 226 | * 1 - RX_TIMEOUT (1 on RX timeout, write 1 to clear) | ||
| 227 | * 0 - RX_RECEIVE (1 on RX receive, write 1 to clear) | ||
| 228 | */ | ||
| 229 | #define CIR_STATUS_IRQ_EN 0x80 | ||
| 230 | #define CIR_STATUS_TX_FINISH 0x08 | ||
| 231 | #define CIR_STATUS_TX_UNDERRUN 0x04 | ||
| 232 | #define CIR_STATUS_RX_TIMEOUT 0x02 | ||
| 233 | #define CIR_STATUS_RX_RECEIVE 0x01 | ||
| 234 | #define CIR_STATUS_IRQ_MASK 0x0f | ||
| 235 | |||
| 236 | /* | ||
| 237 | * CIR TX control register (0x02): | ||
| 238 | * 7 - TX_START (1 to indicate TX start, auto-cleared when done) | ||
| 239 | * 6 - TX_END (1 to indicate TX data written to TX fifo) | ||
| 240 | */ | ||
| 241 | #define CIR_TX_CONTROL_TX_START 0x80 | ||
| 242 | #define CIR_TX_CONTROL_TX_END 0x40 | ||
| 243 | |||
diff --git a/drivers/media/rc/keymaps/rc-lme2510.c b/drivers/media/rc/keymaps/rc-lme2510.c index afae14fd152e..129d3f9a461d 100644 --- a/drivers/media/rc/keymaps/rc-lme2510.c +++ b/drivers/media/rc/keymaps/rc-lme2510.c | |||
| @@ -14,81 +14,81 @@ | |||
| 14 | 14 | ||
| 15 | static struct rc_map_table lme2510_rc[] = { | 15 | static struct rc_map_table lme2510_rc[] = { |
| 16 | /* Type 1 - 26 buttons */ | 16 | /* Type 1 - 26 buttons */ |
| 17 | { 0xef12ba45, KEY_0 }, | 17 | { 0x10ed45, KEY_0 }, |
| 18 | { 0xef12a05f, KEY_1 }, | 18 | { 0x10ed5f, KEY_1 }, |
| 19 | { 0xef12af50, KEY_2 }, | 19 | { 0x10ed50, KEY_2 }, |
| 20 | { 0xef12a25d, KEY_3 }, | 20 | { 0x10ed5d, KEY_3 }, |
| 21 | { 0xef12be41, KEY_4 }, | 21 | { 0x10ed41, KEY_4 }, |
| 22 | { 0xef12f50a, KEY_5 }, | 22 | { 0x10ed0a, KEY_5 }, |
| 23 | { 0xef12bd42, KEY_6 }, | 23 | { 0x10ed42, KEY_6 }, |
| 24 | { 0xef12b847, KEY_7 }, | 24 | { 0x10ed47, KEY_7 }, |
| 25 | { 0xef12b649, KEY_8 }, | 25 | { 0x10ed49, KEY_8 }, |
| 26 | { 0xef12fa05, KEY_9 }, | 26 | { 0x10ed05, KEY_9 }, |
| 27 | { 0xef12bc43, KEY_POWER }, | 27 | { 0x10ed43, KEY_POWER }, |
| 28 | { 0xef12b946, KEY_SUBTITLE }, | 28 | { 0x10ed46, KEY_SUBTITLE }, |
| 29 | { 0xef12f906, KEY_PAUSE }, | 29 | { 0x10ed06, KEY_PAUSE }, |
| 30 | { 0xef12fc03, KEY_MEDIA_REPEAT}, | 30 | { 0x10ed03, KEY_MEDIA_REPEAT}, |
| 31 | { 0xef12fd02, KEY_PAUSE }, | 31 | { 0x10ed02, KEY_PAUSE }, |
| 32 | { 0xef12a15e, KEY_VOLUMEUP }, | 32 | { 0x10ed5e, KEY_VOLUMEUP }, |
| 33 | { 0xef12a35c, KEY_VOLUMEDOWN }, | 33 | { 0x10ed5c, KEY_VOLUMEDOWN }, |
| 34 | { 0xef12f609, KEY_CHANNELUP }, | 34 | { 0x10ed09, KEY_CHANNELUP }, |
| 35 | { 0xef12e51a, KEY_CHANNELDOWN }, | 35 | { 0x10ed1a, KEY_CHANNELDOWN }, |
| 36 | { 0xef12e11e, KEY_PLAY }, | 36 | { 0x10ed1e, KEY_PLAY }, |
| 37 | { 0xef12e41b, KEY_ZOOM }, | 37 | { 0x10ed1b, KEY_ZOOM }, |
| 38 | { 0xef12a659, KEY_MUTE }, | 38 | { 0x10ed59, KEY_MUTE }, |
| 39 | { 0xef12a55a, KEY_TV }, | 39 | { 0x10ed5a, KEY_TV }, |
| 40 | { 0xef12e718, KEY_RECORD }, | 40 | { 0x10ed18, KEY_RECORD }, |
| 41 | { 0xef12f807, KEY_EPG }, | 41 | { 0x10ed07, KEY_EPG }, |
| 42 | { 0xef12fe01, KEY_STOP }, | 42 | { 0x10ed01, KEY_STOP }, |
| 43 | /* Type 2 - 20 buttons */ | 43 | /* Type 2 - 20 buttons */ |
| 44 | { 0xff40ea15, KEY_0 }, | 44 | { 0xbf15, KEY_0 }, |
| 45 | { 0xff40f708, KEY_1 }, | 45 | { 0xbf08, KEY_1 }, |
| 46 | { 0xff40f609, KEY_2 }, | 46 | { 0xbf09, KEY_2 }, |
| 47 | { 0xff40f50a, KEY_3 }, | 47 | { 0xbf0a, KEY_3 }, |
| 48 | { 0xff40f30c, KEY_4 }, | 48 | { 0xbf0c, KEY_4 }, |
| 49 | { 0xff40f20d, KEY_5 }, | 49 | { 0xbf0d, KEY_5 }, |
| 50 | { 0xff40f10e, KEY_6 }, | 50 | { 0xbf0e, KEY_6 }, |
| 51 | { 0xff40ef10, KEY_7 }, | 51 | { 0xbf10, KEY_7 }, |
| 52 | { 0xff40ee11, KEY_8 }, | 52 | { 0xbf11, KEY_8 }, |
| 53 | { 0xff40ed12, KEY_9 }, | 53 | { 0xbf12, KEY_9 }, |
| 54 | { 0xff40ff00, KEY_POWER }, | 54 | { 0xbf00, KEY_POWER }, |
| 55 | { 0xff40fb04, KEY_MEDIA_REPEAT}, /* Recall */ | 55 | { 0xbf04, KEY_MEDIA_REPEAT}, /* Recall */ |
| 56 | { 0xff40e51a, KEY_PAUSE }, /* Timeshift */ | 56 | { 0xbf1a, KEY_PAUSE }, /* Timeshift */ |
| 57 | { 0xff40fd02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ | 57 | { 0xbf02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ |
| 58 | { 0xff40f906, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ | 58 | { 0xbf06, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ |
| 59 | { 0xff40fe01, KEY_CHANNELUP }, | 59 | { 0xbf01, KEY_CHANNELUP }, |
| 60 | { 0xff40fa05, KEY_CHANNELDOWN }, | 60 | { 0xbf05, KEY_CHANNELDOWN }, |
| 61 | { 0xff40eb14, KEY_ZOOM }, | 61 | { 0xbf14, KEY_ZOOM }, |
| 62 | { 0xff40e718, KEY_RECORD }, | 62 | { 0xbf18, KEY_RECORD }, |
| 63 | { 0xff40e916, KEY_STOP }, | 63 | { 0xbf16, KEY_STOP }, |
| 64 | /* Type 3 - 20 buttons */ | 64 | /* Type 3 - 20 buttons */ |
| 65 | { 0xff00e31c, KEY_0 }, | 65 | { 0x1c, KEY_0 }, |
| 66 | { 0xff00f807, KEY_1 }, | 66 | { 0x07, KEY_1 }, |
| 67 | { 0xff00ea15, KEY_2 }, | 67 | { 0x15, KEY_2 }, |
| 68 | { 0xff00f609, KEY_3 }, | 68 | { 0x09, KEY_3 }, |
| 69 | { 0xff00e916, KEY_4 }, | 69 | { 0x16, KEY_4 }, |
| 70 | { 0xff00e619, KEY_5 }, | 70 | { 0x19, KEY_5 }, |
| 71 | { 0xff00f20d, KEY_6 }, | 71 | { 0x0d, KEY_6 }, |
| 72 | { 0xff00f30c, KEY_7 }, | 72 | { 0x0c, KEY_7 }, |
| 73 | { 0xff00e718, KEY_8 }, | 73 | { 0x18, KEY_8 }, |
| 74 | { 0xff00a15e, KEY_9 }, | 74 | { 0x5e, KEY_9 }, |
| 75 | { 0xff00ba45, KEY_POWER }, | 75 | { 0x45, KEY_POWER }, |
| 76 | { 0xff00bb44, KEY_MEDIA_REPEAT}, /* Recall */ | 76 | { 0x44, KEY_MEDIA_REPEAT}, /* Recall */ |
| 77 | { 0xff00b54a, KEY_PAUSE }, /* Timeshift */ | 77 | { 0x4a, KEY_PAUSE }, /* Timeshift */ |
| 78 | { 0xff00b847, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ | 78 | { 0x47, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ |
| 79 | { 0xff00bc43, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ | 79 | { 0x43, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ |
| 80 | { 0xff00b946, KEY_CHANNELUP }, | 80 | { 0x46, KEY_CHANNELUP }, |
| 81 | { 0xff00bf40, KEY_CHANNELDOWN }, | 81 | { 0x40, KEY_CHANNELDOWN }, |
| 82 | { 0xff00f708, KEY_ZOOM }, | 82 | { 0x08, KEY_ZOOM }, |
| 83 | { 0xff00bd42, KEY_RECORD }, | 83 | { 0x42, KEY_RECORD }, |
| 84 | { 0xff00a55a, KEY_STOP }, | 84 | { 0x5a, KEY_STOP }, |
| 85 | }; | 85 | }; |
| 86 | 86 | ||
| 87 | static struct rc_map_list lme2510_map = { | 87 | static struct rc_map_list lme2510_map = { |
| 88 | .map = { | 88 | .map = { |
| 89 | .scan = lme2510_rc, | 89 | .scan = lme2510_rc, |
| 90 | .size = ARRAY_SIZE(lme2510_rc), | 90 | .size = ARRAY_SIZE(lme2510_rc), |
| 91 | .rc_type = RC_TYPE_UNKNOWN, | 91 | .rc_type = RC_TYPE_NEC, |
| 92 | .name = RC_MAP_LME2510, | 92 | .name = RC_MAP_LME2510, |
| 93 | } | 93 | } |
| 94 | }; | 94 | }; |
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 3be180b3ba27..bb53de7fe408 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
| @@ -687,7 +687,7 @@ config VIDEO_HEXIUM_GEMINI | |||
| 687 | 687 | ||
| 688 | config VIDEO_TIMBERDALE | 688 | config VIDEO_TIMBERDALE |
| 689 | tristate "Support for timberdale Video In/LogiWIN" | 689 | tristate "Support for timberdale Video In/LogiWIN" |
| 690 | depends on VIDEO_V4L2 && I2C | 690 | depends on VIDEO_V4L2 && I2C && DMADEVICES |
| 691 | select DMA_ENGINE | 691 | select DMA_ENGINE |
| 692 | select TIMB_DMA | 692 | select TIMB_DMA |
| 693 | select VIDEO_ADV7180 | 693 | select VIDEO_ADV7180 |
| @@ -757,6 +757,8 @@ config VIDEO_NOON010PC30 | |||
| 757 | ---help--- | 757 | ---help--- |
| 758 | This driver supports NOON010PC30 CIF camera from Siliconfile | 758 | This driver supports NOON010PC30 CIF camera from Siliconfile |
| 759 | 759 | ||
| 760 | source "drivers/media/video/m5mols/Kconfig" | ||
| 761 | |||
| 760 | config VIDEO_OMAP3 | 762 | config VIDEO_OMAP3 |
| 761 | tristate "OMAP 3 Camera support (EXPERIMENTAL)" | 763 | tristate "OMAP 3 Camera support (EXPERIMENTAL)" |
| 762 | select OMAP_IOMMU | 764 | select OMAP_IOMMU |
| @@ -952,7 +954,7 @@ config VIDEO_SAMSUNG_S5P_FIMC | |||
| 952 | 954 | ||
| 953 | config VIDEO_S5P_MIPI_CSIS | 955 | config VIDEO_S5P_MIPI_CSIS |
| 954 | tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver" | 956 | tristate "Samsung S5P and EXYNOS4 MIPI CSI receiver driver" |
| 955 | depends on VIDEO_V4L2 && PM_RUNTIME && VIDEO_V4L2_SUBDEV_API | 957 | depends on VIDEO_V4L2 && PM_RUNTIME && PLAT_S5P && VIDEO_V4L2_SUBDEV_API |
| 956 | ---help--- | 958 | ---help--- |
| 957 | This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver. | 959 | This is a v4l2 driver for Samsung S5P/EXYNOS4 MIPI-CSI receiver. |
| 958 | 960 | ||
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 9519160c2e01..f0fecd6f6a33 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
| @@ -69,6 +69,7 @@ obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o | |||
| 69 | obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o | 69 | obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o |
| 70 | obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o | 70 | obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o |
| 71 | obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o | 71 | obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o |
| 72 | obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ | ||
| 72 | 73 | ||
| 73 | obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o | 74 | obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o |
| 74 | obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o | 75 | obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o |
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c index 0073a8c55336..40eb6326e48a 100644 --- a/drivers/media/video/cpia2/cpia2_v4l.c +++ b/drivers/media/video/cpia2/cpia2_v4l.c | |||
| @@ -438,7 +438,7 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v | |||
| 438 | strcat(vc->card, " (676/"); | 438 | strcat(vc->card, " (676/"); |
| 439 | break; | 439 | break; |
| 440 | default: | 440 | default: |
| 441 | strcat(vc->card, " (???/"); | 441 | strcat(vc->card, " (XXX/"); |
| 442 | break; | 442 | break; |
| 443 | } | 443 | } |
| 444 | switch (cam->params.version.sensor_flags) { | 444 | switch (cam->params.version.sensor_flags) { |
| @@ -458,7 +458,7 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v | |||
| 458 | strcat(vc->card, "500)"); | 458 | strcat(vc->card, "500)"); |
| 459 | break; | 459 | break; |
| 460 | default: | 460 | default: |
| 461 | strcat(vc->card, "???)"); | 461 | strcat(vc->card, "XXX)"); |
| 462 | break; | 462 | break; |
| 463 | } | 463 | } |
| 464 | 464 | ||
diff --git a/drivers/media/video/gspca/kinect.c b/drivers/media/video/gspca/kinect.c index 66671a4092e4..26fc206f095e 100644 --- a/drivers/media/video/gspca/kinect.c +++ b/drivers/media/video/gspca/kinect.c | |||
| @@ -34,7 +34,7 @@ MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>"); | |||
| 34 | MODULE_DESCRIPTION("GSPCA/Kinect Sensor Device USB Camera Driver"); | 34 | MODULE_DESCRIPTION("GSPCA/Kinect Sensor Device USB Camera Driver"); |
| 35 | MODULE_LICENSE("GPL"); | 35 | MODULE_LICENSE("GPL"); |
| 36 | 36 | ||
| 37 | #ifdef DEBUG | 37 | #ifdef GSPCA_DEBUG |
| 38 | int gspca_debug = D_ERR | D_PROBE | D_CONF | D_STREAM | D_FRAM | D_PACK | | 38 | int gspca_debug = D_ERR | D_PROBE | D_CONF | D_STREAM | D_FRAM | D_PACK | |
| 39 | D_USBI | D_USBO | D_V4L2; | 39 | D_USBI | D_USBO | D_V4L2; |
| 40 | #endif | 40 | #endif |
diff --git a/drivers/media/video/m5mols/Kconfig b/drivers/media/video/m5mols/Kconfig new file mode 100644 index 000000000000..302dc3d70193 --- /dev/null +++ b/drivers/media/video/m5mols/Kconfig | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | config VIDEO_M5MOLS | ||
| 2 | tristate "Fujitsu M-5MOLS 8MP sensor support" | ||
| 3 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API | ||
| 4 | ---help--- | ||
| 5 | This driver supports Fujitsu M-5MOLS camera sensor with ISP | ||
diff --git a/drivers/media/video/m5mols/Makefile b/drivers/media/video/m5mols/Makefile new file mode 100644 index 000000000000..0a44e028edc7 --- /dev/null +++ b/drivers/media/video/m5mols/Makefile | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | m5mols-objs := m5mols_core.o m5mols_controls.o m5mols_capture.o | ||
| 2 | |||
| 3 | obj-$(CONFIG_VIDEO_M5MOLS) += m5mols.o | ||
diff --git a/drivers/media/video/m5mols/m5mols.h b/drivers/media/video/m5mols/m5mols.h new file mode 100644 index 000000000000..10b55c854487 --- /dev/null +++ b/drivers/media/video/m5mols/m5mols.h | |||
| @@ -0,0 +1,296 @@ | |||
| 1 | /* | ||
| 2 | * Header for M-5MOLS 8M Pixel camera sensor with ISP | ||
| 3 | * | ||
| 4 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | ||
| 5 | * Author: HeungJun Kim, riverful.kim@samsung.com | ||
| 6 | * | ||
| 7 | * Copyright (C) 2009 Samsung Electronics Co., Ltd. | ||
| 8 | * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License as published by | ||
| 12 | * the Free Software Foundation; either version 2 of the License, or | ||
| 13 | * (at your option) any later version. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #ifndef M5MOLS_H | ||
| 17 | #define M5MOLS_H | ||
| 18 | |||
| 19 | #include <media/v4l2-subdev.h> | ||
| 20 | #include "m5mols_reg.h" | ||
| 21 | |||
| 22 | extern int m5mols_debug; | ||
| 23 | |||
| 24 | #define to_m5mols(__sd) container_of(__sd, struct m5mols_info, sd) | ||
| 25 | |||
| 26 | #define to_sd(__ctrl) \ | ||
| 27 | (&container_of(__ctrl->handler, struct m5mols_info, handle)->sd) | ||
| 28 | |||
| 29 | enum m5mols_restype { | ||
| 30 | M5MOLS_RESTYPE_MONITOR, | ||
| 31 | M5MOLS_RESTYPE_CAPTURE, | ||
| 32 | M5MOLS_RESTYPE_MAX, | ||
| 33 | }; | ||
| 34 | |||
| 35 | /** | ||
| 36 | * struct m5mols_resolution - structure for the resolution | ||
| 37 | * @type: resolution type according to the pixel code | ||
| 38 | * @width: width of the resolution | ||
| 39 | * @height: height of the resolution | ||
| 40 | * @reg: resolution preset register value | ||
| 41 | */ | ||
| 42 | struct m5mols_resolution { | ||
| 43 | u8 reg; | ||
| 44 | enum m5mols_restype type; | ||
| 45 | u16 width; | ||
| 46 | u16 height; | ||
| 47 | }; | ||
| 48 | |||
| 49 | /** | ||
| 50 | * struct m5mols_exif - structure for the EXIF information of M-5MOLS | ||
| 51 | * @exposure_time: exposure time register value | ||
| 52 | * @shutter_speed: speed of the shutter register value | ||
| 53 | * @aperture: aperture register value | ||
| 54 | * @exposure_bias: it calls also EV bias | ||
| 55 | * @iso_speed: ISO register value | ||
| 56 | * @flash: status register value of the flash | ||
| 57 | * @sdr: status register value of the Subject Distance Range | ||
| 58 | * @qval: not written exact meaning in document | ||
| 59 | */ | ||
| 60 | struct m5mols_exif { | ||
| 61 | u32 exposure_time; | ||
| 62 | u32 shutter_speed; | ||
| 63 | u32 aperture; | ||
| 64 | u32 brightness; | ||
| 65 | u32 exposure_bias; | ||
| 66 | u16 iso_speed; | ||
| 67 | u16 flash; | ||
| 68 | u16 sdr; | ||
| 69 | u16 qval; | ||
| 70 | }; | ||
| 71 | |||
| 72 | /** | ||
| 73 | * struct m5mols_capture - Structure for the capture capability | ||
| 74 | * @exif: EXIF information | ||
| 75 | * @main: size in bytes of the main image | ||
| 76 | * @thumb: size in bytes of the thumb image, if it was accompanied | ||
| 77 | * @total: total size in bytes of the produced image | ||
| 78 | */ | ||
| 79 | struct m5mols_capture { | ||
| 80 | struct m5mols_exif exif; | ||
| 81 | u32 main; | ||
| 82 | u32 thumb; | ||
| 83 | u32 total; | ||
| 84 | }; | ||
| 85 | |||
| 86 | /** | ||
| 87 | * struct m5mols_scenemode - structure for the scenemode capability | ||
| 88 | * @metering: metering light register value | ||
| 89 | * @ev_bias: EV bias register value | ||
| 90 | * @wb_mode: mode which means the WhiteBalance is Auto or Manual | ||
| 91 | * @wb_preset: whitebalance preset register value in the Manual mode | ||
| 92 | * @chroma_en: register value whether the Chroma capability is enabled or not | ||
| 93 | * @chroma_lvl: chroma's level register value | ||
| 94 | * @edge_en: register value Whether the Edge capability is enabled or not | ||
| 95 | * @edge_lvl: edge's level register value | ||
| 96 | * @af_range: Auto Focus's range | ||
| 97 | * @fd_mode: Face Detection mode | ||
| 98 | * @mcc: Multi-axis Color Conversion which means emotion color | ||
| 99 | * @light: status of the Light | ||
| 100 | * @flash: status of the Flash | ||
| 101 | * @tone: Tone color which means Contrast | ||
| 102 | * @iso: ISO register value | ||
| 103 | * @capt_mode: Mode of the Image Stabilization while the camera capturing | ||
| 104 | * @wdr: Wide Dynamic Range register value | ||
| 105 | * | ||
| 106 | * The each value according to each scenemode is recommended in the documents. | ||
| 107 | */ | ||
| 108 | struct m5mols_scenemode { | ||
| 109 | u32 metering; | ||
| 110 | u32 ev_bias; | ||
| 111 | u32 wb_mode; | ||
| 112 | u32 wb_preset; | ||
| 113 | u32 chroma_en; | ||
| 114 | u32 chroma_lvl; | ||
| 115 | u32 edge_en; | ||
| 116 | u32 edge_lvl; | ||
| 117 | u32 af_range; | ||
| 118 | u32 fd_mode; | ||
| 119 | u32 mcc; | ||
| 120 | u32 light; | ||
| 121 | u32 flash; | ||
| 122 | u32 tone; | ||
| 123 | u32 iso; | ||
| 124 | u32 capt_mode; | ||
| 125 | u32 wdr; | ||
| 126 | }; | ||
| 127 | |||
| 128 | /** | ||
| 129 | * struct m5mols_version - firmware version information | ||
| 130 | * @customer: customer information | ||
| 131 | * @project: version of project information according to customer | ||
| 132 | * @fw: firmware revision | ||
| 133 | * @hw: hardware revision | ||
| 134 | * @param: version of the parameter | ||
| 135 | * @awb: Auto WhiteBalance algorithm version | ||
| 136 | * @str: information about manufacturer and packaging vendor | ||
| 137 | * @af: Auto Focus version | ||
| 138 | * | ||
| 139 | * The register offset starts the customer version at 0x0, and it ends | ||
| 140 | * the awb version at 0x09. The customer, project information occupies 1 bytes | ||
| 141 | * each. And also the fw, hw, param, awb each requires 2 bytes. The str is | ||
| 142 | * unique string associated with firmware's version. It includes information | ||
| 143 | * about manufacturer and the vendor of the sensor's packaging. The least | ||
| 144 | * significant 2 bytes of the string indicate packaging manufacturer. | ||
| 145 | */ | ||
| 146 | #define VERSION_STRING_SIZE 22 | ||
| 147 | struct m5mols_version { | ||
| 148 | u8 customer; | ||
| 149 | u8 project; | ||
| 150 | u16 fw; | ||
| 151 | u16 hw; | ||
| 152 | u16 param; | ||
| 153 | u16 awb; | ||
| 154 | u8 str[VERSION_STRING_SIZE]; | ||
| 155 | u8 af; | ||
| 156 | }; | ||
| 157 | #define VERSION_SIZE sizeof(struct m5mols_version) | ||
| 158 | |||
| 159 | /** | ||
| 160 | * struct m5mols_info - M-5MOLS driver data structure | ||
| 161 | * @pdata: platform data | ||
| 162 | * @sd: v4l-subdev instance | ||
| 163 | * @pad: media pad | ||
| 164 | * @ffmt: current fmt according to resolution type | ||
| 165 | * @res_type: current resolution type | ||
| 166 | * @code: current code | ||
| 167 | * @irq_waitq: waitqueue for the capture | ||
| 168 | * @work_irq: workqueue for the IRQ | ||
| 169 | * @flags: state variable for the interrupt handler | ||
| 170 | * @handle: control handler | ||
| 171 | * @autoexposure: Auto Exposure control | ||
| 172 | * @exposure: Exposure control | ||
| 173 | * @autowb: Auto White Balance control | ||
| 174 | * @colorfx: Color effect control | ||
| 175 | * @saturation: Saturation control | ||
| 176 | * @zoom: Zoom control | ||
| 177 | * @ver: information of the version | ||
| 178 | * @cap: the capture mode attributes | ||
| 179 | * @power: current sensor's power status | ||
| 180 | * @ctrl_sync: true means all controls of the sensor are initialized | ||
| 181 | * @int_capture: true means the capture interrupt is issued once | ||
| 182 | * @lock_ae: true means the Auto Exposure is locked | ||
| 183 | * @lock_awb: true means the Aut WhiteBalance is locked | ||
| 184 | * @resolution: register value for current resolution | ||
| 185 | * @interrupt: register value for current interrupt status | ||
| 186 | * @mode: register value for current operation mode | ||
| 187 | * @mode_save: register value for current operation mode for saving | ||
| 188 | * @set_power: optional power callback to the board code | ||
| 189 | */ | ||
| 190 | struct m5mols_info { | ||
| 191 | const struct m5mols_platform_data *pdata; | ||
| 192 | struct v4l2_subdev sd; | ||
| 193 | struct media_pad pad; | ||
| 194 | struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX]; | ||
| 195 | int res_type; | ||
| 196 | enum v4l2_mbus_pixelcode code; | ||
| 197 | wait_queue_head_t irq_waitq; | ||
| 198 | struct work_struct work_irq; | ||
| 199 | unsigned long flags; | ||
| 200 | |||
| 201 | struct v4l2_ctrl_handler handle; | ||
| 202 | /* Autoexposure/exposure control cluster */ | ||
| 203 | struct { | ||
| 204 | struct v4l2_ctrl *autoexposure; | ||
| 205 | struct v4l2_ctrl *exposure; | ||
| 206 | }; | ||
| 207 | struct v4l2_ctrl *autowb; | ||
| 208 | struct v4l2_ctrl *colorfx; | ||
| 209 | struct v4l2_ctrl *saturation; | ||
| 210 | struct v4l2_ctrl *zoom; | ||
| 211 | |||
| 212 | struct m5mols_version ver; | ||
| 213 | struct m5mols_capture cap; | ||
| 214 | bool power; | ||
| 215 | bool ctrl_sync; | ||
| 216 | bool lock_ae; | ||
| 217 | bool lock_awb; | ||
| 218 | u8 resolution; | ||
| 219 | u32 interrupt; | ||
| 220 | u32 mode; | ||
| 221 | u32 mode_save; | ||
| 222 | int (*set_power)(struct device *dev, int on); | ||
| 223 | }; | ||
| 224 | |||
| 225 | #define ST_CAPT_IRQ 0 | ||
| 226 | |||
| 227 | #define is_powered(__info) (__info->power) | ||
| 228 | #define is_ctrl_synced(__info) (__info->ctrl_sync) | ||
| 229 | #define is_available_af(__info) (__info->ver.af) | ||
| 230 | #define is_code(__code, __type) (__code == m5mols_default_ffmt[__type].code) | ||
| 231 | #define is_manufacturer(__info, __manufacturer) \ | ||
| 232 | (__info->ver.str[0] == __manufacturer[0] && \ | ||
| 233 | __info->ver.str[1] == __manufacturer[1]) | ||
| 234 | /* | ||
| 235 | * I2C operation of the M-5MOLS | ||
| 236 | * | ||
| 237 | * The I2C read operation of the M-5MOLS requires 2 messages. The first | ||
| 238 | * message sends the information about the command, command category, and total | ||
| 239 | * message size. The second message is used to retrieve the data specifed in | ||
| 240 | * the first message | ||
| 241 | * | ||
| 242 | * 1st message 2nd message | ||
| 243 | * +-------+---+----------+-----+-------+ +------+------+------+------+ | ||
| 244 | * | size1 | R | category | cmd | size2 | | d[0] | d[1] | d[2] | d[3] | | ||
| 245 | * +-------+---+----------+-----+-------+ +------+------+------+------+ | ||
| 246 | * - size1: message data size(5 in this case) | ||
| 247 | * - size2: desired buffer size of the 2nd message | ||
| 248 | * - d[0..3]: according to size2 | ||
| 249 | * | ||
| 250 | * The I2C write operation needs just one message. The message includes | ||
| 251 | * category, command, total size, and desired data. | ||
| 252 | * | ||
| 253 | * 1st message | ||
| 254 | * +-------+---+----------+-----+------+------+------+------+ | ||
| 255 | * | size1 | W | category | cmd | d[0] | d[1] | d[2] | d[3] | | ||
| 256 | * +-------+---+----------+-----+------+------+------+------+ | ||
| 257 | * - d[0..3]: according to size1 | ||
| 258 | */ | ||
| 259 | int m5mols_read(struct v4l2_subdev *sd, u32 reg_comb, u32 *val); | ||
| 260 | int m5mols_write(struct v4l2_subdev *sd, u32 reg_comb, u32 val); | ||
| 261 | int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 value); | ||
| 262 | |||
| 263 | /* | ||
| 264 | * Mode operation of the M-5MOLS | ||
| 265 | * | ||
| 266 | * Changing the mode of the M-5MOLS is needed right executing order. | ||
| 267 | * There are three modes(PARAMETER, MONITOR, CAPTURE) which can be changed | ||
| 268 | * by user. There are various categories associated with each mode. | ||
| 269 | * | ||
| 270 | * +============================================================+ | ||
| 271 | * | mode | category | | ||
| 272 | * +============================================================+ | ||
| 273 | * | FLASH | FLASH(only after Stand-by or Power-on) | | ||
| 274 | * | SYSTEM | SYSTEM(only after sensor arm-booting) | | ||
| 275 | * | PARAMETER | PARAMETER | | ||
| 276 | * | MONITOR | MONITOR(preview), Auto Focus, Face Detection | | ||
| 277 | * | CAPTURE | Single CAPTURE, Preview(recording) | | ||
| 278 | * +============================================================+ | ||
| 279 | * | ||
| 280 | * The available executing order between each modes are as follows: | ||
| 281 | * PARAMETER <---> MONITOR <---> CAPTURE | ||
| 282 | */ | ||
| 283 | int m5mols_mode(struct m5mols_info *info, u32 mode); | ||
| 284 | |||
| 285 | int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg); | ||
| 286 | int m5mols_sync_controls(struct m5mols_info *info); | ||
| 287 | int m5mols_start_capture(struct m5mols_info *info); | ||
| 288 | int m5mols_do_scenemode(struct m5mols_info *info, u32 mode); | ||
| 289 | int m5mols_lock_3a(struct m5mols_info *info, bool lock); | ||
| 290 | int m5mols_set_ctrl(struct v4l2_ctrl *ctrl); | ||
| 291 | |||
| 292 | /* The firmware function */ | ||
| 293 | int m5mols_update_fw(struct v4l2_subdev *sd, | ||
| 294 | int (*set_power)(struct m5mols_info *, bool)); | ||
| 295 | |||
| 296 | #endif /* M5MOLS_H */ | ||
diff --git a/drivers/media/video/m5mols/m5mols_capture.c b/drivers/media/video/m5mols/m5mols_capture.c new file mode 100644 index 000000000000..d71a3903b60f --- /dev/null +++ b/drivers/media/video/m5mols/m5mols_capture.c | |||
| @@ -0,0 +1,191 @@ | |||
| 1 | /* | ||
| 2 | * The Capture code for Fujitsu M-5MOLS ISP | ||
| 3 | * | ||
| 4 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | ||
| 5 | * Author: HeungJun Kim, riverful.kim@samsung.com | ||
| 6 | * | ||
| 7 | * Copyright (C) 2009 Samsung Electronics Co., Ltd. | ||
| 8 | * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License as published by | ||
| 12 | * the Free Software Foundation; either version 2 of the License, or | ||
| 13 | * (at your option) any later version. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/i2c.h> | ||
| 17 | #include <linux/slab.h> | ||
| 18 | #include <linux/irq.h> | ||
| 19 | #include <linux/interrupt.h> | ||
| 20 | #include <linux/delay.h> | ||
| 21 | #include <linux/version.h> | ||
| 22 | #include <linux/gpio.h> | ||
| 23 | #include <linux/regulator/consumer.h> | ||
| 24 | #include <linux/videodev2.h> | ||
| 25 | #include <linux/version.h> | ||
| 26 | #include <media/v4l2-ctrls.h> | ||
| 27 | #include <media/v4l2-device.h> | ||
| 28 | #include <media/v4l2-subdev.h> | ||
| 29 | #include <media/m5mols.h> | ||
| 30 | |||
| 31 | #include "m5mols.h" | ||
| 32 | #include "m5mols_reg.h" | ||
| 33 | |||
| 34 | static int m5mols_capture_error_handler(struct m5mols_info *info, | ||
| 35 | int timeout) | ||
| 36 | { | ||
| 37 | int ret; | ||
| 38 | |||
| 39 | /* Disable all interrupts and clear relevant interrupt staus bits */ | ||
| 40 | ret = m5mols_write(&info->sd, SYSTEM_INT_ENABLE, | ||
| 41 | info->interrupt & ~(REG_INT_CAPTURE)); | ||
| 42 | if (ret) | ||
| 43 | return ret; | ||
| 44 | |||
| 45 | if (timeout == 0) | ||
| 46 | return -ETIMEDOUT; | ||
| 47 | |||
| 48 | return 0; | ||
| 49 | } | ||
| 50 | /** | ||
| 51 | * m5mols_read_rational - I2C read of a rational number | ||
| 52 | * | ||
| 53 | * Read numerator and denominator from registers @addr_num and @addr_den | ||
| 54 | * respectively and return the division result in @val. | ||
| 55 | */ | ||
| 56 | static int m5mols_read_rational(struct v4l2_subdev *sd, u32 addr_num, | ||
| 57 | u32 addr_den, u32 *val) | ||
| 58 | { | ||
| 59 | u32 num, den; | ||
| 60 | |||
| 61 | int ret = m5mols_read(sd, addr_num, &num); | ||
| 62 | if (!ret) | ||
| 63 | ret = m5mols_read(sd, addr_den, &den); | ||
| 64 | if (ret) | ||
| 65 | return ret; | ||
| 66 | *val = den == 0 ? 0 : num / den; | ||
| 67 | return ret; | ||
| 68 | } | ||
| 69 | |||
| 70 | /** | ||
| 71 | * m5mols_capture_info - Gather captured image information | ||
| 72 | * | ||
| 73 | * For now it gathers only EXIF information and file size. | ||
| 74 | */ | ||
| 75 | static int m5mols_capture_info(struct m5mols_info *info) | ||
| 76 | { | ||
| 77 | struct m5mols_exif *exif = &info->cap.exif; | ||
| 78 | struct v4l2_subdev *sd = &info->sd; | ||
| 79 | int ret; | ||
| 80 | |||
| 81 | ret = m5mols_read_rational(sd, EXIF_INFO_EXPTIME_NU, | ||
| 82 | EXIF_INFO_EXPTIME_DE, &exif->exposure_time); | ||
| 83 | if (ret) | ||
| 84 | return ret; | ||
| 85 | ret = m5mols_read_rational(sd, EXIF_INFO_TV_NU, EXIF_INFO_TV_DE, | ||
| 86 | &exif->shutter_speed); | ||
| 87 | if (ret) | ||
| 88 | return ret; | ||
| 89 | ret = m5mols_read_rational(sd, EXIF_INFO_AV_NU, EXIF_INFO_AV_DE, | ||
| 90 | &exif->aperture); | ||
| 91 | if (ret) | ||
| 92 | return ret; | ||
| 93 | ret = m5mols_read_rational(sd, EXIF_INFO_BV_NU, EXIF_INFO_BV_DE, | ||
| 94 | &exif->brightness); | ||
| 95 | if (ret) | ||
| 96 | return ret; | ||
| 97 | ret = m5mols_read_rational(sd, EXIF_INFO_EBV_NU, EXIF_INFO_EBV_DE, | ||
| 98 | &exif->exposure_bias); | ||
| 99 | if (ret) | ||
| 100 | return ret; | ||
| 101 | |||
| 102 | ret = m5mols_read(sd, EXIF_INFO_ISO, (u32 *)&exif->iso_speed); | ||
| 103 | if (!ret) | ||
| 104 | ret = m5mols_read(sd, EXIF_INFO_FLASH, (u32 *)&exif->flash); | ||
| 105 | if (!ret) | ||
| 106 | ret = m5mols_read(sd, EXIF_INFO_SDR, (u32 *)&exif->sdr); | ||
| 107 | if (!ret) | ||
| 108 | ret = m5mols_read(sd, EXIF_INFO_QVAL, (u32 *)&exif->qval); | ||
| 109 | if (ret) | ||
| 110 | return ret; | ||
| 111 | |||
| 112 | if (!ret) | ||
| 113 | ret = m5mols_read(sd, CAPC_IMAGE_SIZE, &info->cap.main); | ||
| 114 | if (!ret) | ||
| 115 | ret = m5mols_read(sd, CAPC_THUMB_SIZE, &info->cap.thumb); | ||
| 116 | if (!ret) | ||
| 117 | info->cap.total = info->cap.main + info->cap.thumb; | ||
| 118 | |||
| 119 | return ret; | ||
| 120 | } | ||
| 121 | |||
| 122 | int m5mols_start_capture(struct m5mols_info *info) | ||
| 123 | { | ||
| 124 | struct v4l2_subdev *sd = &info->sd; | ||
| 125 | u32 resolution = info->resolution; | ||
| 126 | int timeout; | ||
| 127 | int ret; | ||
| 128 | |||
| 129 | /* | ||
| 130 | * Preparing capture. Setting control & interrupt before entering | ||
| 131 | * capture mode | ||
| 132 | * | ||
| 133 | * 1) change to MONITOR mode for operating control & interrupt | ||
| 134 | * 2) set controls (considering v4l2_control value & lock 3A) | ||
| 135 | * 3) set interrupt | ||
| 136 | * 4) change to CAPTURE mode | ||
| 137 | */ | ||
| 138 | ret = m5mols_mode(info, REG_MONITOR); | ||
| 139 | if (!ret) | ||
| 140 | ret = m5mols_sync_controls(info); | ||
| 141 | if (!ret) | ||
| 142 | ret = m5mols_lock_3a(info, true); | ||
| 143 | if (!ret) | ||
| 144 | ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE); | ||
| 145 | if (!ret) | ||
| 146 | ret = m5mols_mode(info, REG_CAPTURE); | ||
| 147 | if (!ret) { | ||
| 148 | /* Wait for capture interrupt, after changing capture mode */ | ||
| 149 | timeout = wait_event_interruptible_timeout(info->irq_waitq, | ||
| 150 | test_bit(ST_CAPT_IRQ, &info->flags), | ||
| 151 | msecs_to_jiffies(2000)); | ||
| 152 | if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) | ||
| 153 | ret = m5mols_capture_error_handler(info, timeout); | ||
| 154 | } | ||
| 155 | if (!ret) | ||
| 156 | ret = m5mols_lock_3a(info, false); | ||
| 157 | if (ret) | ||
| 158 | return ret; | ||
| 159 | /* | ||
| 160 | * Starting capture. Setting capture frame count and resolution and | ||
| 161 | * the format(available format: JPEG, Bayer RAW, YUV). | ||
| 162 | * | ||
| 163 | * 1) select single or multi(enable to 25), format, size | ||
| 164 | * 2) set interrupt | ||
| 165 | * 3) start capture(for main image, now) | ||
| 166 | * 4) get information | ||
| 167 | * 5) notify file size to v4l2 device(e.g, to s5p-fimc v4l2 device) | ||
| 168 | */ | ||
| 169 | ret = m5mols_write(sd, CAPC_SEL_FRAME, 1); | ||
| 170 | if (!ret) | ||
| 171 | ret = m5mols_write(sd, CAPP_YUVOUT_MAIN, REG_JPEG); | ||
| 172 | if (!ret) | ||
| 173 | ret = m5mols_write(sd, CAPP_MAIN_IMAGE_SIZE, resolution); | ||
| 174 | if (!ret) | ||
| 175 | ret = m5mols_enable_interrupt(sd, REG_INT_CAPTURE); | ||
| 176 | if (!ret) | ||
| 177 | ret = m5mols_write(sd, CAPC_START, REG_CAP_START_MAIN); | ||
| 178 | if (!ret) { | ||
| 179 | /* Wait for the capture completion interrupt */ | ||
| 180 | timeout = wait_event_interruptible_timeout(info->irq_waitq, | ||
| 181 | test_bit(ST_CAPT_IRQ, &info->flags), | ||
| 182 | msecs_to_jiffies(2000)); | ||
| 183 | if (test_and_clear_bit(ST_CAPT_IRQ, &info->flags)) { | ||
| 184 | ret = m5mols_capture_info(info); | ||
| 185 | if (!ret) | ||
| 186 | v4l2_subdev_notify(sd, 0, &info->cap.total); | ||
| 187 | } | ||
| 188 | } | ||
| 189 | |||
| 190 | return m5mols_capture_error_handler(info, timeout); | ||
| 191 | } | ||
diff --git a/drivers/media/video/m5mols/m5mols_controls.c b/drivers/media/video/m5mols/m5mols_controls.c new file mode 100644 index 000000000000..817c16fec368 --- /dev/null +++ b/drivers/media/video/m5mols/m5mols_controls.c | |||
| @@ -0,0 +1,299 @@ | |||
| 1 | /* | ||
| 2 | * Controls for M-5MOLS 8M Pixel camera sensor with ISP | ||
| 3 | * | ||
| 4 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | ||
| 5 | * Author: HeungJun Kim, riverful.kim@samsung.com | ||
| 6 | * | ||
| 7 | * Copyright (C) 2009 Samsung Electronics Co., Ltd. | ||
| 8 | * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License as published by | ||
| 12 | * the Free Software Foundation; either version 2 of the License, or | ||
| 13 | * (at your option) any later version. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/i2c.h> | ||
| 17 | #include <linux/delay.h> | ||
| 18 | #include <linux/videodev2.h> | ||
| 19 | #include <media/v4l2-ctrls.h> | ||
| 20 | |||
| 21 | #include "m5mols.h" | ||
| 22 | #include "m5mols_reg.h" | ||
| 23 | |||
| 24 | static struct m5mols_scenemode m5mols_default_scenemode[] = { | ||
| 25 | [REG_SCENE_NORMAL] = { | ||
| 26 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
| 27 | REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | ||
| 28 | REG_AF_NORMAL, REG_FD_OFF, | ||
| 29 | REG_MCC_NORMAL, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
| 30 | 5, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | ||
| 31 | }, | ||
| 32 | [REG_SCENE_PORTRAIT] = { | ||
| 33 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
| 34 | REG_CHROMA_ON, 3, REG_EDGE_ON, 4, | ||
| 35 | REG_AF_NORMAL, BIT_FD_EN | BIT_FD_DRAW_FACE_FRAME, | ||
| 36 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
| 37 | 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | ||
| 38 | }, | ||
| 39 | [REG_SCENE_LANDSCAPE] = { | ||
| 40 | REG_AE_ALL, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
| 41 | REG_CHROMA_ON, 4, REG_EDGE_ON, 6, | ||
| 42 | REG_AF_NORMAL, REG_FD_OFF, | ||
| 43 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
| 44 | 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | ||
| 45 | }, | ||
| 46 | [REG_SCENE_SPORTS] = { | ||
| 47 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
| 48 | REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | ||
| 49 | REG_AF_NORMAL, REG_FD_OFF, | ||
| 50 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
| 51 | 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | ||
| 52 | }, | ||
| 53 | [REG_SCENE_PARTY_INDOOR] = { | ||
| 54 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
| 55 | REG_CHROMA_ON, 4, REG_EDGE_ON, 5, | ||
| 56 | REG_AF_NORMAL, REG_FD_OFF, | ||
| 57 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
| 58 | 6, REG_ISO_200, REG_CAP_NONE, REG_WDR_OFF, | ||
| 59 | }, | ||
| 60 | [REG_SCENE_BEACH_SNOW] = { | ||
| 61 | REG_AE_CENTER, REG_AE_INDEX_10_POS, REG_AWB_AUTO, 0, | ||
| 62 | REG_CHROMA_ON, 4, REG_EDGE_ON, 5, | ||
| 63 | REG_AF_NORMAL, REG_FD_OFF, | ||
| 64 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
| 65 | 6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF, | ||
| 66 | }, | ||
| 67 | [REG_SCENE_SUNSET] = { | ||
| 68 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET, | ||
| 69 | REG_AWB_DAYLIGHT, | ||
| 70 | REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | ||
| 71 | REG_AF_NORMAL, REG_FD_OFF, | ||
| 72 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
| 73 | 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | ||
| 74 | }, | ||
| 75 | [REG_SCENE_DAWN_DUSK] = { | ||
| 76 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_PRESET, | ||
| 77 | REG_AWB_FLUORESCENT_1, | ||
| 78 | REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | ||
| 79 | REG_AF_NORMAL, REG_FD_OFF, | ||
| 80 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
| 81 | 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | ||
| 82 | }, | ||
| 83 | [REG_SCENE_FALL] = { | ||
| 84 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
| 85 | REG_CHROMA_ON, 5, REG_EDGE_ON, 5, | ||
| 86 | REG_AF_NORMAL, REG_FD_OFF, | ||
| 87 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
| 88 | 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | ||
| 89 | }, | ||
| 90 | [REG_SCENE_NIGHT] = { | ||
| 91 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
| 92 | REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | ||
| 93 | REG_AF_NORMAL, REG_FD_OFF, | ||
| 94 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
| 95 | 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | ||
| 96 | }, | ||
| 97 | [REG_SCENE_AGAINST_LIGHT] = { | ||
| 98 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
| 99 | REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | ||
| 100 | REG_AF_NORMAL, REG_FD_OFF, | ||
| 101 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
| 102 | 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | ||
| 103 | }, | ||
| 104 | [REG_SCENE_FIRE] = { | ||
| 105 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
| 106 | REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | ||
| 107 | REG_AF_NORMAL, REG_FD_OFF, | ||
| 108 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
| 109 | 6, REG_ISO_50, REG_CAP_NONE, REG_WDR_OFF, | ||
| 110 | }, | ||
| 111 | [REG_SCENE_TEXT] = { | ||
| 112 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
| 113 | REG_CHROMA_ON, 3, REG_EDGE_ON, 7, | ||
| 114 | REG_AF_MACRO, REG_FD_OFF, | ||
| 115 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
| 116 | 6, REG_ISO_AUTO, REG_CAP_ANTI_SHAKE, REG_WDR_ON, | ||
| 117 | }, | ||
| 118 | [REG_SCENE_CANDLE] = { | ||
| 119 | REG_AE_CENTER, REG_AE_INDEX_00, REG_AWB_AUTO, 0, | ||
| 120 | REG_CHROMA_ON, 3, REG_EDGE_ON, 5, | ||
| 121 | REG_AF_NORMAL, REG_FD_OFF, | ||
| 122 | REG_MCC_OFF, REG_LIGHT_OFF, REG_FLASH_OFF, | ||
| 123 | 6, REG_ISO_AUTO, REG_CAP_NONE, REG_WDR_OFF, | ||
| 124 | }, | ||
| 125 | }; | ||
| 126 | |||
| 127 | /** | ||
| 128 | * m5mols_do_scenemode() - Change current scenemode | ||
| 129 | * @mode: Desired mode of the scenemode | ||
| 130 | * | ||
| 131 | * WARNING: The execution order is important. Do not change the order. | ||
| 132 | */ | ||
| 133 | int m5mols_do_scenemode(struct m5mols_info *info, u32 mode) | ||
| 134 | { | ||
| 135 | struct v4l2_subdev *sd = &info->sd; | ||
| 136 | struct m5mols_scenemode scenemode = m5mols_default_scenemode[mode]; | ||
| 137 | int ret; | ||
| 138 | |||
| 139 | if (mode > REG_SCENE_CANDLE) | ||
| 140 | return -EINVAL; | ||
| 141 | |||
| 142 | ret = m5mols_lock_3a(info, false); | ||
| 143 | if (!ret) | ||
| 144 | ret = m5mols_write(sd, AE_EV_PRESET_MONITOR, mode); | ||
| 145 | if (!ret) | ||
| 146 | ret = m5mols_write(sd, AE_EV_PRESET_CAPTURE, mode); | ||
| 147 | if (!ret) | ||
| 148 | ret = m5mols_write(sd, AE_MODE, scenemode.metering); | ||
| 149 | if (!ret) | ||
| 150 | ret = m5mols_write(sd, AE_INDEX, scenemode.ev_bias); | ||
| 151 | if (!ret) | ||
| 152 | ret = m5mols_write(sd, AWB_MODE, scenemode.wb_mode); | ||
| 153 | if (!ret) | ||
| 154 | ret = m5mols_write(sd, AWB_MANUAL, scenemode.wb_preset); | ||
| 155 | if (!ret) | ||
| 156 | ret = m5mols_write(sd, MON_CHROMA_EN, scenemode.chroma_en); | ||
| 157 | if (!ret) | ||
| 158 | ret = m5mols_write(sd, MON_CHROMA_LVL, scenemode.chroma_lvl); | ||
| 159 | if (!ret) | ||
| 160 | ret = m5mols_write(sd, MON_EDGE_EN, scenemode.edge_en); | ||
| 161 | if (!ret) | ||
| 162 | ret = m5mols_write(sd, MON_EDGE_LVL, scenemode.edge_lvl); | ||
| 163 | if (!ret && is_available_af(info)) | ||
| 164 | ret = m5mols_write(sd, AF_MODE, scenemode.af_range); | ||
| 165 | if (!ret && is_available_af(info)) | ||
| 166 | ret = m5mols_write(sd, FD_CTL, scenemode.fd_mode); | ||
| 167 | if (!ret) | ||
| 168 | ret = m5mols_write(sd, MON_TONE_CTL, scenemode.tone); | ||
| 169 | if (!ret) | ||
| 170 | ret = m5mols_write(sd, AE_ISO, scenemode.iso); | ||
| 171 | if (!ret) | ||
| 172 | ret = m5mols_mode(info, REG_CAPTURE); | ||
| 173 | if (!ret) | ||
| 174 | ret = m5mols_write(sd, CAPP_WDR_EN, scenemode.wdr); | ||
| 175 | if (!ret) | ||
| 176 | ret = m5mols_write(sd, CAPP_MCC_MODE, scenemode.mcc); | ||
| 177 | if (!ret) | ||
| 178 | ret = m5mols_write(sd, CAPP_LIGHT_CTRL, scenemode.light); | ||
| 179 | if (!ret) | ||
| 180 | ret = m5mols_write(sd, CAPP_FLASH_CTRL, scenemode.flash); | ||
| 181 | if (!ret) | ||
| 182 | ret = m5mols_write(sd, CAPC_MODE, scenemode.capt_mode); | ||
| 183 | if (!ret) | ||
| 184 | ret = m5mols_mode(info, REG_MONITOR); | ||
| 185 | |||
| 186 | return ret; | ||
| 187 | } | ||
| 188 | |||
| 189 | static int m5mols_lock_ae(struct m5mols_info *info, bool lock) | ||
| 190 | { | ||
| 191 | int ret = 0; | ||
| 192 | |||
| 193 | if (info->lock_ae != lock) | ||
| 194 | ret = m5mols_write(&info->sd, AE_LOCK, | ||
| 195 | lock ? REG_AE_LOCK : REG_AE_UNLOCK); | ||
| 196 | if (!ret) | ||
| 197 | info->lock_ae = lock; | ||
| 198 | |||
| 199 | return ret; | ||
| 200 | } | ||
| 201 | |||
| 202 | static int m5mols_lock_awb(struct m5mols_info *info, bool lock) | ||
| 203 | { | ||
| 204 | int ret = 0; | ||
| 205 | |||
| 206 | if (info->lock_awb != lock) | ||
| 207 | ret = m5mols_write(&info->sd, AWB_LOCK, | ||
| 208 | lock ? REG_AWB_LOCK : REG_AWB_UNLOCK); | ||
| 209 | if (!ret) | ||
| 210 | info->lock_awb = lock; | ||
| 211 | |||
| 212 | return ret; | ||
| 213 | } | ||
| 214 | |||
| 215 | /* m5mols_lock_3a() - Lock 3A(Auto Exposure, Auto Whitebalance, Auto Focus) */ | ||
| 216 | int m5mols_lock_3a(struct m5mols_info *info, bool lock) | ||
| 217 | { | ||
| 218 | int ret; | ||
| 219 | |||
| 220 | ret = m5mols_lock_ae(info, lock); | ||
| 221 | if (!ret) | ||
| 222 | ret = m5mols_lock_awb(info, lock); | ||
| 223 | /* Don't need to handle unlocking AF */ | ||
| 224 | if (!ret && is_available_af(info) && lock) | ||
| 225 | ret = m5mols_write(&info->sd, AF_EXECUTE, REG_AF_STOP); | ||
| 226 | |||
| 227 | return ret; | ||
| 228 | } | ||
| 229 | |||
| 230 | /* m5mols_set_ctrl() - The main s_ctrl function called by m5mols_set_ctrl() */ | ||
| 231 | int m5mols_set_ctrl(struct v4l2_ctrl *ctrl) | ||
| 232 | { | ||
| 233 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
| 234 | struct m5mols_info *info = to_m5mols(sd); | ||
| 235 | int ret; | ||
| 236 | |||
| 237 | switch (ctrl->id) { | ||
| 238 | case V4L2_CID_ZOOM_ABSOLUTE: | ||
| 239 | return m5mols_write(sd, MON_ZOOM, ctrl->val); | ||
| 240 | |||
| 241 | case V4L2_CID_EXPOSURE_AUTO: | ||
| 242 | ret = m5mols_lock_ae(info, | ||
| 243 | ctrl->val == V4L2_EXPOSURE_AUTO ? false : true); | ||
| 244 | if (!ret && ctrl->val == V4L2_EXPOSURE_AUTO) | ||
| 245 | ret = m5mols_write(sd, AE_MODE, REG_AE_ALL); | ||
| 246 | if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) { | ||
| 247 | int val = info->exposure->val; | ||
| 248 | ret = m5mols_write(sd, AE_MODE, REG_AE_OFF); | ||
| 249 | if (!ret) | ||
| 250 | ret = m5mols_write(sd, AE_MAN_GAIN_MON, val); | ||
| 251 | if (!ret) | ||
| 252 | ret = m5mols_write(sd, AE_MAN_GAIN_CAP, val); | ||
| 253 | } | ||
| 254 | return ret; | ||
| 255 | |||
| 256 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
| 257 | ret = m5mols_lock_awb(info, ctrl->val ? false : true); | ||
| 258 | if (!ret) | ||
| 259 | ret = m5mols_write(sd, AWB_MODE, ctrl->val ? | ||
| 260 | REG_AWB_AUTO : REG_AWB_PRESET); | ||
| 261 | return ret; | ||
| 262 | |||
| 263 | case V4L2_CID_SATURATION: | ||
| 264 | ret = m5mols_write(sd, MON_CHROMA_LVL, ctrl->val); | ||
| 265 | if (!ret) | ||
| 266 | ret = m5mols_write(sd, MON_CHROMA_EN, REG_CHROMA_ON); | ||
| 267 | return ret; | ||
| 268 | |||
| 269 | case V4L2_CID_COLORFX: | ||
| 270 | /* | ||
| 271 | * This control uses two kinds of registers: normal & color. | ||
| 272 | * The normal effect belongs to category 1, while the color | ||
| 273 | * one belongs to category 2. | ||
| 274 | * | ||
| 275 | * The normal effect uses one register: CAT1_EFFECT. | ||
| 276 | * The color effect uses three registers: | ||
| 277 | * CAT2_COLOR_EFFECT, CAT2_CFIXR, CAT2_CFIXB. | ||
| 278 | */ | ||
| 279 | ret = m5mols_write(sd, PARM_EFFECT, | ||
| 280 | ctrl->val == V4L2_COLORFX_NEGATIVE ? REG_EFFECT_NEGA : | ||
| 281 | ctrl->val == V4L2_COLORFX_EMBOSS ? REG_EFFECT_EMBOSS : | ||
| 282 | REG_EFFECT_OFF); | ||
| 283 | if (!ret) | ||
| 284 | ret = m5mols_write(sd, MON_EFFECT, | ||
| 285 | ctrl->val == V4L2_COLORFX_SEPIA ? | ||
| 286 | REG_COLOR_EFFECT_ON : REG_COLOR_EFFECT_OFF); | ||
| 287 | if (!ret) | ||
| 288 | ret = m5mols_write(sd, MON_CFIXR, | ||
| 289 | ctrl->val == V4L2_COLORFX_SEPIA ? | ||
| 290 | REG_CFIXR_SEPIA : 0); | ||
| 291 | if (!ret) | ||
| 292 | ret = m5mols_write(sd, MON_CFIXB, | ||
| 293 | ctrl->val == V4L2_COLORFX_SEPIA ? | ||
| 294 | REG_CFIXB_SEPIA : 0); | ||
| 295 | return ret; | ||
| 296 | } | ||
| 297 | |||
| 298 | return -EINVAL; | ||
| 299 | } | ||
diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c new file mode 100644 index 000000000000..76eac26e84ae --- /dev/null +++ b/drivers/media/video/m5mols/m5mols_core.c | |||
| @@ -0,0 +1,1004 @@ | |||
| 1 | /* | ||
| 2 | * Driver for M-5MOLS 8M Pixel camera sensor with ISP | ||
| 3 | * | ||
| 4 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | ||
| 5 | * Author: HeungJun Kim, riverful.kim@samsung.com | ||
| 6 | * | ||
| 7 | * Copyright (C) 2009 Samsung Electronics Co., Ltd. | ||
| 8 | * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License as published by | ||
| 12 | * the Free Software Foundation; either version 2 of the License, or | ||
| 13 | * (at your option) any later version. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/i2c.h> | ||
| 17 | #include <linux/slab.h> | ||
| 18 | #include <linux/irq.h> | ||
| 19 | #include <linux/interrupt.h> | ||
| 20 | #include <linux/delay.h> | ||
| 21 | #include <linux/version.h> | ||
| 22 | #include <linux/gpio.h> | ||
| 23 | #include <linux/regulator/consumer.h> | ||
| 24 | #include <linux/videodev2.h> | ||
| 25 | #include <media/v4l2-ctrls.h> | ||
| 26 | #include <media/v4l2-device.h> | ||
| 27 | #include <media/v4l2-subdev.h> | ||
| 28 | #include <media/m5mols.h> | ||
| 29 | |||
| 30 | #include "m5mols.h" | ||
| 31 | #include "m5mols_reg.h" | ||
| 32 | |||
| 33 | int m5mols_debug; | ||
| 34 | module_param(m5mols_debug, int, 0644); | ||
| 35 | |||
| 36 | #define MODULE_NAME "M5MOLS" | ||
| 37 | #define M5MOLS_I2C_CHECK_RETRY 500 | ||
| 38 | |||
| 39 | /* The regulator consumer names for external voltage regulators */ | ||
| 40 | static struct regulator_bulk_data supplies[] = { | ||
| 41 | { | ||
| 42 | .supply = "core", /* ARM core power, 1.2V */ | ||
| 43 | }, { | ||
| 44 | .supply = "dig_18", /* digital power 1, 1.8V */ | ||
| 45 | }, { | ||
| 46 | .supply = "d_sensor", /* sensor power 1, 1.8V */ | ||
| 47 | }, { | ||
| 48 | .supply = "dig_28", /* digital power 2, 2.8V */ | ||
| 49 | }, { | ||
| 50 | .supply = "a_sensor", /* analog power */ | ||
| 51 | }, { | ||
| 52 | .supply = "dig_12", /* digital power 3, 1.2V */ | ||
| 53 | }, | ||
| 54 | }; | ||
| 55 | |||
| 56 | static struct v4l2_mbus_framefmt m5mols_default_ffmt[M5MOLS_RESTYPE_MAX] = { | ||
| 57 | [M5MOLS_RESTYPE_MONITOR] = { | ||
| 58 | .width = 1920, | ||
| 59 | .height = 1080, | ||
| 60 | .code = V4L2_MBUS_FMT_VYUY8_2X8, | ||
| 61 | .field = V4L2_FIELD_NONE, | ||
| 62 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
| 63 | }, | ||
| 64 | [M5MOLS_RESTYPE_CAPTURE] = { | ||
| 65 | .width = 1920, | ||
| 66 | .height = 1080, | ||
| 67 | .code = V4L2_MBUS_FMT_JPEG_1X8, | ||
| 68 | .field = V4L2_FIELD_NONE, | ||
| 69 | .colorspace = V4L2_COLORSPACE_JPEG, | ||
| 70 | }, | ||
| 71 | }; | ||
| 72 | #define SIZE_DEFAULT_FFMT ARRAY_SIZE(m5mols_default_ffmt) | ||
| 73 | |||
| 74 | static const struct m5mols_resolution m5mols_reg_res[] = { | ||
| 75 | { 0x01, M5MOLS_RESTYPE_MONITOR, 128, 96 }, /* SUB-QCIF */ | ||
| 76 | { 0x03, M5MOLS_RESTYPE_MONITOR, 160, 120 }, /* QQVGA */ | ||
| 77 | { 0x05, M5MOLS_RESTYPE_MONITOR, 176, 144 }, /* QCIF */ | ||
| 78 | { 0x06, M5MOLS_RESTYPE_MONITOR, 176, 176 }, | ||
| 79 | { 0x08, M5MOLS_RESTYPE_MONITOR, 240, 320 }, /* QVGA */ | ||
| 80 | { 0x09, M5MOLS_RESTYPE_MONITOR, 320, 240 }, /* QVGA */ | ||
| 81 | { 0x0c, M5MOLS_RESTYPE_MONITOR, 240, 400 }, /* WQVGA */ | ||
| 82 | { 0x0d, M5MOLS_RESTYPE_MONITOR, 400, 240 }, /* WQVGA */ | ||
| 83 | { 0x0e, M5MOLS_RESTYPE_MONITOR, 352, 288 }, /* CIF */ | ||
| 84 | { 0x13, M5MOLS_RESTYPE_MONITOR, 480, 360 }, | ||
| 85 | { 0x15, M5MOLS_RESTYPE_MONITOR, 640, 360 }, /* qHD */ | ||
| 86 | { 0x17, M5MOLS_RESTYPE_MONITOR, 640, 480 }, /* VGA */ | ||
| 87 | { 0x18, M5MOLS_RESTYPE_MONITOR, 720, 480 }, | ||
| 88 | { 0x1a, M5MOLS_RESTYPE_MONITOR, 800, 480 }, /* WVGA */ | ||
| 89 | { 0x1f, M5MOLS_RESTYPE_MONITOR, 800, 600 }, /* SVGA */ | ||
| 90 | { 0x21, M5MOLS_RESTYPE_MONITOR, 1280, 720 }, /* HD */ | ||
| 91 | { 0x25, M5MOLS_RESTYPE_MONITOR, 1920, 1080 }, /* 1080p */ | ||
| 92 | { 0x29, M5MOLS_RESTYPE_MONITOR, 3264, 2448 }, /* 2.63fps 8M */ | ||
| 93 | { 0x39, M5MOLS_RESTYPE_MONITOR, 800, 602 }, /* AHS_MON debug */ | ||
| 94 | |||
| 95 | { 0x02, M5MOLS_RESTYPE_CAPTURE, 320, 240 }, /* QVGA */ | ||
| 96 | { 0x04, M5MOLS_RESTYPE_CAPTURE, 400, 240 }, /* WQVGA */ | ||
| 97 | { 0x07, M5MOLS_RESTYPE_CAPTURE, 480, 360 }, | ||
| 98 | { 0x08, M5MOLS_RESTYPE_CAPTURE, 640, 360 }, /* qHD */ | ||
| 99 | { 0x09, M5MOLS_RESTYPE_CAPTURE, 640, 480 }, /* VGA */ | ||
| 100 | { 0x0a, M5MOLS_RESTYPE_CAPTURE, 800, 480 }, /* WVGA */ | ||
| 101 | { 0x10, M5MOLS_RESTYPE_CAPTURE, 1280, 720 }, /* HD */ | ||
| 102 | { 0x14, M5MOLS_RESTYPE_CAPTURE, 1280, 960 }, /* 1M */ | ||
| 103 | { 0x17, M5MOLS_RESTYPE_CAPTURE, 1600, 1200 }, /* 2M */ | ||
| 104 | { 0x19, M5MOLS_RESTYPE_CAPTURE, 1920, 1080 }, /* Full-HD */ | ||
| 105 | { 0x1a, M5MOLS_RESTYPE_CAPTURE, 2048, 1152 }, /* 3Mega */ | ||
| 106 | { 0x1b, M5MOLS_RESTYPE_CAPTURE, 2048, 1536 }, | ||
| 107 | { 0x1c, M5MOLS_RESTYPE_CAPTURE, 2560, 1440 }, /* 4Mega */ | ||
| 108 | { 0x1d, M5MOLS_RESTYPE_CAPTURE, 2560, 1536 }, | ||
| 109 | { 0x1f, M5MOLS_RESTYPE_CAPTURE, 2560, 1920 }, /* 5Mega */ | ||
| 110 | { 0x21, M5MOLS_RESTYPE_CAPTURE, 3264, 1836 }, /* 6Mega */ | ||
| 111 | { 0x22, M5MOLS_RESTYPE_CAPTURE, 3264, 1960 }, | ||
| 112 | { 0x25, M5MOLS_RESTYPE_CAPTURE, 3264, 2448 }, /* 8Mega */ | ||
| 113 | }; | ||
| 114 | |||
| 115 | /** | ||
| 116 | * m5mols_swap_byte - an byte array to integer conversion function | ||
| 117 | * @size: size in bytes of I2C packet defined in the M-5MOLS datasheet | ||
| 118 | * | ||
| 119 | * Convert I2C data byte array with performing any required byte | ||
| 120 | * reordering to assure proper values for each data type, regardless | ||
| 121 | * of the architecture endianness. | ||
| 122 | */ | ||
| 123 | static u32 m5mols_swap_byte(u8 *data, u8 length) | ||
| 124 | { | ||
| 125 | if (length == 1) | ||
| 126 | return *data; | ||
| 127 | else if (length == 2) | ||
| 128 | return be16_to_cpu(*((u16 *)data)); | ||
| 129 | else | ||
| 130 | return be32_to_cpu(*((u32 *)data)); | ||
| 131 | } | ||
| 132 | |||
| 133 | /** | ||
| 134 | * m5mols_read - I2C read function | ||
| 135 | * @reg: combination of size, category and command for the I2C packet | ||
| 136 | * @val: read value | ||
| 137 | */ | ||
| 138 | int m5mols_read(struct v4l2_subdev *sd, u32 reg, u32 *val) | ||
| 139 | { | ||
| 140 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 141 | u8 rbuf[M5MOLS_I2C_MAX_SIZE + 1]; | ||
| 142 | u8 size = I2C_SIZE(reg); | ||
| 143 | u8 category = I2C_CATEGORY(reg); | ||
| 144 | u8 cmd = I2C_COMMAND(reg); | ||
| 145 | struct i2c_msg msg[2]; | ||
| 146 | u8 wbuf[5]; | ||
| 147 | int ret; | ||
| 148 | |||
| 149 | if (!client->adapter) | ||
| 150 | return -ENODEV; | ||
| 151 | |||
| 152 | if (size != 1 && size != 2 && size != 4) { | ||
| 153 | v4l2_err(sd, "Wrong data size\n"); | ||
| 154 | return -EINVAL; | ||
| 155 | } | ||
| 156 | |||
| 157 | msg[0].addr = client->addr; | ||
| 158 | msg[0].flags = 0; | ||
| 159 | msg[0].len = 5; | ||
| 160 | msg[0].buf = wbuf; | ||
| 161 | wbuf[0] = 5; | ||
| 162 | wbuf[1] = M5MOLS_BYTE_READ; | ||
| 163 | wbuf[2] = category; | ||
| 164 | wbuf[3] = cmd; | ||
| 165 | wbuf[4] = size; | ||
| 166 | |||
| 167 | msg[1].addr = client->addr; | ||
| 168 | msg[1].flags = I2C_M_RD; | ||
| 169 | msg[1].len = size + 1; | ||
| 170 | msg[1].buf = rbuf; | ||
| 171 | |||
| 172 | /* minimum stabilization time */ | ||
| 173 | usleep_range(200, 200); | ||
| 174 | |||
| 175 | ret = i2c_transfer(client->adapter, msg, 2); | ||
| 176 | if (ret < 0) { | ||
| 177 | v4l2_err(sd, "read failed: size:%d cat:%02x cmd:%02x. %d\n", | ||
| 178 | size, category, cmd, ret); | ||
| 179 | return ret; | ||
| 180 | } | ||
| 181 | |||
| 182 | *val = m5mols_swap_byte(&rbuf[1], size); | ||
| 183 | |||
| 184 | return 0; | ||
| 185 | } | ||
| 186 | |||
| 187 | /** | ||
| 188 | * m5mols_write - I2C command write function | ||
| 189 | * @reg: combination of size, category and command for the I2C packet | ||
| 190 | * @val: value to write | ||
| 191 | */ | ||
| 192 | int m5mols_write(struct v4l2_subdev *sd, u32 reg, u32 val) | ||
| 193 | { | ||
| 194 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 195 | u8 wbuf[M5MOLS_I2C_MAX_SIZE + 4]; | ||
| 196 | u8 category = I2C_CATEGORY(reg); | ||
| 197 | u8 cmd = I2C_COMMAND(reg); | ||
| 198 | u8 size = I2C_SIZE(reg); | ||
| 199 | u32 *buf = (u32 *)&wbuf[4]; | ||
| 200 | struct i2c_msg msg[1]; | ||
| 201 | int ret; | ||
| 202 | |||
| 203 | if (!client->adapter) | ||
| 204 | return -ENODEV; | ||
| 205 | |||
| 206 | if (size != 1 && size != 2 && size != 4) { | ||
| 207 | v4l2_err(sd, "Wrong data size\n"); | ||
| 208 | return -EINVAL; | ||
| 209 | } | ||
| 210 | |||
| 211 | msg->addr = client->addr; | ||
| 212 | msg->flags = 0; | ||
| 213 | msg->len = (u16)size + 4; | ||
| 214 | msg->buf = wbuf; | ||
| 215 | wbuf[0] = size + 4; | ||
| 216 | wbuf[1] = M5MOLS_BYTE_WRITE; | ||
| 217 | wbuf[2] = category; | ||
| 218 | wbuf[3] = cmd; | ||
| 219 | |||
| 220 | *buf = m5mols_swap_byte((u8 *)&val, size); | ||
| 221 | |||
| 222 | usleep_range(200, 200); | ||
| 223 | |||
| 224 | ret = i2c_transfer(client->adapter, msg, 1); | ||
| 225 | if (ret < 0) { | ||
| 226 | v4l2_err(sd, "write failed: size:%d cat:%02x cmd:%02x. %d\n", | ||
| 227 | size, category, cmd, ret); | ||
| 228 | return ret; | ||
| 229 | } | ||
| 230 | |||
| 231 | return 0; | ||
| 232 | } | ||
| 233 | |||
| 234 | int m5mols_busy(struct v4l2_subdev *sd, u8 category, u8 cmd, u32 mask) | ||
| 235 | { | ||
| 236 | u32 busy, i; | ||
| 237 | int ret; | ||
| 238 | |||
| 239 | for (i = 0; i < M5MOLS_I2C_CHECK_RETRY; i++) { | ||
| 240 | ret = m5mols_read(sd, I2C_REG(category, cmd, 1), &busy); | ||
| 241 | if (ret < 0) | ||
| 242 | return ret; | ||
| 243 | if ((busy & mask) == mask) | ||
| 244 | return 0; | ||
| 245 | } | ||
| 246 | return -EBUSY; | ||
| 247 | } | ||
| 248 | |||
| 249 | /** | ||
| 250 | * m5mols_enable_interrupt - Clear interrupt pending bits and unmask interrupts | ||
| 251 | * | ||
| 252 | * Before writing desired interrupt value the INT_FACTOR register should | ||
| 253 | * be read to clear pending interrupts. | ||
| 254 | */ | ||
| 255 | int m5mols_enable_interrupt(struct v4l2_subdev *sd, u32 reg) | ||
| 256 | { | ||
| 257 | struct m5mols_info *info = to_m5mols(sd); | ||
| 258 | u32 mask = is_available_af(info) ? REG_INT_AF : 0; | ||
| 259 | u32 dummy; | ||
| 260 | int ret; | ||
| 261 | |||
| 262 | ret = m5mols_read(sd, SYSTEM_INT_FACTOR, &dummy); | ||
| 263 | if (!ret) | ||
| 264 | ret = m5mols_write(sd, SYSTEM_INT_ENABLE, reg & ~mask); | ||
| 265 | return ret; | ||
| 266 | } | ||
| 267 | |||
| 268 | /** | ||
| 269 | * m5mols_reg_mode - Write the mode and check busy status | ||
| 270 | * | ||
| 271 | * It always accompanies a little delay changing the M-5MOLS mode, so it is | ||
| 272 | * needed checking current busy status to guarantee right mode. | ||
| 273 | */ | ||
| 274 | static int m5mols_reg_mode(struct v4l2_subdev *sd, u32 mode) | ||
| 275 | { | ||
| 276 | int ret = m5mols_write(sd, SYSTEM_SYSMODE, mode); | ||
| 277 | |||
| 278 | return ret ? ret : m5mols_busy(sd, CAT_SYSTEM, CAT0_SYSMODE, mode); | ||
| 279 | } | ||
| 280 | |||
| 281 | /** | ||
| 282 | * m5mols_mode - manage the M-5MOLS's mode | ||
| 283 | * @mode: the required operation mode | ||
| 284 | * | ||
| 285 | * The commands of M-5MOLS are grouped into specific modes. Each functionality | ||
| 286 | * can be guaranteed only when the sensor is operating in mode which which | ||
| 287 | * a command belongs to. | ||
| 288 | */ | ||
| 289 | int m5mols_mode(struct m5mols_info *info, u32 mode) | ||
| 290 | { | ||
| 291 | struct v4l2_subdev *sd = &info->sd; | ||
| 292 | int ret = -EINVAL; | ||
| 293 | u32 reg; | ||
| 294 | |||
| 295 | if (mode < REG_PARAMETER && mode > REG_CAPTURE) | ||
| 296 | return ret; | ||
| 297 | |||
| 298 | ret = m5mols_read(sd, SYSTEM_SYSMODE, ®); | ||
| 299 | if ((!ret && reg == mode) || ret) | ||
| 300 | return ret; | ||
| 301 | |||
| 302 | switch (reg) { | ||
| 303 | case REG_PARAMETER: | ||
| 304 | ret = m5mols_reg_mode(sd, REG_MONITOR); | ||
| 305 | if (!ret && mode == REG_MONITOR) | ||
| 306 | break; | ||
| 307 | if (!ret) | ||
| 308 | ret = m5mols_reg_mode(sd, REG_CAPTURE); | ||
| 309 | break; | ||
| 310 | |||
| 311 | case REG_MONITOR: | ||
| 312 | if (mode == REG_PARAMETER) { | ||
| 313 | ret = m5mols_reg_mode(sd, REG_PARAMETER); | ||
| 314 | break; | ||
| 315 | } | ||
| 316 | |||
| 317 | ret = m5mols_reg_mode(sd, REG_CAPTURE); | ||
| 318 | break; | ||
| 319 | |||
| 320 | case REG_CAPTURE: | ||
| 321 | ret = m5mols_reg_mode(sd, REG_MONITOR); | ||
| 322 | if (!ret && mode == REG_MONITOR) | ||
| 323 | break; | ||
| 324 | if (!ret) | ||
| 325 | ret = m5mols_reg_mode(sd, REG_PARAMETER); | ||
| 326 | break; | ||
| 327 | |||
| 328 | default: | ||
| 329 | v4l2_warn(sd, "Wrong mode: %d\n", mode); | ||
| 330 | } | ||
| 331 | |||
| 332 | if (!ret) | ||
| 333 | info->mode = mode; | ||
| 334 | |||
| 335 | return ret; | ||
| 336 | } | ||
| 337 | |||
| 338 | /** | ||
| 339 | * m5mols_get_version - retrieve full revisions information of M-5MOLS | ||
| 340 | * | ||
| 341 | * The version information includes revisions of hardware and firmware, | ||
| 342 | * AutoFocus alghorithm version and the version string. | ||
| 343 | */ | ||
| 344 | static int m5mols_get_version(struct v4l2_subdev *sd) | ||
| 345 | { | ||
| 346 | struct m5mols_info *info = to_m5mols(sd); | ||
| 347 | union { | ||
| 348 | struct m5mols_version ver; | ||
| 349 | u8 bytes[VERSION_SIZE]; | ||
| 350 | } version; | ||
| 351 | u32 *value; | ||
| 352 | u8 cmd = CAT0_VER_CUSTOMER; | ||
| 353 | int ret; | ||
| 354 | |||
| 355 | do { | ||
| 356 | value = (u32 *)&version.bytes[cmd]; | ||
| 357 | ret = m5mols_read(sd, SYSTEM_CMD(cmd), value); | ||
| 358 | if (ret) | ||
| 359 | return ret; | ||
| 360 | } while (cmd++ != CAT0_VER_AWB); | ||
| 361 | |||
| 362 | do { | ||
| 363 | value = (u32 *)&version.bytes[cmd]; | ||
| 364 | ret = m5mols_read(sd, SYSTEM_VER_STRING, value); | ||
| 365 | if (ret) | ||
| 366 | return ret; | ||
| 367 | if (cmd >= VERSION_SIZE - 1) | ||
| 368 | return -EINVAL; | ||
| 369 | } while (version.bytes[cmd++]); | ||
| 370 | |||
| 371 | value = (u32 *)&version.bytes[cmd]; | ||
| 372 | ret = m5mols_read(sd, AF_VERSION, value); | ||
| 373 | if (ret) | ||
| 374 | return ret; | ||
| 375 | |||
| 376 | /* store version information swapped for being readable */ | ||
| 377 | info->ver = version.ver; | ||
| 378 | info->ver.fw = be16_to_cpu(info->ver.fw); | ||
| 379 | info->ver.hw = be16_to_cpu(info->ver.hw); | ||
| 380 | info->ver.param = be16_to_cpu(info->ver.param); | ||
| 381 | info->ver.awb = be16_to_cpu(info->ver.awb); | ||
| 382 | |||
| 383 | v4l2_info(sd, "Manufacturer\t[%s]\n", | ||
| 384 | is_manufacturer(info, REG_SAMSUNG_ELECTRO) ? | ||
| 385 | "Samsung Electro-Machanics" : | ||
| 386 | is_manufacturer(info, REG_SAMSUNG_OPTICS) ? | ||
| 387 | "Samsung Fiber-Optics" : | ||
| 388 | is_manufacturer(info, REG_SAMSUNG_TECHWIN) ? | ||
| 389 | "Samsung Techwin" : "None"); | ||
| 390 | v4l2_info(sd, "Customer/Project\t[0x%02x/0x%02x]\n", | ||
| 391 | info->ver.customer, info->ver.project); | ||
| 392 | |||
| 393 | if (!is_available_af(info)) | ||
| 394 | v4l2_info(sd, "No support Auto Focus on this firmware\n"); | ||
| 395 | |||
| 396 | return ret; | ||
| 397 | } | ||
| 398 | |||
| 399 | /** | ||
| 400 | * __find_restype - Lookup M-5MOLS resolution type according to pixel code | ||
| 401 | * @code: pixel code | ||
| 402 | */ | ||
| 403 | static enum m5mols_restype __find_restype(enum v4l2_mbus_pixelcode code) | ||
| 404 | { | ||
| 405 | enum m5mols_restype type = M5MOLS_RESTYPE_MONITOR; | ||
| 406 | |||
| 407 | do { | ||
| 408 | if (code == m5mols_default_ffmt[type].code) | ||
| 409 | return type; | ||
| 410 | } while (type++ != SIZE_DEFAULT_FFMT); | ||
| 411 | |||
| 412 | return 0; | ||
| 413 | } | ||
| 414 | |||
| 415 | /** | ||
| 416 | * __find_resolution - Lookup preset and type of M-5MOLS's resolution | ||
| 417 | * @mf: pixel format to find/negotiate the resolution preset for | ||
| 418 | * @type: M-5MOLS resolution type | ||
| 419 | * @resolution: M-5MOLS resolution preset register value | ||
| 420 | * | ||
| 421 | * Find nearest resolution matching resolution preset and adjust mf | ||
| 422 | * to supported values. | ||
| 423 | */ | ||
| 424 | static int __find_resolution(struct v4l2_subdev *sd, | ||
| 425 | struct v4l2_mbus_framefmt *mf, | ||
| 426 | enum m5mols_restype *type, | ||
| 427 | u32 *resolution) | ||
| 428 | { | ||
| 429 | const struct m5mols_resolution *fsize = &m5mols_reg_res[0]; | ||
| 430 | const struct m5mols_resolution *match = NULL; | ||
| 431 | enum m5mols_restype stype = __find_restype(mf->code); | ||
| 432 | int i = ARRAY_SIZE(m5mols_reg_res); | ||
| 433 | unsigned int min_err = ~0; | ||
| 434 | |||
| 435 | while (i--) { | ||
| 436 | int err; | ||
| 437 | if (stype == fsize->type) { | ||
| 438 | err = abs(fsize->width - mf->width) | ||
| 439 | + abs(fsize->height - mf->height); | ||
| 440 | |||
| 441 | if (err < min_err) { | ||
| 442 | min_err = err; | ||
| 443 | match = fsize; | ||
| 444 | } | ||
| 445 | } | ||
| 446 | fsize++; | ||
| 447 | } | ||
| 448 | if (match) { | ||
| 449 | mf->width = match->width; | ||
| 450 | mf->height = match->height; | ||
| 451 | *resolution = match->reg; | ||
| 452 | *type = stype; | ||
| 453 | return 0; | ||
| 454 | } | ||
| 455 | |||
| 456 | return -EINVAL; | ||
| 457 | } | ||
| 458 | |||
| 459 | static struct v4l2_mbus_framefmt *__find_format(struct m5mols_info *info, | ||
| 460 | struct v4l2_subdev_fh *fh, | ||
| 461 | enum v4l2_subdev_format_whence which, | ||
| 462 | enum m5mols_restype type) | ||
| 463 | { | ||
| 464 | if (which == V4L2_SUBDEV_FORMAT_TRY) | ||
| 465 | return fh ? v4l2_subdev_get_try_format(fh, 0) : NULL; | ||
| 466 | |||
| 467 | return &info->ffmt[type]; | ||
| 468 | } | ||
| 469 | |||
| 470 | static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
| 471 | struct v4l2_subdev_format *fmt) | ||
| 472 | { | ||
| 473 | struct m5mols_info *info = to_m5mols(sd); | ||
| 474 | struct v4l2_mbus_framefmt *format; | ||
| 475 | |||
| 476 | if (fmt->pad != 0) | ||
| 477 | return -EINVAL; | ||
| 478 | |||
| 479 | format = __find_format(info, fh, fmt->which, info->res_type); | ||
| 480 | if (!format) | ||
| 481 | return -EINVAL; | ||
| 482 | |||
| 483 | fmt->format = *format; | ||
| 484 | return 0; | ||
| 485 | } | ||
| 486 | |||
| 487 | static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, | ||
| 488 | struct v4l2_subdev_format *fmt) | ||
| 489 | { | ||
| 490 | struct m5mols_info *info = to_m5mols(sd); | ||
| 491 | struct v4l2_mbus_framefmt *format = &fmt->format; | ||
| 492 | struct v4l2_mbus_framefmt *sfmt; | ||
| 493 | enum m5mols_restype type; | ||
| 494 | u32 resolution = 0; | ||
| 495 | int ret; | ||
| 496 | |||
| 497 | if (fmt->pad != 0) | ||
| 498 | return -EINVAL; | ||
| 499 | |||
| 500 | ret = __find_resolution(sd, format, &type, &resolution); | ||
| 501 | if (ret < 0) | ||
| 502 | return ret; | ||
| 503 | |||
| 504 | sfmt = __find_format(info, fh, fmt->which, type); | ||
| 505 | if (!sfmt) | ||
| 506 | return 0; | ||
| 507 | |||
| 508 | *sfmt = m5mols_default_ffmt[type]; | ||
| 509 | sfmt->width = format->width; | ||
| 510 | sfmt->height = format->height; | ||
| 511 | |||
| 512 | if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | ||
| 513 | info->resolution = resolution; | ||
| 514 | info->code = format->code; | ||
| 515 | info->res_type = type; | ||
| 516 | } | ||
| 517 | |||
| 518 | return 0; | ||
| 519 | } | ||
| 520 | |||
| 521 | static int m5mols_enum_mbus_code(struct v4l2_subdev *sd, | ||
| 522 | struct v4l2_subdev_fh *fh, | ||
| 523 | struct v4l2_subdev_mbus_code_enum *code) | ||
| 524 | { | ||
| 525 | if (!code || code->index >= SIZE_DEFAULT_FFMT) | ||
| 526 | return -EINVAL; | ||
| 527 | |||
| 528 | code->code = m5mols_default_ffmt[code->index].code; | ||
| 529 | |||
| 530 | return 0; | ||
| 531 | } | ||
| 532 | |||
| 533 | static struct v4l2_subdev_pad_ops m5mols_pad_ops = { | ||
| 534 | .enum_mbus_code = m5mols_enum_mbus_code, | ||
| 535 | .get_fmt = m5mols_get_fmt, | ||
| 536 | .set_fmt = m5mols_set_fmt, | ||
| 537 | }; | ||
| 538 | |||
| 539 | /** | ||
| 540 | * m5mols_sync_controls - Apply default scene mode and the current controls | ||
| 541 | * | ||
| 542 | * This is used only streaming for syncing between v4l2_ctrl framework and | ||
| 543 | * m5mols's controls. First, do the scenemode to the sensor, then call | ||
| 544 | * v4l2_ctrl_handler_setup. It can be same between some commands and | ||
| 545 | * the scenemode's in the default v4l2_ctrls. But, such commands of control | ||
| 546 | * should be prior to the scenemode's one. | ||
| 547 | */ | ||
| 548 | int m5mols_sync_controls(struct m5mols_info *info) | ||
| 549 | { | ||
| 550 | int ret = -EINVAL; | ||
| 551 | |||
| 552 | if (!is_ctrl_synced(info)) { | ||
| 553 | ret = m5mols_do_scenemode(info, REG_SCENE_NORMAL); | ||
| 554 | if (ret) | ||
| 555 | return ret; | ||
| 556 | |||
| 557 | v4l2_ctrl_handler_setup(&info->handle); | ||
| 558 | info->ctrl_sync = true; | ||
| 559 | } | ||
| 560 | |||
| 561 | return ret; | ||
| 562 | } | ||
| 563 | |||
| 564 | /** | ||
| 565 | * m5mols_start_monitor - Start the monitor mode | ||
| 566 | * | ||
| 567 | * Before applying the controls setup the resolution and frame rate | ||
| 568 | * in PARAMETER mode, and then switch over to MONITOR mode. | ||
| 569 | */ | ||
| 570 | static int m5mols_start_monitor(struct m5mols_info *info) | ||
| 571 | { | ||
| 572 | struct v4l2_subdev *sd = &info->sd; | ||
| 573 | int ret; | ||
| 574 | |||
| 575 | ret = m5mols_mode(info, REG_PARAMETER); | ||
| 576 | if (!ret) | ||
| 577 | ret = m5mols_write(sd, PARM_MON_SIZE, info->resolution); | ||
| 578 | if (!ret) | ||
| 579 | ret = m5mols_write(sd, PARM_MON_FPS, REG_FPS_30); | ||
| 580 | if (!ret) | ||
| 581 | ret = m5mols_mode(info, REG_MONITOR); | ||
| 582 | if (!ret) | ||
| 583 | ret = m5mols_sync_controls(info); | ||
| 584 | |||
| 585 | return ret; | ||
| 586 | } | ||
| 587 | |||
| 588 | static int m5mols_s_stream(struct v4l2_subdev *sd, int enable) | ||
| 589 | { | ||
| 590 | struct m5mols_info *info = to_m5mols(sd); | ||
| 591 | |||
| 592 | if (enable) { | ||
| 593 | int ret = -EINVAL; | ||
| 594 | |||
| 595 | if (is_code(info->code, M5MOLS_RESTYPE_MONITOR)) | ||
| 596 | ret = m5mols_start_monitor(info); | ||
| 597 | if (is_code(info->code, M5MOLS_RESTYPE_CAPTURE)) | ||
| 598 | ret = m5mols_start_capture(info); | ||
| 599 | |||
| 600 | return ret; | ||
| 601 | } | ||
| 602 | |||
| 603 | return m5mols_mode(info, REG_PARAMETER); | ||
| 604 | } | ||
| 605 | |||
| 606 | static const struct v4l2_subdev_video_ops m5mols_video_ops = { | ||
| 607 | .s_stream = m5mols_s_stream, | ||
| 608 | }; | ||
| 609 | |||
| 610 | static int m5mols_s_ctrl(struct v4l2_ctrl *ctrl) | ||
| 611 | { | ||
| 612 | struct v4l2_subdev *sd = to_sd(ctrl); | ||
| 613 | struct m5mols_info *info = to_m5mols(sd); | ||
| 614 | int ret; | ||
| 615 | |||
| 616 | info->mode_save = info->mode; | ||
| 617 | |||
| 618 | ret = m5mols_mode(info, REG_PARAMETER); | ||
| 619 | if (!ret) | ||
| 620 | ret = m5mols_set_ctrl(ctrl); | ||
| 621 | if (!ret) | ||
| 622 | ret = m5mols_mode(info, info->mode_save); | ||
| 623 | |||
| 624 | return ret; | ||
| 625 | } | ||
| 626 | |||
| 627 | static const struct v4l2_ctrl_ops m5mols_ctrl_ops = { | ||
| 628 | .s_ctrl = m5mols_s_ctrl, | ||
| 629 | }; | ||
| 630 | |||
| 631 | static int m5mols_sensor_power(struct m5mols_info *info, bool enable) | ||
| 632 | { | ||
| 633 | struct v4l2_subdev *sd = &info->sd; | ||
| 634 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
| 635 | const struct m5mols_platform_data *pdata = info->pdata; | ||
| 636 | int ret; | ||
| 637 | |||
| 638 | if (enable) { | ||
| 639 | if (is_powered(info)) | ||
| 640 | return 0; | ||
| 641 | |||
| 642 | if (info->set_power) { | ||
| 643 | ret = info->set_power(&client->dev, 1); | ||
| 644 | if (ret) | ||
| 645 | return ret; | ||
| 646 | } | ||
| 647 | |||
| 648 | ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies); | ||
| 649 | if (ret) { | ||
| 650 | info->set_power(&client->dev, 0); | ||
| 651 | return ret; | ||
| 652 | } | ||
| 653 | |||
| 654 | gpio_set_value(pdata->gpio_reset, !pdata->reset_polarity); | ||
| 655 | usleep_range(1000, 1000); | ||
| 656 | info->power = true; | ||
| 657 | |||
| 658 | return ret; | ||
| 659 | } | ||
| 660 | |||
| 661 | if (!is_powered(info)) | ||
| 662 | return 0; | ||
| 663 | |||
| 664 | ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies); | ||
| 665 | if (ret) | ||
| 666 | return ret; | ||
| 667 | |||
| 668 | if (info->set_power) | ||
| 669 | info->set_power(&client->dev, 0); | ||
| 670 | |||
| 671 | gpio_set_value(pdata->gpio_reset, pdata->reset_polarity); | ||
| 672 | usleep_range(1000, 1000); | ||
| 673 | info->power = false; | ||
| 674 | |||
| 675 | return ret; | ||
| 676 | } | ||
| 677 | |||
| 678 | /* m5mols_update_fw - optional firmware update routine */ | ||
| 679 | int __attribute__ ((weak)) m5mols_update_fw(struct v4l2_subdev *sd, | ||
| 680 | int (*set_power)(struct m5mols_info *, bool)) | ||
| 681 | { | ||
| 682 | return 0; | ||
| 683 | } | ||
| 684 | |||
| 685 | /** | ||
| 686 | * m5mols_sensor_armboot - Booting M-5MOLS internal ARM core. | ||
| 687 | * | ||
| 688 | * Booting internal ARM core makes the M-5MOLS is ready for getting commands | ||
| 689 | * with I2C. It's the first thing to be done after it powered up. It must wait | ||
| 690 | * at least 520ms recommended by M-5MOLS datasheet, after executing arm booting. | ||
| 691 | */ | ||
| 692 | static int m5mols_sensor_armboot(struct v4l2_subdev *sd) | ||
| 693 | { | ||
| 694 | int ret; | ||
| 695 | |||
| 696 | ret = m5mols_write(sd, FLASH_CAM_START, REG_START_ARM_BOOT); | ||
| 697 | if (ret < 0) | ||
| 698 | return ret; | ||
| 699 | |||
| 700 | msleep(520); | ||
| 701 | |||
| 702 | ret = m5mols_get_version(sd); | ||
| 703 | if (!ret) | ||
| 704 | ret = m5mols_update_fw(sd, m5mols_sensor_power); | ||
| 705 | if (ret) | ||
| 706 | return ret; | ||
| 707 | |||
| 708 | v4l2_dbg(1, m5mols_debug, sd, "Success ARM Booting\n"); | ||
| 709 | |||
| 710 | ret = m5mols_write(sd, PARM_INTERFACE, REG_INTERFACE_MIPI); | ||
| 711 | if (!ret) | ||
| 712 | ret = m5mols_enable_interrupt(sd, REG_INT_AF); | ||
| 713 | |||
| 714 | return ret; | ||
| 715 | } | ||
| 716 | |||
| 717 | static int m5mols_init_controls(struct m5mols_info *info) | ||
| 718 | { | ||
| 719 | struct v4l2_subdev *sd = &info->sd; | ||
| 720 | u16 max_exposure; | ||
| 721 | u16 step_zoom; | ||
| 722 | int ret; | ||
| 723 | |||
| 724 | /* Determine value's range & step of controls for various FW version */ | ||
| 725 | ret = m5mols_read(sd, AE_MAX_GAIN_MON, (u32 *)&max_exposure); | ||
| 726 | if (!ret) | ||
| 727 | step_zoom = is_manufacturer(info, REG_SAMSUNG_OPTICS) ? 31 : 1; | ||
| 728 | if (ret) | ||
| 729 | return ret; | ||
| 730 | |||
| 731 | v4l2_ctrl_handler_init(&info->handle, 6); | ||
| 732 | info->autowb = v4l2_ctrl_new_std(&info->handle, | ||
| 733 | &m5mols_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE, | ||
| 734 | 0, 1, 1, 0); | ||
| 735 | info->saturation = v4l2_ctrl_new_std(&info->handle, | ||
| 736 | &m5mols_ctrl_ops, V4L2_CID_SATURATION, | ||
| 737 | 1, 5, 1, 3); | ||
| 738 | info->zoom = v4l2_ctrl_new_std(&info->handle, | ||
| 739 | &m5mols_ctrl_ops, V4L2_CID_ZOOM_ABSOLUTE, | ||
| 740 | 1, 70, step_zoom, 1); | ||
| 741 | info->exposure = v4l2_ctrl_new_std(&info->handle, | ||
| 742 | &m5mols_ctrl_ops, V4L2_CID_EXPOSURE, | ||
| 743 | 0, max_exposure, 1, (int)max_exposure/2); | ||
| 744 | info->colorfx = v4l2_ctrl_new_std_menu(&info->handle, | ||
| 745 | &m5mols_ctrl_ops, V4L2_CID_COLORFX, | ||
| 746 | 4, (1 << V4L2_COLORFX_BW), V4L2_COLORFX_NONE); | ||
| 747 | info->autoexposure = v4l2_ctrl_new_std_menu(&info->handle, | ||
| 748 | &m5mols_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, | ||
| 749 | 1, 0, V4L2_EXPOSURE_MANUAL); | ||
| 750 | |||
| 751 | sd->ctrl_handler = &info->handle; | ||
| 752 | if (info->handle.error) { | ||
| 753 | v4l2_err(sd, "Failed to initialize controls: %d\n", ret); | ||
| 754 | v4l2_ctrl_handler_free(&info->handle); | ||
| 755 | return info->handle.error; | ||
| 756 | } | ||
| 757 | |||
| 758 | v4l2_ctrl_cluster(2, &info->autoexposure); | ||
| 759 | |||
| 760 | return 0; | ||
| 761 | } | ||
| 762 | |||
| 763 | /** | ||
| 764 | * m5mols_s_power - Main sensor power control function | ||
| 765 | * | ||
| 766 | * To prevent breaking the lens when the sensor is powered off the Soft-Landing | ||
| 767 | * algorithm is called where available. The Soft-Landing algorithm availability | ||
| 768 | * dependends on the firmware provider. | ||
| 769 | */ | ||
| 770 | static int m5mols_s_power(struct v4l2_subdev *sd, int on) | ||
| 771 | { | ||
| 772 | struct m5mols_info *info = to_m5mols(sd); | ||
| 773 | int ret; | ||
| 774 | |||
| 775 | if (on) { | ||
| 776 | ret = m5mols_sensor_power(info, true); | ||
| 777 | if (!ret) | ||
| 778 | ret = m5mols_sensor_armboot(sd); | ||
| 779 | if (!ret) | ||
| 780 | ret = m5mols_init_controls(info); | ||
| 781 | if (ret) | ||
| 782 | return ret; | ||
| 783 | |||
| 784 | info->ffmt[M5MOLS_RESTYPE_MONITOR] = | ||
| 785 | m5mols_default_ffmt[M5MOLS_RESTYPE_MONITOR]; | ||
| 786 | info->ffmt[M5MOLS_RESTYPE_CAPTURE] = | ||
| 787 | m5mols_default_ffmt[M5MOLS_RESTYPE_CAPTURE]; | ||
| 788 | return ret; | ||
| 789 | } | ||
| 790 | |||
| 791 | if (is_manufacturer(info, REG_SAMSUNG_TECHWIN)) { | ||
| 792 | ret = m5mols_mode(info, REG_MONITOR); | ||
| 793 | if (!ret) | ||
| 794 | ret = m5mols_write(sd, AF_EXECUTE, REG_AF_STOP); | ||
| 795 | if (!ret) | ||
| 796 | ret = m5mols_write(sd, AF_MODE, REG_AF_POWEROFF); | ||
| 797 | if (!ret) | ||
| 798 | ret = m5mols_busy(sd, CAT_SYSTEM, CAT0_STATUS, | ||
| 799 | REG_AF_IDLE); | ||
| 800 | if (!ret) | ||
| 801 | v4l2_info(sd, "Success soft-landing lens\n"); | ||
| 802 | } | ||
| 803 | |||
| 804 | ret = m5mols_sensor_power(info, false); | ||
| 805 | if (!ret) { | ||
| 806 | v4l2_ctrl_handler_free(&info->handle); | ||
| 807 | info->ctrl_sync = false; | ||
| 808 | } | ||
| 809 | |||
| 810 | return ret; | ||
| 811 | } | ||
| 812 | |||
| 813 | static int m5mols_log_status(struct v4l2_subdev *sd) | ||
| 814 | { | ||
| 815 | struct m5mols_info *info = to_m5mols(sd); | ||
| 816 | |||
| 817 | v4l2_ctrl_handler_log_status(&info->handle, sd->name); | ||
| 818 | |||
| 819 | return 0; | ||
| 820 | } | ||
| 821 | |||
| 822 | static const struct v4l2_subdev_core_ops m5mols_core_ops = { | ||
| 823 | .s_power = m5mols_s_power, | ||
| 824 | .g_ctrl = v4l2_subdev_g_ctrl, | ||
| 825 | .s_ctrl = v4l2_subdev_s_ctrl, | ||
| 826 | .queryctrl = v4l2_subdev_queryctrl, | ||
| 827 | .querymenu = v4l2_subdev_querymenu, | ||
| 828 | .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, | ||
| 829 | .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, | ||
| 830 | .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, | ||
| 831 | .log_status = m5mols_log_status, | ||
| 832 | }; | ||
| 833 | |||
| 834 | static const struct v4l2_subdev_ops m5mols_ops = { | ||
| 835 | .core = &m5mols_core_ops, | ||
| 836 | .pad = &m5mols_pad_ops, | ||
| 837 | .video = &m5mols_video_ops, | ||
| 838 | }; | ||
| 839 | |||
| 840 | static void m5mols_irq_work(struct work_struct *work) | ||
| 841 | { | ||
| 842 | struct m5mols_info *info = | ||
| 843 | container_of(work, struct m5mols_info, work_irq); | ||
| 844 | struct v4l2_subdev *sd = &info->sd; | ||
| 845 | u32 reg; | ||
| 846 | int ret; | ||
| 847 | |||
| 848 | if (!is_powered(info) || | ||
| 849 | m5mols_read(sd, SYSTEM_INT_FACTOR, &info->interrupt)) | ||
| 850 | return; | ||
| 851 | |||
| 852 | switch (info->interrupt & REG_INT_MASK) { | ||
| 853 | case REG_INT_AF: | ||
| 854 | if (!is_available_af(info)) | ||
| 855 | break; | ||
| 856 | ret = m5mols_read(sd, AF_STATUS, ®); | ||
| 857 | v4l2_dbg(2, m5mols_debug, sd, "AF %s\n", | ||
| 858 | reg == REG_AF_FAIL ? "Failed" : | ||
| 859 | reg == REG_AF_SUCCESS ? "Success" : | ||
| 860 | reg == REG_AF_IDLE ? "Idle" : "Busy"); | ||
| 861 | break; | ||
| 862 | case REG_INT_CAPTURE: | ||
| 863 | if (!test_and_set_bit(ST_CAPT_IRQ, &info->flags)) | ||
| 864 | wake_up_interruptible(&info->irq_waitq); | ||
| 865 | |||
| 866 | v4l2_dbg(2, m5mols_debug, sd, "CAPTURE\n"); | ||
| 867 | break; | ||
| 868 | default: | ||
| 869 | v4l2_dbg(2, m5mols_debug, sd, "Undefined: %02x\n", reg); | ||
| 870 | break; | ||
| 871 | }; | ||
| 872 | } | ||
| 873 | |||
| 874 | static irqreturn_t m5mols_irq_handler(int irq, void *data) | ||
| 875 | { | ||
| 876 | struct v4l2_subdev *sd = data; | ||
| 877 | struct m5mols_info *info = to_m5mols(sd); | ||
| 878 | |||
| 879 | schedule_work(&info->work_irq); | ||
| 880 | |||
| 881 | return IRQ_HANDLED; | ||
| 882 | } | ||
| 883 | |||
| 884 | static int __devinit m5mols_probe(struct i2c_client *client, | ||
| 885 | const struct i2c_device_id *id) | ||
| 886 | { | ||
| 887 | const struct m5mols_platform_data *pdata = client->dev.platform_data; | ||
| 888 | struct m5mols_info *info; | ||
| 889 | struct v4l2_subdev *sd; | ||
| 890 | int ret; | ||
| 891 | |||
| 892 | if (pdata == NULL) { | ||
| 893 | dev_err(&client->dev, "No platform data\n"); | ||
| 894 | return -EINVAL; | ||
| 895 | } | ||
| 896 | |||
| 897 | if (!gpio_is_valid(pdata->gpio_reset)) { | ||
| 898 | dev_err(&client->dev, "No valid RESET GPIO specified\n"); | ||
| 899 | return -EINVAL; | ||
| 900 | } | ||
| 901 | |||
| 902 | if (!pdata->irq) { | ||
| 903 | dev_err(&client->dev, "Interrupt not assigned\n"); | ||
| 904 | return -EINVAL; | ||
| 905 | } | ||
| 906 | |||
| 907 | info = kzalloc(sizeof(struct m5mols_info), GFP_KERNEL); | ||
| 908 | if (!info) | ||
| 909 | return -ENOMEM; | ||
| 910 | |||
| 911 | info->pdata = pdata; | ||
| 912 | info->set_power = pdata->set_power; | ||
| 913 | |||
| 914 | ret = gpio_request(pdata->gpio_reset, "M5MOLS_NRST"); | ||
| 915 | if (ret) { | ||
| 916 | dev_err(&client->dev, "Failed to request gpio: %d\n", ret); | ||
| 917 | goto out_free; | ||
| 918 | } | ||
| 919 | gpio_direction_output(pdata->gpio_reset, pdata->reset_polarity); | ||
| 920 | |||
| 921 | ret = regulator_bulk_get(&client->dev, ARRAY_SIZE(supplies), supplies); | ||
| 922 | if (ret) { | ||
| 923 | dev_err(&client->dev, "Failed to get regulators: %d\n", ret); | ||
| 924 | goto out_gpio; | ||
| 925 | } | ||
| 926 | |||
| 927 | sd = &info->sd; | ||
| 928 | strlcpy(sd->name, MODULE_NAME, sizeof(sd->name)); | ||
| 929 | v4l2_i2c_subdev_init(sd, client, &m5mols_ops); | ||
| 930 | |||
| 931 | info->pad.flags = MEDIA_PAD_FL_SOURCE; | ||
| 932 | ret = media_entity_init(&sd->entity, 1, &info->pad, 0); | ||
| 933 | if (ret < 0) | ||
| 934 | goto out_reg; | ||
| 935 | sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | ||
| 936 | |||
| 937 | init_waitqueue_head(&info->irq_waitq); | ||
| 938 | INIT_WORK(&info->work_irq, m5mols_irq_work); | ||
| 939 | ret = request_irq(pdata->irq, m5mols_irq_handler, | ||
| 940 | IRQF_TRIGGER_RISING, MODULE_NAME, sd); | ||
| 941 | if (ret) { | ||
| 942 | dev_err(&client->dev, "Interrupt request failed: %d\n", ret); | ||
| 943 | goto out_me; | ||
| 944 | } | ||
| 945 | info->res_type = M5MOLS_RESTYPE_MONITOR; | ||
| 946 | return 0; | ||
| 947 | out_me: | ||
| 948 | media_entity_cleanup(&sd->entity); | ||
| 949 | out_reg: | ||
| 950 | regulator_bulk_free(ARRAY_SIZE(supplies), supplies); | ||
| 951 | out_gpio: | ||
| 952 | gpio_free(pdata->gpio_reset); | ||
| 953 | out_free: | ||
| 954 | kfree(info); | ||
| 955 | return ret; | ||
| 956 | } | ||
| 957 | |||
| 958 | static int __devexit m5mols_remove(struct i2c_client *client) | ||
| 959 | { | ||
| 960 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | ||
| 961 | struct m5mols_info *info = to_m5mols(sd); | ||
| 962 | |||
| 963 | v4l2_device_unregister_subdev(sd); | ||
| 964 | free_irq(info->pdata->irq, sd); | ||
| 965 | |||
| 966 | regulator_bulk_free(ARRAY_SIZE(supplies), supplies); | ||
| 967 | gpio_free(info->pdata->gpio_reset); | ||
| 968 | media_entity_cleanup(&sd->entity); | ||
| 969 | kfree(info); | ||
| 970 | return 0; | ||
| 971 | } | ||
| 972 | |||
| 973 | static const struct i2c_device_id m5mols_id[] = { | ||
| 974 | { MODULE_NAME, 0 }, | ||
| 975 | { }, | ||
| 976 | }; | ||
| 977 | MODULE_DEVICE_TABLE(i2c, m5mols_id); | ||
| 978 | |||
| 979 | static struct i2c_driver m5mols_i2c_driver = { | ||
| 980 | .driver = { | ||
| 981 | .name = MODULE_NAME, | ||
| 982 | }, | ||
| 983 | .probe = m5mols_probe, | ||
| 984 | .remove = __devexit_p(m5mols_remove), | ||
| 985 | .id_table = m5mols_id, | ||
| 986 | }; | ||
| 987 | |||
| 988 | static int __init m5mols_mod_init(void) | ||
| 989 | { | ||
| 990 | return i2c_add_driver(&m5mols_i2c_driver); | ||
| 991 | } | ||
| 992 | |||
| 993 | static void __exit m5mols_mod_exit(void) | ||
| 994 | { | ||
| 995 | i2c_del_driver(&m5mols_i2c_driver); | ||
| 996 | } | ||
| 997 | |||
| 998 | module_init(m5mols_mod_init); | ||
| 999 | module_exit(m5mols_mod_exit); | ||
| 1000 | |||
| 1001 | MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>"); | ||
| 1002 | MODULE_AUTHOR("Dongsoo Kim <dongsoo45.kim@samsung.com>"); | ||
| 1003 | MODULE_DESCRIPTION("Fujitsu M-5MOLS 8M Pixel camera driver"); | ||
| 1004 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/video/m5mols/m5mols_reg.h b/drivers/media/video/m5mols/m5mols_reg.h new file mode 100644 index 000000000000..b83e36fc6ac6 --- /dev/null +++ b/drivers/media/video/m5mols/m5mols_reg.h | |||
| @@ -0,0 +1,399 @@ | |||
| 1 | /* | ||
| 2 | * Register map for M-5MOLS 8M Pixel camera sensor with ISP | ||
| 3 | * | ||
| 4 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | ||
| 5 | * Author: HeungJun Kim, riverful.kim@samsung.com | ||
| 6 | * | ||
| 7 | * Copyright (C) 2009 Samsung Electronics Co., Ltd. | ||
| 8 | * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License as published by | ||
| 12 | * the Free Software Foundation; either version 2 of the License, or | ||
| 13 | * (at your option) any later version. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #ifndef M5MOLS_REG_H | ||
| 17 | #define M5MOLS_REG_H | ||
| 18 | |||
| 19 | #define M5MOLS_I2C_MAX_SIZE 4 | ||
| 20 | #define M5MOLS_BYTE_READ 0x01 | ||
| 21 | #define M5MOLS_BYTE_WRITE 0x02 | ||
| 22 | |||
| 23 | #define I2C_CATEGORY(__cat) ((__cat >> 16) & 0xff) | ||
| 24 | #define I2C_COMMAND(__comm) ((__comm >> 8) & 0xff) | ||
| 25 | #define I2C_SIZE(__reg_s) ((__reg_s) & 0xff) | ||
| 26 | #define I2C_REG(__cat, __cmd, __reg_s) ((__cat << 16) | (__cmd << 8) | __reg_s) | ||
| 27 | |||
| 28 | /* | ||
| 29 | * Category section register | ||
| 30 | * | ||
| 31 | * The category means set including relevant command of M-5MOLS. | ||
| 32 | */ | ||
| 33 | #define CAT_SYSTEM 0x00 | ||
| 34 | #define CAT_PARAM 0x01 | ||
| 35 | #define CAT_MONITOR 0x02 | ||
| 36 | #define CAT_AE 0x03 | ||
| 37 | #define CAT_WB 0x06 | ||
| 38 | #define CAT_EXIF 0x07 | ||
| 39 | #define CAT_FD 0x09 | ||
| 40 | #define CAT_LENS 0x0a | ||
| 41 | #define CAT_CAPT_PARM 0x0b | ||
| 42 | #define CAT_CAPT_CTRL 0x0c | ||
| 43 | #define CAT_FLASH 0x0f /* related to FW, revisions, booting */ | ||
| 44 | |||
| 45 | /* | ||
| 46 | * Category 0 - SYSTEM mode | ||
| 47 | * | ||
| 48 | * The SYSTEM mode in the M-5MOLS means area available to handle with the whole | ||
| 49 | * & all-round system of sensor. It deals with version/interrupt/setting mode & | ||
| 50 | * even sensor's status. Especially, the M-5MOLS sensor with ISP varies by | ||
| 51 | * packaging & manufacturer, even the customer and project code. And the | ||
| 52 | * function details may vary among them. The version information helps to | ||
| 53 | * determine what methods shall be used in the driver. | ||
| 54 | * | ||
| 55 | * There is many registers between customer version address and awb one. For | ||
| 56 | * more specific contents, see definition if file m5mols.h. | ||
| 57 | */ | ||
| 58 | #define CAT0_VER_CUSTOMER 0x00 /* customer version */ | ||
| 59 | #define CAT0_VER_AWB 0x09 /* Auto WB version */ | ||
| 60 | #define CAT0_VER_STRING 0x0a /* string including M-5MOLS */ | ||
| 61 | #define CAT0_SYSMODE 0x0b /* SYSTEM mode register */ | ||
| 62 | #define CAT0_STATUS 0x0c /* SYSTEM mode status register */ | ||
| 63 | #define CAT0_INT_FACTOR 0x10 /* interrupt pending register */ | ||
| 64 | #define CAT0_INT_ENABLE 0x11 /* interrupt enable register */ | ||
| 65 | |||
| 66 | #define SYSTEM_SYSMODE I2C_REG(CAT_SYSTEM, CAT0_SYSMODE, 1) | ||
| 67 | #define REG_SYSINIT 0x00 /* SYSTEM mode */ | ||
| 68 | #define REG_PARAMETER 0x01 /* PARAMETER mode */ | ||
| 69 | #define REG_MONITOR 0x02 /* MONITOR mode */ | ||
| 70 | #define REG_CAPTURE 0x03 /* CAPTURE mode */ | ||
| 71 | |||
| 72 | #define SYSTEM_CMD(__cmd) I2C_REG(CAT_SYSTEM, cmd, 1) | ||
| 73 | #define SYSTEM_VER_STRING I2C_REG(CAT_SYSTEM, CAT0_VER_STRING, 1) | ||
| 74 | #define REG_SAMSUNG_ELECTRO "SE" /* Samsung Electro-Mechanics */ | ||
| 75 | #define REG_SAMSUNG_OPTICS "OP" /* Samsung Fiber-Optics */ | ||
| 76 | #define REG_SAMSUNG_TECHWIN "TB" /* Samsung Techwin */ | ||
| 77 | |||
| 78 | #define SYSTEM_INT_FACTOR I2C_REG(CAT_SYSTEM, CAT0_INT_FACTOR, 1) | ||
| 79 | #define SYSTEM_INT_ENABLE I2C_REG(CAT_SYSTEM, CAT0_INT_ENABLE, 1) | ||
| 80 | #define REG_INT_MODE (1 << 0) | ||
| 81 | #define REG_INT_AF (1 << 1) | ||
| 82 | #define REG_INT_ZOOM (1 << 2) | ||
| 83 | #define REG_INT_CAPTURE (1 << 3) | ||
| 84 | #define REG_INT_FRAMESYNC (1 << 4) | ||
| 85 | #define REG_INT_FD (1 << 5) | ||
| 86 | #define REG_INT_LENS_INIT (1 << 6) | ||
| 87 | #define REG_INT_SOUND (1 << 7) | ||
| 88 | #define REG_INT_MASK 0x0f | ||
| 89 | |||
| 90 | /* | ||
| 91 | * category 1 - PARAMETER mode | ||
| 92 | * | ||
| 93 | * This category supports function of camera features of M-5MOLS. It means we | ||
| 94 | * can handle with preview(MONITOR) resolution size/frame per second/interface | ||
| 95 | * between the sensor and the Application Processor/even the image effect. | ||
| 96 | */ | ||
| 97 | #define CAT1_DATA_INTERFACE 0x00 /* interface between sensor and AP */ | ||
| 98 | #define CAT1_MONITOR_SIZE 0x01 /* resolution at the MONITOR mode */ | ||
| 99 | #define CAT1_MONITOR_FPS 0x02 /* frame per second at this mode */ | ||
| 100 | #define CAT1_EFFECT 0x0b /* image effects */ | ||
| 101 | |||
| 102 | #define PARM_MON_SIZE I2C_REG(CAT_PARAM, CAT1_MONITOR_SIZE, 1) | ||
| 103 | |||
| 104 | #define PARM_MON_FPS I2C_REG(CAT_PARAM, CAT1_MONITOR_FPS, 1) | ||
| 105 | #define REG_FPS_30 0x02 | ||
| 106 | |||
| 107 | #define PARM_INTERFACE I2C_REG(CAT_PARAM, CAT1_DATA_INTERFACE, 1) | ||
| 108 | #define REG_INTERFACE_MIPI 0x02 | ||
| 109 | |||
| 110 | #define PARM_EFFECT I2C_REG(CAT_PARAM, CAT1_EFFECT, 1) | ||
| 111 | #define REG_EFFECT_OFF 0x00 | ||
| 112 | #define REG_EFFECT_NEGA 0x01 | ||
| 113 | #define REG_EFFECT_EMBOSS 0x06 | ||
| 114 | #define REG_EFFECT_OUTLINE 0x07 | ||
| 115 | #define REG_EFFECT_WATERCOLOR 0x08 | ||
| 116 | |||
| 117 | /* | ||
| 118 | * Category 2 - MONITOR mode | ||
| 119 | * | ||
| 120 | * The MONITOR mode is same as preview mode as we said. The M-5MOLS has another | ||
| 121 | * mode named "Preview", but this preview mode is used at the case specific | ||
| 122 | * vider-recording mode. This mmode supports only YUYV format. On the other | ||
| 123 | * hand, the JPEG & RAW formats is supports by CAPTURE mode. And, there are | ||
| 124 | * another options like zoom/color effect(different with effect in PARAMETER | ||
| 125 | * mode)/anti hand shaking algorithm. | ||
| 126 | */ | ||
| 127 | #define CAT2_ZOOM 0x01 /* set the zoom position & execute */ | ||
| 128 | #define CAT2_ZOOM_STEP 0x03 /* set the zoom step */ | ||
| 129 | #define CAT2_CFIXB 0x09 /* CB value for color effect */ | ||
| 130 | #define CAT2_CFIXR 0x0a /* CR value for color effect */ | ||
| 131 | #define CAT2_COLOR_EFFECT 0x0b /* set on/off of color effect */ | ||
| 132 | #define CAT2_CHROMA_LVL 0x0f /* set chroma level */ | ||
| 133 | #define CAT2_CHROMA_EN 0x10 /* set on/off of choroma */ | ||
| 134 | #define CAT2_EDGE_LVL 0x11 /* set sharpness level */ | ||
| 135 | #define CAT2_EDGE_EN 0x12 /* set on/off sharpness */ | ||
| 136 | #define CAT2_TONE_CTL 0x25 /* set tone color(contrast) */ | ||
| 137 | |||
| 138 | #define MON_ZOOM I2C_REG(CAT_MONITOR, CAT2_ZOOM, 1) | ||
| 139 | |||
| 140 | #define MON_CFIXR I2C_REG(CAT_MONITOR, CAT2_CFIXR, 1) | ||
| 141 | #define MON_CFIXB I2C_REG(CAT_MONITOR, CAT2_CFIXB, 1) | ||
| 142 | #define REG_CFIXB_SEPIA 0xd8 | ||
| 143 | #define REG_CFIXR_SEPIA 0x18 | ||
| 144 | |||
| 145 | #define MON_EFFECT I2C_REG(CAT_MONITOR, CAT2_COLOR_EFFECT, 1) | ||
| 146 | #define REG_COLOR_EFFECT_OFF 0x00 | ||
| 147 | #define REG_COLOR_EFFECT_ON 0x01 | ||
| 148 | |||
| 149 | #define MON_CHROMA_EN I2C_REG(CAT_MONITOR, CAT2_CHROMA_EN, 1) | ||
| 150 | #define MON_CHROMA_LVL I2C_REG(CAT_MONITOR, CAT2_CHROMA_LVL, 1) | ||
| 151 | #define REG_CHROMA_OFF 0x00 | ||
| 152 | #define REG_CHROMA_ON 0x01 | ||
| 153 | |||
| 154 | #define MON_EDGE_EN I2C_REG(CAT_MONITOR, CAT2_EDGE_EN, 1) | ||
| 155 | #define MON_EDGE_LVL I2C_REG(CAT_MONITOR, CAT2_EDGE_LVL, 1) | ||
| 156 | #define REG_EDGE_OFF 0x00 | ||
| 157 | #define REG_EDGE_ON 0x01 | ||
| 158 | |||
| 159 | #define MON_TONE_CTL I2C_REG(CAT_MONITOR, CAT2_TONE_CTL, 1) | ||
| 160 | |||
| 161 | /* | ||
| 162 | * Category 3 - Auto Exposure | ||
| 163 | * | ||
| 164 | * The M-5MOLS exposure capbility is detailed as which is similar to digital | ||
| 165 | * camera. This category supports AE locking/various AE mode(range of exposure) | ||
| 166 | * /ISO/flickering/EV bias/shutter/meteoring, and anything else. And the | ||
| 167 | * maximum/minimum exposure gain value depending on M-5MOLS firmware, may be | ||
| 168 | * different. So, this category also provide getting the max/min values. And, | ||
| 169 | * each MONITOR and CAPTURE mode has each gain/shutter/max exposure values. | ||
| 170 | */ | ||
| 171 | #define CAT3_AE_LOCK 0x00 /* locking Auto exposure */ | ||
| 172 | #define CAT3_AE_MODE 0x01 /* set AE mode, mode means range */ | ||
| 173 | #define CAT3_ISO 0x05 /* set ISO */ | ||
| 174 | #define CAT3_EV_PRESET_MONITOR 0x0a /* EV(scenemode) preset for MONITOR */ | ||
| 175 | #define CAT3_EV_PRESET_CAPTURE 0x0b /* EV(scenemode) preset for CAPTURE */ | ||
| 176 | #define CAT3_MANUAL_GAIN_MON 0x12 /* meteoring value for the MONITOR */ | ||
| 177 | #define CAT3_MAX_GAIN_MON 0x1a /* max gain value for the MONITOR */ | ||
| 178 | #define CAT3_MANUAL_GAIN_CAP 0x26 /* meteoring value for the CAPTURE */ | ||
| 179 | #define CAT3_AE_INDEX 0x38 /* AE index */ | ||
| 180 | |||
| 181 | #define AE_LOCK I2C_REG(CAT_AE, CAT3_AE_LOCK, 1) | ||
| 182 | #define REG_AE_UNLOCK 0x00 | ||
| 183 | #define REG_AE_LOCK 0x01 | ||
| 184 | |||
| 185 | #define AE_MODE I2C_REG(CAT_AE, CAT3_AE_MODE, 1) | ||
| 186 | #define REG_AE_OFF 0x00 /* AE off */ | ||
| 187 | #define REG_AE_ALL 0x01 /* calc AE in all block integral */ | ||
| 188 | #define REG_AE_CENTER 0x03 /* calc AE in center weighted */ | ||
| 189 | #define REG_AE_SPOT 0x06 /* calc AE in specific spot */ | ||
| 190 | |||
| 191 | #define AE_ISO I2C_REG(CAT_AE, CAT3_ISO, 1) | ||
| 192 | #define REG_ISO_AUTO 0x00 | ||
| 193 | #define REG_ISO_50 0x01 | ||
| 194 | #define REG_ISO_100 0x02 | ||
| 195 | #define REG_ISO_200 0x03 | ||
| 196 | #define REG_ISO_400 0x04 | ||
| 197 | #define REG_ISO_800 0x05 | ||
| 198 | |||
| 199 | #define AE_EV_PRESET_MONITOR I2C_REG(CAT_AE, CAT3_EV_PRESET_MONITOR, 1) | ||
| 200 | #define AE_EV_PRESET_CAPTURE I2C_REG(CAT_AE, CAT3_EV_PRESET_CAPTURE, 1) | ||
| 201 | #define REG_SCENE_NORMAL 0x00 | ||
| 202 | #define REG_SCENE_PORTRAIT 0x01 | ||
| 203 | #define REG_SCENE_LANDSCAPE 0x02 | ||
| 204 | #define REG_SCENE_SPORTS 0x03 | ||
| 205 | #define REG_SCENE_PARTY_INDOOR 0x04 | ||
| 206 | #define REG_SCENE_BEACH_SNOW 0x05 | ||
| 207 | #define REG_SCENE_SUNSET 0x06 | ||
| 208 | #define REG_SCENE_DAWN_DUSK 0x07 | ||
| 209 | #define REG_SCENE_FALL 0x08 | ||
| 210 | #define REG_SCENE_NIGHT 0x09 | ||
| 211 | #define REG_SCENE_AGAINST_LIGHT 0x0a | ||
| 212 | #define REG_SCENE_FIRE 0x0b | ||
| 213 | #define REG_SCENE_TEXT 0x0c | ||
| 214 | #define REG_SCENE_CANDLE 0x0d | ||
| 215 | |||
| 216 | #define AE_MAN_GAIN_MON I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_MON, 2) | ||
| 217 | #define AE_MAX_GAIN_MON I2C_REG(CAT_AE, CAT3_MAX_GAIN_MON, 2) | ||
| 218 | #define AE_MAN_GAIN_CAP I2C_REG(CAT_AE, CAT3_MANUAL_GAIN_CAP, 2) | ||
| 219 | |||
| 220 | #define AE_INDEX I2C_REG(CAT_AE, CAT3_AE_INDEX, 1) | ||
| 221 | #define REG_AE_INDEX_20_NEG 0x00 | ||
| 222 | #define REG_AE_INDEX_15_NEG 0x01 | ||
| 223 | #define REG_AE_INDEX_10_NEG 0x02 | ||
| 224 | #define REG_AE_INDEX_05_NEG 0x03 | ||
| 225 | #define REG_AE_INDEX_00 0x04 | ||
| 226 | #define REG_AE_INDEX_05_POS 0x05 | ||
| 227 | #define REG_AE_INDEX_10_POS 0x06 | ||
| 228 | #define REG_AE_INDEX_15_POS 0x07 | ||
| 229 | #define REG_AE_INDEX_20_POS 0x08 | ||
| 230 | |||
| 231 | /* | ||
| 232 | * Category 6 - White Balance | ||
| 233 | * | ||
| 234 | * This category provide AWB locking/mode/preset/speed/gain bias, etc. | ||
| 235 | */ | ||
| 236 | #define CAT6_AWB_LOCK 0x00 /* locking Auto Whitebalance */ | ||
| 237 | #define CAT6_AWB_MODE 0x02 /* set Auto or Manual */ | ||
| 238 | #define CAT6_AWB_MANUAL 0x03 /* set Manual(preset) value */ | ||
| 239 | |||
| 240 | #define AWB_LOCK I2C_REG(CAT_WB, CAT6_AWB_LOCK, 1) | ||
| 241 | #define REG_AWB_UNLOCK 0x00 | ||
| 242 | #define REG_AWB_LOCK 0x01 | ||
| 243 | |||
| 244 | #define AWB_MODE I2C_REG(CAT_WB, CAT6_AWB_MODE, 1) | ||
| 245 | #define REG_AWB_AUTO 0x01 /* AWB off */ | ||
| 246 | #define REG_AWB_PRESET 0x02 /* AWB preset */ | ||
| 247 | |||
| 248 | #define AWB_MANUAL I2C_REG(CAT_WB, CAT6_AWB_MANUAL, 1) | ||
| 249 | #define REG_AWB_INCANDESCENT 0x01 | ||
| 250 | #define REG_AWB_FLUORESCENT_1 0x02 | ||
| 251 | #define REG_AWB_FLUORESCENT_2 0x03 | ||
| 252 | #define REG_AWB_DAYLIGHT 0x04 | ||
| 253 | #define REG_AWB_CLOUDY 0x05 | ||
| 254 | #define REG_AWB_SHADE 0x06 | ||
| 255 | #define REG_AWB_HORIZON 0x07 | ||
| 256 | #define REG_AWB_LEDLIGHT 0x09 | ||
| 257 | |||
| 258 | /* | ||
| 259 | * Category 7 - EXIF information | ||
| 260 | */ | ||
| 261 | #define CAT7_INFO_EXPTIME_NU 0x00 | ||
| 262 | #define CAT7_INFO_EXPTIME_DE 0x04 | ||
| 263 | #define CAT7_INFO_TV_NU 0x08 | ||
| 264 | #define CAT7_INFO_TV_DE 0x0c | ||
| 265 | #define CAT7_INFO_AV_NU 0x10 | ||
| 266 | #define CAT7_INFO_AV_DE 0x14 | ||
| 267 | #define CAT7_INFO_BV_NU 0x18 | ||
| 268 | #define CAT7_INFO_BV_DE 0x1c | ||
| 269 | #define CAT7_INFO_EBV_NU 0x20 | ||
| 270 | #define CAT7_INFO_EBV_DE 0x24 | ||
| 271 | #define CAT7_INFO_ISO 0x28 | ||
| 272 | #define CAT7_INFO_FLASH 0x2a | ||
| 273 | #define CAT7_INFO_SDR 0x2c | ||
| 274 | #define CAT7_INFO_QVAL 0x2e | ||
| 275 | |||
| 276 | #define EXIF_INFO_EXPTIME_NU I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_NU, 4) | ||
| 277 | #define EXIF_INFO_EXPTIME_DE I2C_REG(CAT_EXIF, CAT7_INFO_EXPTIME_DE, 4) | ||
| 278 | #define EXIF_INFO_TV_NU I2C_REG(CAT_EXIF, CAT7_INFO_TV_NU, 4) | ||
| 279 | #define EXIF_INFO_TV_DE I2C_REG(CAT_EXIF, CAT7_INFO_TV_DE, 4) | ||
| 280 | #define EXIF_INFO_AV_NU I2C_REG(CAT_EXIF, CAT7_INFO_AV_NU, 4) | ||
| 281 | #define EXIF_INFO_AV_DE I2C_REG(CAT_EXIF, CAT7_INFO_AV_DE, 4) | ||
| 282 | #define EXIF_INFO_BV_NU I2C_REG(CAT_EXIF, CAT7_INFO_BV_NU, 4) | ||
| 283 | #define EXIF_INFO_BV_DE I2C_REG(CAT_EXIF, CAT7_INFO_BV_DE, 4) | ||
| 284 | #define EXIF_INFO_EBV_NU I2C_REG(CAT_EXIF, CAT7_INFO_EBV_NU, 4) | ||
| 285 | #define EXIF_INFO_EBV_DE I2C_REG(CAT_EXIF, CAT7_INFO_EBV_DE, 4) | ||
| 286 | #define EXIF_INFO_ISO I2C_REG(CAT_EXIF, CAT7_INFO_ISO, 2) | ||
| 287 | #define EXIF_INFO_FLASH I2C_REG(CAT_EXIF, CAT7_INFO_FLASH, 2) | ||
| 288 | #define EXIF_INFO_SDR I2C_REG(CAT_EXIF, CAT7_INFO_SDR, 2) | ||
| 289 | #define EXIF_INFO_QVAL I2C_REG(CAT_EXIF, CAT7_INFO_QVAL, 2) | ||
| 290 | |||
| 291 | /* | ||
| 292 | * Category 9 - Face Detection | ||
| 293 | */ | ||
| 294 | #define CAT9_FD_CTL 0x00 | ||
| 295 | |||
| 296 | #define FD_CTL I2C_REG(CAT_FD, CAT9_FD_CTL, 1) | ||
| 297 | #define BIT_FD_EN 0 | ||
| 298 | #define BIT_FD_DRAW_FACE_FRAME 4 | ||
| 299 | #define BIT_FD_DRAW_SMILE_LVL 6 | ||
| 300 | #define REG_FD(shift) (1 << shift) | ||
| 301 | #define REG_FD_OFF 0x0 | ||
| 302 | |||
| 303 | /* | ||
| 304 | * Category A - Lens Parameter | ||
| 305 | */ | ||
| 306 | #define CATA_AF_MODE 0x01 | ||
| 307 | #define CATA_AF_EXECUTE 0x02 | ||
| 308 | #define CATA_AF_STATUS 0x03 | ||
| 309 | #define CATA_AF_VERSION 0x0a | ||
| 310 | |||
| 311 | #define AF_MODE I2C_REG(CAT_LENS, CATA_AF_MODE, 1) | ||
| 312 | #define REG_AF_NORMAL 0x00 /* Normal AF, one time */ | ||
| 313 | #define REG_AF_MACRO 0x01 /* Macro AF, one time */ | ||
| 314 | #define REG_AF_POWEROFF 0x07 | ||
| 315 | |||
| 316 | #define AF_EXECUTE I2C_REG(CAT_LENS, CATA_AF_EXECUTE, 1) | ||
| 317 | #define REG_AF_STOP 0x00 | ||
| 318 | #define REG_AF_EXE_AUTO 0x01 | ||
| 319 | #define REG_AF_EXE_CAF 0x02 | ||
| 320 | |||
| 321 | #define AF_STATUS I2C_REG(CAT_LENS, CATA_AF_STATUS, 1) | ||
| 322 | #define REG_AF_FAIL 0x00 | ||
| 323 | #define REG_AF_SUCCESS 0x02 | ||
| 324 | #define REG_AF_IDLE 0x04 | ||
| 325 | #define REG_AF_BUSY 0x05 | ||
| 326 | |||
| 327 | #define AF_VERSION I2C_REG(CAT_LENS, CATA_AF_VERSION, 1) | ||
| 328 | |||
| 329 | /* | ||
| 330 | * Category B - CAPTURE Parameter | ||
| 331 | */ | ||
| 332 | #define CATB_YUVOUT_MAIN 0x00 | ||
| 333 | #define CATB_MAIN_IMAGE_SIZE 0x01 | ||
| 334 | #define CATB_MCC_MODE 0x1d | ||
| 335 | #define CATB_WDR_EN 0x2c | ||
| 336 | #define CATB_LIGHT_CTRL 0x40 | ||
| 337 | #define CATB_FLASH_CTRL 0x41 | ||
| 338 | |||
| 339 | #define CAPP_YUVOUT_MAIN I2C_REG(CAT_CAPT_PARM, CATB_YUVOUT_MAIN, 1) | ||
| 340 | #define REG_YUV422 0x00 | ||
| 341 | #define REG_BAYER10 0x05 | ||
| 342 | #define REG_BAYER8 0x06 | ||
| 343 | #define REG_JPEG 0x10 | ||
| 344 | |||
| 345 | #define CAPP_MAIN_IMAGE_SIZE I2C_REG(CAT_CAPT_PARM, CATB_MAIN_IMAGE_SIZE, 1) | ||
| 346 | |||
| 347 | #define CAPP_MCC_MODE I2C_REG(CAT_CAPT_PARM, CATB_MCC_MODE, 1) | ||
| 348 | #define REG_MCC_OFF 0x00 | ||
| 349 | #define REG_MCC_NORMAL 0x01 | ||
| 350 | |||
| 351 | #define CAPP_WDR_EN I2C_REG(CAT_CAPT_PARM, CATB_WDR_EN, 1) | ||
| 352 | #define REG_WDR_OFF 0x00 | ||
| 353 | #define REG_WDR_ON 0x01 | ||
| 354 | #define REG_WDR_AUTO 0x02 | ||
| 355 | |||
| 356 | #define CAPP_LIGHT_CTRL I2C_REG(CAT_CAPT_PARM, CATB_LIGHT_CTRL, 1) | ||
| 357 | #define REG_LIGHT_OFF 0x00 | ||
| 358 | #define REG_LIGHT_ON 0x01 | ||
| 359 | #define REG_LIGHT_AUTO 0x02 | ||
| 360 | |||
| 361 | #define CAPP_FLASH_CTRL I2C_REG(CAT_CAPT_PARM, CATB_FLASH_CTRL, 1) | ||
| 362 | #define REG_FLASH_OFF 0x00 | ||
| 363 | #define REG_FLASH_ON 0x01 | ||
| 364 | #define REG_FLASH_AUTO 0x02 | ||
| 365 | |||
| 366 | /* | ||
| 367 | * Category C - CAPTURE Control | ||
| 368 | */ | ||
| 369 | #define CATC_CAP_MODE 0x00 | ||
| 370 | #define CATC_CAP_SEL_FRAME 0x06 /* It determines Single or Multi */ | ||
| 371 | #define CATC_CAP_START 0x09 | ||
| 372 | #define CATC_CAP_IMAGE_SIZE 0x0d | ||
| 373 | #define CATC_CAP_THUMB_SIZE 0x11 | ||
| 374 | |||
| 375 | #define CAPC_MODE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_MODE, 1) | ||
| 376 | #define REG_CAP_NONE 0x00 | ||
| 377 | #define REG_CAP_ANTI_SHAKE 0x02 | ||
| 378 | |||
| 379 | #define CAPC_SEL_FRAME I2C_REG(CAT_CAPT_CTRL, CATC_CAP_SEL_FRAME, 1) | ||
| 380 | |||
| 381 | #define CAPC_START I2C_REG(CAT_CAPT_CTRL, CATC_CAP_START, 1) | ||
| 382 | #define REG_CAP_START_MAIN 0x01 | ||
| 383 | #define REG_CAP_START_THUMB 0x03 | ||
| 384 | |||
| 385 | #define CAPC_IMAGE_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_IMAGE_SIZE, 1) | ||
| 386 | #define CAPC_THUMB_SIZE I2C_REG(CAT_CAPT_CTRL, CATC_CAP_THUMB_SIZE, 1) | ||
| 387 | |||
| 388 | /* | ||
| 389 | * Category F - Flash | ||
| 390 | * | ||
| 391 | * This mode provides functions about internal flash stuff and system startup. | ||
| 392 | */ | ||
| 393 | #define CATF_CAM_START 0x12 /* It starts internal ARM core booting | ||
| 394 | * after power-up */ | ||
| 395 | |||
| 396 | #define FLASH_CAM_START I2C_REG(CAT_FLASH, CATF_CAM_START, 1) | ||
| 397 | #define REG_START_ARM_BOOT 0x01 | ||
| 398 | |||
| 399 | #endif /* M5MOLS_REG_H */ | ||
diff --git a/drivers/media/video/uvc/Makefile b/drivers/media/video/uvc/Makefile index 968c1994eda0..2071ca8a2f03 100644 --- a/drivers/media/video/uvc/Makefile +++ b/drivers/media/video/uvc/Makefile | |||
| @@ -1,3 +1,6 @@ | |||
| 1 | uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \ | 1 | uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \ |
| 2 | uvc_status.o uvc_isight.o | 2 | uvc_status.o uvc_isight.o |
| 3 | ifeq ($(CONFIG_MEDIA_CONTROLLER),y) | ||
| 4 | uvcvideo-objs += uvc_entity.o | ||
| 5 | endif | ||
| 3 | obj-$(CONFIG_USB_VIDEO_CLASS) += uvcvideo.o | 6 | obj-$(CONFIG_USB_VIDEO_CLASS) += uvcvideo.o |
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index 823f4b389745..b6eae48d7fb8 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c | |||
| @@ -248,7 +248,7 @@ uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator) | |||
| 248 | * Terminal and unit management | 248 | * Terminal and unit management |
| 249 | */ | 249 | */ |
| 250 | 250 | ||
| 251 | static struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id) | 251 | struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id) |
| 252 | { | 252 | { |
| 253 | struct uvc_entity *entity; | 253 | struct uvc_entity *entity; |
| 254 | 254 | ||
| @@ -795,9 +795,12 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id, | |||
| 795 | struct uvc_entity *entity; | 795 | struct uvc_entity *entity; |
| 796 | unsigned int num_inputs; | 796 | unsigned int num_inputs; |
| 797 | unsigned int size; | 797 | unsigned int size; |
| 798 | unsigned int i; | ||
| 798 | 799 | ||
| 800 | extra_size = ALIGN(extra_size, sizeof(*entity->pads)); | ||
| 799 | num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1; | 801 | num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1; |
| 800 | size = sizeof(*entity) + extra_size + num_inputs; | 802 | size = sizeof(*entity) + extra_size + sizeof(*entity->pads) * num_pads |
| 803 | + num_inputs; | ||
| 801 | entity = kzalloc(size, GFP_KERNEL); | 804 | entity = kzalloc(size, GFP_KERNEL); |
| 802 | if (entity == NULL) | 805 | if (entity == NULL) |
| 803 | return NULL; | 806 | return NULL; |
| @@ -805,8 +808,17 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id, | |||
| 805 | entity->id = id; | 808 | entity->id = id; |
| 806 | entity->type = type; | 809 | entity->type = type; |
| 807 | 810 | ||
| 811 | entity->num_links = 0; | ||
| 812 | entity->num_pads = num_pads; | ||
| 813 | entity->pads = ((void *)(entity + 1)) + extra_size; | ||
| 814 | |||
| 815 | for (i = 0; i < num_inputs; ++i) | ||
| 816 | entity->pads[i].flags = MEDIA_PAD_FL_SINK; | ||
| 817 | if (!UVC_ENTITY_IS_OTERM(entity)) | ||
| 818 | entity->pads[num_pads-1].flags = MEDIA_PAD_FL_SOURCE; | ||
| 819 | |||
| 808 | entity->bNrInPins = num_inputs; | 820 | entity->bNrInPins = num_inputs; |
| 809 | entity->baSourceID = ((__u8 *)entity) + sizeof(*entity) + extra_size; | 821 | entity->baSourceID = (__u8 *)(&entity->pads[num_pads]); |
| 810 | 822 | ||
| 811 | return entity; | 823 | return entity; |
| 812 | } | 824 | } |
| @@ -1585,6 +1597,13 @@ static void uvc_delete(struct uvc_device *dev) | |||
| 1585 | uvc_status_cleanup(dev); | 1597 | uvc_status_cleanup(dev); |
| 1586 | uvc_ctrl_cleanup_device(dev); | 1598 | uvc_ctrl_cleanup_device(dev); |
| 1587 | 1599 | ||
| 1600 | if (dev->vdev.dev) | ||
| 1601 | v4l2_device_unregister(&dev->vdev); | ||
| 1602 | #ifdef CONFIG_MEDIA_CONTROLLER | ||
| 1603 | if (media_devnode_is_registered(&dev->mdev.devnode)) | ||
| 1604 | media_device_unregister(&dev->mdev); | ||
| 1605 | #endif | ||
| 1606 | |||
| 1588 | list_for_each_safe(p, n, &dev->chains) { | 1607 | list_for_each_safe(p, n, &dev->chains) { |
| 1589 | struct uvc_video_chain *chain; | 1608 | struct uvc_video_chain *chain; |
| 1590 | chain = list_entry(p, struct uvc_video_chain, list); | 1609 | chain = list_entry(p, struct uvc_video_chain, list); |
| @@ -1594,6 +1613,13 @@ static void uvc_delete(struct uvc_device *dev) | |||
| 1594 | list_for_each_safe(p, n, &dev->entities) { | 1613 | list_for_each_safe(p, n, &dev->entities) { |
| 1595 | struct uvc_entity *entity; | 1614 | struct uvc_entity *entity; |
| 1596 | entity = list_entry(p, struct uvc_entity, list); | 1615 | entity = list_entry(p, struct uvc_entity, list); |
| 1616 | #ifdef CONFIG_MEDIA_CONTROLLER | ||
| 1617 | uvc_mc_cleanup_entity(entity); | ||
| 1618 | #endif | ||
| 1619 | if (entity->vdev) { | ||
| 1620 | video_device_release(entity->vdev); | ||
| 1621 | entity->vdev = NULL; | ||
| 1622 | } | ||
| 1597 | kfree(entity); | 1623 | kfree(entity); |
| 1598 | } | 1624 | } |
| 1599 | 1625 | ||
| @@ -1616,8 +1642,6 @@ static void uvc_release(struct video_device *vdev) | |||
| 1616 | struct uvc_streaming *stream = video_get_drvdata(vdev); | 1642 | struct uvc_streaming *stream = video_get_drvdata(vdev); |
| 1617 | struct uvc_device *dev = stream->dev; | 1643 | struct uvc_device *dev = stream->dev; |
| 1618 | 1644 | ||
| 1619 | video_device_release(vdev); | ||
| 1620 | |||
| 1621 | /* Decrement the registered streams count and delete the device when it | 1645 | /* Decrement the registered streams count and delete the device when it |
| 1622 | * reaches zero. | 1646 | * reaches zero. |
| 1623 | */ | 1647 | */ |
| @@ -1682,7 +1706,7 @@ static int uvc_register_video(struct uvc_device *dev, | |||
| 1682 | * unregistered before the reference is released, so we don't need to | 1706 | * unregistered before the reference is released, so we don't need to |
| 1683 | * get another one. | 1707 | * get another one. |
| 1684 | */ | 1708 | */ |
| 1685 | vdev->parent = &dev->intf->dev; | 1709 | vdev->v4l2_dev = &dev->vdev; |
| 1686 | vdev->fops = &uvc_fops; | 1710 | vdev->fops = &uvc_fops; |
| 1687 | vdev->release = uvc_release; | 1711 | vdev->release = uvc_release; |
| 1688 | strlcpy(vdev->name, dev->name, sizeof vdev->name); | 1712 | strlcpy(vdev->name, dev->name, sizeof vdev->name); |
| @@ -1731,6 +1755,8 @@ static int uvc_register_terms(struct uvc_device *dev, | |||
| 1731 | ret = uvc_register_video(dev, stream); | 1755 | ret = uvc_register_video(dev, stream); |
| 1732 | if (ret < 0) | 1756 | if (ret < 0) |
| 1733 | return ret; | 1757 | return ret; |
| 1758 | |||
| 1759 | term->vdev = stream->vdev; | ||
| 1734 | } | 1760 | } |
| 1735 | 1761 | ||
| 1736 | return 0; | 1762 | return 0; |
| @@ -1745,6 +1771,14 @@ static int uvc_register_chains(struct uvc_device *dev) | |||
| 1745 | ret = uvc_register_terms(dev, chain); | 1771 | ret = uvc_register_terms(dev, chain); |
| 1746 | if (ret < 0) | 1772 | if (ret < 0) |
| 1747 | return ret; | 1773 | return ret; |
| 1774 | |||
| 1775 | #ifdef CONFIG_MEDIA_CONTROLLER | ||
| 1776 | ret = uvc_mc_register_entities(chain); | ||
| 1777 | if (ret < 0) { | ||
| 1778 | uvc_printk(KERN_INFO, "Failed to register entites " | ||
| 1779 | "(%d).\n", ret); | ||
| 1780 | } | ||
| 1781 | #endif | ||
| 1748 | } | 1782 | } |
| 1749 | 1783 | ||
| 1750 | return 0; | 1784 | return 0; |
| @@ -1814,6 +1848,24 @@ static int uvc_probe(struct usb_interface *intf, | |||
| 1814 | "linux-uvc-devel mailing list.\n"); | 1848 | "linux-uvc-devel mailing list.\n"); |
| 1815 | } | 1849 | } |
| 1816 | 1850 | ||
| 1851 | /* Register the media and V4L2 devices. */ | ||
| 1852 | #ifdef CONFIG_MEDIA_CONTROLLER | ||
| 1853 | dev->mdev.dev = &intf->dev; | ||
| 1854 | strlcpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model)); | ||
| 1855 | if (udev->serial) | ||
| 1856 | strlcpy(dev->mdev.serial, udev->serial, | ||
| 1857 | sizeof(dev->mdev.serial)); | ||
| 1858 | strcpy(dev->mdev.bus_info, udev->devpath); | ||
| 1859 | dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); | ||
| 1860 | dev->mdev.driver_version = DRIVER_VERSION_NUMBER; | ||
| 1861 | if (media_device_register(&dev->mdev) < 0) | ||
| 1862 | goto error; | ||
| 1863 | |||
| 1864 | dev->vdev.mdev = &dev->mdev; | ||
| 1865 | #endif | ||
| 1866 | if (v4l2_device_register(&intf->dev, &dev->vdev) < 0) | ||
| 1867 | goto error; | ||
| 1868 | |||
| 1817 | /* Initialize controls. */ | 1869 | /* Initialize controls. */ |
| 1818 | if (uvc_ctrl_init_device(dev) < 0) | 1870 | if (uvc_ctrl_init_device(dev) < 0) |
| 1819 | goto error; | 1871 | goto error; |
| @@ -1822,7 +1874,7 @@ static int uvc_probe(struct usb_interface *intf, | |||
| 1822 | if (uvc_scan_device(dev) < 0) | 1874 | if (uvc_scan_device(dev) < 0) |
| 1823 | goto error; | 1875 | goto error; |
| 1824 | 1876 | ||
| 1825 | /* Register video devices. */ | 1877 | /* Register video device nodes. */ |
| 1826 | if (uvc_register_chains(dev) < 0) | 1878 | if (uvc_register_chains(dev) < 0) |
| 1827 | goto error; | 1879 | goto error; |
| 1828 | 1880 | ||
diff --git a/drivers/media/video/uvc/uvc_entity.c b/drivers/media/video/uvc/uvc_entity.c new file mode 100644 index 000000000000..ede7852bb1df --- /dev/null +++ b/drivers/media/video/uvc/uvc_entity.c | |||
| @@ -0,0 +1,118 @@ | |||
| 1 | /* | ||
| 2 | * uvc_entity.c -- USB Video Class driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2005-2011 | ||
| 5 | * Laurent Pinchart (laurent.pinchart@ideasonboard.com) | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/list.h> | ||
| 16 | #include <linux/videodev2.h> | ||
| 17 | |||
| 18 | #include <media/v4l2-common.h> | ||
| 19 | |||
| 20 | #include "uvcvideo.h" | ||
| 21 | |||
| 22 | /* ------------------------------------------------------------------------ | ||
| 23 | * Video subdevices registration and unregistration | ||
| 24 | */ | ||
| 25 | |||
| 26 | static int uvc_mc_register_entity(struct uvc_video_chain *chain, | ||
| 27 | struct uvc_entity *entity) | ||
| 28 | { | ||
| 29 | const u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE; | ||
| 30 | struct uvc_entity *remote; | ||
| 31 | unsigned int i; | ||
| 32 | u8 remote_pad; | ||
| 33 | int ret; | ||
| 34 | |||
| 35 | for (i = 0; i < entity->num_pads; ++i) { | ||
| 36 | struct media_entity *source; | ||
| 37 | struct media_entity *sink; | ||
| 38 | |||
| 39 | if (!(entity->pads[i].flags & MEDIA_PAD_FL_SINK)) | ||
| 40 | continue; | ||
| 41 | |||
| 42 | remote = uvc_entity_by_id(chain->dev, entity->baSourceID[i]); | ||
| 43 | if (remote == NULL) | ||
| 44 | return -EINVAL; | ||
| 45 | |||
| 46 | source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING) | ||
| 47 | ? &remote->vdev->entity : &remote->subdev.entity; | ||
| 48 | sink = (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING) | ||
| 49 | ? &entity->vdev->entity : &entity->subdev.entity; | ||
| 50 | |||
| 51 | remote_pad = remote->num_pads - 1; | ||
| 52 | ret = media_entity_create_link(source, remote_pad, | ||
| 53 | sink, i, flags); | ||
| 54 | if (ret < 0) | ||
| 55 | return ret; | ||
| 56 | } | ||
| 57 | |||
| 58 | if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) | ||
| 59 | ret = v4l2_device_register_subdev(&chain->dev->vdev, | ||
| 60 | &entity->subdev); | ||
| 61 | |||
| 62 | return ret; | ||
| 63 | } | ||
| 64 | |||
| 65 | static struct v4l2_subdev_ops uvc_subdev_ops = { | ||
| 66 | }; | ||
| 67 | |||
| 68 | void uvc_mc_cleanup_entity(struct uvc_entity *entity) | ||
| 69 | { | ||
| 70 | if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) | ||
| 71 | media_entity_cleanup(&entity->subdev.entity); | ||
| 72 | else if (entity->vdev != NULL) | ||
| 73 | media_entity_cleanup(&entity->vdev->entity); | ||
| 74 | } | ||
| 75 | |||
| 76 | static int uvc_mc_init_entity(struct uvc_entity *entity) | ||
| 77 | { | ||
| 78 | int ret; | ||
| 79 | |||
| 80 | if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) { | ||
| 81 | v4l2_subdev_init(&entity->subdev, &uvc_subdev_ops); | ||
| 82 | strlcpy(entity->subdev.name, entity->name, | ||
| 83 | sizeof(entity->subdev.name)); | ||
| 84 | |||
| 85 | ret = media_entity_init(&entity->subdev.entity, | ||
| 86 | entity->num_pads, entity->pads, 0); | ||
| 87 | } else | ||
| 88 | ret = media_entity_init(&entity->vdev->entity, | ||
| 89 | entity->num_pads, entity->pads, 0); | ||
| 90 | |||
| 91 | return ret; | ||
| 92 | } | ||
| 93 | |||
| 94 | int uvc_mc_register_entities(struct uvc_video_chain *chain) | ||
| 95 | { | ||
| 96 | struct uvc_entity *entity; | ||
| 97 | int ret; | ||
| 98 | |||
| 99 | list_for_each_entry(entity, &chain->entities, chain) { | ||
| 100 | ret = uvc_mc_init_entity(entity); | ||
| 101 | if (ret < 0) { | ||
| 102 | uvc_printk(KERN_INFO, "Failed to initialize entity for " | ||
| 103 | "entity %u\n", entity->id); | ||
| 104 | return ret; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | list_for_each_entry(entity, &chain->entities, chain) { | ||
| 109 | ret = uvc_mc_register_entity(chain, entity); | ||
| 110 | if (ret < 0) { | ||
| 111 | uvc_printk(KERN_INFO, "Failed to register entity for " | ||
| 112 | "entity %u\n", entity->id); | ||
| 113 | return ret; | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | return 0; | ||
| 118 | } | ||
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index 7cf224bae2e5..20107fd3574d 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h | |||
| @@ -98,8 +98,11 @@ struct uvc_xu_control { | |||
| 98 | #ifdef __KERNEL__ | 98 | #ifdef __KERNEL__ |
| 99 | 99 | ||
| 100 | #include <linux/poll.h> | 100 | #include <linux/poll.h> |
| 101 | #include <linux/usb.h> | ||
| 101 | #include <linux/usb/video.h> | 102 | #include <linux/usb/video.h> |
| 102 | #include <linux/uvcvideo.h> | 103 | #include <linux/uvcvideo.h> |
| 104 | #include <media/media-device.h> | ||
| 105 | #include <media/v4l2-device.h> | ||
| 103 | 106 | ||
| 104 | /* -------------------------------------------------------------------------- | 107 | /* -------------------------------------------------------------------------- |
| 105 | * UVC constants | 108 | * UVC constants |
| @@ -301,6 +304,13 @@ struct uvc_entity { | |||
| 301 | __u16 type; | 304 | __u16 type; |
| 302 | char name[64]; | 305 | char name[64]; |
| 303 | 306 | ||
| 307 | /* Media controller-related fields. */ | ||
| 308 | struct video_device *vdev; | ||
| 309 | struct v4l2_subdev subdev; | ||
| 310 | unsigned int num_pads; | ||
| 311 | unsigned int num_links; | ||
| 312 | struct media_pad *pads; | ||
| 313 | |||
| 304 | union { | 314 | union { |
| 305 | struct { | 315 | struct { |
| 306 | __u16 wObjectiveFocalLengthMin; | 316 | __u16 wObjectiveFocalLengthMin; |
| @@ -504,6 +514,10 @@ struct uvc_device { | |||
| 504 | atomic_t nmappings; | 514 | atomic_t nmappings; |
| 505 | 515 | ||
| 506 | /* Video control interface */ | 516 | /* Video control interface */ |
| 517 | #ifdef CONFIG_MEDIA_CONTROLLER | ||
| 518 | struct media_device mdev; | ||
| 519 | #endif | ||
| 520 | struct v4l2_device vdev; | ||
| 507 | __u16 uvc_version; | 521 | __u16 uvc_version; |
| 508 | __u32 clock_frequency; | 522 | __u32 clock_frequency; |
| 509 | 523 | ||
| @@ -583,6 +597,8 @@ extern unsigned int uvc_timeout_param; | |||
| 583 | /* Core driver */ | 597 | /* Core driver */ |
| 584 | extern struct uvc_driver uvc_driver; | 598 | extern struct uvc_driver uvc_driver; |
| 585 | 599 | ||
| 600 | extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id); | ||
| 601 | |||
| 586 | /* Video buffers queue management. */ | 602 | /* Video buffers queue management. */ |
| 587 | extern void uvc_queue_init(struct uvc_video_queue *queue, | 603 | extern void uvc_queue_init(struct uvc_video_queue *queue, |
| 588 | enum v4l2_buf_type type, int drop_corrupted); | 604 | enum v4l2_buf_type type, int drop_corrupted); |
| @@ -616,6 +632,10 @@ static inline int uvc_queue_streaming(struct uvc_video_queue *queue) | |||
| 616 | /* V4L2 interface */ | 632 | /* V4L2 interface */ |
| 617 | extern const struct v4l2_file_operations uvc_fops; | 633 | extern const struct v4l2_file_operations uvc_fops; |
| 618 | 634 | ||
| 635 | /* Media controller */ | ||
| 636 | extern int uvc_mc_register_entities(struct uvc_video_chain *chain); | ||
| 637 | extern void uvc_mc_cleanup_entity(struct uvc_entity *entity); | ||
| 638 | |||
| 619 | /* Video */ | 639 | /* Video */ |
| 620 | extern int uvc_video_init(struct uvc_streaming *stream); | 640 | extern int uvc_video_init(struct uvc_streaming *stream); |
| 621 | extern int uvc_video_suspend(struct uvc_streaming *stream); | 641 | extern int uvc_video_suspend(struct uvc_streaming *stream); |
diff --git a/include/media/m5mols.h b/include/media/m5mols.h new file mode 100644 index 000000000000..2d7e7ca2313d --- /dev/null +++ b/include/media/m5mols.h | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | /* | ||
| 2 | * Driver header for M-5MOLS 8M Pixel camera sensor with ISP | ||
| 3 | * | ||
| 4 | * Copyright (C) 2011 Samsung Electronics Co., Ltd. | ||
| 5 | * Author: HeungJun Kim, riverful.kim@samsung.com | ||
| 6 | * | ||
| 7 | * Copyright (C) 2009 Samsung Electronics Co., Ltd. | ||
| 8 | * Author: Dongsoo Nathaniel Kim, dongsoo45.kim@samsung.com | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License as published by | ||
| 12 | * the Free Software Foundation; either version 2 of the License, or | ||
| 13 | * (at your option) any later version. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #ifndef MEDIA_M5MOLS_H | ||
| 17 | #define MEDIA_M5MOLS_H | ||
| 18 | |||
| 19 | /** | ||
| 20 | * struct m5mols_platform_data - platform data for M-5MOLS driver | ||
| 21 | * @irq: GPIO getting the irq pin of M-5MOLS | ||
| 22 | * @gpio_reset: GPIO driving the reset pin of M-5MOLS | ||
| 23 | * @reset_polarity: active state for gpio_rst pin, 0 or 1 | ||
| 24 | * @set_power: an additional callback to the board setup code | ||
| 25 | * to be called after enabling and before disabling | ||
| 26 | * the sensor's supply regulators | ||
| 27 | */ | ||
| 28 | struct m5mols_platform_data { | ||
| 29 | int irq; | ||
| 30 | int gpio_reset; | ||
| 31 | u8 reset_polarity; | ||
| 32 | int (*set_power)(struct device *dev, int on); | ||
| 33 | }; | ||
| 34 | |||
| 35 | #endif /* MEDIA_M5MOLS_H */ | ||
diff --git a/include/media/videobuf-dvb.h b/include/media/videobuf-dvb.h index 07cf4b9d0a65..bf365721d6b0 100644 --- a/include/media/videobuf-dvb.h +++ b/include/media/videobuf-dvb.h | |||
| @@ -4,6 +4,9 @@ | |||
| 4 | #include <dvb_net.h> | 4 | #include <dvb_net.h> |
| 5 | #include <dvb_frontend.h> | 5 | #include <dvb_frontend.h> |
| 6 | 6 | ||
| 7 | #ifndef _VIDEOBUF_DVB_H_ | ||
| 8 | #define _VIDEOBUF_DVB_H_ | ||
| 9 | |||
| 7 | struct videobuf_dvb { | 10 | struct videobuf_dvb { |
| 8 | /* filling that the job of the driver */ | 11 | /* filling that the job of the driver */ |
| 9 | char *name; | 12 | char *name; |
| @@ -54,6 +57,7 @@ void videobuf_dvb_dealloc_frontends(struct videobuf_dvb_frontends *f); | |||
| 54 | struct videobuf_dvb_frontend * videobuf_dvb_get_frontend(struct videobuf_dvb_frontends *f, int id); | 57 | struct videobuf_dvb_frontend * videobuf_dvb_get_frontend(struct videobuf_dvb_frontends *f, int id); |
| 55 | int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f, struct dvb_frontend *p); | 58 | int videobuf_dvb_find_frontend(struct videobuf_dvb_frontends *f, struct dvb_frontend *p); |
| 56 | 59 | ||
| 60 | #endif /* _VIDEOBUF_DVB_H_ */ | ||
| 57 | 61 | ||
| 58 | /* | 62 | /* |
| 59 | * Local variables: | 63 | * Local variables: |
