brintos

brintos / linux-shallow public Read only

0
0
Text · 63.1 KiB · 5ddfd3d Raw
2551 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Allied Vision Technologies GmbH Alvium camera driver4 *5 * Copyright (C) 2023 Tommaso Merciai6 * Copyright (C) 2023 Martin Hecht7 * Copyright (C) 2023 Avnet EMG GmbH8 */9 10#include <linux/i2c.h>11#include <linux/module.h>12#include <linux/pm_runtime.h>13#include <linux/regmap.h>14#include <linux/regulator/consumer.h>15#include <media/mipi-csi2.h>16#include <media/v4l2-async.h>17#include <media/v4l2-ctrls.h>18#include <media/v4l2-device.h>19#include <media/v4l2-event.h>20#include <media/v4l2-fwnode.h>21#include <media/v4l2-subdev.h>22 23#include "alvium-csi2.h"24 25static const struct v4l2_mbus_framefmt alvium_csi2_default_fmt = {26	.code = MEDIA_BUS_FMT_UYVY8_1X16,27	.width = 640,28	.height = 480,29	.colorspace = V4L2_COLORSPACE_SRGB,30	.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB),31	.quantization = V4L2_QUANTIZATION_FULL_RANGE,32	.xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB),33	.field = V4L2_FIELD_NONE,34};35 36static const struct alvium_pixfmt alvium_csi2_fmts[] = {37	{38		/* UYVY8_2X8 */39		.id = ALVIUM_FMT_UYVY8_2X8,40		.code = MEDIA_BUS_FMT_UYVY8_2X8,41		.colorspace = V4L2_COLORSPACE_SRGB,42		.fmt_av_bit = ALVIUM_BIT_YUV422_8,43		.bay_av_bit = ALVIUM_BIT_BAY_NONE,44		.mipi_fmt_regval = MIPI_CSI2_DT_YUV422_8B,45		.bay_fmt_regval = -1,46		.is_raw = 0,47	}, {48		/* UYVY8_1X16 */49		.id = ALVIUM_FMT_UYVY8_1X16,50		.code = MEDIA_BUS_FMT_UYVY8_1X16,51		.colorspace = V4L2_COLORSPACE_SRGB,52		.fmt_av_bit = ALVIUM_BIT_YUV422_8,53		.bay_av_bit = ALVIUM_BIT_BAY_NONE,54		.mipi_fmt_regval = MIPI_CSI2_DT_YUV422_8B,55		.bay_fmt_regval = -1,56		.is_raw = 0,57	}, {58		/* YUYV8_1X16 */59		.id = ALVIUM_FMT_YUYV8_1X16,60		.code = MEDIA_BUS_FMT_YUYV8_1X16,61		.colorspace = V4L2_COLORSPACE_SRGB,62		.fmt_av_bit = ALVIUM_BIT_YUV422_8,63		.bay_av_bit = ALVIUM_BIT_BAY_NONE,64		.mipi_fmt_regval = MIPI_CSI2_DT_YUV422_8B,65		.bay_fmt_regval = -1,66		.is_raw = 0,67	}, {68		/* YUYV8_2X8 */69		.id = ALVIUM_FMT_YUYV8_2X8,70		.code = MEDIA_BUS_FMT_YUYV8_2X8,71		.colorspace = V4L2_COLORSPACE_SRGB,72		.fmt_av_bit = ALVIUM_BIT_YUV422_8,73		.bay_av_bit = ALVIUM_BIT_BAY_NONE,74		.mipi_fmt_regval = MIPI_CSI2_DT_YUV422_8B,75		.bay_fmt_regval = -1,76		.is_raw = 0,77	}, {78		/* YUYV10_1X20 */79		.id = ALVIUM_FMT_YUYV10_1X20,80		.code = MEDIA_BUS_FMT_YUYV10_1X20,81		.colorspace = V4L2_COLORSPACE_SRGB,82		.fmt_av_bit = ALVIUM_BIT_YUV422_10,83		.bay_av_bit = ALVIUM_BIT_BAY_NONE,84		.mipi_fmt_regval = MIPI_CSI2_DT_YUV422_10B,85		.bay_fmt_regval = -1,86		.is_raw = 0,87	}, {88		/* RGB888_1X24 */89		.id = ALVIUM_FMT_RGB888_1X24,90		.code = MEDIA_BUS_FMT_RGB888_1X24,91		.colorspace = V4L2_COLORSPACE_SRGB,92		.fmt_av_bit = ALVIUM_BIT_RGB888,93		.bay_av_bit = ALVIUM_BIT_BAY_NONE,94		.mipi_fmt_regval = MIPI_CSI2_DT_RGB888,95		.bay_fmt_regval = -1,96		.is_raw = 0,97	}, {98		/* RBG888_1X24 */99		.id = ALVIUM_FMT_RBG888_1X24,100		.code = MEDIA_BUS_FMT_RBG888_1X24,101		.colorspace = V4L2_COLORSPACE_SRGB,102		.fmt_av_bit = ALVIUM_BIT_RGB888,103		.bay_av_bit = ALVIUM_BIT_BAY_NONE,104		.mipi_fmt_regval = MIPI_CSI2_DT_RGB888,105		.bay_fmt_regval = -1,106		.is_raw = 0,107	}, {108		/* BGR888_1X24 */109		.id = ALVIUM_FMT_BGR888_1X24,110		.code = MEDIA_BUS_FMT_BGR888_1X24,111		.colorspace = V4L2_COLORSPACE_SRGB,112		.fmt_av_bit = ALVIUM_BIT_RGB888,113		.bay_av_bit = ALVIUM_BIT_BAY_NONE,114		.mipi_fmt_regval = MIPI_CSI2_DT_RGB888,115		.bay_fmt_regval = -1,116		.is_raw = 0,117	}, {118		/* RGB888_3X8 */119		.id = ALVIUM_FMT_RGB888_3X8,120		.code = MEDIA_BUS_FMT_RGB888_3X8,121		.colorspace = V4L2_COLORSPACE_SRGB,122		.fmt_av_bit = ALVIUM_BIT_RGB888,123		.bay_av_bit = ALVIUM_BIT_BAY_NONE,124		.mipi_fmt_regval = MIPI_CSI2_DT_RGB888,125		.bay_fmt_regval = -1,126		.is_raw = 0,127	}, {128		/* Y8_1X8 */129		.id = ALVIUM_FMT_Y8_1X8,130		.code = MEDIA_BUS_FMT_Y8_1X8,131		.colorspace = V4L2_COLORSPACE_RAW,132		.fmt_av_bit = ALVIUM_BIT_RAW8,133		.bay_av_bit = ALVIUM_BIT_BAY_MONO,134		.mipi_fmt_regval = MIPI_CSI2_DT_RAW8,135		.bay_fmt_regval = 0x00,136		.is_raw = 1,137	}, {138		/* SGRBG8_1X8 */139		.id = ALVIUM_FMT_SGRBG8_1X8,140		.code = MEDIA_BUS_FMT_SGRBG8_1X8,141		.colorspace = V4L2_COLORSPACE_RAW,142		.fmt_av_bit = ALVIUM_BIT_RAW8,143		.bay_av_bit = ALVIUM_BIT_BAY_GR,144		.mipi_fmt_regval = MIPI_CSI2_DT_RAW8,145		.bay_fmt_regval = 0x01,146		.is_raw = 1,147	}, {148		/* SRGGB8_1X8 */149		.id = ALVIUM_FMT_SRGGB8_1X8,150		.code = MEDIA_BUS_FMT_SRGGB8_1X8,151		.colorspace = V4L2_COLORSPACE_RAW,152		.fmt_av_bit = ALVIUM_BIT_RAW8,153		.bay_av_bit = ALVIUM_BIT_BAY_RG,154		.mipi_fmt_regval = MIPI_CSI2_DT_RAW8,155		.bay_fmt_regval = 0x02,156		.is_raw = 1,157	}, {158		/* SGBRG8_1X8 */159		.id = ALVIUM_FMT_SGBRG8_1X8,160		.code = MEDIA_BUS_FMT_SGBRG8_1X8,161		.colorspace = V4L2_COLORSPACE_RAW,162		.fmt_av_bit = ALVIUM_BIT_RAW8,163		.bay_av_bit = ALVIUM_BIT_BAY_GB,164		.mipi_fmt_regval = MIPI_CSI2_DT_RAW8,165		.bay_fmt_regval = 0x03,166		.is_raw = 1,167	}, {168		/* SBGGR8_1X8 */169		.id = ALVIUM_FMT_SBGGR8_1X8,170		.code = MEDIA_BUS_FMT_SBGGR8_1X8,171		.colorspace = V4L2_COLORSPACE_RAW,172		.fmt_av_bit = ALVIUM_BIT_RAW8,173		.bay_av_bit = ALVIUM_BIT_BAY_BG,174		.mipi_fmt_regval = MIPI_CSI2_DT_RAW8,175		.bay_fmt_regval = 0x04,176		.is_raw = 1,177	}, {178		/* Y10_1X10 */179		.id = ALVIUM_FMT_Y10_1X10,180		.code = MEDIA_BUS_FMT_Y10_1X10,181		.colorspace = V4L2_COLORSPACE_RAW,182		.fmt_av_bit = ALVIUM_BIT_RAW10,183		.bay_av_bit = ALVIUM_BIT_BAY_MONO,184		.mipi_fmt_regval = MIPI_CSI2_DT_RAW10,185		.bay_fmt_regval = 0x00,186		.is_raw = 1,187	}, {188		/* SGRBG10_1X10 */189		.id = ALVIUM_FMT_SGRBG10_1X10,190		.code = MEDIA_BUS_FMT_SGRBG10_1X10,191		.colorspace = V4L2_COLORSPACE_RAW,192		.fmt_av_bit = ALVIUM_BIT_RAW10,193		.bay_av_bit = ALVIUM_BIT_BAY_GR,194		.mipi_fmt_regval = MIPI_CSI2_DT_RAW10,195		.bay_fmt_regval = 0x01,196		.is_raw = 1,197	}, {198		/* SRGGB10_1X10 */199		.id = ALVIUM_FMT_SRGGB10_1X10,200		.code = MEDIA_BUS_FMT_SRGGB10_1X10,201		.colorspace = V4L2_COLORSPACE_RAW,202		.fmt_av_bit = ALVIUM_BIT_RAW10,203		.bay_av_bit = ALVIUM_BIT_BAY_RG,204		.mipi_fmt_regval = MIPI_CSI2_DT_RAW10,205		.bay_fmt_regval = 0x02,206		.is_raw = 1,207	}, {208		/* SGBRG10_1X10 */209		.id = ALVIUM_FMT_SGBRG10_1X10,210		.code = MEDIA_BUS_FMT_SGBRG10_1X10,211		.colorspace = V4L2_COLORSPACE_RAW,212		.fmt_av_bit = ALVIUM_BIT_RAW10,213		.bay_av_bit = ALVIUM_BIT_BAY_GB,214		.mipi_fmt_regval = MIPI_CSI2_DT_RAW10,215		.bay_fmt_regval = 0x03,216		.is_raw = 1,217	}, {218		/* SBGGR10_1X10 */219		.id = ALVIUM_FMT_SBGGR10_1X10,220		.code = MEDIA_BUS_FMT_SBGGR10_1X10,221		.colorspace = V4L2_COLORSPACE_RAW,222		.fmt_av_bit = ALVIUM_BIT_RAW10,223		.bay_av_bit = ALVIUM_BIT_BAY_BG,224		.mipi_fmt_regval = MIPI_CSI2_DT_RAW10,225		.bay_fmt_regval = 0x04,226		.is_raw = 1,227	}, {228		/* Y12_1X12 */229		.id = ALVIUM_FMT_Y12_1X12,230		.code = MEDIA_BUS_FMT_Y12_1X12,231		.colorspace = V4L2_COLORSPACE_RAW,232		.fmt_av_bit = ALVIUM_BIT_RAW12,233		.bay_av_bit = ALVIUM_BIT_BAY_MONO,234		.mipi_fmt_regval = MIPI_CSI2_DT_RAW12,235		.bay_fmt_regval = 0x00,236		.is_raw = 1,237	}, {238		/* SGRBG12_1X12 */239		.id = ALVIUM_FMT_SGRBG12_1X12,240		.code = MEDIA_BUS_FMT_SGRBG12_1X12,241		.colorspace = V4L2_COLORSPACE_RAW,242		.fmt_av_bit = ALVIUM_BIT_RAW12,243		.bay_av_bit = ALVIUM_BIT_BAY_GR,244		.mipi_fmt_regval = MIPI_CSI2_DT_RAW12,245		.bay_fmt_regval = 0x01,246		.is_raw = 1,247	}, {248		/* SRGGB12_1X12 */249		.id = ALVIUM_FMT_SRGGB12_1X12,250		.code = MEDIA_BUS_FMT_SRGGB12_1X12,251		.colorspace = V4L2_COLORSPACE_RAW,252		.fmt_av_bit = ALVIUM_BIT_RAW12,253		.bay_av_bit = ALVIUM_BIT_BAY_RG,254		.mipi_fmt_regval = MIPI_CSI2_DT_RAW12,255		.bay_fmt_regval = 0x02,256		.is_raw = 1,257	}, {258		/* SGBRG12_1X12 */259		.id = ALVIUM_FMT_SGBRG12_1X12,260		.code = MEDIA_BUS_FMT_SGBRG12_1X12,261		.colorspace = V4L2_COLORSPACE_RAW,262		.fmt_av_bit = ALVIUM_BIT_RAW12,263		.bay_av_bit = ALVIUM_BIT_BAY_GB,264		.mipi_fmt_regval = MIPI_CSI2_DT_RAW12,265		.bay_fmt_regval = 0x03,266		.is_raw = 1,267	}, {268		/* SBGGR12_1X12 */269		.id = ALVIUM_FMT_SBGGR12_1X12,270		.code = MEDIA_BUS_FMT_SBGGR12_1X12,271		.colorspace = V4L2_COLORSPACE_RAW,272		.fmt_av_bit = ALVIUM_BIT_RAW12,273		.bay_av_bit = ALVIUM_BIT_BAY_BG,274		.mipi_fmt_regval = MIPI_CSI2_DT_RAW12,275		.bay_fmt_regval = 0x04,276		.is_raw = 1,277	}, {278		/* SBGGR14_1X14 */279		.id = ALVIUM_FMT_SBGGR14_1X14,280		.code = MEDIA_BUS_FMT_SBGGR14_1X14,281		.colorspace = V4L2_COLORSPACE_RAW,282		.fmt_av_bit = ALVIUM_BIT_RAW14,283		.bay_av_bit = ALVIUM_BIT_BAY_GR,284		.mipi_fmt_regval = MIPI_CSI2_DT_RAW14,285		.bay_fmt_regval = 0x01,286		.is_raw = 1,287	}, {288		/* SGBRG14_1X14 */289		.id = ALVIUM_FMT_SGBRG14_1X14,290		.code = MEDIA_BUS_FMT_SGBRG14_1X14,291		.colorspace = V4L2_COLORSPACE_RAW,292		.fmt_av_bit = ALVIUM_BIT_RAW14,293		.bay_av_bit = ALVIUM_BIT_BAY_RG,294		.mipi_fmt_regval = MIPI_CSI2_DT_RAW14,295		.bay_fmt_regval = 0x02,296		.is_raw = 1,297	}, {298		/* SRGGB14_1X14 */299		.id = ALVIUM_FMT_SRGGB14_1X14,300		.code = MEDIA_BUS_FMT_SRGGB14_1X14,301		.colorspace = V4L2_COLORSPACE_RAW,302		.fmt_av_bit = ALVIUM_BIT_RAW14,303		.bay_av_bit = ALVIUM_BIT_BAY_GB,304		.mipi_fmt_regval = MIPI_CSI2_DT_RAW14,305		.bay_fmt_regval = 0x03,306		.is_raw = 1,307	}, {308		/* SGRBG14_1X14 */309		.id = ALVIUM_FMT_SGRBG14_1X14,310		.code = MEDIA_BUS_FMT_SGRBG14_1X14,311		.colorspace = V4L2_COLORSPACE_RAW,312		.fmt_av_bit = ALVIUM_BIT_RAW14,313		.bay_av_bit = ALVIUM_BIT_BAY_BG,314		.mipi_fmt_regval = MIPI_CSI2_DT_RAW14,315		.bay_fmt_regval = 0x04,316		.is_raw = 1,317	},318	{ /* sentinel */ }319};320 321static int alvium_read(struct alvium_dev *alvium, u32 reg, u64 *val, int *err)322{323	if (reg & REG_BCRM_V4L2) {324		reg &= ~REG_BCRM_V4L2;325		reg += alvium->bcrm_addr;326	}327 328	return cci_read(alvium->regmap, reg, val, err);329}330 331static int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val, int *err)332{333	if (reg & REG_BCRM_V4L2) {334		reg &= ~REG_BCRM_V4L2;335		reg += alvium->bcrm_addr;336	}337 338	return cci_write(alvium->regmap, reg, val, err);339}340 341static int alvium_write_hshake(struct alvium_dev *alvium, u32 reg, u64 val)342{343	struct device *dev = &alvium->i2c_client->dev;344	u64 hshake_bit;345	int ret = 0;346 347	/* reset handshake bit and write alvium reg */348	alvium_write(alvium, REG_BCRM_WRITE_HANDSHAKE_RW, 0, &ret);349	alvium_write(alvium, reg, val, &ret);350	if (ret) {351		dev_err(dev, "Fail to write reg\n");352		return ret;353	}354 355	/* poll handshake bit since bit0 = 1 */356	read_poll_timeout(alvium_read, hshake_bit,357			  ((hshake_bit & BCRM_HANDSHAKE_W_DONE_EN_BIT) == 1),358			  15000, 45000, true,359			  alvium, REG_BCRM_WRITE_HANDSHAKE_RW,360			  &hshake_bit, &ret);361	if (ret) {362		dev_err(dev, "poll bit[0] = 1, hshake reg fail\n");363		return ret;364	}365 366	/* reset handshake bit, write 0 to bit0 */367	alvium_write(alvium, REG_BCRM_WRITE_HANDSHAKE_RW, 0, &ret);368	if (ret) {369		dev_err(dev, "Fail to reset hshake reg\n");370		return ret;371	}372 373	/* poll handshake bit since bit0 = 0 */374	read_poll_timeout(alvium_read, hshake_bit,375			  ((hshake_bit & BCRM_HANDSHAKE_W_DONE_EN_BIT) == 0),376			  15000, 45000, true,377			  alvium, REG_BCRM_WRITE_HANDSHAKE_RW,378			  &hshake_bit, &ret);379	if (ret) {380		dev_err(dev, "poll bit[0] = 0, hshake reg fail\n");381		return ret;382	}383 384	return 0;385}386 387static int alvium_get_bcrm_vers(struct alvium_dev *alvium)388{389	struct device *dev = &alvium->i2c_client->dev;390	u64 min, maj;391	int ret = 0;392 393	ret = alvium_read(alvium, REG_BCRM_MINOR_VERSION_R, &min, &ret);394	ret = alvium_read(alvium, REG_BCRM_MAJOR_VERSION_R, &maj, &ret);395	if (ret)396		return ret;397 398	dev_info(dev, "bcrm version: %llu.%llu\n", min, maj);399 400	return 0;401}402 403static int alvium_get_fw_version(struct alvium_dev *alvium)404{405	struct device *dev = &alvium->i2c_client->dev;406	u64 val;407	int ret;408 409	ret = alvium_read(alvium, REG_BCRM_DEVICE_FW, &val, NULL);410	if (ret)411		return ret;412 413	dev_info(dev, "fw version: %02u.%02u.%04u.%08x\n",414		 (u8)((val & BCRM_DEVICE_FW_SPEC_MASK) >>415		       BCRM_DEVICE_FW_SPEC_SHIFT),416		 (u8)((val & BCRM_DEVICE_FW_MAJOR_MASK) >>417		       BCRM_DEVICE_FW_MAJOR_SHIFT),418		 (u16)((val & BCRM_DEVICE_FW_MINOR_MASK) >>419			BCRM_DEVICE_FW_MINOR_SHIFT),420		 (u32)((val & BCRM_DEVICE_FW_PATCH_MASK) >>421			BCRM_DEVICE_FW_PATCH_SHIFT));422 423	return 0;424}425 426static int alvium_get_bcrm_addr(struct alvium_dev *alvium)427{428	u64 val;429	int ret;430 431	ret = alvium_read(alvium, REG_BCRM_REG_ADDR_R, &val, NULL);432	if (ret)433		return ret;434 435	alvium->bcrm_addr = val;436 437	return 0;438}439 440static int alvium_is_alive(struct alvium_dev *alvium)441{442	u64 bcrm, hbeat;443	int ret = 0;444 445	alvium_read(alvium, REG_BCRM_MINOR_VERSION_R, &bcrm, &ret);446	alvium_read(alvium, REG_BCRM_HEARTBEAT_RW, &hbeat, &ret);447	if (ret)448		return ret;449 450	return hbeat;451}452 453static void alvium_print_avail_mipi_fmt(struct alvium_dev *alvium)454{455	struct device *dev = &alvium->i2c_client->dev;456 457	dev_dbg(dev, "avail mipi_fmt yuv420_8_leg: %u\n",458		alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV420_8_LEG]);459	dev_dbg(dev, "avail mipi_fmt yuv420_8: %u\n",460		alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV420_8]);461	dev_dbg(dev, "avail mipi_fmt yuv420_10: %u\n",462		alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV420_10]);463	dev_dbg(dev, "avail mipi_fmt yuv420_8_csps: %u\n",464		alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV420_8_CSPS]);465	dev_dbg(dev, "avail mipi_fmt yuv420_10_csps: %u\n",466		alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV420_10_CSPS]);467	dev_dbg(dev, "avail mipi_fmt yuv422_8: %u\n",468		alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV422_8]);469	dev_dbg(dev, "avail mipi_fmt yuv422_10: %u\n",470		alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV422_10]);471	dev_dbg(dev, "avail mipi_fmt rgb888: %u\n",472		alvium->is_mipi_fmt_avail[ALVIUM_BIT_RGB888]);473	dev_dbg(dev, "avail mipi_fmt rgb666: %u\n",474		alvium->is_mipi_fmt_avail[ALVIUM_BIT_RGB666]);475	dev_dbg(dev, "avail mipi_fmt rgb565: %u\n",476		alvium->is_mipi_fmt_avail[ALVIUM_BIT_RGB565]);477	dev_dbg(dev, "avail mipi_fmt rgb555: %u\n",478		alvium->is_mipi_fmt_avail[ALVIUM_BIT_RGB555]);479	dev_dbg(dev, "avail mipi_fmt rgb444: %u\n",480		alvium->is_mipi_fmt_avail[ALVIUM_BIT_RGB444]);481	dev_dbg(dev, "avail mipi_fmt raw6: %u\n",482		alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW6]);483	dev_dbg(dev, "avail mipi_fmt raw7: %u\n",484		alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW7]);485	dev_dbg(dev, "avail mipi_fmt raw8: %u\n",486		alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW8]);487	dev_dbg(dev, "avail mipi_fmt raw10: %u\n",488		alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW10]);489	dev_dbg(dev, "avail mipi_fmt raw12: %u\n",490		alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW12]);491	dev_dbg(dev, "avail mipi_fmt raw14: %u\n",492		alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW14]);493	dev_dbg(dev, "avail mipi_fmt jpeg: %u\n",494		alvium->is_mipi_fmt_avail[ALVIUM_BIT_JPEG]);495}496 497static void alvium_print_avail_feat(struct alvium_dev *alvium)498{499	struct device *dev = &alvium->i2c_client->dev;500 501	dev_dbg(dev, "feature rev_x: %u\n", alvium->avail_ft.rev_x);502	dev_dbg(dev, "feature rev_y: %u\n", alvium->avail_ft.rev_y);503	dev_dbg(dev, "feature int_autop: %u\n", alvium->avail_ft.int_autop);504	dev_dbg(dev, "feature black_lvl: %u\n", alvium->avail_ft.black_lvl);505	dev_dbg(dev, "feature gain: %u\n", alvium->avail_ft.gain);506	dev_dbg(dev, "feature gamma: %u\n", alvium->avail_ft.gamma);507	dev_dbg(dev, "feature contrast: %u\n", alvium->avail_ft.contrast);508	dev_dbg(dev, "feature sat: %u\n", alvium->avail_ft.sat);509	dev_dbg(dev, "feature hue: %u\n", alvium->avail_ft.hue);510	dev_dbg(dev, "feature whiteb: %u\n", alvium->avail_ft.whiteb);511	dev_dbg(dev, "feature sharp: %u\n", alvium->avail_ft.sharp);512	dev_dbg(dev, "feature auto_exp: %u\n", alvium->avail_ft.auto_exp);513	dev_dbg(dev, "feature auto_gain: %u\n", alvium->avail_ft.auto_gain);514	dev_dbg(dev, "feature auto_whiteb: %u\n", alvium->avail_ft.auto_whiteb);515	dev_dbg(dev, "feature dev_temp: %u\n", alvium->avail_ft.dev_temp);516	dev_dbg(dev, "feature acq_abort: %u\n", alvium->avail_ft.acq_abort);517	dev_dbg(dev, "feature acq_fr: %u\n", alvium->avail_ft.acq_fr);518	dev_dbg(dev, "feature fr_trigger: %u\n", alvium->avail_ft.fr_trigger);519	dev_dbg(dev, "feature exp_acq_line: %u\n",520		alvium->avail_ft.exp_acq_line);521}522 523static void alvium_print_avail_bayer(struct alvium_dev *alvium)524{525	struct device *dev = &alvium->i2c_client->dev;526 527	dev_dbg(dev, "avail bayer mono: %u\n",528		alvium->is_bay_avail[ALVIUM_BIT_BAY_MONO]);529	dev_dbg(dev, "avail bayer gr: %u\n",530		alvium->is_bay_avail[ALVIUM_BIT_BAY_GR]);531	dev_dbg(dev, "avail bayer rg: %u\n",532		alvium->is_bay_avail[ALVIUM_BIT_BAY_RG]);533	dev_dbg(dev, "avail bayer gb: %u\n",534		alvium->is_bay_avail[ALVIUM_BIT_BAY_GB]);535	dev_dbg(dev, "avail bayer bg: %u\n",536		alvium->is_bay_avail[ALVIUM_BIT_BAY_BG]);537}538 539static int alvium_get_feat_inq(struct alvium_dev *alvium)540{541	struct alvium_avail_feat *f;542	u64 val;543	int ret;544 545	ret = alvium_read(alvium, REG_BCRM_FEATURE_INQUIRY_R, &val, NULL);546	if (ret)547		return ret;548 549	f = (struct alvium_avail_feat *)&val;550	alvium->avail_ft = *f;551	alvium_print_avail_feat(alvium);552 553	return 0;554}555 556static int alvium_get_host_supp_csi_lanes(struct alvium_dev *alvium)557{558	u64 val;559	int ret;560 561	ret = alvium_read(alvium, REG_BCRM_CSI2_LANE_COUNT_RW, &val, NULL);562	if (ret)563		return ret;564 565	alvium->h_sup_csi_lanes = val;566 567	return 0;568}569 570static int alvium_set_csi_lanes(struct alvium_dev *alvium)571{572	struct device *dev = &alvium->i2c_client->dev;573	u64 num_lanes;574	int ret;575 576	num_lanes = alvium->ep.bus.mipi_csi2.num_data_lanes;577 578	if (num_lanes > alvium->h_sup_csi_lanes)579		return -EINVAL;580 581	ret = alvium_write_hshake(alvium, REG_BCRM_CSI2_LANE_COUNT_RW,582				  num_lanes);583	if (ret) {584		dev_err(dev, "Fail to set csi lanes reg\n");585		return ret;586	}587 588	return 0;589}590 591static int alvium_set_lp2hs_delay(struct alvium_dev *alvium)592{593	struct device *dev = &alvium->i2c_client->dev;594	int ret = 0;595 596	/*597	 * The purpose of this reg is force a DPhy reset598	 * for the period described by the millisecond on599	 * the reg, before it starts streaming.600	 *601	 * To be clear, with that value bigger than 0 the602	 * Alvium forces a dphy-reset on all lanes for that period.603	 * That means all lanes go up into low power state.604	 *605	 */606	alvium_write(alvium, REG_BCRM_LP2HS_DELAY_RW,607		     ALVIUM_LP2HS_DELAY_MS, &ret);608	if (ret) {609		dev_err(dev, "Fail to set lp2hs delay reg\n");610		return ret;611	}612 613	return 0;614}615 616static int alvium_get_csi_clk_params(struct alvium_dev *alvium)617{618	u64 min_csi_clk, max_csi_clk;619	int ret = 0;620 621	alvium_read(alvium, REG_BCRM_CSI2_CLOCK_MIN_R, &min_csi_clk, &ret);622	alvium_read(alvium, REG_BCRM_CSI2_CLOCK_MAX_R, &max_csi_clk, &ret);623	if (ret)624		return ret;625 626	alvium->min_csi_clk = min_csi_clk;627	alvium->max_csi_clk = max_csi_clk;628 629	return 0;630}631 632static int alvium_set_csi_clk(struct alvium_dev *alvium)633{634	struct device *dev = &alvium->i2c_client->dev;635	u64 csi_clk;636	int ret;637 638	csi_clk = clamp(alvium->ep.link_frequencies[0],639			(u64)alvium->min_csi_clk, (u64)alvium->max_csi_clk);640 641	if (alvium->ep.link_frequencies[0] != (u64)csi_clk) {642		dev_warn(dev,643			 "requested csi clock (%llu MHz) out of range [%u, %u] Adjusted to %llu\n",644			 alvium->ep.link_frequencies[0],645			 alvium->min_csi_clk, alvium->max_csi_clk, csi_clk);646	}647 648	ret = alvium_write_hshake(alvium, REG_BCRM_CSI2_CLOCK_RW, csi_clk);649	if (ret) {650		dev_err(dev, "Fail to set csi clock reg\n");651		return ret;652	}653 654	alvium->link_freq = csi_clk;655 656	return 0;657}658 659static int alvium_get_img_width_params(struct alvium_dev *alvium)660{661	u64 imgw, imgw_min, imgw_max, imgw_inc;662	int ret = 0;663 664	alvium_read(alvium, REG_BCRM_IMG_WIDTH_RW, &imgw, &ret);665	alvium_read(alvium, REG_BCRM_IMG_WIDTH_MIN_R, &imgw_min, &ret);666	alvium_read(alvium, REG_BCRM_IMG_WIDTH_MAX_R, &imgw_max, &ret);667	alvium_read(alvium, REG_BCRM_IMG_WIDTH_INC_R, &imgw_inc, &ret);668	if (ret)669		return ret;670 671	alvium->dft_img_width = imgw;672	alvium->img_min_width = imgw_min;673	alvium->img_max_width = imgw_max;674	alvium->img_inc_width = imgw_inc;675 676	return 0;677}678 679static int alvium_get_img_height_params(struct alvium_dev *alvium)680{681	u64 imgh, imgh_min, imgh_max, imgh_inc;682	int ret = 0;683 684	alvium_read(alvium, REG_BCRM_IMG_HEIGHT_RW, &imgh, &ret);685	alvium_read(alvium, REG_BCRM_IMG_HEIGHT_MIN_R, &imgh_min, &ret);686	alvium_read(alvium, REG_BCRM_IMG_HEIGHT_MAX_R, &imgh_max, &ret);687	alvium_read(alvium, REG_BCRM_IMG_HEIGHT_INC_R, &imgh_inc, &ret);688	if (ret)689		return ret;690 691	alvium->dft_img_height = imgh;692	alvium->img_min_height = imgh_min;693	alvium->img_max_height = imgh_max;694	alvium->img_inc_height = imgh_inc;695 696	return 0;697}698 699static int alvium_set_img_width(struct alvium_dev *alvium, u32 width)700{701	struct device *dev = &alvium->i2c_client->dev;702	int ret;703 704	ret = alvium_write_hshake(alvium, REG_BCRM_IMG_WIDTH_RW, width);705	if (ret) {706		dev_err(dev, "Fail to set img width\n");707		return ret;708	}709 710	return 0;711}712 713static int alvium_set_img_height(struct alvium_dev *alvium, u32 height)714{715	struct device *dev = &alvium->i2c_client->dev;716	int ret;717 718	ret = alvium_write_hshake(alvium, REG_BCRM_IMG_HEIGHT_RW, height);719	if (ret) {720		dev_err(dev, "Fail to set img height\n");721		return ret;722	}723 724	return 0;725}726 727static int alvium_set_img_offx(struct alvium_dev *alvium, u32 offx)728{729	struct device *dev = &alvium->i2c_client->dev;730	int ret;731 732	ret = alvium_write_hshake(alvium, REG_BCRM_IMG_OFFSET_X_RW, offx);733	if (ret) {734		dev_err(dev, "Fail to set img offx\n");735		return ret;736	}737 738	return 0;739}740 741static int alvium_set_img_offy(struct alvium_dev *alvium, u32 offy)742{743	struct device *dev = &alvium->i2c_client->dev;744	int ret;745 746	ret = alvium_write_hshake(alvium, REG_BCRM_IMG_OFFSET_Y_RW, offy);747	if (ret) {748		dev_err(dev, "Fail to set img offy\n");749		return ret;750	}751 752	return 0;753}754 755static int alvium_get_offx_params(struct alvium_dev *alvium)756{757	u64 min_offx, max_offx, inc_offx;758	int ret = 0;759 760	alvium_read(alvium, REG_BCRM_IMG_OFFSET_X_MIN_R, &min_offx, &ret);761	alvium_read(alvium, REG_BCRM_IMG_OFFSET_X_MAX_R, &max_offx, &ret);762	alvium_read(alvium, REG_BCRM_IMG_OFFSET_X_INC_R, &inc_offx, &ret);763	if (ret)764		return ret;765 766	alvium->min_offx = min_offx;767	alvium->max_offx = max_offx;768	alvium->inc_offx = inc_offx;769 770	return 0;771}772 773static int alvium_get_offy_params(struct alvium_dev *alvium)774{775	u64 min_offy, max_offy, inc_offy;776	int ret = 0;777 778	alvium_read(alvium, REG_BCRM_IMG_OFFSET_Y_MIN_R, &min_offy, &ret);779	alvium_read(alvium, REG_BCRM_IMG_OFFSET_Y_MAX_R, &max_offy, &ret);780	alvium_read(alvium, REG_BCRM_IMG_OFFSET_Y_INC_R, &inc_offy, &ret);781	if (ret)782		return ret;783 784	alvium->min_offy = min_offy;785	alvium->max_offy = max_offy;786	alvium->inc_offy = inc_offy;787 788	return 0;789}790 791static int alvium_get_gain_params(struct alvium_dev *alvium)792{793	u64 dft_gain, min_gain, max_gain, inc_gain;794	int ret = 0;795 796	alvium_read(alvium, REG_BCRM_GAIN_RW, &dft_gain, &ret);797	alvium_read(alvium, REG_BCRM_GAIN_MIN_R, &min_gain, &ret);798	alvium_read(alvium, REG_BCRM_GAIN_MAX_R, &max_gain, &ret);799	alvium_read(alvium, REG_BCRM_GAIN_INC_R, &inc_gain, &ret);800	if (ret)801		return ret;802 803	alvium->dft_gain = dft_gain;804	alvium->min_gain = min_gain;805	alvium->max_gain = max_gain;806	alvium->inc_gain = inc_gain;807 808	return 0;809}810 811static int alvium_get_exposure_params(struct alvium_dev *alvium)812{813	u64 dft_exp, min_exp, max_exp, inc_exp;814	int ret = 0;815 816	alvium_read(alvium, REG_BCRM_EXPOSURE_TIME_RW, &dft_exp, &ret);817	alvium_read(alvium, REG_BCRM_EXPOSURE_TIME_MIN_R, &min_exp, &ret);818	alvium_read(alvium, REG_BCRM_EXPOSURE_TIME_MAX_R, &max_exp, &ret);819	alvium_read(alvium, REG_BCRM_EXPOSURE_TIME_INC_R, &inc_exp, &ret);820	if (ret)821		return ret;822 823	alvium->dft_exp = dft_exp;824	alvium->min_exp = min_exp;825	alvium->max_exp = max_exp;826	alvium->inc_exp = inc_exp;827 828	return 0;829}830 831static int alvium_get_red_balance_ratio_params(struct alvium_dev *alvium)832{833	u64 dft_rb, min_rb, max_rb, inc_rb;834	int ret = 0;835 836	alvium_read(alvium, REG_BCRM_RED_BALANCE_RATIO_RW, &dft_rb, &ret);837	alvium_read(alvium, REG_BCRM_RED_BALANCE_RATIO_MIN_R, &min_rb, &ret);838	alvium_read(alvium, REG_BCRM_RED_BALANCE_RATIO_MAX_R, &max_rb, &ret);839	alvium_read(alvium, REG_BCRM_RED_BALANCE_RATIO_INC_R, &inc_rb, &ret);840	if (ret)841		return ret;842 843	alvium->dft_rbalance = dft_rb;844	alvium->min_rbalance = min_rb;845	alvium->max_rbalance = max_rb;846	alvium->inc_rbalance = inc_rb;847 848	return 0;849}850 851static int alvium_get_blue_balance_ratio_params(struct alvium_dev *alvium)852{853	u64 dft_bb, min_bb, max_bb, inc_bb;854	int ret = 0;855 856	alvium_read(alvium, REG_BCRM_BLUE_BALANCE_RATIO_RW, &dft_bb, &ret);857	alvium_read(alvium, REG_BCRM_BLUE_BALANCE_RATIO_MIN_R, &min_bb, &ret);858	alvium_read(alvium, REG_BCRM_BLUE_BALANCE_RATIO_MAX_R, &max_bb, &ret);859	alvium_read(alvium, REG_BCRM_BLUE_BALANCE_RATIO_INC_R, &inc_bb, &ret);860	if (ret)861		return ret;862 863	alvium->dft_bbalance = dft_bb;864	alvium->min_bbalance = min_bb;865	alvium->max_bbalance = max_bb;866	alvium->inc_bbalance = inc_bb;867 868	return 0;869}870 871static int alvium_get_hue_params(struct alvium_dev *alvium)872{873	u64 dft_hue, min_hue, max_hue, inc_hue;874	int ret = 0;875 876	alvium_read(alvium, REG_BCRM_HUE_RW, &dft_hue, &ret);877	alvium_read(alvium, REG_BCRM_HUE_MIN_R, &min_hue, &ret);878	alvium_read(alvium, REG_BCRM_HUE_MAX_R, &max_hue, &ret);879	alvium_read(alvium, REG_BCRM_HUE_INC_R, &inc_hue, &ret);880	if (ret)881		return ret;882 883	alvium->dft_hue = (s32)dft_hue;884	alvium->min_hue = (s32)min_hue;885	alvium->max_hue = (s32)max_hue;886	alvium->inc_hue = (s32)inc_hue;887 888	return 0;889}890 891static int alvium_get_black_lvl_params(struct alvium_dev *alvium)892{893	u64 dft_blvl, min_blvl, max_blvl, inc_blvl;894	int ret = 0;895 896	alvium_read(alvium, REG_BCRM_BLACK_LEVEL_RW, &dft_blvl, &ret);897	alvium_read(alvium, REG_BCRM_BLACK_LEVEL_MIN_R, &min_blvl, &ret);898	alvium_read(alvium, REG_BCRM_BLACK_LEVEL_MAX_R, &max_blvl, &ret);899	alvium_read(alvium, REG_BCRM_BLACK_LEVEL_INC_R, &inc_blvl, &ret);900	if (ret)901		return ret;902 903	alvium->dft_black_lvl = (s32)dft_blvl;904	alvium->min_black_lvl = (s32)min_blvl;905	alvium->max_black_lvl = (s32)max_blvl;906	alvium->inc_black_lvl = (s32)inc_blvl;907 908	return 0;909}910 911static int alvium_get_gamma_params(struct alvium_dev *alvium)912{913	u64 dft_g, min_g, max_g, inc_g;914	int ret = 0;915 916	alvium_read(alvium, REG_BCRM_GAMMA_RW, &dft_g, &ret);917	alvium_read(alvium, REG_BCRM_GAMMA_MIN_R, &min_g, &ret);918	alvium_read(alvium, REG_BCRM_GAMMA_MAX_R, &max_g, &ret);919	alvium_read(alvium, REG_BCRM_GAMMA_INC_R, &inc_g, &ret);920	if (ret)921		return ret;922 923	alvium->dft_gamma = dft_g;924	alvium->min_gamma = min_g;925	alvium->max_gamma = max_g;926	alvium->inc_gamma = inc_g;927 928	return 0;929}930 931static int alvium_get_sharpness_params(struct alvium_dev *alvium)932{933	u64 dft_sh, min_sh, max_sh, inc_sh;934	int ret = 0;935 936	alvium_read(alvium, REG_BCRM_SHARPNESS_RW, &dft_sh, &ret);937	alvium_read(alvium, REG_BCRM_SHARPNESS_MIN_R, &min_sh, &ret);938	alvium_read(alvium, REG_BCRM_BLACK_LEVEL_MAX_R, &max_sh, &ret);939	alvium_read(alvium, REG_BCRM_SHARPNESS_INC_R, &inc_sh, &ret);940	if (ret)941		return ret;942 943	alvium->dft_sharp = (s32)dft_sh;944	alvium->min_sharp = (s32)min_sh;945	alvium->max_sharp = (s32)max_sh;946	alvium->inc_sharp = (s32)inc_sh;947 948	return 0;949}950 951static int alvium_get_contrast_params(struct alvium_dev *alvium)952{953	u64 dft_c, min_c, max_c, inc_c;954	int ret = 0;955 956	alvium_read(alvium, REG_BCRM_CONTRAST_VALUE_RW, &dft_c, &ret);957	alvium_read(alvium, REG_BCRM_CONTRAST_VALUE_MIN_R, &min_c, &ret);958	alvium_read(alvium, REG_BCRM_CONTRAST_VALUE_MAX_R, &max_c, &ret);959	alvium_read(alvium, REG_BCRM_CONTRAST_VALUE_INC_R, &inc_c, &ret);960	if (ret)961		return ret;962 963	alvium->dft_contrast = dft_c;964	alvium->min_contrast = min_c;965	alvium->max_contrast = max_c;966	alvium->inc_contrast = inc_c;967 968	return 0;969}970 971static int alvium_get_saturation_params(struct alvium_dev *alvium)972{973	u64 dft_sat, min_sat, max_sat, inc_sat;974	int ret = 0;975 976	alvium_read(alvium, REG_BCRM_SATURATION_RW, &dft_sat, &ret);977	alvium_read(alvium, REG_BCRM_SATURATION_MIN_R, &min_sat, &ret);978	alvium_read(alvium, REG_BCRM_SATURATION_MAX_R, &max_sat, &ret);979	alvium_read(alvium, REG_BCRM_SATURATION_INC_R, &inc_sat, &ret);980	if (ret)981		return ret;982 983	alvium->dft_sat = dft_sat;984	alvium->min_sat = min_sat;985	alvium->max_sat = max_sat;986	alvium->inc_sat = inc_sat;987 988	return 0;989}990 991static int alvium_set_bcm_mode(struct alvium_dev *alvium)992{993	int ret = 0;994 995	alvium_write(alvium, REG_GENCP_CHANGEMODE_W, ALVIUM_BCM_MODE, &ret);996	alvium->bcrm_mode = ALVIUM_BCM_MODE;997 998	return ret;999}1000 1001static int alvium_get_mode(struct alvium_dev *alvium)1002{1003	u64 bcrm_mode;1004	int ret;1005 1006	ret = alvium_read(alvium, REG_GENCP_CURRENTMODE_R, &bcrm_mode, NULL);1007	if (ret)1008		return ret;1009 1010	switch (bcrm_mode) {1011	case ALVIUM_BCM_MODE:1012		alvium->bcrm_mode = ALVIUM_BCM_MODE;1013		break;1014	case ALVIUM_GENCP_MODE:1015		alvium->bcrm_mode = ALVIUM_GENCP_MODE;1016		break;1017	}1018 1019	return 0;1020}1021 1022static int alvium_get_avail_mipi_data_format(struct alvium_dev *alvium)1023{1024	struct alvium_avail_mipi_fmt *avail_fmt;1025	u64 val;1026	int ret;1027 1028	ret = alvium_read(alvium, REG_BCRM_IMG_AVAILABLE_MIPI_DATA_FORMATS_R,1029			  &val, NULL);1030	if (ret)1031		return ret;1032 1033	avail_fmt = (struct alvium_avail_mipi_fmt *)&val;1034 1035	alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV420_8_LEG] =1036				  avail_fmt->yuv420_8_leg;1037	alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV420_8] =1038				  avail_fmt->yuv420_8;1039	alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV420_10] =1040				  avail_fmt->yuv420_10;1041	alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV420_8_CSPS] =1042				  avail_fmt->yuv420_8_csps;1043	alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV420_10_CSPS] =1044				  avail_fmt->yuv420_10_csps;1045	alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV422_8] =1046				  avail_fmt->yuv422_8;1047	alvium->is_mipi_fmt_avail[ALVIUM_BIT_YUV422_10] =1048				  avail_fmt->yuv422_10;1049	alvium->is_mipi_fmt_avail[ALVIUM_BIT_RGB888] =1050				  avail_fmt->rgb888;1051	alvium->is_mipi_fmt_avail[ALVIUM_BIT_RGB666] =1052				  avail_fmt->rgb666;1053	alvium->is_mipi_fmt_avail[ALVIUM_BIT_RGB565] =1054				  avail_fmt->rgb565;1055	alvium->is_mipi_fmt_avail[ALVIUM_BIT_RGB555] =1056				  avail_fmt->rgb555;1057	alvium->is_mipi_fmt_avail[ALVIUM_BIT_RGB444] =1058				  avail_fmt->rgb444;1059	alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW6] =1060				  avail_fmt->raw6;1061	alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW7] =1062				  avail_fmt->raw7;1063	alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW8] =1064				  avail_fmt->raw8;1065	alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW10] =1066				  avail_fmt->raw10;1067	alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW12] =1068				  avail_fmt->raw12;1069	alvium->is_mipi_fmt_avail[ALVIUM_BIT_RAW14] =1070				  avail_fmt->raw14;1071	alvium->is_mipi_fmt_avail[ALVIUM_BIT_JPEG] =1072				  avail_fmt->jpeg;1073 1074	alvium_print_avail_mipi_fmt(alvium);1075 1076	return 0;1077}1078 1079static int alvium_setup_mipi_fmt(struct alvium_dev *alvium)1080{1081	unsigned int avail_fmt_cnt = 0;1082	unsigned int fmt = 0;1083	size_t sz = 0;1084 1085	/* calculate fmt array size */1086	for (fmt = 0; fmt < ALVIUM_NUM_SUPP_MIPI_DATA_FMT; fmt++) {1087		if (!alvium->is_mipi_fmt_avail[alvium_csi2_fmts[fmt].fmt_av_bit])1088			continue;1089 1090		if (!alvium_csi2_fmts[fmt].is_raw ||1091		    alvium->is_bay_avail[alvium_csi2_fmts[fmt].bay_av_bit])1092			sz++;1093	}1094 1095	/* init alvium_csi2_fmt array */1096	alvium->alvium_csi2_fmt_n = sz;1097	alvium->alvium_csi2_fmt =1098		kmalloc_array(sz, sizeof(struct alvium_pixfmt), GFP_KERNEL);1099	if (!alvium->alvium_csi2_fmt)1100		return -ENOMEM;1101 1102	/* Create the alvium_csi2 fmt array from formats available */1103	for (fmt = 0; fmt < ALVIUM_NUM_SUPP_MIPI_DATA_FMT; fmt++) {1104		if (!alvium->is_mipi_fmt_avail[alvium_csi2_fmts[fmt].fmt_av_bit])1105			continue;1106 1107		if (!alvium_csi2_fmts[fmt].is_raw ||1108		    alvium->is_bay_avail[alvium_csi2_fmts[fmt].bay_av_bit]) {1109			alvium->alvium_csi2_fmt[avail_fmt_cnt] =1110				alvium_csi2_fmts[fmt];1111			avail_fmt_cnt++;1112		}1113	}1114 1115	return 0;1116}1117 1118static int alvium_set_mipi_fmt(struct alvium_dev *alvium,1119			       const struct alvium_pixfmt *pixfmt)1120{1121	struct device *dev = &alvium->i2c_client->dev;1122	int ret;1123 1124	ret = alvium_write_hshake(alvium, REG_BCRM_IMG_MIPI_DATA_FORMAT_RW,1125				  pixfmt->mipi_fmt_regval);1126	if (ret) {1127		dev_err(dev, "Fail to set mipi fmt\n");1128		return ret;1129	}1130 1131	return 0;1132}1133 1134static int alvium_get_avail_bayer(struct alvium_dev *alvium)1135{1136	struct alvium_avail_bayer *avail_bay;1137	u64 val;1138	int ret;1139 1140	ret = alvium_read(alvium, REG_BCRM_IMG_BAYER_PATTERN_INQUIRY_R,1141			  &val, NULL);1142	if (ret)1143		return ret;1144 1145	avail_bay = (struct alvium_avail_bayer *)&val;1146 1147	alvium->is_bay_avail[ALVIUM_BIT_BAY_MONO] = avail_bay->mono;1148	alvium->is_bay_avail[ALVIUM_BIT_BAY_GR] = avail_bay->gr;1149	alvium->is_bay_avail[ALVIUM_BIT_BAY_RG] = avail_bay->rg;1150	alvium->is_bay_avail[ALVIUM_BIT_BAY_GB] = avail_bay->gb;1151	alvium->is_bay_avail[ALVIUM_BIT_BAY_BG] = avail_bay->bg;1152 1153	alvium_print_avail_bayer(alvium);1154 1155	return 0;1156}1157 1158static int alvium_set_bayer_pattern(struct alvium_dev *alvium,1159				    const struct alvium_pixfmt *pixfmt)1160{1161	struct device *dev = &alvium->i2c_client->dev;1162	int ret;1163 1164	ret = alvium_write_hshake(alvium, REG_BCRM_IMG_BAYER_PATTERN_RW,1165				  pixfmt->bay_fmt_regval);1166	if (ret) {1167		dev_err(dev, "Fail to set bayer pattern\n");1168		return ret;1169	}1170 1171	return 0;1172}1173 1174static int alvium_get_frame_interval(struct alvium_dev *alvium,1175				     u64 *min_fr, u64 *max_fr)1176{1177	int ret = 0;1178 1179	alvium_read(alvium, REG_BCRM_ACQUISITION_FRAME_RATE_MIN_R,1180		    min_fr, &ret);1181	alvium_read(alvium, REG_BCRM_ACQUISITION_FRAME_RATE_MAX_R,1182		    max_fr, &ret);1183 1184	return ret;1185}1186 1187static int alvium_set_frame_rate(struct alvium_dev *alvium, u64 fr)1188{1189	struct device *dev = &alvium->i2c_client->dev;1190	int ret;1191 1192	ret = alvium_write_hshake(alvium, REG_BCRM_ACQUISITION_FRAME_RATE_EN_RW,1193				  1);1194	if (ret) {1195		dev_err(dev, "Fail to set acquisition frame rate enable reg\n");1196		return ret;1197	}1198 1199	ret = alvium_write_hshake(alvium, REG_BCRM_FRAME_START_TRIGGER_MODE_RW,1200				  0);1201	if (ret) {1202		dev_err(dev, "Fail to set frame start trigger mode reg\n");1203		return ret;1204	}1205 1206	ret = alvium_write_hshake(alvium, REG_BCRM_ACQUISITION_FRAME_RATE_RW,1207				  fr);1208	if (ret) {1209		dev_err(dev, "Fail to set frame rate lanes reg\n");1210		return ret;1211	}1212 1213	dev_dbg(dev, "set frame rate: %llu us\n", fr);1214 1215	return 0;1216}1217 1218static int alvium_set_stream_mipi(struct alvium_dev *alvium, bool on)1219{1220	struct device *dev = &alvium->i2c_client->dev;1221	int ret;1222 1223	ret = alvium_write_hshake(alvium, on ? REG_BCRM_ACQUISITION_START_RW :1224				  REG_BCRM_ACQUISITION_STOP_RW, 0x01);1225	if (ret) {1226		dev_err(dev, "Fail set_stream_mipi\n");1227		return ret;1228	}1229 1230	return 0;1231}1232 1233static int alvium_get_gain(struct alvium_dev *alvium)1234{1235	u64 gain;1236	int ret;1237 1238	/* The unit is millibel (1 mB = 0.01 dB) */1239	ret = alvium_read(alvium, REG_BCRM_GAIN_RW, &gain, NULL);1240	if (ret)1241		return ret;1242 1243	return gain;1244}1245 1246static int alvium_set_ctrl_gain(struct alvium_dev *alvium, int gain)1247{1248	struct device *dev = &alvium->i2c_client->dev;1249	int ret;1250 1251	/* The unit is millibel (1 mB = 0.01 dB) */1252	ret = alvium_write_hshake(alvium, REG_BCRM_GAIN_RW, (u64)gain);1253	if (ret) {1254		dev_err(dev, "Fail to set gain value reg\n");1255		return ret;1256	}1257 1258	return 0;1259}1260 1261static int alvium_set_ctrl_auto_gain(struct alvium_dev *alvium, bool on)1262{1263	struct device *dev = &alvium->i2c_client->dev;1264	int ret;1265 1266	ret = alvium_write_hshake(alvium, REG_BCRM_GAIN_AUTO_RW,1267				  on ? 0x02 : 0x00);1268	if (ret) {1269		dev_err(dev, "Fail to set autogain reg\n");1270		return ret;1271	}1272 1273	return 0;1274}1275 1276static int alvium_get_exposure(struct alvium_dev *alvium)1277{1278	u64 exp;1279	int ret;1280 1281	/* Exposure time in ns */1282	ret = alvium_read(alvium, REG_BCRM_EXPOSURE_TIME_RW, &exp, NULL);1283	if (ret)1284		return ret;1285 1286	return exp;1287}1288 1289static int alvium_set_ctrl_auto_exposure(struct alvium_dev *alvium, bool on)1290{1291	struct device *dev = &alvium->i2c_client->dev;1292	int ret;1293 1294	ret = alvium_write_hshake(alvium, REG_BCRM_WHITE_BALANCE_AUTO_RW,1295				  on ? 0x02 : 0x00);1296	if (ret) {1297		dev_err(dev, "Fail to set autoexposure reg\n");1298		return ret;1299	}1300 1301	return 0;1302}1303 1304static int alvium_set_ctrl_exposure(struct alvium_dev *alvium, int exposure_ns)1305{1306	struct device *dev = &alvium->i2c_client->dev;1307	int ret;1308 1309	ret = alvium_write_hshake(alvium, REG_BCRM_EXPOSURE_TIME_RW,1310				  (u64)exposure_ns);1311	if (ret) {1312		dev_err(dev, "Fail to set exposure value reg\n");1313		return ret;1314	}1315 1316	return 0;1317}1318 1319static int alvium_set_ctrl_blue_balance_ratio(struct alvium_dev *alvium,1320					      int blue)1321{1322	struct device *dev = &alvium->i2c_client->dev;1323	int ret;1324 1325	ret = alvium_write_hshake(alvium, REG_BCRM_BLUE_BALANCE_RATIO_RW,1326				  (u64)blue);1327	if (ret) {1328		dev_err(dev, "Fail to set blue ratio value reg\n");1329		return ret;1330	}1331 1332	return 0;1333}1334 1335static int alvium_set_ctrl_red_balance_ratio(struct alvium_dev *alvium, int red)1336{1337	struct device *dev = &alvium->i2c_client->dev;1338	int ret;1339 1340	ret = alvium_write_hshake(alvium, REG_BCRM_RED_BALANCE_RATIO_RW,1341				  (u64)red);1342	if (ret) {1343		dev_err(dev, "Fail to set red ratio value reg\n");1344		return ret;1345	}1346 1347	return 0;1348}1349 1350static int alvium_set_ctrl_awb(struct alvium_dev *alvium, bool on)1351{1352	struct device *dev = &alvium->i2c_client->dev;1353	int ret;1354 1355	ret = alvium_write_hshake(alvium, REG_BCRM_WHITE_BALANCE_AUTO_RW,1356				  on ? 0x02 : 0x00);1357	if (ret) {1358		dev_err(dev, "Fail to set awb reg\n");1359		return ret;1360	}1361 1362	return 0;1363}1364 1365static int alvium_set_ctrl_hue(struct alvium_dev *alvium, int val)1366{1367	struct device *dev = &alvium->i2c_client->dev;1368	int ret;1369 1370	ret = alvium_write_hshake(alvium, REG_BCRM_HUE_RW, (u64)val);1371	if (ret) {1372		dev_err(dev, "Fail to set hue value reg\n");1373		return ret;1374	}1375 1376	return 0;1377}1378 1379static int alvium_set_ctrl_contrast(struct alvium_dev *alvium, int val)1380{1381	struct device *dev = &alvium->i2c_client->dev;1382	int ret;1383 1384	ret = alvium_write_hshake(alvium, REG_BCRM_CONTRAST_VALUE_RW, (u64)val);1385	if (ret) {1386		dev_err(dev, "Fail to set contrast value reg\n");1387		return ret;1388	}1389 1390	return 0;1391}1392 1393static int alvium_set_ctrl_saturation(struct alvium_dev *alvium, int val)1394{1395	struct device *dev = &alvium->i2c_client->dev;1396	int ret;1397 1398	ret = alvium_write_hshake(alvium, REG_BCRM_SATURATION_RW, (u64)val);1399	if (ret) {1400		dev_err(dev, "Fail to set contrast value reg\n");1401		return ret;1402	}1403 1404	return 0;1405}1406 1407static int alvium_set_ctrl_gamma(struct alvium_dev *alvium, int val)1408{1409	struct device *dev = &alvium->i2c_client->dev;1410	int ret;1411 1412	ret = alvium_write_hshake(alvium, REG_BCRM_GAMMA_RW, (u64)val);1413	if (ret) {1414		dev_err(dev, "Fail to set gamma value reg\n");1415		return ret;1416	}1417 1418	return 0;1419}1420 1421static int alvium_set_ctrl_sharpness(struct alvium_dev *alvium, int val)1422{1423	struct device *dev = &alvium->i2c_client->dev;1424	int ret;1425 1426	ret = alvium_write_hshake(alvium, REG_BCRM_SHARPNESS_RW, (u64)val);1427	if (ret) {1428		dev_err(dev, "Fail to set sharpness value reg\n");1429		return ret;1430	}1431 1432	return 0;1433}1434 1435static int alvium_set_ctrl_hflip(struct alvium_dev *alvium, int val)1436{1437	struct device *dev = &alvium->i2c_client->dev;1438	int ret;1439 1440	ret = alvium_write_hshake(alvium, REG_BCRM_IMG_REVERSE_X_RW, (u64)val);1441	if (ret) {1442		dev_err(dev, "Fail to set reverse_x value reg\n");1443		return ret;1444	}1445 1446	return 0;1447}1448 1449static int alvium_set_ctrl_vflip(struct alvium_dev *alvium, int val)1450{1451	struct device *dev = &alvium->i2c_client->dev;1452	int ret;1453 1454	ret = alvium_write_hshake(alvium, REG_BCRM_IMG_REVERSE_Y_RW, (u64)val);1455	if (ret) {1456		dev_err(dev, "Fail to set reverse_y value reg\n");1457		return ret;1458	}1459 1460	return 0;1461}1462 1463static int alvium_get_hw_features_params(struct alvium_dev *alvium)1464{1465	struct device *dev = &alvium->i2c_client->dev;1466	int ret;1467 1468	ret = alvium_get_csi_clk_params(alvium);1469	if (ret) {1470		dev_err(dev, "Fail to read min/max csi clock regs\n");1471		return ret;1472	}1473 1474	ret = alvium_get_img_width_params(alvium);1475	if (ret) {1476		dev_err(dev, "Fail to read img width regs\n");1477		return ret;1478	}1479 1480	ret = alvium_get_img_height_params(alvium);1481	if (ret) {1482		dev_err(dev, "Fail to read img height regs\n");1483		return ret;1484	}1485 1486	ret = alvium_get_offx_params(alvium);1487	if (ret) {1488		dev_err(dev, "Fail to read offx regs\n");1489		return ret;1490	}1491 1492	ret = alvium_get_offy_params(alvium);1493	if (ret) {1494		dev_err(dev, "Fail to read offy regs\n");1495		return ret;1496	}1497 1498	ret = alvium_get_gain_params(alvium);1499	if (ret) {1500		dev_err(dev, "Fail to read gain regs\n");1501		return ret;1502	}1503 1504	ret = alvium_get_exposure_params(alvium);1505	if (ret) {1506		dev_err(dev, "Fail to read min/max exp regs\n");1507		return ret;1508	}1509 1510	ret = alvium_get_red_balance_ratio_params(alvium);1511	if (ret) {1512		dev_err(dev, "Fail to read red balance ratio regs\n");1513		return ret;1514	}1515 1516	ret = alvium_get_blue_balance_ratio_params(alvium);1517	if (ret) {1518		dev_err(dev, "Fail to read blue balance ratio regs\n");1519		return ret;1520	}1521 1522	ret = alvium_get_hue_params(alvium);1523	if (ret) {1524		dev_err(dev, "Fail to read hue regs\n");1525		return ret;1526	}1527 1528	ret = alvium_get_contrast_params(alvium);1529	if (ret) {1530		dev_err(dev, "Fail to read contrast regs\n");1531		return ret;1532	}1533 1534	ret = alvium_get_saturation_params(alvium);1535	if (ret) {1536		dev_err(dev, "Fail to read saturation regs\n");1537		return ret;1538	}1539 1540	ret = alvium_get_black_lvl_params(alvium);1541	if (ret) {1542		dev_err(dev, "Fail to read black lvl regs\n");1543		return ret;1544	}1545 1546	ret = alvium_get_gamma_params(alvium);1547	if (ret) {1548		dev_err(dev, "Fail to read gamma regs\n");1549		return ret;1550	}1551 1552	ret = alvium_get_sharpness_params(alvium);1553	if (ret) {1554		dev_err(dev, "Fail to read sharpness regs\n");1555		return ret;1556	}1557 1558	return 0;1559}1560 1561static int alvium_get_hw_info(struct alvium_dev *alvium)1562{1563	struct device *dev = &alvium->i2c_client->dev;1564	int ret;1565 1566	ret = alvium_get_bcrm_vers(alvium);1567	if (ret) {1568		dev_err(dev, "Fail to read bcrm version reg\n");1569		return ret;1570	}1571 1572	ret = alvium_get_bcrm_addr(alvium);1573	if (ret) {1574		dev_err(dev, "Fail to bcrm address reg\n");1575		return ret;1576	}1577 1578	ret = alvium_get_fw_version(alvium);1579	if (ret) {1580		dev_err(dev, "Fail to read fw version reg\n");1581		return ret;1582	}1583 1584	ret = alvium_get_host_supp_csi_lanes(alvium);1585	if (ret) {1586		dev_err(dev, "Fail to read host supported csi lanes reg\n");1587		return ret;1588	}1589 1590	ret = alvium_get_feat_inq(alvium);1591	if (ret) {1592		dev_err(dev, "Fail to read bcrm feature inquiry reg\n");1593		return ret;1594	}1595 1596	ret = alvium_get_hw_features_params(alvium);1597	if (ret) {1598		dev_err(dev, "Fail to read features params regs\n");1599		return ret;1600	}1601 1602	ret = alvium_get_avail_mipi_data_format(alvium);1603	if (ret) {1604		dev_err(dev, "Fail to read available mipi data formats reg\n");1605		return ret;1606	}1607 1608	ret = alvium_get_avail_bayer(alvium);1609	if (ret) {1610		dev_err(dev, "Fail to read available Bayer patterns reg\n");1611		return ret;1612	}1613 1614	ret = alvium_get_mode(alvium);1615	if (ret) {1616		dev_err(dev, "Fail to get current mode reg\n");1617		return ret;1618	}1619 1620	return 0;1621}1622 1623static int alvium_hw_init(struct alvium_dev *alvium)1624{1625	struct device *dev = &alvium->i2c_client->dev;1626	int ret;1627 1628	/* Set Alvium BCM mode*/1629	ret = alvium_set_bcm_mode(alvium);1630	if (ret) {1631		dev_err(dev, "Fail to set BCM mode\n");1632		return ret;1633	}1634 1635	ret = alvium_set_csi_lanes(alvium);1636	if (ret) {1637		dev_err(dev, "Fail to set csi lanes\n");1638		return ret;1639	}1640 1641	ret = alvium_set_csi_clk(alvium);1642	if (ret) {1643		dev_err(dev, "Fail to set csi clk\n");1644		return ret;1645	}1646 1647	ret = alvium_set_lp2hs_delay(alvium);1648	if (ret) {1649		dev_err(dev, "Fail to set lp2hs reg\n");1650		return ret;1651	}1652 1653	return 0;1654}1655 1656/* --------------- Subdev Operations --------------- */1657static int alvium_s_frame_interval(struct v4l2_subdev *sd,1658				   struct v4l2_subdev_state *sd_state,1659				   struct v4l2_subdev_frame_interval *fi)1660{1661	struct alvium_dev *alvium = sd_to_alvium(sd);1662	struct device *dev = &alvium->i2c_client->dev;1663	u64 req_fr, min_fr, max_fr;1664	struct v4l2_fract *interval;1665	int ret;1666 1667	if (alvium->streaming)1668		return -EBUSY;1669 1670	if (fi->interval.denominator == 0)1671		return -EINVAL;1672 1673	ret = alvium_get_frame_interval(alvium, &min_fr, &max_fr);1674	if (ret) {1675		dev_err(dev, "Fail to get frame interval\n");1676		return ret;1677	}1678 1679	dev_dbg(dev, "fi->interval.numerator = %d\n",1680		fi->interval.numerator);1681	dev_dbg(dev, "fi->interval.denominator = %d\n",1682		fi->interval.denominator);1683 1684	req_fr = (u64)((fi->interval.denominator * USEC_PER_SEC) /1685		       fi->interval.numerator);1686	req_fr = clamp(req_fr, min_fr, max_fr);1687 1688	interval = v4l2_subdev_state_get_interval(sd_state, 0);1689 1690	interval->numerator = fi->interval.numerator;1691	interval->denominator = fi->interval.denominator;1692 1693	if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)1694		return 0;1695 1696	return alvium_set_frame_rate(alvium, req_fr);1697}1698 1699static int alvium_enum_mbus_code(struct v4l2_subdev *sd,1700				 struct v4l2_subdev_state *sd_state,1701				 struct v4l2_subdev_mbus_code_enum *code)1702{1703	struct alvium_dev *alvium = sd_to_alvium(sd);1704 1705	if (code->index >= alvium->alvium_csi2_fmt_n)1706		return -EINVAL;1707 1708	code->code = alvium->alvium_csi2_fmt[code->index].code;1709 1710	return 0;1711}1712 1713static const struct alvium_pixfmt *1714alvium_code_to_pixfmt(struct alvium_dev *alvium, u32 code)1715{1716	unsigned int i;1717 1718	for (i = 0; alvium->alvium_csi2_fmt[i].code; ++i)1719		if (alvium->alvium_csi2_fmt[i].code == code)1720			return &alvium->alvium_csi2_fmt[i];1721 1722	return &alvium->alvium_csi2_fmt[0];1723}1724 1725static int alvium_enum_frame_size(struct v4l2_subdev *sd,1726				  struct v4l2_subdev_state *state,1727				  struct v4l2_subdev_frame_size_enum *fse)1728{1729	struct alvium_dev *alvium = sd_to_alvium(sd);1730	const struct alvium_pixfmt *alvium_csi2_fmt;1731 1732	if (fse->index)1733		return -EINVAL;1734 1735	alvium_csi2_fmt = alvium_code_to_pixfmt(alvium, fse->code);1736	if (fse->code != alvium_csi2_fmt->code)1737		return -EINVAL;1738 1739	fse->min_width = alvium->img_min_width;1740	fse->max_width = alvium->img_max_width;1741	fse->min_height = alvium->img_min_height;1742	fse->max_height = alvium->img_max_height;1743	return 0;1744}1745 1746static int alvium_set_mode(struct alvium_dev *alvium,1747			   struct v4l2_subdev_state *state)1748{1749	struct v4l2_mbus_framefmt *fmt;1750	struct v4l2_rect *crop;1751	int ret;1752 1753	crop = v4l2_subdev_state_get_crop(state, 0);1754	fmt = v4l2_subdev_state_get_format(state, 0);1755 1756	v4l_bound_align_image(&fmt->width, alvium->img_min_width,1757			      alvium->img_max_width, 0,1758			      &fmt->height, alvium->img_min_height,1759			      alvium->img_max_height, 0, 0);1760 1761	/* alvium don't accept negative crop left/top */1762	crop->left = clamp((u32)max(0, crop->left), alvium->min_offx,1763			   (u32)(alvium->img_max_width - fmt->width));1764	crop->top = clamp((u32)max(0, crop->top), alvium->min_offy,1765			  (u32)(alvium->img_max_height - fmt->height));1766 1767	ret = alvium_set_img_width(alvium, fmt->width);1768	if (ret)1769		return ret;1770 1771	ret = alvium_set_img_height(alvium, fmt->height);1772	if (ret)1773		return ret;1774 1775	ret = alvium_set_img_offx(alvium, crop->left);1776	if (ret)1777		return ret;1778 1779	ret = alvium_set_img_offy(alvium, crop->top);1780	if (ret)1781		return ret;1782 1783	return 0;1784}1785 1786static int alvium_set_framefmt(struct alvium_dev *alvium,1787			       struct v4l2_mbus_framefmt *format)1788{1789	struct device *dev = &alvium->i2c_client->dev;1790	const struct alvium_pixfmt *alvium_csi2_fmt;1791	int ret = 0;1792 1793	alvium_csi2_fmt = alvium_code_to_pixfmt(alvium, format->code);1794 1795	ret = alvium_set_mipi_fmt(alvium, alvium_csi2_fmt);1796	if (ret)1797		return ret;1798 1799	if (alvium_csi2_fmt->is_raw) {1800		ret = alvium_set_bayer_pattern(alvium, alvium_csi2_fmt);1801		if (ret)1802			return ret;1803	}1804 1805	dev_dbg(dev, "start: %s, mipi_fmt_regval regval = 0x%llx",1806		__func__, alvium_csi2_fmt->mipi_fmt_regval);1807 1808	return ret;1809}1810 1811static int alvium_s_stream(struct v4l2_subdev *sd, int enable)1812{1813	struct alvium_dev *alvium = sd_to_alvium(sd);1814	struct i2c_client *client = v4l2_get_subdevdata(&alvium->sd);1815	struct v4l2_mbus_framefmt *fmt;1816	struct v4l2_subdev_state *state;1817	int ret = 0;1818 1819	state = v4l2_subdev_lock_and_get_active_state(sd);1820 1821	if (enable) {1822		ret = pm_runtime_resume_and_get(&client->dev);1823		if (ret < 0)1824			goto out;1825 1826		ret = __v4l2_ctrl_handler_setup(&alvium->ctrls.handler);1827		if (ret)1828			goto out;1829 1830		ret = alvium_set_mode(alvium, state);1831		if (ret)1832			goto out;1833 1834		fmt = v4l2_subdev_state_get_format(state, 0);1835		ret = alvium_set_framefmt(alvium, fmt);1836		if (ret)1837			goto out;1838 1839		ret = alvium_set_stream_mipi(alvium, enable);1840		if (ret)1841			goto out;1842 1843	} else {1844		alvium_set_stream_mipi(alvium, enable);1845		pm_runtime_mark_last_busy(&client->dev);1846		pm_runtime_put_autosuspend(&client->dev);1847	}1848 1849	alvium->streaming = !!enable;1850	v4l2_subdev_unlock_state(state);1851 1852	return 0;1853 1854out:1855	pm_runtime_put(&client->dev);1856	v4l2_subdev_unlock_state(state);1857	return ret;1858}1859 1860static int alvium_init_state(struct v4l2_subdev *sd,1861			     struct v4l2_subdev_state *state)1862{1863	struct alvium_dev *alvium = sd_to_alvium(sd);1864	struct alvium_mode *mode = &alvium->mode;1865	struct v4l2_fract *interval;1866	struct v4l2_subdev_format sd_fmt = {1867		.which = V4L2_SUBDEV_FORMAT_TRY,1868		.format = alvium_csi2_default_fmt,1869	};1870	struct v4l2_subdev_crop sd_crop = {1871		.which = V4L2_SUBDEV_FORMAT_TRY,1872		.rect = {1873			.left = mode->crop.left,1874			.top = mode->crop.top,1875			.width = mode->crop.width,1876			.height = mode->crop.height,1877		},1878	};1879 1880	*v4l2_subdev_state_get_crop(state, 0) = sd_crop.rect;1881	*v4l2_subdev_state_get_format(state, 0) = sd_fmt.format;1882 1883	/* Setup initial frame interval*/1884	interval = v4l2_subdev_state_get_interval(state, 0);1885	interval->numerator = 1;1886	interval->denominator = ALVIUM_DEFAULT_FR_HZ;1887 1888	return 0;1889}1890 1891static int alvium_set_fmt(struct v4l2_subdev *sd,1892			  struct v4l2_subdev_state *sd_state,1893			  struct v4l2_subdev_format *format)1894{1895	struct alvium_dev *alvium = sd_to_alvium(sd);1896	const struct alvium_pixfmt *alvium_csi2_fmt;1897	struct v4l2_mbus_framefmt *fmt;1898	struct v4l2_rect *crop;1899 1900	fmt = v4l2_subdev_state_get_format(sd_state, 0);1901	crop = v4l2_subdev_state_get_crop(sd_state, 0);1902 1903	v4l_bound_align_image(&format->format.width, alvium->img_min_width,1904			      alvium->img_max_width, 0,1905			      &format->format.height, alvium->img_min_height,1906			      alvium->img_max_height, 0, 0);1907 1908	/* Adjust left and top to prevent roll over sensor area */1909	crop->left = clamp((u32)crop->left, (u32)0,1910			   (alvium->img_max_width - fmt->width));1911	crop->top = clamp((u32)crop->top, (u32)0,1912			  (alvium->img_max_height - fmt->height));1913 1914	/* Set also the crop width and height when set a new fmt */1915	crop->width = fmt->width;1916	crop->height = fmt->height;1917 1918	alvium_csi2_fmt = alvium_code_to_pixfmt(alvium, format->format.code);1919	fmt->code = alvium_csi2_fmt->code;1920 1921	*fmt = format->format;1922 1923	return 0;1924}1925 1926static int alvium_set_selection(struct v4l2_subdev *sd,1927				struct v4l2_subdev_state *sd_state,1928				struct v4l2_subdev_selection *sel)1929{1930	struct alvium_dev *alvium = sd_to_alvium(sd);1931	struct v4l2_mbus_framefmt *fmt;1932	struct v4l2_rect *crop;1933 1934	if (sel->target != V4L2_SEL_TGT_CROP)1935		return -EINVAL;1936 1937	crop = v4l2_subdev_state_get_crop(sd_state, 0);1938	fmt = v4l2_subdev_state_get_format(sd_state, 0);1939 1940	/*1941	 * Alvium can only shift the origin of the img1942	 * then we accept only value with the same value of the actual fmt1943	 */1944	if (sel->r.width != fmt->width)1945		sel->r.width = fmt->width;1946 1947	if (sel->r.height != fmt->height)1948		sel->r.height = fmt->height;1949 1950	/* alvium don't accept negative crop left/top */1951	crop->left = clamp((u32)max(0, sel->r.left), alvium->min_offx,1952			   alvium->img_max_width - sel->r.width);1953	crop->top = clamp((u32)max(0, sel->r.top), alvium->min_offy,1954			  alvium->img_max_height - sel->r.height);1955 1956	sel->r = *crop;1957 1958	return 0;1959}1960 1961static int alvium_get_selection(struct v4l2_subdev *sd,1962				struct v4l2_subdev_state *sd_state,1963				struct v4l2_subdev_selection *sel)1964{1965	struct alvium_dev *alvium = sd_to_alvium(sd);1966 1967	switch (sel->target) {1968	/* Current cropping area */1969	case V4L2_SEL_TGT_CROP:1970		sel->r = *v4l2_subdev_state_get_crop(sd_state, 0);1971		break;1972	/* Cropping bounds */1973	case V4L2_SEL_TGT_NATIVE_SIZE:1974		sel->r.top = 0;1975		sel->r.left = 0;1976		sel->r.width = alvium->img_max_width;1977		sel->r.height = alvium->img_max_height;1978		break;1979	/* Default cropping area */1980	case V4L2_SEL_TGT_CROP_BOUNDS:1981	case V4L2_SEL_TGT_CROP_DEFAULT:1982		sel->r.top = alvium->min_offy;1983		sel->r.left = alvium->min_offx;1984		sel->r.width = alvium->img_max_width;1985		sel->r.height = alvium->img_max_height;1986		break;1987	default:1988		return -EINVAL;1989	}1990 1991	return 0;1992}1993 1994static int alvium_g_volatile_ctrl(struct v4l2_ctrl *ctrl)1995{1996	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);1997	struct alvium_dev *alvium = sd_to_alvium(sd);1998	int val;1999 2000	switch (ctrl->id) {2001	case V4L2_CID_ANALOGUE_GAIN:2002		val = alvium_get_gain(alvium);2003		if (val < 0)2004			return val;2005		alvium->ctrls.gain->val = val;2006		break;2007	case V4L2_CID_EXPOSURE:2008		val = alvium_get_exposure(alvium);2009		if (val < 0)2010			return val;2011		alvium->ctrls.exposure->val = val;2012		break;2013	}2014 2015	return 0;2016}2017 2018static int alvium_s_ctrl(struct v4l2_ctrl *ctrl)2019{2020	struct v4l2_subdev *sd = ctrl_to_sd(ctrl);2021	struct alvium_dev *alvium = sd_to_alvium(sd);2022	struct i2c_client *client = v4l2_get_subdevdata(&alvium->sd);2023	int ret;2024 2025	/*2026	 * Applying V4L2 control value only happens2027	 * when power is up for streaming2028	 */2029	if (!pm_runtime_get_if_in_use(&client->dev))2030		return 0;2031 2032	switch (ctrl->id) {2033	case V4L2_CID_ANALOGUE_GAIN:2034		ret = alvium_set_ctrl_gain(alvium, ctrl->val);2035		break;2036	case V4L2_CID_AUTOGAIN:2037		ret = alvium_set_ctrl_auto_gain(alvium, ctrl->val);2038		break;2039	case V4L2_CID_EXPOSURE:2040		ret = alvium_set_ctrl_exposure(alvium, ctrl->val);2041		break;2042	case V4L2_CID_EXPOSURE_AUTO:2043		ret = alvium_set_ctrl_auto_exposure(alvium, ctrl->val);2044		break;2045	case V4L2_CID_RED_BALANCE:2046		ret = alvium_set_ctrl_red_balance_ratio(alvium, ctrl->val);2047		break;2048	case V4L2_CID_BLUE_BALANCE:2049		ret = alvium_set_ctrl_blue_balance_ratio(alvium, ctrl->val);2050		break;2051	case V4L2_CID_AUTO_WHITE_BALANCE:2052		ret = alvium_set_ctrl_awb(alvium, ctrl->val);2053		break;2054	case V4L2_CID_HUE:2055		ret = alvium_set_ctrl_hue(alvium, ctrl->val);2056		break;2057	case V4L2_CID_CONTRAST:2058		ret = alvium_set_ctrl_contrast(alvium, ctrl->val);2059		break;2060	case V4L2_CID_SATURATION:2061		ret = alvium_set_ctrl_saturation(alvium, ctrl->val);2062		break;2063	case V4L2_CID_GAMMA:2064		ret = alvium_set_ctrl_gamma(alvium, ctrl->val);2065		break;2066	case V4L2_CID_SHARPNESS:2067		ret = alvium_set_ctrl_sharpness(alvium, ctrl->val);2068		break;2069	case V4L2_CID_HFLIP:2070		ret = alvium_set_ctrl_hflip(alvium, ctrl->val);2071		break;2072	case V4L2_CID_VFLIP:2073		ret = alvium_set_ctrl_vflip(alvium, ctrl->val);2074		break;2075	default:2076		ret = -EINVAL;2077		break;2078	}2079 2080	pm_runtime_put(&client->dev);2081 2082	return ret;2083}2084 2085static const struct v4l2_ctrl_ops alvium_ctrl_ops = {2086	.g_volatile_ctrl = alvium_g_volatile_ctrl,2087	.s_ctrl = alvium_s_ctrl,2088};2089 2090static int alvium_ctrl_init(struct alvium_dev *alvium)2091{2092	const struct v4l2_ctrl_ops *ops = &alvium_ctrl_ops;2093	struct alvium_ctrls *ctrls = &alvium->ctrls;2094	struct v4l2_ctrl_handler *hdl = &ctrls->handler;2095	struct v4l2_fwnode_device_properties props;2096	int ret;2097 2098	v4l2_ctrl_handler_init(hdl, 32);2099 2100	/* Pixel rate is fixed */2101	ctrls->pixel_rate = v4l2_ctrl_new_std(hdl, ops,2102					      V4L2_CID_PIXEL_RATE, 0,2103					      ALVIUM_DEFAULT_PIXEL_RATE_MHZ, 1,2104					      ALVIUM_DEFAULT_PIXEL_RATE_MHZ);2105	ctrls->pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY;2106 2107	/* Link freq is fixed */2108	ctrls->link_freq = v4l2_ctrl_new_int_menu(hdl, ops,2109						  V4L2_CID_LINK_FREQ,2110						  0, 0, &alvium->link_freq);2111	ctrls->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;2112 2113	/* Auto/manual white balance */2114	if (alvium->avail_ft.auto_whiteb) {2115		ctrls->auto_wb = v4l2_ctrl_new_std(hdl, ops,2116						   V4L2_CID_AUTO_WHITE_BALANCE,2117						   0, 1, 1, 1);2118		v4l2_ctrl_auto_cluster(3, &ctrls->auto_wb, 0, false);2119	}2120 2121	ctrls->blue_balance = v4l2_ctrl_new_std(hdl, ops,2122						V4L2_CID_BLUE_BALANCE,2123						alvium->min_bbalance,2124						alvium->max_bbalance,2125						alvium->inc_bbalance,2126						alvium->dft_bbalance);2127	ctrls->red_balance = v4l2_ctrl_new_std(hdl, ops,2128					       V4L2_CID_RED_BALANCE,2129					       alvium->min_rbalance,2130					       alvium->max_rbalance,2131					       alvium->inc_rbalance,2132					       alvium->dft_rbalance);2133 2134	/* Auto/manual exposure */2135	if (alvium->avail_ft.auto_exp) {2136		ctrls->auto_exp =2137			v4l2_ctrl_new_std_menu(hdl, ops,2138					       V4L2_CID_EXPOSURE_AUTO,2139					       V4L2_EXPOSURE_MANUAL, 0,2140					       V4L2_EXPOSURE_AUTO);2141		v4l2_ctrl_auto_cluster(2, &ctrls->auto_exp, 1, true);2142	}2143 2144	ctrls->exposure = v4l2_ctrl_new_std(hdl, ops,2145					    V4L2_CID_EXPOSURE,2146					    alvium->min_exp,2147					    alvium->max_exp,2148					    alvium->inc_exp,2149					    alvium->dft_exp);2150	ctrls->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;2151 2152	/* Auto/manual gain */2153	if (alvium->avail_ft.auto_gain) {2154		ctrls->auto_gain = v4l2_ctrl_new_std(hdl, ops,2155						     V4L2_CID_AUTOGAIN,2156						     0, 1, 1, 1);2157		v4l2_ctrl_auto_cluster(2, &ctrls->auto_gain, 0, true);2158	}2159 2160	if (alvium->avail_ft.gain) {2161		ctrls->gain = v4l2_ctrl_new_std(hdl, ops,2162						V4L2_CID_ANALOGUE_GAIN,2163						alvium->min_gain,2164						alvium->max_gain,2165						alvium->inc_gain,2166						alvium->dft_gain);2167		ctrls->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;2168	}2169 2170	if (alvium->avail_ft.sat)2171		ctrls->saturation = v4l2_ctrl_new_std(hdl, ops,2172						      V4L2_CID_SATURATION,2173						      alvium->min_sat,2174						      alvium->max_sat,2175						      alvium->inc_sat,2176						      alvium->dft_sat);2177 2178	if (alvium->avail_ft.hue)2179		ctrls->hue = v4l2_ctrl_new_std(hdl, ops,2180					       V4L2_CID_HUE,2181					       alvium->min_hue,2182					       alvium->max_hue,2183					       alvium->inc_hue,2184					       alvium->dft_hue);2185 2186	if (alvium->avail_ft.contrast)2187		ctrls->contrast = v4l2_ctrl_new_std(hdl, ops,2188						    V4L2_CID_CONTRAST,2189						    alvium->min_contrast,2190						    alvium->max_contrast,2191						    alvium->inc_contrast,2192						    alvium->dft_contrast);2193 2194	if (alvium->avail_ft.gamma)2195		ctrls->gamma = v4l2_ctrl_new_std(hdl, ops,2196						 V4L2_CID_GAMMA,2197						 alvium->min_gamma,2198						 alvium->max_gamma,2199						 alvium->inc_gamma,2200						 alvium->dft_gamma);2201 2202	if (alvium->avail_ft.sharp)2203		ctrls->sharpness = v4l2_ctrl_new_std(hdl, ops,2204						     V4L2_CID_SHARPNESS,2205						     alvium->min_sharp,2206						     alvium->max_sharp,2207						     alvium->inc_sharp,2208						     alvium->dft_sharp);2209 2210	if (alvium->avail_ft.rev_x)2211		ctrls->hflip = v4l2_ctrl_new_std(hdl, ops,2212						 V4L2_CID_HFLIP,2213						 0, 1, 1, 0);2214 2215	if (alvium->avail_ft.rev_y)2216		ctrls->vflip = v4l2_ctrl_new_std(hdl, ops,2217						 V4L2_CID_VFLIP,2218						 0, 1, 1, 0);2219 2220	if (hdl->error) {2221		ret = hdl->error;2222		goto free_ctrls;2223	}2224 2225	ret = v4l2_fwnode_device_parse(&alvium->i2c_client->dev, &props);2226	if (ret)2227		goto free_ctrls;2228 2229	ret = v4l2_ctrl_new_fwnode_properties(hdl, ops, &props);2230	if (ret)2231		goto free_ctrls;2232 2233	alvium->sd.ctrl_handler = hdl;2234	return 0;2235 2236free_ctrls:2237	v4l2_ctrl_handler_free(hdl);2238	return ret;2239}2240 2241static const struct v4l2_subdev_core_ops alvium_core_ops = {2242	.log_status = v4l2_ctrl_subdev_log_status,2243	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,2244	.unsubscribe_event = v4l2_event_subdev_unsubscribe,2245};2246 2247static const struct v4l2_subdev_video_ops alvium_video_ops = {2248	.s_stream		= alvium_s_stream,2249};2250 2251static const struct v4l2_subdev_pad_ops alvium_pad_ops = {2252	.enum_mbus_code = alvium_enum_mbus_code,2253	.enum_frame_size = alvium_enum_frame_size,2254	.get_fmt = v4l2_subdev_get_fmt,2255	.set_fmt = alvium_set_fmt,2256	.get_selection = alvium_get_selection,2257	.set_selection = alvium_set_selection,2258	.get_frame_interval = v4l2_subdev_get_frame_interval,2259	.set_frame_interval = alvium_s_frame_interval,2260};2261 2262static const struct v4l2_subdev_internal_ops alvium_internal_ops = {2263	.init_state = alvium_init_state,2264};2265 2266static const struct v4l2_subdev_ops alvium_subdev_ops = {2267	.core	= &alvium_core_ops,2268	.pad	= &alvium_pad_ops,2269	.video	= &alvium_video_ops,2270};2271 2272static int alvium_subdev_init(struct alvium_dev *alvium)2273{2274	struct i2c_client *client = alvium->i2c_client;2275	struct device *dev = &alvium->i2c_client->dev;2276	struct v4l2_subdev *sd = &alvium->sd;2277	int ret;2278 2279	/* Setup the initial mode */2280	alvium->mode.fmt = alvium_csi2_default_fmt;2281	alvium->mode.width = alvium_csi2_default_fmt.width;2282	alvium->mode.height = alvium_csi2_default_fmt.height;2283	alvium->mode.crop.left = alvium->min_offx;2284	alvium->mode.crop.top = alvium->min_offy;2285	alvium->mode.crop.width = alvium_csi2_default_fmt.width;2286	alvium->mode.crop.height = alvium_csi2_default_fmt.height;2287 2288	/* init alvium sd */2289	v4l2_i2c_subdev_init(sd, client, &alvium_subdev_ops);2290 2291	sd->internal_ops = &alvium_internal_ops;2292	sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;2293	alvium->pad.flags = MEDIA_PAD_FL_SOURCE;2294	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;2295 2296	ret = media_entity_pads_init(&sd->entity, 1, &alvium->pad);2297	if (ret) {2298		dev_err(dev, "Could not register media entity\n");2299		return ret;2300	}2301 2302	ret = alvium_ctrl_init(alvium);2303	if (ret) {2304		dev_err(dev, "Control initialization error %d\n", ret);2305		goto entity_cleanup;2306	}2307 2308	alvium->sd.state_lock = alvium->ctrls.handler.lock;2309 2310	ret = v4l2_subdev_init_finalize(sd);2311	if (ret < 0) {2312		dev_err(dev, "subdev initialization error %d\n", ret);2313		goto err_ctrls;2314	}2315 2316	return 0;2317 2318err_ctrls:2319	v4l2_ctrl_handler_free(&alvium->ctrls.handler);2320entity_cleanup:2321	media_entity_cleanup(&alvium->sd.entity);2322	return ret;2323}2324 2325static void alvium_subdev_cleanup(struct alvium_dev *alvium)2326{2327	v4l2_fwnode_endpoint_free(&alvium->ep);2328	v4l2_subdev_cleanup(&alvium->sd);2329	media_entity_cleanup(&alvium->sd.entity);2330	v4l2_ctrl_handler_free(&alvium->ctrls.handler);2331}2332 2333static int alvium_get_dt_data(struct alvium_dev *alvium)2334{2335	struct device *dev = &alvium->i2c_client->dev;2336	struct fwnode_handle *fwnode = dev_fwnode(dev);2337	struct fwnode_handle *endpoint;2338 2339	if (!fwnode)2340		return -EINVAL;2341 2342	/* Only CSI2 is supported for now: */2343	alvium->ep.bus_type = V4L2_MBUS_CSI2_DPHY;2344 2345	endpoint = fwnode_graph_get_endpoint_by_id(fwnode, 0, 0, 0);2346	if (!endpoint) {2347		dev_err(dev, "endpoint node not found\n");2348		return -EINVAL;2349	}2350 2351	if (v4l2_fwnode_endpoint_alloc_parse(endpoint, &alvium->ep)) {2352		dev_err(dev, "could not parse endpoint\n");2353		goto error_out;2354	}2355 2356	if (!alvium->ep.nr_of_link_frequencies) {2357		dev_err(dev, "no link frequencies defined");2358		goto error_out;2359	}2360 2361	return 0;2362 2363error_out:2364	v4l2_fwnode_endpoint_free(&alvium->ep);2365	fwnode_handle_put(endpoint);2366 2367	return -EINVAL;2368}2369 2370static int alvium_set_power(struct alvium_dev *alvium, bool on)2371{2372	int ret;2373 2374	if (!on)2375		return regulator_disable(alvium->reg_vcc);2376 2377	ret = regulator_enable(alvium->reg_vcc);2378	if (ret)2379		return ret;2380 2381	/* alvium boot time 7s */2382	msleep(7000);2383	return 0;2384}2385 2386static int alvium_runtime_resume(struct device *dev)2387{2388	struct v4l2_subdev *sd = dev_get_drvdata(dev);2389	struct alvium_dev *alvium = sd_to_alvium(sd);2390	int ret;2391 2392	ret = alvium_set_power(alvium, true);2393	if (ret)2394		return ret;2395 2396	ret = alvium_hw_init(alvium);2397	if (ret) {2398		alvium_set_power(alvium, false);2399		return ret;2400	}2401 2402	return 0;2403}2404 2405static int alvium_runtime_suspend(struct device *dev)2406{2407	struct v4l2_subdev *sd = dev_get_drvdata(dev);2408	struct alvium_dev *alvium = sd_to_alvium(sd);2409 2410	alvium_set_power(alvium, false);2411 2412	return 0;2413}2414 2415static const struct dev_pm_ops alvium_pm_ops = {2416	RUNTIME_PM_OPS(alvium_runtime_suspend, alvium_runtime_resume, NULL)2417};2418 2419static int alvium_probe(struct i2c_client *client)2420{2421	struct device *dev = &client->dev;2422	struct alvium_dev *alvium;2423	int ret;2424 2425	alvium = devm_kzalloc(dev, sizeof(*alvium), GFP_KERNEL);2426	if (!alvium)2427		return -ENOMEM;2428 2429	alvium->i2c_client = client;2430 2431	alvium->regmap = devm_cci_regmap_init_i2c(client, 16);2432	if (IS_ERR(alvium->regmap))2433		return PTR_ERR(alvium->regmap);2434 2435	ret = alvium_get_dt_data(alvium);2436	if (ret)2437		return ret;2438 2439	alvium->reg_vcc = devm_regulator_get_optional(dev, "vcc-ext-in");2440	if (IS_ERR(alvium->reg_vcc))2441		return dev_err_probe(dev, PTR_ERR(alvium->reg_vcc),2442				     "no vcc-ext-in regulator provided\n");2443 2444	ret = alvium_set_power(alvium, true);2445	if (ret)2446		goto err_powerdown;2447 2448	if (!alvium_is_alive(alvium)) {2449		ret = -ENODEV;2450		dev_err_probe(dev, ret, "Device detection failed\n");2451		goto err_powerdown;2452	}2453 2454	ret = alvium_get_hw_info(alvium);2455	if (ret) {2456		dev_err_probe(dev, ret, "get_hw_info fail\n");2457		goto err_powerdown;2458	}2459 2460	ret = alvium_hw_init(alvium);2461	if (ret) {2462		dev_err_probe(dev, ret, "hw_init fail\n");2463		goto err_powerdown;2464	}2465 2466	ret = alvium_setup_mipi_fmt(alvium);2467	if (ret) {2468		dev_err_probe(dev, ret, "setup_mipi_fmt fail\n");2469		goto err_powerdown;2470	}2471 2472	/*2473	 * Enable runtime PM without autosuspend:2474	 *2475	 * Don't use pm autosuspend (alvium have ~7s boot time).2476	 * Alvium has been powered manually:2477	 *  - mark it as active2478	 *  - increase the usage count without resuming the device.2479	 */2480	pm_runtime_set_active(dev);2481	pm_runtime_get_noresume(dev);2482	pm_runtime_enable(dev);2483 2484	/* Initialize the V4L2 subdev. */2485	ret = alvium_subdev_init(alvium);2486	if (ret)2487		goto err_pm;2488 2489	ret = v4l2_async_register_subdev(&alvium->sd);2490	if (ret < 0) {2491		dev_err_probe(dev, ret, "Could not register v4l2 device\n");2492		goto err_subdev;2493	}2494 2495	return 0;2496 2497err_subdev:2498	alvium_subdev_cleanup(alvium);2499err_pm:2500	pm_runtime_disable(dev);2501	pm_runtime_put_noidle(dev);2502	kfree(alvium->alvium_csi2_fmt);2503err_powerdown:2504	alvium_set_power(alvium, false);2505 2506	return ret;2507}2508 2509static void alvium_remove(struct i2c_client *client)2510{2511	struct v4l2_subdev *sd = i2c_get_clientdata(client);2512	struct alvium_dev *alvium = sd_to_alvium(sd);2513	struct device *dev = &alvium->i2c_client->dev;2514 2515	v4l2_async_unregister_subdev(sd);2516	alvium_subdev_cleanup(alvium);2517	kfree(alvium->alvium_csi2_fmt);2518	/*2519	 * Disable runtime PM. In case runtime PM is disabled in the kernel,2520	 * make sure to turn power off manually.2521	 */2522	pm_runtime_disable(dev);2523	if (!pm_runtime_status_suspended(dev))2524		alvium_set_power(alvium, false);2525	pm_runtime_set_suspended(dev);2526}2527 2528static const struct of_device_id alvium_of_ids[] = {2529	{ .compatible = "alliedvision,alvium-csi2", },2530	{ }2531};2532MODULE_DEVICE_TABLE(of, alvium_of_ids);2533 2534static struct i2c_driver alvium_i2c_driver = {2535	.driver = {2536		.name = "alvium-csi2",2537		.pm = pm_ptr(&alvium_pm_ops),2538		.of_match_table = alvium_of_ids,2539	},2540	.probe = alvium_probe,2541	.remove = alvium_remove,2542};2543 2544module_i2c_driver(alvium_i2c_driver);2545 2546MODULE_DESCRIPTION("Allied Vision's Alvium Camera Driver");2547MODULE_AUTHOR("Tommaso Merciai <tomm.merciai@gmail.com>");2548MODULE_AUTHOR("Martin Hecht <martin.hecht@avnet.eu>");2549MODULE_AUTHOR("Avnet Silica Software & Services EMEA");2550MODULE_LICENSE("GPL");2551