]>
Commit | Line | Data |
---|---|---|
1802d0be | 1 | // SPDX-License-Identifier: GPL-2.0-only |
ec367c3c HV |
2 | /* |
3 | * Copyright (C) 2005-2006 Micronas USA Inc. | |
ec367c3c HV |
4 | */ |
5 | ||
6 | #include <linux/init.h> | |
7 | #include <linux/module.h> | |
8 | #include <linux/i2c.h> | |
9 | #include <linux/videodev2.h> | |
10 | #include <media/v4l2-device.h> | |
ec367c3c HV |
11 | #include <linux/slab.h> |
12 | ||
13 | MODULE_DESCRIPTION("OmniVision ov7640 sensor driver"); | |
14 | MODULE_LICENSE("GPL v2"); | |
15 | ||
378a0e4b MCB |
16 | struct reg_val { |
17 | u8 reg; | |
18 | u8 val; | |
ec367c3c HV |
19 | }; |
20 | ||
378a0e4b MCB |
21 | static const struct reg_val regval_init[] = { |
22 | {0x12, 0x80}, | |
23 | {0x12, 0x54}, | |
24 | {0x14, 0x24}, | |
25 | {0x15, 0x01}, | |
26 | {0x28, 0x20}, | |
27 | {0x75, 0x82}, | |
28 | }; | |
ec367c3c | 29 | |
378a0e4b MCB |
30 | static int write_regs(struct i2c_client *client, |
31 | const struct reg_val *rv, int len) | |
32 | { | |
33 | while (--len >= 0) { | |
34 | if (i2c_smbus_write_byte_data(client, rv->reg, rv->val) < 0) | |
ec367c3c | 35 | return -1; |
378a0e4b MCB |
36 | rv++; |
37 | } | |
ec367c3c HV |
38 | return 0; |
39 | } | |
40 | ||
41 | /* ----------------------------------------------------------------------- */ | |
42 | ||
43 | static const struct v4l2_subdev_ops ov7640_ops; | |
44 | ||
45 | static int ov7640_probe(struct i2c_client *client, | |
46 | const struct i2c_device_id *id) | |
47 | { | |
48 | struct i2c_adapter *adapter = client->adapter; | |
49 | struct v4l2_subdev *sd; | |
50 | ||
51 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | |
52 | return -ENODEV; | |
53 | ||
c02b211d | 54 | sd = devm_kzalloc(&client->dev, sizeof(*sd), GFP_KERNEL); |
ec367c3c HV |
55 | if (sd == NULL) |
56 | return -ENOMEM; | |
57 | v4l2_i2c_subdev_init(sd, client, &ov7640_ops); | |
58 | ||
59 | client->flags = I2C_CLIENT_SCCB; | |
60 | ||
61 | v4l_info(client, "chip found @ 0x%02x (%s)\n", | |
62 | client->addr << 1, client->adapter->name); | |
63 | ||
378a0e4b | 64 | if (write_regs(client, regval_init, ARRAY_SIZE(regval_init)) < 0) { |
ec367c3c | 65 | v4l_err(client, "error initializing OV7640\n"); |
ec367c3c HV |
66 | return -ENODEV; |
67 | } | |
68 | ||
69 | return 0; | |
70 | } | |
71 | ||
72 | ||
ed5c2f5f | 73 | static void ov7640_remove(struct i2c_client *client) |
ec367c3c HV |
74 | { |
75 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
76 | ||
77 | v4l2_device_unregister_subdev(sd); | |
ec367c3c HV |
78 | } |
79 | ||
80 | static const struct i2c_device_id ov7640_id[] = { | |
81 | { "ov7640", 0 }, | |
82 | { } | |
83 | }; | |
84 | MODULE_DEVICE_TABLE(i2c, ov7640_id); | |
85 | ||
86 | static struct i2c_driver ov7640_driver = { | |
87 | .driver = { | |
ec367c3c HV |
88 | .name = "ov7640", |
89 | }, | |
90 | .probe = ov7640_probe, | |
91 | .remove = ov7640_remove, | |
92 | .id_table = ov7640_id, | |
93 | }; | |
94 | module_i2c_driver(ov7640_driver); |