brintos

brintos / linux-shallow public Read only

0
0
Text · 39.3 KiB · b2dce67 Raw
1800 lines · c
1// SPDX-License-Identifier: GPL-2.02// Copyright (C) 2018 Intel Corporation3 4#include <linux/unaligned.h>5#include <linux/acpi.h>6#include <linux/i2c.h>7#include <linux/module.h>8#include <linux/pm_runtime.h>9#include <media/v4l2-ctrls.h>10#include <media/v4l2-device.h>11#include <media/v4l2-event.h>12#include <media/v4l2-fwnode.h>13 14#define IMX355_REG_MODE_SELECT		0x010015#define IMX355_MODE_STANDBY		0x0016#define IMX355_MODE_STREAMING		0x0117 18/* Chip ID */19#define IMX355_REG_CHIP_ID		0x001620#define IMX355_CHIP_ID			0x035521 22/* V_TIMING internal */23#define IMX355_REG_FLL			0x034024#define IMX355_FLL_MAX			0xffff25 26/* Exposure control */27#define IMX355_REG_EXPOSURE		0x020228#define IMX355_EXPOSURE_MIN		129#define IMX355_EXPOSURE_STEP		130#define IMX355_EXPOSURE_DEFAULT		0x028231 32/* Analog gain control */33#define IMX355_REG_ANALOG_GAIN		0x020434#define IMX355_ANA_GAIN_MIN		035#define IMX355_ANA_GAIN_MAX		96036#define IMX355_ANA_GAIN_STEP		137#define IMX355_ANA_GAIN_DEFAULT		038 39/* Digital gain control */40#define IMX355_REG_DPGA_USE_GLOBAL_GAIN	0x307041#define IMX355_REG_DIG_GAIN_GLOBAL	0x020e42#define IMX355_DGTL_GAIN_MIN		25643#define IMX355_DGTL_GAIN_MAX		409544#define IMX355_DGTL_GAIN_STEP		145#define IMX355_DGTL_GAIN_DEFAULT	25646 47/* Test Pattern Control */48#define IMX355_REG_TEST_PATTERN		0x060049#define IMX355_TEST_PATTERN_DISABLED		050#define IMX355_TEST_PATTERN_SOLID_COLOR		151#define IMX355_TEST_PATTERN_COLOR_BARS		252#define IMX355_TEST_PATTERN_GRAY_COLOR_BARS	353#define IMX355_TEST_PATTERN_PN9			454 55/* Flip Control */56#define IMX355_REG_ORIENTATION		0x010157 58/* default link frequency and external clock */59#define IMX355_LINK_FREQ_DEFAULT	360000000LL60#define IMX355_EXT_CLK			1920000061#define IMX355_LINK_FREQ_INDEX		062 63struct imx355_reg {64	u16 address;65	u8 val;66};67 68struct imx355_reg_list {69	u32 num_of_regs;70	const struct imx355_reg *regs;71};72 73/* Mode : resolution and related config&values */74struct imx355_mode {75	/* Frame width */76	u32 width;77	/* Frame height */78	u32 height;79 80	/* V-timing */81	u32 fll_def;82	u32 fll_min;83 84	/* H-timing */85	u32 llp;86 87	/* index of link frequency */88	u32 link_freq_index;89 90	/* Default register values */91	struct imx355_reg_list reg_list;92};93 94struct imx355_hwcfg {95	u32 ext_clk;			/* sensor external clk */96	unsigned long link_freq_bitmap;97};98 99struct imx355 {100	struct v4l2_subdev sd;101	struct media_pad pad;102 103	struct v4l2_ctrl_handler ctrl_handler;104	/* V4L2 Controls */105	struct v4l2_ctrl *link_freq;106	struct v4l2_ctrl *pixel_rate;107	struct v4l2_ctrl *vblank;108	struct v4l2_ctrl *hblank;109	struct v4l2_ctrl *exposure;110	struct v4l2_ctrl *vflip;111	struct v4l2_ctrl *hflip;112 113	/* Current mode */114	const struct imx355_mode *cur_mode;115 116	struct imx355_hwcfg *hwcfg;117 118	/*119	 * Mutex for serialized access:120	 * Protect sensor set pad format and start/stop streaming safely.121	 * Protect access to sensor v4l2 controls.122	 */123	struct mutex mutex;124};125 126static const struct imx355_reg imx355_global_regs[] = {127	{ 0x0136, 0x13 },128	{ 0x0137, 0x33 },129	{ 0x304e, 0x03 },130	{ 0x4348, 0x16 },131	{ 0x4350, 0x19 },132	{ 0x4408, 0x0a },133	{ 0x440c, 0x0b },134	{ 0x4411, 0x5f },135	{ 0x4412, 0x2c },136	{ 0x4623, 0x00 },137	{ 0x462c, 0x0f },138	{ 0x462d, 0x00 },139	{ 0x462e, 0x00 },140	{ 0x4684, 0x54 },141	{ 0x480a, 0x07 },142	{ 0x4908, 0x07 },143	{ 0x4909, 0x07 },144	{ 0x490d, 0x0a },145	{ 0x491e, 0x0f },146	{ 0x4921, 0x06 },147	{ 0x4923, 0x28 },148	{ 0x4924, 0x28 },149	{ 0x4925, 0x29 },150	{ 0x4926, 0x29 },151	{ 0x4927, 0x1f },152	{ 0x4928, 0x20 },153	{ 0x4929, 0x20 },154	{ 0x492a, 0x20 },155	{ 0x492c, 0x05 },156	{ 0x492d, 0x06 },157	{ 0x492e, 0x06 },158	{ 0x492f, 0x06 },159	{ 0x4930, 0x03 },160	{ 0x4931, 0x04 },161	{ 0x4932, 0x04 },162	{ 0x4933, 0x05 },163	{ 0x595e, 0x01 },164	{ 0x5963, 0x01 },165	{ 0x3030, 0x01 },166	{ 0x3031, 0x01 },167	{ 0x3045, 0x01 },168	{ 0x4010, 0x00 },169	{ 0x4011, 0x00 },170	{ 0x4012, 0x00 },171	{ 0x4013, 0x01 },172	{ 0x68a8, 0xfe },173	{ 0x68a9, 0xff },174	{ 0x6888, 0x00 },175	{ 0x6889, 0x00 },176	{ 0x68b0, 0x00 },177	{ 0x3058, 0x00 },178	{ 0x305a, 0x00 },179};180 181static const struct imx355_reg_list imx355_global_setting = {182	.num_of_regs = ARRAY_SIZE(imx355_global_regs),183	.regs = imx355_global_regs,184};185 186static const struct imx355_reg mode_3268x2448_regs[] = {187	{ 0x0112, 0x0a },188	{ 0x0113, 0x0a },189	{ 0x0114, 0x03 },190	{ 0x0342, 0x0e },191	{ 0x0343, 0x58 },192	{ 0x0340, 0x0a },193	{ 0x0341, 0x37 },194	{ 0x0344, 0x00 },195	{ 0x0345, 0x08 },196	{ 0x0346, 0x00 },197	{ 0x0347, 0x08 },198	{ 0x0348, 0x0c },199	{ 0x0349, 0xcb },200	{ 0x034a, 0x09 },201	{ 0x034b, 0x97 },202	{ 0x0220, 0x00 },203	{ 0x0222, 0x01 },204	{ 0x0900, 0x00 },205	{ 0x0901, 0x11 },206	{ 0x0902, 0x00 },207	{ 0x034c, 0x0c },208	{ 0x034d, 0xc4 },209	{ 0x034e, 0x09 },210	{ 0x034f, 0x90 },211	{ 0x0301, 0x05 },212	{ 0x0303, 0x01 },213	{ 0x0305, 0x02 },214	{ 0x0306, 0x00 },215	{ 0x0307, 0x78 },216	{ 0x030b, 0x01 },217	{ 0x030d, 0x02 },218	{ 0x030e, 0x00 },219	{ 0x030f, 0x4b },220	{ 0x0310, 0x00 },221	{ 0x0700, 0x00 },222	{ 0x0701, 0x10 },223	{ 0x0820, 0x0b },224	{ 0x0821, 0x40 },225	{ 0x3088, 0x04 },226	{ 0x6813, 0x02 },227	{ 0x6835, 0x07 },228	{ 0x6836, 0x01 },229	{ 0x6837, 0x04 },230	{ 0x684d, 0x07 },231	{ 0x684e, 0x01 },232	{ 0x684f, 0x04 },233};234 235static const struct imx355_reg mode_3264x2448_regs[] = {236	{ 0x0112, 0x0a },237	{ 0x0113, 0x0a },238	{ 0x0114, 0x03 },239	{ 0x0342, 0x0e },240	{ 0x0343, 0x58 },241	{ 0x0340, 0x0a },242	{ 0x0341, 0x37 },243	{ 0x0344, 0x00 },244	{ 0x0345, 0x08 },245	{ 0x0346, 0x00 },246	{ 0x0347, 0x08 },247	{ 0x0348, 0x0c },248	{ 0x0349, 0xc7 },249	{ 0x034a, 0x09 },250	{ 0x034b, 0x97 },251	{ 0x0220, 0x00 },252	{ 0x0222, 0x01 },253	{ 0x0900, 0x00 },254	{ 0x0901, 0x11 },255	{ 0x0902, 0x00 },256	{ 0x034c, 0x0c },257	{ 0x034d, 0xc0 },258	{ 0x034e, 0x09 },259	{ 0x034f, 0x90 },260	{ 0x0301, 0x05 },261	{ 0x0303, 0x01 },262	{ 0x0305, 0x02 },263	{ 0x0306, 0x00 },264	{ 0x0307, 0x78 },265	{ 0x030b, 0x01 },266	{ 0x030d, 0x02 },267	{ 0x030e, 0x00 },268	{ 0x030f, 0x4b },269	{ 0x0310, 0x00 },270	{ 0x0700, 0x00 },271	{ 0x0701, 0x10 },272	{ 0x0820, 0x0b },273	{ 0x0821, 0x40 },274	{ 0x3088, 0x04 },275	{ 0x6813, 0x02 },276	{ 0x6835, 0x07 },277	{ 0x6836, 0x01 },278	{ 0x6837, 0x04 },279	{ 0x684d, 0x07 },280	{ 0x684e, 0x01 },281	{ 0x684f, 0x04 },282};283 284static const struct imx355_reg mode_3280x2464_regs[] = {285	{ 0x0112, 0x0a },286	{ 0x0113, 0x0a },287	{ 0x0114, 0x03 },288	{ 0x0342, 0x0e },289	{ 0x0343, 0x58 },290	{ 0x0340, 0x0a },291	{ 0x0341, 0x37 },292	{ 0x0344, 0x00 },293	{ 0x0345, 0x00 },294	{ 0x0346, 0x00 },295	{ 0x0347, 0x00 },296	{ 0x0348, 0x0c },297	{ 0x0349, 0xcf },298	{ 0x034a, 0x09 },299	{ 0x034b, 0x9f },300	{ 0x0220, 0x00 },301	{ 0x0222, 0x01 },302	{ 0x0900, 0x00 },303	{ 0x0901, 0x11 },304	{ 0x0902, 0x00 },305	{ 0x034c, 0x0c },306	{ 0x034d, 0xd0 },307	{ 0x034e, 0x09 },308	{ 0x034f, 0xa0 },309	{ 0x0301, 0x05 },310	{ 0x0303, 0x01 },311	{ 0x0305, 0x02 },312	{ 0x0306, 0x00 },313	{ 0x0307, 0x78 },314	{ 0x030b, 0x01 },315	{ 0x030d, 0x02 },316	{ 0x030e, 0x00 },317	{ 0x030f, 0x4b },318	{ 0x0310, 0x00 },319	{ 0x0700, 0x00 },320	{ 0x0701, 0x10 },321	{ 0x0820, 0x0b },322	{ 0x0821, 0x40 },323	{ 0x3088, 0x04 },324	{ 0x6813, 0x02 },325	{ 0x6835, 0x07 },326	{ 0x6836, 0x01 },327	{ 0x6837, 0x04 },328	{ 0x684d, 0x07 },329	{ 0x684e, 0x01 },330	{ 0x684f, 0x04 },331};332 333static const struct imx355_reg mode_1940x1096_regs[] = {334	{ 0x0112, 0x0a },335	{ 0x0113, 0x0a },336	{ 0x0114, 0x03 },337	{ 0x0342, 0x0e },338	{ 0x0343, 0x58 },339	{ 0x0340, 0x05 },340	{ 0x0341, 0x1a },341	{ 0x0344, 0x02 },342	{ 0x0345, 0xa0 },343	{ 0x0346, 0x02 },344	{ 0x0347, 0xac },345	{ 0x0348, 0x0a },346	{ 0x0349, 0x33 },347	{ 0x034a, 0x06 },348	{ 0x034b, 0xf3 },349	{ 0x0220, 0x00 },350	{ 0x0222, 0x01 },351	{ 0x0900, 0x00 },352	{ 0x0901, 0x11 },353	{ 0x0902, 0x00 },354	{ 0x034c, 0x07 },355	{ 0x034d, 0x94 },356	{ 0x034e, 0x04 },357	{ 0x034f, 0x48 },358	{ 0x0301, 0x05 },359	{ 0x0303, 0x01 },360	{ 0x0305, 0x02 },361	{ 0x0306, 0x00 },362	{ 0x0307, 0x78 },363	{ 0x030b, 0x01 },364	{ 0x030d, 0x02 },365	{ 0x030e, 0x00 },366	{ 0x030f, 0x4b },367	{ 0x0310, 0x00 },368	{ 0x0700, 0x00 },369	{ 0x0701, 0x10 },370	{ 0x0820, 0x0b },371	{ 0x0821, 0x40 },372	{ 0x3088, 0x04 },373	{ 0x6813, 0x02 },374	{ 0x6835, 0x07 },375	{ 0x6836, 0x01 },376	{ 0x6837, 0x04 },377	{ 0x684d, 0x07 },378	{ 0x684e, 0x01 },379	{ 0x684f, 0x04 },380};381 382static const struct imx355_reg mode_1936x1096_regs[] = {383	{ 0x0112, 0x0a },384	{ 0x0113, 0x0a },385	{ 0x0114, 0x03 },386	{ 0x0342, 0x0e },387	{ 0x0343, 0x58 },388	{ 0x0340, 0x05 },389	{ 0x0341, 0x1a },390	{ 0x0344, 0x02 },391	{ 0x0345, 0xa0 },392	{ 0x0346, 0x02 },393	{ 0x0347, 0xac },394	{ 0x0348, 0x0a },395	{ 0x0349, 0x2f },396	{ 0x034a, 0x06 },397	{ 0x034b, 0xf3 },398	{ 0x0220, 0x00 },399	{ 0x0222, 0x01 },400	{ 0x0900, 0x00 },401	{ 0x0901, 0x11 },402	{ 0x0902, 0x00 },403	{ 0x034c, 0x07 },404	{ 0x034d, 0x90 },405	{ 0x034e, 0x04 },406	{ 0x034f, 0x48 },407	{ 0x0301, 0x05 },408	{ 0x0303, 0x01 },409	{ 0x0305, 0x02 },410	{ 0x0306, 0x00 },411	{ 0x0307, 0x78 },412	{ 0x030b, 0x01 },413	{ 0x030d, 0x02 },414	{ 0x030e, 0x00 },415	{ 0x030f, 0x4b },416	{ 0x0310, 0x00 },417	{ 0x0700, 0x00 },418	{ 0x0701, 0x10 },419	{ 0x0820, 0x0b },420	{ 0x0821, 0x40 },421	{ 0x3088, 0x04 },422	{ 0x6813, 0x02 },423	{ 0x6835, 0x07 },424	{ 0x6836, 0x01 },425	{ 0x6837, 0x04 },426	{ 0x684d, 0x07 },427	{ 0x684e, 0x01 },428	{ 0x684f, 0x04 },429};430 431static const struct imx355_reg mode_1924x1080_regs[] = {432	{ 0x0112, 0x0a },433	{ 0x0113, 0x0a },434	{ 0x0114, 0x03 },435	{ 0x0342, 0x0e },436	{ 0x0343, 0x58 },437	{ 0x0340, 0x05 },438	{ 0x0341, 0x1a },439	{ 0x0344, 0x02 },440	{ 0x0345, 0xa8 },441	{ 0x0346, 0x02 },442	{ 0x0347, 0xb4 },443	{ 0x0348, 0x0a },444	{ 0x0349, 0x2b },445	{ 0x034a, 0x06 },446	{ 0x034b, 0xeb },447	{ 0x0220, 0x00 },448	{ 0x0222, 0x01 },449	{ 0x0900, 0x00 },450	{ 0x0901, 0x11 },451	{ 0x0902, 0x00 },452	{ 0x034c, 0x07 },453	{ 0x034d, 0x84 },454	{ 0x034e, 0x04 },455	{ 0x034f, 0x38 },456	{ 0x0301, 0x05 },457	{ 0x0303, 0x01 },458	{ 0x0305, 0x02 },459	{ 0x0306, 0x00 },460	{ 0x0307, 0x78 },461	{ 0x030b, 0x01 },462	{ 0x030d, 0x02 },463	{ 0x030e, 0x00 },464	{ 0x030f, 0x4b },465	{ 0x0310, 0x00 },466	{ 0x0700, 0x00 },467	{ 0x0701, 0x10 },468	{ 0x0820, 0x0b },469	{ 0x0821, 0x40 },470	{ 0x3088, 0x04 },471	{ 0x6813, 0x02 },472	{ 0x6835, 0x07 },473	{ 0x6836, 0x01 },474	{ 0x6837, 0x04 },475	{ 0x684d, 0x07 },476	{ 0x684e, 0x01 },477	{ 0x684f, 0x04 },478};479 480static const struct imx355_reg mode_1920x1080_regs[] = {481	{ 0x0112, 0x0a },482	{ 0x0113, 0x0a },483	{ 0x0114, 0x03 },484	{ 0x0342, 0x0e },485	{ 0x0343, 0x58 },486	{ 0x0340, 0x05 },487	{ 0x0341, 0x1a },488	{ 0x0344, 0x02 },489	{ 0x0345, 0xa8 },490	{ 0x0346, 0x02 },491	{ 0x0347, 0xb4 },492	{ 0x0348, 0x0a },493	{ 0x0349, 0x27 },494	{ 0x034a, 0x06 },495	{ 0x034b, 0xeb },496	{ 0x0220, 0x00 },497	{ 0x0222, 0x01 },498	{ 0x0900, 0x00 },499	{ 0x0901, 0x11 },500	{ 0x0902, 0x00 },501	{ 0x034c, 0x07 },502	{ 0x034d, 0x80 },503	{ 0x034e, 0x04 },504	{ 0x034f, 0x38 },505	{ 0x0301, 0x05 },506	{ 0x0303, 0x01 },507	{ 0x0305, 0x02 },508	{ 0x0306, 0x00 },509	{ 0x0307, 0x78 },510	{ 0x030b, 0x01 },511	{ 0x030d, 0x02 },512	{ 0x030e, 0x00 },513	{ 0x030f, 0x4b },514	{ 0x0310, 0x00 },515	{ 0x0700, 0x00 },516	{ 0x0701, 0x10 },517	{ 0x0820, 0x0b },518	{ 0x0821, 0x40 },519	{ 0x3088, 0x04 },520	{ 0x6813, 0x02 },521	{ 0x6835, 0x07 },522	{ 0x6836, 0x01 },523	{ 0x6837, 0x04 },524	{ 0x684d, 0x07 },525	{ 0x684e, 0x01 },526	{ 0x684f, 0x04 },527};528 529static const struct imx355_reg mode_1640x1232_regs[] = {530	{ 0x0112, 0x0a },531	{ 0x0113, 0x0a },532	{ 0x0114, 0x03 },533	{ 0x0342, 0x07 },534	{ 0x0343, 0x2c },535	{ 0x0340, 0x05 },536	{ 0x0341, 0x1a },537	{ 0x0344, 0x00 },538	{ 0x0345, 0x00 },539	{ 0x0346, 0x00 },540	{ 0x0347, 0x00 },541	{ 0x0348, 0x0c },542	{ 0x0349, 0xcf },543	{ 0x034a, 0x09 },544	{ 0x034b, 0x9f },545	{ 0x0220, 0x00 },546	{ 0x0222, 0x01 },547	{ 0x0900, 0x01 },548	{ 0x0901, 0x22 },549	{ 0x0902, 0x00 },550	{ 0x034c, 0x06 },551	{ 0x034d, 0x68 },552	{ 0x034e, 0x04 },553	{ 0x034f, 0xd0 },554	{ 0x0301, 0x05 },555	{ 0x0303, 0x01 },556	{ 0x0305, 0x02 },557	{ 0x0306, 0x00 },558	{ 0x0307, 0x78 },559	{ 0x030b, 0x01 },560	{ 0x030d, 0x02 },561	{ 0x030e, 0x00 },562	{ 0x030f, 0x4b },563	{ 0x0310, 0x00 },564	{ 0x0700, 0x00 },565	{ 0x0701, 0x10 },566	{ 0x0820, 0x0b },567	{ 0x0821, 0x40 },568	{ 0x3088, 0x04 },569	{ 0x6813, 0x02 },570	{ 0x6835, 0x07 },571	{ 0x6836, 0x01 },572	{ 0x6837, 0x04 },573	{ 0x684d, 0x07 },574	{ 0x684e, 0x01 },575	{ 0x684f, 0x04 },576};577 578static const struct imx355_reg mode_1640x922_regs[] = {579	{ 0x0112, 0x0a },580	{ 0x0113, 0x0a },581	{ 0x0114, 0x03 },582	{ 0x0342, 0x07 },583	{ 0x0343, 0x2c },584	{ 0x0340, 0x05 },585	{ 0x0341, 0x1a },586	{ 0x0344, 0x00 },587	{ 0x0345, 0x00 },588	{ 0x0346, 0x01 },589	{ 0x0347, 0x30 },590	{ 0x0348, 0x0c },591	{ 0x0349, 0xcf },592	{ 0x034a, 0x08 },593	{ 0x034b, 0x63 },594	{ 0x0220, 0x00 },595	{ 0x0222, 0x01 },596	{ 0x0900, 0x01 },597	{ 0x0901, 0x22 },598	{ 0x0902, 0x00 },599	{ 0x034c, 0x06 },600	{ 0x034d, 0x68 },601	{ 0x034e, 0x03 },602	{ 0x034f, 0x9a },603	{ 0x0301, 0x05 },604	{ 0x0303, 0x01 },605	{ 0x0305, 0x02 },606	{ 0x0306, 0x00 },607	{ 0x0307, 0x78 },608	{ 0x030b, 0x01 },609	{ 0x030d, 0x02 },610	{ 0x030e, 0x00 },611	{ 0x030f, 0x4b },612	{ 0x0310, 0x00 },613	{ 0x0700, 0x00 },614	{ 0x0701, 0x10 },615	{ 0x0820, 0x0b },616	{ 0x0821, 0x40 },617	{ 0x3088, 0x04 },618	{ 0x6813, 0x02 },619	{ 0x6835, 0x07 },620	{ 0x6836, 0x01 },621	{ 0x6837, 0x04 },622	{ 0x684d, 0x07 },623	{ 0x684e, 0x01 },624	{ 0x684f, 0x04 },625};626 627static const struct imx355_reg mode_1300x736_regs[] = {628	{ 0x0112, 0x0a },629	{ 0x0113, 0x0a },630	{ 0x0114, 0x03 },631	{ 0x0342, 0x07 },632	{ 0x0343, 0x2c },633	{ 0x0340, 0x05 },634	{ 0x0341, 0x1a },635	{ 0x0344, 0x01 },636	{ 0x0345, 0x58 },637	{ 0x0346, 0x01 },638	{ 0x0347, 0xf0 },639	{ 0x0348, 0x0b },640	{ 0x0349, 0x7f },641	{ 0x034a, 0x07 },642	{ 0x034b, 0xaf },643	{ 0x0220, 0x00 },644	{ 0x0222, 0x01 },645	{ 0x0900, 0x01 },646	{ 0x0901, 0x22 },647	{ 0x0902, 0x00 },648	{ 0x034c, 0x05 },649	{ 0x034d, 0x14 },650	{ 0x034e, 0x02 },651	{ 0x034f, 0xe0 },652	{ 0x0301, 0x05 },653	{ 0x0303, 0x01 },654	{ 0x0305, 0x02 },655	{ 0x0306, 0x00 },656	{ 0x0307, 0x78 },657	{ 0x030b, 0x01 },658	{ 0x030d, 0x02 },659	{ 0x030e, 0x00 },660	{ 0x030f, 0x4b },661	{ 0x0310, 0x00 },662	{ 0x0700, 0x00 },663	{ 0x0701, 0x10 },664	{ 0x0820, 0x0b },665	{ 0x0821, 0x40 },666	{ 0x3088, 0x04 },667	{ 0x6813, 0x02 },668	{ 0x6835, 0x07 },669	{ 0x6836, 0x01 },670	{ 0x6837, 0x04 },671	{ 0x684d, 0x07 },672	{ 0x684e, 0x01 },673	{ 0x684f, 0x04 },674};675 676static const struct imx355_reg mode_1296x736_regs[] = {677	{ 0x0112, 0x0a },678	{ 0x0113, 0x0a },679	{ 0x0114, 0x03 },680	{ 0x0342, 0x07 },681	{ 0x0343, 0x2c },682	{ 0x0340, 0x05 },683	{ 0x0341, 0x1a },684	{ 0x0344, 0x01 },685	{ 0x0345, 0x58 },686	{ 0x0346, 0x01 },687	{ 0x0347, 0xf0 },688	{ 0x0348, 0x0b },689	{ 0x0349, 0x77 },690	{ 0x034a, 0x07 },691	{ 0x034b, 0xaf },692	{ 0x0220, 0x00 },693	{ 0x0222, 0x01 },694	{ 0x0900, 0x01 },695	{ 0x0901, 0x22 },696	{ 0x0902, 0x00 },697	{ 0x034c, 0x05 },698	{ 0x034d, 0x10 },699	{ 0x034e, 0x02 },700	{ 0x034f, 0xe0 },701	{ 0x0301, 0x05 },702	{ 0x0303, 0x01 },703	{ 0x0305, 0x02 },704	{ 0x0306, 0x00 },705	{ 0x0307, 0x78 },706	{ 0x030b, 0x01 },707	{ 0x030d, 0x02 },708	{ 0x030e, 0x00 },709	{ 0x030f, 0x4b },710	{ 0x0310, 0x00 },711	{ 0x0700, 0x00 },712	{ 0x0701, 0x10 },713	{ 0x0820, 0x0b },714	{ 0x0821, 0x40 },715	{ 0x3088, 0x04 },716	{ 0x6813, 0x02 },717	{ 0x6835, 0x07 },718	{ 0x6836, 0x01 },719	{ 0x6837, 0x04 },720	{ 0x684d, 0x07 },721	{ 0x684e, 0x01 },722	{ 0x684f, 0x04 },723};724 725static const struct imx355_reg mode_1284x720_regs[] = {726	{ 0x0112, 0x0a },727	{ 0x0113, 0x0a },728	{ 0x0114, 0x03 },729	{ 0x0342, 0x07 },730	{ 0x0343, 0x2c },731	{ 0x0340, 0x05 },732	{ 0x0341, 0x1a },733	{ 0x0344, 0x01 },734	{ 0x0345, 0x68 },735	{ 0x0346, 0x02 },736	{ 0x0347, 0x00 },737	{ 0x0348, 0x0b },738	{ 0x0349, 0x6f },739	{ 0x034a, 0x07 },740	{ 0x034b, 0x9f },741	{ 0x0220, 0x00 },742	{ 0x0222, 0x01 },743	{ 0x0900, 0x01 },744	{ 0x0901, 0x22 },745	{ 0x0902, 0x00 },746	{ 0x034c, 0x05 },747	{ 0x034d, 0x04 },748	{ 0x034e, 0x02 },749	{ 0x034f, 0xd0 },750	{ 0x0301, 0x05 },751	{ 0x0303, 0x01 },752	{ 0x0305, 0x02 },753	{ 0x0306, 0x00 },754	{ 0x0307, 0x78 },755	{ 0x030b, 0x01 },756	{ 0x030d, 0x02 },757	{ 0x030e, 0x00 },758	{ 0x030f, 0x4b },759	{ 0x0310, 0x00 },760	{ 0x0700, 0x00 },761	{ 0x0701, 0x10 },762	{ 0x0820, 0x0b },763	{ 0x0821, 0x40 },764	{ 0x3088, 0x04 },765	{ 0x6813, 0x02 },766	{ 0x6835, 0x07 },767	{ 0x6836, 0x01 },768	{ 0x6837, 0x04 },769	{ 0x684d, 0x07 },770	{ 0x684e, 0x01 },771	{ 0x684f, 0x04 },772};773 774static const struct imx355_reg mode_1280x720_regs[] = {775	{ 0x0112, 0x0a },776	{ 0x0113, 0x0a },777	{ 0x0114, 0x03 },778	{ 0x0342, 0x07 },779	{ 0x0343, 0x2c },780	{ 0x0340, 0x05 },781	{ 0x0341, 0x1a },782	{ 0x0344, 0x01 },783	{ 0x0345, 0x68 },784	{ 0x0346, 0x02 },785	{ 0x0347, 0x00 },786	{ 0x0348, 0x0b },787	{ 0x0349, 0x67 },788	{ 0x034a, 0x07 },789	{ 0x034b, 0x9f },790	{ 0x0220, 0x00 },791	{ 0x0222, 0x01 },792	{ 0x0900, 0x01 },793	{ 0x0901, 0x22 },794	{ 0x0902, 0x00 },795	{ 0x034c, 0x05 },796	{ 0x034d, 0x00 },797	{ 0x034e, 0x02 },798	{ 0x034f, 0xd0 },799	{ 0x0301, 0x05 },800	{ 0x0303, 0x01 },801	{ 0x0305, 0x02 },802	{ 0x0306, 0x00 },803	{ 0x0307, 0x78 },804	{ 0x030b, 0x01 },805	{ 0x030d, 0x02 },806	{ 0x030e, 0x00 },807	{ 0x030f, 0x4b },808	{ 0x0310, 0x00 },809	{ 0x0700, 0x00 },810	{ 0x0701, 0x10 },811	{ 0x0820, 0x0b },812	{ 0x0821, 0x40 },813	{ 0x3088, 0x04 },814	{ 0x6813, 0x02 },815	{ 0x6835, 0x07 },816	{ 0x6836, 0x01 },817	{ 0x6837, 0x04 },818	{ 0x684d, 0x07 },819	{ 0x684e, 0x01 },820	{ 0x684f, 0x04 },821};822 823static const struct imx355_reg mode_820x616_regs[] = {824	{ 0x0112, 0x0a },825	{ 0x0113, 0x0a },826	{ 0x0114, 0x03 },827	{ 0x0342, 0x0e },828	{ 0x0343, 0x58 },829	{ 0x0340, 0x02 },830	{ 0x0341, 0x8c },831	{ 0x0344, 0x00 },832	{ 0x0345, 0x00 },833	{ 0x0346, 0x00 },834	{ 0x0347, 0x00 },835	{ 0x0348, 0x0c },836	{ 0x0349, 0xcf },837	{ 0x034a, 0x09 },838	{ 0x034b, 0x9f },839	{ 0x0220, 0x00 },840	{ 0x0222, 0x01 },841	{ 0x0900, 0x01 },842	{ 0x0901, 0x44 },843	{ 0x0902, 0x00 },844	{ 0x034c, 0x03 },845	{ 0x034d, 0x34 },846	{ 0x034e, 0x02 },847	{ 0x034f, 0x68 },848	{ 0x0301, 0x05 },849	{ 0x0303, 0x01 },850	{ 0x0305, 0x02 },851	{ 0x0306, 0x00 },852	{ 0x0307, 0x78 },853	{ 0x030b, 0x01 },854	{ 0x030d, 0x02 },855	{ 0x030e, 0x00 },856	{ 0x030f, 0x4b },857	{ 0x0310, 0x00 },858	{ 0x0700, 0x02 },859	{ 0x0701, 0x78 },860	{ 0x0820, 0x0b },861	{ 0x0821, 0x40 },862	{ 0x3088, 0x04 },863	{ 0x6813, 0x02 },864	{ 0x6835, 0x07 },865	{ 0x6836, 0x01 },866	{ 0x6837, 0x04 },867	{ 0x684d, 0x07 },868	{ 0x684e, 0x01 },869	{ 0x684f, 0x04 },870};871 872static const char * const imx355_test_pattern_menu[] = {873	"Disabled",874	"Solid Colour",875	"Eight Vertical Colour Bars",876	"Colour Bars With Fade to Grey",877	"Pseudorandom Sequence (PN9)",878};879 880/*881 * When adding more than the one below, make sure the disallowed ones will882 * actually be disabled in the LINK_FREQ control.883 */884static const s64 link_freq_menu_items[] = {885	IMX355_LINK_FREQ_DEFAULT,886};887 888/* Mode configs */889static const struct imx355_mode supported_modes[] = {890	{891		.width = 3280,892		.height = 2464,893		.fll_def = 2615,894		.fll_min = 2615,895		.llp = 3672,896		.link_freq_index = IMX355_LINK_FREQ_INDEX,897		.reg_list = {898			.num_of_regs = ARRAY_SIZE(mode_3280x2464_regs),899			.regs = mode_3280x2464_regs,900		},901	},902	{903		.width = 3268,904		.height = 2448,905		.fll_def = 2615,906		.fll_min = 2615,907		.llp = 3672,908		.link_freq_index = IMX355_LINK_FREQ_INDEX,909		.reg_list = {910			.num_of_regs = ARRAY_SIZE(mode_3268x2448_regs),911			.regs = mode_3268x2448_regs,912		},913	},914	{915		.width = 3264,916		.height = 2448,917		.fll_def = 2615,918		.fll_min = 2615,919		.llp = 3672,920		.link_freq_index = IMX355_LINK_FREQ_INDEX,921		.reg_list = {922			.num_of_regs = ARRAY_SIZE(mode_3264x2448_regs),923			.regs = mode_3264x2448_regs,924		},925	},926	{927		.width = 1940,928		.height = 1096,929		.fll_def = 1306,930		.fll_min = 1306,931		.llp = 3672,932		.link_freq_index = IMX355_LINK_FREQ_INDEX,933		.reg_list = {934			.num_of_regs = ARRAY_SIZE(mode_1940x1096_regs),935			.regs = mode_1940x1096_regs,936		},937	},938	{939		.width = 1936,940		.height = 1096,941		.fll_def = 1306,942		.fll_min = 1306,943		.llp = 3672,944		.link_freq_index = IMX355_LINK_FREQ_INDEX,945		.reg_list = {946			.num_of_regs = ARRAY_SIZE(mode_1936x1096_regs),947			.regs = mode_1936x1096_regs,948		},949	},950	{951		.width = 1924,952		.height = 1080,953		.fll_def = 1306,954		.fll_min = 1306,955		.llp = 3672,956		.link_freq_index = IMX355_LINK_FREQ_INDEX,957		.reg_list = {958			.num_of_regs = ARRAY_SIZE(mode_1924x1080_regs),959			.regs = mode_1924x1080_regs,960		},961	},962	{963		.width = 1920,964		.height = 1080,965		.fll_def = 1306,966		.fll_min = 1306,967		.llp = 3672,968		.link_freq_index = IMX355_LINK_FREQ_INDEX,969		.reg_list = {970			.num_of_regs = ARRAY_SIZE(mode_1920x1080_regs),971			.regs = mode_1920x1080_regs,972		},973	},974	{975		.width = 1640,976		.height = 1232,977		.fll_def = 1306,978		.fll_min = 1306,979		.llp = 1836,980		.link_freq_index = IMX355_LINK_FREQ_INDEX,981		.reg_list = {982			.num_of_regs = ARRAY_SIZE(mode_1640x1232_regs),983			.regs = mode_1640x1232_regs,984		},985	},986	{987		.width = 1640,988		.height = 922,989		.fll_def = 1306,990		.fll_min = 1306,991		.llp = 1836,992		.link_freq_index = IMX355_LINK_FREQ_INDEX,993		.reg_list = {994			.num_of_regs = ARRAY_SIZE(mode_1640x922_regs),995			.regs = mode_1640x922_regs,996		},997	},998	{999		.width = 1300,1000		.height = 736,1001		.fll_def = 1306,1002		.fll_min = 1306,1003		.llp = 1836,1004		.link_freq_index = IMX355_LINK_FREQ_INDEX,1005		.reg_list = {1006			.num_of_regs = ARRAY_SIZE(mode_1300x736_regs),1007			.regs = mode_1300x736_regs,1008		},1009	},1010	{1011		.width = 1296,1012		.height = 736,1013		.fll_def = 1306,1014		.fll_min = 1306,1015		.llp = 1836,1016		.link_freq_index = IMX355_LINK_FREQ_INDEX,1017		.reg_list = {1018			.num_of_regs = ARRAY_SIZE(mode_1296x736_regs),1019			.regs = mode_1296x736_regs,1020		},1021	},1022	{1023		.width = 1284,1024		.height = 720,1025		.fll_def = 1306,1026		.fll_min = 1306,1027		.llp = 1836,1028		.link_freq_index = IMX355_LINK_FREQ_INDEX,1029		.reg_list = {1030			.num_of_regs = ARRAY_SIZE(mode_1284x720_regs),1031			.regs = mode_1284x720_regs,1032		},1033	},1034	{1035		.width = 1280,1036		.height = 720,1037		.fll_def = 1306,1038		.fll_min = 1306,1039		.llp = 1836,1040		.link_freq_index = IMX355_LINK_FREQ_INDEX,1041		.reg_list = {1042			.num_of_regs = ARRAY_SIZE(mode_1280x720_regs),1043			.regs = mode_1280x720_regs,1044		},1045	},1046	{1047		.width = 820,1048		.height = 616,1049		.fll_def = 652,1050		.fll_min = 652,1051		.llp = 3672,1052		.link_freq_index = IMX355_LINK_FREQ_INDEX,1053		.reg_list = {1054			.num_of_regs = ARRAY_SIZE(mode_820x616_regs),1055			.regs = mode_820x616_regs,1056		},1057	},1058};1059 1060static inline struct imx355 *to_imx355(struct v4l2_subdev *_sd)1061{1062	return container_of(_sd, struct imx355, sd);1063}1064 1065/* Get bayer order based on flip setting. */1066static u32 imx355_get_format_code(struct imx355 *imx355)1067{1068	/*1069	 * Only one bayer order is supported.1070	 * It depends on the flip settings.1071	 */1072	u32 code;1073	static const u32 codes[2][2] = {1074		{ MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10, },1075		{ MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10, },1076	};1077 1078	lockdep_assert_held(&imx355->mutex);1079	code = codes[imx355->vflip->val][imx355->hflip->val];1080 1081	return code;1082}1083 1084/* Read registers up to 4 at a time */1085static int imx355_read_reg(struct imx355 *imx355, u16 reg, u32 len, u32 *val)1086{1087	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);1088	struct i2c_msg msgs[2];1089	u8 addr_buf[2];1090	u8 data_buf[4] = { 0 };1091	int ret;1092 1093	if (len > 4)1094		return -EINVAL;1095 1096	put_unaligned_be16(reg, addr_buf);1097	/* Write register address */1098	msgs[0].addr = client->addr;1099	msgs[0].flags = 0;1100	msgs[0].len = ARRAY_SIZE(addr_buf);1101	msgs[0].buf = addr_buf;1102 1103	/* Read data from register */1104	msgs[1].addr = client->addr;1105	msgs[1].flags = I2C_M_RD;1106	msgs[1].len = len;1107	msgs[1].buf = &data_buf[4 - len];1108 1109	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));1110	if (ret != ARRAY_SIZE(msgs))1111		return -EIO;1112 1113	*val = get_unaligned_be32(data_buf);1114 1115	return 0;1116}1117 1118/* Write registers up to 4 at a time */1119static int imx355_write_reg(struct imx355 *imx355, u16 reg, u32 len, u32 val)1120{1121	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);1122	u8 buf[6];1123 1124	if (len > 4)1125		return -EINVAL;1126 1127	put_unaligned_be16(reg, buf);1128	put_unaligned_be32(val << (8 * (4 - len)), buf + 2);1129	if (i2c_master_send(client, buf, len + 2) != len + 2)1130		return -EIO;1131 1132	return 0;1133}1134 1135/* Write a list of registers */1136static int imx355_write_regs(struct imx355 *imx355,1137			     const struct imx355_reg *regs, u32 len)1138{1139	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);1140	int ret;1141	u32 i;1142 1143	for (i = 0; i < len; i++) {1144		ret = imx355_write_reg(imx355, regs[i].address, 1, regs[i].val);1145		if (ret) {1146			dev_err_ratelimited(&client->dev,1147					    "write reg 0x%4.4x return err %d",1148					    regs[i].address, ret);1149 1150			return ret;1151		}1152	}1153 1154	return 0;1155}1156 1157/* Open sub-device */1158static int imx355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)1159{1160	struct imx355 *imx355 = to_imx355(sd);1161	struct v4l2_mbus_framefmt *try_fmt =1162		v4l2_subdev_state_get_format(fh->state, 0);1163 1164	mutex_lock(&imx355->mutex);1165 1166	/* Initialize try_fmt */1167	try_fmt->width = imx355->cur_mode->width;1168	try_fmt->height = imx355->cur_mode->height;1169	try_fmt->code = imx355_get_format_code(imx355);1170	try_fmt->field = V4L2_FIELD_NONE;1171 1172	mutex_unlock(&imx355->mutex);1173 1174	return 0;1175}1176 1177static int imx355_set_ctrl(struct v4l2_ctrl *ctrl)1178{1179	struct imx355 *imx355 = container_of(ctrl->handler,1180					     struct imx355, ctrl_handler);1181	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);1182	s64 max;1183	int ret;1184 1185	/* Propagate change of current control to all related controls */1186	switch (ctrl->id) {1187	case V4L2_CID_VBLANK:1188		/* Update max exposure while meeting expected vblanking */1189		max = imx355->cur_mode->height + ctrl->val - 10;1190		__v4l2_ctrl_modify_range(imx355->exposure,1191					 imx355->exposure->minimum,1192					 max, imx355->exposure->step, max);1193		break;1194	}1195 1196	/*1197	 * Applying V4L2 control value only happens1198	 * when power is up for streaming1199	 */1200	if (!pm_runtime_get_if_in_use(&client->dev))1201		return 0;1202 1203	switch (ctrl->id) {1204	case V4L2_CID_ANALOGUE_GAIN:1205		/* Analog gain = 1024/(1024 - ctrl->val) times */1206		ret = imx355_write_reg(imx355, IMX355_REG_ANALOG_GAIN, 2,1207				       ctrl->val);1208		break;1209	case V4L2_CID_DIGITAL_GAIN:1210		ret = imx355_write_reg(imx355, IMX355_REG_DIG_GAIN_GLOBAL, 2,1211				       ctrl->val);1212		break;1213	case V4L2_CID_EXPOSURE:1214		ret = imx355_write_reg(imx355, IMX355_REG_EXPOSURE, 2,1215				       ctrl->val);1216		break;1217	case V4L2_CID_VBLANK:1218		/* Update FLL that meets expected vertical blanking */1219		ret = imx355_write_reg(imx355, IMX355_REG_FLL, 2,1220				       imx355->cur_mode->height + ctrl->val);1221		break;1222	case V4L2_CID_TEST_PATTERN:1223		ret = imx355_write_reg(imx355, IMX355_REG_TEST_PATTERN,1224				       2, ctrl->val);1225		break;1226	case V4L2_CID_HFLIP:1227	case V4L2_CID_VFLIP:1228		ret = imx355_write_reg(imx355, IMX355_REG_ORIENTATION, 1,1229				       imx355->hflip->val |1230				       imx355->vflip->val << 1);1231		break;1232	default:1233		ret = -EINVAL;1234		dev_info(&client->dev, "ctrl(id:0x%x,val:0x%x) is not handled",1235			 ctrl->id, ctrl->val);1236		break;1237	}1238 1239	pm_runtime_put(&client->dev);1240 1241	return ret;1242}1243 1244static const struct v4l2_ctrl_ops imx355_ctrl_ops = {1245	.s_ctrl = imx355_set_ctrl,1246};1247 1248static int imx355_enum_mbus_code(struct v4l2_subdev *sd,1249				 struct v4l2_subdev_state *sd_state,1250				 struct v4l2_subdev_mbus_code_enum *code)1251{1252	struct imx355 *imx355 = to_imx355(sd);1253 1254	if (code->index > 0)1255		return -EINVAL;1256 1257	mutex_lock(&imx355->mutex);1258	code->code = imx355_get_format_code(imx355);1259	mutex_unlock(&imx355->mutex);1260 1261	return 0;1262}1263 1264static int imx355_enum_frame_size(struct v4l2_subdev *sd,1265				  struct v4l2_subdev_state *sd_state,1266				  struct v4l2_subdev_frame_size_enum *fse)1267{1268	struct imx355 *imx355 = to_imx355(sd);1269 1270	if (fse->index >= ARRAY_SIZE(supported_modes))1271		return -EINVAL;1272 1273	mutex_lock(&imx355->mutex);1274	if (fse->code != imx355_get_format_code(imx355)) {1275		mutex_unlock(&imx355->mutex);1276		return -EINVAL;1277	}1278	mutex_unlock(&imx355->mutex);1279 1280	fse->min_width = supported_modes[fse->index].width;1281	fse->max_width = fse->min_width;1282	fse->min_height = supported_modes[fse->index].height;1283	fse->max_height = fse->min_height;1284 1285	return 0;1286}1287 1288static void imx355_update_pad_format(struct imx355 *imx355,1289				     const struct imx355_mode *mode,1290				     struct v4l2_subdev_format *fmt)1291{1292	fmt->format.width = mode->width;1293	fmt->format.height = mode->height;1294	fmt->format.code = imx355_get_format_code(imx355);1295	fmt->format.field = V4L2_FIELD_NONE;1296}1297 1298static int imx355_do_get_pad_format(struct imx355 *imx355,1299				    struct v4l2_subdev_state *sd_state,1300				    struct v4l2_subdev_format *fmt)1301{1302	struct v4l2_mbus_framefmt *framefmt;1303 1304	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {1305		framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);1306		fmt->format = *framefmt;1307	} else {1308		imx355_update_pad_format(imx355, imx355->cur_mode, fmt);1309	}1310 1311	return 0;1312}1313 1314static int imx355_get_pad_format(struct v4l2_subdev *sd,1315				 struct v4l2_subdev_state *sd_state,1316				 struct v4l2_subdev_format *fmt)1317{1318	struct imx355 *imx355 = to_imx355(sd);1319	int ret;1320 1321	mutex_lock(&imx355->mutex);1322	ret = imx355_do_get_pad_format(imx355, sd_state, fmt);1323	mutex_unlock(&imx355->mutex);1324 1325	return ret;1326}1327 1328static int1329imx355_set_pad_format(struct v4l2_subdev *sd,1330		      struct v4l2_subdev_state *sd_state,1331		      struct v4l2_subdev_format *fmt)1332{1333	struct imx355 *imx355 = to_imx355(sd);1334	const struct imx355_mode *mode;1335	struct v4l2_mbus_framefmt *framefmt;1336	s32 vblank_def;1337	s32 vblank_min;1338	s64 h_blank;1339	u64 pixel_rate;1340	u32 height;1341 1342	mutex_lock(&imx355->mutex);1343 1344	/*1345	 * Only one bayer order is supported.1346	 * It depends on the flip settings.1347	 */1348	fmt->format.code = imx355_get_format_code(imx355);1349 1350	mode = v4l2_find_nearest_size(supported_modes,1351				      ARRAY_SIZE(supported_modes),1352				      width, height,1353				      fmt->format.width, fmt->format.height);1354	imx355_update_pad_format(imx355, mode, fmt);1355	if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {1356		framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);1357		*framefmt = fmt->format;1358	} else {1359		imx355->cur_mode = mode;1360		pixel_rate = IMX355_LINK_FREQ_DEFAULT * 2 * 4;1361		do_div(pixel_rate, 10);1362		__v4l2_ctrl_s_ctrl_int64(imx355->pixel_rate, pixel_rate);1363		/* Update limits and set FPS to default */1364		height = imx355->cur_mode->height;1365		vblank_def = imx355->cur_mode->fll_def - height;1366		vblank_min = imx355->cur_mode->fll_min - height;1367		height = IMX355_FLL_MAX - height;1368		__v4l2_ctrl_modify_range(imx355->vblank, vblank_min, height, 1,1369					 vblank_def);1370		__v4l2_ctrl_s_ctrl(imx355->vblank, vblank_def);1371		h_blank = mode->llp - imx355->cur_mode->width;1372		/*1373		 * Currently hblank is not changeable.1374		 * So FPS control is done only by vblank.1375		 */1376		__v4l2_ctrl_modify_range(imx355->hblank, h_blank,1377					 h_blank, 1, h_blank);1378	}1379 1380	mutex_unlock(&imx355->mutex);1381 1382	return 0;1383}1384 1385/* Start streaming */1386static int imx355_start_streaming(struct imx355 *imx355)1387{1388	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);1389	const struct imx355_reg_list *reg_list;1390	int ret;1391 1392	/* Global Setting */1393	reg_list = &imx355_global_setting;1394	ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs);1395	if (ret) {1396		dev_err(&client->dev, "failed to set global settings");1397		return ret;1398	}1399 1400	/* Apply default values of current mode */1401	reg_list = &imx355->cur_mode->reg_list;1402	ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs);1403	if (ret) {1404		dev_err(&client->dev, "failed to set mode");1405		return ret;1406	}1407 1408	/* set digital gain control to all color mode */1409	ret = imx355_write_reg(imx355, IMX355_REG_DPGA_USE_GLOBAL_GAIN, 1, 1);1410	if (ret)1411		return ret;1412 1413	/* Apply customized values from user */1414	ret =  __v4l2_ctrl_handler_setup(imx355->sd.ctrl_handler);1415	if (ret)1416		return ret;1417 1418	return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT,1419				1, IMX355_MODE_STREAMING);1420}1421 1422/* Stop streaming */1423static int imx355_stop_streaming(struct imx355 *imx355)1424{1425	return imx355_write_reg(imx355, IMX355_REG_MODE_SELECT,1426				1, IMX355_MODE_STANDBY);1427}1428 1429static int imx355_set_stream(struct v4l2_subdev *sd, int enable)1430{1431	struct imx355 *imx355 = to_imx355(sd);1432	struct i2c_client *client = v4l2_get_subdevdata(sd);1433	int ret = 0;1434 1435	mutex_lock(&imx355->mutex);1436 1437	if (enable) {1438		ret = pm_runtime_resume_and_get(&client->dev);1439		if (ret < 0)1440			goto err_unlock;1441 1442		/*1443		 * Apply default & customized values1444		 * and then start streaming.1445		 */1446		ret = imx355_start_streaming(imx355);1447		if (ret)1448			goto err_rpm_put;1449	} else {1450		imx355_stop_streaming(imx355);1451		pm_runtime_put(&client->dev);1452	}1453 1454	/* vflip and hflip cannot change during streaming */1455	__v4l2_ctrl_grab(imx355->vflip, enable);1456	__v4l2_ctrl_grab(imx355->hflip, enable);1457 1458	mutex_unlock(&imx355->mutex);1459 1460	return ret;1461 1462err_rpm_put:1463	pm_runtime_put(&client->dev);1464err_unlock:1465	mutex_unlock(&imx355->mutex);1466 1467	return ret;1468}1469 1470/* Verify chip ID */1471static int imx355_identify_module(struct imx355 *imx355)1472{1473	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);1474	int ret;1475	u32 val;1476 1477	ret = imx355_read_reg(imx355, IMX355_REG_CHIP_ID, 2, &val);1478	if (ret)1479		return ret;1480 1481	if (val != IMX355_CHIP_ID) {1482		dev_err(&client->dev, "chip id mismatch: %x!=%x",1483			IMX355_CHIP_ID, val);1484		return -EIO;1485	}1486	return 0;1487}1488 1489static const struct v4l2_subdev_core_ops imx355_subdev_core_ops = {1490	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,1491	.unsubscribe_event = v4l2_event_subdev_unsubscribe,1492};1493 1494static const struct v4l2_subdev_video_ops imx355_video_ops = {1495	.s_stream = imx355_set_stream,1496};1497 1498static const struct v4l2_subdev_pad_ops imx355_pad_ops = {1499	.enum_mbus_code = imx355_enum_mbus_code,1500	.get_fmt = imx355_get_pad_format,1501	.set_fmt = imx355_set_pad_format,1502	.enum_frame_size = imx355_enum_frame_size,1503};1504 1505static const struct v4l2_subdev_ops imx355_subdev_ops = {1506	.core = &imx355_subdev_core_ops,1507	.video = &imx355_video_ops,1508	.pad = &imx355_pad_ops,1509};1510 1511static const struct media_entity_operations imx355_subdev_entity_ops = {1512	.link_validate = v4l2_subdev_link_validate,1513};1514 1515static const struct v4l2_subdev_internal_ops imx355_internal_ops = {1516	.open = imx355_open,1517};1518 1519/* Initialize control handlers */1520static int imx355_init_controls(struct imx355 *imx355)1521{1522	struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd);1523	struct v4l2_fwnode_device_properties props;1524	struct v4l2_ctrl_handler *ctrl_hdlr;1525	s64 exposure_max;1526	s64 vblank_def;1527	s64 vblank_min;1528	s64 hblank;1529	u64 pixel_rate;1530	const struct imx355_mode *mode;1531	u32 max;1532	int ret;1533 1534	ctrl_hdlr = &imx355->ctrl_handler;1535	ret = v4l2_ctrl_handler_init(ctrl_hdlr, 12);1536	if (ret)1537		return ret;1538 1539	ctrl_hdlr->lock = &imx355->mutex;1540	max = ARRAY_SIZE(link_freq_menu_items) - 1;1541	imx355->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx355_ctrl_ops,1542						   V4L2_CID_LINK_FREQ, max, 0,1543						   link_freq_menu_items);1544	if (imx355->link_freq)1545		imx355->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;1546 1547	/* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */1548	pixel_rate = IMX355_LINK_FREQ_DEFAULT * 2 * 4;1549	do_div(pixel_rate, 10);1550	/* By default, PIXEL_RATE is read only */1551	imx355->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,1552					       V4L2_CID_PIXEL_RATE, pixel_rate,1553					       pixel_rate, 1, pixel_rate);1554 1555	/* Initialize vblank/hblank/exposure parameters based on current mode */1556	mode = imx355->cur_mode;1557	vblank_def = mode->fll_def - mode->height;1558	vblank_min = mode->fll_min - mode->height;1559	imx355->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,1560					   V4L2_CID_VBLANK, vblank_min,1561					   IMX355_FLL_MAX - mode->height,1562					   1, vblank_def);1563 1564	hblank = mode->llp - mode->width;1565	imx355->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,1566					   V4L2_CID_HBLANK, hblank, hblank,1567					   1, hblank);1568	if (imx355->hblank)1569		imx355->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;1570 1571	/* fll >= exposure time + adjust parameter (default value is 10) */1572	exposure_max = mode->fll_def - 10;1573	imx355->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,1574					     V4L2_CID_EXPOSURE,1575					     IMX355_EXPOSURE_MIN, exposure_max,1576					     IMX355_EXPOSURE_STEP,1577					     IMX355_EXPOSURE_DEFAULT);1578 1579	imx355->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,1580					  V4L2_CID_HFLIP, 0, 1, 1, 0);1581	if (imx355->hflip)1582		imx355->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;1583	imx355->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops,1584					  V4L2_CID_VFLIP, 0, 1, 1, 0);1585	if (imx355->vflip)1586		imx355->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;1587 1588	v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,1589			  IMX355_ANA_GAIN_MIN, IMX355_ANA_GAIN_MAX,1590			  IMX355_ANA_GAIN_STEP, IMX355_ANA_GAIN_DEFAULT);1591 1592	/* Digital gain */1593	v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, V4L2_CID_DIGITAL_GAIN,1594			  IMX355_DGTL_GAIN_MIN, IMX355_DGTL_GAIN_MAX,1595			  IMX355_DGTL_GAIN_STEP, IMX355_DGTL_GAIN_DEFAULT);1596 1597	v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx355_ctrl_ops,1598				     V4L2_CID_TEST_PATTERN,1599				     ARRAY_SIZE(imx355_test_pattern_menu) - 1,1600				     0, 0, imx355_test_pattern_menu);1601	if (ctrl_hdlr->error) {1602		ret = ctrl_hdlr->error;1603		dev_err(&client->dev, "control init failed: %d", ret);1604		goto error;1605	}1606 1607	ret = v4l2_fwnode_device_parse(&client->dev, &props);1608	if (ret)1609		goto error;1610 1611	ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx355_ctrl_ops,1612					      &props);1613	if (ret)1614		goto error;1615 1616	imx355->sd.ctrl_handler = ctrl_hdlr;1617 1618	return 0;1619 1620error:1621	v4l2_ctrl_handler_free(ctrl_hdlr);1622 1623	return ret;1624}1625 1626static struct imx355_hwcfg *imx355_get_hwcfg(struct device *dev)1627{1628	struct imx355_hwcfg *cfg;1629	struct v4l2_fwnode_endpoint bus_cfg = {1630		.bus_type = V4L2_MBUS_CSI2_DPHY1631	};1632	struct fwnode_handle *ep;1633	struct fwnode_handle *fwnode = dev_fwnode(dev);1634	int ret;1635 1636	if (!fwnode)1637		return NULL;1638 1639	ep = fwnode_graph_get_next_endpoint(fwnode, NULL);1640	if (!ep)1641		return NULL;1642 1643	ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);1644	if (ret)1645		goto out_err;1646 1647	cfg = devm_kzalloc(dev, sizeof(*cfg), GFP_KERNEL);1648	if (!cfg)1649		goto out_err;1650 1651	ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",1652				       &cfg->ext_clk);1653	if (ret) {1654		dev_err(dev, "can't get clock frequency");1655		goto out_err;1656	}1657 1658	dev_dbg(dev, "ext clk: %d", cfg->ext_clk);1659	if (cfg->ext_clk != IMX355_EXT_CLK) {1660		dev_err(dev, "external clock %d is not supported",1661			cfg->ext_clk);1662		goto out_err;1663	}1664 1665	ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies,1666				       bus_cfg.nr_of_link_frequencies,1667				       link_freq_menu_items,1668				       ARRAY_SIZE(link_freq_menu_items),1669				       &cfg->link_freq_bitmap);1670	if (ret)1671		goto out_err;1672 1673	v4l2_fwnode_endpoint_free(&bus_cfg);1674	fwnode_handle_put(ep);1675	return cfg;1676 1677out_err:1678	v4l2_fwnode_endpoint_free(&bus_cfg);1679	fwnode_handle_put(ep);1680	return NULL;1681}1682 1683static int imx355_probe(struct i2c_client *client)1684{1685	struct imx355 *imx355;1686	int ret;1687 1688	imx355 = devm_kzalloc(&client->dev, sizeof(*imx355), GFP_KERNEL);1689	if (!imx355)1690		return -ENOMEM;1691 1692	mutex_init(&imx355->mutex);1693 1694	/* Initialize subdev */1695	v4l2_i2c_subdev_init(&imx355->sd, client, &imx355_subdev_ops);1696 1697	/* Check module identity */1698	ret = imx355_identify_module(imx355);1699	if (ret) {1700		dev_err(&client->dev, "failed to find sensor: %d", ret);1701		goto error_probe;1702	}1703 1704	imx355->hwcfg = imx355_get_hwcfg(&client->dev);1705	if (!imx355->hwcfg) {1706		dev_err(&client->dev, "failed to get hwcfg");1707		ret = -ENODEV;1708		goto error_probe;1709	}1710 1711	/* Set default mode to max resolution */1712	imx355->cur_mode = &supported_modes[0];1713 1714	ret = imx355_init_controls(imx355);1715	if (ret) {1716		dev_err(&client->dev, "failed to init controls: %d", ret);1717		goto error_probe;1718	}1719 1720	/* Initialize subdev */1721	imx355->sd.internal_ops = &imx355_internal_ops;1722	imx355->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |1723		V4L2_SUBDEV_FL_HAS_EVENTS;1724	imx355->sd.entity.ops = &imx355_subdev_entity_ops;1725	imx355->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;1726 1727	/* Initialize source pad */1728	imx355->pad.flags = MEDIA_PAD_FL_SOURCE;1729	ret = media_entity_pads_init(&imx355->sd.entity, 1, &imx355->pad);1730	if (ret) {1731		dev_err(&client->dev, "failed to init entity pads: %d", ret);1732		goto error_handler_free;1733	}1734 1735	/*1736	 * Device is already turned on by i2c-core with ACPI domain PM.1737	 * Enable runtime PM and turn off the device.1738	 */1739	pm_runtime_set_active(&client->dev);1740	pm_runtime_enable(&client->dev);1741	pm_runtime_idle(&client->dev);1742 1743	ret = v4l2_async_register_subdev_sensor(&imx355->sd);1744	if (ret < 0)1745		goto error_media_entity_runtime_pm;1746 1747	return 0;1748 1749error_media_entity_runtime_pm:1750	pm_runtime_disable(&client->dev);1751	pm_runtime_set_suspended(&client->dev);1752	media_entity_cleanup(&imx355->sd.entity);1753 1754error_handler_free:1755	v4l2_ctrl_handler_free(imx355->sd.ctrl_handler);1756 1757error_probe:1758	mutex_destroy(&imx355->mutex);1759 1760	return ret;1761}1762 1763static void imx355_remove(struct i2c_client *client)1764{1765	struct v4l2_subdev *sd = i2c_get_clientdata(client);1766	struct imx355 *imx355 = to_imx355(sd);1767 1768	v4l2_async_unregister_subdev(sd);1769	media_entity_cleanup(&sd->entity);1770	v4l2_ctrl_handler_free(sd->ctrl_handler);1771 1772	pm_runtime_disable(&client->dev);1773	pm_runtime_set_suspended(&client->dev);1774 1775	mutex_destroy(&imx355->mutex);1776}1777 1778static const struct acpi_device_id imx355_acpi_ids[] __maybe_unused = {1779	{ "SONY355A" },1780	{ /* sentinel */ }1781};1782MODULE_DEVICE_TABLE(acpi, imx355_acpi_ids);1783 1784static struct i2c_driver imx355_i2c_driver = {1785	.driver = {1786		.name = "imx355",1787		.acpi_match_table = ACPI_PTR(imx355_acpi_ids),1788	},1789	.probe = imx355_probe,1790	.remove = imx355_remove,1791};1792module_i2c_driver(imx355_i2c_driver);1793 1794MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu@intel.com>");1795MODULE_AUTHOR("Rapolu, Chiranjeevi");1796MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>");1797MODULE_AUTHOR("Yang, Hyungwoo");1798MODULE_DESCRIPTION("Sony imx355 sensor driver");1799MODULE_LICENSE("GPL v2");1800