1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Support for GalaxyCore GC0310 VGA camera sensor.
4  *
5  * Copyright (c) 2013 Intel Corporation. All Rights Reserved.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License version
9  * 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  */
17 
18 #include <linux/module.h>
19 #include <linux/types.h>
20 #include <linux/kernel.h>
21 #include <linux/mm.h>
22 #include <linux/string.h>
23 #include <linux/errno.h>
24 #include <linux/init.h>
25 #include <linux/kmod.h>
26 #include <linux/device.h>
27 #include <linux/delay.h>
28 #include <linux/slab.h>
29 #include <linux/i2c.h>
30 #include <linux/moduleparam.h>
31 #include <media/v4l2-device.h>
32 #include <linux/io.h>
33 #include "../include/linux/atomisp_gmin_platform.h"
34 
35 #include "gc0310.h"
36 
37 /*
38  * gc0310_write_reg_array - Initializes a list of GC0310 registers
39  * @client: i2c driver client structure
40  * @reglist: list of registers to be written
41  * @count: number of register, value pairs in the list
42  */
43 static int gc0310_write_reg_array(struct i2c_client *client,
44 				  const struct gc0310_reg *reglist, int count)
45 {
46 	int i, err;
47 
48 	for (i = 0; i < count; i++) {
49 		err = i2c_smbus_write_byte_data(client, reglist[i].reg, reglist[i].val);
50 		if (err) {
51 			dev_err(&client->dev, "write error: wrote 0x%x to offset 0x%x error %d",
52 				reglist[i].val, reglist[i].reg, err);
53 			return err;
54 		}
55 	}
56 
57 	return 0;
58 }
59 
60 static int gc0310_exposure_set(struct gc0310_device *dev, u32 exp)
61 {
62 	struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
63 
64 	return i2c_smbus_write_word_swapped(client, GC0310_AEC_PK_EXPO_H, exp);
65 }
66 
67 static int gc0310_gain_set(struct gc0310_device *dev, u32 gain)
68 {
69 	struct i2c_client *client = v4l2_get_subdevdata(&dev->sd);
70 	u8 again, dgain;
71 	int ret;
72 
73 	/* Taken from original driver, this never sets dgain lower then 32? */
74 
75 	/* Change 0 - 95 to 32 - 127 */
76 	gain += 32;
77 
78 	if (gain < 64) {
79 		again = 0x0; /* sqrt(2) */
80 		dgain = gain;
81 	} else {
82 		again = 0x2; /* 2 * sqrt(2) */
83 		dgain = gain / 2;
84 	}
85 
86 	ret = i2c_smbus_write_byte_data(client, GC0310_AGC_ADJ, again);
87 	if (ret)
88 		return ret;
89 
90 	return i2c_smbus_write_byte_data(client, GC0310_DGC_ADJ, dgain);
91 }
92 
93 static int gc0310_s_ctrl(struct v4l2_ctrl *ctrl)
94 {
95 	struct gc0310_device *dev =
96 		container_of(ctrl->handler, struct gc0310_device, ctrls.handler);
97 	int ret;
98 
99 	if (!dev->power_on)
100 		return 0;
101 
102 	switch (ctrl->id) {
103 	case V4L2_CID_EXPOSURE:
104 		ret = gc0310_exposure_set(dev, ctrl->val);
105 		break;
106 	case V4L2_CID_GAIN:
107 		ret = gc0310_gain_set(dev, ctrl->val);
108 		break;
109 	default:
110 		ret = -EINVAL;
111 		break;
112 	}
113 
114 	return ret;
115 }
116 
117 static const struct v4l2_ctrl_ops ctrl_ops = {
118 	.s_ctrl = gc0310_s_ctrl,
119 };
120 
121 static int gc0310_init(struct v4l2_subdev *sd)
122 {
123 	int ret;
124 	struct i2c_client *client = v4l2_get_subdevdata(sd);
125 	struct gc0310_device *dev = to_gc0310_sensor(sd);
126 
127 	mutex_lock(&dev->input_lock);
128 
129 	/* set initial registers */
130 	ret = gc0310_write_reg_array(client, gc0310_reset_register,
131 				     ARRAY_SIZE(gc0310_reset_register));
132 	if (ret)
133 		goto out_unlock;
134 
135 	/* restore settings */
136 	gc0310_res = gc0310_res_preview;
137 	N_RES = N_RES_PREVIEW;
138 
139 	/* restore value of all ctrls */
140 	ret = __v4l2_ctrl_handler_setup(&dev->ctrls.handler);
141 
142 out_unlock:
143 	mutex_unlock(&dev->input_lock);
144 	return ret;
145 }
146 
147 static int power_ctrl(struct v4l2_subdev *sd, bool flag)
148 {
149 	int ret = 0;
150 	struct gc0310_device *dev = to_gc0310_sensor(sd);
151 
152 	if (!dev || !dev->platform_data)
153 		return -ENODEV;
154 
155 	if (flag) {
156 		/* The upstream module driver (written to Crystal
157 		 * Cove) had this logic to pulse the rails low first.
158 		 * This appears to break things on the MRD7 with the
159 		 * X-Powers PMIC...
160 		 *
161 		 *     ret = dev->platform_data->v1p8_ctrl(sd, 0);
162 		 *     ret |= dev->platform_data->v2p8_ctrl(sd, 0);
163 		 *     mdelay(50);
164 		 */
165 		ret |= dev->platform_data->v1p8_ctrl(sd, 1);
166 		ret |= dev->platform_data->v2p8_ctrl(sd, 1);
167 		usleep_range(10000, 15000);
168 	}
169 
170 	if (!flag || ret) {
171 		ret |= dev->platform_data->v1p8_ctrl(sd, 0);
172 		ret |= dev->platform_data->v2p8_ctrl(sd, 0);
173 	}
174 	return ret;
175 }
176 
177 static int gpio_ctrl(struct v4l2_subdev *sd, bool flag)
178 {
179 	int ret;
180 	struct gc0310_device *dev = to_gc0310_sensor(sd);
181 
182 	if (!dev || !dev->platform_data)
183 		return -ENODEV;
184 
185 	/* GPIO0 == "reset" (active low), GPIO1 == "power down" */
186 	if (flag) {
187 		/* Pulse reset, then release power down */
188 		ret = dev->platform_data->gpio0_ctrl(sd, 0);
189 		usleep_range(5000, 10000);
190 		ret |= dev->platform_data->gpio0_ctrl(sd, 1);
191 		usleep_range(10000, 15000);
192 		ret |= dev->platform_data->gpio1_ctrl(sd, 0);
193 		usleep_range(10000, 15000);
194 	} else {
195 		ret = dev->platform_data->gpio1_ctrl(sd, 1);
196 		ret |= dev->platform_data->gpio0_ctrl(sd, 0);
197 	}
198 	return ret;
199 }
200 
201 static int power_up(struct v4l2_subdev *sd)
202 {
203 	struct gc0310_device *dev = to_gc0310_sensor(sd);
204 	struct i2c_client *client = v4l2_get_subdevdata(sd);
205 	int ret;
206 
207 	if (!dev->platform_data) {
208 		dev_err(&client->dev,
209 			"no camera_sensor_platform_data");
210 		return -ENODEV;
211 	}
212 
213 	if (dev->power_on)
214 		return 0; /* Already on */
215 
216 	/* power control */
217 	ret = power_ctrl(sd, 1);
218 	if (ret)
219 		goto fail_power;
220 
221 	/* flis clock control */
222 	ret = dev->platform_data->flisclk_ctrl(sd, 1);
223 	if (ret)
224 		goto fail_clk;
225 
226 	/* gpio ctrl */
227 	ret = gpio_ctrl(sd, 1);
228 	if (ret) {
229 		ret = gpio_ctrl(sd, 1);
230 		if (ret)
231 			goto fail_gpio;
232 	}
233 
234 	msleep(100);
235 
236 	dev->power_on = true;
237 	return 0;
238 
239 fail_gpio:
240 	dev->platform_data->flisclk_ctrl(sd, 0);
241 fail_clk:
242 	power_ctrl(sd, 0);
243 fail_power:
244 	dev_err(&client->dev, "sensor power-up failed\n");
245 
246 	return ret;
247 }
248 
249 static int power_down(struct v4l2_subdev *sd)
250 {
251 	struct gc0310_device *dev = to_gc0310_sensor(sd);
252 	struct i2c_client *client = v4l2_get_subdevdata(sd);
253 	int ret = 0;
254 
255 	if (!dev->platform_data) {
256 		dev_err(&client->dev,
257 			"no camera_sensor_platform_data");
258 		return -ENODEV;
259 	}
260 
261 	if (!dev->power_on)
262 		return 0; /* Already off */
263 
264 	/* gpio ctrl */
265 	ret = gpio_ctrl(sd, 0);
266 	if (ret) {
267 		ret = gpio_ctrl(sd, 0);
268 		if (ret)
269 			dev_err(&client->dev, "gpio failed 2\n");
270 	}
271 
272 	ret = dev->platform_data->flisclk_ctrl(sd, 0);
273 	if (ret)
274 		dev_err(&client->dev, "flisclk failed\n");
275 
276 	/* power control */
277 	ret = power_ctrl(sd, 0);
278 	if (ret)
279 		dev_err(&client->dev, "vprog failed.\n");
280 
281 	dev->power_on = false;
282 	return ret;
283 }
284 
285 static int gc0310_s_power(struct v4l2_subdev *sd, int on)
286 {
287 	int ret;
288 
289 	if (on == 0)
290 		return power_down(sd);
291 
292 	ret = power_up(sd);
293 	if (ret)
294 		return ret;
295 
296 	return gc0310_init(sd);
297 }
298 
299 /* TODO: remove it. */
300 static int startup(struct v4l2_subdev *sd)
301 {
302 	struct gc0310_device *dev = to_gc0310_sensor(sd);
303 	struct i2c_client *client = v4l2_get_subdevdata(sd);
304 	int ret = 0;
305 
306 	ret = gc0310_write_reg_array(client, dev->res->regs, dev->res->reg_count);
307 	if (ret) {
308 		dev_err(&client->dev, "gc0310 write register err.\n");
309 		return ret;
310 	}
311 
312 	return ret;
313 }
314 
315 static int gc0310_set_fmt(struct v4l2_subdev *sd,
316 			  struct v4l2_subdev_state *sd_state,
317 			  struct v4l2_subdev_format *format)
318 {
319 	struct v4l2_mbus_framefmt *fmt = &format->format;
320 	struct gc0310_device *dev = to_gc0310_sensor(sd);
321 	struct i2c_client *client = v4l2_get_subdevdata(sd);
322 	struct camera_mipi_info *gc0310_info = NULL;
323 	struct gc0310_resolution *res;
324 	int ret = 0;
325 
326 	if (format->pad)
327 		return -EINVAL;
328 
329 	if (!fmt)
330 		return -EINVAL;
331 
332 	gc0310_info = v4l2_get_subdev_hostdata(sd);
333 	if (!gc0310_info)
334 		return -EINVAL;
335 
336 	mutex_lock(&dev->input_lock);
337 
338 	res = v4l2_find_nearest_size(gc0310_res_preview,
339 				     ARRAY_SIZE(gc0310_res_preview), width,
340 				     height, fmt->width, fmt->height);
341 	if (!res)
342 		res = &gc0310_res_preview[N_RES - 1];
343 
344 	fmt->width = res->width;
345 	fmt->height = res->height;
346 	dev->res = res;
347 
348 	fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8;
349 
350 	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
351 		sd_state->pads->try_fmt = *fmt;
352 		mutex_unlock(&dev->input_lock);
353 		return 0;
354 	}
355 
356 	/* s_power has not been called yet for std v4l2 clients (camorama) */
357 	power_up(sd);
358 
359 	dev_dbg(&client->dev, "%s: before gc0310_write_reg_array %s\n",
360 		__func__, dev->res->desc);
361 	ret = startup(sd);
362 	if (ret) {
363 		dev_err(&client->dev, "gc0310 startup err\n");
364 		goto err;
365 	}
366 
367 err:
368 	mutex_unlock(&dev->input_lock);
369 	return ret;
370 }
371 
372 static int gc0310_get_fmt(struct v4l2_subdev *sd,
373 			  struct v4l2_subdev_state *sd_state,
374 			  struct v4l2_subdev_format *format)
375 {
376 	struct v4l2_mbus_framefmt *fmt = &format->format;
377 	struct gc0310_device *dev = to_gc0310_sensor(sd);
378 
379 	if (format->pad)
380 		return -EINVAL;
381 
382 	if (!fmt)
383 		return -EINVAL;
384 
385 	fmt->width = dev->res->width;
386 	fmt->height = dev->res->height;
387 	fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8;
388 
389 	return 0;
390 }
391 
392 static int gc0310_detect(struct i2c_client *client)
393 {
394 	struct i2c_adapter *adapter = client->adapter;
395 	int ret;
396 
397 	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
398 		return -ENODEV;
399 
400 	ret = i2c_smbus_read_word_swapped(client, GC0310_SC_CMMN_CHIP_ID_H);
401 	if (ret < 0) {
402 		dev_err(&client->dev, "read sensor_id failed: %d\n", ret);
403 		return -ENODEV;
404 	}
405 
406 	dev_dbg(&client->dev, "sensor ID = 0x%x\n", ret);
407 
408 	if (ret != GC0310_ID) {
409 		dev_err(&client->dev, "sensor ID error, read id = 0x%x, target id = 0x%x\n",
410 			ret, GC0310_ID);
411 		return -ENODEV;
412 	}
413 
414 	dev_dbg(&client->dev, "detect gc0310 success\n");
415 
416 	return 0;
417 }
418 
419 static int gc0310_s_stream(struct v4l2_subdev *sd, int enable)
420 {
421 	struct gc0310_device *dev = to_gc0310_sensor(sd);
422 	struct i2c_client *client = v4l2_get_subdevdata(sd);
423 	int ret;
424 
425 	dev_dbg(&client->dev, "%s S enable=%d\n", __func__, enable);
426 	mutex_lock(&dev->input_lock);
427 
428 	if (enable) {
429 		/* enable per frame MIPI and sensor ctrl reset  */
430 		ret = i2c_smbus_write_byte_data(client, 0xFE, 0x30);
431 		if (ret)
432 			goto error_unlock;
433 	}
434 
435 	ret = i2c_smbus_write_byte_data(client, GC0310_RESET_RELATED, GC0310_REGISTER_PAGE_3);
436 	if (ret)
437 		goto error_unlock;
438 
439 	ret = i2c_smbus_write_byte_data(client, GC0310_SW_STREAM,
440 					enable ? GC0310_START_STREAMING : GC0310_STOP_STREAMING);
441 	if (ret)
442 		goto error_unlock;
443 
444 	ret = i2c_smbus_write_byte_data(client, GC0310_RESET_RELATED, GC0310_REGISTER_PAGE_0);
445 	if (ret)
446 		goto error_unlock;
447 
448 	mutex_unlock(&dev->input_lock);
449 	return 0;
450 
451 error_unlock:
452 	mutex_unlock(&dev->input_lock);
453 	return ret;
454 }
455 
456 static int gc0310_s_config(struct v4l2_subdev *sd,
457 			   int irq, void *platform_data)
458 {
459 	struct gc0310_device *dev = to_gc0310_sensor(sd);
460 	struct i2c_client *client = v4l2_get_subdevdata(sd);
461 	int ret = 0;
462 
463 	if (!platform_data)
464 		return -ENODEV;
465 
466 	dev->platform_data =
467 	    (struct camera_sensor_platform_data *)platform_data;
468 
469 	mutex_lock(&dev->input_lock);
470 	/* power off the module, then power on it in future
471 	 * as first power on by board may not fulfill the
472 	 * power on sequqence needed by the module
473 	 */
474 	dev->power_on = true; /* force power_down() to run */
475 	ret = power_down(sd);
476 	if (ret) {
477 		dev_err(&client->dev, "gc0310 power-off err.\n");
478 		goto fail_power_off;
479 	}
480 
481 	ret = power_up(sd);
482 	if (ret) {
483 		dev_err(&client->dev, "gc0310 power-up err.\n");
484 		goto fail_power_on;
485 	}
486 
487 	ret = dev->platform_data->csi_cfg(sd, 1);
488 	if (ret)
489 		goto fail_csi_cfg;
490 
491 	/* config & detect sensor */
492 	ret = gc0310_detect(client);
493 	if (ret) {
494 		dev_err(&client->dev, "gc0310_detect err s_config.\n");
495 		goto fail_csi_cfg;
496 	}
497 
498 	/* turn off sensor, after probed */
499 	ret = power_down(sd);
500 	if (ret) {
501 		dev_err(&client->dev, "gc0310 power-off err.\n");
502 		goto fail_csi_cfg;
503 	}
504 	mutex_unlock(&dev->input_lock);
505 
506 	return 0;
507 
508 fail_csi_cfg:
509 	dev->platform_data->csi_cfg(sd, 0);
510 fail_power_on:
511 	power_down(sd);
512 	dev_err(&client->dev, "sensor power-gating failed\n");
513 fail_power_off:
514 	mutex_unlock(&dev->input_lock);
515 	return ret;
516 }
517 
518 static int gc0310_g_frame_interval(struct v4l2_subdev *sd,
519 				   struct v4l2_subdev_frame_interval *interval)
520 {
521 	struct gc0310_device *dev = to_gc0310_sensor(sd);
522 
523 	interval->interval.numerator = 1;
524 	interval->interval.denominator = dev->res->fps;
525 
526 	return 0;
527 }
528 
529 static int gc0310_enum_mbus_code(struct v4l2_subdev *sd,
530 				 struct v4l2_subdev_state *sd_state,
531 				 struct v4l2_subdev_mbus_code_enum *code)
532 {
533 	if (code->index >= MAX_FMTS)
534 		return -EINVAL;
535 
536 	code->code = MEDIA_BUS_FMT_SGRBG8_1X8;
537 	return 0;
538 }
539 
540 static int gc0310_enum_frame_size(struct v4l2_subdev *sd,
541 				  struct v4l2_subdev_state *sd_state,
542 				  struct v4l2_subdev_frame_size_enum *fse)
543 {
544 	int index = fse->index;
545 
546 	if (index >= N_RES)
547 		return -EINVAL;
548 
549 	fse->min_width = gc0310_res[index].width;
550 	fse->min_height = gc0310_res[index].height;
551 	fse->max_width = gc0310_res[index].width;
552 	fse->max_height = gc0310_res[index].height;
553 
554 	return 0;
555 }
556 
557 static int gc0310_g_skip_frames(struct v4l2_subdev *sd, u32 *frames)
558 {
559 	struct gc0310_device *dev = to_gc0310_sensor(sd);
560 
561 	mutex_lock(&dev->input_lock);
562 	*frames = dev->res->skip_frames;
563 	mutex_unlock(&dev->input_lock);
564 
565 	return 0;
566 }
567 
568 static const struct v4l2_subdev_sensor_ops gc0310_sensor_ops = {
569 	.g_skip_frames	= gc0310_g_skip_frames,
570 };
571 
572 static const struct v4l2_subdev_video_ops gc0310_video_ops = {
573 	.s_stream = gc0310_s_stream,
574 	.g_frame_interval = gc0310_g_frame_interval,
575 };
576 
577 static const struct v4l2_subdev_core_ops gc0310_core_ops = {
578 	.s_power = gc0310_s_power,
579 };
580 
581 static const struct v4l2_subdev_pad_ops gc0310_pad_ops = {
582 	.enum_mbus_code = gc0310_enum_mbus_code,
583 	.enum_frame_size = gc0310_enum_frame_size,
584 	.get_fmt = gc0310_get_fmt,
585 	.set_fmt = gc0310_set_fmt,
586 };
587 
588 static const struct v4l2_subdev_ops gc0310_ops = {
589 	.core = &gc0310_core_ops,
590 	.video = &gc0310_video_ops,
591 	.pad = &gc0310_pad_ops,
592 	.sensor = &gc0310_sensor_ops,
593 };
594 
595 static int gc0310_init_controls(struct gc0310_device *dev)
596 {
597 	struct v4l2_ctrl_handler *hdl = &dev->ctrls.handler;
598 
599 	v4l2_ctrl_handler_init(hdl, 2);
600 
601 	/* Use the same lock for controls as for everything else */
602 	hdl->lock = &dev->input_lock;
603 	dev->sd.ctrl_handler = hdl;
604 
605 	dev->ctrls.exposure =
606 		v4l2_ctrl_new_std(hdl, &ctrl_ops, V4L2_CID_EXPOSURE, 0, 4095, 1, 1023);
607 
608 	/* 32 steps at base gain 1 + 64 half steps at base gain 2 */
609 	dev->ctrls.gain =
610 		v4l2_ctrl_new_std(hdl, &ctrl_ops, V4L2_CID_GAIN, 0, 95, 1, 31);
611 
612 	return hdl->error;
613 }
614 
615 static void gc0310_remove(struct i2c_client *client)
616 {
617 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
618 	struct gc0310_device *dev = to_gc0310_sensor(sd);
619 
620 	dev_dbg(&client->dev, "gc0310_remove...\n");
621 
622 	dev->platform_data->csi_cfg(sd, 0);
623 
624 	v4l2_device_unregister_subdev(sd);
625 	media_entity_cleanup(&dev->sd.entity);
626 	v4l2_ctrl_handler_free(&dev->ctrls.handler);
627 	kfree(dev);
628 }
629 
630 static int gc0310_probe(struct i2c_client *client)
631 {
632 	struct gc0310_device *dev;
633 	int ret;
634 	void *pdata;
635 
636 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
637 	if (!dev)
638 		return -ENOMEM;
639 
640 	mutex_init(&dev->input_lock);
641 
642 	dev->res = &gc0310_res_preview[0];
643 	v4l2_i2c_subdev_init(&dev->sd, client, &gc0310_ops);
644 
645 	pdata = gmin_camera_platform_data(&dev->sd,
646 					  ATOMISP_INPUT_FORMAT_RAW_8,
647 					  atomisp_bayer_order_grbg);
648 	if (!pdata) {
649 		ret = -EINVAL;
650 		goto out_free;
651 	}
652 
653 	ret = gc0310_s_config(&dev->sd, client->irq, pdata);
654 	if (ret)
655 		goto out_free;
656 
657 	ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA);
658 	if (ret)
659 		goto out_free;
660 
661 	dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
662 	dev->pad.flags = MEDIA_PAD_FL_SOURCE;
663 	dev->format.code = MEDIA_BUS_FMT_SGRBG8_1X8;
664 	dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
665 
666 	ret = gc0310_init_controls(dev);
667 	if (ret) {
668 		gc0310_remove(client);
669 		return ret;
670 	}
671 
672 	ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad);
673 	if (ret)
674 		gc0310_remove(client);
675 
676 	return ret;
677 out_free:
678 	v4l2_device_unregister_subdev(&dev->sd);
679 	kfree(dev);
680 	return ret;
681 }
682 
683 static const struct acpi_device_id gc0310_acpi_match[] = {
684 	{"XXGC0310"},
685 	{"INT0310"},
686 	{},
687 };
688 MODULE_DEVICE_TABLE(acpi, gc0310_acpi_match);
689 
690 static struct i2c_driver gc0310_driver = {
691 	.driver = {
692 		.name = "gc0310",
693 		.acpi_match_table = gc0310_acpi_match,
694 	},
695 	.probe_new = gc0310_probe,
696 	.remove = gc0310_remove,
697 };
698 module_i2c_driver(gc0310_driver);
699 
700 MODULE_AUTHOR("Lai, Angie <angie.lai@intel.com>");
701 MODULE_DESCRIPTION("A low-level driver for GalaxyCore GC0310 sensors");
702 MODULE_LICENSE("GPL");
703