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