blob: 190adc7349b985121625b2fdcbfd8e4355d1f9cf [file] [log] [blame]
Angel Pons8a3453f2020-04-02 23:48:19 +02001/* SPDX-License-Identifier: GPL-2.0-only */
V Sowmya9f8023a2017-02-28 17:52:05 +05302
Matt Delco879b3c12020-06-17 13:10:22 +05303#include <stdlib.h>
Furquan Shaikh76cedd22020-05-02 10:24:23 -07004#include <acpi/acpi.h>
5#include <acpi/acpi_device.h>
6#include <acpi/acpigen.h>
Tim Wawrzynczakd40a4c22021-02-25 13:14:49 -07007#include <acpi/acpigen_pci.h>
V Sowmya9f8023a2017-02-28 17:52:05 +05308#include <console/console.h>
Nico Huber0f2dd1e2017-08-01 14:02:40 +02009#include <device/i2c_simple.h>
V Sowmya9f8023a2017-02-28 17:52:05 +053010#include <device/device.h>
Matt Delco7d002932020-06-16 11:39:52 +053011#include <device/pci_def.h>
V Sowmya9f8023a2017-02-28 17:52:05 +053012#include "chip.h"
13
CoolStar674ee502024-04-25 17:06:13 -070014#define CSI2_DATA_STREAM_INTERFACE_GUID \
15 GUID_INIT(0x8A395669, 0x11F7, 0x4EA9, \
16 0x9C, 0x7D, 0x20, 0xEE, 0x0A, 0xB5, 0xCA, 0x40)
17
Matt Delco1245b1e2020-06-17 07:26:55 +053018#define SENSOR_NAME_UUID "822ace8f-2814-4174-a56b-5f029fe079ee"
19#define SENSOR_TYPE_UUID "26257549-9271-4ca4-bb43-c4899d5a4881"
20#define DEFAULT_ENDPOINT 0
Matt Delco879b3c12020-06-17 13:10:22 +053021#define DEFAULT_REMOTE_NAME "\\_SB.PCI0.CIO2"
22#define CIO2_PCI_DEV 0x14
23#define CIO2_PCI_FN 0x3
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +053024#define POWER_RESOURCE_NAME "PRIC"
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +053025#define GUARD_VARIABLE_FORMAT "RES%1d"
26#define ENABLE_METHOD_FORMAT "ENB%1d"
27#define DISABLE_METHOD_FORMAT "DSB%1d"
28#define UNKNOWN_METHOD_FORMAT "UNK%1d"
29#define CLK_ENABLE_METHOD "MCON"
30#define CLK_DISABLE_METHOD "MCOF"
31
32static struct camera_resource_manager res_mgr;
33
34static void resource_set_action_type(struct resource_config *res_config,
35 enum action_type action)
36{
37 if (res_config)
38 res_config->action = action;
39}
40
41static enum action_type resource_get_action_type(const struct resource_config *res_config)
42{
43 return res_config ? res_config->action : UNKNOWN_ACTION;
44}
45
46static enum ctrl_type resource_get_ctrl_type(const struct resource_config *res_config)
47{
48 return res_config ? res_config->type : UNKNOWN_CTRL;
49}
50
51static void resource_set_clk_config(struct resource_config *res_config,
52 const struct clk_config *clk_conf)
53{
54 if (res_config) {
55 res_config->type = IMGCLK;
56 res_config->clk_conf = clk_conf;
57 }
58}
59
60static const struct clk_config *resource_clk_config(const struct resource_config *res_config)
61{
62 return res_config ? res_config->clk_conf : NULL;
63}
64
65static void resource_set_gpio_config(struct resource_config *res_config,
66 const struct gpio_config *gpio_conf)
67{
68 if (res_config) {
69 res_config->type = GPIO;
70 res_config->gpio_conf = gpio_conf;
71 }
72}
73
74static const struct gpio_config *resource_gpio_config(const struct resource_config *res_config)
75{
76 return res_config ? res_config->gpio_conf : NULL;
77}
Matt Delco879b3c12020-06-17 13:10:22 +053078
79/*
80 * This implementation assumes there is only 1 endpoint at each end of every data port. It also
81 * assumes there are no clock lanes. It also assumes that any VCM or NVM for a CAM is on the
82 * same I2C bus as the CAM.
83 */
84
85/*
86 * Adds settings for a CIO2 device (typically at "\_SB.PCI0.CIO2"). A _DSD is added that
87 * specifies a child table for each port (e.g., PRT0 for "port0" and PRT1 for "port1"). Each
88 * PRTx table specifies a table for each endpoint (though only 1 endpoint is supported by this
89 * implementation so the table only has an "endpoint0" that points to a EPx0 table). The EPx0
90 * table primarily describes the # of lanes in "data-lines" and specifies the name of the other
91 * side in "remote-endpoint" (the name is usually of the form "\_SB.PCI0.I2Cx.CAM0" for the
92 * first port/cam and "\_SB.PCI0.I2Cx.CAM1" if there's a second port/cam).
93 */
94static void camera_fill_cio2(const struct device *dev)
95{
96 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
97 struct acpi_dp *dsd = acpi_dp_new_table("_DSD");
98 char *ep_table_name[MAX_PORT_ENTRIES] = {NULL};
99 char *port_table_name[MAX_PORT_ENTRIES] = {NULL};
100 char *port_name[MAX_PORT_ENTRIES] = {NULL};
101 unsigned int i, j;
102 char name[BUS_PATH_MAX];
103 struct acpi_dp *ep_table = NULL;
104 struct acpi_dp *port_table = NULL;
105 struct acpi_dp *remote = NULL;
106 struct acpi_dp *lanes = NULL;
107
108 for (i = 0; i < config->cio2_num_ports && i < MAX_PORT_ENTRIES; ++i) {
109 snprintf(name, sizeof(name), "EP%u0", i);
110 ep_table_name[i] = strdup(name);
111 ep_table = acpi_dp_new_table(ep_table_name[i]);
112 acpi_dp_add_integer(ep_table, "endpoint", 0);
113 acpi_dp_add_integer(ep_table, "clock-lanes", 0);
114
115 if (config->cio2_lanes_used[i] > 0) {
116 lanes = acpi_dp_new_table("data-lanes");
117
118 for (j = 1; j <= config->cio2_lanes_used[i] &&
119 j <= MAX_PORT_ENTRIES; ++j)
120 acpi_dp_add_integer(lanes, NULL, j);
121 acpi_dp_add_array(ep_table, lanes);
122 }
123
124 if (config->cio2_lane_endpoint[i]) {
125 remote = acpi_dp_new_table("remote-endpoint");
126 acpi_dp_add_reference(remote, NULL, config->cio2_lane_endpoint[i]);
127 acpi_dp_add_integer(remote, NULL, 0);
128 acpi_dp_add_integer(remote, NULL, 0);
129 acpi_dp_add_array(ep_table, remote);
130 }
131
132 snprintf(name, sizeof(name), "PRT%u", i);
133 port_table_name[i] = strdup(name);
134 port_table = acpi_dp_new_table(port_table_name[i]);
135 acpi_dp_add_integer(port_table, "port", config->cio2_prt[i]);
136 acpi_dp_add_child(port_table, "endpoint0", ep_table);
137
138 snprintf(name, sizeof(name), "port%u", i);
139 port_name[i] = strdup(name);
Jamie Ryud6f30922023-09-11 15:38:46 -0700140 acpi_dp_add_integer(dsd, "is_es",
141 CONFIG(DRIVERS_INTEL_MIPI_SUPPORTS_PRE_PRODUCTION_SOC));
Matt Delco879b3c12020-06-17 13:10:22 +0530142 acpi_dp_add_child(dsd, port_name[i], port_table);
143 }
144
145 acpi_dp_write(dsd);
146
147 for (i = 0; i < config->cio2_num_ports; ++i) {
148 free(ep_table_name[i]);
149 free(port_table_name[i]);
150 free(port_name[i]);
151 }
152}
Matt Delco1245b1e2020-06-17 07:26:55 +0530153
Matt Delco1ffee9d2020-06-17 12:55:35 +0530154static void apply_pld_defaults(struct drivers_intel_mipi_camera_config *config)
155{
156 if (!config->pld.ignore_color)
157 config->pld.ignore_color = 1;
158
159 if (!config->pld.visible)
160 config->pld.visible = 1;
161
162 if (!config->pld.vertical_offset)
163 config->pld.vertical_offset = 0xffff;
164
165 if (!config->pld.horizontal_offset)
166 config->pld.horizontal_offset = 0xffff;
167
168 /*
169 * PLD_PANEL_TOP has a value of zero, so the following will change any instance of
170 * PLD_PANEL_TOP to PLD_PANEL_FRONT unless disable_pld_defaults is set.
171 */
172 if (!config->pld.panel)
173 config->pld.panel = PLD_PANEL_FRONT;
174
175 /*
176 * PLD_HORIZONTAL_POSITION_LEFT has a value of zero, so the following will change any
177 * instance of that value to PLD_HORIZONTAL_POSITION_CENTER unless disable_pld_defaults
178 * is set.
179 */
180 if (!config->pld.horizontal_position)
181 config->pld.horizontal_position = PLD_HORIZONTAL_POSITION_CENTER;
182
183 /*
184 * The desired default for |vertical_position| is PLD_VERTICAL_POSITION_UPPER, which
185 * has a value of zero so no work is needed to set a default. The same applies for
186 * setting |shape| to PLD_SHAPE_ROUND.
187 */
188}
189
190static void camera_generate_pld(const struct device *dev)
191{
192 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
193
194 if (config->use_pld) {
195 if (!config->disable_pld_defaults)
196 apply_pld_defaults(config);
197
198 acpigen_write_pld(&config->pld);
199 }
200}
201
Matt Delco964033f2020-06-17 12:49:43 +0530202static uint32_t address_for_dev_type(const struct device *dev, uint8_t dev_type)
203{
204 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200205 uint16_t i2c_bus = dev->upstream ? dev->upstream->secondary : 0xFFFF;
Matt Delco964033f2020-06-17 12:49:43 +0530206 uint16_t i2c_addr;
207
208 switch (dev_type) {
209 case DEV_TYPE_SENSOR:
210 i2c_addr = dev->path.i2c.device;
211 break;
212 case DEV_TYPE_VCM:
213 i2c_addr = config->vcm_address;
214 break;
215 case DEV_TYPE_ROM:
216 i2c_addr = config->rom_address;
217 break;
218 default:
219 return 0;
220 }
221
222 return (((uint32_t)i2c_bus) << 24 | ((uint32_t)i2c_addr) << 8 | dev_type);
223}
224
225static void camera_generate_dsm(const struct device *dev)
226{
227 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
228 int local1_ret = 1 + (config->ssdb.vcm_type ? 1 : 0) + (config->ssdb.rom_type ? 1 : 0);
229 int next_local1 = 1;
230 /* Method (_DSM, 4, NotSerialized) */
231 acpigen_write_method("_DSM", 4);
232
233 /* ToBuffer (Arg0, Local0) */
234 acpigen_write_to_buffer(ARG0_OP, LOCAL0_OP);
235
236 /* If (LEqual (Local0, ToUUID(uuid))) */
237 acpigen_write_if();
238 acpigen_emit_byte(LEQUAL_OP);
239 acpigen_emit_byte(LOCAL0_OP);
240 acpigen_write_uuid(SENSOR_NAME_UUID);
241 acpigen_write_return_string(config->sensor_name ? config->sensor_name : "UNKNOWN");
242 acpigen_pop_len(); /* If */
243
244 /* If (LEqual (Local0, ToUUID(uuid))) */
245 acpigen_write_if();
246 acpigen_emit_byte(LEQUAL_OP);
247 acpigen_emit_byte(LOCAL0_OP);
248 acpigen_write_uuid(SENSOR_TYPE_UUID);
249 /* ToInteger (Arg2, Local1) */
250 acpigen_write_to_integer(ARG2_OP, LOCAL1_OP);
251
252 /* If (LEqual (Local1, 1)) */
253 acpigen_write_if_lequal_op_int(LOCAL1_OP, next_local1++);
254 acpigen_write_return_integer(local1_ret);
255 acpigen_pop_len(); /* If Arg2=1 */
256
257 /* If (LEqual (Local1, 2)) */
258 acpigen_write_if_lequal_op_int(LOCAL1_OP, next_local1++);
259 acpigen_write_return_integer(address_for_dev_type(dev, DEV_TYPE_SENSOR));
260 acpigen_pop_len(); /* If Arg2=2 */
261
262 if (config->ssdb.vcm_type) {
263 /* If (LEqual (Local1, 3)) */
264 acpigen_write_if_lequal_op_int(LOCAL1_OP, next_local1++);
265 acpigen_write_return_integer(address_for_dev_type(dev, DEV_TYPE_VCM));
266 acpigen_pop_len(); /* If Arg2=3 */
267 }
268
269 if (config->ssdb.rom_type) {
270 /* If (LEqual (Local1, 3 or 4)) */
271 acpigen_write_if_lequal_op_int(LOCAL1_OP, next_local1);
272 acpigen_write_return_integer(address_for_dev_type(dev, DEV_TYPE_ROM));
273 acpigen_pop_len(); /* If Arg2=3 or 4 */
274 }
275
276 acpigen_pop_len(); /* If uuid */
277
278 /* Return (Buffer (One) { 0x0 }) */
279 acpigen_write_return_singleton_buffer(0x0);
280
281 acpigen_pop_len(); /* Method _DSM */
282}
283
Matt Delco879b3c12020-06-17 13:10:22 +0530284static void camera_fill_ssdb_defaults(struct drivers_intel_mipi_camera_config *config)
Matt Delco1245b1e2020-06-17 07:26:55 +0530285{
Matt Delco879b3c12020-06-17 13:10:22 +0530286 struct device *cio2 = pcidev_on_root(CIO2_PCI_DEV, CIO2_PCI_FN);
287 struct drivers_intel_mipi_camera_config *cio2_config;
288
Matt Delco1245b1e2020-06-17 07:26:55 +0530289 if (config->disable_ssdb_defaults)
290 return;
291
CoolStar674ee502024-04-25 17:06:13 -0700292 guidcpy(&config->ssdb.csi2_data_stream_interface, &CSI2_DATA_STREAM_INTERFACE_GUID);
293
Matt Delco879b3c12020-06-17 13:10:22 +0530294 if (!config->ssdb.bdf_value)
295 config->ssdb.bdf_value = PCI_DEVFN(CIO2_PCI_DEV, CIO2_PCI_FN);
296
Matt Delco1245b1e2020-06-17 07:26:55 +0530297 if (!config->ssdb.platform)
298 config->ssdb.platform = PLATFORM_SKC;
299
300 if (!config->ssdb.flash_support)
301 config->ssdb.flash_support = FLASH_DISABLE;
302
303 if (!config->ssdb.privacy_led)
304 config->ssdb.privacy_led = PRIVACY_LED_A_16mA;
305
306 if (!config->ssdb.mipi_define)
307 config->ssdb.mipi_define = MIPI_INFO_ACPI_DEFINED;
308
309 if (!config->ssdb.mclk_speed)
310 config->ssdb.mclk_speed = CLK_FREQ_19_2MHZ;
Matt Delco879b3c12020-06-17 13:10:22 +0530311
312 if (!config->ssdb.lanes_used) {
313 cio2_config = cio2 ? cio2->chip_info : NULL;
314
315 if (!cio2_config) {
316 printk(BIOS_ERR, "Failed to get CIO2 config\n");
317 } else if (cio2_config->device_type != INTEL_ACPI_CAMERA_CIO2) {
318 printk(BIOS_ERR, "Device type isn't CIO2: %u\n",
319 (u32)cio2_config->device_type);
320 } else if (config->ssdb.link_used >= cio2_config->cio2_num_ports) {
321 printk(BIOS_ERR, "%u exceeds CIO2's %u links\n",
322 (u32)config->ssdb.link_used,
323 (u32)cio2_config->cio2_num_ports);
324 } else {
325 config->ssdb.lanes_used =
326 cio2_config->cio2_lanes_used[config->ssdb.link_used];
327 }
328 }
Matt Delco1245b1e2020-06-17 07:26:55 +0530329}
330
331/*
332 * Adds settings for a camera sensor device (typically at "\_SB.PCI0.I2Cx.CAMy"). The drivers
333 * for Linux tends to expect the camera sensor device and any related nvram / vcm devices to be
334 * separate ACPI devices, while the drivers for Windows want all of these to be grouped
335 * together in the camera sensor ACPI device. This implementation tries to satisfy both,
336 * though the unfortunate tradeoff is that the same I2C address for nvram and vcm is advertised
337 * by multiple devices in ACPI (via "_CRS"). The Windows driver can use the "_DSM" method to
338 * disambiguate the I2C resources in the camera sensor ACPI device. Drivers for Windows
339 * typically query "SSDB" for configuration information (represented as a binary blob dump of
340 * struct), while Linux drivers typically consult individual parameters in "_DSD".
341 *
342 * The tree of tables in "_DSD" is analogous to what's used for the "CIO2" device. The _DSD
343 * specifies a child table for the sensor's port (e.g., PRT0 for "port0"--this implementation
344 * assumes a camera only has 1 port). The PRT0 table specifies a table for each endpoint
345 * (though only 1 endpoint is supported by this implementation so the table only has an
346 * "endpoint0" that points to a EP00 table). The EP00 table primarily describes the # of lanes
347 * in "data-lines", a list of frequencies in "list-frequencies", and specifies the name of the
348 * other side in "remote-endpoint" (typically "\_SB.PCI0.CIO2").
349 */
350static void camera_fill_sensor(const struct device *dev)
351{
352 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
353 struct acpi_dp *ep00 = NULL;
354 struct acpi_dp *prt0 = NULL;
355 struct acpi_dp *dsd = NULL;
356 struct acpi_dp *remote = NULL;
357 const char *vcm_name = NULL;
358 struct acpi_dp *lens_focus = NULL;
Matt Delco879b3c12020-06-17 13:10:22 +0530359 const char *remote_name;
360 struct device *cio2 = pcidev_on_root(CIO2_PCI_DEV, CIO2_PCI_FN);
Matt Delco1245b1e2020-06-17 07:26:55 +0530361
Matt Delco1ffee9d2020-06-17 12:55:35 +0530362 camera_generate_pld(dev);
363
Matt Delco879b3c12020-06-17 13:10:22 +0530364 camera_fill_ssdb_defaults(config);
Matt Delco1245b1e2020-06-17 07:26:55 +0530365
Matt Delco964033f2020-06-17 12:49:43 +0530366 /* _DSM */
367 camera_generate_dsm(dev);
368
Matt Delco1245b1e2020-06-17 07:26:55 +0530369 ep00 = acpi_dp_new_table("EP00");
370 acpi_dp_add_integer(ep00, "endpoint", DEFAULT_ENDPOINT);
371 acpi_dp_add_integer(ep00, "clock-lanes", 0);
372
373 if (config->ssdb.lanes_used > 0) {
374 struct acpi_dp *lanes = acpi_dp_new_table("data-lanes");
375 uint32_t i;
376 for (i = 1; i <= config->ssdb.lanes_used; ++i)
377 acpi_dp_add_integer(lanes, NULL, i);
378 acpi_dp_add_array(ep00, lanes);
379 }
380
381 if (config->num_freq_entries) {
382 struct acpi_dp *freq = acpi_dp_new_table("link-frequencies");
383 uint32_t i;
384 for (i = 0; i < config->num_freq_entries && i < MAX_LINK_FREQ_ENTRIES; ++i)
385 acpi_dp_add_integer(freq, NULL, config->link_freq[i]);
386 acpi_dp_add_array(ep00, freq);
387 }
388
389 remote = acpi_dp_new_table("remote-endpoint");
390
Matt Delco879b3c12020-06-17 13:10:22 +0530391 if (config->remote_name) {
392 remote_name = config->remote_name;
393 } else {
394 if (cio2)
395 remote_name = acpi_device_path(cio2);
396 else
397 remote_name = DEFAULT_REMOTE_NAME;
398 }
399
400 acpi_dp_add_reference(remote, NULL, remote_name);
Matt Delco1245b1e2020-06-17 07:26:55 +0530401 acpi_dp_add_integer(remote, NULL, config->ssdb.link_used);
402 acpi_dp_add_integer(remote, NULL, DEFAULT_ENDPOINT);
403 acpi_dp_add_array(ep00, remote);
404
405 prt0 = acpi_dp_new_table("PRT0");
406
407 acpi_dp_add_integer(prt0, "port", 0);
408 acpi_dp_add_child(prt0, "endpoint0", ep00);
409 dsd = acpi_dp_new_table("_DSD");
410
411 acpi_dp_add_integer(dsd, "clock-frequency", config->ssdb.mclk_speed);
412
413 if (config->ssdb.degree)
414 acpi_dp_add_integer(dsd, "rotation", 180);
415
416 if (config->ssdb.vcm_type) {
417 if (config->vcm_name) {
418 vcm_name = config->vcm_name;
419 } else {
420 const struct device_path path = {
421 .type = DEVICE_PATH_I2C,
422 .i2c.device = config->vcm_address,
423 };
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200424 struct device *vcm_dev = find_dev_path(dev->upstream, &path);
Matt Delco1245b1e2020-06-17 07:26:55 +0530425 struct drivers_intel_mipi_camera_config *vcm_config;
426 vcm_config = vcm_dev ? vcm_dev->chip_info : NULL;
427
428 if (!vcm_config)
429 printk(BIOS_ERR, "Failed to get VCM\n");
430 else if (vcm_config->device_type != INTEL_ACPI_CAMERA_VCM)
431 printk(BIOS_ERR, "Device isn't VCM\n");
432 else
433 vcm_name = acpi_device_path(vcm_dev);
434 }
435 }
436
437 if (vcm_name) {
438 lens_focus = acpi_dp_new_table("lens-focus");
439 acpi_dp_add_reference(lens_focus, NULL, vcm_name);
440 acpi_dp_add_array(dsd, lens_focus);
441 }
442
Sugnan Prabhu S60be9db2021-02-09 10:31:15 +0530443 if (config->low_power_probe)
444 acpi_dp_add_integer(dsd, "i2c-allow-low-power-probe", 0x01);
445
Matt Delco1245b1e2020-06-17 07:26:55 +0530446 acpi_dp_add_child(dsd, "port0", prt0);
447 acpi_dp_write(dsd);
448
449 acpigen_write_method_serialized("SSDB", 0);
450 acpigen_write_return_byte_buffer((uint8_t *)&config->ssdb, sizeof(config->ssdb));
451 acpigen_pop_len(); /* Method */
452
453 /* Fill Power Sequencing Data */
454 if (config->num_pwdb_entries > 0) {
455 acpigen_write_method_serialized("PWDB", 0);
456 acpigen_write_return_byte_buffer((uint8_t *)&config->pwdb,
457 sizeof(struct intel_pwdb) *
458 config->num_pwdb_entries);
459 acpigen_pop_len(); /* Method */
460 }
461}
462
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530463static void camera_fill_nvm(const struct device *dev)
464{
465 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
John Zhao388e5512020-09-18 11:54:05 -0700466 struct acpi_dp *dsd;
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530467
Pandya, Varshit Bcd91db92020-09-03 20:38:46 +0530468 if (!config->nvm_compat)
469 return;
470
John Zhao388e5512020-09-18 11:54:05 -0700471 dsd = acpi_dp_new_table("_DSD");
472
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530473 /* It might be possible to default size or width based on type. */
474 if (!config->disable_nvm_defaults && !config->nvm_pagesize)
475 config->nvm_pagesize = 1;
476
477 if (!config->disable_nvm_defaults && !config->nvm_readonly)
478 config->nvm_readonly = 1;
479
480 if (config->nvm_size)
481 acpi_dp_add_integer(dsd, "size", config->nvm_size);
482
483 if (config->nvm_pagesize)
484 acpi_dp_add_integer(dsd, "pagesize", config->nvm_pagesize);
485
486 if (config->nvm_readonly)
487 acpi_dp_add_integer(dsd, "read-only", config->nvm_readonly);
488
489 if (config->nvm_width)
490 acpi_dp_add_integer(dsd, "address-width", config->nvm_width);
491
Pandya, Varshit Bcd91db92020-09-03 20:38:46 +0530492 acpi_dp_add_string(dsd, "compatible", config->nvm_compat);
Sugnan Prabhu S60be9db2021-02-09 10:31:15 +0530493
494 if (config->low_power_probe)
495 acpi_dp_add_integer(dsd, "i2c-allow-low-power-probe", 0x01);
496
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530497 acpi_dp_write(dsd);
498}
499
500static void camera_fill_vcm(const struct device *dev)
501{
502 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
503 struct acpi_dp *dsd;
504
505 if (!config->vcm_compat)
506 return;
507
508 dsd = acpi_dp_new_table("_DSD");
509 acpi_dp_add_string(dsd, "compatible", config->vcm_compat);
Sugnan Prabhu S60be9db2021-02-09 10:31:15 +0530510
511 if (config->low_power_probe)
512 acpi_dp_add_integer(dsd, "i2c-allow-low-power-probe", 0x01);
513
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530514 acpi_dp_write(dsd);
515}
516
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530517static int get_resource_index(const struct resource_config *res_config)
518{
519 enum ctrl_type type = resource_get_ctrl_type(res_config);
520 const struct clk_config *clk_config;
521 const struct gpio_config *gpio_config;
522 unsigned int i;
523 uint8_t res_id;
524
525 switch (type) {
526 case IMGCLK:
527 clk_config = resource_clk_config(res_config);
528 res_id = clk_config->clknum;
529 break;
530 case GPIO:
531 gpio_config = resource_gpio_config(res_config);
532 res_id = gpio_config->gpio_num;
533 break;
534 default:
535 printk(BIOS_ERR, "Unsupported power operation: %x\n"
536 "OS camera driver will likely not work", type);
537 return -1;
538 }
539
540 for (i = 0; i < res_mgr.cnt; i++)
541 if (res_mgr.resource[i].type == type && res_mgr.resource[i].id == res_id)
542 return i;
543
544 return -1;
545}
546
547static void add_guarded_method_namestring(struct resource_config *res_config, int res_index)
548{
549 char method_name[ACPI_NAME_BUFFER_SIZE];
550 enum action_type action = resource_get_action_type(res_config);
551
552 switch (action) {
553 case ENABLE:
554 snprintf(method_name, sizeof(method_name), ENABLE_METHOD_FORMAT, res_index);
555 break;
556 case DISABLE:
557 snprintf(method_name, sizeof(method_name), DISABLE_METHOD_FORMAT, res_index);
558 break;
559 default:
560 snprintf(method_name, sizeof(method_name), UNKNOWN_METHOD_FORMAT, res_index);
561 printk(BIOS_ERR, "Unsupported resource action: %x\n", action);
562 }
563
564 acpigen_emit_namestring(method_name);
565}
566
567static void call_guarded_method(struct resource_config *res_config)
568{
569 int res_index;
570
571 if (res_config == NULL)
572 return;
573
574 res_index = get_resource_index(res_config);
575
576 if (res_index != -1)
577 add_guarded_method_namestring(res_config, res_index);
578}
579
580static void add_clk_op(const struct clk_config *clk_config, enum action_type action)
581{
582 if (clk_config == NULL)
583 return;
584
585 switch (action) {
586 case ENABLE:
587 acpigen_write_if();
588 acpigen_emit_ext_op(COND_REFOF_OP);
589 acpigen_emit_string(CLK_ENABLE_METHOD);
590 acpigen_emit_namestring(CLK_ENABLE_METHOD);
591 acpigen_write_integer(clk_config->clknum);
592 acpigen_write_integer(clk_config->freq);
593 acpigen_pop_len(); /* CondRefOf */
594 break;
595 case DISABLE:
596 acpigen_write_if();
597 acpigen_emit_ext_op(COND_REFOF_OP);
598 acpigen_emit_string(CLK_DISABLE_METHOD);
599 acpigen_emit_namestring(CLK_DISABLE_METHOD);
600 acpigen_write_integer(clk_config->clknum);
601 acpigen_pop_len(); /* CondRefOf */
602 break;
603 default:
604 acpigen_write_debug_string("Unsupported clock action");
605 printk(BIOS_ERR, "Unsupported clock action: %x\n"
606 "OS camera driver will likely not work", action);
607 }
608}
609
610static void add_gpio_op(const struct gpio_config *gpio_config, enum action_type action)
611{
612 if (gpio_config == NULL)
613 return;
614
615 switch (action) {
616 case ENABLE:
617 acpigen_soc_set_tx_gpio(gpio_config->gpio_num);
618 break;
619 case DISABLE:
620 acpigen_soc_clear_tx_gpio(gpio_config->gpio_num);
621 break;
622 default:
623 acpigen_write_debug_string("Unsupported GPIO action");
624 printk(BIOS_ERR, "Unsupported GPIO action: %x\n"
625 "OS camera driver will likely not work\n", action);
626 }
627}
628
629static void add_power_operation(const struct resource_config *res_config)
630{
631 const struct clk_config *clk_config;
632 const struct gpio_config *gpio_config;
633 enum ctrl_type type = resource_get_ctrl_type(res_config);
634 enum action_type action = resource_get_action_type(res_config);
635
636 if (res_config == NULL)
637 return;
638
639 switch (type) {
640 case IMGCLK:
641 clk_config = resource_clk_config(res_config);
642 add_clk_op(clk_config, action);
643 break;
644 case GPIO:
645 gpio_config = resource_gpio_config(res_config);
646 add_gpio_op(gpio_config, action);
647 break;
648 default:
649 printk(BIOS_ERR, "Unsupported power operation: %x\n"
650 "OS camera driver will likely not work\n", type);
651 break;
652 }
653}
654
655static void write_guard_variable(uint8_t res_index)
656{
657 char varname[ACPI_NAME_BUFFER_SIZE];
658
659 snprintf(varname, sizeof(varname), GUARD_VARIABLE_FORMAT, res_index);
660 acpigen_write_name_integer(varname, 0);
661}
662
663static void write_enable_method(struct resource_config *res_config, uint8_t res_index)
664{
665 char method_name[ACPI_NAME_BUFFER_SIZE];
666 char varname[ACPI_NAME_BUFFER_SIZE];
667
668 snprintf(varname, sizeof(varname), GUARD_VARIABLE_FORMAT, res_index);
669
670 snprintf(method_name, sizeof(method_name), ENABLE_METHOD_FORMAT, res_index);
671
672 acpigen_write_method_serialized(method_name, 0);
673 acpigen_write_if_lequal_namestr_int(varname, 0);
674 resource_set_action_type(res_config, ENABLE);
675 add_power_operation(res_config);
676 acpigen_pop_len(); /* if */
677
678 acpigen_emit_byte(INCREMENT_OP);
679 acpigen_emit_namestring(varname);
680 acpigen_pop_len(); /* method_name */
681}
682
683static void write_disable_method(struct resource_config *res_config, uint8_t res_index)
684{
685 char method_name[ACPI_NAME_BUFFER_SIZE];
686 char varname[ACPI_NAME_BUFFER_SIZE];
687
688 snprintf(varname, sizeof(varname), GUARD_VARIABLE_FORMAT, res_index);
689
690 snprintf(method_name, sizeof(method_name), DISABLE_METHOD_FORMAT, res_index);
691
692 acpigen_write_method_serialized(method_name, 0);
693 acpigen_write_if();
694 acpigen_emit_byte(LGREATER_OP);
695 acpigen_emit_namestring(varname);
696 acpigen_write_integer(0x0);
697 acpigen_emit_byte(DECREMENT_OP);
698 acpigen_emit_namestring(varname);
699 acpigen_pop_len(); /* if */
700
701 acpigen_write_if_lequal_namestr_int(varname, 0);
702 resource_set_action_type(res_config, DISABLE);
703 add_power_operation(res_config);
704 acpigen_pop_len(); /* if */
705 acpigen_pop_len(); /* method_name */
706}
707
708static void add_guarded_operations(const struct drivers_intel_mipi_camera_config *config,
709 const struct operation_seq *seq)
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530710{
711 unsigned int i;
712 uint8_t index;
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530713 uint8_t res_id;
714 struct resource_config res_config;
715 int res_index;
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530716
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530717 for (i = 0; i < seq->ops_cnt && i < MAX_PWR_OPS; i++) {
718 index = seq->ops[i].index;
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530719 switch (seq->ops[i].type) {
720 case IMGCLK:
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530721 res_id = config->clk_panel.clks[index].clknum;
722 resource_set_clk_config(&res_config, &config->clk_panel.clks[index]);
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530723 break;
724 case GPIO:
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530725 res_id = config->gpio_panel.gpio[index].gpio_num;
726 resource_set_gpio_config(&res_config, &config->gpio_panel.gpio[index]);
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530727 break;
728 default:
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530729 printk(BIOS_ERR, "Unsupported power operation: %x\n"
730 "OS camera driver will likely not work\n",
731 seq->ops[i].type);
732 return;
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530733 }
734
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530735 res_index = get_resource_index(&res_config);
736
737 if (res_index == -1) {
738 if (res_mgr.cnt >= MAX_GUARDED_RESOURCES) {
739 printk(BIOS_ERR, "Unable to add guarded camera resource\n"
740 "OS camera driver will likely not work\n");
741 return;
742 }
743
744 res_mgr.resource[res_mgr.cnt].id = res_id;
745 res_mgr.resource[res_mgr.cnt].type = seq->ops[i].type;
746
747 write_guard_variable(res_mgr.cnt);
748 write_enable_method(&res_config, res_mgr.cnt);
749 write_disable_method(&res_config, res_mgr.cnt);
750
751 res_mgr.cnt++;
752 }
753 }
754}
755
756static void fill_power_res_sequence(struct drivers_intel_mipi_camera_config *config,
757 struct operation_seq *seq)
758{
759 struct resource_config res_config;
760 unsigned int i;
761 uint8_t index;
762
763 for (i = 0; i < seq->ops_cnt && i < MAX_PWR_OPS; i++) {
764 index = seq->ops[i].index;
765
766 switch (seq->ops[i].type) {
767 case IMGCLK:
768 resource_set_clk_config(&res_config, &config->clk_panel.clks[index]);
769 break;
770 case GPIO:
771 resource_set_gpio_config(&res_config, &config->gpio_panel.gpio[index]);
772 break;
773 default:
774 printk(BIOS_ERR, "Unsupported power operation: %x\n"
775 "OS camera driver will likely not work\n",
776 seq->ops[i].type);
777 return;
778 }
779
780 resource_set_action_type(&res_config, seq->ops[i].action);
781 call_guarded_method(&res_config);
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530782 if (seq->ops[i].delay_ms)
783 acpigen_write_sleep(seq->ops[i].delay_ms);
784 }
785}
786
Matt Delco7d002932020-06-16 11:39:52 +0530787static void write_pci_camera_device(const struct device *dev)
V Sowmya9f8023a2017-02-28 17:52:05 +0530788{
Matt Delco7d002932020-06-16 11:39:52 +0530789 if (dev->path.type != DEVICE_PATH_PCI) {
790 printk(BIOS_ERR, "CIO2/IMGU devices require PCI\n");
791 return;
792 }
793
794 acpigen_write_device(acpi_device_name(dev));
795 acpigen_write_ADR_pci_device(dev);
Sugnan Prabhu S3ea036f2020-07-29 23:18:46 +0530796 acpigen_write_name_string("_DDN", "Camera and Imaging Subsystem");
Matt Delco7d002932020-06-16 11:39:52 +0530797}
798
799static void write_i2c_camera_device(const struct device *dev, const char *scope)
800{
801 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
V Sowmya9f8023a2017-02-28 17:52:05 +0530802 struct acpi_i2c i2c = {
803 .address = dev->path.i2c.device,
804 .mode_10bit = dev->path.i2c.mode_10bit,
805 .speed = I2C_SPEED_FAST,
806 .resource = scope,
807 };
808
V Sowmya9f8023a2017-02-28 17:52:05 +0530809 acpigen_write_device(acpi_device_name(dev));
Matt Delco7d002932020-06-16 11:39:52 +0530810
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530811 /* add power resource */
812 if (config->has_power_resource) {
813 acpigen_write_power_res(POWER_RESOURCE_NAME, 0, 0, NULL, 0);
814 acpigen_write_name_integer("STA", 0);
815 acpigen_write_STA_ext("STA");
816
817 acpigen_write_method_serialized("_ON", 0);
818 acpigen_write_if();
819 acpigen_emit_byte(LEQUAL_OP);
820 acpigen_emit_namestring("STA");
821 acpigen_write_integer(0);
822
823 fill_power_res_sequence(config, &config->on_seq);
824
825 acpigen_write_store_op_to_namestr(1, "STA");
826 acpigen_pop_len(); /* if */
827 acpigen_pop_len(); /* _ON */
828
829 /* _OFF operations */
830 acpigen_write_method_serialized("_OFF", 0);
831 acpigen_write_if();
832 acpigen_emit_byte(LEQUAL_OP);
833 acpigen_emit_namestring("STA");
834 acpigen_write_integer(1);
835
836 fill_power_res_sequence(config, &config->off_seq);
837
838 acpigen_write_store_op_to_namestr(0, "STA");
839 acpigen_pop_len(); /* if */
840 acpigen_pop_len(); /* _ON */
841
842 acpigen_pop_len(); /* Power Resource */
843 }
844
Matt Delco7d002932020-06-16 11:39:52 +0530845 if (config->device_type == INTEL_ACPI_CAMERA_SENSOR)
846 acpigen_write_name_integer("_ADR", 0);
847
848 if (config->acpi_hid)
849 acpigen_write_name_string("_HID", config->acpi_hid);
Pandya, Varshit Bcd91db92020-09-03 20:38:46 +0530850 else if (config->device_type == INTEL_ACPI_CAMERA_VCM ||
851 config->device_type == INTEL_ACPI_CAMERA_NVM)
Matt Delco7d002932020-06-16 11:39:52 +0530852 acpigen_write_name_string("_HID", ACPI_DT_NAMESPACE_HID);
Matt Delco7d002932020-06-16 11:39:52 +0530853
V Sowmya9f8023a2017-02-28 17:52:05 +0530854 acpigen_write_name_integer("_UID", config->acpi_uid);
855 acpigen_write_name_string("_DDN", config->chip_name);
Hung-Te Linb4be50c2018-09-10 10:55:49 +0800856 acpigen_write_STA(acpi_device_status(dev));
Varshit B Pandya04e8c2b2021-10-27 10:41:32 +0530857 acpigen_write_method("_DSC", 0);
858 acpigen_write_return_integer(config->max_dstate_for_probe);
859 acpigen_pop_len(); /* Method _DSC */
V Sowmya9f8023a2017-02-28 17:52:05 +0530860
861 /* Resources */
862 acpigen_write_name("_CRS");
863 acpigen_write_resourcetemplate_header();
864 acpi_device_write_i2c(&i2c);
V Sowmya9f8023a2017-02-28 17:52:05 +0530865
Matt Delco7d002932020-06-16 11:39:52 +0530866 /*
867 * The optional vcm/nvram devices are presumed to be on the same I2C bus as the camera
868 * sensor.
869 */
870 if (config->device_type == INTEL_ACPI_CAMERA_SENSOR &&
871 config->ssdb.vcm_type && config->vcm_address) {
872 struct acpi_i2c i2c_vcm = i2c;
873 i2c_vcm.address = config->vcm_address;
874 acpi_device_write_i2c(&i2c_vcm);
V Sowmya9f8023a2017-02-28 17:52:05 +0530875 }
876
Matt Delco7d002932020-06-16 11:39:52 +0530877 if (config->device_type == INTEL_ACPI_CAMERA_SENSOR &&
878 config->ssdb.rom_type && config->rom_address) {
879 struct acpi_i2c i2c_rom = i2c;
880 i2c_rom.address = config->rom_address;
881 acpi_device_write_i2c(&i2c_rom);
882 }
883
884 acpigen_write_resourcetemplate_footer();
885}
886
887static void write_camera_device_common(const struct device *dev)
888{
889 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
890
891 /* Mark it as Camera related device */
892 if (config->device_type == INTEL_ACPI_CAMERA_CIO2 ||
893 config->device_type == INTEL_ACPI_CAMERA_IMGU ||
894 config->device_type == INTEL_ACPI_CAMERA_SENSOR ||
895 config->device_type == INTEL_ACPI_CAMERA_VCM) {
896 acpigen_write_name_integer("CAMD", config->device_type);
897 }
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530898
Sugnan Prabhu Sb087a942020-05-21 20:41:03 +0530899 if (config->pr0 || config->has_power_resource) {
900 acpigen_write_name("_PR0");
901 acpigen_write_package(1);
902 if (config->pr0)
903 acpigen_emit_namestring(config->pr0); /* External power resource */
904 else
905 acpigen_emit_namestring(POWER_RESOURCE_NAME);
906
907 acpigen_pop_len(); /* _PR0 */
908 }
909
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530910 switch (config->device_type) {
Matt Delco879b3c12020-06-17 13:10:22 +0530911 case INTEL_ACPI_CAMERA_CIO2:
912 camera_fill_cio2(dev);
913 break;
Matt Delco1245b1e2020-06-17 07:26:55 +0530914 case INTEL_ACPI_CAMERA_SENSOR:
915 camera_fill_sensor(dev);
916 break;
Matt Delcoc3a83bf2020-06-16 12:02:34 +0530917 case INTEL_ACPI_CAMERA_VCM:
918 camera_fill_vcm(dev);
919 break;
920 case INTEL_ACPI_CAMERA_NVM:
921 camera_fill_nvm(dev);
922 break;
923 default:
924 break;
925 }
Matt Delco7d002932020-06-16 11:39:52 +0530926}
927
928static void camera_fill_ssdt(const struct device *dev)
929{
930 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530931 const char *scope = NULL;
932 const struct device *pdev;
Matt Delco7d002932020-06-16 11:39:52 +0530933
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530934 if (config->has_power_resource) {
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200935 pdev = dev->upstream->dev;
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530936 if (!pdev || !pdev->enabled)
937 return;
938
939 scope = acpi_device_scope(pdev);
940 if (!scope)
941 return;
942
943 acpigen_write_scope(scope);
944 add_guarded_operations(config, &config->on_seq);
945 add_guarded_operations(config, &config->off_seq);
946 acpigen_pop_len(); /* Guarded power resource operations scope */
947 }
948
Sugnan Prabhu S3ea036f2020-07-29 23:18:46 +0530949 switch (dev->path.type) {
950 case DEVICE_PATH_I2C:
951 scope = acpi_device_scope(dev);
952 if (!scope)
953 return;
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530954
Sugnan Prabhu S3ea036f2020-07-29 23:18:46 +0530955 acpigen_write_scope(scope);
Matt Delco7d002932020-06-16 11:39:52 +0530956 write_i2c_camera_device(dev, scope);
Sugnan Prabhu S3ea036f2020-07-29 23:18:46 +0530957 break;
958 case DEVICE_PATH_GENERIC:
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200959 pdev = dev->upstream->dev;
Sugnan Prabhu S3ea036f2020-07-29 23:18:46 +0530960 scope = acpi_device_scope(pdev);
961 if (!scope)
962 return;
963
964 acpigen_write_scope(scope);
965 write_pci_camera_device(pdev);
966 break;
967 default:
968 printk(BIOS_ERR, "Unsupported device type: %x\n"
969 "OS camera driver will likely not work\n", dev->path.type);
970 return;
971 }
Matt Delco7d002932020-06-16 11:39:52 +0530972
973 write_camera_device_common(dev);
V Sowmya9f8023a2017-02-28 17:52:05 +0530974
975 acpigen_pop_len(); /* Device */
976 acpigen_pop_len(); /* Scope */
Matt Delco7d002932020-06-16 11:39:52 +0530977
978 if (dev->path.type == DEVICE_PATH_PCI) {
979 printk(BIOS_INFO, "%s: %s PCI address 0%x\n", acpi_device_path(dev),
980 dev->chip_ops->name, dev->path.pci.devfn);
981 } else {
982 printk(BIOS_INFO, "%s: %s I2C address 0%xh\n", acpi_device_path(dev),
983 dev->chip_ops->name, dev->path.i2c.device);
984 }
V Sowmya9f8023a2017-02-28 17:52:05 +0530985}
986
Aaron Durbinaa090cb2017-09-13 16:01:52 -0600987static const char *camera_acpi_name(const struct device *dev)
V Sowmya9f8023a2017-02-28 17:52:05 +0530988{
Matt Delco7d002932020-06-16 11:39:52 +0530989 const char *prefix = NULL;
Sugnan Prabhu S6d9f2432020-07-02 13:02:23 +0530990 static char name[ACPI_NAME_BUFFER_SIZE];
V Sowmya9f8023a2017-02-28 17:52:05 +0530991 struct drivers_intel_mipi_camera_config *config = dev->chip_info;
Matt Delco7d002932020-06-16 11:39:52 +0530992
993 if (config->acpi_name)
994 return config->acpi_name;
995
996 switch (config->device_type) {
997 case INTEL_ACPI_CAMERA_CIO2:
998 return "CIO2";
999 case INTEL_ACPI_CAMERA_IMGU:
1000 return "IMGU";
1001 case INTEL_ACPI_CAMERA_PMIC:
1002 return "PMIC";
1003 case INTEL_ACPI_CAMERA_SENSOR:
1004 prefix = "CAM";
1005 break;
1006 case INTEL_ACPI_CAMERA_VCM:
1007 prefix = "VCM";
1008 break;
1009 case INTEL_ACPI_CAMERA_NVM:
1010 prefix = "NVM";
1011 break;
1012 default:
1013 printk(BIOS_ERR, "Invalid device type: %x\n", config->device_type);
1014 return NULL;
1015 }
1016
1017 /*
1018 * The camera # knows which link # they use, so that's used as the basis for the
1019 * instance #. The VCM and NVM don't have this information, so the best we can go on is
1020 * the _UID.
1021 */
1022 snprintf(name, sizeof(name), "%s%1u", prefix,
1023 config->device_type == INTEL_ACPI_CAMERA_SENSOR ?
1024 config->ssdb.link_used : config->acpi_uid);
1025 return name;
V Sowmya9f8023a2017-02-28 17:52:05 +05301026}
1027
1028static struct device_operations camera_ops = {
Nico Huber2f8ba692020-04-05 14:05:24 +02001029 .read_resources = noop_read_resources,
1030 .set_resources = noop_set_resources,
Nico Huber68680dd2020-03-31 17:34:52 +02001031 .acpi_name = camera_acpi_name,
1032 .acpi_fill_ssdt = camera_fill_ssdt,
V Sowmya9f8023a2017-02-28 17:52:05 +05301033};
1034
1035static void camera_enable(struct device *dev)
1036{
1037 dev->ops = &camera_ops;
1038}
1039
1040struct chip_operations drivers_intel_mipi_camera_ops = {
Nicholas Sudsgaardbfb11be2024-01-30 09:53:46 +09001041 .name = "Intel MIPI Camera Device",
Elyes HAOUAS2aa3b162018-11-27 17:02:10 +01001042 .enable_dev = camera_enable
V Sowmya9f8023a2017-02-28 17:52:05 +05301043};