From 805f23af6fc44138983ea92aee73419910d51563 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 1 Sep 2017 04:37:54 -0400 Subject: media: cec-pin.c: use proper ktime accessor functions Use ktime_to_ns/ns_to_ktime. This makes it possible to work with older kernels and the media_build compatibility system. For the mainline kernel these functions are NOPs. Signed-off-by: Hans Verkuil Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-pin.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/drivers/media/cec/cec-pin.c b/drivers/media/cec/cec-pin.c index c003b8eac617..e2aa5d6e619d 100644 --- a/drivers/media/cec/cec-pin.c +++ b/drivers/media/cec/cec-pin.c @@ -132,7 +132,7 @@ static void cec_pin_to_idle(struct cec_pin *pin) pin->rx_msg.len = 0; memset(pin->rx_msg.msg, 0, sizeof(pin->rx_msg.msg)); pin->state = CEC_ST_IDLE; - pin->ts = 0; + pin->ts = ns_to_ktime(0); } /* @@ -426,7 +426,7 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts) v = cec_pin_read(pin); if (v && pin->rx_eom) { pin->work_rx_msg = pin->rx_msg; - pin->work_rx_msg.rx_ts = ts; + pin->work_rx_msg.rx_ts = ktime_to_ns(ts); wake_up_interruptible(&pin->kthread_waitq); pin->ts = ts; pin->state = CEC_ST_RX_ACK_FINISH; @@ -457,7 +457,7 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) s32 delta; ts = ktime_get(); - if (pin->timer_ts) { + if (ktime_to_ns(pin->timer_ts)) { delta = ktime_us_delta(ts, pin->timer_ts); pin->timer_cnt++; if (delta > 100 && pin->state != CEC_ST_IDLE) { @@ -481,17 +481,19 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) if (pin->wait_usecs > 150) { pin->wait_usecs -= 100; pin->timer_ts = ktime_add_us(ts, 100); - hrtimer_forward_now(timer, 100000); + hrtimer_forward_now(timer, ns_to_ktime(100000)); return HRTIMER_RESTART; } if (pin->wait_usecs > 100) { pin->wait_usecs /= 2; pin->timer_ts = ktime_add_us(ts, pin->wait_usecs); - hrtimer_forward_now(timer, pin->wait_usecs * 1000); + hrtimer_forward_now(timer, + ns_to_ktime(pin->wait_usecs * 1000)); return HRTIMER_RESTART; } pin->timer_ts = ktime_add_us(ts, pin->wait_usecs); - hrtimer_forward_now(timer, pin->wait_usecs * 1000); + hrtimer_forward_now(timer, + ns_to_ktime(pin->wait_usecs * 1000)); pin->wait_usecs = 0; return HRTIMER_RESTART; } @@ -531,7 +533,7 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) pin->state = CEC_ST_RX_START_BIT_LOW; break; } - if (pin->ts == 0) + if (ktime_to_ns(pin->ts) == 0) pin->ts = ts; if (pin->tx_msg.len) { /* @@ -572,12 +574,13 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer) if (!adap->monitor_pin_cnt || states[pin->state].usecs <= 150) { pin->wait_usecs = 0; pin->timer_ts = ktime_add_us(ts, states[pin->state].usecs); - hrtimer_forward_now(timer, states[pin->state].usecs * 1000); + hrtimer_forward_now(timer, + ns_to_ktime(states[pin->state].usecs * 1000)); return HRTIMER_RESTART; } pin->wait_usecs = states[pin->state].usecs - 100; pin->timer_ts = ktime_add_us(ts, 100); - hrtimer_forward_now(timer, 100000); + hrtimer_forward_now(timer, ns_to_ktime(100000)); return HRTIMER_RESTART; } @@ -596,7 +599,7 @@ static int cec_pin_thread_func(void *_adap) if (pin->work_rx_msg.len) { cec_received_msg_ts(adap, &pin->work_rx_msg, - pin->work_rx_msg.rx_ts); + ns_to_ktime(pin->work_rx_msg.rx_ts)); pin->work_rx_msg.len = 0; } if (pin->work_tx_status) { @@ -623,13 +626,15 @@ static int cec_pin_thread_func(void *_adap) pin->ops->disable_irq(adap); cec_pin_high(pin); cec_pin_to_idle(pin); - hrtimer_start(&pin->timer, 0, HRTIMER_MODE_REL); + hrtimer_start(&pin->timer, ns_to_ktime(0), + HRTIMER_MODE_REL); break; case CEC_PIN_IRQ_ENABLE: pin->enable_irq_failed = !pin->ops->enable_irq(adap); if (pin->enable_irq_failed) { cec_pin_to_idle(pin); - hrtimer_start(&pin->timer, 0, HRTIMER_MODE_REL); + hrtimer_start(&pin->timer, ns_to_ktime(0), + HRTIMER_MODE_REL); } break; default: @@ -653,7 +658,7 @@ static int cec_pin_adap_enable(struct cec_adapter *adap, bool enable) cec_pin_read(pin); cec_pin_to_idle(pin); pin->tx_msg.len = 0; - pin->timer_ts = 0; + pin->timer_ts = ns_to_ktime(0); atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_UNCHANGED); pin->kthread = kthread_run(cec_pin_thread_func, adap, "cec-pin"); @@ -661,7 +666,8 @@ static int cec_pin_adap_enable(struct cec_adapter *adap, bool enable) pr_err("cec-pin: kernel_thread() failed\n"); return PTR_ERR(pin->kthread); } - hrtimer_start(&pin->timer, 0, HRTIMER_MODE_REL); + hrtimer_start(&pin->timer, ns_to_ktime(0), + HRTIMER_MODE_REL); } else { if (pin->ops->disable_irq) pin->ops->disable_irq(adap); @@ -699,7 +705,8 @@ static int cec_pin_adap_transmit(struct cec_adapter *adap, u8 attempts, pin->ops->disable_irq(adap); cec_pin_high(pin); cec_pin_to_idle(pin); - hrtimer_start(&pin->timer, 0, HRTIMER_MODE_REL); + hrtimer_start(&pin->timer, ns_to_ktime(0), + HRTIMER_MODE_REL); } return 0; } -- cgit v1.2.3 From 9a59d9361a68b0f664372312debd7396eda3ed55 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 18 Sep 2017 06:26:03 -0400 Subject: media: cec-ioc-dqevent.rst: fix typo The documentation talked about INITIAL_VALUE when the actual define is INITIAL_STATE. Fix this. Signed-off-by: Hans Verkuil Reported-by: Jonas Karlman Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/cec.h.rst.exceptions | 2 -- Documentation/media/uapi/cec/cec-ioc-dqevent.rst | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Documentation/media/cec.h.rst.exceptions b/Documentation/media/cec.h.rst.exceptions index b1687532742f..d9fd092de6f8 100644 --- a/Documentation/media/cec.h.rst.exceptions +++ b/Documentation/media/cec.h.rst.exceptions @@ -24,8 +24,6 @@ ignore define CEC_VENDOR_ID_NONE ignore define CEC_MODE_INITIATOR_MSK ignore define CEC_MODE_FOLLOWER_MSK -ignore define CEC_EVENT_FL_INITIAL_STATE - # Part of CEC 2.0 spec - shouldn't be documented too? ignore define CEC_LOG_ADDR_TV ignore define CEC_LOG_ADDR_RECORD_1 diff --git a/Documentation/media/uapi/cec/cec-ioc-dqevent.rst b/Documentation/media/uapi/cec/cec-ioc-dqevent.rst index a5c821809cc6..4fe96e2adf4c 100644 --- a/Documentation/media/uapi/cec/cec-ioc-dqevent.rst +++ b/Documentation/media/uapi/cec/cec-ioc-dqevent.rst @@ -172,9 +172,9 @@ it is guaranteed that the state did change in between the two events. :stub-columns: 0 :widths: 3 1 8 - * .. _`CEC-EVENT-FL-INITIAL-VALUE`: + * .. _`CEC-EVENT-FL-INITIAL-STATE`: - - ``CEC_EVENT_FL_INITIAL_VALUE`` + - ``CEC_EVENT_FL_INITIAL_STATE`` - 1 - Set for the initial events that are generated when the device is opened. See the table above for which events do this. This allows -- cgit v1.2.3 From da634f623e4879d7716029a84791fc596ebac24d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 18 Sep 2017 05:23:57 -0400 Subject: media: cec-core.rst/cec-ioc-receive.rst: clarify CEC_TX_STATUS_ERROR CEC_TX_STATUS_ERROR can be used if the HW cannot tell LOST_ARB and LOW_DRIVE apart, or when some other error occurs. It is not a replacement for NACK. So the hardware must be able to tell the difference between OK, NACK and 'something else'. Clarify the documentation (both public and kernel API) on this point. Also fix two small typos (this messages -> this message). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/kapi/cec-core.rst | 7 +++++-- Documentation/media/uapi/cec/cec-ioc-receive.rst | 10 +++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Documentation/media/kapi/cec-core.rst b/Documentation/media/kapi/cec-core.rst index 28866259998c..d37e107f2fde 100644 --- a/Documentation/media/kapi/cec-core.rst +++ b/Documentation/media/kapi/cec-core.rst @@ -227,8 +227,8 @@ CEC_TX_STATUS_LOW_DRIVE: retransmission. CEC_TX_STATUS_ERROR: - some unspecified error occurred: this can be one of - the previous two if the hardware cannot differentiate or something + some unspecified error occurred: this can be one of ARB_LOST + or LOW_DRIVE if the hardware cannot differentiate or something else entirely. CEC_TX_STATUS_MAX_RETRIES: @@ -238,6 +238,9 @@ CEC_TX_STATUS_MAX_RETRIES: doesn't have to make another attempt to transmit the message since the hardware did that already. +The hardware must be able to differentiate between OK, NACK and 'something +else'. + The \*_cnt arguments are the number of error conditions that were seen. This may be 0 if no information is available. Drivers that do not support hardware retry can just set the counter corresponding to the transmit error diff --git a/Documentation/media/uapi/cec/cec-ioc-receive.rst b/Documentation/media/uapi/cec/cec-ioc-receive.rst index 0f397c535a4c..bdad4b197bcd 100644 --- a/Documentation/media/uapi/cec/cec-ioc-receive.rst +++ b/Documentation/media/uapi/cec/cec-ioc-receive.rst @@ -131,7 +131,7 @@ View On' messages from initiator 0xf ('Unregistered') to destination 0 ('TV'). - ``tx_status`` - The status bits of the transmitted message. See :ref:`cec-tx-status` for the possible status values. It is 0 if - this messages was received, not transmitted. + this message was received, not transmitted. * - __u8 - ``msg[16]`` - The message payload. For :ref:`ioctl CEC_TRANSMIT ` this is filled in by the @@ -168,7 +168,7 @@ View On' messages from initiator 0xf ('Unregistered') to destination 0 ('TV'). - ``tx_status`` - The status bits of the transmitted message. See :ref:`cec-tx-status` for the possible status values. It is 0 if - this messages was received, not transmitted. + this message was received, not transmitted. * - __u8 - ``tx_arb_lost_cnt`` - A counter of the number of transmit attempts that resulted in the @@ -256,9 +256,9 @@ View On' messages from initiator 0xf ('Unregistered') to destination 0 ('TV'). - ``CEC_TX_STATUS_ERROR`` - 0x10 - Some error occurred. This is used for any errors that do not fit - the previous two, either because the hardware could not tell which - error occurred, or because the hardware tested for other - conditions besides those two. + ``CEC_TX_STATUS_ARB_LOST`` or ``CEC_TX_STATUS_LOW_DRIVE``, either because + the hardware could not tell which error occurred, or because the hardware + tested for other conditions besides those two. * .. _`CEC-TX-STATUS-MAX-RETRIES`: - ``CEC_TX_STATUS_MAX_RETRIES`` -- cgit v1.2.3 From 333ef6bd10c3ffdaf6da94e34dc6cae675ed27fc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 15 Aug 2017 10:07:25 -0400 Subject: media: cec: add CEC_EVENT_PIN_HPD_LOW/HIGH events Add support for two new low-level events: PIN_HPD_LOW and PIN_HPD_HIGH. This is specifically meant for use with the upcoming cec-gpio driver and makes it possible to trace when the HPD pin changes. Some HDMI sinks do strange things with the HPD and this makes it easy to debug this. Note that this also moves the initialization of a devnode mutex and list to the allocate_adapter function: if the HPD is high, then as soon as the HPD interrupt is created an interrupt occurs and cec_queue_pin_hpd_event() is called which requires that the devnode mutex and list are initialized. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-adap.c | 18 +++++++++++++++++- drivers/media/cec/cec-api.c | 18 ++++++++++++++---- drivers/media/cec/cec-core.c | 8 ++++---- include/media/cec-pin.h | 4 ++++ include/media/cec.h | 12 +++++++++++- include/uapi/linux/cec.h | 2 ++ 6 files changed, 52 insertions(+), 10 deletions(-) diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index 84d1b67f850c..dd0c9cacd1d0 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -86,7 +86,7 @@ void cec_queue_event_fh(struct cec_fh *fh, const struct cec_event *new_ev, u64 ts) { static const u8 max_events[CEC_NUM_EVENTS] = { - 1, 1, 64, 64, + 1, 1, 64, 64, 8, 8, }; struct cec_event_entry *entry; unsigned int ev_idx = new_ev->event - 1; @@ -170,6 +170,22 @@ void cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high, ktime_t ts) } EXPORT_SYMBOL_GPL(cec_queue_pin_cec_event); +/* Notify userspace that the HPD pin changed state at the given time. */ +void cec_queue_pin_hpd_event(struct cec_adapter *adap, bool is_high, ktime_t ts) +{ + struct cec_event ev = { + .event = is_high ? CEC_EVENT_PIN_HPD_HIGH : + CEC_EVENT_PIN_HPD_LOW, + }; + struct cec_fh *fh; + + mutex_lock(&adap->devnode.lock); + list_for_each_entry(fh, &adap->devnode.fhs, list) + cec_queue_event_fh(fh, &ev, ktime_to_ns(ts)); + mutex_unlock(&adap->devnode.lock); +} +EXPORT_SYMBOL_GPL(cec_queue_pin_hpd_event); + /* * Queue a new message for this filehandle. * diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c index a079f7fe018c..465bb3ec21f6 100644 --- a/drivers/media/cec/cec-api.c +++ b/drivers/media/cec/cec-api.c @@ -529,7 +529,7 @@ static int cec_open(struct inode *inode, struct file *filp) * Initial events that are automatically sent when the cec device is * opened. */ - struct cec_event ev_state = { + struct cec_event ev = { .event = CEC_EVENT_STATE_CHANGE, .flags = CEC_EVENT_FL_INITIAL_STATE, }; @@ -569,9 +569,19 @@ static int cec_open(struct inode *inode, struct file *filp) filp->private_data = fh; /* Queue up initial state events */ - ev_state.state_change.phys_addr = adap->phys_addr; - ev_state.state_change.log_addr_mask = adap->log_addrs.log_addr_mask; - cec_queue_event_fh(fh, &ev_state, 0); + ev.state_change.phys_addr = adap->phys_addr; + ev.state_change.log_addr_mask = adap->log_addrs.log_addr_mask; + cec_queue_event_fh(fh, &ev, 0); +#ifdef CONFIG_CEC_PIN + if (adap->pin && adap->pin->ops->read_hpd) { + err = adap->pin->ops->read_hpd(adap); + if (err >= 0) { + ev.event = err ? CEC_EVENT_PIN_HPD_HIGH : + CEC_EVENT_PIN_HPD_LOW; + cec_queue_event_fh(fh, &ev, 0); + } + } +#endif list_add(&fh->list, &devnode->fhs); mutex_unlock(&devnode->lock); diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c index 648136e552d5..e3a1fb6d6690 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c @@ -112,10 +112,6 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode, int minor; int ret; - /* Initialization */ - INIT_LIST_HEAD(&devnode->fhs); - mutex_init(&devnode->lock); - /* Part 1: Find a free minor number */ mutex_lock(&cec_devnode_lock); minor = find_next_zero_bit(cec_devnode_nums, CEC_NUM_DEVICES, 0); @@ -242,6 +238,10 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, INIT_LIST_HEAD(&adap->wait_queue); init_waitqueue_head(&adap->kthread_waitq); + /* adap->devnode initialization */ + INIT_LIST_HEAD(&adap->devnode.fhs); + mutex_init(&adap->devnode.lock); + adap->kthread = kthread_run(cec_thread_func, adap, "cec-%s", name); if (IS_ERR(adap->kthread)) { pr_err("cec-%s: kernel_thread() failed\n", name); diff --git a/include/media/cec-pin.h b/include/media/cec-pin.h index f09cc9579d53..ea84b9c9e0c3 100644 --- a/include/media/cec-pin.h +++ b/include/media/cec-pin.h @@ -97,6 +97,9 @@ enum cec_pin_state { * @free: optional. Free any allocated resources. Called when the * adapter is deleted. * @status: optional, log status information. + * @read_hpd: read the HPD pin. Return true if high, false if low or + * an error if negative. If NULL or -ENOTTY is returned, + * then this is not supported. * * These operations are used by the cec pin framework to manipulate * the CEC pin. @@ -109,6 +112,7 @@ struct cec_pin_ops { void (*disable_irq)(struct cec_adapter *adap); void (*free)(struct cec_adapter *adap); void (*status)(struct cec_adapter *adap, struct seq_file *file); + int (*read_hpd)(struct cec_adapter *adap); }; #define CEC_NUM_PIN_EVENTS 128 diff --git a/include/media/cec.h b/include/media/cec.h index df6b3bd31284..9d0f983faea9 100644 --- a/include/media/cec.h +++ b/include/media/cec.h @@ -91,7 +91,7 @@ struct cec_event_entry { }; #define CEC_NUM_CORE_EVENTS 2 -#define CEC_NUM_EVENTS CEC_EVENT_PIN_CEC_HIGH +#define CEC_NUM_EVENTS CEC_EVENT_PIN_HPD_HIGH struct cec_fh { struct list_head list; @@ -296,6 +296,16 @@ static inline void cec_received_msg(struct cec_adapter *adap, void cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high, ktime_t ts); +/** + * cec_queue_pin_hpd_event() - queue a pin event with a given timestamp. + * + * @adap: pointer to the cec adapter + * @is_high: when true the HPD pin is high, otherwise it is low + * @ts: the timestamp for this event + * + */ +void cec_queue_pin_hpd_event(struct cec_adapter *adap, bool is_high, ktime_t ts); + /** * cec_get_edid_phys_addr() - find and return the physical address * diff --git a/include/uapi/linux/cec.h b/include/uapi/linux/cec.h index 4351c3481aea..b9f8df3a0477 100644 --- a/include/uapi/linux/cec.h +++ b/include/uapi/linux/cec.h @@ -410,6 +410,8 @@ struct cec_log_addrs { #define CEC_EVENT_LOST_MSGS 2 #define CEC_EVENT_PIN_CEC_LOW 3 #define CEC_EVENT_PIN_CEC_HIGH 4 +#define CEC_EVENT_PIN_HPD_LOW 5 +#define CEC_EVENT_PIN_HPD_HIGH 6 #define CEC_EVENT_FL_INITIAL_STATE (1 << 0) #define CEC_EVENT_FL_DROPPED_EVENTS (1 << 1) -- cgit v1.2.3 From 00f7adff0c3a1d793ffa213c28d82c47dfd8ab04 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 30 Aug 2017 12:05:55 -0400 Subject: media: cec-ioc-dqevent.rst: document new CEC_EVENT_PIN_HPD_LOW/HIGH events Document these new CEC events. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/uapi/cec/cec-ioc-dqevent.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Documentation/media/uapi/cec/cec-ioc-dqevent.rst b/Documentation/media/uapi/cec/cec-ioc-dqevent.rst index 4fe96e2adf4c..b6fd86424fbb 100644 --- a/Documentation/media/uapi/cec/cec-ioc-dqevent.rst +++ b/Documentation/media/uapi/cec/cec-ioc-dqevent.rst @@ -161,6 +161,24 @@ it is guaranteed that the state did change in between the two events. - Generated if the CEC pin goes from a low voltage to a high voltage. Only applies to adapters that have the ``CEC_CAP_MONITOR_PIN`` capability set. + * .. _`CEC-EVENT-PIN-HPD-LOW`: + + - ``CEC_EVENT_PIN_HPD_LOW`` + - 5 + - Generated if the HPD pin goes from a high voltage to a low voltage. + Only applies to adapters that have the ``CEC_CAP_MONITOR_PIN`` + capability set. When open() is called, the HPD pin can be read and + if the HPD is low, then an initial event will be generated for that + filehandle. + * .. _`CEC-EVENT-PIN-HPD-HIGH`: + + - ``CEC_EVENT_PIN_HPD_HIGH`` + - 6 + - Generated if the HPD pin goes from a low voltage to a high voltage. + Only applies to adapters that have the ``CEC_CAP_MONITOR_PIN`` + capability set. When open() is called, the HPD pin can be read and + if the HPD is high, then an initial event will be generated for that + filehandle. .. tabularcolumns:: |p{6.0cm}|p{0.6cm}|p{10.9cm}| -- cgit v1.2.3 From 67f2a06f14a9419bc2da0a8e6b440c6813dccdb0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 2 Aug 2017 03:22:33 -0400 Subject: media: dt-bindings: document the CEC GPIO bindings Document the bindings for the cec-gpio module for hardware where the CEC line and optionally the HPD line are connected to GPIO lines. Signed-off-by: Hans Verkuil Reviewed-by: Linus Walleij Reviewed-by: Rob Herring Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/cec-gpio.txt | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/cec-gpio.txt diff --git a/Documentation/devicetree/bindings/media/cec-gpio.txt b/Documentation/devicetree/bindings/media/cec-gpio.txt new file mode 100644 index 000000000000..46a0bac8b3b9 --- /dev/null +++ b/Documentation/devicetree/bindings/media/cec-gpio.txt @@ -0,0 +1,32 @@ +* HDMI CEC GPIO driver + +The HDMI CEC GPIO module supports CEC implementations where the CEC line +is hooked up to a pull-up GPIO line and - optionally - the HPD line is +hooked up to another GPIO line. + +Required properties: + - compatible: value must be "cec-gpio". + - cec-gpios: gpio that the CEC line is connected to. The line should be + tagged as open drain. + +If the CEC line is associated with an HDMI receiver/transmitter, then the +following property is also required: + + - hdmi-phandle - phandle to the HDMI controller, see also cec.txt. + +If the CEC line is not associated with an HDMI receiver/transmitter, then +the following property is optional: + + - hpd-gpios: gpio that the HPD line is connected to. + +Example for the Raspberry Pi 3 where the CEC line is connected to +pin 26 aka BCM7 aka CE1 on the GPIO pin header and the HPD line is +connected to pin 11 aka BCM17: + +#include + +cec-gpio { + compatible = "cec-gpio"; + cec-gpios = <&gpio 7 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + hpd-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; +}; -- cgit v1.2.3 From 1e33936d3baee3b688ec12b372534522b9256032 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 28 Jun 2017 04:14:28 -0400 Subject: media: cec-gpio: add HDMI CEC GPIO driver Add a simple HDMI CEC GPIO driver that sits on top of the cec-pin framework. While I have heard of SoCs that use the GPIO pin for CEC (apparently an early RockChip SoC used that), the main use-case of this driver is to function as a debugging tool. By connecting the CEC line to a GPIO pin on a Raspberry Pi 3 for example it turns it into a CEC debugger and protocol analyzer. With 'cec-ctl --monitor-pin' the CEC traffic can be analyzed. But of course it can also be used with any hardware project where the HDMI CEC line is hooked up to a pull-up gpio line. In addition this has (optional) support for tracing HPD changes if the HPD is connected to a GPIO. Signed-off-by: Hans Verkuil Reviewed-by: Linus Walleij Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 10 ++ drivers/media/platform/Makefile | 2 + drivers/media/platform/cec-gpio/Makefile | 1 + drivers/media/platform/cec-gpio/cec-gpio.c | 236 +++++++++++++++++++++++++++++ 4 files changed, 249 insertions(+) create mode 100644 drivers/media/platform/cec-gpio/Makefile create mode 100644 drivers/media/platform/cec-gpio/cec-gpio.c diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 7e7cc49b8674..e4c89a16a3e7 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -553,6 +553,16 @@ config VIDEO_MESON_AO_CEC This is a driver for Amlogic Meson SoCs AO CEC interface. It uses the generic CEC framework interface. CEC bus is present in the HDMI connector and enables communication + +config CEC_GPIO + tristate "Generic GPIO-based CEC driver" + depends on PREEMPT + select CEC_CORE + select CEC_PIN + select GPIOLIB + ---help--- + This is a generic GPIO-based CEC driver. + The CEC bus is present in the HDMI connector and enables communication between compatible devices. config VIDEO_SAMSUNG_S5P_CEC diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index c1ef946bf032..9bf48f118537 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -26,6 +26,8 @@ obj-$(CONFIG_VIDEO_CODA) += coda/ obj-$(CONFIG_VIDEO_SH_VEU) += sh_veu.o +obj-$(CONFIG_CEC_GPIO) += cec-gpio/ + obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE) += m2m-deinterlace.o obj-$(CONFIG_VIDEO_MUX) += video-mux.o diff --git a/drivers/media/platform/cec-gpio/Makefile b/drivers/media/platform/cec-gpio/Makefile new file mode 100644 index 000000000000..e82b258afa55 --- /dev/null +++ b/drivers/media/platform/cec-gpio/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_CEC_GPIO) += cec-gpio.o diff --git a/drivers/media/platform/cec-gpio/cec-gpio.c b/drivers/media/platform/cec-gpio/cec-gpio.c new file mode 100644 index 000000000000..eb982bce99fc --- /dev/null +++ b/drivers/media/platform/cec-gpio/cec-gpio.c @@ -0,0 +1,236 @@ +/* + * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +struct cec_gpio { + struct cec_adapter *adap; + struct device *dev; + + struct gpio_desc *cec_gpio; + int cec_irq; + bool cec_is_low; + bool cec_have_irq; + + struct gpio_desc *hpd_gpio; + int hpd_irq; + bool hpd_is_high; + ktime_t hpd_ts; +}; + +static bool cec_gpio_read(struct cec_adapter *adap) +{ + struct cec_gpio *cec = cec_get_drvdata(adap); + + if (cec->cec_is_low) + return false; + return gpiod_get_value(cec->cec_gpio); +} + +static void cec_gpio_high(struct cec_adapter *adap) +{ + struct cec_gpio *cec = cec_get_drvdata(adap); + + if (!cec->cec_is_low) + return; + cec->cec_is_low = false; + gpiod_set_value(cec->cec_gpio, 1); +} + +static void cec_gpio_low(struct cec_adapter *adap) +{ + struct cec_gpio *cec = cec_get_drvdata(adap); + + if (cec->cec_is_low) + return; + if (WARN_ON_ONCE(cec->cec_have_irq)) + free_irq(cec->cec_irq, cec); + cec->cec_have_irq = false; + cec->cec_is_low = true; + gpiod_set_value(cec->cec_gpio, 0); +} + +static irqreturn_t cec_hpd_gpio_irq_handler_thread(int irq, void *priv) +{ + struct cec_gpio *cec = priv; + + cec_queue_pin_hpd_event(cec->adap, cec->hpd_is_high, cec->hpd_ts); + return IRQ_HANDLED; +} + +static irqreturn_t cec_hpd_gpio_irq_handler(int irq, void *priv) +{ + struct cec_gpio *cec = priv; + + cec->hpd_ts = ktime_get(); + cec->hpd_is_high = gpiod_get_value(cec->hpd_gpio); + return IRQ_WAKE_THREAD; +} + +static irqreturn_t cec_gpio_irq_handler(int irq, void *priv) +{ + struct cec_gpio *cec = priv; + + cec_pin_changed(cec->adap, gpiod_get_value(cec->cec_gpio)); + return IRQ_HANDLED; +} + +static bool cec_gpio_enable_irq(struct cec_adapter *adap) +{ + struct cec_gpio *cec = cec_get_drvdata(adap); + + if (cec->cec_have_irq) + return true; + + if (request_irq(cec->cec_irq, cec_gpio_irq_handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + adap->name, cec)) + return false; + cec->cec_have_irq = true; + return true; +} + +static void cec_gpio_disable_irq(struct cec_adapter *adap) +{ + struct cec_gpio *cec = cec_get_drvdata(adap); + + if (cec->cec_have_irq) + free_irq(cec->cec_irq, cec); + cec->cec_have_irq = false; +} + +static void cec_gpio_status(struct cec_adapter *adap, struct seq_file *file) +{ + struct cec_gpio *cec = cec_get_drvdata(adap); + + seq_printf(file, "mode: %s\n", cec->cec_is_low ? "low-drive" : "read"); + if (cec->cec_have_irq) + seq_printf(file, "using irq: %d\n", cec->cec_irq); + if (cec->hpd_gpio) + seq_printf(file, "hpd: %s\n", + cec->hpd_is_high ? "high" : "low"); +} + +static int cec_gpio_read_hpd(struct cec_adapter *adap) +{ + struct cec_gpio *cec = cec_get_drvdata(adap); + + if (!cec->hpd_gpio) + return -ENOTTY; + return gpiod_get_value(cec->hpd_gpio); +} + +static void cec_gpio_free(struct cec_adapter *adap) +{ + cec_gpio_disable_irq(adap); +} + +static const struct cec_pin_ops cec_gpio_pin_ops = { + .read = cec_gpio_read, + .low = cec_gpio_low, + .high = cec_gpio_high, + .enable_irq = cec_gpio_enable_irq, + .disable_irq = cec_gpio_disable_irq, + .status = cec_gpio_status, + .free = cec_gpio_free, + .read_hpd = cec_gpio_read_hpd, +}; + +static int cec_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct cec_gpio *cec; + int ret; + + cec = devm_kzalloc(dev, sizeof(*cec), GFP_KERNEL); + if (!cec) + return -ENOMEM; + + cec->dev = dev; + + cec->cec_gpio = devm_gpiod_get(dev, "cec", GPIOD_IN); + if (IS_ERR(cec->cec_gpio)) + return PTR_ERR(cec->cec_gpio); + cec->cec_irq = gpiod_to_irq(cec->cec_gpio); + + cec->hpd_gpio = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN); + if (IS_ERR(cec->hpd_gpio)) + return PTR_ERR(cec->hpd_gpio); + + cec->adap = cec_pin_allocate_adapter(&cec_gpio_pin_ops, + cec, pdev->name, CEC_CAP_DEFAULTS | CEC_CAP_PHYS_ADDR | + CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN); + if (IS_ERR(cec->adap)) + return PTR_ERR(cec->adap); + + if (cec->hpd_gpio) { + cec->hpd_irq = gpiod_to_irq(cec->hpd_gpio); + ret = devm_request_threaded_irq(dev, cec->hpd_irq, + cec_hpd_gpio_irq_handler, + cec_hpd_gpio_irq_handler_thread, + IRQF_ONESHOT | + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + "hpd-gpio", cec); + if (ret) + return ret; + } + + ret = cec_register_adapter(cec->adap, &pdev->dev); + if (ret) { + cec_delete_adapter(cec->adap); + return ret; + } + + platform_set_drvdata(pdev, cec); + return 0; +} + +static int cec_gpio_remove(struct platform_device *pdev) +{ + struct cec_gpio *cec = platform_get_drvdata(pdev); + + cec_unregister_adapter(cec->adap); + return 0; +} + +static const struct of_device_id cec_gpio_match[] = { + { + .compatible = "cec-gpio", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, cec_gpio_match); + +static struct platform_driver cec_gpio_pdrv = { + .probe = cec_gpio_probe, + .remove = cec_gpio_remove, + .driver = { + .name = "cec-gpio", + .of_match_table = cec_gpio_match, + }, +}; + +module_platform_driver(cec_gpio_pdrv); + +MODULE_AUTHOR("Hans Verkuil "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("CEC GPIO driver"); -- cgit v1.2.3 From 96b52ab3d0bee56e79f8e0e87daef5133c40a407 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 28 Jun 2017 04:14:15 -0400 Subject: media: MAINTAINERS: add cec-gpio entry Add an entry for the CEC GPIO driver. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index eb930ebecfcb..5ef0d34ef502 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3205,6 +3205,15 @@ F: include/uapi/linux/cec.h F: include/uapi/linux/cec-funcs.h F: Documentation/devicetree/bindings/media/cec.txt +CEC GPIO DRIVER +M: Hans Verkuil +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +W: http://linuxtv.org +S: Supported +F: drivers/media/platform/cec-gpio/ +F: Documentation/devicetree/bindings/media/cec-gpio.txt + CELL BROADBAND ENGINE ARCHITECTURE M: Arnd Bergmann L: linuxppc-dev@lists.ozlabs.org -- cgit v1.2.3 From 42ded7a866492c4cfffdcd10eee46a7660d18953 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 31 Aug 2017 04:12:54 -0400 Subject: media: tc358743_regs.h: add CEC registers Add the missing CEC register defines. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358743_regs.h | 94 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/tc358743_regs.h b/drivers/media/i2c/tc358743_regs.h index 657ef50f215f..227b46471793 100644 --- a/drivers/media/i2c/tc358743_regs.h +++ b/drivers/media/i2c/tc358743_regs.h @@ -193,8 +193,98 @@ #define CSI_START 0x0518 #define MASK_STRT 0x00000001 -#define CECEN 0x0600 -#define MASK_CECEN 0x0001 +/* *** CEC (32 bit) *** */ +#define CECHCLK 0x0028 /* 16 bits */ +#define MASK_CECHCLK (0x7ff << 0) + +#define CECLCLK 0x002a /* 16 bits */ +#define MASK_CECLCLK (0x7ff << 0) + +#define CECEN 0x0600 +#define MASK_CECEN 0x0001 + +#define CECADD 0x0604 +#define CECRST 0x0608 +#define MASK_CECRESET 0x0001 + +#define CECREN 0x060c +#define MASK_CECREN 0x0001 + +#define CECRCTL1 0x0614 +#define MASK_CECACKDIS (1 << 24) +#define MASK_CECHNC (3 << 20) +#define MASK_CECLNC (7 << 16) +#define MASK_CECMIN (7 << 12) +#define MASK_CECMAX (7 << 8) +#define MASK_CECDAT (7 << 4) +#define MASK_CECTOUT (3 << 2) +#define MASK_CECRIHLD (1 << 1) +#define MASK_CECOTH (1 << 0) + +#define CECRCTL2 0x0618 +#define MASK_CECSWAV3 (7 << 12) +#define MASK_CECSWAV2 (7 << 8) +#define MASK_CECSWAV1 (7 << 4) +#define MASK_CECSWAV0 (7 << 0) + +#define CECRCTL3 0x061c +#define MASK_CECWAV3 (7 << 20) +#define MASK_CECWAV2 (7 << 16) +#define MASK_CECWAV1 (7 << 12) +#define MASK_CECWAV0 (7 << 8) +#define MASK_CECACKEI (1 << 4) +#define MASK_CECMINEI (1 << 3) +#define MASK_CECMAXEI (1 << 2) +#define MASK_CECRSTEI (1 << 1) +#define MASK_CECWAVEI (1 << 0) + +#define CECTEN 0x0620 +#define MASK_CECTBUSY (1 << 1) +#define MASK_CECTEN (1 << 0) + +#define CECTCTL 0x0628 +#define MASK_CECSTRS (7 << 20) +#define MASK_CECSPRD (7 << 16) +#define MASK_CECDTRS (7 << 12) +#define MASK_CECDPRD (15 << 8) +#define MASK_CECBRD (1 << 4) +#define MASK_CECFREE (15 << 0) + +#define CECRSTAT 0x062c +#define MASK_CECRIWA (1 << 6) +#define MASK_CECRIOR (1 << 5) +#define MASK_CECRIACK (1 << 4) +#define MASK_CECRIMIN (1 << 3) +#define MASK_CECRIMAX (1 << 2) +#define MASK_CECRISTA (1 << 1) +#define MASK_CECRIEND (1 << 0) + +#define CECTSTAT 0x0630 +#define MASK_CECTIUR (1 << 4) +#define MASK_CECTIACK (1 << 3) +#define MASK_CECTIAL (1 << 2) +#define MASK_CECTIEND (1 << 1) + +#define CECRBUF1 0x0634 +#define MASK_CECRACK (1 << 9) +#define MASK_CECEOM (1 << 8) +#define MASK_CECRBYTE (0xff << 0) + +#define CECTBUF1 0x0674 +#define MASK_CECTEOM (1 << 8) +#define MASK_CECTBYTE (0xff << 0) + +#define CECRCTR 0x06b4 +#define MASK_CECRCTR (0x1f << 0) + +#define CECIMSK 0x06c0 +#define MASK_CECTIM (1 << 1) +#define MASK_CECRIM (1 << 0) + +#define CECICLR 0x06cc +#define MASK_CECTICLR (1 << 1) +#define MASK_CECRICLR (1 << 0) + #define HDMI_INT0 0x8500 #define MASK_I_KEY 0x80 -- cgit v1.2.3 From a0ec8d1dc42e4255307cb1b95345c01c327a10a6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 31 Aug 2017 04:12:55 -0400 Subject: media: tc358743: add CEC support Add CEC support for the tc358743 HDMI-CSI bridge. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 8 ++ drivers/media/i2c/tc358743.c | 205 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 207 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 94153895fcd4..47113774a297 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -354,6 +354,14 @@ config VIDEO_TC358743 To compile this driver as a module, choose M here: the module will be called tc358743. +config VIDEO_TC358743_CEC + bool "Enable Toshiba TC358743 CEC support" + depends on VIDEO_TC358743 + select CEC_CORE + ---help--- + When selected the tc358743 will support the optional + HDMI CEC feature. + config VIDEO_TVP514X tristate "Texas Instruments TVP514x video decoder" depends on VIDEO_V4L2 && I2C diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index e6f5c363ccab..e1d8eef7055e 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,7 @@ MODULE_LICENSE("GPL"); #define I2C_MAX_XFER_SIZE (EDID_BLOCK_SIZE + 2) +#define POLL_INTERVAL_CEC_MS 10 #define POLL_INTERVAL_MS 1000 static const struct v4l2_dv_timings_cap tc358743_timings_cap = { @@ -106,6 +108,8 @@ struct tc358743_state { u8 csi_lanes_in_use; struct gpio_desc *reset_gpio; + + struct cec_adapter *cec_adap; }; static void tc358743_enable_interrupts(struct v4l2_subdev *sd, @@ -595,6 +599,7 @@ static void tc358743_set_ref_clk(struct v4l2_subdev *sd) struct tc358743_platform_data *pdata = &state->pdata; u32 sys_freq; u32 lockdet_ref; + u32 cec_freq; u16 fh_min; u16 fh_max; @@ -626,6 +631,15 @@ static void tc358743_set_ref_clk(struct v4l2_subdev *sd) i2c_wr8_and_or(sd, NCO_F0_MOD, ~MASK_NCO_F0_MOD, (pdata->refclk_hz == 27000000) ? MASK_NCO_F0_MOD_27MHZ : 0x0); + + /* + * Trial and error suggests that the default register value + * of 656 is for a 42 MHz reference clock. Use that to derive + * a new value based on the actual reference clock. + */ + cec_freq = (656 * sys_freq) / 4200; + i2c_wr16(sd, CECHCLK, cec_freq); + i2c_wr16(sd, CECLCLK, cec_freq); } static void tc358743_set_csi_color_space(struct v4l2_subdev *sd) @@ -814,11 +828,17 @@ static void tc358743_initial_setup(struct v4l2_subdev *sd) struct tc358743_state *state = to_state(sd); struct tc358743_platform_data *pdata = &state->pdata; - /* CEC and IR are not supported by this driver */ - i2c_wr16_and_or(sd, SYSCTL, ~(MASK_CECRST | MASK_IRRST), - (MASK_CECRST | MASK_IRRST)); + /* + * IR is not supported by this driver. + * CEC is only enabled if needed. + */ + i2c_wr16_and_or(sd, SYSCTL, ~(MASK_IRRST | MASK_CECRST), + (MASK_IRRST | MASK_CECRST)); tc358743_reset(sd, MASK_CTXRST | MASK_HDMIRST); +#ifdef CONFIG_VIDEO_TC358743_CEC + tc358743_reset(sd, MASK_CECRST); +#endif tc358743_sleep_mode(sd, false); i2c_wr16(sd, FIFOCTL, pdata->fifo_level); @@ -842,6 +862,133 @@ static void tc358743_initial_setup(struct v4l2_subdev *sd) i2c_wr8(sd, VOUT_SET3, MASK_VOUT_EXTCNT); } +/* --------------- CEC --------------- */ + +#ifdef CONFIG_VIDEO_TC358743_CEC +static int tc358743_cec_adap_enable(struct cec_adapter *adap, bool enable) +{ + struct tc358743_state *state = adap->priv; + struct v4l2_subdev *sd = &state->sd; + + i2c_wr32(sd, CECIMSK, enable ? MASK_CECTIM | MASK_CECRIM : 0); + i2c_wr32(sd, CECICLR, MASK_CECTICLR | MASK_CECRICLR); + i2c_wr32(sd, CECEN, enable); + if (enable) + i2c_wr32(sd, CECREN, MASK_CECREN); + return 0; +} + +static int tc358743_cec_adap_monitor_all_enable(struct cec_adapter *adap, + bool enable) +{ + struct tc358743_state *state = adap->priv; + struct v4l2_subdev *sd = &state->sd; + u32 reg; + + reg = i2c_rd32(sd, CECRCTL1); + if (enable) + reg |= MASK_CECOTH; + else + reg &= ~MASK_CECOTH; + i2c_wr32(sd, CECRCTL1, reg); + return 0; +} + +static int tc358743_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) +{ + struct tc358743_state *state = adap->priv; + struct v4l2_subdev *sd = &state->sd; + unsigned int la = 0; + + if (log_addr != CEC_LOG_ADDR_INVALID) { + la = i2c_rd32(sd, CECADD); + la |= 1 << log_addr; + } + i2c_wr32(sd, CECADD, la); + return 0; +} + +static int tc358743_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg) +{ + struct tc358743_state *state = adap->priv; + struct v4l2_subdev *sd = &state->sd; + unsigned int i; + + i2c_wr32(sd, CECTCTL, + (cec_msg_is_broadcast(msg) ? MASK_CECBRD : 0) | + (signal_free_time - 1)); + for (i = 0; i < msg->len; i++) + i2c_wr32(sd, CECTBUF1 + i * 4, + msg->msg[i] | ((i == msg->len - 1) ? MASK_CECTEOM : 0)); + i2c_wr32(sd, CECTEN, MASK_CECTEN); + return 0; +} + +static const struct cec_adap_ops tc358743_cec_adap_ops = { + .adap_enable = tc358743_cec_adap_enable, + .adap_log_addr = tc358743_cec_adap_log_addr, + .adap_transmit = tc358743_cec_adap_transmit, + .adap_monitor_all_enable = tc358743_cec_adap_monitor_all_enable, +}; + +static void tc358743_cec_isr(struct v4l2_subdev *sd, u16 intstatus, + bool *handled) +{ + struct tc358743_state *state = to_state(sd); + unsigned int cec_rxint, cec_txint; + unsigned int clr = 0; + + cec_rxint = i2c_rd32(sd, CECRSTAT); + cec_txint = i2c_rd32(sd, CECTSTAT); + + if (intstatus & MASK_CEC_RINT) + clr |= MASK_CECRICLR; + if (intstatus & MASK_CEC_TINT) + clr |= MASK_CECTICLR; + i2c_wr32(sd, CECICLR, clr); + + if ((intstatus & MASK_CEC_TINT) && cec_txint) { + if (cec_txint & MASK_CECTIEND) + cec_transmit_attempt_done(state->cec_adap, + CEC_TX_STATUS_OK); + else if (cec_txint & MASK_CECTIAL) + cec_transmit_attempt_done(state->cec_adap, + CEC_TX_STATUS_ARB_LOST); + else if (cec_txint & MASK_CECTIACK) + cec_transmit_attempt_done(state->cec_adap, + CEC_TX_STATUS_NACK); + else if (cec_txint & MASK_CECTIUR) { + /* + * Not sure when this bit is set. Treat + * it as an error for now. + */ + cec_transmit_attempt_done(state->cec_adap, + CEC_TX_STATUS_ERROR); + } + *handled = true; + } + if ((intstatus & MASK_CEC_RINT) && + (cec_rxint & MASK_CECRIEND)) { + struct cec_msg msg = {}; + unsigned int i; + unsigned int v; + + v = i2c_rd32(sd, CECRCTR); + msg.len = v & 0x1f; + for (i = 0; i < msg.len; i++) { + v = i2c_rd32(sd, CECRBUF1 + i * 4); + msg.msg[i] = v & 0xff; + } + cec_received_msg(state->cec_adap, &msg); + *handled = true; + } + i2c_wr16(sd, INTSTATUS, + intstatus & (MASK_CEC_RINT | MASK_CEC_TINT)); +} + +#endif + /* --------------- IRQ --------------- */ static void tc358743_format_change(struct v4l2_subdev *sd) @@ -1296,6 +1443,15 @@ static int tc358743_isr(struct v4l2_subdev *sd, u32 status, bool *handled) intstatus &= ~MASK_HDMI_INT; } +#ifdef CONFIG_VIDEO_TC358743_CEC + if (intstatus & (MASK_CEC_RINT | MASK_CEC_TINT)) { + tc358743_cec_isr(sd, intstatus, handled); + i2c_wr16(sd, INTSTATUS, + intstatus & (MASK_CEC_RINT | MASK_CEC_TINT)); + intstatus &= ~(MASK_CEC_RINT | MASK_CEC_TINT); + } +#endif + if (intstatus & MASK_CSI_INT) { u32 csi_int = i2c_rd32(sd, CSI_INT); @@ -1328,10 +1484,15 @@ static irqreturn_t tc358743_irq_handler(int irq, void *dev_id) static void tc358743_irq_poll_timer(unsigned long arg) { struct tc358743_state *state = (struct tc358743_state *)arg; + unsigned int msecs; schedule_work(&state->work_i2c_poll); - - mod_timer(&state->timer, jiffies + msecs_to_jiffies(POLL_INTERVAL_MS)); + /* + * If CEC is present, then we need to poll more frequently, + * otherwise we will miss CEC messages. + */ + msecs = state->cec_adap ? POLL_INTERVAL_CEC_MS : POLL_INTERVAL_MS; + mod_timer(&state->timer, jiffies + msecs_to_jiffies(msecs)); } static void tc358743_work_i2c_poll(struct work_struct *work) @@ -1621,6 +1782,8 @@ static int tc358743_s_edid(struct v4l2_subdev *sd, { struct tc358743_state *state = to_state(sd); u16 edid_len = edid->blocks * EDID_BLOCK_SIZE; + u16 pa; + int err; int i; v4l2_dbg(2, debug, sd, "%s, pad %d, start block %d, blocks %d\n", @@ -1638,6 +1801,12 @@ static int tc358743_s_edid(struct v4l2_subdev *sd, edid->blocks = EDID_NUM_BLOCKS_MAX; return -E2BIG; } + pa = cec_get_edid_phys_addr(edid->edid, edid->blocks * 128, NULL); + err = cec_phys_addr_validate(pa, &pa, NULL); + if (err) + return err; + + cec_phys_addr_invalidate(state->cec_adap); tc358743_disable_edid(sd); @@ -1654,6 +1823,8 @@ static int tc358743_s_edid(struct v4l2_subdev *sd, state->edid_blocks_written = edid->blocks; + cec_s_phys_addr(state->cec_adap, pa, false); + if (tx_5v_power_present(sd)) tc358743_enable_edid(sd); @@ -1867,6 +2038,7 @@ static int tc358743_probe(struct i2c_client *client, struct tc358743_state *state; struct tc358743_platform_data *pdata = client->dev.platform_data; struct v4l2_subdev *sd; + u16 irq_mask = MASK_HDMI_MSK | MASK_CSI_MSK; int err; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) @@ -1945,6 +2117,17 @@ static int tc358743_probe(struct i2c_client *client, INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, tc358743_delayed_work_enable_hotplug); +#ifdef CONFIG_VIDEO_TC358743_CEC + state->cec_adap = cec_allocate_adapter(&tc358743_cec_adap_ops, + state, dev_name(&client->dev), + CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL, CEC_MAX_LOG_ADDRS); + if (IS_ERR(state->cec_adap)) { + err = state->cec_adap ? PTR_ERR(state->cec_adap) : -ENOMEM; + goto err_hdl; + } + irq_mask |= MASK_CEC_RMSK | MASK_CEC_TMSK; +#endif + tc358743_initial_setup(sd); tc358743_s_dv_timings(sd, &default_timing); @@ -1971,8 +2154,16 @@ static int tc358743_probe(struct i2c_client *client, add_timer(&state->timer); } + err = cec_register_adapter(state->cec_adap, &client->dev); + if (err < 0) { + pr_err("%s: failed to register the cec device\n", __func__); + cec_delete_adapter(state->cec_adap); + state->cec_adap = NULL; + goto err_work_queues; + } + tc358743_enable_interrupts(sd, tx_5v_power_present(sd)); - i2c_wr16(sd, INTMASK, ~(MASK_HDMI_MSK | MASK_CSI_MSK) & 0xffff); + i2c_wr16(sd, INTMASK, ~irq_mask); err = v4l2_ctrl_handler_setup(sd->ctrl_handler); if (err) @@ -1984,6 +2175,7 @@ static int tc358743_probe(struct i2c_client *client, return 0; err_work_queues: + cec_unregister_adapter(state->cec_adap); if (!state->i2c_client->irq) flush_work(&state->work_i2c_poll); cancel_delayed_work(&state->delayed_work_enable_hotplug); @@ -2004,6 +2196,7 @@ static int tc358743_remove(struct i2c_client *client) flush_work(&state->work_i2c_poll); } cancel_delayed_work(&state->delayed_work_enable_hotplug); + cec_unregister_adapter(state->cec_adap); v4l2_async_unregister_subdev(sd); v4l2_device_unregister_subdev(sd); mutex_destroy(&state->confctl_mutex); -- cgit v1.2.3 From c38e8657a471e9af42b86009e5d3085031b41fda Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 28 Aug 2017 05:46:57 -0400 Subject: media: drivers: delete error messages for failed memory allocation Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. [mchehab@s-opensource.com: fold several similar patches into one] Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/cypress_firmware.c | 4 +--- drivers/media/common/siano/smscoreapi.c | 13 ++++--------- drivers/media/dvb-frontends/as102_fe.c | 5 ++--- drivers/media/dvb-frontends/cx24113.c | 5 ++--- drivers/media/dvb-frontends/cx24116.c | 1 - drivers/media/dvb-frontends/drxd_hard.c | 1 - drivers/media/dvb-frontends/ds3000.c | 8 ++------ drivers/media/dvb-frontends/mb86a20s.c | 5 +---- drivers/media/dvb-frontends/si2168.c | 1 - drivers/media/dvb-frontends/sp2.c | 1 - drivers/media/i2c/adv7604.c | 4 +--- drivers/media/i2c/adv7842.c | 4 +--- drivers/media/pci/cx18/cx18-driver.c | 6 ++---- drivers/media/pci/mantis/hopper_cards.c | 1 - drivers/media/pci/mantis/mantis_cards.c | 4 +--- drivers/media/pci/meye/meye.c | 13 ++++--------- drivers/media/pci/saa7146/hexium_gemini.c | 5 ++--- drivers/media/pci/saa7146/hexium_orion.c | 4 +--- drivers/media/pci/saa7164/saa7164-buffer.c | 4 +--- drivers/media/platform/atmel/atmel-isc.c | 4 +--- drivers/media/platform/atmel/atmel-isi.c | 8 ++------ drivers/media/platform/blackfin/ppi.c | 1 - drivers/media/usb/zr364xx/zr364xx.c | 8 ++------ 23 files changed, 30 insertions(+), 80 deletions(-) diff --git a/drivers/media/common/cypress_firmware.c b/drivers/media/common/cypress_firmware.c index 50e3f76d4847..bfe47bc5f716 100644 --- a/drivers/media/common/cypress_firmware.c +++ b/drivers/media/common/cypress_firmware.c @@ -75,10 +75,8 @@ int cypress_load_firmware(struct usb_device *udev, int ret, pos = 0; hx = kmalloc(sizeof(struct hexline), GFP_KERNEL); - if (!hx) { - dev_err(&udev->dev, "%s: kmalloc() failed\n", KBUILD_MODNAME); + if (!hx) return -ENOMEM; - } /* stop the CPU */ hx->data[0] = 1; diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index e7a0d7798d5b..889b486fbc72 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -1301,10 +1301,8 @@ static int smscore_init_device(struct smscore_device_t *coredev, int mode) buffer = kmalloc(sizeof(struct sms_msg_data) + SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA); - if (!buffer) { - pr_err("Could not allocate buffer for init device message.\n"); + if (!buffer) return -ENOMEM; - } msg = (struct sms_msg_data *)SMS_ALIGN_ADDRESS(buffer); SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ, @@ -1687,10 +1685,9 @@ static int smscore_validate_client(struct smscore_device_t *coredev, return -EEXIST; } listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL); - if (!listentry) { - pr_err("Can't allocate memory for client id.\n"); + if (!listentry) return -ENOMEM; - } + listentry->id = id; listentry->data_type = data_type; list_add_locked(&listentry->entry, &client->idlist, @@ -1725,10 +1722,8 @@ int smscore_register_client(struct smscore_device_t *coredev, } newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL); - if (!newclient) { - pr_err("Failed to allocate memory for client.\n"); + if (!newclient) return -ENOMEM; - } INIT_LIST_HEAD(&newclient->idlist); newclient->coredev = coredev; diff --git a/drivers/media/dvb-frontends/as102_fe.c b/drivers/media/dvb-frontends/as102_fe.c index 98d575f2744c..1fb4ab21d786 100644 --- a/drivers/media/dvb-frontends/as102_fe.c +++ b/drivers/media/dvb-frontends/as102_fe.c @@ -456,10 +456,9 @@ struct dvb_frontend *as102_attach(const char *name, struct dvb_frontend *fe; state = kzalloc(sizeof(struct as102_state), GFP_KERNEL); - if (state == NULL) { - pr_err("%s: unable to allocate memory for state\n", __func__); + if (!state) return NULL; - } + fe = &state->frontend; fe->demodulator_priv = state; state->ops = ops; diff --git a/drivers/media/dvb-frontends/cx24113.c b/drivers/media/dvb-frontends/cx24113.c index 0118c2658cf7..8fc7333c76b7 100644 --- a/drivers/media/dvb-frontends/cx24113.c +++ b/drivers/media/dvb-frontends/cx24113.c @@ -555,10 +555,9 @@ struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe, struct cx24113_state *state = kzalloc(sizeof(struct cx24113_state), GFP_KERNEL); int rc; - if (state == NULL) { - cx_err("Unable to kzalloc\n"); + + if (!state) goto error; - } /* setup the state */ state->config = config; diff --git a/drivers/media/dvb-frontends/cx24116.c b/drivers/media/dvb-frontends/cx24116.c index e105532bfba8..96af4ffba0f9 100644 --- a/drivers/media/dvb-frontends/cx24116.c +++ b/drivers/media/dvb-frontends/cx24116.c @@ -227,7 +227,6 @@ static int cx24116_writeregN(struct cx24116_state *state, int reg, buf = kmalloc(len + 1, GFP_KERNEL); if (buf == NULL) { - printk("Unable to kmalloc\n"); ret = -ENOMEM; goto error; } diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index 7d04400b18dd..47b0d37e70ba 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -911,7 +911,6 @@ static int load_firmware(struct drxd_state *state, const char *fw_name) state->microcode = kmemdup(fw->data, fw->size, GFP_KERNEL); if (state->microcode == NULL) { release_firmware(fw); - printk(KERN_ERR "drxd: firmware load failure: no memory\n"); return -ENOMEM; } diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c index 0b17a45c5640..c2959a9695a7 100644 --- a/drivers/media/dvb-frontends/ds3000.c +++ b/drivers/media/dvb-frontends/ds3000.c @@ -277,10 +277,8 @@ static int ds3000_writeFW(struct ds3000_state *state, int reg, u8 *buf; buf = kmalloc(33, GFP_KERNEL); - if (buf == NULL) { - printk(KERN_ERR "Unable to kmalloc\n"); + if (!buf) return -ENOMEM; - } *(buf) = reg; @@ -842,10 +840,8 @@ struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, /* allocate memory for the internal state */ state = kzalloc(sizeof(struct ds3000_state), GFP_KERNEL); - if (state == NULL) { - printk(KERN_ERR "Unable to kmalloc\n"); + if (!state) goto error2; - } state->config = config; state->i2c = i2c; diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index e8ac8c3e2ec0..340984100aec 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -2072,11 +2072,8 @@ struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config, /* allocate memory for the internal state */ state = kzalloc(sizeof(struct mb86a20s_state), GFP_KERNEL); - if (state == NULL) { - dev_err(&i2c->dev, - "%s: unable to allocate memory for state\n", __func__); + if (!state) goto error; - } /* setup the state */ state->config = config; diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 172fc367ccaa..41d9c513b7e8 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -696,7 +696,6 @@ static int si2168_probe(struct i2c_client *client, dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { ret = -ENOMEM; - dev_err(&client->dev, "kzalloc() failed\n"); goto err; } diff --git a/drivers/media/dvb-frontends/sp2.c b/drivers/media/dvb-frontends/sp2.c index 43d47dfcc7b8..d3b4f8822096 100644 --- a/drivers/media/dvb-frontends/sp2.c +++ b/drivers/media/dvb-frontends/sp2.c @@ -384,7 +384,6 @@ static int sp2_probe(struct i2c_client *client, s = kzalloc(sizeof(struct sp2), GFP_KERNEL); if (!s) { ret = -ENOMEM; - dev_err(&client->dev, "kzalloc() failed\n"); goto err; } diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index f289b8aca1da..5217f9ad5e6b 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -3316,10 +3316,8 @@ static int adv76xx_probe(struct i2c_client *client, client->addr << 1); state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); - if (!state) { - v4l_err(client, "Could not allocate adv76xx_state memory!\n"); + if (!state) return -ENOMEM; - } state->i2c_clients[ADV76XX_PAGE_IO] = client; diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 65f34e7e146f..c582bcb782a6 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -3468,10 +3468,8 @@ static int adv7842_probe(struct i2c_client *client, } state = devm_kzalloc(&client->dev, sizeof(struct adv7842_state), GFP_KERNEL); - if (!state) { - v4l_err(client, "Could not allocate adv7842_state memory!\n"); + if (!state) return -ENOMEM; - } /* platform data */ state->pdata = *pdata; diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index 8654710464cc..9e99c6ef1476 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c @@ -910,11 +910,9 @@ static int cx18_probe(struct pci_dev *pci_dev, } cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC); - if (cx == NULL) { - printk(KERN_ERR "cx18: cannot manage card %d, out of memory\n", - i); + if (!cx) return -ENOMEM; - } + cx->pci_dev = pci_dev; cx->instance = i; diff --git a/drivers/media/pci/mantis/hopper_cards.c b/drivers/media/pci/mantis/hopper_cards.c index 11e987860b23..0c91df34ec67 100644 --- a/drivers/media/pci/mantis/hopper_cards.c +++ b/drivers/media/pci/mantis/hopper_cards.c @@ -165,7 +165,6 @@ static int hopper_pci_probe(struct pci_dev *pdev, mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); if (mantis == NULL) { - printk(KERN_ERR "%s ERROR: Out of memory\n", __func__); err = -ENOMEM; goto fail0; } diff --git a/drivers/media/pci/mantis/mantis_cards.c b/drivers/media/pci/mantis/mantis_cards.c index adc980d33711..2dba030c7132 100644 --- a/drivers/media/pci/mantis/mantis_cards.c +++ b/drivers/media/pci/mantis/mantis_cards.c @@ -174,10 +174,8 @@ static int mantis_pci_probe(struct pci_dev *pdev, int err = 0; mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); - if (mantis == NULL) { - printk(KERN_ERR "%s ERROR: Out of memory\n", __func__); + if (!mantis) return -ENOMEM; - } drvdata = (void *)pci_id->driver_data; mantis->num = devs; diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c index 49e047e4a81e..af9cd02fac0c 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/media/pci/meye/meye.c @@ -1626,23 +1626,18 @@ static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) meye.mchip_dev = pcidev; meye.grab_temp = vmalloc(MCHIP_NB_PAGES_MJPEG * PAGE_SIZE); - if (!meye.grab_temp) { - v4l2_err(v4l2_dev, "grab buffer allocation failed\n"); + if (!meye.grab_temp) goto outvmalloc; - } spin_lock_init(&meye.grabq_lock); if (kfifo_alloc(&meye.grabq, sizeof(int) * MEYE_MAX_BUFNBRS, - GFP_KERNEL)) { - v4l2_err(v4l2_dev, "fifo allocation failed\n"); + GFP_KERNEL)) goto outkfifoalloc1; - } + spin_lock_init(&meye.doneq_lock); if (kfifo_alloc(&meye.doneq, sizeof(int) * MEYE_MAX_BUFNBRS, - GFP_KERNEL)) { - v4l2_err(v4l2_dev, "fifo allocation failed\n"); + GFP_KERNEL)) goto outkfifoalloc2; - } meye.vdev = meye_template; meye.vdev.v4l2_dev = &meye.v4l2_dev; diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c index f708cab01fef..32c19bad9a17 100644 --- a/drivers/media/pci/saa7146/hexium_gemini.c +++ b/drivers/media/pci/saa7146/hexium_gemini.c @@ -261,10 +261,9 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d DEB_EE("\n"); hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL); - if (NULL == hexium) { - pr_err("not enough kernel memory in hexium_attach()\n"); + if (!hexium) return -ENOMEM; - } + dev->ext_priv = hexium; /* enable i2c-port pins */ diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c index 01f01580c7ca..8d1dc8eea988 100644 --- a/drivers/media/pci/saa7146/hexium_orion.c +++ b/drivers/media/pci/saa7146/hexium_orion.c @@ -220,10 +220,8 @@ static int hexium_probe(struct saa7146_dev *dev) } hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL); - if (NULL == hexium) { - pr_err("hexium_probe: not enough kernel memory\n"); + if (!hexium) return -ENOMEM; - } /* enable i2c-port pins */ saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26)); diff --git a/drivers/media/pci/saa7164/saa7164-buffer.c b/drivers/media/pci/saa7164/saa7164-buffer.c index a0d2129c6ca9..6bd665ea190d 100644 --- a/drivers/media/pci/saa7164/saa7164-buffer.c +++ b/drivers/media/pci/saa7164/saa7164-buffer.c @@ -99,10 +99,8 @@ struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_port *port, } buf = kzalloc(sizeof(struct saa7164_buffer), GFP_KERNEL); - if (!buf) { - log_warn("%s() SAA_ERR_NO_RESOURCES\n", __func__); + if (!buf) goto ret; - } buf->idx = -1; buf->port = port; diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index d7103c5f92c3..db410c558a74 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -1507,10 +1507,8 @@ static int isc_formats_init(struct isc_device *isc) isc->user_formats = devm_kcalloc(isc->dev, num_fmts, sizeof(struct isc_format *), GFP_KERNEL); - if (!isc->user_formats) { - v4l2_err(&isc->v4l2_dev, "could not allocate memory\n"); + if (!isc->user_formats) return -ENOMEM; - } fmt = &isc_formats[0]; for (i = 0, j = 0; i < ARRAY_SIZE(isc_formats); i++) { diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index 891fa2505efa..154e9c39b64f 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -1038,10 +1038,8 @@ static int isi_formats_init(struct atmel_isi *isi) isi->user_formats = devm_kcalloc(isi->dev, num_fmts, sizeof(struct isi_format *), GFP_KERNEL); - if (!isi->user_formats) { - dev_err(isi->dev, "could not allocate memory\n"); + if (!isi->user_formats) return -ENOMEM; - } memcpy(isi->user_formats, isi_fmts, num_fmts * sizeof(struct isi_format *)); @@ -1176,10 +1174,8 @@ static int atmel_isi_probe(struct platform_device *pdev) int ret, i; isi = devm_kzalloc(&pdev->dev, sizeof(struct atmel_isi), GFP_KERNEL); - if (!isi) { - dev_err(&pdev->dev, "Can't allocate interface!\n"); + if (!isi) return -ENOMEM; - } isi->pclk = devm_clk_get(&pdev->dev, "isi_clk"); if (IS_ERR(isi->pclk)) diff --git a/drivers/media/platform/blackfin/ppi.c b/drivers/media/platform/blackfin/ppi.c index 37169054b828..478eb2f7d723 100644 --- a/drivers/media/platform/blackfin/ppi.c +++ b/drivers/media/platform/blackfin/ppi.c @@ -338,7 +338,6 @@ struct ppi_if *ppi_create_instance(struct platform_device *pdev, ppi = kzalloc(sizeof(*ppi), GFP_KERNEL); if (!ppi) { peripheral_free_list(info->pin_req); - dev_err(&pdev->dev, "unable to allocate memory for ppi handle\n"); return NULL; } ppi->ops = &ppi_ops; diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index 4ff8d0aed015..b50cff4ef9eb 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -209,10 +209,8 @@ static int send_control_msg(struct usb_device *udev, u8 request, u16 value, int status; unsigned char *transfer_buffer = kmalloc(size, GFP_KERNEL); - if (!transfer_buffer) { - dev_err(&udev->dev, "kmalloc(%d) failed\n", size); + if (!transfer_buffer) return -ENOMEM; - } memcpy(transfer_buffer, cp, size); @@ -1424,10 +1422,8 @@ static int zr364xx_probe(struct usb_interface *intf, le16_to_cpu(udev->descriptor.idProduct)); cam = kzalloc(sizeof(struct zr364xx_camera), GFP_KERNEL); - if (cam == NULL) { - dev_err(&udev->dev, "cam: out of memory !\n"); + if (!cam) return -ENOMEM; - } cam->v4l2_dev.release = zr364xx_release; err = v4l2_device_register(&intf->dev, &cam->v4l2_dev); -- cgit v1.2.3 From d303b7c5b2660d93ba0dd2bf99b7dfa7bb93de73 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 30 Aug 2017 02:10:38 -0400 Subject: media: drivers: delete unnecessary variable initialisations The variables will be set to an appropriate value before usage. Thus omit the explicit initialisation at the beginning. [mchehab@s-opensource.com: fold similar patches into one] Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil --- drivers/media/dvb-frontends/cx24116.c | 4 ++-- drivers/media/dvb-frontends/ds3000.c | 2 +- drivers/media/pci/mantis/hopper_cards.c | 2 +- drivers/media/pci/mantis/mantis_cards.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb-frontends/cx24116.c b/drivers/media/dvb-frontends/cx24116.c index 96af4ffba0f9..e5135fbe0297 100644 --- a/drivers/media/dvb-frontends/cx24116.c +++ b/drivers/media/dvb-frontends/cx24116.c @@ -221,7 +221,7 @@ static int cx24116_writereg(struct cx24116_state *state, int reg, int data) static int cx24116_writeregN(struct cx24116_state *state, int reg, const u8 *data, u16 len) { - int ret = -EREMOTEIO; + int ret; struct i2c_msg msg; u8 *buf; @@ -1120,7 +1120,7 @@ static const struct dvb_frontend_ops cx24116_ops; struct dvb_frontend *cx24116_attach(const struct cx24116_config *config, struct i2c_adapter *i2c) { - struct cx24116_state *state = NULL; + struct cx24116_state *state; int ret; dprintk("%s\n", __func__); diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c index c2959a9695a7..293c4103e5ff 100644 --- a/drivers/media/dvb-frontends/ds3000.c +++ b/drivers/media/dvb-frontends/ds3000.c @@ -833,7 +833,7 @@ static const struct dvb_frontend_ops ds3000_ops; struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, struct i2c_adapter *i2c) { - struct ds3000_state *state = NULL; + struct ds3000_state *state; int ret; dprintk("%s\n", __func__); diff --git a/drivers/media/pci/mantis/hopper_cards.c b/drivers/media/pci/mantis/hopper_cards.c index 0c91df34ec67..a96ac0144fd2 100644 --- a/drivers/media/pci/mantis/hopper_cards.c +++ b/drivers/media/pci/mantis/hopper_cards.c @@ -161,7 +161,7 @@ static int hopper_pci_probe(struct pci_dev *pdev, struct mantis_pci_drvdata *drvdata; struct mantis_pci *mantis; struct mantis_hwconfig *config; - int err = 0; + int err; mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); if (mantis == NULL) { diff --git a/drivers/media/pci/mantis/mantis_cards.c b/drivers/media/pci/mantis/mantis_cards.c index 2dba030c7132..9958b6f4405f 100644 --- a/drivers/media/pci/mantis/mantis_cards.c +++ b/drivers/media/pci/mantis/mantis_cards.c @@ -171,7 +171,7 @@ static int mantis_pci_probe(struct pci_dev *pdev, struct mantis_pci_drvdata *drvdata; struct mantis_pci *mantis; struct mantis_hwconfig *config; - int err = 0; + int err; mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); if (!mantis) -- cgit v1.2.3 From 2d3da59ff163b2aa805de0fc65ba933a735b00cd Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 28 Aug 2017 05:55:16 -0400 Subject: media: drivers: improve a size determination Replace the specification of a data structure by a pointer dereference as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. [mchehab@s-opensoure.com: merge similar patches into one] Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil --- drivers/media/common/cypress_firmware.c | 2 +- drivers/media/common/siano/smscoreapi.c | 14 ++++++-------- drivers/media/dvb-frontends/as102_fe.c | 2 +- drivers/media/dvb-frontends/cx24113.c | 3 +-- drivers/media/dvb-frontends/cx24116.c | 2 +- drivers/media/dvb-frontends/ds3000.c | 2 +- drivers/media/dvb-frontends/mb86a20s.c | 2 +- drivers/media/dvb-frontends/sp2.c | 2 +- drivers/media/i2c/adv7842.c | 2 +- drivers/media/pci/cx18/cx18-driver.c | 2 +- drivers/media/pci/mantis/hopper_cards.c | 2 +- drivers/media/pci/mantis/mantis_cards.c | 2 +- drivers/media/pci/saa7146/hexium_gemini.c | 2 +- drivers/media/pci/saa7146/hexium_orion.c | 2 +- drivers/media/pci/saa7164/saa7164-buffer.c | 4 ++-- drivers/media/platform/atmel/atmel-isc.c | 2 +- drivers/media/usb/zr364xx/zr364xx.c | 2 +- 17 files changed, 23 insertions(+), 26 deletions(-) diff --git a/drivers/media/common/cypress_firmware.c b/drivers/media/common/cypress_firmware.c index bfe47bc5f716..8895158c1962 100644 --- a/drivers/media/common/cypress_firmware.c +++ b/drivers/media/common/cypress_firmware.c @@ -74,7 +74,7 @@ int cypress_load_firmware(struct usb_device *udev, struct hexline *hx; int ret, pos = 0; - hx = kmalloc(sizeof(struct hexline), GFP_KERNEL); + hx = kmalloc(sizeof(*hx), GFP_KERNEL); if (!hx) return -ENOMEM; diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 889b486fbc72..ad1c41f727b1 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -447,7 +447,7 @@ static struct smscore_registry_entry_t *smscore_find_registry(char *devpath) return entry; } } - entry = kmalloc(sizeof(struct smscore_registry_entry_t), GFP_KERNEL); + entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (entry) { entry->mode = default_mode; strcpy(entry->devpath, devpath); @@ -536,9 +536,7 @@ int smscore_register_hotplug(hotplug_t hotplug) int rc = 0; kmutex_lock(&g_smscore_deviceslock); - - notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t), - GFP_KERNEL); + notifyee = kmalloc(sizeof(*notifyee), GFP_KERNEL); if (notifyee) { /* now notify callback about existing devices */ first = &g_smscore_devices; @@ -627,7 +625,7 @@ smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer, { struct smscore_buffer_t *cb; - cb = kzalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL); + cb = kzalloc(sizeof(*cb), GFP_KERNEL); if (!cb) return NULL; @@ -655,7 +653,7 @@ int smscore_register_device(struct smsdevice_params_t *params, struct smscore_device_t *dev; u8 *buffer; - dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; @@ -1684,7 +1682,7 @@ static int smscore_validate_client(struct smscore_device_t *coredev, pr_err("The msg ID already registered to another client.\n"); return -EEXIST; } - listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL); + listentry = kzalloc(sizeof(*listentry), GFP_KERNEL); if (!listentry) return -ENOMEM; @@ -1721,7 +1719,7 @@ int smscore_register_client(struct smscore_device_t *coredev, return -EEXIST; } - newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL); + newclient = kzalloc(sizeof(*newclient), GFP_KERNEL); if (!newclient) return -ENOMEM; diff --git a/drivers/media/dvb-frontends/as102_fe.c b/drivers/media/dvb-frontends/as102_fe.c index 1fb4ab21d786..b1c84ee914f0 100644 --- a/drivers/media/dvb-frontends/as102_fe.c +++ b/drivers/media/dvb-frontends/as102_fe.c @@ -455,7 +455,7 @@ struct dvb_frontend *as102_attach(const char *name, struct as102_state *state; struct dvb_frontend *fe; - state = kzalloc(sizeof(struct as102_state), GFP_KERNEL); + state = kzalloc(sizeof(*state), GFP_KERNEL); if (!state) return NULL; diff --git a/drivers/media/dvb-frontends/cx24113.c b/drivers/media/dvb-frontends/cx24113.c index 8fc7333c76b7..2c5502cab5e1 100644 --- a/drivers/media/dvb-frontends/cx24113.c +++ b/drivers/media/dvb-frontends/cx24113.c @@ -552,8 +552,7 @@ struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe, const struct cx24113_config *config, struct i2c_adapter *i2c) { /* allocate memory for the internal state */ - struct cx24113_state *state = - kzalloc(sizeof(struct cx24113_state), GFP_KERNEL); + struct cx24113_state *state = kzalloc(sizeof(*state), GFP_KERNEL); int rc; if (!state) diff --git a/drivers/media/dvb-frontends/cx24116.c b/drivers/media/dvb-frontends/cx24116.c index e5135fbe0297..531c5861a27e 100644 --- a/drivers/media/dvb-frontends/cx24116.c +++ b/drivers/media/dvb-frontends/cx24116.c @@ -1126,7 +1126,7 @@ struct dvb_frontend *cx24116_attach(const struct cx24116_config *config, dprintk("%s\n", __func__); /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct cx24116_state), GFP_KERNEL); + state = kzalloc(sizeof(*state), GFP_KERNEL); if (state == NULL) goto error1; diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c index 293c4103e5ff..3e347d03acb3 100644 --- a/drivers/media/dvb-frontends/ds3000.c +++ b/drivers/media/dvb-frontends/ds3000.c @@ -839,7 +839,7 @@ struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, dprintk("%s\n", __func__); /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct ds3000_state), GFP_KERNEL); + state = kzalloc(sizeof(*state), GFP_KERNEL); if (!state) goto error2; diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 340984100aec..ba7a433dd424 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -2071,7 +2071,7 @@ struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config, dev_dbg(&i2c->dev, "%s called.\n", __func__); /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct mb86a20s_state), GFP_KERNEL); + state = kzalloc(sizeof(*state), GFP_KERNEL); if (!state) goto error; diff --git a/drivers/media/dvb-frontends/sp2.c b/drivers/media/dvb-frontends/sp2.c index d3b4f8822096..dd556012ceb6 100644 --- a/drivers/media/dvb-frontends/sp2.c +++ b/drivers/media/dvb-frontends/sp2.c @@ -381,7 +381,7 @@ static int sp2_probe(struct i2c_client *client, dev_dbg(&client->dev, "\n"); - s = kzalloc(sizeof(struct sp2), GFP_KERNEL); + s = kzalloc(sizeof(*s), GFP_KERNEL); if (!s) { ret = -ENOMEM; goto err; diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index c582bcb782a6..136aa80a834b 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -3467,7 +3467,7 @@ static int adv7842_probe(struct i2c_client *client, return -ENODEV; } - state = devm_kzalloc(&client->dev, sizeof(struct adv7842_state), GFP_KERNEL); + state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); if (!state) return -ENOMEM; diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index 9e99c6ef1476..6efa93168059 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c @@ -909,7 +909,7 @@ static int cx18_probe(struct pci_dev *pci_dev, return -ENOMEM; } - cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC); + cx = kzalloc(sizeof(*cx), GFP_ATOMIC); if (!cx) return -ENOMEM; diff --git a/drivers/media/pci/mantis/hopper_cards.c b/drivers/media/pci/mantis/hopper_cards.c index a96ac0144fd2..ecb97dc381fb 100644 --- a/drivers/media/pci/mantis/hopper_cards.c +++ b/drivers/media/pci/mantis/hopper_cards.c @@ -163,7 +163,7 @@ static int hopper_pci_probe(struct pci_dev *pdev, struct mantis_hwconfig *config; int err; - mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); + mantis = kzalloc(sizeof(*mantis), GFP_KERNEL); if (mantis == NULL) { err = -ENOMEM; goto fail0; diff --git a/drivers/media/pci/mantis/mantis_cards.c b/drivers/media/pci/mantis/mantis_cards.c index 9958b6f4405f..4ce8a90d69dc 100644 --- a/drivers/media/pci/mantis/mantis_cards.c +++ b/drivers/media/pci/mantis/mantis_cards.c @@ -173,7 +173,7 @@ static int mantis_pci_probe(struct pci_dev *pdev, struct mantis_hwconfig *config; int err; - mantis = kzalloc(sizeof(struct mantis_pci), GFP_KERNEL); + mantis = kzalloc(sizeof(*mantis), GFP_KERNEL); if (!mantis) return -ENOMEM; diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c index 32c19bad9a17..d31a2d4494d1 100644 --- a/drivers/media/pci/saa7146/hexium_gemini.c +++ b/drivers/media/pci/saa7146/hexium_gemini.c @@ -260,7 +260,7 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d DEB_EE("\n"); - hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL); + hexium = kzalloc(sizeof(*hexium), GFP_KERNEL); if (!hexium) return -ENOMEM; diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c index 8d1dc8eea988..7dc182202f8b 100644 --- a/drivers/media/pci/saa7146/hexium_orion.c +++ b/drivers/media/pci/saa7146/hexium_orion.c @@ -219,7 +219,7 @@ static int hexium_probe(struct saa7146_dev *dev) return -EFAULT; } - hexium = kzalloc(sizeof(struct hexium), GFP_KERNEL); + hexium = kzalloc(sizeof(*hexium), GFP_KERNEL); if (!hexium) return -ENOMEM; diff --git a/drivers/media/pci/saa7164/saa7164-buffer.c b/drivers/media/pci/saa7164/saa7164-buffer.c index 6bd665ea190d..c83b2e914dcb 100644 --- a/drivers/media/pci/saa7164/saa7164-buffer.c +++ b/drivers/media/pci/saa7164/saa7164-buffer.c @@ -98,7 +98,7 @@ struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_port *port, goto ret; } - buf = kzalloc(sizeof(struct saa7164_buffer), GFP_KERNEL); + buf = kzalloc(sizeof(*buf), GFP_KERNEL); if (!buf) goto ret; @@ -281,7 +281,7 @@ struct saa7164_user_buffer *saa7164_buffer_alloc_user(struct saa7164_dev *dev, { struct saa7164_user_buffer *buf; - buf = kzalloc(sizeof(struct saa7164_user_buffer), GFP_KERNEL); + buf = kzalloc(sizeof(*buf), GFP_KERNEL); if (!buf) return NULL; diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index db410c558a74..755d2d4dd142 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -1505,7 +1505,7 @@ static int isc_formats_init(struct isc_device *isc) isc->num_user_formats = num_fmts; isc->user_formats = devm_kcalloc(isc->dev, - num_fmts, sizeof(struct isc_format *), + num_fmts, sizeof(*isc->user_formats), GFP_KERNEL); if (!isc->user_formats) return -ENOMEM; diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index b50cff4ef9eb..b3d05027bd9a 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -1421,7 +1421,7 @@ static int zr364xx_probe(struct usb_interface *intf, le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); - cam = kzalloc(sizeof(struct zr364xx_camera), GFP_KERNEL); + cam = kzalloc(sizeof(*cam), GFP_KERNEL); if (!cam) return -ENOMEM; -- cgit v1.2.3 From af28c99628ebfbdc3fff3d92c7044d3a51b7ccea Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Mon, 28 Aug 2017 06:50:28 -0400 Subject: media: drivers: Adjust checks for null pointers The script “checkpatch.pl” pointed information out like the following. Comparison to NULL could be written !… Thus fix the affected source code places. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil --- drivers/media/common/siano/smscoreapi.c | 12 ++++++------ drivers/media/dvb-frontends/drxd_hard.c | 6 +++--- drivers/media/dvb-frontends/sp2.c | 6 +++--- drivers/media/i2c/adv7604.c | 6 +++--- drivers/media/pci/cx18/cx18-driver.c | 20 ++++++++++---------- drivers/media/pci/mantis/hopper_cards.c | 4 ++-- drivers/media/platform/atmel/atmel-isc.c | 6 +++--- drivers/media/platform/atmel/atmel-isi.c | 6 +++--- drivers/media/usb/zr364xx/zr364xx.c | 22 +++++++++++----------- 9 files changed, 44 insertions(+), 44 deletions(-) diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index ad1c41f727b1..e4ea2a0c7a24 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -749,7 +749,7 @@ static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev, void *buffer, size_t size, struct completion *completion) { int rc; - if (completion == NULL) + if (!completion) return -EINVAL; init_completion(completion); @@ -1151,8 +1151,8 @@ static int smscore_load_firmware_from_file(struct smscore_device_t *coredev, } pr_debug("Firmware name: %s\n", fw_filename); - if (loadfirmware_handler == NULL && !(coredev->device_flags - & SMS_DEVICE_FAMILY2)) + if (!loadfirmware_handler && + !(coredev->device_flags & SMS_DEVICE_FAMILY2)) return -EINVAL; rc = request_firmware(&fw, fw_filename, coredev->device); @@ -1789,7 +1789,7 @@ int smsclient_sendrequest(struct smscore_client_t *client, struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) buffer; int rc; - if (client == NULL) { + if (!client) { pr_err("Got NULL client\n"); return -EINVAL; } @@ -1797,7 +1797,7 @@ int smsclient_sendrequest(struct smscore_client_t *client, coredev = client->coredev; /* check that no other channel with same id exists */ - if (coredev == NULL) { + if (!coredev) { pr_err("Got NULL coredev\n"); return -EINVAL; } @@ -1954,7 +1954,7 @@ int smscore_gpio_configure(struct smscore_device_t *coredev, u8 pin_num, if (pin_num > MAX_GPIO_PIN_NUMBER) return -EINVAL; - if (p_gpio_config == NULL) + if (!p_gpio_config) return -EINVAL; total_len = sizeof(struct sms_msg_hdr) + (sizeof(u32) * 6); diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index 47b0d37e70ba..3bdf9b1f4e7c 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -328,7 +328,7 @@ static int WriteTable(struct drxd_state *state, u8 * pTable) { int status = 0; - if (pTable == NULL) + if (!pTable) return 0; while (!status) { @@ -909,7 +909,7 @@ static int load_firmware(struct drxd_state *state, const char *fw_name) } state->microcode = kmemdup(fw->data, fw->size, GFP_KERNEL); - if (state->microcode == NULL) { + if (!state->microcode) { release_firmware(fw); return -ENOMEM; } @@ -2629,7 +2629,7 @@ static int DRXD_init(struct drxd_state *state, const u8 *fw, u32 fw_size) break; /* Apply I2c address patch to B1 */ - if (!state->type_A && state->m_HiI2cPatch != NULL) { + if (!state->type_A && state->m_HiI2cPatch) { status = WriteTable(state, state->m_HiI2cPatch); if (status < 0) break; diff --git a/drivers/media/dvb-frontends/sp2.c b/drivers/media/dvb-frontends/sp2.c index dd556012ceb6..53e66c232d3c 100644 --- a/drivers/media/dvb-frontends/sp2.c +++ b/drivers/media/dvb-frontends/sp2.c @@ -357,14 +357,14 @@ static int sp2_exit(struct i2c_client *client) dev_dbg(&client->dev, "\n"); - if (client == NULL) + if (!client) return 0; s = i2c_get_clientdata(client); - if (s == NULL) + if (!s) return 0; - if (s->ca.data == NULL) + if (!s->ca.data) return 0; dvb_ca_en50221_release(&s->ca); diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 5217f9ad5e6b..c786cd125417 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1948,7 +1948,7 @@ static int adv76xx_set_format(struct v4l2_subdev *sd, return -EINVAL; info = adv76xx_format_info(state, format->format.code); - if (info == NULL) + if (!info) info = adv76xx_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8); adv76xx_fill_format(state, &format->format); @@ -2256,7 +2256,7 @@ static int adv76xx_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) return 0; } - if (data == NULL) + if (!data) return -ENODATA; if (edid->start_block >= state->edid.blocks) @@ -3480,7 +3480,7 @@ static int adv76xx_probe(struct i2c_client *client, state->i2c_clients[i] = adv76xx_dummy_client(sd, state->pdata.i2c_addresses[i], 0xf2 + i); - if (state->i2c_clients[i] == NULL) { + if (!state->i2c_clients[i]) { err = -ENOMEM; v4l2_err(sd, "failed to create i2c client %u\n", i); goto err_i2c; diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index 6efa93168059..8f314ca320c7 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c @@ -255,7 +255,7 @@ static void request_module_async(struct work_struct *work) request_module("cx18-alsa"); /* Initialize cx18-alsa for this instance of the cx18 device */ - if (cx18_ext_init != NULL) + if (cx18_ext_init) cx18_ext_init(dev); } @@ -291,11 +291,11 @@ int cx18_msleep_timeout(unsigned int msecs, int intr) /* Release ioremapped memory */ static void cx18_iounmap(struct cx18 *cx) { - if (cx == NULL) + if (!cx) return; /* Release io memory */ - if (cx->enc_mem != NULL) { + if (cx->enc_mem) { CX18_DEBUG_INFO("releasing enc_mem\n"); iounmap(cx->enc_mem); cx->enc_mem = NULL; @@ -649,15 +649,15 @@ static void cx18_process_options(struct cx18 *cx) CX18_INFO("User specified %s card\n", cx->card->name); else if (cx->options.cardtype != 0) CX18_ERR("Unknown user specified type, trying to autodetect card\n"); - if (cx->card == NULL) { + if (!cx->card) { if (cx->pci_dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) { cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); CX18_INFO("Autodetected Hauppauge card\n"); } } - if (cx->card == NULL) { + if (!cx->card) { for (i = 0; (cx->card = cx18_get_card(i)); i++) { - if (cx->card->pci_list == NULL) + if (!cx->card->pci_list) continue; for (j = 0; cx->card->pci_list[j].device; j++) { if (cx->pci_dev->device != @@ -676,7 +676,7 @@ static void cx18_process_options(struct cx18 *cx) } done: - if (cx->card == NULL) { + if (!cx->card) { cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); CX18_ERR("Unknown card: vendor/device: [%04x:%04x]\n", cx->pci_dev->vendor, cx->pci_dev->device); @@ -698,7 +698,7 @@ static int cx18_create_in_workq(struct cx18 *cx) snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in", cx->v4l2_dev.name); cx->in_work_queue = alloc_ordered_workqueue("%s", 0, cx->in_workq_name); - if (cx->in_work_queue == NULL) { + if (!cx->in_work_queue) { CX18_ERR("Unable to create incoming mailbox handler thread\n"); return -ENOMEM; } @@ -1254,7 +1254,7 @@ static void cx18_cancel_out_work_orders(struct cx18 *cx) { int i; for (i = 0; i < CX18_MAX_STREAMS; i++) - if (&cx->streams[i].video_dev != NULL) + if (&cx->streams[i].video_dev) cancel_work_sync(&cx->streams[i].out_work_order); } @@ -1299,7 +1299,7 @@ static void cx18_remove(struct pci_dev *pci_dev) pci_disable_device(cx->pci_dev); - if (cx->vbi.sliced_mpeg_data[0] != NULL) + if (cx->vbi.sliced_mpeg_data[0]) for (i = 0; i < CX18_VBI_FRAMES; i++) kfree(cx->vbi.sliced_mpeg_data[i]); diff --git a/drivers/media/pci/mantis/hopper_cards.c b/drivers/media/pci/mantis/hopper_cards.c index ecb97dc381fb..ed855e3df558 100644 --- a/drivers/media/pci/mantis/hopper_cards.c +++ b/drivers/media/pci/mantis/hopper_cards.c @@ -72,7 +72,7 @@ static irqreturn_t hopper_irq_handler(int irq, void *dev_id) struct mantis_ca *ca; mantis = (struct mantis_pci *) dev_id; - if (unlikely(mantis == NULL)) { + if (unlikely(!mantis)) { dprintk(MANTIS_ERROR, 1, "Mantis == NULL"); return IRQ_NONE; } @@ -164,7 +164,7 @@ static int hopper_pci_probe(struct pci_dev *pdev, int err; mantis = kzalloc(sizeof(*mantis), GFP_KERNEL); - if (mantis == NULL) { + if (!mantis) { err = -ENOMEM; goto fail0; } diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 755d2d4dd142..2f8e345d297e 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -1590,7 +1590,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) spin_lock_init(&isc->dma_queue_lock); sd_entity->config = v4l2_subdev_alloc_pad_config(sd_entity->sd); - if (sd_entity->config == NULL) + if (!sd_entity->config) return -ENOMEM; ret = isc_formats_init(isc); @@ -1714,7 +1714,7 @@ static int isc_parse_dt(struct device *dev, struct isc_device *isc) subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity), GFP_KERNEL); - if (subdev_entity == NULL) { + if (!subdev_entity) { of_node_put(rem); ret = -ENOMEM; break; @@ -1722,7 +1722,7 @@ static int isc_parse_dt(struct device *dev, struct isc_device *isc) subdev_entity->asd = devm_kzalloc(dev, sizeof(*subdev_entity->asd), GFP_KERNEL); - if (subdev_entity->asd == NULL) { + if (!subdev_entity->asd) { of_node_put(rem); ret = -ENOMEM; break; diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index 154e9c39b64f..463c0146915e 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -411,7 +411,7 @@ static void buffer_queue(struct vb2_buffer *vb) spin_lock_irqsave(&isi->irqlock, flags); list_add_tail(&buf->list, &isi->video_buffer_list); - if (isi->active == NULL) { + if (!isi->active) { isi->active = buf; if (vb2_is_streaming(vb->vb2_queue)) start_dma(isi, buf); @@ -1141,7 +1141,7 @@ static int isi_graph_init(struct atmel_isi *isi) /* Register the subdevices notifier. */ subdevs = devm_kzalloc(isi->dev, sizeof(*subdevs), GFP_KERNEL); - if (subdevs == NULL) { + if (!subdevs) { of_node_put(isi->entity.node); return -ENOMEM; } @@ -1200,7 +1200,7 @@ static int atmel_isi_probe(struct platform_device *pdev) return ret; isi->vdev = video_device_alloc(); - if (isi->vdev == NULL) { + if (!isi->vdev) { ret = -ENOMEM; goto err_vdev_alloc; } diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index b3d05027bd9a..1d888661fd03 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -385,9 +385,9 @@ static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, vb); int rc; - DBG("%s, field=%d, fmt name = %s\n", __func__, field, cam->fmt != NULL ? - cam->fmt->name : ""); - if (cam->fmt == NULL) + DBG("%s, field=%d, fmt name = %s\n", __func__, field, + cam->fmt ? cam->fmt->name : ""); + if (!cam->fmt) return -EINVAL; buf->vb.size = cam->width * cam->height * (cam->fmt->depth >> 3); @@ -787,7 +787,7 @@ static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct zr364xx_camera *cam = video_drvdata(file); char pixelformat_name[5]; - if (cam == NULL) + if (!cam) return -ENODEV; if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) { @@ -817,7 +817,7 @@ static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv, { struct zr364xx_camera *cam; - if (file == NULL) + if (!file) return -ENODEV; cam = video_drvdata(file); @@ -979,13 +979,13 @@ static void read_pipe_completion(struct urb *purb) pipe_info = purb->context; _DBG("%s %p, status %d\n", __func__, purb, purb->status); - if (pipe_info == NULL) { + if (!pipe_info) { printk(KERN_ERR KBUILD_MODNAME ": no context!\n"); return; } cam = pipe_info->cam; - if (cam == NULL) { + if (!cam) { printk(KERN_ERR KBUILD_MODNAME ": no context!\n"); return; } @@ -1069,7 +1069,7 @@ static void zr364xx_stop_readpipe(struct zr364xx_camera *cam) { struct zr364xx_pipeinfo *pipe_info; - if (cam == NULL) { + if (!cam) { printk(KERN_ERR KBUILD_MODNAME ": invalid device\n"); return; } @@ -1273,7 +1273,7 @@ static int zr364xx_mmap(struct file *file, struct vm_area_struct *vma) struct zr364xx_camera *cam = video_drvdata(file); int ret; - if (cam == NULL) { + if (!cam) { DBG("%s: cam == NULL\n", __func__); return -ENODEV; } @@ -1357,7 +1357,7 @@ static int zr364xx_board_init(struct zr364xx_camera *cam) pipe->transfer_buffer = kzalloc(pipe->transfer_size, GFP_KERNEL); - if (pipe->transfer_buffer == NULL) { + if (!pipe->transfer_buffer) { DBG("out of memory!\n"); return -ENOMEM; } @@ -1373,7 +1373,7 @@ static int zr364xx_board_init(struct zr364xx_camera *cam) DBG("valloc %p, idx %lu, pdata %p\n", &cam->buffer.frame[i], i, cam->buffer.frame[i].lpvbits); - if (cam->buffer.frame[i].lpvbits == NULL) { + if (!cam->buffer.frame[i].lpvbits) { printk(KERN_INFO KBUILD_MODNAME ": out of memory. Using less frames\n"); break; } -- cgit v1.2.3 From 9722e5696ca729044462c4456ddde90061809f7e Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 30 Aug 2017 02:44:29 -0400 Subject: media: dvb-frontends: delete jump targets * Return directly after a call of the function "kzalloc" failed at the beginning. * Move a bit of exception handling code into an if branch. * Delete jump targets which became unnecessary with this refactoring. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil --- drivers/media/dvb-frontends/cx24113.c | 2 +- drivers/media/dvb-frontends/cx24116.c | 15 +++++---------- drivers/media/dvb-frontends/ds3000.c | 10 +++------- drivers/media/dvb-frontends/mb86a20s.c | 16 +++++----------- 4 files changed, 14 insertions(+), 29 deletions(-) diff --git a/drivers/media/dvb-frontends/cx24113.c b/drivers/media/dvb-frontends/cx24113.c index 2c5502cab5e1..ee1f704f81f2 100644 --- a/drivers/media/dvb-frontends/cx24113.c +++ b/drivers/media/dvb-frontends/cx24113.c @@ -556,7 +556,7 @@ struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe, int rc; if (!state) - goto error; + return NULL; /* setup the state */ state->config = config; diff --git a/drivers/media/dvb-frontends/cx24116.c b/drivers/media/dvb-frontends/cx24116.c index 531c5861a27e..8fb3f095e21c 100644 --- a/drivers/media/dvb-frontends/cx24116.c +++ b/drivers/media/dvb-frontends/cx24116.c @@ -226,10 +226,8 @@ static int cx24116_writeregN(struct cx24116_state *state, int reg, u8 *buf; buf = kmalloc(len + 1, GFP_KERNEL); - if (buf == NULL) { - ret = -ENOMEM; - goto error; - } + if (!buf) + return -ENOMEM; *(buf) = reg; memcpy(buf + 1, data, len); @@ -250,7 +248,6 @@ static int cx24116_writeregN(struct cx24116_state *state, int reg, ret = -EREMOTEIO; } -error: kfree(buf); return ret; @@ -1128,7 +1125,7 @@ struct dvb_frontend *cx24116_attach(const struct cx24116_config *config, /* allocate memory for the internal state */ state = kzalloc(sizeof(*state), GFP_KERNEL); if (state == NULL) - goto error1; + return NULL; state->config = config; state->i2c = i2c; @@ -1137,8 +1134,9 @@ struct dvb_frontend *cx24116_attach(const struct cx24116_config *config, ret = (cx24116_readreg(state, 0xFF) << 8) | cx24116_readreg(state, 0xFE); if (ret != 0x0501) { + kfree(state); printk(KERN_INFO "Invalid probe, probably not a CX24116 device\n"); - goto error2; + return NULL; } /* create dvb_frontend */ @@ -1146,9 +1144,6 @@ struct dvb_frontend *cx24116_attach(const struct cx24116_config *config, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; - -error2: kfree(state); -error1: return NULL; } EXPORT_SYMBOL(cx24116_attach); diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c index 3e347d03acb3..bd4f8278c906 100644 --- a/drivers/media/dvb-frontends/ds3000.c +++ b/drivers/media/dvb-frontends/ds3000.c @@ -841,7 +841,7 @@ struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, /* allocate memory for the internal state */ state = kzalloc(sizeof(*state), GFP_KERNEL); if (!state) - goto error2; + return NULL; state->config = config; state->i2c = i2c; @@ -850,8 +850,9 @@ struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, /* check if the demod is present */ ret = ds3000_readreg(state, 0x00) & 0xfe; if (ret != 0xe0) { + kfree(state); printk(KERN_ERR "Invalid probe, probably not a DS3000\n"); - goto error3; + return NULL; } printk(KERN_INFO "DS3000 chip version: %d.%d attached.\n", @@ -869,11 +870,6 @@ struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, */ ds3000_set_voltage(&state->frontend, SEC_VOLTAGE_OFF); return &state->frontend; - -error3: - kfree(state); -error2: - return NULL; } EXPORT_SYMBOL(ds3000_attach); diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index ba7a433dd424..bdaf9d235fed 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -2073,7 +2073,7 @@ struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config, /* allocate memory for the internal state */ state = kzalloc(sizeof(*state), GFP_KERNEL); if (!state) - goto error; + return NULL; /* setup the state */ state->config = config; @@ -2086,22 +2086,16 @@ struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config, /* Check if it is a mb86a20s frontend */ rev = mb86a20s_readreg(state, 0); - - if (rev == 0x13) { - dev_info(&i2c->dev, - "Detected a Fujitsu mb86a20s frontend\n"); - } else { + if (rev != 0x13) { + kfree(state); dev_dbg(&i2c->dev, "Frontend revision %d is unknown - aborting.\n", rev); - goto error; + return NULL; } + dev_info(&i2c->dev, "Detected a Fujitsu mb86a20s frontend\n"); return &state->frontend; - -error: - kfree(state); - return NULL; } EXPORT_SYMBOL(mb86a20s_attach); -- cgit v1.2.3 From 2b83247f3e4a40c767dcbc149b7ad544e2e6c002 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Mon, 28 Aug 2017 03:21:35 -0400 Subject: media: usb: make i2c_client const Make these const as they are only used in a copy operation. Done using Coccinelle. @match disable optional_qualifier@ identifier s; @@ static struct i2c_client s = {...}; @ref@ position p; identifier match.s; @@ s@p @good1@ position ref.p; identifier match.s,f,c; expression e; @@ ( e = s@p | e = s@p.f | c(...,s@p.f,...) | c(...,s@p,...) ) @bad depends on !good1@ position ref.p; identifier match.s; @@ s@p @depends on forall !bad disable optional_qualifier@ identifier match.s; @@ static + const struct i2c_client s; Signed-off-by: Bhumika Goyal Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-i2c.c | 2 +- drivers/media/usb/em28xx/em28xx-i2c.c | 2 +- drivers/media/usb/stk1160/stk1160-i2c.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-i2c.c b/drivers/media/usb/au0828/au0828-i2c.c index ef7d1b830ca3..1b8ec5d9e7ab 100644 --- a/drivers/media/usb/au0828/au0828-i2c.c +++ b/drivers/media/usb/au0828/au0828-i2c.c @@ -342,7 +342,7 @@ static const struct i2c_adapter au0828_i2c_adap_template = { .algo = &au0828_i2c_algo_template, }; -static struct i2c_client au0828_i2c_client_template = { +static const struct i2c_client au0828_i2c_client_template = { .name = "au0828 internal", }; diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 66c5012a628a..9bf49d666e5a 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -882,7 +882,7 @@ static const struct i2c_adapter em28xx_adap_template = { .algo = &em28xx_algo, }; -static struct i2c_client em28xx_client_template = { +static const struct i2c_client em28xx_client_template = { .name = "em28xx internal", }; diff --git a/drivers/media/usb/stk1160/stk1160-i2c.c b/drivers/media/usb/stk1160/stk1160-i2c.c index 2c70173e3c82..62a12d5356ad 100644 --- a/drivers/media/usb/stk1160/stk1160-i2c.c +++ b/drivers/media/usb/stk1160/stk1160-i2c.c @@ -246,7 +246,7 @@ static const struct i2c_adapter adap_template = { .algo = &algo, }; -static struct i2c_client client_template = { +static const struct i2c_client client_template = { .name = "stk1160 internal", }; -- cgit v1.2.3 From b8e9b36d2fc463d87f7b595fedf7ed7ae68dba1d Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Mon, 28 Aug 2017 03:42:09 -0400 Subject: media: pci: make i2c_client const Make these const as they are only used in a copy operation. Done using Coccinelle. Signed-off-by: Bhumika Goyal Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-i2c.c | 2 +- drivers/media/pci/cx25821/cx25821-i2c.c | 2 +- drivers/media/pci/ivtv/ivtv-i2c.c | 2 +- drivers/media/pci/saa7134/saa7134-i2c.c | 2 +- drivers/media/pci/saa7164/saa7164-i2c.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/pci/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c index 0f21467ae88e..ef863492c0ac 100644 --- a/drivers/media/pci/cx23885/cx23885-i2c.c +++ b/drivers/media/pci/cx23885/cx23885-i2c.c @@ -270,7 +270,7 @@ static const struct i2c_adapter cx23885_i2c_adap_template = { .algo = &cx23885_i2c_algo_template, }; -static struct i2c_client cx23885_i2c_client_template = { +static const struct i2c_client cx23885_i2c_client_template = { .name = "cx23885 internal", }; diff --git a/drivers/media/pci/cx25821/cx25821-i2c.c b/drivers/media/pci/cx25821/cx25821-i2c.c index 000049d3c71b..31479a41f359 100644 --- a/drivers/media/pci/cx25821/cx25821-i2c.c +++ b/drivers/media/pci/cx25821/cx25821-i2c.c @@ -291,7 +291,7 @@ static const struct i2c_adapter cx25821_i2c_adap_template = { .algo = &cx25821_i2c_algo_template, }; -static struct i2c_client cx25821_i2c_client_template = { +static const struct i2c_client cx25821_i2c_client_template = { .name = "cx25821 internal", }; diff --git a/drivers/media/pci/ivtv/ivtv-i2c.c b/drivers/media/pci/ivtv/ivtv-i2c.c index 5a35e366f4c0..893962ac85de 100644 --- a/drivers/media/pci/ivtv/ivtv-i2c.c +++ b/drivers/media/pci/ivtv/ivtv-i2c.c @@ -700,7 +700,7 @@ static const struct i2c_algo_bit_data ivtv_i2c_algo_template = { .timeout = IVTV_ALGO_BIT_TIMEOUT * HZ, /* jiffies */ }; -static struct i2c_client ivtv_i2c_client_template = { +static const struct i2c_client ivtv_i2c_client_template = { .name = "ivtv internal", }; diff --git a/drivers/media/pci/saa7134/saa7134-i2c.c b/drivers/media/pci/saa7134/saa7134-i2c.c index 8f2ed632840f..cf1e526de56a 100644 --- a/drivers/media/pci/saa7134/saa7134-i2c.c +++ b/drivers/media/pci/saa7134/saa7134-i2c.c @@ -345,7 +345,7 @@ static const struct i2c_adapter saa7134_adap_template = { .algo = &saa7134_algo, }; -static struct i2c_client saa7134_client_template = { +static const struct i2c_client saa7134_client_template = { .name = "saa7134 internal", }; diff --git a/drivers/media/pci/saa7164/saa7164-i2c.c b/drivers/media/pci/saa7164/saa7164-i2c.c index 4bcde7c79dc3..6d13cbb9d010 100644 --- a/drivers/media/pci/saa7164/saa7164-i2c.c +++ b/drivers/media/pci/saa7164/saa7164-i2c.c @@ -84,7 +84,7 @@ static const struct i2c_adapter saa7164_i2c_adap_template = { .algo = &saa7164_i2c_algo_template, }; -static struct i2c_client saa7164_i2c_client_template = { +static const struct i2c_client saa7164_i2c_client_template = { .name = "saa7164 internal", }; -- cgit v1.2.3 From bab4cb30dbf798f6d6df798aa23d33fb25f394e0 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 1 Sep 2017 11:35:08 -0400 Subject: media: rtl28xxu: make array rc_nec_tab static const Don't populate the array rc_nec_tab on the stack, instead make it static const. Makes the object code smaller by over 620 bytes: Before: text data bss dec hex filename 49511 17040 64 66615 10437 rtl28xxu.o After: text data bss dec hex filename 48825 17104 64 65993 101c9 rtl28xxu.o Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/rtl28xxu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 95a7b9123f8e..c76e78f9638a 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -1598,7 +1598,7 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d) struct rtl28xxu_dev *dev = d->priv; u8 buf[5]; u32 rc_code; - struct rtl28xxu_reg_val rc_nec_tab[] = { + static const struct rtl28xxu_reg_val rc_nec_tab[] = { { 0x3033, 0x80 }, { 0x3020, 0x43 }, { 0x3021, 0x16 }, -- cgit v1.2.3 From f71c43060aa534df9ae2a055be983bd7194c4a13 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Fri, 1 Sep 2017 15:43:45 -0400 Subject: media: dvb-frontends/mxl5xx: declare LIST_HEAD(mxllist) static Fixes one sparse warning: mxl5xx.c:46:1: warning: symbol 'mxllist' was not declared. Should it be static? Signed-off-by: Daniel Scheller Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mxl5xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/mxl5xx.c b/drivers/media/dvb-frontends/mxl5xx.c index 676c96c216c3..53064e11f5f1 100644 --- a/drivers/media/dvb-frontends/mxl5xx.c +++ b/drivers/media/dvb-frontends/mxl5xx.c @@ -43,7 +43,7 @@ #define BYTE2(v) ((v >> 16) & 0xff) #define BYTE3(v) ((v >> 24) & 0xff) -LIST_HEAD(mxllist); +static LIST_HEAD(mxllist); struct mxl_base { struct list_head mxllist; -- cgit v1.2.3 From 1f679ff6c761729607630c731c8bae0f8691ae79 Mon Sep 17 00:00:00 2001 From: Thomas Meyer Date: Sun, 3 Sep 2017 08:19:31 -0400 Subject: media: lgdt3306a: Use ARRAY_SIZE macro Use ARRAY_SIZE macro, rather than explicitly coding some variant of it yourself. Found with: find -type f -name "*.c" -o -name "*.h" | xargs perl -p -i -e 's/\bsizeof\s*\(\s*(\w+)\s*\)\s*\ /\s*sizeof\s*\(\s*\1\s*\[\s*0\s*\]\s*\) /ARRAY_SIZE(\1)/g' and manual check/verification. Signed-off-by: Thomas Meyer Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/lgdt3306a.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index c9b1eb38444e..724e9aac0f11 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -19,6 +19,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include "dvb_math.h" #include "lgdt3306a.h" @@ -2072,7 +2073,7 @@ static const short regtab[] = { 0x30aa, /* MPEGLOCK */ }; -#define numDumpRegs (sizeof(regtab)/sizeof(regtab[0])) +#define numDumpRegs (ARRAY_SIZE(regtab)) static u8 regval1[numDumpRegs] = {0, }; static u8 regval2[numDumpRegs] = {0, }; -- cgit v1.2.3 From 2be730b828c59fc776c8045883c1dc7a37d7b457 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 5 Sep 2017 07:03:32 -0400 Subject: media: cx25840: make array stds static const, reduces object code size Don't populate the array syds on the stack, instead make it static const. Makes the object code smaller by over 280 bytes: Before: text data bss dec hex filename 81451 12784 704 94939 172db cx25840-core.o text data bss dec hex filename 81070 12880 704 94654 171be cx25840-core.o Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/cx25840/cx25840-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 39f51daa7558..f38bf819d805 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -1745,7 +1745,7 @@ static int cx25840_g_std(struct v4l2_subdev *sd, v4l2_std_id *std) { struct i2c_client *client = v4l2_get_subdevdata(sd); - v4l2_std_id stds[] = { + static const v4l2_std_id stds[] = { /* 0000 */ V4L2_STD_UNKNOWN, /* 0001 */ V4L2_STD_NTSC_M, -- cgit v1.2.3 From e90ce8aa3cb2fcfb0fd45f95e89946a15c03737c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 5 Sep 2017 11:19:44 -0400 Subject: media: cobalt: remove redundant zero check on retval The error handling paths all end up with retval being non-zero, so the check for retval being zero is always false and hence is redundant. Remove it. Detected by CoverityScan CID#1309479 ("Logically dead code") Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cobalt/cobalt-driver.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index 98b6cb9505d1..8487ecaa4d30 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.c +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -767,8 +767,6 @@ err_pci: err_wq: destroy_workqueue(cobalt->irq_work_queues); err: - if (retval == 0) - retval = -ENODEV; cobalt_err("error %d on initialization\n", retval); v4l2_device_unregister(&cobalt->v4l2_dev); -- cgit v1.2.3 From 3ff692fad32829b5b2199273d2b35273ecab007f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 6 Sep 2017 09:30:16 -0400 Subject: media: ov9640: make const arrays res_x/y static const, reduces object code size Don't populate the arrays res_x and resy_y on the stack, instead make them static const. Makes the object code smaller by over 160 bytes: Before: text data bss dec hex filename 10509 2800 64 13373 343d ov9640.o After: text data bss dec hex filename 10184 2960 64 13208 3398 ov9640.o Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/soc_camera/ov9640.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/ov9640.c index 0146d1f7aacb..dafea6d90ad9 100644 --- a/drivers/media/i2c/soc_camera/ov9640.c +++ b/drivers/media/i2c/soc_camera/ov9640.c @@ -335,8 +335,8 @@ static void ov9640_res_roundup(u32 *width, u32 *height) { int i; enum { QQCIF, QQVGA, QCIF, QVGA, CIF, VGA, SXGA }; - int res_x[] = { 88, 160, 176, 320, 352, 640, 1280 }; - int res_y[] = { 72, 120, 144, 240, 288, 480, 960 }; + static const int res_x[] = { 88, 160, 176, 320, 352, 640, 1280 }; + static const int res_y[] = { 72, 120, 144, 240, 288, 480, 960 }; for (i = 0; i < ARRAY_SIZE(res_x); i++) { if (res_x[i] >= *width && res_y[i] >= *height) { -- cgit v1.2.3 From 601b1f0ac7fadbe90cc04c41a1cb31c7cd402fea Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 7 Sep 2017 05:50:23 -0400 Subject: media: cx23885: make const array buf static, reduces object code size Don't populate the array buf on the stack, instead make it static. Makes the object code smaller by over 240 bytes: Before: text data bss dec hex filename 21689 22992 416 45097 b029 cx23885-cards.o After: text data bss dec hex filename 21348 23088 416 44852 af34 cx23885-cards.o Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-cards.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 78a8836d03e4..28eab9c518c5 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -1323,7 +1323,7 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) static void tbs_card_init(struct cx23885_dev *dev) { int i; - const u8 buf[] = { + static const u8 buf[] = { 0xe0, 0x06, 0x66, 0x33, 0x65, 0x01, 0x17, 0x06, 0xde}; -- cgit v1.2.3 From 84c62fb996721897623337e9ebd19f9846873b55 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 3 Sep 2017 09:41:53 -0400 Subject: media: meye: Adjust two function calls together with a variable assignment The script "checkpatch.pl" pointed information out like the following. ERROR: do not use assignment in if condition Thus fix the affected source code places. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/meye/meye.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c index af9cd02fac0c..23999a8cef37 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/media/pci/meye/meye.c @@ -1642,14 +1642,15 @@ static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) meye.vdev = meye_template; meye.vdev.v4l2_dev = &meye.v4l2_dev; - ret = -EIO; - if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) { + ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1); + if (ret) { v4l2_err(v4l2_dev, "meye: unable to power on the camera\n"); v4l2_err(v4l2_dev, "meye: did you enable the camera in sonypi using the module options ?\n"); goto outsonypienable; } - if ((ret = pci_enable_device(meye.mchip_dev))) { + ret = pci_enable_device(meye.mchip_dev); + if (ret) { v4l2_err(v4l2_dev, "meye: pci_enable_device failed\n"); goto outenabledev; } -- cgit v1.2.3 From 5f4d34693cfb217354e079789864ed8801b0d39d Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 3 Sep 2017 14:12:36 -0400 Subject: media: Hexium Orion: Adjust one function call together with a variable assignment The script "checkpatch.pl" pointed information out like the following. ERROR: do not use assignment in if condition Thus fix the affected source code place. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7146/hexium_orion.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c index 7dc182202f8b..043318aa19e2 100644 --- a/drivers/media/pci/saa7146/hexium_orion.c +++ b/drivers/media/pci/saa7146/hexium_orion.c @@ -266,7 +266,9 @@ static int hexium_probe(struct saa7146_dev *dev) /* check if this is an old hexium Orion card by looking at a saa7110 at address 0x4e */ - if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) { + err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, + 0x00, I2C_SMBUS_BYTE_DATA, &data); + if (err == 0) { pr_info("device is a Hexium HV-PCI6/Orion (old)\n"); /* we store the pointer in our private data field */ dev->ext_priv = hexium; -- cgit v1.2.3 From 7a6e6c3be88dcc18f592c76f11cf8e7e090dc9dd Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 7 Sep 2017 16:37:16 -0400 Subject: media: davinci: do a couple of checkpatch cleanups - Delete an error message for a failed memory allocation in init_vpbe_layer(); - Replace the specification of data structures by pointer dereferences as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention; - media: DaVinci-VPBE-Display: Improve a size determination in two functions - Adjust 12 checks for null pointers Those issues were pointed by checkpatch.pl and Coccinelle. [mchehab@s-opensource.com: fold three cleanup patches into one] Signed-off-by: Markus Elfring Acked-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpbe_display.c | 37 +++++++++++---------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 13d027031ff0..6aabd21fe69f 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -122,7 +122,7 @@ static irqreturn_t venc_isr(int irq, void *arg) int fid; int i; - if ((NULL == arg) || (NULL == disp_dev->dev[0])) + if (!arg || !disp_dev->dev[0]) return IRQ_HANDLED; if (venc_is_second_field(disp_dev)) @@ -337,10 +337,10 @@ static void vpbe_stop_streaming(struct vb2_queue *vq) vb2_buffer_done(&layer->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); } else { - if (layer->cur_frm != NULL) + if (layer->cur_frm) vb2_buffer_done(&layer->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); - if (layer->next_frm != NULL) + if (layer->next_frm) vb2_buffer_done(&layer->next_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); } @@ -947,7 +947,7 @@ static int vpbe_display_s_std(struct file *file, void *priv, if (vb2_is_busy(&layer->buffer_queue)) return -EBUSY; - if (NULL != vpbe_dev->ops.s_std) { + if (vpbe_dev->ops.s_std) { ret = vpbe_dev->ops.s_std(vpbe_dev, std_id); if (ret) { v4l2_err(&vpbe_dev->v4l2_dev, @@ -1000,8 +1000,7 @@ static int vpbe_display_enum_output(struct file *file, void *priv, v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_OUTPUT\n"); /* Enumerate outputs */ - - if (NULL == vpbe_dev->ops.enum_outputs) + if (!vpbe_dev->ops.enum_outputs) return -EINVAL; ret = vpbe_dev->ops.enum_outputs(vpbe_dev, output); @@ -1030,7 +1029,7 @@ static int vpbe_display_s_output(struct file *file, void *priv, if (vb2_is_busy(&layer->buffer_queue)) return -EBUSY; - if (NULL == vpbe_dev->ops.set_output) + if (!vpbe_dev->ops.set_output) return -EINVAL; ret = vpbe_dev->ops.set_output(vpbe_dev, i); @@ -1077,7 +1076,7 @@ vpbe_display_enum_dv_timings(struct file *file, void *priv, v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_TIMINGS\n"); /* Enumerate outputs */ - if (NULL == vpbe_dev->ops.enum_dv_timings) + if (!vpbe_dev->ops.enum_dv_timings) return -EINVAL; ret = vpbe_dev->ops.enum_dv_timings(vpbe_dev, timings); @@ -1292,7 +1291,7 @@ static int vpbe_device_get(struct device *dev, void *data) if (strcmp("vpbe_controller", pdev->name) == 0) vpbe_disp->vpbe_dev = platform_get_drvdata(pdev); - if (strstr(pdev->name, "vpbe-osd") != NULL) + if (strstr(pdev->name, "vpbe-osd")) vpbe_disp->osd_device = platform_get_drvdata(pdev); return 0; @@ -1305,15 +1304,10 @@ static int init_vpbe_layer(int i, struct vpbe_display *disp_dev, struct video_device *vbd = NULL; /* Allocate memory for four plane display objects */ - - disp_dev->dev[i] = - kzalloc(sizeof(struct vpbe_layer), GFP_KERNEL); - - /* If memory allocation fails, return error */ - if (!disp_dev->dev[i]) { - printk(KERN_ERR "ran out of memory\n"); + disp_dev->dev[i] = kzalloc(sizeof(*disp_dev->dev[i]), GFP_KERNEL); + if (!disp_dev->dev[i]) return -ENOMEM; - } + spin_lock_init(&disp_dev->dev[i]->irqlock); mutex_init(&disp_dev->dev[i]->opslock); @@ -1397,8 +1391,7 @@ static int vpbe_display_probe(struct platform_device *pdev) printk(KERN_DEBUG "vpbe_display_probe\n"); /* Allocate memory for vpbe_display */ - disp_dev = devm_kzalloc(&pdev->dev, sizeof(struct vpbe_display), - GFP_KERNEL); + disp_dev = devm_kzalloc(&pdev->dev, sizeof(*disp_dev), GFP_KERNEL); if (!disp_dev) return -ENOMEM; @@ -1414,7 +1407,7 @@ static int vpbe_display_probe(struct platform_device *pdev) v4l2_dev = &disp_dev->vpbe_dev->v4l2_dev; /* Initialize the vpbe display controller */ - if (NULL != disp_dev->vpbe_dev->ops.initialize) { + if (disp_dev->vpbe_dev->ops.initialize) { err = disp_dev->vpbe_dev->ops.initialize(&pdev->dev, disp_dev->vpbe_dev); if (err) { @@ -1482,7 +1475,7 @@ static int vpbe_display_probe(struct platform_device *pdev) probe_out: for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) { /* Unregister video device */ - if (disp_dev->dev[k] != NULL) { + if (disp_dev->dev[k]) { video_unregister_device(&disp_dev->dev[k]->video_dev); kfree(disp_dev->dev[k]); } @@ -1504,7 +1497,7 @@ static int vpbe_display_remove(struct platform_device *pdev) v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_remove\n"); /* deinitialize the vpbe display controller */ - if (NULL != vpbe_dev->ops.deinitialize) + if (vpbe_dev->ops.deinitialize) vpbe_dev->ops.deinitialize(&pdev->dev, vpbe_dev); /* un-register device */ for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { -- cgit v1.2.3 From 2489477e4f2c19f19fde8e0a1166506fd5e5cc28 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 8 Sep 2017 11:47:10 -0400 Subject: media: v4l-ioctl: Fix typo on v4l_print_frmsizeenum max_width and max_height are swap with step_width and step_height. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index b60a6b0841d1..79614992ee21 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -730,9 +730,12 @@ static void v4l_print_frmsizeenum(const void *arg, bool write_only) break; case V4L2_FRMSIZE_TYPE_STEPWISE: pr_cont(", min=%ux%u, max=%ux%u, step=%ux%u\n", - p->stepwise.min_width, p->stepwise.min_height, - p->stepwise.step_width, p->stepwise.step_height, - p->stepwise.max_width, p->stepwise.max_height); + p->stepwise.min_width, + p->stepwise.min_height, + p->stepwise.max_width, + p->stepwise.max_height, + p->stepwise.step_width, + p->stepwise.step_height); break; case V4L2_FRMSIZE_TYPE_CONTINUOUS: /* fall through */ -- cgit v1.2.3 From 201c799637f293f8c2a9e4c91de1987bc8b9075c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 28 Aug 2017 04:45:58 -0400 Subject: media: cobalt: do not register subdev nodes In the distant past the adv7604 driver used private controls. In order to access them the v4l-subdevX nodes were needed. Later the is_private tag was removed in the adv7604 driver and the need for v4l-subdevX device nodes disappeared. Remove the creation of those device nodes from this driver. Note: the cobalt card is only used inside Cisco and we never actually used the v4l-subdevX nodes for anything. So this API change can be done safely without breaking anything. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cobalt/cobalt-driver.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index 8487ecaa4d30..3f16cf3f6d74 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.c +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -738,9 +738,6 @@ static int cobalt_probe(struct pci_dev *pci_dev, goto err_i2c; } - retval = v4l2_device_register_subdev_nodes(&cobalt->v4l2_dev); - if (retval) - goto err_i2c; retval = cobalt_nodes_register(cobalt); if (retval) { cobalt_err("Error %d registering device nodes\n", retval); -- cgit v1.2.3 From 561b29e4ec8d0aac7e094f70d649ee4abccdda03 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 30 Aug 2017 04:47:21 -0400 Subject: media: fix media Kconfig help syntax issues The help text should be indented by at least two spaces after the 'help' separator. This is both good practice and the media_build system for building media drivers makes this assumption. I went through all Kconfigs under drivers/media and fixed any bad help sections. This makes it conform to the common practice and should fix problems with 'make menuconfig' when using media_build. This is due to a "WARNING" message that media_build can insert in the Kconfig and that assumes the help text is indented by at least two spaces. If not, then the Kconfig becomes invalid and 'make menuconfig' fails. Signed-off-by: Hans Verkuil Reported-by: Thomas Kaiser Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/Kconfig | 6 +++--- drivers/media/pci/b2c2/Kconfig | 4 ++-- drivers/media/pci/netup_unidvb/Kconfig | 12 ++++++------ drivers/media/platform/exynos4-is/Kconfig | 2 +- drivers/media/radio/wl128x/Kconfig | 10 +++++----- drivers/media/usb/b2c2/Kconfig | 6 +++--- drivers/media/usb/gspca/Kconfig | 16 ++++++++-------- drivers/media/usb/pvrusb2/Kconfig | 1 - 8 files changed, 28 insertions(+), 29 deletions(-) diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 2631d0e0a024..d17722eb4456 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -173,7 +173,7 @@ config DVB_STB6000 tristate "ST STB6000 silicon tuner" depends on DVB_CORE && I2C default m if !MEDIA_SUBDRV_AUTOSELECT - help + help A DVB-S silicon tuner module. Say Y when you want to support this tuner. config DVB_STV0299 @@ -187,7 +187,7 @@ config DVB_STV6110 tristate "ST STV6110 silicon tuner" depends on DVB_CORE && I2C default m if !MEDIA_SUBDRV_AUTOSELECT - help + help A DVB-S silicon tuner module. Say Y when you want to support this tuner. config DVB_STV0900 @@ -902,7 +902,7 @@ config DVB_HELENE depends on DVB_CORE && I2C default m if !MEDIA_SUBDRV_AUTOSELECT help - Say Y when you want to support this frontend. + Say Y when you want to support this frontend. comment "Tools to develop new frontends" diff --git a/drivers/media/pci/b2c2/Kconfig b/drivers/media/pci/b2c2/Kconfig index 58761a21caa0..7b818d445f39 100644 --- a/drivers/media/pci/b2c2/Kconfig +++ b/drivers/media/pci/b2c2/Kconfig @@ -11,5 +11,5 @@ config DVB_B2C2_FLEXCOP_PCI_DEBUG depends on DVB_B2C2_FLEXCOP_PCI select DVB_B2C2_FLEXCOP_DEBUG help - Say Y if you want to enable the module option to control debug messages - of all B2C2 FlexCop drivers. + Say Y if you want to enable the module option to control debug messages + of all B2C2 FlexCop drivers. diff --git a/drivers/media/pci/netup_unidvb/Kconfig b/drivers/media/pci/netup_unidvb/Kconfig index 0ad37714c7fd..b663154d0cc4 100644 --- a/drivers/media/pci/netup_unidvb/Kconfig +++ b/drivers/media/pci/netup_unidvb/Kconfig @@ -1,8 +1,8 @@ config DVB_NETUP_UNIDVB tristate "NetUP Universal DVB card support" depends on DVB_CORE && VIDEO_DEV && PCI && I2C && SPI_MASTER - select VIDEOBUF2_DVB - select VIDEOBUF2_VMALLOC + select VIDEOBUF2_DVB + select VIDEOBUF2_VMALLOC select DVB_HORUS3A if MEDIA_SUBDRV_AUTOSELECT select DVB_ASCOT2E if MEDIA_SUBDRV_AUTOSELECT select DVB_HELENE if MEDIA_SUBDRV_AUTOSELECT @@ -10,8 +10,8 @@ config DVB_NETUP_UNIDVB select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT ---help--- Support for NetUP PCI express Universal DVB card. - help - Say Y when you want to support NetUP Dual Universal DVB card - Card can receive two independent streams in following standards: + + Say Y when you want to support NetUP Dual Universal DVB card. + Card can receive two independent streams in following standards: DVB-S/S2, T/T2, C/C2 - Two CI slots available for CAM modules. + Two CI slots available for CAM modules. diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig index c480efb755f5..46a7d242a1a5 100644 --- a/drivers/media/platform/exynos4-is/Kconfig +++ b/drivers/media/platform/exynos4-is/Kconfig @@ -76,7 +76,7 @@ config VIDEO_EXYNOS4_ISP_DMA_CAPTURE depends on VIDEO_EXYNOS4_FIMC_IS select VIDEO_EXYNOS4_IS_COMMON default y - help + help This option enables an additional video device node exposing a V4L2 video capture interface for the FIMC-IS ISP raw (Bayer) capture DMA. diff --git a/drivers/media/radio/wl128x/Kconfig b/drivers/media/radio/wl128x/Kconfig index c9e349b169c4..2add222ea346 100644 --- a/drivers/media/radio/wl128x/Kconfig +++ b/drivers/media/radio/wl128x/Kconfig @@ -7,11 +7,11 @@ config RADIO_WL128X depends on VIDEO_V4L2 && RFKILL && TTY && TI_ST depends on GPIOLIB || COMPILE_TEST help - Choose Y here if you have this FM radio chip. + Choose Y here if you have this FM radio chip. - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux 2 API. Information on - this API and pointers to "v4l2" programs may be found at - . + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux 2 API. Information on + this API and pointers to "v4l2" programs may be found at + . endmenu diff --git a/drivers/media/usb/b2c2/Kconfig b/drivers/media/usb/b2c2/Kconfig index 17d35833980c..a620ae42dfc8 100644 --- a/drivers/media/usb/b2c2/Kconfig +++ b/drivers/media/usb/b2c2/Kconfig @@ -10,6 +10,6 @@ config DVB_B2C2_FLEXCOP_USB_DEBUG bool "Enable debug for the B2C2 FlexCop drivers" depends on DVB_B2C2_FLEXCOP_USB select DVB_B2C2_FLEXCOP_DEBUG - help - Say Y if you want to enable the module option to control debug messages - of all B2C2 FlexCop drivers. + help + Say Y if you want to enable the module option to control debug messages + of all B2C2 FlexCop drivers. diff --git a/drivers/media/usb/gspca/Kconfig b/drivers/media/usb/gspca/Kconfig index 3fd94fe7e1eb..d214a21acff7 100644 --- a/drivers/media/usb/gspca/Kconfig +++ b/drivers/media/usb/gspca/Kconfig @@ -204,11 +204,11 @@ config USB_GSPCA_SE401 tristate "SE401 USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the - Endpoints (formerly known as AOX) se401 chip. + Say Y here if you want support for cameras based on the + Endpoints (formerly known as AOX) se401 chip. - To compile this driver as a module, choose M here: the - module will be called gspca_se401. + To compile this driver as a module, choose M here: the + module will be called gspca_se401. config USB_GSPCA_SN9C2028 tristate "SONIX Dual-Mode USB Camera Driver" @@ -224,11 +224,11 @@ config USB_GSPCA_SN9C20X tristate "SN9C20X USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA help - Say Y here if you want support for cameras based on the - sn9c20x chips (SN9C201 and SN9C202). + Say Y here if you want support for cameras based on the + sn9c20x chips (SN9C201 and SN9C202). - To compile this driver as a module, choose M here: the - module will be called gspca_sn9c20x. + To compile this driver as a module, choose M here: the + module will be called gspca_sn9c20x. config USB_GSPCA_SONIXB tristate "SONIX Bayer USB Camera Driver" diff --git a/drivers/media/usb/pvrusb2/Kconfig b/drivers/media/usb/pvrusb2/Kconfig index 60a2604e4cb3..1ad913fc30bf 100644 --- a/drivers/media/usb/pvrusb2/Kconfig +++ b/drivers/media/usb/pvrusb2/Kconfig @@ -44,7 +44,6 @@ config VIDEO_PVRUSB2_DVB select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT ---help--- - This option enables a DVB interface for the pvrusb2 driver. If your device does not support digital television, this feature will have no affect on the driver's operation. -- cgit v1.2.3 From 9267d90c564fc4ac7e51b922fa03107bb8c78739 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 31 Aug 2017 04:12:53 -0400 Subject: media: cec.h: initialize *parent and *port in cec_phys_addr_validate Make sure these values are set to avoid 'uninitialized variable' warnings. Hasn't happened yet, but better safe than sorry. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/cec.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/media/cec.h b/include/media/cec.h index 9d0f983faea9..16341210d3ba 100644 --- a/include/media/cec.h +++ b/include/media/cec.h @@ -427,6 +427,10 @@ static inline u16 cec_phys_addr_for_input(u16 phys_addr, u8 input) static inline int cec_phys_addr_validate(u16 phys_addr, u16 *parent, u16 *port) { + if (parent) + *parent = phys_addr; + if (port) + *port = 0; return 0; } -- cgit v1.2.3 From 727d38a89179fb052b946c59860f86353b9daeb5 Mon Sep 17 00:00:00 2001 From: Himanshu Jha Date: Sat, 26 Aug 2017 16:51:49 -0400 Subject: media: atomisp2: Remove null check before kfree Kfree on NULL pointer is a no-op and therefore checking is redundant. Signed-off-by: Himanshu Jha Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c index 63582161050a..451c76e7eec0 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c @@ -295,10 +295,8 @@ void sh_css_unload_firmware(void) } memset(&sh_css_sp_fw, 0, sizeof(sh_css_sp_fw)); - if (sh_css_blob_info) { - kfree(sh_css_blob_info); - sh_css_blob_info = NULL; - } + kfree(sh_css_blob_info); + sh_css_blob_info = NULL; sh_css_num_binaries = 0; } -- cgit v1.2.3 From 6d5f41985f408e35e63a710429434d0c0c1153ce Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Thu, 31 Aug 2017 03:48:37 -0400 Subject: media: Staging: atomisp: constify driver_attribute driver_attribute are not supposed to change at runtime. Functions driver_create_file/driver_remove_file are working with const driver_attribute. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp2/atomisp_drvfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_drvfs.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_drvfs.c index 1ae2358de8d4..9f74b2dcbfaf 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_drvfs.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_drvfs.c @@ -162,7 +162,7 @@ static ssize_t iunit_dbgopt_store(struct device_driver *drv, const char *buf, return size; } -static struct driver_attribute iunit_drvfs_attrs[] = { +static const struct driver_attribute iunit_drvfs_attrs[] = { __ATTR(dbglvl, 0644, iunit_dbglvl_show, iunit_dbglvl_store), __ATTR(dbgfun, 0644, iunit_dbgfun_show, iunit_dbgfun_store), __ATTR(dbgopt, 0644, iunit_dbgopt_show, iunit_dbgopt_store), -- cgit v1.2.3 From 2fc8b694f2316041df971cca41c9a7d1595e3a6d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 30 Aug 2017 04:39:00 -0400 Subject: media: atomisp: fix small Kconfig issues The help text should be indented by at least two spaces after the 'help' separator. This is both good practice and the media_build system for building media drivers makes this assumption. Fix this for the atomisp/i2c/Kconfig and fix the atomisp/pci/Kconfig that didn't align the help separator with the preceding keywords. Signed-off-by: Hans Verkuil Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/Kconfig | 4 ++-- drivers/staging/media/atomisp/pci/Kconfig | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/Kconfig b/drivers/staging/media/atomisp/i2c/Kconfig index b80d29d53e65..e628b5c37455 100644 --- a/drivers/staging/media/atomisp/i2c/Kconfig +++ b/drivers/staging/media/atomisp/i2c/Kconfig @@ -75,8 +75,8 @@ config VIDEO_GC0310 tristate "GC0310 sensor support" depends on I2C && VIDEO_V4L2 ---help--- - This is a Video4Linux2 sensor-level driver for the Galaxycore - GC0310 0.3MP sensor. + This is a Video4Linux2 sensor-level driver for the Galaxycore + GC0310 0.3MP sensor. config VIDEO_OV2680 tristate "Omnivision OV2680 sensor support" diff --git a/drivers/staging/media/atomisp/pci/Kconfig b/drivers/staging/media/atomisp/pci/Kconfig index a72421431c7a..6b2203e6d511 100644 --- a/drivers/staging/media/atomisp/pci/Kconfig +++ b/drivers/staging/media/atomisp/pci/Kconfig @@ -3,11 +3,11 @@ # config VIDEO_ATOMISP - tristate "Intel Atom Image Signal Processor Driver" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - select VIDEOBUF_VMALLOC - ---help--- - Say Y here if your platform supports Intel Atom SoC - camera imaging subsystem. - To compile this driver as a module, choose M here: the - module will be called atomisp + tristate "Intel Atom Image Signal Processor Driver" + depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + select VIDEOBUF_VMALLOC + ---help--- + Say Y here if your platform supports Intel Atom SoC + camera imaging subsystem. + To compile this driver as a module, choose M here: the + module will be called atomisp -- cgit v1.2.3 From d13f47c2a2df7b6afe13036ba6fa164bedea5b0a Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 31 Aug 2017 04:11:00 -0400 Subject: media: staging: media: atomisp: Use tabs in Kconfig Use tabs in Kconfig for indentation rather than spaces. The patch has been created using the following command: find drivers/staging/media/atomisp/ -name Kconfig| \ xargs perl -i -pe 's/ {8}/\t/g' Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/Kconfig | 10 ++-- drivers/staging/media/atomisp/i2c/Kconfig | 70 ++++++++++++------------ drivers/staging/media/atomisp/i2c/ov5693/Kconfig | 8 +-- 3 files changed, 44 insertions(+), 44 deletions(-) diff --git a/drivers/staging/media/atomisp/Kconfig b/drivers/staging/media/atomisp/Kconfig index 8eb13c3ba29c..52b86b7e433f 100644 --- a/drivers/staging/media/atomisp/Kconfig +++ b/drivers/staging/media/atomisp/Kconfig @@ -1,9 +1,9 @@ menuconfig INTEL_ATOMISP - bool "Enable support to Intel MIPI camera drivers" - depends on X86 && EFI && MEDIA_CONTROLLER && PCI && ACPI - help - Enable support for the Intel ISP2 camera interfaces and MIPI - sensor drivers. + bool "Enable support to Intel MIPI camera drivers" + depends on X86 && EFI && MEDIA_CONTROLLER && PCI && ACPI + help + Enable support for the Intel ISP2 camera interfaces and MIPI + sensor drivers. if INTEL_ATOMISP source "drivers/staging/media/atomisp/pci/Kconfig" diff --git a/drivers/staging/media/atomisp/i2c/Kconfig b/drivers/staging/media/atomisp/i2c/Kconfig index e628b5c37455..57505b7a25ca 100644 --- a/drivers/staging/media/atomisp/i2c/Kconfig +++ b/drivers/staging/media/atomisp/i2c/Kconfig @@ -9,85 +9,85 @@ config VIDEO_OV2722 tristate "OVT ov2722 sensor support" depends on I2C && VIDEO_V4L2 ---help--- - This is a Video4Linux2 sensor-level driver for the OVT - OV2722 raw camera. + This is a Video4Linux2 sensor-level driver for the OVT + OV2722 raw camera. - OVT is a 2M raw sensor. + OVT is a 2M raw sensor. - It currently only works with the atomisp driver. + It currently only works with the atomisp driver. config VIDEO_GC2235 tristate "Galaxy gc2235 sensor support" depends on I2C && VIDEO_V4L2 ---help--- - This is a Video4Linux2 sensor-level driver for the OVT - GC2235 raw camera. + This is a Video4Linux2 sensor-level driver for the OVT + GC2235 raw camera. - GC2235 is a 2M raw sensor. + GC2235 is a 2M raw sensor. - It currently only works with the atomisp driver. + It currently only works with the atomisp driver. config VIDEO_OV8858 tristate "Omnivision ov8858 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_ATOMISP ---help--- - This is a Video4Linux2 sensor-level driver for the Omnivision - ov8858 RAW sensor. + This is a Video4Linux2 sensor-level driver for the Omnivision + ov8858 RAW sensor. OV8858 is a 8M raw sensor. - It currently only works with the atomisp driver. + It currently only works with the atomisp driver. config VIDEO_MSRLIST_HELPER tristate "Helper library to load, parse and apply large register lists." depends on I2C ---help--- - This is a helper library to be used from a sensor driver to load, parse - and apply large register lists. + This is a helper library to be used from a sensor driver to load, parse + and apply large register lists. - To compile this driver as a module, choose M here: the - module will be called libmsrlisthelper. + To compile this driver as a module, choose M here: the + module will be called libmsrlisthelper. config VIDEO_MT9M114 tristate "Aptina mt9m114 sensor support" depends on I2C && VIDEO_V4L2 ---help--- - This is a Video4Linux2 sensor-level driver for the Micron - mt9m114 1.3 Mpixel camera. + This is a Video4Linux2 sensor-level driver for the Micron + mt9m114 1.3 Mpixel camera. - mt9m114 is video camera sensor. + mt9m114 is video camera sensor. - It currently only works with the atomisp driver. + It currently only works with the atomisp driver. config VIDEO_AP1302 tristate "AP1302 external ISP support" depends on I2C && VIDEO_V4L2 select REGMAP_I2C ---help--- - This is a Video4Linux2 sensor-level driver for the external - ISP AP1302. + This is a Video4Linux2 sensor-level driver for the external + ISP AP1302. - AP1302 is an exteral ISP. + AP1302 is an exteral ISP. - It currently only works with the atomisp driver. + It currently only works with the atomisp driver. config VIDEO_GC0310 tristate "GC0310 sensor support" - depends on I2C && VIDEO_V4L2 - ---help--- - This is a Video4Linux2 sensor-level driver for the Galaxycore - GC0310 0.3MP sensor. + depends on I2C && VIDEO_V4L2 + ---help--- + This is a Video4Linux2 sensor-level driver for the Galaxycore + GC0310 0.3MP sensor. config VIDEO_OV2680 tristate "Omnivision OV2680 sensor support" depends on I2C && VIDEO_V4L2 ---help--- - This is a Video4Linux2 sensor-level driver for the Omnivision - OV2680 raw camera. + This is a Video4Linux2 sensor-level driver for the Omnivision + OV2680 raw camera. - ov2680 is a 2M raw sensor. + ov2680 is a 2M raw sensor. - It currently only works with the atomisp driver. + It currently only works with the atomisp driver. # # Kconfig for flash drivers @@ -97,10 +97,10 @@ config VIDEO_LM3554 tristate "LM3554 flash light driver" depends on VIDEO_V4L2 && I2C ---help--- - This is a Video4Linux2 sub-dev driver for the LM3554 - flash light driver. + This is a Video4Linux2 sub-dev driver for the LM3554 + flash light driver. - To compile this driver as a module, choose M here: the - module will be called lm3554 + To compile this driver as a module, choose M here: the + module will be called lm3554 diff --git a/drivers/staging/media/atomisp/i2c/ov5693/Kconfig b/drivers/staging/media/atomisp/i2c/ov5693/Kconfig index 9fb1bffbe9b3..9e8d32521e7e 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/Kconfig +++ b/drivers/staging/media/atomisp/i2c/ov5693/Kconfig @@ -2,10 +2,10 @@ config VIDEO_OV5693 tristate "Omnivision ov5693 sensor support" depends on I2C && VIDEO_V4L2 ---help--- - This is a Video4Linux2 sensor-level driver for the Micron - ov5693 5 Mpixel camera. + This is a Video4Linux2 sensor-level driver for the Micron + ov5693 5 Mpixel camera. - ov5693 is video camera sensor. + ov5693 is video camera sensor. - It currently only works with the atomisp driver. + It currently only works with the atomisp driver. -- cgit v1.2.3 From 5fc90b632ea9a107ed6b71eb7058bb58e1b5493b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 1 Sep 2017 09:36:34 -0400 Subject: media: staging: atomisp: Remove dead code for MID (#1) Remove dead code. If someone needs it the P-Unit semaphore is handled by I2C DesignWare driver (drivers/i2c/busses/i2c-designware-baytrail.c). Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../atomisp/include/asm/intel_mid_pcihelpers.h | 2 - .../platform/intel-mid/intel_mid_pcihelpers.c | 101 --------------------- 2 files changed, 103 deletions(-) diff --git a/drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h b/drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h index c5e22bba455a..b7c079f3630a 100644 --- a/drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h +++ b/drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h @@ -33,5 +33,3 @@ void intel_mid_msgbus_write32(u8 port, u32 addr, u32 data); u32 intel_mid_msgbus_read32_raw_ext(u32 cmd, u32 cmd_ext); void intel_mid_msgbus_write32_raw_ext(u32 cmd, u32 cmd_ext, u32 data); u32 intel_mid_soc_stepping(void); -int intel_mid_dw_i2c_acquire_ownership(void); -int intel_mid_dw_i2c_release_ownership(void); diff --git a/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c b/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c index cd452cc20fea..0d01a269989d 100644 --- a/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c +++ b/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c @@ -14,13 +14,6 @@ #define INTEL_ATOM_BYT 0x37 #define INTEL_ATOM_MOORFLD 0x5a #define INTEL_ATOM_CHT 0x4c -/* synchronization for sharing the I2C controller */ -#define PUNIT_PORT 0x04 -#define PUNIT_DOORBELL_OPCODE (0xE0) -#define PUNIT_DOORBELL_REG (0x0) -#ifndef CSTATE_EXIT_LATENCY -#define CSTATE_EXIT_LATENCY_C1 1 -#endif static inline int platform_is(u8 model) { return (boot_cpu_data.x86_model == model); @@ -201,97 +194,3 @@ static void pci_d3_delay_fixup(struct pci_dev *dev) } } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_d3_delay_fixup); - -#define PUNIT_SEMAPHORE (platform_is(INTEL_ATOM_BYT) ? 0x7 : 0x10E) -#define GET_SEM() (intel_mid_msgbus_read32(PUNIT_PORT, PUNIT_SEMAPHORE) & 0x1) - -static void reset_semaphore(void) -{ - u32 data; - - data = intel_mid_msgbus_read32(PUNIT_PORT, PUNIT_SEMAPHORE); - smp_mb(); - data = data & 0xfffffffc; - intel_mid_msgbus_write32(PUNIT_PORT, PUNIT_SEMAPHORE, data); - smp_mb(); - -} - -int intel_mid_dw_i2c_acquire_ownership(void) -{ - u32 ret = 0; - u32 data = 0; /* data sent to PUNIT */ - u32 cmd; - u32 cmdext; - int timeout = 1000; - - if (DW_I2C_NEED_QOS) - pm_qos_update_request(&pm_qos, CSTATE_EXIT_LATENCY_C1 - 1); - - /* - * We need disable irq. Otherwise, the main thread - * might be preempted and the other thread jumps to - * disable irq for a long time. Another case is - * some irq handlers might trigger power voltage change - */ - BUG_ON(irqs_disabled()); - local_irq_disable(); - - /* host driver writes 0x2 to side band register 0x7 */ - intel_mid_msgbus_write32(PUNIT_PORT, PUNIT_SEMAPHORE, 0x2); - smp_mb(); - - /* host driver sends 0xE0 opcode to PUNIT and writes 0 register */ - cmd = (PUNIT_DOORBELL_OPCODE << 24) | (PUNIT_PORT << 16) | - ((PUNIT_DOORBELL_REG & 0xFF) << 8) | PCI_ROOT_MSGBUS_DWORD_ENABLE; - cmdext = PUNIT_DOORBELL_REG & 0xffffff00; - - if (cmdext) - intel_mid_msgbus_write32_raw_ext(cmd, cmdext, data); - else - intel_mid_msgbus_write32_raw(cmd, data); - - /* host driver waits for bit 0 to be set in side band 0x7 */ - while (GET_SEM() != 0x1) { - udelay(100); - timeout--; - if (timeout <= 0) { - pr_err("Timeout: semaphore timed out, reset sem\n"); - ret = -ETIMEDOUT; - reset_semaphore(); - /*Delay 1ms in case race with punit*/ - udelay(1000); - if (GET_SEM() != 0) { - /*Reset again as kernel might race with punit*/ - reset_semaphore(); - } - pr_err("PUNIT SEM: %d\n", - intel_mid_msgbus_read32(PUNIT_PORT, - PUNIT_SEMAPHORE)); - local_irq_enable(); - - if (DW_I2C_NEED_QOS) { - pm_qos_update_request(&pm_qos, - PM_QOS_DEFAULT_VALUE); - } - - return ret; - } - } - smp_mb(); - - return ret; -} -EXPORT_SYMBOL(intel_mid_dw_i2c_acquire_ownership); - -int intel_mid_dw_i2c_release_ownership(void) -{ - reset_semaphore(); - local_irq_enable(); - - if (DW_I2C_NEED_QOS) - pm_qos_update_request(&pm_qos, PM_QOS_DEFAULT_VALUE); - - return 0; -} -EXPORT_SYMBOL(intel_mid_dw_i2c_release_ownership); -- cgit v1.2.3 From 90154e130f45f4fcad595058cc2d34ce412bec33 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 1 Sep 2017 09:36:35 -0400 Subject: media: staging: atomisp: Don't override D3 delay settings here The d3_delay parameter is set by arch/x86/pci/intel_mid_pci.c and drivers/pci/quirks.c. No need to override that settings in unrelated driver. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../atomisp/include/asm/intel_mid_pcihelpers.h | 8 ------ .../platform/intel-mid/intel_mid_pcihelpers.c | 33 ---------------------- 2 files changed, 41 deletions(-) diff --git a/drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h b/drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h index b7c079f3630a..0d7f5c618b56 100644 --- a/drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h +++ b/drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h @@ -18,14 +18,6 @@ #define PCI_ROOT_MSGBUS_WRITE 0x11 #define PCI_ROOT_MSGBUS_DWORD_ENABLE 0xf0 -/* In BYT platform for all internal PCI devices d3 delay - * of 3 ms is sufficient. Default value of 10 ms is overkill. - */ -#define INTERNAL_PCI_PM_D3_WAIT 3 - -#define ISP_SUB_CLASS 0x80 -#define SUB_CLASS_MASK 0xFF00 - u32 intel_mid_msgbus_read32_raw(u32 cmd); u32 intel_mid_msgbus_read32(u8 port, u32 addr); void intel_mid_msgbus_write32_raw(u32 cmd, u32 data); diff --git a/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c b/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c index 0d01a269989d..341bfd3ab313 100644 --- a/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c +++ b/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c @@ -161,36 +161,3 @@ u32 intel_mid_soc_stepping(void) return pci_root->revision; } EXPORT_SYMBOL(intel_mid_soc_stepping); - -static bool is_south_complex_device(struct pci_dev *dev) -{ - unsigned int base_class = dev->class >> 16; - unsigned int sub_class = (dev->class & SUB_CLASS_MASK) >> 8; - - /* other than camera, pci bridges and display, - * everything else are south complex devices. - */ - if (((base_class == PCI_BASE_CLASS_MULTIMEDIA) && - (sub_class == ISP_SUB_CLASS)) || - (base_class == PCI_BASE_CLASS_BRIDGE) || - ((base_class == PCI_BASE_CLASS_DISPLAY) && !sub_class)) - return false; - else - return true; -} - -/* In BYT platform, d3_delay for internal south complex devices, - * they are not subject to 10 ms d3 to d0 delay required by pci spec. - */ -static void pci_d3_delay_fixup(struct pci_dev *dev) -{ - if (platform_is(INTEL_ATOM_BYT) || - platform_is(INTEL_ATOM_CHT)) { - /* All internal devices are in bus 0. */ - if (dev->bus->number == 0 && is_south_complex_device(dev)) { - dev->d3_delay = INTERNAL_PCI_PM_D3_WAIT; - dev->d3cold_delay = INTERNAL_PCI_PM_D3_WAIT; - } - } -} -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_d3_delay_fixup); -- cgit v1.2.3 From e84bf2225d55fab90b4627c61d81ca2fb333907e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 1 Sep 2017 09:36:36 -0400 Subject: media: staging: atomisp: Remove dead code for MID (#2) intel_mid_soc_stepping() is not used anywhere. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h | 1 - .../media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c | 7 ------- 2 files changed, 8 deletions(-) diff --git a/drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h b/drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h index 0d7f5c618b56..5d8451ee391e 100644 --- a/drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h +++ b/drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h @@ -24,4 +24,3 @@ void intel_mid_msgbus_write32_raw(u32 cmd, u32 data); void intel_mid_msgbus_write32(u8 port, u32 addr, u32 data); u32 intel_mid_msgbus_read32_raw_ext(u32 cmd, u32 cmd_ext); void intel_mid_msgbus_write32_raw_ext(u32 cmd, u32 cmd_ext, u32 data); -u32 intel_mid_soc_stepping(void); diff --git a/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c b/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c index 341bfd3ab313..c34f461653db 100644 --- a/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c +++ b/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c @@ -154,10 +154,3 @@ void intel_mid_msgbus_write32(u8 port, u32 addr, u32 data) spin_unlock_irqrestore(&msgbus_lock, irq_flags); } EXPORT_SYMBOL(intel_mid_msgbus_write32); - -/* called only from where is later then fs_initcall */ -u32 intel_mid_soc_stepping(void) -{ - return pci_root->revision; -} -EXPORT_SYMBOL(intel_mid_soc_stepping); -- cgit v1.2.3 From e64d5bd481be674db9e9626e71c2dd0a77445fa8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 1 Sep 2017 09:36:37 -0400 Subject: media: staging: atomisp: Remove dead code for MID (#3) intel_mid_msgbus_*_raw*() are not used anywhere. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../atomisp/include/asm/intel_mid_pcihelpers.h | 4 -- .../platform/intel-mid/intel_mid_pcihelpers.c | 58 ---------------------- 2 files changed, 62 deletions(-) diff --git a/drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h b/drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h index 5d8451ee391e..bf39f42c1c96 100644 --- a/drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h +++ b/drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h @@ -18,9 +18,5 @@ #define PCI_ROOT_MSGBUS_WRITE 0x11 #define PCI_ROOT_MSGBUS_DWORD_ENABLE 0xf0 -u32 intel_mid_msgbus_read32_raw(u32 cmd); u32 intel_mid_msgbus_read32(u8 port, u32 addr); -void intel_mid_msgbus_write32_raw(u32 cmd, u32 data); void intel_mid_msgbus_write32(u8 port, u32 addr, u32 data); -u32 intel_mid_msgbus_read32_raw_ext(u32 cmd, u32 cmd_ext); -void intel_mid_msgbus_write32_raw_ext(u32 cmd, u32 cmd_ext, u32 data); diff --git a/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c b/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c index c34f461653db..4ed3268c4e63 100644 --- a/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c +++ b/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c @@ -46,64 +46,6 @@ static int intel_mid_msgbus_init(void) } fs_initcall(intel_mid_msgbus_init); -u32 intel_mid_msgbus_read32_raw(u32 cmd) -{ - unsigned long irq_flags; - u32 data; - - spin_lock_irqsave(&msgbus_lock, irq_flags); - pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd); - pci_read_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, &data); - spin_unlock_irqrestore(&msgbus_lock, irq_flags); - - return data; -} -EXPORT_SYMBOL(intel_mid_msgbus_read32_raw); - -/* - * GU: this function is only used by the VISA and 'VXD' drivers. - */ -u32 intel_mid_msgbus_read32_raw_ext(u32 cmd, u32 cmd_ext) -{ - unsigned long irq_flags; - u32 data; - - spin_lock_irqsave(&msgbus_lock, irq_flags); - pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_EXT_REG, cmd_ext); - pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd); - pci_read_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, &data); - spin_unlock_irqrestore(&msgbus_lock, irq_flags); - - return data; -} -EXPORT_SYMBOL(intel_mid_msgbus_read32_raw_ext); - -void intel_mid_msgbus_write32_raw(u32 cmd, u32 data) -{ - unsigned long irq_flags; - - spin_lock_irqsave(&msgbus_lock, irq_flags); - pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, data); - pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd); - spin_unlock_irqrestore(&msgbus_lock, irq_flags); -} -EXPORT_SYMBOL(intel_mid_msgbus_write32_raw); - -/* - * GU: this function is only used by the VISA and 'VXD' drivers. - */ -void intel_mid_msgbus_write32_raw_ext(u32 cmd, u32 cmd_ext, u32 data) -{ - unsigned long irq_flags; - - spin_lock_irqsave(&msgbus_lock, irq_flags); - pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, data); - pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_EXT_REG, cmd_ext); - pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd); - spin_unlock_irqrestore(&msgbus_lock, irq_flags); -} -EXPORT_SYMBOL(intel_mid_msgbus_write32_raw_ext); - u32 intel_mid_msgbus_read32(u8 port, u32 addr) { unsigned long irq_flags; -- cgit v1.2.3 From 66228be9fff77d3fcc02663d534dff17c30aedc1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 1 Sep 2017 09:36:38 -0400 Subject: media: staging: atomisp: Move to upstream IOSF MBI API There is a common for x86 IOSF MBI API. Move atomisp code to use it. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/Kconfig | 1 + .../media/atomisp/pci/atomisp2/atomisp_cmd.c | 20 +++++++----- .../media/atomisp/pci/atomisp2/atomisp_v4l2.c | 38 ++++++++++------------ 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/Kconfig b/drivers/staging/media/atomisp/pci/Kconfig index 6b2203e6d511..41f116d52060 100644 --- a/drivers/staging/media/atomisp/pci/Kconfig +++ b/drivers/staging/media/atomisp/pci/Kconfig @@ -5,6 +5,7 @@ config VIDEO_ATOMISP tristate "Intel Atom Image Signal Processor Driver" depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + select IOSF_MBI select VIDEOBUF_VMALLOC ---help--- Say Y here if your platform supports Intel Atom SoC diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c index f48bf451c1f5..73e15dd9d4d6 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c @@ -27,7 +27,9 @@ #include #include #include + #include +#include #include #include @@ -143,36 +145,36 @@ static int write_target_freq_to_hw(struct atomisp_device *isp, unsigned int ratio, timeout, guar_ratio; u32 isp_sspm1 = 0; int i; + if (!isp->hpll_freq) { dev_err(isp->dev, "failed to get hpll_freq. no change to freq\n"); return -EINVAL; } - isp_sspm1 = intel_mid_msgbus_read32(PUNIT_PORT, ISPSSPM1); + iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1); if (isp_sspm1 & ISP_FREQ_VALID_MASK) { dev_dbg(isp->dev, "clearing ISPSSPM1 valid bit.\n"); - intel_mid_msgbus_write32(PUNIT_PORT, ISPSSPM1, + iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, ISPSSPM1, isp_sspm1 & ~(1 << ISP_FREQ_VALID_OFFSET)); } ratio = (2 * isp->hpll_freq + new_freq / 2) / new_freq - 1; guar_ratio = (2 * isp->hpll_freq + 200 / 2) / 200 - 1; - isp_sspm1 = intel_mid_msgbus_read32(PUNIT_PORT, ISPSSPM1); + iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1); isp_sspm1 &= ~(0x1F << ISP_REQ_FREQ_OFFSET); for (i = 0; i < ISP_DFS_TRY_TIMES; i++) { - intel_mid_msgbus_write32(PUNIT_PORT, ISPSSPM1, + iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, ISPSSPM1, isp_sspm1 | ratio << ISP_REQ_FREQ_OFFSET | 1 << ISP_FREQ_VALID_OFFSET | guar_ratio << ISP_REQ_GUAR_FREQ_OFFSET); - isp_sspm1 = intel_mid_msgbus_read32(PUNIT_PORT, ISPSSPM1); - + iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1); timeout = 20; while ((isp_sspm1 & ISP_FREQ_VALID_MASK) && timeout) { - isp_sspm1 = intel_mid_msgbus_read32(PUNIT_PORT, ISPSSPM1); + iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1); dev_dbg(isp->dev, "waiting for ISPSSPM1 valid bit to be 0.\n"); udelay(100); timeout--; @@ -187,10 +189,10 @@ static int write_target_freq_to_hw(struct atomisp_device *isp, return -EINVAL; } - isp_sspm1 = intel_mid_msgbus_read32(PUNIT_PORT, ISPSSPM1); + iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1); timeout = 10; while (((isp_sspm1 >> ISP_FREQ_STAT_OFFSET) != ratio) && timeout) { - isp_sspm1 = intel_mid_msgbus_read32(PUNIT_PORT, ISPSSPM1); + iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, ISPSSPM1, &isp_sspm1); dev_dbg(isp->dev, "waiting for ISPSSPM1 status bit to be 0x%x.\n", new_freq); udelay(100); diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c index 663aa916e3ca..0896f5ea7e4e 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c @@ -28,6 +28,9 @@ #include #include +#include +#include + #include "../../include/linux/atomisp_gmin_platform.h" #include "atomisp_cmd.h" @@ -46,7 +49,6 @@ #include "hrt/hive_isp_css_mm_hrt.h" #include "device_access.h" -#include /* G-Min addition: pull this in from intel_mid_pm.h */ #define CSTATE_EXIT_LATENCY_C1 1 @@ -386,28 +388,23 @@ done: */ static void punit_ddr_dvfs_enable(bool enable) { - int reg = intel_mid_msgbus_read32(PUNIT_PORT, MRFLD_ISPSSDVFS); int door_bell = 1 << 8; int max_wait = 30; + int reg; + iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSDVFS, ®); if (enable) { reg &= ~(MRFLD_BIT0 | MRFLD_BIT1); } else { reg |= (MRFLD_BIT1 | door_bell); reg &= ~(MRFLD_BIT0); } + iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, MRFLD_ISPSSDVFS, reg); - intel_mid_msgbus_write32(PUNIT_PORT, MRFLD_ISPSSDVFS, reg); - - /*Check Req_ACK to see freq status, wait until door_bell is cleared*/ - if (reg & door_bell) { - while (max_wait--) { - if (0 == (intel_mid_msgbus_read32(PUNIT_PORT, - MRFLD_ISPSSDVFS) & door_bell)) - break; - - usleep_range(100, 500); - } + /* Check Req_ACK to see freq status, wait until door_bell is cleared */ + while ((reg & door_bell) && max_wait--) { + iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSDVFS, ®); + usleep_range(100, 500); } if (max_wait == -1) @@ -421,10 +418,10 @@ int atomisp_mrfld_power_down(struct atomisp_device *isp) u32 reg_value; /* writing 0x3 to ISPSSPM0 bit[1:0] to power off the IUNIT */ - reg_value = intel_mid_msgbus_read32(PUNIT_PORT, MRFLD_ISPSSPM0); + iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSPM0, ®_value); reg_value &= ~MRFLD_ISPSSPM0_ISPSSC_MASK; reg_value |= MRFLD_ISPSSPM0_IUNIT_POWER_OFF; - intel_mid_msgbus_write32(PUNIT_PORT, MRFLD_ISPSSPM0, reg_value); + iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, MRFLD_ISPSSPM0, reg_value); /*WA:Enable DVFS*/ if (IS_CHT) @@ -437,8 +434,7 @@ int atomisp_mrfld_power_down(struct atomisp_device *isp) */ timeout = jiffies + msecs_to_jiffies(50); while (1) { - reg_value = intel_mid_msgbus_read32(PUNIT_PORT, - MRFLD_ISPSSPM0); + iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSPM0, ®_value); dev_dbg(isp->dev, "power-off in progress, ISPSSPM0: 0x%x\n", reg_value); /* wait until ISPSSPM0 bit[25:24] shows 0x3 */ @@ -477,14 +473,14 @@ int atomisp_mrfld_power_up(struct atomisp_device *isp) msleep(10); /* writing 0x0 to ISPSSPM0 bit[1:0] to power off the IUNIT */ - reg_value = intel_mid_msgbus_read32(PUNIT_PORT, MRFLD_ISPSSPM0); + iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSPM0, ®_value); reg_value &= ~MRFLD_ISPSSPM0_ISPSSC_MASK; - intel_mid_msgbus_write32(PUNIT_PORT, MRFLD_ISPSSPM0, reg_value); + iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_REG_WRITE, MRFLD_ISPSSPM0, reg_value); /* FIXME: experienced value for delay */ timeout = jiffies + msecs_to_jiffies(50); while (1) { - reg_value = intel_mid_msgbus_read32(PUNIT_PORT, MRFLD_ISPSSPM0); + iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ, MRFLD_ISPSSPM0, ®_value); dev_dbg(isp->dev, "power-on in progress, ISPSSPM0: 0x%x\n", reg_value); /* wait until ISPSSPM0 bit[25:24] shows 0x0 */ @@ -1323,7 +1319,7 @@ static int atomisp_pci_probe(struct pci_dev *dev, isp->dfs = &dfs_config_cht; isp->pdev->d3cold_delay = 0; - val = intel_mid_msgbus_read32(CCK_PORT, CCK_FUSE_REG_0); + iosf_mbi_read(CCK_PORT, MBI_REG_READ, CCK_FUSE_REG_0, &val); switch (val & CCK_FUSE_HPLL_FREQ_MASK) { case 0x00: isp->hpll_freq = HPLL_FREQ_800MHZ; -- cgit v1.2.3 From 209627bff1c609983aaea7085a03677ce12bf2c6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 1 Sep 2017 09:36:39 -0400 Subject: media: staging: atomisp: Remove dead code for MID (#4) Since we switched to upstream IOSF MBI API the custom code become not in use anymore. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../atomisp/include/asm/intel_mid_pcihelpers.h | 22 ----- .../media/atomisp/pci/atomisp2/atomisp_internal.h | 1 - .../media/atomisp/platform/intel-mid/Makefile | 1 - .../platform/intel-mid/intel_mid_pcihelpers.c | 98 ---------------------- 4 files changed, 122 deletions(-) delete mode 100644 drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h delete mode 100644 drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c diff --git a/drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h b/drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h deleted file mode 100644 index bf39f42c1c96..000000000000 --- a/drivers/staging/media/atomisp/include/asm/intel_mid_pcihelpers.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Access to message bus through three registers - * in CUNIT(0:0:0) PCI configuration space. - * MSGBUS_CTRL_REG(0xD0): - * 31:24 = message bus opcode - * 23:16 = message bus port - * 15:8 = message bus address, low 8 bits. - * 7:4 = message bus byte enables - * MSGBUS_CTRL_EXT_REG(0xD8): - * 31:8 = message bus address, high 24 bits. - * MSGBUS_DATA_REG(0xD4): - * hold the data for write or read - */ -#define PCI_ROOT_MSGBUS_CTRL_REG 0xD0 -#define PCI_ROOT_MSGBUS_DATA_REG 0xD4 -#define PCI_ROOT_MSGBUS_CTRL_EXT_REG 0xD8 -#define PCI_ROOT_MSGBUS_READ 0x10 -#define PCI_ROOT_MSGBUS_WRITE 0x11 -#define PCI_ROOT_MSGBUS_DWORD_ENABLE 0xf0 - -u32 intel_mid_msgbus_read32(u8 port, u32 addr); -void intel_mid_msgbus_write32(u8 port, u32 addr, u32 data); diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_internal.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_internal.h index 7542a72f1d0f..1fe1711387a2 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_internal.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_internal.h @@ -30,7 +30,6 @@ #include #include -#include "../../include/asm/intel_mid_pcihelpers.h" #include #include diff --git a/drivers/staging/media/atomisp/platform/intel-mid/Makefile b/drivers/staging/media/atomisp/platform/intel-mid/Makefile index 4621261c35db..c53db1364e21 100644 --- a/drivers/staging/media/atomisp/platform/intel-mid/Makefile +++ b/drivers/staging/media/atomisp/platform/intel-mid/Makefile @@ -1,5 +1,4 @@ # # Makefile for intel-mid devices. # -obj-$(CONFIG_INTEL_ATOMISP) += intel_mid_pcihelpers.o obj-$(CONFIG_INTEL_ATOMISP) += atomisp_gmin_platform.o diff --git a/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c b/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c deleted file mode 100644 index 4ed3268c4e63..000000000000 --- a/drivers/staging/media/atomisp/platform/intel-mid/intel_mid_pcihelpers.c +++ /dev/null @@ -1,98 +0,0 @@ -#include -#include -#include -#include - -/* G-Min addition: "platform_is()" lives in intel_mid_pm.h in the MCG - * tree, but it's just platform ID info and we don't want to pull in - * the whole SFI-based PM architecture. - */ -#define INTEL_ATOM_MRST 0x26 -#define INTEL_ATOM_MFLD 0x27 -#define INTEL_ATOM_CLV 0x35 -#define INTEL_ATOM_MRFLD 0x4a -#define INTEL_ATOM_BYT 0x37 -#define INTEL_ATOM_MOORFLD 0x5a -#define INTEL_ATOM_CHT 0x4c -static inline int platform_is(u8 model) -{ - return (boot_cpu_data.x86_model == model); -} - -#include "../../include/asm/intel_mid_pcihelpers.h" - -/* Unified message bus read/write operation */ -static DEFINE_SPINLOCK(msgbus_lock); - -static struct pci_dev *pci_root; -static struct pm_qos_request pm_qos; - -#define DW_I2C_NEED_QOS (platform_is(INTEL_ATOM_BYT)) - -static int intel_mid_msgbus_init(void) -{ - pci_root = pci_get_bus_and_slot(0, PCI_DEVFN(0, 0)); - if (!pci_root) { - pr_err("%s: Error: msgbus PCI handle NULL\n", __func__); - return -ENODEV; - } - - if (DW_I2C_NEED_QOS) { - pm_qos_add_request(&pm_qos, - PM_QOS_CPU_DMA_LATENCY, - PM_QOS_DEFAULT_VALUE); - } - return 0; -} -fs_initcall(intel_mid_msgbus_init); - -u32 intel_mid_msgbus_read32(u8 port, u32 addr) -{ - unsigned long irq_flags; - u32 data; - u32 cmd; - u32 cmdext; - - cmd = (PCI_ROOT_MSGBUS_READ << 24) | (port << 16) | - ((addr & 0xff) << 8) | PCI_ROOT_MSGBUS_DWORD_ENABLE; - cmdext = addr & 0xffffff00; - - spin_lock_irqsave(&msgbus_lock, irq_flags); - - if (cmdext) { - /* This resets to 0 automatically, no need to write 0 */ - pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_EXT_REG, - cmdext); - } - - pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd); - pci_read_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, &data); - spin_unlock_irqrestore(&msgbus_lock, irq_flags); - - return data; -} -EXPORT_SYMBOL(intel_mid_msgbus_read32); - -void intel_mid_msgbus_write32(u8 port, u32 addr, u32 data) -{ - unsigned long irq_flags; - u32 cmd; - u32 cmdext; - - cmd = (PCI_ROOT_MSGBUS_WRITE << 24) | (port << 16) | - ((addr & 0xFF) << 8) | PCI_ROOT_MSGBUS_DWORD_ENABLE; - cmdext = addr & 0xffffff00; - - spin_lock_irqsave(&msgbus_lock, irq_flags); - pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_DATA_REG, data); - - if (cmdext) { - /* This resets to 0 automatically, no need to write 0 */ - pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_EXT_REG, - cmdext); - } - - pci_write_config_dword(pci_root, PCI_ROOT_MSGBUS_CTRL_REG, cmd); - spin_unlock_irqrestore(&msgbus_lock, irq_flags); -} -EXPORT_SYMBOL(intel_mid_msgbus_write32); -- cgit v1.2.3 From 9a965ff4273cb62ac76d22b6b6781bfa9a7f3491 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 1 Sep 2017 09:36:40 -0400 Subject: media: staging: atomisp: Remove unneeded intel-mid.h inclusion In many files in the driver the intel-mid.h header inclusion is redundant. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/imx/drv201.c | 1 - drivers/staging/media/atomisp/i2c/imx/dw9714.c | 1 - drivers/staging/media/atomisp/i2c/imx/imx.c | 1 - drivers/staging/media/atomisp/i2c/imx/otp_imx.c | 1 - drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c | 1 - drivers/staging/media/atomisp/pci/atomisp2/atomisp_internal.h | 2 -- drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c | 1 - drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c | 1 - drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c | 1 - drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.h | 1 - 10 files changed, 11 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/imx/drv201.c b/drivers/staging/media/atomisp/i2c/imx/drv201.c index 6d9d4c968722..532af7da3158 100644 --- a/drivers/staging/media/atomisp/i2c/imx/drv201.c +++ b/drivers/staging/media/atomisp/i2c/imx/drv201.c @@ -16,7 +16,6 @@ #include #include #include -#include #include "drv201.h" diff --git a/drivers/staging/media/atomisp/i2c/imx/dw9714.c b/drivers/staging/media/atomisp/i2c/imx/dw9714.c index 6397a7ee0af6..7e58fb3589cc 100644 --- a/drivers/staging/media/atomisp/i2c/imx/dw9714.c +++ b/drivers/staging/media/atomisp/i2c/imx/dw9714.c @@ -16,7 +16,6 @@ #include #include #include -#include #include "dw9714.h" diff --git a/drivers/staging/media/atomisp/i2c/imx/imx.c b/drivers/staging/media/atomisp/i2c/imx/imx.c index 49ab0af87096..71b688970822 100644 --- a/drivers/staging/media/atomisp/i2c/imx/imx.c +++ b/drivers/staging/media/atomisp/i2c/imx/imx.c @@ -18,7 +18,6 @@ * 02110-1301, USA. * */ -#include #include "../../include/linux/atomisp_platform.h" #include #include diff --git a/drivers/staging/media/atomisp/i2c/imx/otp_imx.c b/drivers/staging/media/atomisp/i2c/imx/otp_imx.c index 1ca27c26ef75..279784cab6c3 100644 --- a/drivers/staging/media/atomisp/i2c/imx/otp_imx.c +++ b/drivers/staging/media/atomisp/i2c/imx/otp_imx.c @@ -30,7 +30,6 @@ #include #include #include -#include #include "common.h" /* Defines for OTP Data Registers */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c index 73e15dd9d4d6..b0c647f4d250 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c @@ -28,7 +28,6 @@ #include #include -#include #include #include diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_internal.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_internal.h index 1fe1711387a2..6c1eb417361d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_internal.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_internal.h @@ -29,8 +29,6 @@ #include #include -#include - #include #include diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c index 717647951fb6..dd59167237c1 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c @@ -24,7 +24,6 @@ #include #include -#include #include #include diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c index 744ab6eb42a0..d27a50e66be2 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c index 0896f5ea7e4e..e85b3819bffa 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c @@ -28,7 +28,6 @@ #include #include -#include #include #include "../../include/linux/atomisp_gmin_platform.h" diff --git a/drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.h b/drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.h index b730ab0e8223..3bc0de129780 100644 --- a/drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.h +++ b/drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.h @@ -20,7 +20,6 @@ #define _PLATFORM_VLV2_PLAT_CLK_H_ #include -#include extern void __init *vlv2_plat_clk_device_platform_data( void *info) __attribute__((weak)); -- cgit v1.2.3 From 8cd0cd065f3720385eef223a63dcc552ba98bc01 Mon Sep 17 00:00:00 2001 From: Nicolas Iooss Date: Sun, 3 Sep 2017 08:05:26 -0400 Subject: media: staging/atomisp: fix header guards Files input_formatter_subsystem_defs.h begin with: #ifndef _if_subsystem_defs_h #define _if_subsystem_defs_h__ and end with: #endif /* _if_subsystem_defs_h__ */ The intent seems to have been to use _if_subsystem_defs_h__ everywhere but two underscores are missing in the initial #ifndef. Fixes: a49d25364dfb ("staging/atomisp: Add support for the Intel IPU v2") Signed-off-by: Nicolas Iooss Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../css2400/css_2400_system/hrt/input_formatter_subsystem_defs.h | 2 +- .../css2400/css_2401_csi2p_system/hrt/input_formatter_subsystem_defs.h | 2 +- .../css2400/css_2401_system/hrt/input_formatter_subsystem_defs.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2400_system/hrt/input_formatter_subsystem_defs.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2400_system/hrt/input_formatter_subsystem_defs.h index 16bfe1d80bc9..7766f78cd123 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2400_system/hrt/input_formatter_subsystem_defs.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2400_system/hrt/input_formatter_subsystem_defs.h @@ -12,7 +12,7 @@ * more details. */ -#ifndef _if_subsystem_defs_h +#ifndef _if_subsystem_defs_h__ #define _if_subsystem_defs_h__ #define HIVE_IFMT_GP_REGS_INPUT_SWITCH_LUT_REG_0 0 diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/hrt/input_formatter_subsystem_defs.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/hrt/input_formatter_subsystem_defs.h index 16bfe1d80bc9..7766f78cd123 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/hrt/input_formatter_subsystem_defs.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/hrt/input_formatter_subsystem_defs.h @@ -12,7 +12,7 @@ * more details. */ -#ifndef _if_subsystem_defs_h +#ifndef _if_subsystem_defs_h__ #define _if_subsystem_defs_h__ #define HIVE_IFMT_GP_REGS_INPUT_SWITCH_LUT_REG_0 0 diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_system/hrt/input_formatter_subsystem_defs.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_system/hrt/input_formatter_subsystem_defs.h index 16bfe1d80bc9..7766f78cd123 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_system/hrt/input_formatter_subsystem_defs.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_system/hrt/input_formatter_subsystem_defs.h @@ -12,7 +12,7 @@ * more details. */ -#ifndef _if_subsystem_defs_h +#ifndef _if_subsystem_defs_h__ #define _if_subsystem_defs_h__ #define HIVE_IFMT_GP_REGS_INPUT_SWITCH_LUT_REG_0 0 -- cgit v1.2.3 From 7e8e809185fa703aa5d88d4b1f2f7054d73ef176 Mon Sep 17 00:00:00 2001 From: Thomas Meyer Date: Sun, 3 Sep 2017 08:19:31 -0400 Subject: media: staging/atomisp: Use ARRAY_SIZE macro Use ARRAY_SIZE macro, rather than explicitly coding some variant of it yourself. Found with: find -type f -name "*.c" -o -name "*.h" | xargs perl -p -i -e 's/\bsizeof\s*\(\s*(\w+)\s*\)\s*\ /\s*sizeof\s*\(\s*\1\s*\[\s*0\s*\]\s*\) /ARRAY_SIZE(\1)/g' and manual check/verification. Signed-off-by: Thomas Meyer Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/pci/atomisp2/css2400/runtime/ifmtr/src/ifmtr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/ifmtr/src/ifmtr.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/ifmtr/src/ifmtr.c index a7c6bba7e094..11d3995ba0db 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/ifmtr/src/ifmtr.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/ifmtr/src/ifmtr.c @@ -29,6 +29,7 @@ more details. #endif #include "system_global.h" +#include #ifdef USE_INPUT_SYSTEM_VERSION_2 @@ -487,7 +488,7 @@ static void ifmtr_set_if_blocking_mode( { int i; bool block[] = { false, false, false, false }; - assert(N_INPUT_FORMATTER_ID <= (sizeof(block) / sizeof(block[0]))); + assert(N_INPUT_FORMATTER_ID <= (ARRAY_SIZE(block))); #if !defined(IS_ISP_2400_SYSTEM) #error "ifmtr_set_if_blocking_mode: ISP_SYSTEM must be one of {IS_ISP_2400_SYSTEM}" -- cgit v1.2.3 From 866af46e6ebbce55dbf6f63ad11a4a9bb3b9abf0 Mon Sep 17 00:00:00 2001 From: Branislav Radocaj Date: Thu, 7 Sep 2017 12:26:42 -0400 Subject: media: Staging: atomisp: fix alloc_cast.cocci warnings Remove casting the values returned by memory allocation functions like kmalloc, kzalloc, kmem_cache_alloc, kmem_cache_zalloc etc. Semantic patch information: This makes an effort to find cases of casting of values returned by kmalloc, kzalloc, kcalloc, kmem_cache_alloc, kmem_cache_zalloc, kmem_cache_alloc_node, kmalloc_node and kzalloc_node and removes the casting as it is not required. The result in the patch case may need some reformatting. Generated by: scripts/coccinelle/api/alloc/alloc_cast.cocci Signed-off-by: Branislav Radocaj Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c index 451c76e7eec0..696f5020dce6 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c @@ -145,7 +145,7 @@ sh_css_load_blob_info(const char *fw, const struct ia_css_fw_info *bi, struct ia size_t configstruct_size = sizeof(struct ia_css_config_memory_offsets); size_t statestruct_size = sizeof(struct ia_css_state_memory_offsets); - char *parambuf = (char *)kmalloc(paramstruct_size + configstruct_size + statestruct_size, + char *parambuf = kmalloc(paramstruct_size + configstruct_size + statestruct_size, GFP_KERNEL); if (parambuf == NULL) return IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; -- cgit v1.2.3 From 34d340b784de0ba77c3c14f26c3ae678f8bb762a Mon Sep 17 00:00:00 2001 From: Srishti Sharma Date: Tue, 12 Sep 2017 10:12:29 -0400 Subject: media: Staging: media: atomisp: Merge assignment with return Merge the assignment and the return statements to return the value directly. Done using the following semantic patch by coccinelle. @@ local idexpression ret; expression e; @@ -ret = +return e; -return ret; Signed-off-by: Srishti Sharma Acked-by: Julia Lawall Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/ov5693/ov5693.c | 11 ++--------- drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_bo.c | 6 +----- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.c index 123642557aa8..219501167584 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.c +++ b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.c @@ -945,12 +945,8 @@ static int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val) int ad5823_t_focus_abs(struct v4l2_subdev *sd, s32 value) { - int ret; - value = min(value, AD5823_MAX_FOCUS_POS); - ret = ad5823_t_focus_vcm(sd, value); - - return ret; + return ad5823_t_focus_vcm(sd, value); } static int ov5693_t_focus_abs(struct v4l2_subdev *sd, s32 value) @@ -1332,7 +1328,6 @@ static int power_ctrl(struct v4l2_subdev *sd, bool flag) static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) { - int ret; struct ov5693_device *dev = to_ov5693_sensor(sd); if (!dev || !dev->platform_data) @@ -1342,9 +1337,7 @@ static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) if (dev->platform_data->gpio_ctrl) return dev->platform_data->gpio_ctrl(sd, flag); - ret = dev->platform_data->gpio0_ctrl(sd, flag); - - return ret; + return dev->platform_data->gpio0_ctrl(sd, flag); } static int __power_up(struct v4l2_subdev *sd) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_bo.c b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_bo.c index 11162f595fc7..e6ddfbf0c4e2 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_bo.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_bo.c @@ -1168,13 +1168,9 @@ status_err2: int hmm_bo_page_allocated(struct hmm_buffer_object *bo) { - int ret; - check_bo_null_return(bo, 0); - ret = bo->status & HMM_BO_PAGE_ALLOCED; - - return ret; + return bo->status & HMM_BO_PAGE_ALLOCED; } /* -- cgit v1.2.3 From e6cc710806e191acfa2691d2fb8cb7f19ffd2b0e Mon Sep 17 00:00:00 2001 From: Allen Pais Date: Wed, 13 Sep 2017 05:15:58 -0400 Subject: media: atomisp:use ARRAY_SIZE() instead of open coding The array_length() macro just duplicates ARRAY_SIZE(), so we can delete it. Signed-off-by: Allen Pais Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c index e882b5596813..bee30438e6fd 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c @@ -451,8 +451,6 @@ static enum ia_css_frame_format yuv422_copy_formats[] = { IA_CSS_FRAME_FORMAT_YUYV }; -#define array_length(array) (sizeof(array)/sizeof(array[0])) - /* Verify whether the selected output format is can be produced * by the copy binary given the stream format. * */ @@ -468,7 +466,7 @@ verify_copy_out_frame_format(struct ia_css_pipe *pipe) switch (pipe->stream->config.input_config.format) { case IA_CSS_STREAM_FORMAT_YUV420_8_LEGACY: case IA_CSS_STREAM_FORMAT_YUV420_8: - for (i=0; i Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c index 696f5020dce6..5e45d5fe0b2a 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c @@ -235,7 +235,9 @@ sh_css_load_firmware(const char *fw_data, sh_css_blob_info = NULL; } - fw_minibuffer = kzalloc(sh_css_num_binaries * sizeof(struct fw_param), GFP_KERNEL); + fw_minibuffer = kcalloc(sh_css_num_binaries, sizeof(struct fw_param), + GFP_KERNEL); + if (fw_minibuffer == NULL) return IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; -- cgit v1.2.3 From d5426f4c2ebac8cf05de43988c3fccddbee13d28 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 20 Sep 2017 16:53:58 -0400 Subject: media: staging: atomisp: use clock framework for camera clocks The Atom ISP driver initializes and configures PMC clocks which are already handled by the clock framework. Remove all legacy vlv2_platform_clock stuff and move to the clk API to avoid conflicts, e.g. with audio machine drivers enabling the MCLK for external codecs Fixes: a49d25364dfb ("staging/atomisp: Add support for the Intel IPU v2") Tested-by: Carlo Caione Reviewed-by: Andy Shevchenko Signed-off-by: Pierre-Louis Bossart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/Kconfig | 1 + drivers/staging/media/atomisp/platform/Makefile | 1 - .../staging/media/atomisp/platform/clock/Makefile | 6 - .../platform/clock/platform_vlv2_plat_clk.c | 40 ---- .../platform/clock/platform_vlv2_plat_clk.h | 26 --- .../media/atomisp/platform/clock/vlv2_plat_clock.c | 247 --------------------- .../platform/intel-mid/atomisp_gmin_platform.c | 63 +++++- 7 files changed, 52 insertions(+), 332 deletions(-) delete mode 100644 drivers/staging/media/atomisp/platform/clock/Makefile delete mode 100644 drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.c delete mode 100644 drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.h delete mode 100644 drivers/staging/media/atomisp/platform/clock/vlv2_plat_clock.c diff --git a/drivers/staging/media/atomisp/Kconfig b/drivers/staging/media/atomisp/Kconfig index 52b86b7e433f..27f078749148 100644 --- a/drivers/staging/media/atomisp/Kconfig +++ b/drivers/staging/media/atomisp/Kconfig @@ -1,6 +1,7 @@ menuconfig INTEL_ATOMISP bool "Enable support to Intel MIPI camera drivers" depends on X86 && EFI && MEDIA_CONTROLLER && PCI && ACPI + select COMMON_CLK help Enable support for the Intel ISP2 camera interfaces and MIPI sensor drivers. diff --git a/drivers/staging/media/atomisp/platform/Makefile b/drivers/staging/media/atomisp/platform/Makefile index df157630bda9..0e3b7e1c81c6 100644 --- a/drivers/staging/media/atomisp/platform/Makefile +++ b/drivers/staging/media/atomisp/platform/Makefile @@ -2,5 +2,4 @@ # Makefile for camera drivers. # -obj-$(CONFIG_INTEL_ATOMISP) += clock/ obj-$(CONFIG_INTEL_ATOMISP) += intel-mid/ diff --git a/drivers/staging/media/atomisp/platform/clock/Makefile b/drivers/staging/media/atomisp/platform/clock/Makefile deleted file mode 100644 index 82fbe8b6968a..000000000000 --- a/drivers/staging/media/atomisp/platform/clock/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# -# Makefile for clock devices. -# - -obj-$(CONFIG_INTEL_ATOMISP) += vlv2_plat_clock.o -obj-$(CONFIG_INTEL_ATOMISP) += platform_vlv2_plat_clk.o diff --git a/drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.c b/drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.c deleted file mode 100644 index 0aae9b0283bb..000000000000 --- a/drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * platform_vlv2_plat_clk.c - VLV2 platform clock driver - * Copyright (C) 2013 Intel Corporation - * - * Author: Asutosh Pathak - * Author: Chandra Sekhar Anagani - * Author: Sergio Aguirre - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - */ - -#include -#include -#include -#include -#include - -static int __init vlv2_plat_clk_init(void) -{ - struct platform_device *pdev; - - pdev = platform_device_register_simple("vlv2_plat_clk", -1, NULL, 0); - if (IS_ERR(pdev)) { - pr_err("platform_vlv2_plat_clk:register failed: %ld\n", - PTR_ERR(pdev)); - return PTR_ERR(pdev); - } - - return 0; -} - -device_initcall(vlv2_plat_clk_init); diff --git a/drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.h b/drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.h deleted file mode 100644 index 3bc0de129780..000000000000 --- a/drivers/staging/media/atomisp/platform/clock/platform_vlv2_plat_clk.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * platform_vlv2_plat_clk.h: platform clock driver library header file - * Copyright (C) 2013 Intel Corporation - * - * Author: Asutosh Pathak - * Author: Chandra Sekhar Anagani - * Author: Sergio Aguirre - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - */ -#ifndef _PLATFORM_VLV2_PLAT_CLK_H_ -#define _PLATFORM_VLV2_PLAT_CLK_H_ - -#include - -extern void __init *vlv2_plat_clk_device_platform_data( - void *info) __attribute__((weak)); -#endif diff --git a/drivers/staging/media/atomisp/platform/clock/vlv2_plat_clock.c b/drivers/staging/media/atomisp/platform/clock/vlv2_plat_clock.c deleted file mode 100644 index f96789a31819..000000000000 --- a/drivers/staging/media/atomisp/platform/clock/vlv2_plat_clock.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - * vlv2_plat_clock.c - VLV2 platform clock driver - * Copyright (C) 2013 Intel Corporation - * - * Author: Asutosh Pathak - * Author: Chandra Sekhar Anagani - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - */ - -#include -#include -#include -#include -#include "../../include/linux/vlv2_plat_clock.h" - -/* NOTE: Most of below constants could come from platform data. - * To be fixed when appropriate ACPI support comes. - */ -#define VLV2_PMC_CLK_BASE_ADDRESS 0xfed03060 -#define PLT_CLK_CTL_OFFSET(x) (0x04 * (x)) - -#define CLK_CONFG_BIT_POS 0 -#define CLK_CONFG_BIT_LEN 2 -#define CLK_CONFG_D3_GATED 0 -#define CLK_CONFG_FORCE_ON 1 -#define CLK_CONFG_FORCE_OFF 2 - -#define CLK_FREQ_TYPE_BIT_POS 2 -#define CLK_FREQ_TYPE_BIT_LEN 1 -#define CLK_FREQ_TYPE_XTAL 0 /* 25 MHz */ -#define CLK_FREQ_TYPE_PLL 1 /* 19.2 MHz */ - -#define MAX_CLK_COUNT 5 - -/* Helper macros to manipulate bitfields */ -#define REG_MASK(n) (((1 << (n##_BIT_LEN)) - 1) << (n##_BIT_POS)) -#define REG_SET_FIELD(r, n, v) (((r) & ~REG_MASK(n)) | \ - (((v) << (n##_BIT_POS)) & REG_MASK(n))) -#define REG_GET_FIELD(r, n) (((r) & REG_MASK(n)) >> n##_BIT_POS) -/* - * vlv2 platform has 6 platform clocks, controlled by 4 byte registers - * Total size required for mapping is 6*4 = 24 bytes - */ -#define PMC_MAP_SIZE 24 - -static DEFINE_MUTEX(clk_mutex); -static void __iomem *pmc_base; - -/* - * vlv2_plat_set_clock_freq - Set clock frequency to a specified platform clock - * @clk_num: Platform clock number (i.e. 0, 1, 2, ...,5) - * @freq_type: Clock frequency (0-25 MHz(XTAL), 1-19.2 MHz(PLL) ) - */ -int vlv2_plat_set_clock_freq(int clk_num, int freq_type) -{ - void __iomem *addr; - - if (clk_num < 0 || clk_num >= MAX_CLK_COUNT) { - pr_err("Clock number out of range (%d)\n", clk_num); - return -EINVAL; - } - - if (freq_type != CLK_FREQ_TYPE_XTAL && - freq_type != CLK_FREQ_TYPE_PLL) { - pr_err("wrong clock type\n"); - return -EINVAL; - } - - if (!pmc_base) { - pr_err("memio map is not set\n"); - return -EINVAL; - } - - addr = pmc_base + PLT_CLK_CTL_OFFSET(clk_num); - - mutex_lock(&clk_mutex); - writel(REG_SET_FIELD(readl(addr), CLK_FREQ_TYPE, freq_type), addr); - mutex_unlock(&clk_mutex); - - return 0; -} -EXPORT_SYMBOL_GPL(vlv2_plat_set_clock_freq); - -/* - * vlv2_plat_get_clock_freq - Get the status of specified platform clock - * @clk_num: Platform clock number (i.e. 0, 1, 2, ...,5) - * - * Returns 0 for 25 MHz(XTAL) and 1 for 19.2 MHz(PLL) - */ -int vlv2_plat_get_clock_freq(int clk_num) -{ - u32 ret; - - if (clk_num < 0 || clk_num >= MAX_CLK_COUNT) { - pr_err("Clock number out of range (%d)\n", clk_num); - return -EINVAL; - } - - if (!pmc_base) { - pr_err("memio map is not set\n"); - return -EINVAL; - } - - mutex_lock(&clk_mutex); - ret = REG_GET_FIELD(readl(pmc_base + PLT_CLK_CTL_OFFSET(clk_num)), - CLK_FREQ_TYPE); - mutex_unlock(&clk_mutex); - return ret; -} -EXPORT_SYMBOL_GPL(vlv2_plat_get_clock_freq); - -/* - * vlv2_plat_configure_clock - Configure the specified platform clock - * @clk_num: Platform clock number (i.e. 0, 1, 2, ...,5) - * @conf: Clock gating: - * 0 - Clock gated on D3 state - * 1 - Force on - * 2,3 - Force off - */ -int vlv2_plat_configure_clock(int clk_num, u32 conf) -{ - void __iomem *addr; - - if (clk_num < 0 || clk_num >= MAX_CLK_COUNT) { - pr_err("Clock number out of range (%d)\n", clk_num); - return -EINVAL; - } - - if (conf != CLK_CONFG_D3_GATED && - conf != CLK_CONFG_FORCE_ON && - conf != CLK_CONFG_FORCE_OFF) { - pr_err("Invalid clock configuration requested\n"); - return -EINVAL; - } - - if (!pmc_base) { - pr_err("memio map is not set\n"); - return -EINVAL; - } - - addr = pmc_base + PLT_CLK_CTL_OFFSET(clk_num); - - mutex_lock(&clk_mutex); - writel(REG_SET_FIELD(readl(addr), CLK_CONFG, conf), addr); - mutex_unlock(&clk_mutex); - return 0; -} -EXPORT_SYMBOL_GPL(vlv2_plat_configure_clock); - -/* - * vlv2_plat_get_clock_status - Get the status of specified platform clock - * @clk_num: Platform clock number (i.e. 0, 1, 2, ...,5) - * - * Returns 1 - On, 0 - Off - */ -int vlv2_plat_get_clock_status(int clk_num) -{ - int ret; - - if (clk_num < 0 || clk_num >= MAX_CLK_COUNT) { - pr_err("Clock number out of range (%d)\n", clk_num); - return -EINVAL; - } - - if (!pmc_base) { - pr_err("memio map is not set\n"); - return -EINVAL; - } - - mutex_lock(&clk_mutex); - ret = (int)REG_GET_FIELD(readl(pmc_base + PLT_CLK_CTL_OFFSET(clk_num)), - CLK_CONFG); - mutex_unlock(&clk_mutex); - return ret; -} -EXPORT_SYMBOL_GPL(vlv2_plat_get_clock_status); - -static int vlv2_plat_clk_probe(struct platform_device *pdev) -{ - int i = 0; - - pmc_base = ioremap_nocache(VLV2_PMC_CLK_BASE_ADDRESS, PMC_MAP_SIZE); - if (!pmc_base) { - dev_err(&pdev->dev, "I/O memory remapping failed\n"); - return -ENOMEM; - } - - /* Initialize all clocks as disabled */ - for (i = 0; i < MAX_CLK_COUNT; i++) - vlv2_plat_configure_clock(i, CLK_CONFG_FORCE_OFF); - - dev_info(&pdev->dev, "vlv2_plat_clk initialized\n"); - return 0; -} - -static const struct platform_device_id vlv2_plat_clk_id[] = { - {"vlv2_plat_clk", 0}, - {} -}; - -static int vlv2_resume(struct device *device) -{ - int i; - - /* Initialize all clocks as disabled */ - for (i = 0; i < MAX_CLK_COUNT; i++) - vlv2_plat_configure_clock(i, CLK_CONFG_FORCE_OFF); - - return 0; -} - -static int vlv2_suspend(struct device *device) -{ - return 0; -} - -static const struct dev_pm_ops vlv2_pm_ops = { - .suspend = vlv2_suspend, - .resume = vlv2_resume, -}; - -static struct platform_driver vlv2_plat_clk_driver = { - .probe = vlv2_plat_clk_probe, - .id_table = vlv2_plat_clk_id, - .driver = { - .name = "vlv2_plat_clk", - .pm = &vlv2_pm_ops, - }, -}; - -static int __init vlv2_plat_clk_init(void) -{ - return platform_driver_register(&vlv2_plat_clk_driver); -} -arch_initcall(vlv2_plat_clk_init); diff --git a/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c index edaae93af8f9..17b4cfae5abf 100644 --- a/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c @@ -4,10 +4,10 @@ #include #include #include +#include #include #include #include -#include "../../include/linux/vlv2_plat_clock.h" #include #include #include @@ -17,11 +17,7 @@ #define MAX_SUBDEVS 8 -/* Should be defined in vlv2_plat_clock API, isn't: */ -#define VLV2_CLK_PLL_19P2MHZ 1 -#define VLV2_CLK_XTAL_19P2MHZ 0 -#define VLV2_CLK_ON 1 -#define VLV2_CLK_OFF 2 +#define VLV2_CLK_PLL_19P2MHZ 1 /* XTAL on CHT */ #define ELDO1_SEL_REG 0x19 #define ELDO1_1P8V 0x16 #define ELDO1_CTRL_SHIFT 0x00 @@ -33,6 +29,7 @@ struct gmin_subdev { struct v4l2_subdev *subdev; int clock_num; int clock_src; + struct clk *pmc_clk; struct gpio_desc *gpio0; struct gpio_desc *gpio1; struct regulator *v1p8_reg; @@ -344,6 +341,9 @@ static int gmin_platform_deinit(void) return 0; } +#define GMIN_PMC_CLK_NAME 14 /* "pmc_plt_clk_[0..5]" */ +static char gmin_pmc_clk_name[GMIN_PMC_CLK_NAME]; + static struct gmin_subdev *gmin_subdev_add(struct v4l2_subdev *subdev) { int i, ret; @@ -377,6 +377,37 @@ static struct gmin_subdev *gmin_subdev_add(struct v4l2_subdev *subdev) gmin_subdevs[i].gpio0 = gpiod_get_index(dev, NULL, 0, GPIOD_OUT_LOW); gmin_subdevs[i].gpio1 = gpiod_get_index(dev, NULL, 1, GPIOD_OUT_LOW); + /* get PMC clock with clock framework */ + snprintf(gmin_pmc_clk_name, + sizeof(gmin_pmc_clk_name), + "%s_%d", "pmc_plt_clk", gmin_subdevs[i].clock_num); + + gmin_subdevs[i].pmc_clk = devm_clk_get(dev, gmin_pmc_clk_name); + if (IS_ERR(gmin_subdevs[i].pmc_clk)) { + ret = PTR_ERR(gmin_subdevs[i].pmc_clk); + + dev_err(dev, + "Failed to get clk from %s : %d\n", + gmin_pmc_clk_name, + ret); + + return NULL; + } + + /* + * The firmware might enable the clock at + * boot (this information may or may not + * be reflected in the enable clock register). + * To change the rate we must disable the clock + * first to cover these cases. Due to common + * clock framework restrictions that do not allow + * to disable a clock that has not been enabled, + * we need to enable the clock first. + */ + ret = clk_prepare_enable(gmin_subdevs[i].pmc_clk); + if (!ret) + clk_disable_unprepare(gmin_subdevs[i].pmc_clk); + if (!IS_ERR(gmin_subdevs[i].gpio0)) { ret = gpiod_direction_output(gmin_subdevs[i].gpio0, 0); if (ret) @@ -539,13 +570,21 @@ static int gmin_flisclk_ctrl(struct v4l2_subdev *subdev, int on) { int ret = 0; struct gmin_subdev *gs = find_gmin_subdev(subdev); + struct i2c_client *client = v4l2_get_subdevdata(subdev); + + if (on) { + ret = clk_set_rate(gs->pmc_clk, gs->clock_src); + + if (ret) + dev_err(&client->dev, "unable to set PMC rate %d\n", + gs->clock_src); - if (on) - ret = vlv2_plat_set_clock_freq(gs->clock_num, gs->clock_src); - if (ret) - return ret; - return vlv2_plat_configure_clock(gs->clock_num, - on ? VLV2_CLK_ON : VLV2_CLK_OFF); + ret = clk_prepare_enable(gs->pmc_clk); + } else { + clk_disable_unprepare(gs->pmc_clk); + } + + return ret; } static int gmin_csi_cfg(struct v4l2_subdev *sd, int flag) -- cgit v1.2.3 From de226ec8a6ac10e65fcc689a28761c966986e6a6 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Sun, 25 Jun 2017 09:31:19 -0300 Subject: [media] media: lirc_dev: clarify error handling If an error is generated, it is more logical to error out ASAP. Signed-off-by: David Härdeman Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 9080e39ea391..5e3c4779d866 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -286,7 +286,7 @@ EXPORT_SYMBOL(lirc_unregister_driver); int lirc_dev_fop_open(struct inode *inode, struct file *file) { struct irctl *ir; - int retval = 0; + int retval; if (iminor(inode) >= MAX_IRCTL_DEVICES) { pr_err("open result for %d is -ENODEV\n", iminor(inode)); @@ -327,9 +327,11 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file) ir->open++; -error: nonseekable_open(inode, file); + return 0; + +error: return retval; } EXPORT_SYMBOL(lirc_dev_fop_open); -- cgit v1.2.3 From c3c6dd750e0b8dcee0306b9c5a45708922debbbe Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Sun, 25 Jun 2017 09:31:24 -0300 Subject: [media] media: lirc_dev: remove support for manually specifying minor number All users of lirc_register_driver() uses dynamic minor allocation, therefore we can remove the ability to explicitly request a given number. This changes the function prototype of lirc_unregister_driver() to also take a struct lirc_driver pointer as the sole argument. Signed-off-by: David Härdeman Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 9 ++--- drivers/media/rc/lirc_dev.c | 68 +++++++++------------------------ drivers/staging/media/lirc/lirc_zilog.c | 14 +++---- include/media/lirc_dev.h | 20 +++++----- 4 files changed, 34 insertions(+), 77 deletions(-) diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index d2223c04e9ad..58bff7a75d5b 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -382,7 +382,6 @@ static int ir_lirc_register(struct rc_dev *dev) snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)", dev->driver_name); - drv->minor = -1; drv->features = features; drv->data = &dev->raw->lirc; drv->rbuf = NULL; @@ -394,11 +393,9 @@ static int ir_lirc_register(struct rc_dev *dev) drv->rdev = dev; drv->owner = THIS_MODULE; - drv->minor = lirc_register_driver(drv); - if (drv->minor < 0) { - rc = -ENODEV; + rc = lirc_register_driver(drv); + if (rc < 0) goto out; - } dev->raw->lirc.drv = drv; dev->raw->lirc.dev = dev; @@ -413,7 +410,7 @@ static int ir_lirc_unregister(struct rc_dev *dev) { struct lirc_codec *lirc = &dev->raw->lirc; - lirc_unregister_driver(lirc->drv->minor); + lirc_unregister_driver(lirc->drv); kfree(lirc->drv); lirc->drv = NULL; diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 5e3c4779d866..f1d8c1ef072e 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -29,7 +29,6 @@ #include #include -#define NOPLUG -1 #define LOGHEAD "lirc_dev (%s[%d]): " static dev_t lirc_base_dev; @@ -114,7 +113,7 @@ out: int lirc_register_driver(struct lirc_driver *d) { struct irctl *ir; - int minor; + unsigned int minor; int err; if (!d) { @@ -132,12 +131,6 @@ int lirc_register_driver(struct lirc_driver *d) return -EINVAL; } - if (d->minor >= MAX_IRCTL_DEVICES) { - dev_err(d->dev, "minor must be between 0 and %d!\n", - MAX_IRCTL_DEVICES - 1); - return -EBADRQC; - } - if (d->code_length < 1 || d->code_length > (BUFLEN * 8)) { dev_err(d->dev, "code length must be less than %d bits\n", BUFLEN * 8); @@ -152,21 +145,14 @@ int lirc_register_driver(struct lirc_driver *d) mutex_lock(&lirc_dev_lock); - minor = d->minor; + /* find first free slot for driver */ + for (minor = 0; minor < MAX_IRCTL_DEVICES; minor++) + if (!irctls[minor]) + break; - if (minor < 0) { - /* find first free slot for driver */ - for (minor = 0; minor < MAX_IRCTL_DEVICES; minor++) - if (!irctls[minor]) - break; - if (minor == MAX_IRCTL_DEVICES) { - dev_err(d->dev, "no free slots for drivers!\n"); - err = -ENOMEM; - goto out_lock; - } - } else if (irctls[minor]) { - dev_err(d->dev, "minor (%d) just registered!\n", minor); - err = -EBUSY; + if (minor == MAX_IRCTL_DEVICES) { + dev_err(d->dev, "no free slots for drivers!\n"); + err = -ENOMEM; goto out_lock; } @@ -178,6 +164,7 @@ int lirc_register_driver(struct lirc_driver *d) mutex_init(&ir->irctl_lock); irctls[minor] = ir; + d->irctl = ir; d->minor = minor; /* some safety check 8-) */ @@ -225,7 +212,7 @@ int lirc_register_driver(struct lirc_driver *d) dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n", ir->d.name, ir->d.minor); - return minor; + return 0; out_cdev: cdev_del(&ir->cdev); @@ -238,38 +225,24 @@ out_lock: } EXPORT_SYMBOL(lirc_register_driver); -int lirc_unregister_driver(int minor) +void lirc_unregister_driver(struct lirc_driver *d) { struct irctl *ir; - if (minor < 0 || minor >= MAX_IRCTL_DEVICES) { - pr_err("minor (%d) must be between 0 and %d!\n", - minor, MAX_IRCTL_DEVICES - 1); - return -EBADRQC; - } + if (!d || !d->irctl) + return; - ir = irctls[minor]; - if (!ir) { - pr_err("failed to get irctl\n"); - return -ENOENT; - } + ir = d->irctl; mutex_lock(&lirc_dev_lock); - if (ir->d.minor != minor) { - dev_err(ir->d.dev, "lirc_dev: minor %d device not registered\n", - minor); - mutex_unlock(&lirc_dev_lock); - return -ENOENT; - } - dev_dbg(ir->d.dev, "lirc_dev: driver %s unregistered from minor = %d\n", - ir->d.name, ir->d.minor); + d->name, d->minor); ir->attached = 0; if (ir->open) { dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n", - ir->d.name, ir->d.minor); + d->name, d->minor); wake_up_interruptible(&ir->buf->wait_poll); } @@ -278,8 +251,6 @@ int lirc_unregister_driver(int minor) device_del(&ir->dev); cdev_del(&ir->cdev); put_device(&ir->dev); - - return 0; } EXPORT_SYMBOL(lirc_unregister_driver); @@ -306,11 +277,6 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file) dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor); - if (ir->d.minor == NOPLUG) { - retval = -ENODEV; - goto error; - } - if (ir->open) { retval = -EBUSY; goto error; @@ -403,7 +369,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n", ir->d.name, ir->d.minor, cmd); - if (ir->d.minor == NOPLUG || !ir->attached) { + if (!ir->attached) { dev_err(ir->d.dev, LOGHEAD "ioctl result = -ENODEV\n", ir->d.name, ir->d.minor); return -ENODEV; diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c index 71af13bd0ebd..efcbfef1980e 100644 --- a/drivers/staging/media/lirc/lirc_zilog.c +++ b/drivers/staging/media/lirc/lirc_zilog.c @@ -183,10 +183,7 @@ static void release_ir_device(struct kref *ref) * ir->open_count == 0 - happens on final close() * ir_lock, tx_ref_lock, rx_ref_lock, all released */ - if (ir->l.minor >= 0) { - lirc_unregister_driver(ir->l.minor); - ir->l.minor = -1; - } + lirc_unregister_driver(&ir->l); if (kfifo_initialized(&ir->rbuf.fifo)) lirc_buffer_free(&ir->rbuf); @@ -1385,7 +1382,6 @@ static const struct file_operations lirc_fops = { static struct lirc_driver lirc_template = { .name = "lirc_zilog", - .minor = -1, .code_length = 13, .buffer_size = BUFLEN / 2, .chunk_size = 2, @@ -1599,14 +1595,14 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) } /* register with lirc */ - ir->l.minor = lirc_register_driver(&ir->l); - if (ir->l.minor < 0) { + ret = lirc_register_driver(&ir->l); + if (ret < 0) { dev_err(tx->ir->l.dev, "%s: lirc_register_driver() failed: %i\n", - __func__, ir->l.minor); - ret = -EBADRQC; + __func__, ret); goto out_put_xx; } + dev_info(ir->l.dev, "IR unit on %s (i2c-%d) registered as lirc%d and ready\n", adap->name, adap->nr, ir->l.minor); diff --git a/include/media/lirc_dev.h b/include/media/lirc_dev.h index 86d15a9b6c01..1bb9890744fa 100644 --- a/include/media/lirc_dev.h +++ b/include/media/lirc_dev.h @@ -116,10 +116,8 @@ static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf, * * @name: this string will be used for logs * - * @minor: indicates minor device (/dev/lirc) number for - * registered driver if caller fills it with negative - * value, then the first free minor number will be used - * (if available). + * @minor: the minor device (/dev/lircX) number for a registered + * driver. * * @code_length: length of the remote control key code expressed in bits. * @@ -157,10 +155,12 @@ static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf, * device. * * @owner: the module owning this struct + * + * @irctl: the struct irctl for this LIRC device. */ struct lirc_driver { char name[40]; - int minor; + unsigned int minor; __u32 code_length; unsigned int buffer_size; /* in chunks holding one code each */ __u32 features; @@ -175,19 +175,17 @@ struct lirc_driver { const struct file_operations *fops; struct device *dev; struct module *owner; + struct irctl *irctl; }; /* following functions can be called ONLY from user context * - * returns negative value on error or minor number - * of the registered device if success + * returns negative value on error or zero * contents of the structure pointed by p is copied */ -extern int lirc_register_driver(struct lirc_driver *d); +int lirc_register_driver(struct lirc_driver *d); -/* returns negative value on error or 0 if success -*/ -extern int lirc_unregister_driver(int minor); +void lirc_unregister_driver(struct lirc_driver *d); /* Returns the private data stored in the lirc_driver * associated with the given device file pointer. -- cgit v1.2.3 From 0510d81081498eae2a8bf9d116cc03492fab5894 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Sun, 25 Jun 2017 09:31:35 -0300 Subject: [media] media: lirc_dev: use cdev_device_add() helper function Replace calls to cdev_add() and device_add() with the cdev_device_add() helper function. Signed-off-by: David Härdeman Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index f1d8c1ef072e..057983b8ec53 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -193,17 +193,11 @@ int lirc_register_driver(struct lirc_driver *d) cdev_init(&ir->cdev, d->fops); ir->cdev.owner = ir->d.owner; - ir->cdev.kobj.parent = &ir->dev.kobj; - - err = cdev_add(&ir->cdev, ir->dev.devt, 1); - if (err) - goto out_free_dev; - ir->attached = 1; - err = device_add(&ir->dev); + err = cdev_device_add(&ir->cdev, &ir->dev); if (err) - goto out_cdev; + goto out_dev; mutex_unlock(&lirc_dev_lock); @@ -214,9 +208,7 @@ int lirc_register_driver(struct lirc_driver *d) return 0; -out_cdev: - cdev_del(&ir->cdev); -out_free_dev: +out_dev: put_device(&ir->dev); out_lock: mutex_unlock(&lirc_dev_lock); @@ -248,8 +240,7 @@ void lirc_unregister_driver(struct lirc_driver *d) mutex_unlock(&lirc_dev_lock); - device_del(&ir->dev); - cdev_del(&ir->cdev); + cdev_device_del(&ir->cdev, &ir->dev); put_device(&ir->dev); } EXPORT_SYMBOL(lirc_unregister_driver); -- cgit v1.2.3 From 615cd3fe6cccb950b46728120009a1805cce908e Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Sun, 25 Jun 2017 09:31:40 -0300 Subject: [media] media: lirc_dev: make better use of file->private_data By making better use of file->private_data in lirc_dev we can avoid digging around in the irctls[] array, thereby simplifying the code. External drivers need to use lirc_get_pdata() instead of mucking around in file->private_data. The newly introduced lirc_init_pdata() function isn't very elegant, but it's a stopgap measure which can be removed once lirc_zilog is converted to rc-core. Signed-off-by: David Härdeman Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 70 ++++++++++----------------------- drivers/staging/media/lirc/lirc_zilog.c | 53 +++++-------------------- include/media/lirc_dev.h | 3 ++ 3 files changed, 33 insertions(+), 93 deletions(-) diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 057983b8ec53..ffa203eb2045 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -247,36 +247,18 @@ EXPORT_SYMBOL(lirc_unregister_driver); int lirc_dev_fop_open(struct inode *inode, struct file *file) { - struct irctl *ir; + struct irctl *ir = container_of(inode->i_cdev, struct irctl, cdev); int retval; - if (iminor(inode) >= MAX_IRCTL_DEVICES) { - pr_err("open result for %d is -ENODEV\n", iminor(inode)); - return -ENODEV; - } - - if (mutex_lock_interruptible(&lirc_dev_lock)) - return -ERESTARTSYS; - - ir = irctls[iminor(inode)]; - mutex_unlock(&lirc_dev_lock); - - if (!ir) { - retval = -ENODEV; - goto error; - } - dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor); - if (ir->open) { - retval = -EBUSY; - goto error; - } + if (ir->open) + return -EBUSY; if (ir->d.rdev) { retval = rc_open(ir->d.rdev); if (retval) - goto error; + return retval; } if (ir->buf) @@ -284,25 +266,18 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file) ir->open++; + lirc_init_pdata(inode, file); nonseekable_open(inode, file); return 0; - -error: - return retval; } EXPORT_SYMBOL(lirc_dev_fop_open); int lirc_dev_fop_close(struct inode *inode, struct file *file) { - struct irctl *ir = irctls[iminor(inode)]; + struct irctl *ir = file->private_data; int ret; - if (!ir) { - pr_err("called with invalid irctl\n"); - return -EINVAL; - } - ret = mutex_lock_killable(&lirc_dev_lock); WARN_ON(ret); @@ -318,14 +293,9 @@ EXPORT_SYMBOL(lirc_dev_fop_close); unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait) { - struct irctl *ir = irctls[iminor(file_inode(file))]; + struct irctl *ir = file->private_data; unsigned int ret; - if (!ir) { - pr_err("called with invalid irctl\n"); - return POLLERR; - } - if (!ir->attached) return POLLHUP | POLLERR; @@ -348,14 +318,9 @@ EXPORT_SYMBOL(lirc_dev_fop_poll); long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { + struct irctl *ir = file->private_data; __u32 mode; int result = 0; - struct irctl *ir = irctls[iminor(file_inode(file))]; - - if (!ir) { - pr_err("no irctl found!\n"); - return -ENODEV; - } dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n", ir->d.name, ir->d.minor, cmd); @@ -432,16 +397,11 @@ ssize_t lirc_dev_fop_read(struct file *file, size_t length, loff_t *ppos) { - struct irctl *ir = irctls[iminor(file_inode(file))]; + struct irctl *ir = file->private_data; unsigned char *buf; int ret = 0, written = 0; DECLARE_WAITQUEUE(wait, current); - if (!ir) { - pr_err("called with invalid irctl\n"); - return -ENODEV; - } - if (!LIRC_CAN_REC(ir->d.features)) return -EINVAL; @@ -532,9 +492,19 @@ out_unlocked: } EXPORT_SYMBOL(lirc_dev_fop_read); +void lirc_init_pdata(struct inode *inode, struct file *file) +{ + struct irctl *ir = container_of(inode->i_cdev, struct irctl, cdev); + + file->private_data = ir; +} +EXPORT_SYMBOL(lirc_init_pdata); + void *lirc_get_pdata(struct file *file) { - return irctls[iminor(file_inode(file))]->d.data; + struct irctl *ir = file->private_data; + + return ir->d.data; } EXPORT_SYMBOL(lirc_get_pdata); diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c index efcbfef1980e..c4a4c2f93ae8 100644 --- a/drivers/staging/media/lirc/lirc_zilog.c +++ b/drivers/staging/media/lirc/lirc_zilog.c @@ -879,7 +879,7 @@ out: static ssize_t read(struct file *filep, char __user *outbuf, size_t n, loff_t *ppos) { - struct IR *ir = filep->private_data; + struct IR *ir = lirc_get_pdata(filep); struct IR_rx *rx; struct lirc_buffer *rbuf = ir->l.rbuf; int ret = 0, written = 0, retries = 0; @@ -1089,7 +1089,7 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) static ssize_t write(struct file *filep, const char __user *buf, size_t n, loff_t *ppos) { - struct IR *ir = filep->private_data; + struct IR *ir = lirc_get_pdata(filep); struct IR_tx *tx; size_t i; int failures = 0; @@ -1197,7 +1197,7 @@ static ssize_t write(struct file *filep, const char __user *buf, size_t n, /* copied from lirc_dev */ static unsigned int poll(struct file *filep, poll_table *wait) { - struct IR *ir = filep->private_data; + struct IR *ir = lirc_get_pdata(filep); struct IR_rx *rx; struct lirc_buffer *rbuf = ir->l.rbuf; unsigned int ret; @@ -1230,7 +1230,7 @@ static unsigned int poll(struct file *filep, poll_table *wait) static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { - struct IR *ir = filep->private_data; + struct IR *ir = lirc_get_pdata(filep); unsigned long __user *uptr = (unsigned long __user *)arg; int result; unsigned long mode, features; @@ -1280,46 +1280,18 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg) return result; } -static struct IR *get_ir_device_by_minor(unsigned int minor) -{ - struct IR *ir; - struct IR *ret = NULL; - - mutex_lock(&ir_devices_lock); - - if (!list_empty(&ir_devices_list)) { - list_for_each_entry(ir, &ir_devices_list, list) { - if (ir->l.minor == minor) { - ret = get_ir_device(ir, true); - break; - } - } - } - - mutex_unlock(&ir_devices_lock); - return ret; -} - /* - * Open the IR device. Get hold of our IR structure and - * stash it in private_data for the file + * Open the IR device. */ static int open(struct inode *node, struct file *filep) { struct IR *ir; - unsigned int minor = MINOR(node->i_rdev); - - /* find our IR struct */ - ir = get_ir_device_by_minor(minor); - if (!ir) - return -ENODEV; + lirc_init_pdata(node, filep); + ir = lirc_get_pdata(filep); atomic_inc(&ir->open_count); - /* stash our IR struct */ - filep->private_data = ir; - nonseekable_open(node, filep); return 0; } @@ -1327,14 +1299,7 @@ static int open(struct inode *node, struct file *filep) /* Close the IR device */ static int close(struct inode *node, struct file *filep) { - /* find our IR struct */ - struct IR *ir = filep->private_data; - - if (!ir) { - pr_err("ir: %s: no private_data attached to the file!\n", - __func__); - return -ENODEV; - } + struct IR *ir = lirc_get_pdata(filep); atomic_dec(&ir->open_count); @@ -1489,6 +1454,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) */ ir->l.rbuf = &ir->rbuf; ir->l.dev = &adap->dev; + /* This will be returned by lirc_get_pdata() */ + ir->l.data = ir; ret = lirc_buffer_init(ir->l.rbuf, ir->l.chunk_size, ir->l.buffer_size); if (ret) diff --git a/include/media/lirc_dev.h b/include/media/lirc_dev.h index 1bb9890744fa..d07a53232ffc 100644 --- a/include/media/lirc_dev.h +++ b/include/media/lirc_dev.h @@ -187,6 +187,9 @@ int lirc_register_driver(struct lirc_driver *d); void lirc_unregister_driver(struct lirc_driver *d); +/* Must be called in the open fop before lirc_get_pdata() can be used */ +void lirc_init_pdata(struct inode *inode, struct file *file); + /* Returns the private data stored in the lirc_driver * associated with the given device file pointer. */ -- cgit v1.2.3 From b145ef94f63e02c2615ffde61a376b53f3367bc6 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Sun, 25 Jun 2017 09:31:45 -0300 Subject: [media] media: lirc_dev: make chunk_size and buffer_size mandatory Make setting chunk_size and buffer_size mandatory for drivers which expect lirc_dev to allocate the lirc_buffer (i.e. ir-lirc-codec) and don't set them in lirc-zilog (which creates its own buffer). Also remove an unnecessary copy of chunk_size in struct irctl (the same information is already available from struct lirc_buffer). Signed-off-by: David Härdeman Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 26 +++++++++++++------------- drivers/staging/media/lirc/lirc_zilog.c | 5 +---- include/media/lirc_dev.h | 9 +++++---- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index ffa203eb2045..1915ffc52955 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -41,7 +41,6 @@ struct irctl { struct mutex irctl_lock; struct lirc_buffer *buf; bool buf_internal; - unsigned int chunk_size; struct device dev; struct cdev cdev; @@ -74,16 +73,8 @@ static void lirc_release(struct device *ld) static int lirc_allocate_buffer(struct irctl *ir) { int err = 0; - int bytes_in_key; - unsigned int chunk_size; - unsigned int buffer_size; struct lirc_driver *d = &ir->d; - bytes_in_key = BITS_TO_LONGS(d->code_length) + - (d->code_length % 8 ? 1 : 0); - buffer_size = d->buffer_size ? d->buffer_size : BUFLEN / bytes_in_key; - chunk_size = d->chunk_size ? d->chunk_size : bytes_in_key; - if (d->rbuf) { ir->buf = d->rbuf; ir->buf_internal = false; @@ -94,7 +85,7 @@ static int lirc_allocate_buffer(struct irctl *ir) goto out; } - err = lirc_buffer_init(ir->buf, chunk_size, buffer_size); + err = lirc_buffer_init(ir->buf, d->chunk_size, d->buffer_size); if (err) { kfree(ir->buf); ir->buf = NULL; @@ -104,7 +95,6 @@ static int lirc_allocate_buffer(struct irctl *ir) ir->buf_internal = true; d->rbuf = ir->buf; } - ir->chunk_size = ir->buf->chunk_size; out: return err; @@ -131,6 +121,16 @@ int lirc_register_driver(struct lirc_driver *d) return -EINVAL; } + if (!d->rbuf && d->chunk_size < 1) { + pr_err("chunk_size must be set!\n"); + return -EINVAL; + } + + if (!d->rbuf && d->buffer_size < 1) { + pr_err("buffer_size must be set!\n"); + return -EINVAL; + } + if (d->code_length < 1 || d->code_length > (BUFLEN * 8)) { dev_err(d->dev, "code length must be less than %d bits\n", BUFLEN * 8); @@ -407,7 +407,7 @@ ssize_t lirc_dev_fop_read(struct file *file, dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor); - buf = kzalloc(ir->chunk_size, GFP_KERNEL); + buf = kzalloc(ir->buf->chunk_size, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -420,7 +420,7 @@ ssize_t lirc_dev_fop_read(struct file *file, goto out_locked; } - if (length % ir->chunk_size) { + if (length % ir->buf->chunk_size) { ret = -EINVAL; goto out_locked; } diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c index c4a4c2f93ae8..780b2d9f2f4b 100644 --- a/drivers/staging/media/lirc/lirc_zilog.c +++ b/drivers/staging/media/lirc/lirc_zilog.c @@ -1348,8 +1348,6 @@ static const struct file_operations lirc_fops = { static struct lirc_driver lirc_template = { .name = "lirc_zilog", .code_length = 13, - .buffer_size = BUFLEN / 2, - .chunk_size = 2, .fops = &lirc_fops, .owner = THIS_MODULE, }; @@ -1456,8 +1454,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) ir->l.dev = &adap->dev; /* This will be returned by lirc_get_pdata() */ ir->l.data = ir; - ret = lirc_buffer_init(ir->l.rbuf, - ir->l.chunk_size, ir->l.buffer_size); + ret = lirc_buffer_init(ir->l.rbuf, 2, BUFLEN / 2); if (ret) goto out_put_ir; } diff --git a/include/media/lirc_dev.h b/include/media/lirc_dev.h index d07a53232ffc..8e3894e2d2c8 100644 --- a/include/media/lirc_dev.h +++ b/include/media/lirc_dev.h @@ -121,13 +121,14 @@ static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf, * * @code_length: length of the remote control key code expressed in bits. * - * @buffer_size: Number of FIFO buffers with @chunk_size size. If zero, - * creates a buffer with BUFLEN size (16 bytes). - * * @features: lirc compatible hardware features, like LIRC_MODE_RAW, * LIRC_CAN\_\*, as defined at include/media/lirc.h. * + * @buffer_size: Number of FIFO buffers with @chunk_size size. + * Only used if @rbuf is NULL. + * * @chunk_size: Size of each FIFO buffer. + * Only used if @rbuf is NULL. * * @data: it may point to any driver data and this pointer will * be passed to all callback functions. @@ -162,9 +163,9 @@ struct lirc_driver { char name[40]; unsigned int minor; __u32 code_length; - unsigned int buffer_size; /* in chunks holding one code each */ __u32 features; + unsigned int buffer_size; /* in chunks holding one code each */ unsigned int chunk_size; void *data; -- cgit v1.2.3 From 3bce5572364899970cbe908d98c51d1bc743b2f8 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Sun, 25 Jun 2017 09:31:55 -0300 Subject: [media] media: lirc_dev: change irctl->attached to be a boolean The "attached" member of struct irctl is a boolean value, so let the code reflect that. Signed-off-by: David Härdeman Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 1915ffc52955..b07d0ab37d6b 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -35,7 +35,7 @@ static dev_t lirc_base_dev; struct irctl { struct lirc_driver d; - int attached; + bool attached; int open; struct mutex irctl_lock; @@ -193,7 +193,7 @@ int lirc_register_driver(struct lirc_driver *d) cdev_init(&ir->cdev, d->fops); ir->cdev.owner = ir->d.owner; - ir->attached = 1; + ir->attached = true; err = cdev_device_add(&ir->cdev, &ir->dev); if (err) @@ -231,7 +231,7 @@ void lirc_unregister_driver(struct lirc_driver *d) dev_dbg(ir->d.dev, "lirc_dev: driver %s unregistered from minor = %d\n", d->name, d->minor); - ir->attached = 0; + ir->attached = false; if (ir->open) { dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n", d->name, d->minor); -- cgit v1.2.3 From 3381b779a736f4908a64b603ce339ab067e01de7 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Fri, 30 Jun 2017 05:41:57 -0300 Subject: [media] media: lirc_dev: sanitize locking Use the irctl mutex for all device operations and only use lirc_dev_lock to protect the irctls array. Also, make sure that the device is alive early in each fops function before doing anything else. Since this patch touches nearly every line where the irctl mutex is taken/released, it also renames the mutex at the same time (the name irctl_lock will be misleading once struct irctl goes away in later patches). [mchehab@s-opensource.com: fix a merge conflict] Signed-off-by: David Härdeman Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 165 +++++++++++++++++++++++++------------------- 1 file changed, 93 insertions(+), 72 deletions(-) diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index b07d0ab37d6b..c83fffec0681 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -38,7 +38,7 @@ struct irctl { bool attached; int open; - struct mutex irctl_lock; + struct mutex mutex; /* protect from simultaneous accesses */ struct lirc_buffer *buf; bool buf_internal; @@ -46,6 +46,7 @@ struct irctl { struct cdev cdev; }; +/* This mutex protects the irctls array */ static DEFINE_MUTEX(lirc_dev_lock); static struct irctl *irctls[MAX_IRCTL_DEVICES]; @@ -53,20 +54,25 @@ static struct irctl *irctls[MAX_IRCTL_DEVICES]; /* Only used for sysfs but defined to void otherwise */ static struct class *lirc_class; -static void lirc_release(struct device *ld) +static void lirc_free_buffer(struct irctl *ir) { - struct irctl *ir = container_of(ld, struct irctl, dev); - put_device(ir->dev.parent); if (ir->buf_internal) { lirc_buffer_free(ir->buf); kfree(ir->buf); + ir->buf = NULL; } +} + +static void lirc_release(struct device *ld) +{ + struct irctl *ir = container_of(ld, struct irctl, dev); mutex_lock(&lirc_dev_lock); irctls[ir->d.minor] = NULL; mutex_unlock(&lirc_dev_lock); + lirc_free_buffer(ir); kfree(ir); } @@ -143,6 +149,28 @@ int lirc_register_driver(struct lirc_driver *d) return -EBADRQC; } + /* some safety check 8-) */ + d->name[sizeof(d->name) - 1] = '\0'; + + if (d->features == 0) + d->features = LIRC_CAN_REC_LIRCCODE; + + ir = kzalloc(sizeof(*ir), GFP_KERNEL); + if (!ir) + return -ENOMEM; + + mutex_init(&ir->mutex); + ir->d = *d; + + if (LIRC_CAN_REC(d->features)) { + err = lirc_allocate_buffer(ir); + if (err) { + kfree(ir); + return err; + } + d->rbuf = ir->buf; + } + mutex_lock(&lirc_dev_lock); /* find first free slot for driver */ @@ -152,37 +180,18 @@ int lirc_register_driver(struct lirc_driver *d) if (minor == MAX_IRCTL_DEVICES) { dev_err(d->dev, "no free slots for drivers!\n"); - err = -ENOMEM; - goto out_lock; - } - - ir = kzalloc(sizeof(struct irctl), GFP_KERNEL); - if (!ir) { - err = -ENOMEM; - goto out_lock; + mutex_unlock(&lirc_dev_lock); + lirc_free_buffer(ir); + kfree(ir); + return -ENOMEM; } - mutex_init(&ir->irctl_lock); irctls[minor] = ir; d->irctl = ir; d->minor = minor; + ir->d.minor = minor; - /* some safety check 8-) */ - d->name[sizeof(d->name)-1] = '\0'; - - if (d->features == 0) - d->features = LIRC_CAN_REC_LIRCCODE; - - ir->d = *d; - - if (LIRC_CAN_REC(d->features)) { - err = lirc_allocate_buffer(irctls[minor]); - if (err) { - kfree(ir); - goto out_lock; - } - d->rbuf = ir->buf; - } + mutex_unlock(&lirc_dev_lock); device_initialize(&ir->dev); ir->dev.devt = MKDEV(MAJOR(lirc_base_dev), ir->d.minor); @@ -196,10 +205,10 @@ int lirc_register_driver(struct lirc_driver *d) ir->attached = true; err = cdev_device_add(&ir->cdev, &ir->dev); - if (err) - goto out_dev; - - mutex_unlock(&lirc_dev_lock); + if (err) { + put_device(&ir->dev); + return err; + } get_device(ir->dev.parent); @@ -207,13 +216,6 @@ int lirc_register_driver(struct lirc_driver *d) ir->d.name, ir->d.minor); return 0; - -out_dev: - put_device(&ir->dev); -out_lock: - mutex_unlock(&lirc_dev_lock); - - return err; } EXPORT_SYMBOL(lirc_register_driver); @@ -226,11 +228,13 @@ void lirc_unregister_driver(struct lirc_driver *d) ir = d->irctl; - mutex_lock(&lirc_dev_lock); - dev_dbg(ir->d.dev, "lirc_dev: driver %s unregistered from minor = %d\n", d->name, d->minor); + cdev_device_del(&ir->cdev, &ir->dev); + + mutex_lock(&ir->mutex); + ir->attached = false; if (ir->open) { dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n", @@ -238,9 +242,8 @@ void lirc_unregister_driver(struct lirc_driver *d) wake_up_interruptible(&ir->buf->wait_poll); } - mutex_unlock(&lirc_dev_lock); + mutex_unlock(&ir->mutex); - cdev_device_del(&ir->cdev, &ir->dev); put_device(&ir->dev); } EXPORT_SYMBOL(lirc_unregister_driver); @@ -252,13 +255,24 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file) dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor); - if (ir->open) - return -EBUSY; + retval = mutex_lock_interruptible(&ir->mutex); + if (retval) + return retval; + + if (!ir->attached) { + retval = -ENODEV; + goto out; + } + + if (ir->open) { + retval = -EBUSY; + goto out; + } if (ir->d.rdev) { retval = rc_open(ir->d.rdev); if (retval) - return retval; + goto out; } if (ir->buf) @@ -268,24 +282,26 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file) lirc_init_pdata(inode, file); nonseekable_open(inode, file); + mutex_unlock(&ir->mutex); return 0; + +out: + mutex_unlock(&ir->mutex); + return retval; } EXPORT_SYMBOL(lirc_dev_fop_open); int lirc_dev_fop_close(struct inode *inode, struct file *file) { struct irctl *ir = file->private_data; - int ret; - ret = mutex_lock_killable(&lirc_dev_lock); - WARN_ON(ret); + mutex_lock(&ir->mutex); rc_close(ir->d.rdev); - ir->open--; - if (!ret) - mutex_unlock(&lirc_dev_lock); + + mutex_unlock(&ir->mutex); return 0; } @@ -320,19 +336,20 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct irctl *ir = file->private_data; __u32 mode; - int result = 0; + int result; dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n", ir->d.name, ir->d.minor, cmd); + result = mutex_lock_interruptible(&ir->mutex); + if (result) + return result; + if (!ir->attached) { - dev_err(ir->d.dev, LOGHEAD "ioctl result = -ENODEV\n", - ir->d.name, ir->d.minor); - return -ENODEV; + result = -ENODEV; + goto out; } - mutex_lock(&ir->irctl_lock); - switch (cmd) { case LIRC_GET_FEATURES: result = put_user(ir->d.features, (__u32 __user *)arg); @@ -386,8 +403,8 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) result = -ENOTTY; } - mutex_unlock(&ir->irctl_lock); - +out: + mutex_unlock(&ir->mutex); return result; } EXPORT_SYMBOL(lirc_dev_fop_ioctl); @@ -399,27 +416,31 @@ ssize_t lirc_dev_fop_read(struct file *file, { struct irctl *ir = file->private_data; unsigned char *buf; - int ret = 0, written = 0; + int ret, written = 0; DECLARE_WAITQUEUE(wait, current); - if (!LIRC_CAN_REC(ir->d.features)) - return -EINVAL; - dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor); buf = kzalloc(ir->buf->chunk_size, GFP_KERNEL); if (!buf) return -ENOMEM; - if (mutex_lock_interruptible(&ir->irctl_lock)) { - ret = -ERESTARTSYS; - goto out_unlocked; + ret = mutex_lock_interruptible(&ir->mutex); + if (ret) { + kfree(buf); + return ret; } + if (!ir->attached) { ret = -ENODEV; goto out_locked; } + if (!LIRC_CAN_REC(ir->d.features)) { + ret = -EINVAL; + goto out_locked; + } + if (length % ir->buf->chunk_size) { ret = -EINVAL; goto out_locked; @@ -454,13 +475,13 @@ ssize_t lirc_dev_fop_read(struct file *file, break; } - mutex_unlock(&ir->irctl_lock); + mutex_unlock(&ir->mutex); set_current_state(TASK_INTERRUPTIBLE); schedule(); set_current_state(TASK_RUNNING); - if (mutex_lock_interruptible(&ir->irctl_lock)) { - ret = -ERESTARTSYS; + ret = mutex_lock_interruptible(&ir->mutex); + if (ret) { remove_wait_queue(&ir->buf->wait_poll, &wait); goto out_unlocked; } @@ -483,7 +504,7 @@ ssize_t lirc_dev_fop_read(struct file *file, remove_wait_queue(&ir->buf->wait_poll, &wait); out_locked: - mutex_unlock(&ir->irctl_lock); + mutex_unlock(&ir->mutex); out_unlocked: kfree(buf); -- cgit v1.2.3 From 46c8f4771154eb0dc21f5f2bc2640a33e8fe1d02 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Sun, 25 Jun 2017 09:32:05 -0300 Subject: [media] media: lirc_dev: use an IDA instead of an array to keep track of registered devices Using the kernel-provided IDA simplifies the code and makes it possible to remove the lirc_dev_lock mutex. Signed-off-by: David Härdeman Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 36 ++++++++++++------------------------ include/media/lirc_dev.h | 1 - 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index c83fffec0681..a2c5ed0181c1 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -46,10 +47,9 @@ struct irctl { struct cdev cdev; }; -/* This mutex protects the irctls array */ -static DEFINE_MUTEX(lirc_dev_lock); - -static struct irctl *irctls[MAX_IRCTL_DEVICES]; +/* Used to keep track of allocated lirc devices */ +#define LIRC_MAX_DEVICES 256 +static DEFINE_IDA(lirc_ida); /* Only used for sysfs but defined to void otherwise */ static struct class *lirc_class; @@ -69,9 +69,6 @@ static void lirc_release(struct device *ld) { struct irctl *ir = container_of(ld, struct irctl, dev); - mutex_lock(&lirc_dev_lock); - irctls[ir->d.minor] = NULL; - mutex_unlock(&lirc_dev_lock); lirc_free_buffer(ir); kfree(ir); } @@ -109,7 +106,7 @@ out: int lirc_register_driver(struct lirc_driver *d) { struct irctl *ir; - unsigned int minor; + int minor; int err; if (!d) { @@ -171,28 +168,17 @@ int lirc_register_driver(struct lirc_driver *d) d->rbuf = ir->buf; } - mutex_lock(&lirc_dev_lock); - - /* find first free slot for driver */ - for (minor = 0; minor < MAX_IRCTL_DEVICES; minor++) - if (!irctls[minor]) - break; - - if (minor == MAX_IRCTL_DEVICES) { - dev_err(d->dev, "no free slots for drivers!\n"); - mutex_unlock(&lirc_dev_lock); + minor = ida_simple_get(&lirc_ida, 0, LIRC_MAX_DEVICES, GFP_KERNEL); + if (minor < 0) { lirc_free_buffer(ir); kfree(ir); - return -ENOMEM; + return minor; } - irctls[minor] = ir; d->irctl = ir; d->minor = minor; ir->d.minor = minor; - mutex_unlock(&lirc_dev_lock); - device_initialize(&ir->dev); ir->dev.devt = MKDEV(MAJOR(lirc_base_dev), ir->d.minor); ir->dev.class = lirc_class; @@ -206,6 +192,7 @@ int lirc_register_driver(struct lirc_driver *d) err = cdev_device_add(&ir->cdev, &ir->dev); if (err) { + ida_simple_remove(&lirc_ida, minor); put_device(&ir->dev); return err; } @@ -244,6 +231,7 @@ void lirc_unregister_driver(struct lirc_driver *d) mutex_unlock(&ir->mutex); + ida_simple_remove(&lirc_ida, d->minor); put_device(&ir->dev); } EXPORT_SYMBOL(lirc_unregister_driver); @@ -540,7 +528,7 @@ static int __init lirc_dev_init(void) return PTR_ERR(lirc_class); } - retval = alloc_chrdev_region(&lirc_base_dev, 0, MAX_IRCTL_DEVICES, + retval = alloc_chrdev_region(&lirc_base_dev, 0, LIRC_MAX_DEVICES, "BaseRemoteCtl"); if (retval) { class_destroy(lirc_class); @@ -557,7 +545,7 @@ static int __init lirc_dev_init(void) static void __exit lirc_dev_exit(void) { class_destroy(lirc_class); - unregister_chrdev_region(lirc_base_dev, MAX_IRCTL_DEVICES); + unregister_chrdev_region(lirc_base_dev, LIRC_MAX_DEVICES); pr_info("module unloaded\n"); } diff --git a/include/media/lirc_dev.h b/include/media/lirc_dev.h index 8e3894e2d2c8..51c15c050e85 100644 --- a/include/media/lirc_dev.h +++ b/include/media/lirc_dev.h @@ -9,7 +9,6 @@ #ifndef _LINUX_LIRC_DEV_H #define _LINUX_LIRC_DEV_H -#define MAX_IRCTL_DEVICES 8 #define BUFLEN 16 #include -- cgit v1.2.3 From 5ddc9c098dc3f91243840cec12a2170e9ab9f33a Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Thu, 21 Sep 2017 16:13:34 -0300 Subject: [media] media: rename struct lirc_driver to struct lirc_dev This is in preparation for the later patches which do away with struct irctl entirely. Signed-off-by: David Härdeman Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 52 ++++++++++++++++----------------- drivers/media/rc/lirc_dev.c | 12 ++++---- drivers/media/rc/rc-core-priv.h | 2 +- drivers/staging/media/lirc/lirc_zilog.c | 12 ++++---- include/media/lirc_dev.h | 48 +++++++++--------------------- 5 files changed, 52 insertions(+), 74 deletions(-) diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 58bff7a75d5b..2d591168c991 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -35,7 +35,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) struct lirc_codec *lirc = &dev->raw->lirc; int sample; - if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf) + if (!dev->raw->lirc.ldev || !dev->raw->lirc.ldev->rbuf) return -EINVAL; /* Packet start */ @@ -84,8 +84,8 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) (u64)LIRC_VALUE_MASK); gap_sample = LIRC_SPACE(lirc->gap_duration); - lirc_buffer_write(dev->raw->lirc.drv->rbuf, - (unsigned char *) &gap_sample); + lirc_buffer_write(dev->raw->lirc.ldev->rbuf, + (unsigned char *)&gap_sample); lirc->gap = false; } @@ -95,9 +95,9 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) TO_US(ev.duration), TO_STR(ev.pulse)); } - lirc_buffer_write(dev->raw->lirc.drv->rbuf, + lirc_buffer_write(dev->raw->lirc.ldev->rbuf, (unsigned char *) &sample); - wake_up(&dev->raw->lirc.drv->rbuf->wait_poll); + wake_up(&dev->raw->lirc.ldev->rbuf->wait_poll); return 0; } @@ -343,12 +343,12 @@ static const struct file_operations lirc_fops = { static int ir_lirc_register(struct rc_dev *dev) { - struct lirc_driver *drv; + struct lirc_dev *ldev; int rc = -ENOMEM; unsigned long features = 0; - drv = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL); - if (!drv) + ldev = kzalloc(sizeof(*ldev), GFP_KERNEL); + if (!ldev) return rc; if (dev->driver_type != RC_DRIVER_IR_RAW_TX) { @@ -380,29 +380,29 @@ static int ir_lirc_register(struct rc_dev *dev) if (dev->max_timeout) features |= LIRC_CAN_SET_REC_TIMEOUT; - snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)", + snprintf(ldev->name, sizeof(ldev->name), "ir-lirc-codec (%s)", dev->driver_name); - drv->features = features; - drv->data = &dev->raw->lirc; - drv->rbuf = NULL; - drv->code_length = sizeof(struct ir_raw_event) * 8; - drv->chunk_size = sizeof(int); - drv->buffer_size = LIRCBUF_SIZE; - drv->fops = &lirc_fops; - drv->dev = &dev->dev; - drv->rdev = dev; - drv->owner = THIS_MODULE; - - rc = lirc_register_driver(drv); + ldev->features = features; + ldev->data = &dev->raw->lirc; + ldev->rbuf = NULL; + ldev->code_length = sizeof(struct ir_raw_event) * 8; + ldev->chunk_size = sizeof(int); + ldev->buffer_size = LIRCBUF_SIZE; + ldev->fops = &lirc_fops; + ldev->dev = &dev->dev; + ldev->rdev = dev; + ldev->owner = THIS_MODULE; + + rc = lirc_register_device(ldev); if (rc < 0) goto out; - dev->raw->lirc.drv = drv; + dev->raw->lirc.ldev = ldev; dev->raw->lirc.dev = dev; return 0; out: - kfree(drv); + kfree(ldev); return rc; } @@ -410,9 +410,9 @@ static int ir_lirc_unregister(struct rc_dev *dev) { struct lirc_codec *lirc = &dev->raw->lirc; - lirc_unregister_driver(lirc->drv); - kfree(lirc->drv); - lirc->drv = NULL; + lirc_unregister_device(lirc->ldev); + kfree(lirc->ldev); + lirc->ldev = NULL; return 0; } diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index a2c5ed0181c1..e381a1c04bea 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -35,7 +35,7 @@ static dev_t lirc_base_dev; struct irctl { - struct lirc_driver d; + struct lirc_dev d; bool attached; int open; @@ -76,7 +76,7 @@ static void lirc_release(struct device *ld) static int lirc_allocate_buffer(struct irctl *ir) { int err = 0; - struct lirc_driver *d = &ir->d; + struct lirc_dev *d = &ir->d; if (d->rbuf) { ir->buf = d->rbuf; @@ -103,7 +103,7 @@ out: return err; } -int lirc_register_driver(struct lirc_driver *d) +int lirc_register_device(struct lirc_dev *d) { struct irctl *ir; int minor; @@ -204,9 +204,9 @@ int lirc_register_driver(struct lirc_driver *d) return 0; } -EXPORT_SYMBOL(lirc_register_driver); +EXPORT_SYMBOL(lirc_register_device); -void lirc_unregister_driver(struct lirc_driver *d) +void lirc_unregister_device(struct lirc_dev *d) { struct irctl *ir; @@ -234,7 +234,7 @@ void lirc_unregister_driver(struct lirc_driver *d) ida_simple_remove(&lirc_ida, d->minor); put_device(&ir->dev); } -EXPORT_SYMBOL(lirc_unregister_driver); +EXPORT_SYMBOL(lirc_unregister_device); int lirc_dev_fop_open(struct inode *inode, struct file *file) { diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h index 7da9c96cb058..ae4dd0c27731 100644 --- a/drivers/media/rc/rc-core-priv.h +++ b/drivers/media/rc/rc-core-priv.h @@ -106,7 +106,7 @@ struct ir_raw_event_ctrl { } mce_kbd; struct lirc_codec { struct rc_dev *dev; - struct lirc_driver *drv; + struct lirc_dev *ldev; int carrier_low; ktime_t gap_start; diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c index 780b2d9f2f4b..0766e5029bd7 100644 --- a/drivers/staging/media/lirc/lirc_zilog.c +++ b/drivers/staging/media/lirc/lirc_zilog.c @@ -100,7 +100,7 @@ struct IR { struct list_head list; /* FIXME spinlock access to l.features */ - struct lirc_driver l; + struct lirc_dev l; struct lirc_buffer rbuf; struct mutex ir_lock; @@ -183,7 +183,7 @@ static void release_ir_device(struct kref *ref) * ir->open_count == 0 - happens on final close() * ir_lock, tx_ref_lock, rx_ref_lock, all released */ - lirc_unregister_driver(&ir->l); + lirc_unregister_device(&ir->l); if (kfifo_initialized(&ir->rbuf.fifo)) lirc_buffer_free(&ir->rbuf); @@ -1345,7 +1345,7 @@ static const struct file_operations lirc_fops = { .release = close }; -static struct lirc_driver lirc_template = { +static struct lirc_dev lirc_template = { .name = "lirc_zilog", .code_length = 13, .fops = &lirc_fops, @@ -1441,7 +1441,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) spin_lock_init(&ir->rx_ref_lock); /* set lirc_dev stuff */ - memcpy(&ir->l, &lirc_template, sizeof(struct lirc_driver)); + memcpy(&ir->l, &lirc_template, sizeof(struct lirc_dev)); /* * FIXME this is a pointer reference to us, but no refcount. * @@ -1559,10 +1559,10 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) } /* register with lirc */ - ret = lirc_register_driver(&ir->l); + ret = lirc_register_device(&ir->l); if (ret < 0) { dev_err(tx->ir->l.dev, - "%s: lirc_register_driver() failed: %i\n", + "%s: lirc_register_device() failed: %i\n", __func__, ret); goto out_put_xx; } diff --git a/include/media/lirc_dev.h b/include/media/lirc_dev.h index 51c15c050e85..d16d6e0ef8da 100644 --- a/include/media/lirc_dev.h +++ b/include/media/lirc_dev.h @@ -111,54 +111,32 @@ static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf, } /** - * struct lirc_driver - Defines the parameters on a LIRC driver - * - * @name: this string will be used for logs - * - * @minor: the minor device (/dev/lircX) number for a registered - * driver. - * - * @code_length: length of the remote control key code expressed in bits. + * struct lirc_dev - represents a LIRC device * + * @name: used for logging + * @minor: the minor device (/dev/lircX) number for the device + * @code_length: length of a remote control key code expressed in bits * @features: lirc compatible hardware features, like LIRC_MODE_RAW, * LIRC_CAN\_\*, as defined at include/media/lirc.h. - * * @buffer_size: Number of FIFO buffers with @chunk_size size. * Only used if @rbuf is NULL. - * * @chunk_size: Size of each FIFO buffer. * Only used if @rbuf is NULL. - * - * @data: it may point to any driver data and this pointer will - * be passed to all callback functions. - * + * @data: private per-driver data * @min_timeout: Minimum timeout for record. Valid only if * LIRC_CAN_SET_REC_TIMEOUT is defined. - * * @max_timeout: Maximum timeout for record. Valid only if * LIRC_CAN_SET_REC_TIMEOUT is defined. - * * @rbuf: if not NULL, it will be used as a read buffer, you will * have to write to the buffer by other means, like irq's * (see also lirc_serial.c). - * - * @rdev: Pointed to struct rc_dev associated with the LIRC - * device. - * - * @fops: file_operations for drivers which don't fit the current - * driver model. - * Some ioctl's can be directly handled by lirc_dev if the - * driver's ioctl function is NULL or if it returns - * -ENOIOCTLCMD (see also lirc_serial.c). - * - * @dev: pointer to the struct device associated with the LIRC - * device. - * + * @rdev: &struct rc_dev associated with the device + * @fops: &struct file_operations for the device + * @dev: &struct device assigned to the device * @owner: the module owning this struct - * - * @irctl: the struct irctl for this LIRC device. + * @irctl: &struct irctl assigned to the device */ -struct lirc_driver { +struct lirc_dev { char name[40]; unsigned int minor; __u32 code_length; @@ -183,14 +161,14 @@ struct lirc_driver { * returns negative value on error or zero * contents of the structure pointed by p is copied */ -int lirc_register_driver(struct lirc_driver *d); +int lirc_register_device(struct lirc_dev *d); -void lirc_unregister_driver(struct lirc_driver *d); +void lirc_unregister_device(struct lirc_dev *d); /* Must be called in the open fop before lirc_get_pdata() can be used */ void lirc_init_pdata(struct inode *inode, struct file *file); -/* Returns the private data stored in the lirc_driver +/* Returns the private data stored in the lirc_dev * associated with the given device file pointer. */ void *lirc_get_pdata(struct file *file); -- cgit v1.2.3 From 6ecccc379b7334c02f90a401dafea6fce5c91310 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Sun, 25 Jun 2017 09:32:15 -0300 Subject: [media] media: lirc_dev: introduce lirc_allocate_device and lirc_free_device Introduce two new functions so that the API for lirc_dev matches that of the rc-core and input subsystems. This means that lirc_dev structs are managed using the usual four functions: lirc_allocate_device lirc_free_device lirc_register_device lirc_unregister_device The functions are pretty simplistic at this point, later patches will put more flesh on the bones of both. Signed-off-by: David Härdeman Signed-off-by: Sean Young --- drivers/media/rc/ir-lirc-codec.c | 2 +- drivers/media/rc/lirc_dev.c | 13 +++++++++++++ include/media/lirc_dev.h | 9 ++++----- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 2d591168c991..d5c155a5a547 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -347,7 +347,7 @@ static int ir_lirc_register(struct rc_dev *dev) int rc = -ENOMEM; unsigned long features = 0; - ldev = kzalloc(sizeof(*ldev), GFP_KERNEL); + ldev = lirc_allocate_device(); if (!ldev) return rc; diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index e381a1c04bea..a6005f70de5a 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -103,6 +103,19 @@ out: return err; } +struct lirc_dev * +lirc_allocate_device(void) +{ + return kzalloc(sizeof(struct lirc_dev), GFP_KERNEL); +} +EXPORT_SYMBOL(lirc_allocate_device); + +void lirc_free_device(struct lirc_dev *d) +{ + kfree(d); +} +EXPORT_SYMBOL(lirc_free_device); + int lirc_register_device(struct lirc_dev *d) { struct irctl *ir; diff --git a/include/media/lirc_dev.h b/include/media/lirc_dev.h index d16d6e0ef8da..4b0dc640e142 100644 --- a/include/media/lirc_dev.h +++ b/include/media/lirc_dev.h @@ -156,11 +156,10 @@ struct lirc_dev { struct irctl *irctl; }; -/* following functions can be called ONLY from user context - * - * returns negative value on error or zero - * contents of the structure pointed by p is copied - */ +struct lirc_dev *lirc_allocate_device(void); + +void lirc_free_device(struct lirc_dev *d); + int lirc_register_device(struct lirc_dev *d); void lirc_unregister_device(struct lirc_dev *d); -- cgit v1.2.3 From f08e52878e101f3794c432dcbaa2179d1a903ded Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Sun, 25 Jun 2017 09:32:25 -0300 Subject: [media] media: lirc_zilog: add a pointer to the parent device to struct IR lirc_zilog stashes a pointer to the parent device in struct lirc_dev and uses it for logging. It makes more sense to let lirc_zilog keep track of that pointer in its own struct (this is in preparation for subsequent patches which will remodel struct lirc_dev). Signed-off-by: David Härdeman Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/lirc/lirc_zilog.c | 98 +++++++++++++++++---------------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c index 0766e5029bd7..cd2eeb365cd7 100644 --- a/drivers/staging/media/lirc/lirc_zilog.c +++ b/drivers/staging/media/lirc/lirc_zilog.c @@ -106,6 +106,7 @@ struct IR { struct mutex ir_lock; atomic_t open_count; + struct device *dev; struct i2c_adapter *adapter; spinlock_t rx_ref_lock; /* struct IR_rx kref get()/put() */ @@ -319,7 +320,7 @@ static int add_to_buf(struct IR *ir) struct IR_tx *tx; if (lirc_buffer_full(rbuf)) { - dev_dbg(ir->l.dev, "buffer overflow\n"); + dev_dbg(ir->dev, "buffer overflow\n"); return -EOVERFLOW; } @@ -365,17 +366,17 @@ static int add_to_buf(struct IR *ir) */ ret = i2c_master_send(rx->c, sendbuf, 1); if (ret != 1) { - dev_err(ir->l.dev, "i2c_master_send failed with %d\n", + dev_err(ir->dev, "i2c_master_send failed with %d\n", ret); if (failures >= 3) { mutex_unlock(&ir->ir_lock); - dev_err(ir->l.dev, + dev_err(ir->dev, "unable to read from the IR chip after 3 resets, giving up\n"); break; } /* Looks like the chip crashed, reset it */ - dev_err(ir->l.dev, + dev_err(ir->dev, "polling the IR receiver chip failed, trying reset\n"); set_current_state(TASK_UNINTERRUPTIBLE); @@ -402,14 +403,14 @@ static int add_to_buf(struct IR *ir) ret = i2c_master_recv(rx->c, keybuf, sizeof(keybuf)); mutex_unlock(&ir->ir_lock); if (ret != sizeof(keybuf)) { - dev_err(ir->l.dev, + dev_err(ir->dev, "i2c_master_recv failed with %d -- keeping last read buffer\n", ret); } else { rx->b[0] = keybuf[3]; rx->b[1] = keybuf[4]; rx->b[2] = keybuf[5]; - dev_dbg(ir->l.dev, + dev_dbg(ir->dev, "key (0x%02x/0x%02x)\n", rx->b[0], rx->b[1]); } @@ -462,7 +463,7 @@ static int lirc_thread(void *arg) struct IR *ir = arg; struct lirc_buffer *rbuf = ir->l.rbuf; - dev_dbg(ir->l.dev, "poll thread started\n"); + dev_dbg(ir->dev, "poll thread started\n"); while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); @@ -490,7 +491,7 @@ static int lirc_thread(void *arg) wake_up_interruptible(&rbuf->wait_poll); } - dev_dbg(ir->l.dev, "poll thread ended\n"); + dev_dbg(ir->dev, "poll thread ended\n"); return 0; } @@ -643,10 +644,10 @@ static int send_data_block(struct IR_tx *tx, unsigned char *data_block) buf[0] = (unsigned char)(i + 1); for (j = 0; j < tosend; ++j) buf[1 + j] = data_block[i + j]; - dev_dbg(tx->ir->l.dev, "%*ph", 5, buf); + dev_dbg(tx->ir->dev, "%*ph", 5, buf); ret = i2c_master_send(tx->c, buf, tosend + 1); if (ret != tosend + 1) { - dev_err(tx->ir->l.dev, + dev_err(tx->ir->dev, "i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; } @@ -671,7 +672,7 @@ static int send_boot_data(struct IR_tx *tx) buf[1] = 0x20; ret = i2c_master_send(tx->c, buf, 2); if (ret != 2) { - dev_err(tx->ir->l.dev, "i2c_master_send failed with %d\n", ret); + dev_err(tx->ir->dev, "i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; } @@ -688,22 +689,22 @@ static int send_boot_data(struct IR_tx *tx) } if (ret != 1) { - dev_err(tx->ir->l.dev, "i2c_master_send failed with %d\n", ret); + dev_err(tx->ir->dev, "i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; } /* Here comes the firmware version... (hopefully) */ ret = i2c_master_recv(tx->c, buf, 4); if (ret != 4) { - dev_err(tx->ir->l.dev, "i2c_master_recv failed with %d\n", ret); + dev_err(tx->ir->dev, "i2c_master_recv failed with %d\n", ret); return 0; } if ((buf[0] != 0x80) && (buf[0] != 0xa0)) { - dev_err(tx->ir->l.dev, "unexpected IR TX init response: %02x\n", + dev_err(tx->ir->dev, "unexpected IR TX init response: %02x\n", buf[0]); return 0; } - dev_notice(tx->ir->l.dev, + dev_notice(tx->ir->dev, "Zilog/Hauppauge IR blaster firmware version %d.%d.%d loaded\n", buf[1], buf[2], buf[3]); @@ -748,15 +749,15 @@ static int fw_load(struct IR_tx *tx) } /* Request codeset data file */ - ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", tx->ir->l.dev); + ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", tx->ir->dev); if (ret != 0) { - dev_err(tx->ir->l.dev, + dev_err(tx->ir->dev, "firmware haup-ir-blaster.bin not available (%d)\n", ret); ret = ret < 0 ? ret : -EFAULT; goto out; } - dev_dbg(tx->ir->l.dev, "firmware of size %zu loaded\n", fw_entry->size); + dev_dbg(tx->ir->dev, "firmware of size %zu loaded\n", fw_entry->size); /* Parse the file */ tx_data = vmalloc(sizeof(*tx_data)); @@ -784,7 +785,7 @@ static int fw_load(struct IR_tx *tx) if (!read_uint8(&data, tx_data->endp, &version)) goto corrupt; if (version != 1) { - dev_err(tx->ir->l.dev, + dev_err(tx->ir->dev, "unsupported code set file version (%u, expected 1) -- please upgrade to a newer driver\n", version); fw_unload_locked(); @@ -801,7 +802,7 @@ static int fw_load(struct IR_tx *tx) &tx_data->num_code_sets)) goto corrupt; - dev_dbg(tx->ir->l.dev, "%u IR blaster codesets loaded\n", + dev_dbg(tx->ir->dev, "%u IR blaster codesets loaded\n", tx_data->num_code_sets); tx_data->code_sets = vmalloc( @@ -866,7 +867,7 @@ static int fw_load(struct IR_tx *tx) goto out; corrupt: - dev_err(tx->ir->l.dev, "firmware is corrupt\n"); + dev_err(tx->ir->dev, "firmware is corrupt\n"); fw_unload_locked(); ret = -EFAULT; @@ -886,9 +887,9 @@ static ssize_t read(struct file *filep, char __user *outbuf, size_t n, unsigned int m; DECLARE_WAITQUEUE(wait, current); - dev_dbg(ir->l.dev, "read called\n"); + dev_dbg(ir->dev, "read called\n"); if (n % rbuf->chunk_size) { - dev_dbg(ir->l.dev, "read result = -EINVAL\n"); + dev_dbg(ir->dev, "read result = -EINVAL\n"); return -EINVAL; } @@ -932,7 +933,7 @@ static ssize_t read(struct file *filep, char __user *outbuf, size_t n, unsigned char buf[MAX_XFER_SIZE]; if (rbuf->chunk_size > sizeof(buf)) { - dev_err(ir->l.dev, + dev_err(ir->dev, "chunk_size is too big (%d)!\n", rbuf->chunk_size); ret = -EINVAL; @@ -947,7 +948,7 @@ static ssize_t read(struct file *filep, char __user *outbuf, size_t n, retries++; } if (retries >= 5) { - dev_err(ir->l.dev, "Buffer read failed!\n"); + dev_err(ir->dev, "Buffer read failed!\n"); ret = -EIO; } } @@ -957,7 +958,7 @@ static ssize_t read(struct file *filep, char __user *outbuf, size_t n, put_ir_rx(rx, false); set_current_state(TASK_RUNNING); - dev_dbg(ir->l.dev, "read result = %d (%s)\n", ret, + dev_dbg(ir->dev, "read result = %d (%s)\n", ret, ret ? "Error" : "OK"); return ret ? ret : written; @@ -974,7 +975,7 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) ret = get_key_data(data_block, code, key); if (ret == -EPROTO) { - dev_err(tx->ir->l.dev, + dev_err(tx->ir->dev, "failed to get data for code %u, key %u -- check lircd.conf entries\n", code, key); return ret; @@ -992,7 +993,7 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) buf[1] = 0x40; ret = i2c_master_send(tx->c, buf, 2); if (ret != 2) { - dev_err(tx->ir->l.dev, "i2c_master_send failed with %d\n", ret); + dev_err(tx->ir->dev, "i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; } @@ -1005,18 +1006,18 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) } if (ret != 1) { - dev_err(tx->ir->l.dev, "i2c_master_send failed with %d\n", ret); + dev_err(tx->ir->dev, "i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; } /* Send finished download? */ ret = i2c_master_recv(tx->c, buf, 1); if (ret != 1) { - dev_err(tx->ir->l.dev, "i2c_master_recv failed with %d\n", ret); + dev_err(tx->ir->dev, "i2c_master_recv failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; } if (buf[0] != 0xA0) { - dev_err(tx->ir->l.dev, "unexpected IR TX response #1: %02x\n", + dev_err(tx->ir->dev, "unexpected IR TX response #1: %02x\n", buf[0]); return -EFAULT; } @@ -1026,7 +1027,7 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) buf[1] = 0x80; ret = i2c_master_send(tx->c, buf, 2); if (ret != 2) { - dev_err(tx->ir->l.dev, "i2c_master_send failed with %d\n", ret); + dev_err(tx->ir->dev, "i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; } @@ -1036,7 +1037,7 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) * going to skip this whole mess and say we're done on the HD PVR */ if (!tx->post_tx_ready_poll) { - dev_dbg(tx->ir->l.dev, "sent code %u, key %u\n", code, key); + dev_dbg(tx->ir->dev, "sent code %u, key %u\n", code, key); return 0; } @@ -1052,12 +1053,12 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) ret = i2c_master_send(tx->c, buf, 1); if (ret == 1) break; - dev_dbg(tx->ir->l.dev, + dev_dbg(tx->ir->dev, "NAK expected: i2c_master_send failed with %d (try %d)\n", ret, i + 1); } if (ret != 1) { - dev_err(tx->ir->l.dev, + dev_err(tx->ir->dev, "IR TX chip never got ready: last i2c_master_send failed with %d\n", ret); return ret < 0 ? ret : -EFAULT; @@ -1066,17 +1067,17 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key) /* Seems to be an 'ok' response */ i = i2c_master_recv(tx->c, buf, 1); if (i != 1) { - dev_err(tx->ir->l.dev, "i2c_master_recv failed with %d\n", ret); + dev_err(tx->ir->dev, "i2c_master_recv failed with %d\n", ret); return -EFAULT; } if (buf[0] != 0x80) { - dev_err(tx->ir->l.dev, "unexpected IR TX response #2: %02x\n", + dev_err(tx->ir->dev, "unexpected IR TX response #2: %02x\n", buf[0]); return -EFAULT; } /* Oh good, it worked */ - dev_dbg(tx->ir->l.dev, "sent code %u, key %u\n", code, key); + dev_dbg(tx->ir->dev, "sent code %u, key %u\n", code, key); return 0; } @@ -1162,11 +1163,11 @@ static ssize_t write(struct file *filep, const char __user *buf, size_t n, */ if (ret != 0) { /* Looks like the chip crashed, reset it */ - dev_err(tx->ir->l.dev, + dev_err(tx->ir->dev, "sending to the IR transmitter chip failed, trying reset\n"); if (failures >= 3) { - dev_err(tx->ir->l.dev, + dev_err(tx->ir->dev, "unable to send to the IR chip after 3 resets, giving up\n"); mutex_unlock(&ir->ir_lock); mutex_unlock(&tx->client_lock); @@ -1202,7 +1203,7 @@ static unsigned int poll(struct file *filep, poll_table *wait) struct lirc_buffer *rbuf = ir->l.rbuf; unsigned int ret; - dev_dbg(ir->l.dev, "%s called\n", __func__); + dev_dbg(ir->dev, "%s called\n", __func__); rx = get_ir_rx(ir); if (!rx) { @@ -1210,7 +1211,7 @@ static unsigned int poll(struct file *filep, poll_table *wait) * Revisit this, if our poll function ever reports writeable * status for Tx */ - dev_dbg(ir->l.dev, "%s result = POLLERR\n", __func__); + dev_dbg(ir->dev, "%s result = POLLERR\n", __func__); return POLLERR; } @@ -1223,7 +1224,7 @@ static unsigned int poll(struct file *filep, poll_table *wait) /* Indicate what ops could happen immediately without blocking */ ret = lirc_buffer_empty(rbuf) ? 0 : (POLLIN | POLLRDNORM); - dev_dbg(ir->l.dev, "%s result = %s\n", __func__, + dev_dbg(ir->dev, "%s result = %s\n", __func__, ret ? "POLLIN|POLLRDNORM" : "none"); return ret; } @@ -1435,6 +1436,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) list_add_tail(&ir->list, &ir_devices_list); ir->adapter = adap; + ir->dev = &adap->dev; mutex_init(&ir->ir_lock); atomic_set(&ir->open_count, 0); spin_lock_init(&ir->tx_ref_lock); @@ -1498,7 +1500,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) /* Proceed only if the Rx client is also ready or not needed */ if (!rx && !tx_only) { - dev_info(tx->ir->l.dev, + dev_info(tx->ir->dev, "probe of IR Tx on %s (i2c-%d) done. Waiting on IR Rx.\n", adap->name, adap->nr); goto out_ok; @@ -1538,7 +1540,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) "zilog-rx-i2c-%d", adap->nr); if (IS_ERR(rx->task)) { ret = PTR_ERR(rx->task); - dev_err(tx->ir->l.dev, + dev_err(tx->ir->dev, "%s: could not start IR Rx polling thread\n", __func__); /* Failed kthread, so put back the ir ref */ @@ -1561,13 +1563,13 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) /* register with lirc */ ret = lirc_register_device(&ir->l); if (ret < 0) { - dev_err(tx->ir->l.dev, + dev_err(tx->ir->dev, "%s: lirc_register_device() failed: %i\n", __func__, ret); goto out_put_xx; } - dev_info(ir->l.dev, + dev_info(ir->dev, "IR unit on %s (i2c-%d) registered as lirc%d and ready\n", adap->name, adap->nr, ir->l.minor); @@ -1577,7 +1579,7 @@ out_ok: if (tx) put_ir_tx(tx, true); put_ir_device(ir, true); - dev_info(ir->l.dev, + dev_info(ir->dev, "probe of IR %s on %s (i2c-%d) done\n", tx_probe ? "Tx" : "Rx", adap->name, adap->nr); mutex_unlock(&ir_devices_lock); -- cgit v1.2.3 From 13f96555d6faa6dc57fb5faedf728447a3188230 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Sun, 25 Jun 2017 09:32:31 -0300 Subject: [media] media: lirc_zilog: use a dynamically allocated lirc_dev lirc_zilog currently embeds a struct lirc_dev in its own struct IR, but subsequent patches will make the lifetime of struct lirc_dev dynamic (i.e. it will be free():d once lirc_dev is sure there are no users of the struct). Therefore, change lirc_zilog to use a pointer to a dynamically allocated struct lirc_dev. Signed-off-by: David Härdeman Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/lirc/lirc_zilog.c | 69 +++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c index cd2eeb365cd7..00e8c8f224b7 100644 --- a/drivers/staging/media/lirc/lirc_zilog.c +++ b/drivers/staging/media/lirc/lirc_zilog.c @@ -99,8 +99,8 @@ struct IR { struct kref ref; struct list_head list; - /* FIXME spinlock access to l.features */ - struct lirc_dev l; + /* FIXME spinlock access to l->features */ + struct lirc_dev *l; struct lirc_buffer rbuf; struct mutex ir_lock; @@ -184,7 +184,10 @@ static void release_ir_device(struct kref *ref) * ir->open_count == 0 - happens on final close() * ir_lock, tx_ref_lock, rx_ref_lock, all released */ - lirc_unregister_device(&ir->l); + if (ir->l) { + lirc_unregister_device(ir->l); + lirc_free_device(ir->l); + } if (kfifo_initialized(&ir->rbuf.fifo)) lirc_buffer_free(&ir->rbuf); @@ -241,7 +244,7 @@ static void release_ir_rx(struct kref *ref) * and releasing the ir reference can cause a sleep. That work is * performed by put_ir_rx() */ - ir->l.features &= ~LIRC_CAN_REC_LIRCCODE; + ir->l->features &= ~LIRC_CAN_REC_LIRCCODE; /* Don't put_ir_device(rx->ir) here; lock can't be freed yet */ ir->rx = NULL; /* Don't do the kfree(rx) here; we still need to kill the poll thread */ @@ -286,7 +289,7 @@ static void release_ir_tx(struct kref *ref) struct IR_tx *tx = container_of(ref, struct IR_tx, ref); struct IR *ir = tx->ir; - ir->l.features &= ~LIRC_CAN_SEND_LIRCCODE; + ir->l->features &= ~LIRC_CAN_SEND_LIRCCODE; /* Don't put_ir_device(tx->ir) here, so our lock doesn't get freed */ ir->tx = NULL; kfree(tx); @@ -315,7 +318,7 @@ static int add_to_buf(struct IR *ir) int ret; int failures = 0; unsigned char sendbuf[1] = { 0 }; - struct lirc_buffer *rbuf = ir->l.rbuf; + struct lirc_buffer *rbuf = ir->l->rbuf; struct IR_rx *rx; struct IR_tx *tx; @@ -461,7 +464,7 @@ static int add_to_buf(struct IR *ir) static int lirc_thread(void *arg) { struct IR *ir = arg; - struct lirc_buffer *rbuf = ir->l.rbuf; + struct lirc_buffer *rbuf = ir->l->rbuf; dev_dbg(ir->dev, "poll thread started\n"); @@ -882,7 +885,7 @@ static ssize_t read(struct file *filep, char __user *outbuf, size_t n, { struct IR *ir = lirc_get_pdata(filep); struct IR_rx *rx; - struct lirc_buffer *rbuf = ir->l.rbuf; + struct lirc_buffer *rbuf = ir->l->rbuf; int ret = 0, written = 0, retries = 0; unsigned int m; DECLARE_WAITQUEUE(wait, current); @@ -1200,7 +1203,7 @@ static unsigned int poll(struct file *filep, poll_table *wait) { struct IR *ir = lirc_get_pdata(filep); struct IR_rx *rx; - struct lirc_buffer *rbuf = ir->l.rbuf; + struct lirc_buffer *rbuf = ir->l->rbuf; unsigned int ret; dev_dbg(ir->dev, "%s called\n", __func__); @@ -1236,7 +1239,7 @@ static long ioctl(struct file *filep, unsigned int cmd, unsigned long arg) int result; unsigned long mode, features; - features = ir->l.features; + features = ir->l->features; switch (cmd) { case LIRC_GET_LENGTH: @@ -1346,13 +1349,6 @@ static const struct file_operations lirc_fops = { .release = close }; -static struct lirc_dev lirc_template = { - .name = "lirc_zilog", - .code_length = 13, - .fops = &lirc_fops, - .owner = THIS_MODULE, -}; - static int ir_remove(struct i2c_client *client) { if (strncmp("ir_tx_z8", client->name, 8) == 0) { @@ -1443,22 +1439,35 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) spin_lock_init(&ir->rx_ref_lock); /* set lirc_dev stuff */ - memcpy(&ir->l, &lirc_template, sizeof(struct lirc_dev)); + ir->l = lirc_allocate_device(); + if (!ir->l) { + ret = -ENOMEM; + goto out_put_ir; + } + + snprintf(ir->l->name, sizeof(ir->l->name), "lirc_zilog"); + ir->l->code_length = 13; + ir->l->fops = &lirc_fops; + ir->l->owner = THIS_MODULE; + /* * FIXME this is a pointer reference to us, but no refcount. * * This OK for now, since lirc_dev currently won't touch this * buffer as we provide our own lirc_fops. * - * Currently our own lirc_fops rely on this ir->l.rbuf pointer + * Currently our own lirc_fops rely on this ir->l->rbuf pointer */ - ir->l.rbuf = &ir->rbuf; - ir->l.dev = &adap->dev; + ir->l->rbuf = &ir->rbuf; + ir->l->dev = &adap->dev; /* This will be returned by lirc_get_pdata() */ - ir->l.data = ir; - ret = lirc_buffer_init(ir->l.rbuf, 2, BUFLEN / 2); - if (ret) + ir->l->data = ir; + ret = lirc_buffer_init(ir->l->rbuf, 2, BUFLEN / 2); + if (ret) { + lirc_free_device(ir->l); + ir->l = NULL; goto out_put_ir; + } } if (tx_probe) { @@ -1474,7 +1483,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) kref_init(&tx->ref); ir->tx = tx; - ir->l.features |= LIRC_CAN_SEND_LIRCCODE; + ir->l->features |= LIRC_CAN_SEND_LIRCCODE; mutex_init(&tx->client_lock); tx->c = client; tx->need_boot = 1; @@ -1518,7 +1527,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) kref_init(&rx->ref); ir->rx = rx; - ir->l.features |= LIRC_CAN_REC_LIRCCODE; + ir->l->features |= LIRC_CAN_REC_LIRCCODE; mutex_init(&rx->client_lock); rx->c = client; rx->hdpvr_data_fmt = @@ -1548,7 +1557,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) /* Failure exit, so put back rx ref from i2c_client */ i2c_set_clientdata(client, NULL); put_ir_rx(rx, true); - ir->l.features &= ~LIRC_CAN_REC_LIRCCODE; + ir->l->features &= ~LIRC_CAN_REC_LIRCCODE; goto out_put_tx; } @@ -1561,17 +1570,19 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) } /* register with lirc */ - ret = lirc_register_device(&ir->l); + ret = lirc_register_device(ir->l); if (ret < 0) { dev_err(tx->ir->dev, "%s: lirc_register_device() failed: %i\n", __func__, ret); + lirc_free_device(ir->l); + ir->l = NULL; goto out_put_xx; } dev_info(ir->dev, "IR unit on %s (i2c-%d) registered as lirc%d and ready\n", - adap->name, adap->nr, ir->l.minor); + adap->name, adap->nr, ir->l->minor); out_ok: if (rx) -- cgit v1.2.3 From b15e39379fe8700fe0ec849a5c5ee2b44cd16381 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Sun, 25 Jun 2017 09:32:36 -0300 Subject: [media] media: lirc_dev: merge struct irctl into struct lirc_dev The use of two separate structs (lirc_dev aka lirc_driver and irctl) makes it much harder to follow the proper lifetime of the various structs and necessitates hacks such as keeping a copy of struct lirc_dev inside struct irctl. Merging the two structs means that lirc_dev can properly manage the lifetime of the resulting struct and simplifies the code at the same time. [mchehab@s-opensource.com: fix merge conflict] Signed-off-by: David Härdeman Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 15 +- drivers/media/rc/lirc_dev.c | 314 ++++++++++++++------------------ drivers/staging/media/lirc/lirc_zilog.c | 20 +- include/media/lirc_dev.h | 26 ++- 4 files changed, 175 insertions(+), 200 deletions(-) diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index d5c155a5a547..bd046c41a53a 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -35,7 +35,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) struct lirc_codec *lirc = &dev->raw->lirc; int sample; - if (!dev->raw->lirc.ldev || !dev->raw->lirc.ldev->rbuf) + if (!dev->raw->lirc.ldev || !dev->raw->lirc.ldev->buf) return -EINVAL; /* Packet start */ @@ -84,7 +84,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) (u64)LIRC_VALUE_MASK); gap_sample = LIRC_SPACE(lirc->gap_duration); - lirc_buffer_write(dev->raw->lirc.ldev->rbuf, + lirc_buffer_write(dev->raw->lirc.ldev->buf, (unsigned char *)&gap_sample); lirc->gap = false; } @@ -95,9 +95,9 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) TO_US(ev.duration), TO_STR(ev.pulse)); } - lirc_buffer_write(dev->raw->lirc.ldev->rbuf, + lirc_buffer_write(dev->raw->lirc.ldev->buf, (unsigned char *) &sample); - wake_up(&dev->raw->lirc.ldev->rbuf->wait_poll); + wake_up(&dev->raw->lirc.ldev->buf->wait_poll); return 0; } @@ -384,12 +384,12 @@ static int ir_lirc_register(struct rc_dev *dev) dev->driver_name); ldev->features = features; ldev->data = &dev->raw->lirc; - ldev->rbuf = NULL; + ldev->buf = NULL; ldev->code_length = sizeof(struct ir_raw_event) * 8; ldev->chunk_size = sizeof(int); ldev->buffer_size = LIRCBUF_SIZE; ldev->fops = &lirc_fops; - ldev->dev = &dev->dev; + ldev->dev.parent = &dev->dev; ldev->rdev = dev; ldev->owner = THIS_MODULE; @@ -402,7 +402,7 @@ static int ir_lirc_register(struct rc_dev *dev) return 0; out: - kfree(ldev); + lirc_free_device(ldev); return rc; } @@ -411,7 +411,6 @@ static int ir_lirc_unregister(struct rc_dev *dev) struct lirc_codec *lirc = &dev->raw->lirc; lirc_unregister_device(lirc->ldev); - kfree(lirc->ldev); lirc->ldev = NULL; return 0; diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index a6005f70de5a..e9dae8621670 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -34,19 +34,6 @@ static dev_t lirc_base_dev; -struct irctl { - struct lirc_dev d; - bool attached; - int open; - - struct mutex mutex; /* protect from simultaneous accesses */ - struct lirc_buffer *buf; - bool buf_internal; - - struct device dev; - struct cdev cdev; -}; - /* Used to keep track of allocated lirc devices */ #define LIRC_MAX_DEVICES 256 static DEFINE_IDA(lirc_ida); @@ -54,71 +41,74 @@ static DEFINE_IDA(lirc_ida); /* Only used for sysfs but defined to void otherwise */ static struct class *lirc_class; -static void lirc_free_buffer(struct irctl *ir) +static void lirc_release_device(struct device *ld) { - put_device(ir->dev.parent); - - if (ir->buf_internal) { - lirc_buffer_free(ir->buf); - kfree(ir->buf); - ir->buf = NULL; - } -} + struct lirc_dev *d = container_of(ld, struct lirc_dev, dev); -static void lirc_release(struct device *ld) -{ - struct irctl *ir = container_of(ld, struct irctl, dev); + put_device(d->dev.parent); - lirc_free_buffer(ir); - kfree(ir); + if (d->buf_internal) { + lirc_buffer_free(d->buf); + kfree(d->buf); + d->buf = NULL; + } + kfree(d); + module_put(THIS_MODULE); } -static int lirc_allocate_buffer(struct irctl *ir) +static int lirc_allocate_buffer(struct lirc_dev *d) { - int err = 0; - struct lirc_dev *d = &ir->d; + int err; - if (d->rbuf) { - ir->buf = d->rbuf; - ir->buf_internal = false; - } else { - ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL); - if (!ir->buf) { - err = -ENOMEM; - goto out; - } + if (d->buf) { + d->buf_internal = false; + return 0; + } - err = lirc_buffer_init(ir->buf, d->chunk_size, d->buffer_size); - if (err) { - kfree(ir->buf); - ir->buf = NULL; - goto out; - } + d->buf = kmalloc(sizeof(*d->buf), GFP_KERNEL); + if (!d->buf) + return -ENOMEM; - ir->buf_internal = true; - d->rbuf = ir->buf; + err = lirc_buffer_init(d->buf, d->chunk_size, d->buffer_size); + if (err) { + kfree(d->buf); + d->buf = NULL; + return err; } -out: - return err; + d->buf_internal = true; + return 0; } struct lirc_dev * lirc_allocate_device(void) { - return kzalloc(sizeof(struct lirc_dev), GFP_KERNEL); + struct lirc_dev *d; + + d = kzalloc(sizeof(*d), GFP_KERNEL); + if (d) { + mutex_init(&d->mutex); + device_initialize(&d->dev); + d->dev.class = lirc_class; + d->dev.release = lirc_release_device; + __module_get(THIS_MODULE); + } + + return d; } EXPORT_SYMBOL(lirc_allocate_device); void lirc_free_device(struct lirc_dev *d) { - kfree(d); + if (!d) + return; + + put_device(&d->dev); } EXPORT_SYMBOL(lirc_free_device); int lirc_register_device(struct lirc_dev *d) { - struct irctl *ir; int minor; int err; @@ -127,8 +117,8 @@ int lirc_register_device(struct lirc_dev *d) return -EBADRQC; } - if (!d->dev) { - pr_err("dev pointer not filled in!\n"); + if (!d->dev.parent) { + pr_err("dev parent pointer not filled in!\n"); return -EINVAL; } @@ -137,25 +127,25 @@ int lirc_register_device(struct lirc_dev *d) return -EINVAL; } - if (!d->rbuf && d->chunk_size < 1) { + if (!d->buf && d->chunk_size < 1) { pr_err("chunk_size must be set!\n"); return -EINVAL; } - if (!d->rbuf && d->buffer_size < 1) { + if (!d->buf && d->buffer_size < 1) { pr_err("buffer_size must be set!\n"); return -EINVAL; } if (d->code_length < 1 || d->code_length > (BUFLEN * 8)) { - dev_err(d->dev, "code length must be less than %d bits\n", - BUFLEN * 8); + dev_err(&d->dev, "code length must be less than %d bits\n", + BUFLEN * 8); return -EBADRQC; } - if (!d->rbuf && !(d->fops && d->fops->read && - d->fops->poll && d->fops->unlocked_ioctl)) { - dev_err(d->dev, "undefined read, poll, ioctl\n"); + if (!d->buf && !(d->fops && d->fops->read && + d->fops->poll && d->fops->unlocked_ioctl)) { + dev_err(&d->dev, "undefined read, poll, ioctl\n"); return -EBADRQC; } @@ -165,55 +155,34 @@ int lirc_register_device(struct lirc_dev *d) if (d->features == 0) d->features = LIRC_CAN_REC_LIRCCODE; - ir = kzalloc(sizeof(*ir), GFP_KERNEL); - if (!ir) - return -ENOMEM; - - mutex_init(&ir->mutex); - ir->d = *d; - if (LIRC_CAN_REC(d->features)) { - err = lirc_allocate_buffer(ir); - if (err) { - kfree(ir); + err = lirc_allocate_buffer(d); + if (err) return err; - } - d->rbuf = ir->buf; } minor = ida_simple_get(&lirc_ida, 0, LIRC_MAX_DEVICES, GFP_KERNEL); - if (minor < 0) { - lirc_free_buffer(ir); - kfree(ir); + if (minor < 0) return minor; - } - d->irctl = ir; d->minor = minor; - ir->d.minor = minor; - - device_initialize(&ir->dev); - ir->dev.devt = MKDEV(MAJOR(lirc_base_dev), ir->d.minor); - ir->dev.class = lirc_class; - ir->dev.parent = d->dev; - ir->dev.release = lirc_release; - dev_set_name(&ir->dev, "lirc%d", ir->d.minor); + d->dev.devt = MKDEV(MAJOR(lirc_base_dev), d->minor); + dev_set_name(&d->dev, "lirc%d", d->minor); - cdev_init(&ir->cdev, d->fops); - ir->cdev.owner = ir->d.owner; - ir->attached = true; + cdev_init(&d->cdev, d->fops); + d->cdev.owner = d->owner; + d->attached = true; - err = cdev_device_add(&ir->cdev, &ir->dev); + err = cdev_device_add(&d->cdev, &d->dev); if (err) { ida_simple_remove(&lirc_ida, minor); - put_device(&ir->dev); return err; } - get_device(ir->dev.parent); + get_device(d->dev.parent); - dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n", - ir->d.name, ir->d.minor); + dev_info(&d->dev, "lirc_dev: driver %s registered at minor = %d\n", + d->name, d->minor); return 0; } @@ -221,88 +190,83 @@ EXPORT_SYMBOL(lirc_register_device); void lirc_unregister_device(struct lirc_dev *d) { - struct irctl *ir; - - if (!d || !d->irctl) + if (!d) return; - ir = d->irctl; - - dev_dbg(ir->d.dev, "lirc_dev: driver %s unregistered from minor = %d\n", + dev_dbg(&d->dev, "lirc_dev: driver %s unregistered from minor = %d\n", d->name, d->minor); - cdev_device_del(&ir->cdev, &ir->dev); - - mutex_lock(&ir->mutex); + mutex_lock(&d->mutex); - ir->attached = false; - if (ir->open) { - dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n", + d->attached = false; + if (d->open) { + dev_dbg(&d->dev, LOGHEAD "releasing opened driver\n", d->name, d->minor); - wake_up_interruptible(&ir->buf->wait_poll); + wake_up_interruptible(&d->buf->wait_poll); } - mutex_unlock(&ir->mutex); + mutex_unlock(&d->mutex); + cdev_device_del(&d->cdev, &d->dev); ida_simple_remove(&lirc_ida, d->minor); - put_device(&ir->dev); + put_device(&d->dev); } EXPORT_SYMBOL(lirc_unregister_device); int lirc_dev_fop_open(struct inode *inode, struct file *file) { - struct irctl *ir = container_of(inode->i_cdev, struct irctl, cdev); + struct lirc_dev *d = container_of(inode->i_cdev, struct lirc_dev, cdev); int retval; - dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor); + dev_dbg(&d->dev, LOGHEAD "open called\n", d->name, d->minor); - retval = mutex_lock_interruptible(&ir->mutex); + retval = mutex_lock_interruptible(&d->mutex); if (retval) return retval; - if (!ir->attached) { + if (!d->attached) { retval = -ENODEV; goto out; } - if (ir->open) { + if (d->open) { retval = -EBUSY; goto out; } - if (ir->d.rdev) { - retval = rc_open(ir->d.rdev); + if (d->rdev) { + retval = rc_open(d->rdev); if (retval) goto out; } - if (ir->buf) - lirc_buffer_clear(ir->buf); + if (d->buf) + lirc_buffer_clear(d->buf); - ir->open++; + d->open++; lirc_init_pdata(inode, file); nonseekable_open(inode, file); - mutex_unlock(&ir->mutex); + mutex_unlock(&d->mutex); return 0; out: - mutex_unlock(&ir->mutex); + mutex_unlock(&d->mutex); return retval; } EXPORT_SYMBOL(lirc_dev_fop_open); int lirc_dev_fop_close(struct inode *inode, struct file *file) { - struct irctl *ir = file->private_data; + struct lirc_dev *d = file->private_data; - mutex_lock(&ir->mutex); + mutex_lock(&d->mutex); - rc_close(ir->d.rdev); - ir->open--; + rc_close(d->rdev); + d->open--; - mutex_unlock(&ir->mutex); + mutex_unlock(&d->mutex); return 0; } @@ -310,24 +274,24 @@ EXPORT_SYMBOL(lirc_dev_fop_close); unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait) { - struct irctl *ir = file->private_data; + struct lirc_dev *d = file->private_data; unsigned int ret; - if (!ir->attached) + if (!d->attached) return POLLHUP | POLLERR; - if (ir->buf) { - poll_wait(file, &ir->buf->wait_poll, wait); + if (d->buf) { + poll_wait(file, &d->buf->wait_poll, wait); - if (lirc_buffer_empty(ir->buf)) + if (lirc_buffer_empty(d->buf)) ret = 0; else ret = POLLIN | POLLRDNORM; - } else + } else { ret = POLLERR; + } - dev_dbg(ir->d.dev, LOGHEAD "poll result = %d\n", - ir->d.name, ir->d.minor, ret); + dev_dbg(&d->dev, LOGHEAD "poll result = %d\n", d->name, d->minor, ret); return ret; } @@ -335,44 +299,44 @@ EXPORT_SYMBOL(lirc_dev_fop_poll); long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct irctl *ir = file->private_data; + struct lirc_dev *d = file->private_data; __u32 mode; int result; - dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n", - ir->d.name, ir->d.minor, cmd); + dev_dbg(&d->dev, LOGHEAD "ioctl called (0x%x)\n", + d->name, d->minor, cmd); - result = mutex_lock_interruptible(&ir->mutex); + result = mutex_lock_interruptible(&d->mutex); if (result) return result; - if (!ir->attached) { + if (!d->attached) { result = -ENODEV; goto out; } switch (cmd) { case LIRC_GET_FEATURES: - result = put_user(ir->d.features, (__u32 __user *)arg); + result = put_user(d->features, (__u32 __user *)arg); break; case LIRC_GET_REC_MODE: - if (!LIRC_CAN_REC(ir->d.features)) { + if (!LIRC_CAN_REC(d->features)) { result = -ENOTTY; break; } result = put_user(LIRC_REC2MODE - (ir->d.features & LIRC_CAN_REC_MASK), + (d->features & LIRC_CAN_REC_MASK), (__u32 __user *)arg); break; case LIRC_SET_REC_MODE: - if (!LIRC_CAN_REC(ir->d.features)) { + if (!LIRC_CAN_REC(d->features)) { result = -ENOTTY; break; } result = get_user(mode, (__u32 __user *)arg); - if (!result && !(LIRC_MODE2REC(mode) & ir->d.features)) + if (!result && !(LIRC_MODE2REC(mode) & d->features)) result = -EINVAL; /* * FIXME: We should actually set the mode somehow but @@ -380,32 +344,32 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) */ break; case LIRC_GET_LENGTH: - result = put_user(ir->d.code_length, (__u32 __user *)arg); + result = put_user(d->code_length, (__u32 __user *)arg); break; case LIRC_GET_MIN_TIMEOUT: - if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || - ir->d.min_timeout == 0) { + if (!(d->features & LIRC_CAN_SET_REC_TIMEOUT) || + d->min_timeout == 0) { result = -ENOTTY; break; } - result = put_user(ir->d.min_timeout, (__u32 __user *)arg); + result = put_user(d->min_timeout, (__u32 __user *)arg); break; case LIRC_GET_MAX_TIMEOUT: - if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) || - ir->d.max_timeout == 0) { + if (!(d->features & LIRC_CAN_SET_REC_TIMEOUT) || + d->max_timeout == 0) { result = -ENOTTY; break; } - result = put_user(ir->d.max_timeout, (__u32 __user *)arg); + result = put_user(d->max_timeout, (__u32 __user *)arg); break; default: result = -ENOTTY; } out: - mutex_unlock(&ir->mutex); + mutex_unlock(&d->mutex); return result; } EXPORT_SYMBOL(lirc_dev_fop_ioctl); @@ -415,34 +379,34 @@ ssize_t lirc_dev_fop_read(struct file *file, size_t length, loff_t *ppos) { - struct irctl *ir = file->private_data; + struct lirc_dev *d = file->private_data; unsigned char *buf; int ret, written = 0; DECLARE_WAITQUEUE(wait, current); - dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor); - - buf = kzalloc(ir->buf->chunk_size, GFP_KERNEL); + buf = kzalloc(d->buf->chunk_size, GFP_KERNEL); if (!buf) return -ENOMEM; - ret = mutex_lock_interruptible(&ir->mutex); + dev_dbg(&d->dev, LOGHEAD "read called\n", d->name, d->minor); + + ret = mutex_lock_interruptible(&d->mutex); if (ret) { kfree(buf); return ret; } - if (!ir->attached) { + if (!d->attached) { ret = -ENODEV; goto out_locked; } - if (!LIRC_CAN_REC(ir->d.features)) { + if (!LIRC_CAN_REC(d->features)) { ret = -EINVAL; goto out_locked; } - if (length % ir->buf->chunk_size) { + if (length % d->buf->chunk_size) { ret = -EINVAL; goto out_locked; } @@ -452,14 +416,14 @@ ssize_t lirc_dev_fop_read(struct file *file, * to avoid losing scan code (in case when queue is awaken somewhere * between while condition checking and scheduling) */ - add_wait_queue(&ir->buf->wait_poll, &wait); + add_wait_queue(&d->buf->wait_poll, &wait); /* * while we didn't provide 'length' bytes, device is opened in blocking * mode and 'copy_to_user' is happy, wait for data. */ while (written < length && ret == 0) { - if (lirc_buffer_empty(ir->buf)) { + if (lirc_buffer_empty(d->buf)) { /* According to the read(2) man page, 'written' can be * returned as less than 'length', instead of blocking * again, returning -EWOULDBLOCK, or returning @@ -476,36 +440,36 @@ ssize_t lirc_dev_fop_read(struct file *file, break; } - mutex_unlock(&ir->mutex); + mutex_unlock(&d->mutex); set_current_state(TASK_INTERRUPTIBLE); schedule(); set_current_state(TASK_RUNNING); - ret = mutex_lock_interruptible(&ir->mutex); + ret = mutex_lock_interruptible(&d->mutex); if (ret) { - remove_wait_queue(&ir->buf->wait_poll, &wait); + remove_wait_queue(&d->buf->wait_poll, &wait); goto out_unlocked; } - if (!ir->attached) { + if (!d->attached) { ret = -ENODEV; goto out_locked; } } else { - lirc_buffer_read(ir->buf, buf); + lirc_buffer_read(d->buf, buf); ret = copy_to_user((void __user *)buffer+written, buf, - ir->buf->chunk_size); + d->buf->chunk_size); if (!ret) - written += ir->buf->chunk_size; + written += d->buf->chunk_size; else ret = -EFAULT; } } - remove_wait_queue(&ir->buf->wait_poll, &wait); + remove_wait_queue(&d->buf->wait_poll, &wait); out_locked: - mutex_unlock(&ir->mutex); + mutex_unlock(&d->mutex); out_unlocked: kfree(buf); @@ -516,17 +480,17 @@ EXPORT_SYMBOL(lirc_dev_fop_read); void lirc_init_pdata(struct inode *inode, struct file *file) { - struct irctl *ir = container_of(inode->i_cdev, struct irctl, cdev); + struct lirc_dev *d = container_of(inode->i_cdev, struct lirc_dev, cdev); - file->private_data = ir; + file->private_data = d; } EXPORT_SYMBOL(lirc_init_pdata); void *lirc_get_pdata(struct file *file) { - struct irctl *ir = file->private_data; + struct lirc_dev *d = file->private_data; - return ir->d.data; + return d->data; } EXPORT_SYMBOL(lirc_get_pdata); diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c index 00e8c8f224b7..6bd0717bf76e 100644 --- a/drivers/staging/media/lirc/lirc_zilog.c +++ b/drivers/staging/media/lirc/lirc_zilog.c @@ -184,10 +184,8 @@ static void release_ir_device(struct kref *ref) * ir->open_count == 0 - happens on final close() * ir_lock, tx_ref_lock, rx_ref_lock, all released */ - if (ir->l) { + if (ir->l) lirc_unregister_device(ir->l); - lirc_free_device(ir->l); - } if (kfifo_initialized(&ir->rbuf.fifo)) lirc_buffer_free(&ir->rbuf); @@ -318,7 +316,7 @@ static int add_to_buf(struct IR *ir) int ret; int failures = 0; unsigned char sendbuf[1] = { 0 }; - struct lirc_buffer *rbuf = ir->l->rbuf; + struct lirc_buffer *rbuf = ir->l->buf; struct IR_rx *rx; struct IR_tx *tx; @@ -464,7 +462,7 @@ static int add_to_buf(struct IR *ir) static int lirc_thread(void *arg) { struct IR *ir = arg; - struct lirc_buffer *rbuf = ir->l->rbuf; + struct lirc_buffer *rbuf = ir->l->buf; dev_dbg(ir->dev, "poll thread started\n"); @@ -885,7 +883,7 @@ static ssize_t read(struct file *filep, char __user *outbuf, size_t n, { struct IR *ir = lirc_get_pdata(filep); struct IR_rx *rx; - struct lirc_buffer *rbuf = ir->l->rbuf; + struct lirc_buffer *rbuf = ir->l->buf; int ret = 0, written = 0, retries = 0; unsigned int m; DECLARE_WAITQUEUE(wait, current); @@ -1203,7 +1201,7 @@ static unsigned int poll(struct file *filep, poll_table *wait) { struct IR *ir = lirc_get_pdata(filep); struct IR_rx *rx; - struct lirc_buffer *rbuf = ir->l->rbuf; + struct lirc_buffer *rbuf = ir->l->buf; unsigned int ret; dev_dbg(ir->dev, "%s called\n", __func__); @@ -1449,6 +1447,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) ir->l->code_length = 13; ir->l->fops = &lirc_fops; ir->l->owner = THIS_MODULE; + ir->l->dev.parent = &adap->dev; /* * FIXME this is a pointer reference to us, but no refcount. @@ -1456,13 +1455,12 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) * This OK for now, since lirc_dev currently won't touch this * buffer as we provide our own lirc_fops. * - * Currently our own lirc_fops rely on this ir->l->rbuf pointer + * Currently our own lirc_fops rely on this ir->l->buf pointer */ - ir->l->rbuf = &ir->rbuf; - ir->l->dev = &adap->dev; + ir->l->buf = &ir->rbuf; /* This will be returned by lirc_get_pdata() */ ir->l->data = ir; - ret = lirc_buffer_init(ir->l->rbuf, 2, BUFLEN / 2); + ret = lirc_buffer_init(ir->l->buf, 2, BUFLEN / 2); if (ret) { lirc_free_device(ir->l); ir->l = NULL; diff --git a/include/media/lirc_dev.h b/include/media/lirc_dev.h index 4b0dc640e142..981dcabd5fd5 100644 --- a/include/media/lirc_dev.h +++ b/include/media/lirc_dev.h @@ -17,6 +17,8 @@ #include #include #include +#include +#include struct lirc_buffer { wait_queue_head_t wait_poll; @@ -127,14 +129,19 @@ static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf, * LIRC_CAN_SET_REC_TIMEOUT is defined. * @max_timeout: Maximum timeout for record. Valid only if * LIRC_CAN_SET_REC_TIMEOUT is defined. - * @rbuf: if not NULL, it will be used as a read buffer, you will + * @buf: if %NULL, lirc_dev will allocate and manage the buffer, + * otherwise allocated by the caller which will * have to write to the buffer by other means, like irq's * (see also lirc_serial.c). + * @buf_internal: whether lirc_dev has allocated the read buffer or not * @rdev: &struct rc_dev associated with the device * @fops: &struct file_operations for the device - * @dev: &struct device assigned to the device * @owner: the module owning this struct - * @irctl: &struct irctl assigned to the device + * @attached: if the device is still live + * @open: open count for the device's chardev + * @mutex: serialises file_operations calls + * @dev: &struct device assigned to the device + * @cdev: &struct cdev assigned to the device */ struct lirc_dev { char name[40]; @@ -144,16 +151,23 @@ struct lirc_dev { unsigned int buffer_size; /* in chunks holding one code each */ unsigned int chunk_size; + struct lirc_buffer *buf; + bool buf_internal; void *data; int min_timeout; int max_timeout; - struct lirc_buffer *rbuf; struct rc_dev *rdev; const struct file_operations *fops; - struct device *dev; struct module *owner; - struct irctl *irctl; + + bool attached; + int open; + + struct mutex mutex; /* protect from simultaneous accesses */ + + struct device dev; + struct cdev cdev; }; struct lirc_dev *lirc_allocate_device(void); -- cgit v1.2.3 From 5fad16b5969b43a9722bbe3b288e40bff0003504 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Sun, 13 Aug 2017 05:54:44 -0300 Subject: [media] media: rc: constify usb_device_id usb_device_id are not supposed to change at runtime. All functions working with usb_device_id provided by work with const usb_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ati_remote.c | 2 +- drivers/media/rc/igorplugusb.c | 2 +- drivers/media/rc/imon.c | 2 +- drivers/media/rc/mceusb.c | 2 +- drivers/media/rc/redrat3.c | 2 +- drivers/media/rc/streamzap.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index d0871d60a723..8e82610ffaad 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -198,7 +198,7 @@ static const struct ati_receiver_type type_firefly = { .default_keymap = RC_MAP_SNAPSTREAM_FIREFLY }; -static struct usb_device_id ati_remote_table[] = { +static const struct usb_device_id ati_remote_table[] = { { USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID), .driver_info = (unsigned long)&type_ati diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c index a5ea86be8f44..4b715eb995f8 100644 --- a/drivers/media/rc/igorplugusb.c +++ b/drivers/media/rc/igorplugusb.c @@ -245,7 +245,7 @@ static void igorplugusb_disconnect(struct usb_interface *intf) usb_free_urb(ir->urb); } -static struct usb_device_id igorplugusb_table[] = { +static const struct usb_device_id igorplugusb_table[] = { /* Igor Plug USB (Atmel's Manufact. ID) */ { USB_DEVICE(0x03eb, 0x0002) }, /* Fit PC2 Infrared Adapter */ diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 7b3f31cc63d2..b93dc6e1f1bf 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -346,7 +346,7 @@ static const struct imon_usb_dev_descr imon_ir_raw = { * devices use the SoundGraph vendor ID (0x15c2). This driver only supports * the ffdc and later devices, which do onboard decoding. */ -static struct usb_device_id imon_usb_id_table[] = { +static const struct usb_device_id imon_usb_id_table[] = { /* * Several devices with this same device ID, all use iMON_PAD.inf * SoundGraph iMON PAD (IR & VFD) diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index bf7aaff3aa37..67c1ff099eb4 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -249,7 +249,7 @@ static const struct mceusb_model mceusb_model[] = { }, }; -static struct usb_device_id mceusb_dev_table[] = { +static const struct usb_device_id mceusb_dev_table[] = { /* Original Microsoft MCE IR Transceiver (often HP-branded) */ { USB_DEVICE(VENDOR_MICROSOFT, 0x006d), .driver_info = MCE_GEN1 }, diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 6784cb9fc4e7..6bfc24885b5c 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -186,7 +186,7 @@ struct redrat3_error { } __packed; /* table of devices that work with this driver */ -static struct usb_device_id redrat3_dev_table[] = { +static const struct usb_device_id redrat3_dev_table[] = { /* Original version of the RedRat3 */ {USB_DEVICE(USB_RR3USB_VENDOR_ID, USB_RR3USB_PRODUCT_ID)}, /* Second Version/release of the RedRat3 - RetRat3-II */ diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index f03a174ddf9d..4eebfcfc10f3 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c @@ -43,7 +43,7 @@ #define USB_STREAMZAP_PRODUCT_ID 0x0000 /* table of devices that work with this driver */ -static struct usb_device_id streamzap_table[] = { +static const struct usb_device_id streamzap_table[] = { /* Streamzap Remote Control */ { USB_DEVICE(USB_STREAMZAP_VENDOR_ID, USB_STREAMZAP_PRODUCT_ID) }, /* Terminating entry */ -- cgit v1.2.3 From f03f02f9d261902a5761f02ff03a0620ed4f9d0d Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Sat, 19 Aug 2017 05:22:15 -0300 Subject: [media] media: rc: make device_type const Make this const as it is only stored in the type field of a device structure, which is const. Done using Coccinelle. Signed-off-by: Bhumika Goyal Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 981cccd6b988..33bddba6e541 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1529,7 +1529,7 @@ static const struct attribute_group rc_dev_wakeup_filter_attr_grp = { .attrs = rc_dev_wakeup_filter_attrs, }; -static struct device_type rc_dev_type = { +static const struct device_type rc_dev_type = { .release = rc_dev_release, .uevent = rc_dev_uevent, }; -- cgit v1.2.3 From 3e70b256a6b6a549bdbbd5d70895ff8147c7cf7d Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 29 Aug 2017 07:40:07 -0300 Subject: [media] media: imon: delete an error message for a failed memory allocation Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index b93dc6e1f1bf..188cf1b4ebb1 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -2311,10 +2311,9 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf, int ret = -ENOMEM; ictx = kzalloc(sizeof(struct imon_context), GFP_KERNEL); - if (!ictx) { - dev_err(dev, "%s: kzalloc failed for context", __func__); + if (!ictx) goto exit; - } + rx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!rx_urb) goto rx_urb_alloc_failed; -- cgit v1.2.3 From 6805454b9ceaf526f18193d89aeab0c00715dca3 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 29 Aug 2017 16:04:20 -0300 Subject: [media] media: img-ir: delete an error message for a failed memory allocation Omit an extra message for a memory allocation failure in this function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/img-ir/img-ir-core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/rc/img-ir/img-ir-core.c b/drivers/media/rc/img-ir/img-ir-core.c index 03fe080278df..bcbabeeab12a 100644 --- a/drivers/media/rc/img-ir/img-ir-core.c +++ b/drivers/media/rc/img-ir/img-ir-core.c @@ -92,10 +92,9 @@ static int img_ir_probe(struct platform_device *pdev) /* Private driver data */ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(&pdev->dev, "cannot allocate device data\n"); + if (!priv) return -ENOMEM; - } + platform_set_drvdata(pdev, priv); priv->dev = &pdev->dev; spin_lock_init(&priv->lock); -- cgit v1.2.3 From 3003812b37dcd2d47b1dbad54d46ef14bd043498 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Fri, 1 Sep 2017 09:29:58 -0300 Subject: [media] media: dvb: a800: port to rc-core This receiver only accepts nec16 messages, I've tried many other protocols and they're all dropped. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/a800.c | 65 +++++++++------------------------------- 1 file changed, 14 insertions(+), 51 deletions(-) diff --git a/drivers/media/usb/dvb-usb/a800.c b/drivers/media/usb/dvb-usb/a800.c index 7ba975bea96a..540886b3bb29 100644 --- a/drivers/media/usb/dvb-usb/a800.c +++ b/drivers/media/usb/dvb-usb/a800.c @@ -37,48 +37,9 @@ static int a800_identify_state(struct usb_device *udev, struct dvb_usb_device_pr return 0; } -static struct rc_map_table rc_map_a800_table[] = { - { 0x0201, KEY_MODE }, /* SOURCE */ - { 0x0200, KEY_POWER2 }, /* POWER */ - { 0x0205, KEY_1 }, /* 1 */ - { 0x0206, KEY_2 }, /* 2 */ - { 0x0207, KEY_3 }, /* 3 */ - { 0x0209, KEY_4 }, /* 4 */ - { 0x020a, KEY_5 }, /* 5 */ - { 0x020b, KEY_6 }, /* 6 */ - { 0x020d, KEY_7 }, /* 7 */ - { 0x020e, KEY_8 }, /* 8 */ - { 0x020f, KEY_9 }, /* 9 */ - { 0x0212, KEY_LEFT }, /* L / DISPLAY */ - { 0x0211, KEY_0 }, /* 0 */ - { 0x0213, KEY_RIGHT }, /* R / CH RTN */ - { 0x0217, KEY_CAMERA }, /* SNAP SHOT */ - { 0x0210, KEY_LAST }, /* 16-CH PREV */ - { 0x021e, KEY_VOLUMEDOWN }, /* VOL DOWN */ - { 0x020c, KEY_ZOOM }, /* FULL SCREEN */ - { 0x021f, KEY_VOLUMEUP }, /* VOL UP */ - { 0x0214, KEY_MUTE }, /* MUTE */ - { 0x0208, KEY_AUDIO }, /* AUDIO */ - { 0x0219, KEY_RECORD }, /* RECORD */ - { 0x0218, KEY_PLAY }, /* PLAY */ - { 0x021b, KEY_STOP }, /* STOP */ - { 0x021a, KEY_PLAYPAUSE }, /* TIMESHIFT / PAUSE */ - { 0x021d, KEY_BACK }, /* << / RED */ - { 0x021c, KEY_FORWARD }, /* >> / YELLOW */ - { 0x0203, KEY_TEXT }, /* TELETEXT */ - { 0x0204, KEY_EPG }, /* EPG */ - { 0x0215, KEY_MENU }, /* MENU */ - - { 0x0303, KEY_CHANNELUP }, /* CH UP */ - { 0x0302, KEY_CHANNELDOWN }, /* CH DOWN */ - { 0x0301, KEY_FIRST }, /* |<< / GREEN */ - { 0x0300, KEY_LAST }, /* >>| / BLUE */ - -}; - -static int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +static int a800_rc_query(struct dvb_usb_device *d) { - int ret; + int ret = 0; u8 *key = kmalloc(5, GFP_KERNEL); if (!key) return -ENOMEM; @@ -90,11 +51,12 @@ static int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state) goto out; } - /* call the universal NEC remote processor, to find out the key's state and event */ - dvb_usb_nec_rc_key_to_event(d,key,event,state); - if (key[0] != 0) - deb_rc("key: %*ph\n", 5, key); - ret = 0; + /* Note that extended nec and nec32 are dropped */ + if (key[0] == 1) + rc_keydown(d->rc_dev, RC_PROTO_NEC, + RC_SCANCODE_NEC(key[1], key[3]), 0); + else if (key[0] == 2) + rc_repeat(d->rc_dev); out: kfree(key); return ret; @@ -157,11 +119,12 @@ static struct dvb_usb_device_properties a800_properties = { .power_ctrl = a800_power_ctrl, .identify_state = a800_identify_state, - .rc.legacy = { - .rc_interval = DEFAULT_RC_INTERVAL, - .rc_map_table = rc_map_a800_table, - .rc_map_size = ARRAY_SIZE(rc_map_a800_table), - .rc_query = a800_rc_query, + .rc.core = { + .rc_interval = DEFAULT_RC_INTERVAL, + .rc_codes = RC_MAP_AVERMEDIA_M135A, + .module_name = KBUILD_MODNAME, + .rc_query = a800_rc_query, + .allowed_protos = RC_PROTO_BIT_NEC, }, .i2c_algo = &dibusb_i2c_algo, -- cgit v1.2.3 From efdc16adb7d37a57b4d07833bbab73a0a1aed476 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Fri, 1 Sep 2017 08:34:50 -0300 Subject: [media] media: rc: avermedia keymap for a800 The keymap is missing one key, and correct another. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/rc-avermedia-m135a.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/rc/keymaps/rc-avermedia-m135a.c b/drivers/media/rc/keymaps/rc-avermedia-m135a.c index 9882e2cde975..6d5a73b7ccec 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-m135a.c +++ b/drivers/media/rc/keymaps/rc-avermedia-m135a.c @@ -43,7 +43,8 @@ static struct rc_map_table avermedia_m135a[] = { { 0x0213, KEY_RIGHT }, /* -> or L */ { 0x0212, KEY_LEFT }, /* <- or R */ - { 0x0217, KEY_SLEEP }, /* Capturar Imagem or Snapshot */ + { 0x0215, KEY_MENU }, + { 0x0217, KEY_CAMERA }, /* Capturar Imagem or Snapshot */ { 0x0210, KEY_SHUFFLE }, /* Amostra or 16 chan prev */ { 0x0303, KEY_CHANNELUP }, -- cgit v1.2.3 From 831c4c81e8ceba7d34b7fc66da1693bc4b9e7e11 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Fri, 1 Sep 2017 09:55:59 -0300 Subject: [media] media: rc: ensure that protocols are enabled for scancode drivers rc scancode drivers without change_protocol should have all protocols enabled at all time. This was only true for cec and ir-kbd-i2c. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-core.c | 1 - drivers/media/i2c/ir-kbd-i2c.c | 1 - drivers/media/rc/rc-main.c | 3 +++ 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c index e3a1fb6d6690..5870da6a567f 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c @@ -277,7 +277,6 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, adap->rc->input_id.version = 1; adap->rc->driver_name = CEC_NAME; adap->rc->allowed_protocols = RC_PROTO_BIT_CEC; - adap->rc->enabled_protocols = RC_PROTO_BIT_CEC; adap->rc->priv = adap; adap->rc->map_name = RC_MAP_CEC; adap->rc->timeout = MS_TO_NS(100); diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index a374e2a0ac3d..8b5f7d0435e4 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -460,7 +460,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) */ rc->map_name = ir->ir_codes; rc->allowed_protocols = rc_proto; - rc->enabled_protocols = rc_proto; if (!rc->driver_name) rc->driver_name = MODULE_NAME; diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 33bddba6e541..127f3215cd84 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1638,6 +1638,9 @@ static int rc_prepare_rx_device(struct rc_dev *dev) rc_proto = BIT_ULL(rc_map->rc_proto); + if (dev->driver_type == RC_DRIVER_SCANCODE && !dev->change_protocol) + dev->enabled_protocols = dev->allowed_protocols; + if (dev->change_protocol) { rc = dev->change_protocol(dev, &rc_proto); if (rc < 0) -- cgit v1.2.3 From 3c03726aaf3f99f6b08959fcb3c1c409b0c9813d Mon Sep 17 00:00:00 2001 From: Sean Young Date: Fri, 1 Sep 2017 10:10:01 -0300 Subject: [media] media: rc: dvb: use dvb device name for rc device "IR-receiver inside an USB DVB receiver" is not descriptive and we have a proper name available. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/dvb-usb-remote.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/dvb-usb/dvb-usb-remote.c b/drivers/media/usb/dvb-usb/dvb-usb-remote.c index 0b03f9bd9c26..b027d378102a 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c @@ -279,7 +279,7 @@ static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d) dev->change_protocol = d->props.rc.core.change_protocol; dev->allowed_protocols = d->props.rc.core.allowed_protos; usb_to_input_id(d->udev, &dev->input_id); - dev->device_name = "IR-receiver inside an USB DVB receiver"; + dev->device_name = d->desc->name; dev->input_phys = d->rc_phys; dev->dev.parent = &d->udev->dev; dev->priv = d; -- cgit v1.2.3 From 6d75db305b8a964bfec337ca5f3c2cd5047b9bb1 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Fri, 1 Sep 2017 11:30:50 -0300 Subject: [media] media: rc: if protocols can't be changed, don't be writable If the protocols of an rc device cannot be changed, ensure the sysfs file is not writable. This makes it possible to detect this from userspace, so ir-keytable can deal with case without giving an error. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 127f3215cd84..42ac3490b5f8 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1487,7 +1487,10 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) /* * Static device attribute struct with the sysfs attributes for IR's */ -static DEVICE_ATTR(protocols, 0644, show_protocols, store_protocols); +static struct device_attribute dev_attr_ro_protocols = +__ATTR(protocols, 0444, show_protocols, NULL); +static struct device_attribute dev_attr_rw_protocols = +__ATTR(protocols, 0644, show_protocols, store_protocols); static DEVICE_ATTR(wakeup_protocols, 0644, show_wakeup_protocols, store_wakeup_protocols); static RC_FILTER_ATTR(filter, S_IRUGO|S_IWUSR, @@ -1499,13 +1502,22 @@ static RC_FILTER_ATTR(wakeup_filter, S_IRUGO|S_IWUSR, static RC_FILTER_ATTR(wakeup_filter_mask, S_IRUGO|S_IWUSR, show_filter, store_filter, RC_FILTER_WAKEUP, true); -static struct attribute *rc_dev_protocol_attrs[] = { - &dev_attr_protocols.attr, +static struct attribute *rc_dev_rw_protocol_attrs[] = { + &dev_attr_rw_protocols.attr, NULL, }; -static const struct attribute_group rc_dev_protocol_attr_grp = { - .attrs = rc_dev_protocol_attrs, +static const struct attribute_group rc_dev_rw_protocol_attr_grp = { + .attrs = rc_dev_rw_protocol_attrs, +}; + +static struct attribute *rc_dev_ro_protocol_attrs[] = { + &dev_attr_ro_protocols.attr, + NULL, +}; + +static const struct attribute_group rc_dev_ro_protocol_attr_grp = { + .attrs = rc_dev_ro_protocol_attrs, }; static struct attribute *rc_dev_filter_attrs[] = { @@ -1732,8 +1744,10 @@ int rc_register_device(struct rc_dev *dev) dev_set_drvdata(&dev->dev, dev); dev->dev.groups = dev->sysfs_groups; - if (dev->driver_type != RC_DRIVER_IR_RAW_TX) - dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp; + if (dev->driver_type == RC_DRIVER_SCANCODE && !dev->change_protocol) + dev->sysfs_groups[attr++] = &rc_dev_ro_protocol_attr_grp; + else if (dev->driver_type != RC_DRIVER_IR_RAW_TX) + dev->sysfs_groups[attr++] = &rc_dev_rw_protocol_attr_grp; if (dev->s_filter) dev->sysfs_groups[attr++] = &rc_dev_filter_attr_grp; if (dev->s_wakeup_filter) -- cgit v1.2.3 From b9f407e31c50730784f70ec2deec71491395565f Mon Sep 17 00:00:00 2001 From: Sean Young Date: Fri, 1 Sep 2017 11:34:23 -0300 Subject: [media] media: rc: include device name in rc udev event This name is also stored in the input's device name, but that is not available in TX only hardware (no input device). Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 42ac3490b5f8..8c828fee4f5a 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1480,6 +1480,8 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name); if (dev->driver_name) ADD_HOTPLUG_VAR("DRV_NAME=%s", dev->driver_name); + if (dev->device_name) + ADD_HOTPLUG_VAR("DEV_NAME=%s", dev->device_name); return 0; } -- cgit v1.2.3 From 771f87268e8cd0e50719eb20f0b613ec4b2a19ec Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 6 Sep 2017 08:19:06 -0300 Subject: [media] media: vp7045: port TwinhanDTV Alpha to rc-core Only the nec protocol is understood, but then it doesn't pass on the full scancode and it ignores the nec repeats its own remote sends, so holding buttons does not work. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/rc-twinhan1027.c | 2 +- drivers/media/usb/dvb-usb/dvb-usb-remote.c | 1 + drivers/media/usb/dvb-usb/dvb-usb.h | 1 + drivers/media/usb/dvb-usb/vp7045.c | 88 +++++------------------------- 4 files changed, 18 insertions(+), 74 deletions(-) diff --git a/drivers/media/rc/keymaps/rc-twinhan1027.c b/drivers/media/rc/keymaps/rc-twinhan1027.c index 2275b37c61d2..78bb3143a1a8 100644 --- a/drivers/media/rc/keymaps/rc-twinhan1027.c +++ b/drivers/media/rc/keymaps/rc-twinhan1027.c @@ -66,7 +66,7 @@ static struct rc_map_list twinhan_vp1027_map = { .map = { .scan = twinhan_vp1027, .size = ARRAY_SIZE(twinhan_vp1027), - .rc_proto = RC_PROTO_UNKNOWN, /* Legacy IR type */ + .rc_proto = RC_PROTO_NEC, .name = RC_MAP_TWINHAN_VP1027_DVBS, } }; diff --git a/drivers/media/usb/dvb-usb/dvb-usb-remote.c b/drivers/media/usb/dvb-usb/dvb-usb-remote.c index b027d378102a..bf7dcd6b03e0 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c @@ -283,6 +283,7 @@ static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d) dev->input_phys = d->rc_phys; dev->dev.parent = &d->udev->dev; dev->priv = d; + dev->scancode_mask = d->props.rc.core.scancode_mask; err = rc_register_device(dev); if (err < 0) { diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h index 72468fdffa18..1da9e47553f5 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb.h +++ b/drivers/media/usb/dvb-usb/dvb-usb.h @@ -207,6 +207,7 @@ struct dvb_rc { int (*rc_query) (struct dvb_usb_device *d); int rc_interval; bool bulk_mode; /* uses bulk mode */ + u32 scancode_mask; }; /** diff --git a/drivers/media/usb/dvb-usb/vp7045.c b/drivers/media/usb/dvb-usb/vp7045.c index 13340af0d39c..2527b88beb87 100644 --- a/drivers/media/usb/dvb-usb/vp7045.c +++ b/drivers/media/usb/dvb-usb/vp7045.c @@ -97,82 +97,22 @@ static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff) return vp7045_usb_op(d,SET_TUNER_POWER,&v,1,NULL,0,150); } -/* remote control stuff */ - -/* The keymapping struct. Somehow this should be loaded to the driver, but - * currently it is hardcoded. */ -static struct rc_map_table rc_map_vp7045_table[] = { - { 0x0016, KEY_POWER }, - { 0x0010, KEY_MUTE }, - { 0x0003, KEY_1 }, - { 0x0001, KEY_2 }, - { 0x0006, KEY_3 }, - { 0x0009, KEY_4 }, - { 0x001d, KEY_5 }, - { 0x001f, KEY_6 }, - { 0x000d, KEY_7 }, - { 0x0019, KEY_8 }, - { 0x001b, KEY_9 }, - { 0x0015, KEY_0 }, - { 0x0005, KEY_CHANNELUP }, - { 0x0002, KEY_CHANNELDOWN }, - { 0x001e, KEY_VOLUMEUP }, - { 0x000a, KEY_VOLUMEDOWN }, - { 0x0011, KEY_RECORD }, - { 0x0017, KEY_FAVORITES }, /* Heart symbol - Channel list. */ - { 0x0014, KEY_PLAY }, - { 0x001a, KEY_STOP }, - { 0x0040, KEY_REWIND }, - { 0x0012, KEY_FASTFORWARD }, - { 0x000e, KEY_PREVIOUS }, /* Recall - Previous channel. */ - { 0x004c, KEY_PAUSE }, - { 0x004d, KEY_SCREEN }, /* Full screen mode. */ - { 0x0054, KEY_AUDIO }, /* MTS - Switch to secondary audio. */ - { 0x000c, KEY_CANCEL }, /* Cancel */ - { 0x001c, KEY_EPG }, /* EPG */ - { 0x0000, KEY_TAB }, /* Tab */ - { 0x0048, KEY_INFO }, /* Preview */ - { 0x0004, KEY_LIST }, /* RecordList */ - { 0x000f, KEY_TEXT }, /* Teletext */ - { 0x0041, KEY_PREVIOUSSONG }, - { 0x0042, KEY_NEXTSONG }, - { 0x004b, KEY_UP }, - { 0x0051, KEY_DOWN }, - { 0x004e, KEY_LEFT }, - { 0x0052, KEY_RIGHT }, - { 0x004f, KEY_ENTER }, - { 0x0013, KEY_CANCEL }, - { 0x004a, KEY_CLEAR }, - { 0x0054, KEY_PRINT }, /* Capture */ - { 0x0043, KEY_SUBTITLE }, /* Subtitle/CC */ - { 0x0008, KEY_VIDEO }, /* A/V */ - { 0x0007, KEY_SLEEP }, /* Hibernate */ - { 0x0045, KEY_ZOOM }, /* Zoom+ */ - { 0x0018, KEY_RED}, - { 0x0053, KEY_GREEN}, - { 0x005e, KEY_YELLOW}, - { 0x005f, KEY_BLUE} -}; - -static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state) +static int vp7045_rc_query(struct dvb_usb_device *d) { u8 key; - int i; vp7045_usb_op(d,RC_VAL_READ,NULL,0,&key,1,20); deb_rc("remote query key: %x %d\n",key,key); - if (key == 0x44) { - *state = REMOTE_NO_KEY_PRESSED; - return 0; + if (key != 0x44) { + /* + * The 8 bit address isn't available, but since the remote uses + * address 0 we'll use that. nec repeats are ignored too, even + * though the remote sends them. + */ + rc_keydown(d->rc_dev, RC_PROTO_NEC, RC_SCANCODE_NEC(0, key), 0); } - for (i = 0; i < ARRAY_SIZE(rc_map_vp7045_table); i++) - if (rc5_data(&rc_map_vp7045_table[i]) == key) { - *state = REMOTE_KEY_PRESSED; - *event = rc_map_vp7045_table[i].keycode; - break; - } return 0; } @@ -265,11 +205,13 @@ static struct dvb_usb_device_properties vp7045_properties = { .power_ctrl = vp7045_power_ctrl, .read_mac_address = vp7045_read_mac_addr, - .rc.legacy = { - .rc_interval = 400, - .rc_map_table = rc_map_vp7045_table, - .rc_map_size = ARRAY_SIZE(rc_map_vp7045_table), - .rc_query = vp7045_rc_query, + .rc.core = { + .rc_interval = 400, + .rc_codes = RC_MAP_TWINHAN_VP1027_DVBS, + .module_name = KBUILD_MODNAME, + .rc_query = vp7045_rc_query, + .allowed_protos = RC_PROTO_BIT_NEC, + .scancode_mask = 0xff, }, .num_device_descs = 2, -- cgit v1.2.3 From c25895c7d6c957124ceb3b090b7eaa68b1d3bf54 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 5 Sep 2017 09:07:50 -0300 Subject: [media] media: imon: make two const arrays static, reduces object code size Don't populate the const arrays vfd_packet6 and fp_packet on the stack, instead make them static. Makes the object code smaller by over 600 bytes: Before: text data bss dec hex filename 43794 17920 1024 62738 f512 drivers/media/rc/imon.o After: text data bss dec hex filename 42994 18080 1024 62098 f292 drivers/media/rc/imon.o Signed-off-by: Colin Ian King Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 188cf1b4ebb1..b83ad6d483aa 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -943,7 +943,7 @@ static ssize_t vfd_write(struct file *file, const char __user *buf, int seq; int retval = 0; struct imon_context *ictx; - const unsigned char vfd_packet6[] = { + static const unsigned char vfd_packet6[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF }; ictx = file->private_data; @@ -2047,8 +2047,8 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) { struct rc_dev *rdev; int ret; - const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x88 }; + static const unsigned char fp_packet[] = { + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88 }; rdev = rc_allocate_device(ictx->dev_descr->flags & IMON_IR_RAW ? RC_DRIVER_IR_RAW : RC_DRIVER_SCANCODE); -- cgit v1.2.3 From 94d40b2ff2fb2cb1763d7afb96360a0eb95f1493 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Thu, 7 Sep 2017 20:34:35 -0300 Subject: [media] media: rc: gpio-ir-recv: use helper variable to access device info Using explicit struct device variable makes code a bit more readable. Signed-off-by: Ladislav Michl Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/gpio-ir-recv.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 7248b3662285..741a68c192ce 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -95,18 +95,18 @@ err_get_value: static int gpio_ir_recv_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct gpio_rc_dev *gpio_dev; struct rc_dev *rcdev; - const struct gpio_ir_recv_platform_data *pdata = - pdev->dev.platform_data; + const struct gpio_ir_recv_platform_data *pdata = dev->platform_data; int rc; if (pdev->dev.of_node) { struct gpio_ir_recv_platform_data *dtpdata = - devm_kzalloc(&pdev->dev, sizeof(*dtpdata), GFP_KERNEL); + devm_kzalloc(dev, sizeof(*dtpdata), GFP_KERNEL); if (!dtpdata) return -ENOMEM; - rc = gpio_ir_recv_get_devtree_pdata(&pdev->dev, dtpdata); + rc = gpio_ir_recv_get_devtree_pdata(dev, dtpdata); if (rc) return rc; pdata = dtpdata; @@ -135,7 +135,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) rcdev->input_id.vendor = 0x0001; rcdev->input_id.product = 0x0001; rcdev->input_id.version = 0x0100; - rcdev->dev.parent = &pdev->dev; + rcdev->dev.parent = dev; rcdev->driver_name = GPIO_IR_DRIVER_NAME; rcdev->min_timeout = 1; rcdev->timeout = IR_DEFAULT_TIMEOUT; @@ -159,7 +159,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) rc = rc_register_device(rcdev); if (rc < 0) { - dev_err(&pdev->dev, "failed to register rc device\n"); + dev_err(dev, "failed to register rc device (%d)\n", rc); goto err_register_rc_device; } -- cgit v1.2.3 From 08d94274b8d0c25551b29a069334d8e627333a82 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Thu, 7 Sep 2017 20:35:22 -0300 Subject: [media] media: rc: gpio-ir-recv: use devm_kzalloc Use of devm_kzalloc simplifies error unwinding. Signed-off-by: Ladislav Michl Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/gpio-ir-recv.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 741a68c192ce..6fe7e7c14fe4 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -118,15 +118,13 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) if (pdata->gpio_nr < 0) return -EINVAL; - gpio_dev = kzalloc(sizeof(struct gpio_rc_dev), GFP_KERNEL); + gpio_dev = devm_kzalloc(dev, sizeof(*gpio_dev), GFP_KERNEL); if (!gpio_dev) return -ENOMEM; rcdev = rc_allocate_device(RC_DRIVER_IR_RAW); - if (!rcdev) { - rc = -ENOMEM; - goto err_allocate_device; - } + if (!rcdev) + return -ENOMEM; rcdev->priv = gpio_dev; rcdev->device_name = GPIO_IR_DEVICE_NAME; @@ -182,8 +180,6 @@ err_gpio_direction_input: gpio_free(pdata->gpio_nr); err_gpio_request: rc_free_device(rcdev); -err_allocate_device: - kfree(gpio_dev); return rc; } @@ -194,7 +190,6 @@ static int gpio_ir_recv_remove(struct platform_device *pdev) free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev); rc_unregister_device(gpio_dev->rcdev); gpio_free(gpio_dev->gpio_nr); - kfree(gpio_dev); return 0; } -- cgit v1.2.3 From f4940b563feff6f2514fc8c5309b844b0540a4cb Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Thu, 7 Sep 2017 20:36:11 -0300 Subject: [media] media: rc: gpio-ir-recv: use devm_rc_allocate_device Use of devm_rc_allocate_device simplifies error unwinding. Signed-off-by: Ladislav Michl Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/gpio-ir-recv.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 6fe7e7c14fe4..98dcb8399506 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -122,7 +122,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) if (!gpio_dev) return -ENOMEM; - rcdev = rc_allocate_device(RC_DRIVER_IR_RAW); + rcdev = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW); if (!rcdev) return -ENOMEM; @@ -150,7 +150,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv"); if (rc < 0) - goto err_gpio_request; + return rc; rc = gpio_direction_input(pdata->gpio_nr); if (rc < 0) goto err_gpio_direction_input; @@ -178,8 +178,6 @@ err_request_irq: err_register_rc_device: err_gpio_direction_input: gpio_free(pdata->gpio_nr); -err_gpio_request: - rc_free_device(rcdev); return rc; } -- cgit v1.2.3 From fcca09edb9f6e406de6014e3f1c2695b15b52abb Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Thu, 7 Sep 2017 20:36:39 -0300 Subject: [media] media: rc: gpio-ir-recv: use devm_gpio_request_one Use of devm_gpio_request_one simplifies error unwinding. Signed-off-by: Ladislav Michl Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/gpio-ir-recv.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 98dcb8399506..77044d664371 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -148,12 +148,10 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) gpio_dev->gpio_nr = pdata->gpio_nr; gpio_dev->active_low = pdata->active_low; - rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv"); + rc = devm_gpio_request_one(dev, pdata->gpio_nr, GPIOF_DIR_IN, + "gpio-ir-recv"); if (rc < 0) return rc; - rc = gpio_direction_input(pdata->gpio_nr); - if (rc < 0) - goto err_gpio_direction_input; rc = rc_register_device(rcdev); if (rc < 0) { @@ -176,8 +174,6 @@ err_request_irq: rc_unregister_device(rcdev); rcdev = NULL; err_register_rc_device: -err_gpio_direction_input: - gpio_free(pdata->gpio_nr); return rc; } @@ -187,7 +183,6 @@ static int gpio_ir_recv_remove(struct platform_device *pdev) free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev); rc_unregister_device(gpio_dev->rcdev); - gpio_free(gpio_dev->gpio_nr); return 0; } -- cgit v1.2.3 From 52ea79910720c56420f58771b9790e257764e006 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Thu, 7 Sep 2017 20:37:07 -0300 Subject: [media] media: rc: gpio-ir-recv: use devm_rc_register_device Use of devm_rc_register_device simplifies error unwinding. Signed-off-by: Ladislav Michl Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/gpio-ir-recv.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 77044d664371..ae5f9099c8a6 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -153,10 +153,10 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) if (rc < 0) return rc; - rc = rc_register_device(rcdev); + rc = devm_rc_register_device(dev, rcdev); if (rc < 0) { dev_err(dev, "failed to register rc device (%d)\n", rc); - goto err_register_rc_device; + return rc; } platform_set_drvdata(pdev, gpio_dev); @@ -171,9 +171,6 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) return 0; err_request_irq: - rc_unregister_device(rcdev); - rcdev = NULL; -err_register_rc_device: return rc; } @@ -182,7 +179,6 @@ static int gpio_ir_recv_remove(struct platform_device *pdev) struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev); free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev); - rc_unregister_device(gpio_dev->rcdev); return 0; } -- cgit v1.2.3 From 375929f9f48356e862789c72ddc1175d89866f44 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Thu, 7 Sep 2017 20:37:36 -0300 Subject: [media] media: rc: gpio-ir-recv: do not allow threaded interrupt handler Requesting any context irq is not actually great idea since threaded interrupt handler is run at too unpredictable time which turns timing information wrong. Fix it by requesting regular interrupt. Signed-off-by: Ladislav Michl Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/gpio-ir-recv.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index ae5f9099c8a6..d82ddf906695 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -161,10 +161,9 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) platform_set_drvdata(pdev, gpio_dev); - rc = request_any_context_irq(gpio_to_irq(pdata->gpio_nr), - gpio_ir_recv_irq, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - "gpio-ir-recv-irq", gpio_dev); + rc = request_irq(gpio_to_irq(pdata->gpio_nr), gpio_ir_recv_irq, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + "gpio-ir-recv-irq", gpio_dev); if (rc < 0) goto err_request_irq; -- cgit v1.2.3 From 1a2a60b1af1293e8ee7780691ef90a8aa68991c1 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Thu, 7 Sep 2017 20:38:20 -0300 Subject: [media] media: rc: gpio-ir-recv: use devm_request_irq Use of devm_request_irq simplifies error unwinding and as free_irq was the last user of driver remove function, remove it too. Signed-off-by: Ladislav Michl Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/gpio-ir-recv.c | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index d82ddf906695..fe0dd2443af0 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -161,24 +161,10 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) platform_set_drvdata(pdev, gpio_dev); - rc = request_irq(gpio_to_irq(pdata->gpio_nr), gpio_ir_recv_irq, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, - "gpio-ir-recv-irq", gpio_dev); - if (rc < 0) - goto err_request_irq; - - return 0; - -err_request_irq: - return rc; -} - -static int gpio_ir_recv_remove(struct platform_device *pdev) -{ - struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev); - - free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev); - return 0; + return devm_request_irq(dev, gpio_to_irq(pdata->gpio_nr), + gpio_ir_recv_irq, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + "gpio-ir-recv-irq", gpio_dev); } #ifdef CONFIG_PM @@ -216,7 +202,6 @@ static const struct dev_pm_ops gpio_ir_recv_pm_ops = { static struct platform_driver gpio_ir_recv_driver = { .probe = gpio_ir_recv_probe, - .remove = gpio_ir_recv_remove, .driver = { .name = GPIO_IR_DRIVER_NAME, .of_match_table = of_match_ptr(gpio_ir_recv_of_match), -- cgit v1.2.3 From 916d1c9fd457a11e1f1fed70f123f461da72a56d Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Thu, 7 Sep 2017 20:39:14 -0300 Subject: [media] media: rc: gpio-ir-recv: use KBUILD_MODNAME There already is standard macro providing driver name, use it. Signed-off-by: Ladislav Michl Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/gpio-ir-recv.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index fe0dd2443af0..b78195f06354 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -23,7 +23,6 @@ #include #include -#define GPIO_IR_DRIVER_NAME "gpio-rc-recv" #define GPIO_IR_DEVICE_NAME "gpio_ir_recv" struct gpio_rc_dev { @@ -134,7 +133,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) rcdev->input_id.product = 0x0001; rcdev->input_id.version = 0x0100; rcdev->dev.parent = dev; - rcdev->driver_name = GPIO_IR_DRIVER_NAME; + rcdev->driver_name = KBUILD_MODNAME; rcdev->min_timeout = 1; rcdev->timeout = IR_DEFAULT_TIMEOUT; rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT; @@ -203,7 +202,7 @@ static const struct dev_pm_ops gpio_ir_recv_pm_ops = { static struct platform_driver gpio_ir_recv_driver = { .probe = gpio_ir_recv_probe, .driver = { - .name = GPIO_IR_DRIVER_NAME, + .name = KBUILD_MODNAME, .of_match_table = of_match_ptr(gpio_ir_recv_of_match), #ifdef CONFIG_PM .pm = &gpio_ir_recv_pm_ops, -- cgit v1.2.3 From 5c95878f618cf4f3eb0a4c7ff54a09ca6d4d0426 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Thu, 7 Sep 2017 20:39:45 -0300 Subject: [media] media: rc: gpio-ir-recv: remove gpio_ir_recv_platform_data gpio_ir_recv_platform_data are not used anywhere in kernel tree, so remove it. Signed-off-by: Ladislav Michl Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/gpio-ir-recv.c | 92 +++++++----------------- include/linux/platform_data/media/gpio-ir-recv.h | 23 ------ 2 files changed, 26 insertions(+), 89 deletions(-) delete mode 100644 include/linux/platform_data/media/gpio-ir-recv.h diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index b78195f06354..2634b81cbe7e 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -21,7 +21,6 @@ #include #include #include -#include #define GPIO_IR_DEVICE_NAME "gpio_ir_recv" @@ -31,45 +30,6 @@ struct gpio_rc_dev { bool active_low; }; -#ifdef CONFIG_OF -/* - * Translate OpenFirmware node properties into platform_data - */ -static int gpio_ir_recv_get_devtree_pdata(struct device *dev, - struct gpio_ir_recv_platform_data *pdata) -{ - struct device_node *np = dev->of_node; - enum of_gpio_flags flags; - int gpio; - - gpio = of_get_gpio_flags(np, 0, &flags); - if (gpio < 0) { - if (gpio != -EPROBE_DEFER) - dev_err(dev, "Failed to get gpio flags (%d)\n", gpio); - return gpio; - } - - pdata->gpio_nr = gpio; - pdata->active_low = (flags & OF_GPIO_ACTIVE_LOW); - /* probe() takes care of map_name == NULL or allowed_protos == 0 */ - pdata->map_name = of_get_property(np, "linux,rc-map-name", NULL); - pdata->allowed_protos = 0; - - return 0; -} - -static const struct of_device_id gpio_ir_recv_of_match[] = { - { .compatible = "gpio-ir-receiver", }, - { }, -}; -MODULE_DEVICE_TABLE(of, gpio_ir_recv_of_match); - -#else /* !CONFIG_OF */ - -#define gpio_ir_recv_get_devtree_pdata(dev, pdata) (-ENOSYS) - -#endif - static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id) { struct gpio_rc_dev *gpio_dev = dev_id; @@ -95,32 +55,29 @@ err_get_value: static int gpio_ir_recv_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; struct gpio_rc_dev *gpio_dev; + enum of_gpio_flags flags; struct rc_dev *rcdev; - const struct gpio_ir_recv_platform_data *pdata = dev->platform_data; int rc; - if (pdev->dev.of_node) { - struct gpio_ir_recv_platform_data *dtpdata = - devm_kzalloc(dev, sizeof(*dtpdata), GFP_KERNEL); - if (!dtpdata) - return -ENOMEM; - rc = gpio_ir_recv_get_devtree_pdata(dev, dtpdata); - if (rc) - return rc; - pdata = dtpdata; - } - - if (!pdata) - return -EINVAL; - - if (pdata->gpio_nr < 0) - return -EINVAL; + if (!np) + return -ENODEV; gpio_dev = devm_kzalloc(dev, sizeof(*gpio_dev), GFP_KERNEL); if (!gpio_dev) return -ENOMEM; + rc = of_get_gpio_flags(np, 0, &flags); + if (rc < 0) { + if (rc != -EPROBE_DEFER) + dev_err(dev, "Failed to get gpio flags (%d)\n", rc); + return rc; + } + + gpio_dev->gpio_nr = rc; + gpio_dev->active_low = (flags & OF_GPIO_ACTIVE_LOW); + rcdev = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW); if (!rcdev) return -ENOMEM; @@ -137,17 +94,14 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) rcdev->min_timeout = 1; rcdev->timeout = IR_DEFAULT_TIMEOUT; rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT; - if (pdata->allowed_protos) - rcdev->allowed_protocols = pdata->allowed_protos; - else - rcdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; - rcdev->map_name = pdata->map_name ?: RC_MAP_EMPTY; + rcdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; + rcdev->map_name = of_get_property(np, "linux,rc-map-name", NULL); + if (!rcdev->map_name) + rcdev->map_name = RC_MAP_EMPTY; gpio_dev->rcdev = rcdev; - gpio_dev->gpio_nr = pdata->gpio_nr; - gpio_dev->active_low = pdata->active_low; - rc = devm_gpio_request_one(dev, pdata->gpio_nr, GPIOF_DIR_IN, + rc = devm_gpio_request_one(dev, gpio_dev->gpio_nr, GPIOF_DIR_IN, "gpio-ir-recv"); if (rc < 0) return rc; @@ -160,7 +114,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) platform_set_drvdata(pdev, gpio_dev); - return devm_request_irq(dev, gpio_to_irq(pdata->gpio_nr), + return devm_request_irq(dev, gpio_to_irq(gpio_dev->gpio_nr), gpio_ir_recv_irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "gpio-ir-recv-irq", gpio_dev); @@ -199,6 +153,12 @@ static const struct dev_pm_ops gpio_ir_recv_pm_ops = { }; #endif +static const struct of_device_id gpio_ir_recv_of_match[] = { + { .compatible = "gpio-ir-receiver", }, + { }, +}; +MODULE_DEVICE_TABLE(of, gpio_ir_recv_of_match); + static struct platform_driver gpio_ir_recv_driver = { .probe = gpio_ir_recv_probe, .driver = { diff --git a/include/linux/platform_data/media/gpio-ir-recv.h b/include/linux/platform_data/media/gpio-ir-recv.h deleted file mode 100644 index 0c298f569d5a..000000000000 --- a/include/linux/platform_data/media/gpio-ir-recv.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (c) 2012, Code Aurora Forum. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef __GPIO_IR_RECV_H__ -#define __GPIO_IR_RECV_H__ - -struct gpio_ir_recv_platform_data { - int gpio_nr; - bool active_low; - u64 allowed_protos; - const char *map_name; -}; - -#endif /* __GPIO_IR_RECV_H__ */ -- cgit v1.2.3 From eed008e605d13ee4fb64668350be58999e85aac7 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Thu, 7 Sep 2017 20:41:32 -0300 Subject: [media] media: rc: gpio-ir-recv: use gpiolib API Gpiolib API is preferred way to access gpios. Signed-off-by: Ladislav Michl Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/gpio-ir-recv.c | 59 +++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 38 deletions(-) diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 2634b81cbe7e..24641a9079da 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -26,29 +26,19 @@ struct gpio_rc_dev { struct rc_dev *rcdev; - int gpio_nr; - bool active_low; + struct gpio_desc *gpiod; + int irq; }; static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id) { + int val; struct gpio_rc_dev *gpio_dev = dev_id; - int gval; - int rc = 0; - gval = gpio_get_value(gpio_dev->gpio_nr); + val = gpiod_get_value(gpio_dev->gpiod); + if (val >= 0) + ir_raw_event_store_edge(gpio_dev->rcdev, val == 1); - if (gval < 0) - goto err_get_value; - - if (gpio_dev->active_low) - gval = !gval; - - rc = ir_raw_event_store_edge(gpio_dev->rcdev, gval == 1); - if (rc < 0) - goto err_get_value; - -err_get_value: return IRQ_HANDLED; } @@ -57,7 +47,6 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; struct gpio_rc_dev *gpio_dev; - enum of_gpio_flags flags; struct rc_dev *rcdev; int rc; @@ -68,15 +57,17 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) if (!gpio_dev) return -ENOMEM; - rc = of_get_gpio_flags(np, 0, &flags); - if (rc < 0) { + gpio_dev->gpiod = devm_gpiod_get(dev, NULL, GPIOD_IN); + if (IS_ERR(gpio_dev->gpiod)) { + rc = PTR_ERR(gpio_dev->gpiod); + /* Just try again if this happens */ if (rc != -EPROBE_DEFER) - dev_err(dev, "Failed to get gpio flags (%d)\n", rc); + dev_err(dev, "error getting gpio (%d)\n", rc); return rc; } - - gpio_dev->gpio_nr = rc; - gpio_dev->active_low = (flags & OF_GPIO_ACTIVE_LOW); + gpio_dev->irq = gpiod_to_irq(gpio_dev->gpiod); + if (gpio_dev->irq < 0) + return gpio_dev->irq; rcdev = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW); if (!rcdev) @@ -101,11 +92,6 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) gpio_dev->rcdev = rcdev; - rc = devm_gpio_request_one(dev, gpio_dev->gpio_nr, GPIOF_DIR_IN, - "gpio-ir-recv"); - if (rc < 0) - return rc; - rc = devm_rc_register_device(dev, rcdev); if (rc < 0) { dev_err(dev, "failed to register rc device (%d)\n", rc); @@ -114,8 +100,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) platform_set_drvdata(pdev, gpio_dev); - return devm_request_irq(dev, gpio_to_irq(gpio_dev->gpio_nr), - gpio_ir_recv_irq, + return devm_request_irq(dev, gpio_dev->irq, gpio_ir_recv_irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "gpio-ir-recv-irq", gpio_dev); } @@ -123,26 +108,24 @@ static int gpio_ir_recv_probe(struct platform_device *pdev) #ifdef CONFIG_PM static int gpio_ir_recv_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev); + struct gpio_rc_dev *gpio_dev = dev_get_drvdata(dev); if (device_may_wakeup(dev)) - enable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr)); + enable_irq_wake(gpio_dev->irq); else - disable_irq(gpio_to_irq(gpio_dev->gpio_nr)); + disable_irq(gpio_dev->irq); return 0; } static int gpio_ir_recv_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev); + struct gpio_rc_dev *gpio_dev = dev_get_drvdata(dev); if (device_may_wakeup(dev)) - disable_irq_wake(gpio_to_irq(gpio_dev->gpio_nr)); + disable_irq_wake(gpio_dev->irq); else - enable_irq(gpio_to_irq(gpio_dev->gpio_nr)); + enable_irq(gpio_dev->irq); return 0; } -- cgit v1.2.3 From 8ca01d4f9588bd58722a388400896c11e4343047 Mon Sep 17 00:00:00 2001 From: Thomas Meyer Date: Fri, 8 Sep 2017 13:33:36 -0300 Subject: [media] media: rc: Use bsearch library function Replace self coded binary search, by existing library version. Signed-off-by: Thomas Meyer Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 8c828fee4f5a..e0901a2a1ec9 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -15,6 +15,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include +#include #include #include #include @@ -460,6 +461,18 @@ static int ir_setkeytable(struct rc_dev *dev, return rc; } +static int rc_map_cmp(const void *key, const void *elt) +{ + const unsigned int *scancode = key; + const struct rc_map_table *e = elt; + + if (*scancode < e->scancode) + return -1; + else if (*scancode > e->scancode) + return 1; + return 0; +} + /** * ir_lookup_by_scancode() - locate mapping by scancode * @rc_map: the struct rc_map to search @@ -472,21 +485,14 @@ static int ir_setkeytable(struct rc_dev *dev, static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map, unsigned int scancode) { - int start = 0; - int end = rc_map->len - 1; - int mid; - - while (start <= end) { - mid = (start + end) / 2; - if (rc_map->scan[mid].scancode < scancode) - start = mid + 1; - else if (rc_map->scan[mid].scancode > scancode) - end = mid - 1; - else - return mid; - } + struct rc_map_table *res; - return -1U; + res = bsearch(&scancode, rc_map->scan, rc_map->len, + sizeof(struct rc_map_table), rc_map_cmp); + if (!res) + return -1U; + else + return res - rc_map->scan; } /** -- cgit v1.2.3 From 5573d124292a01afaecb7612773c21321ffcd6d2 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 8 Sep 2017 13:39:29 -0300 Subject: [media] media: default for RC_CORE should be n The Linus policy on Kconfig is that the default should be no for all new devices. I.e the user rebuild a new kernel from an old config should not by default get a larger kernel. Fixes: b4c184e506a4 ("[media] media: reorganize the main Kconfig items") Signed-off-by: Stephen Hemminger Acked-by: Geert Uytterhoeven Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index d9ce8ff55d0c..467cf2bdbd42 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -2,7 +2,6 @@ menuconfig RC_CORE tristate "Remote Controller support" depends on INPUT - default y ---help--- Enable support for Remote Controllers on Linux. This is needed in order to support several video capture adapters, -- cgit v1.2.3 From d7a6795b1d7cce8c6dcfd67d3348ba68ade9d397 Mon Sep 17 00:00:00 2001 From: Marc Gonzalez Date: Mon, 18 Sep 2017 11:31:41 -0300 Subject: [media] media: rc: Delete duplicate debug message ir_setkeytable() and ir_create_table() print the same debug message. Delete the one in ir_setkeytable() Signed-off-by: Marc Gonzalez Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index e0901a2a1ec9..cb78e5702bef 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -440,9 +440,6 @@ static int ir_setkeytable(struct rc_dev *dev, if (rc) return rc; - IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n", - rc_map->size, rc_map->alloc); - for (i = 0; i < from->size; i++) { index = ir_establish_scancode(dev, rc_map, from->scan[i].scancode, false); -- cgit v1.2.3 From a8c779eb056e9874c6278151ade857c3ac227db9 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 29 Aug 2017 07:45:59 -0300 Subject: [media] imon: Improve a size determination in two functions Replace the specification of data structures by pointer dereferences as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index b83ad6d483aa..9724fe8110e3 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -602,8 +602,7 @@ static int send_packet(struct imon_context *ictx) ictx->tx_urb->actual_length = 0; } else { /* fill request into kmalloc'ed space: */ - control_req = kmalloc(sizeof(struct usb_ctrlrequest), - GFP_KERNEL); + control_req = kmalloc(sizeof(*control_req), GFP_KERNEL); if (control_req == NULL) return -ENOMEM; @@ -2310,7 +2309,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf, struct usb_host_interface *iface_desc; int ret = -ENOMEM; - ictx = kzalloc(sizeof(struct imon_context), GFP_KERNEL); + ictx = kzalloc(sizeof(*ictx), GFP_KERNEL); if (!ictx) goto exit; -- cgit v1.2.3 From 15a35ca66aaff3386f174cfd3daa4713976e6edc Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 11 Sep 2017 13:53:07 -0300 Subject: [media] media: v4l2-pci-skeleton: Fix error handling path in 'skeleton_probe()' If this memory allocation fails, we must release some resources, as already done in the code below and above. Signed-off-by: Christophe JAILLET Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- samples/v4l/v4l2-pci-skeleton.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/samples/v4l/v4l2-pci-skeleton.c b/samples/v4l/v4l2-pci-skeleton.c index 483e9bca9444..f520e3aef9c6 100644 --- a/samples/v4l/v4l2-pci-skeleton.c +++ b/samples/v4l/v4l2-pci-skeleton.c @@ -772,8 +772,10 @@ static int skeleton_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* Allocate a new instance */ skel = devm_kzalloc(&pdev->dev, sizeof(struct skeleton), GFP_KERNEL); - if (!skel) - return -ENOMEM; + if (!skel) { + ret = -ENOMEM; + goto disable_pci; + } /* Allocate the interrupt */ ret = devm_request_irq(&pdev->dev, pdev->irq, -- cgit v1.2.3 From bc66c99a7e65d3964b4c5d10f574d462f40ae48e Mon Sep 17 00:00:00 2001 From: Simon Yuan Date: Mon, 11 Sep 2017 19:26:53 -0300 Subject: [media] media: i2c: adv748x: Map v4l2_std_id to the internal reg value The video standard was not mapped to the corresponding value of the internal video standard in adv748x_afe_querystd, causing the wrong video standard to be selected. Fixes: 3e89586a64df ("media: i2c: adv748x: add adv748x driver") [Kieran: Obtain the std from the afe->curr_norm] Signed-off-by: Simon Yuan Signed-off-by: Kieran Bingham Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv748x/adv748x-afe.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/adv748x/adv748x-afe.c b/drivers/media/i2c/adv748x/adv748x-afe.c index b33ccfc08708..4aa8e45b5cd3 100644 --- a/drivers/media/i2c/adv748x/adv748x-afe.c +++ b/drivers/media/i2c/adv748x/adv748x-afe.c @@ -217,6 +217,7 @@ static int adv748x_afe_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) { struct adv748x_afe *afe = adv748x_sd_to_afe(sd); struct adv748x_state *state = adv748x_afe_to_state(afe); + int afe_std; int ret; mutex_lock(&state->mutex); @@ -235,8 +236,12 @@ static int adv748x_afe_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) /* Read detected standard */ ret = adv748x_afe_status(afe, NULL, std); + afe_std = adv748x_afe_std(afe->curr_norm); + if (afe_std < 0) + goto unlock; + /* Restore original state */ - adv748x_afe_set_video_standard(state, afe->curr_norm); + adv748x_afe_set_video_standard(state, afe_std); unlock: mutex_unlock(&state->mutex); -- cgit v1.2.3 From 022565200a4f27ffcf9315b2194ca9454059d6b1 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 12 Sep 2017 08:08:13 -0300 Subject: [media] gspca: make arrays static, reduces object code size Don't populate const arrays on the stack, instead make them static. Makes the object code smaller by over 5200 bytes: Before: text data bss dec hex filename 58259 8880 128 67267 106c3 ov519.o After: text data bss dec hex filename 52155 9776 128 62059 f26b ov519.o Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/ov519.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/media/usb/gspca/ov519.c b/drivers/media/usb/gspca/ov519.c index cdb79c5f0c38..f1537daf4e2e 100644 --- a/drivers/media/usb/gspca/ov519.c +++ b/drivers/media/usb/gspca/ov519.c @@ -2865,7 +2865,7 @@ static void sd_reset_snapshot(struct gspca_dev *gspca_dev) static void ov51x_upload_quan_tables(struct sd *sd) { - const unsigned char yQuanTable511[] = { + static const unsigned char yQuanTable511[] = { 0, 1, 1, 2, 2, 3, 3, 4, 1, 1, 1, 2, 2, 3, 4, 4, 1, 1, 2, 2, 3, 4, 4, 4, @@ -2876,7 +2876,7 @@ static void ov51x_upload_quan_tables(struct sd *sd) 4, 4, 4, 4, 5, 5, 5, 5 }; - const unsigned char uvQuanTable511[] = { + static const unsigned char uvQuanTable511[] = { 0, 2, 2, 3, 4, 4, 4, 4, 2, 2, 2, 4, 4, 4, 4, 4, 2, 2, 3, 4, 4, 4, 4, 4, @@ -2888,13 +2888,13 @@ static void ov51x_upload_quan_tables(struct sd *sd) }; /* OV518 quantization tables are 8x4 (instead of 8x8) */ - const unsigned char yQuanTable518[] = { + static const unsigned char yQuanTable518[] = { 5, 4, 5, 6, 6, 7, 7, 7, 5, 5, 5, 5, 6, 7, 7, 7, 6, 6, 6, 6, 7, 7, 7, 8, 7, 7, 6, 7, 7, 7, 8, 8 }; - const unsigned char uvQuanTable518[] = { + static const unsigned char uvQuanTable518[] = { 6, 6, 6, 7, 7, 7, 7, 7, 6, 6, 6, 7, 7, 7, 7, 7, 6, 6, 6, 7, 7, 7, 7, 8, @@ -2943,7 +2943,7 @@ static void ov511_configure(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; /* For 511 and 511+ */ - const struct ov_regvals init_511[] = { + static const struct ov_regvals init_511[] = { { R51x_SYS_RESET, 0x7f }, { R51x_SYS_INIT, 0x01 }, { R51x_SYS_RESET, 0x7f }, @@ -2953,7 +2953,7 @@ static void ov511_configure(struct gspca_dev *gspca_dev) { R51x_SYS_RESET, 0x3d }, }; - const struct ov_regvals norm_511[] = { + static const struct ov_regvals norm_511[] = { { R511_DRAM_FLOW_CTL, 0x01 }, { R51x_SYS_SNAP, 0x00 }, { R51x_SYS_SNAP, 0x02 }, @@ -2963,7 +2963,7 @@ static void ov511_configure(struct gspca_dev *gspca_dev) { R511_COMP_LUT_EN, 0x03 }, }; - const struct ov_regvals norm_511_p[] = { + static const struct ov_regvals norm_511_p[] = { { R511_DRAM_FLOW_CTL, 0xff }, { R51x_SYS_SNAP, 0x00 }, { R51x_SYS_SNAP, 0x02 }, @@ -2973,7 +2973,7 @@ static void ov511_configure(struct gspca_dev *gspca_dev) { R511_COMP_LUT_EN, 0x03 }, }; - const struct ov_regvals compress_511[] = { + static const struct ov_regvals compress_511[] = { { 0x70, 0x1f }, { 0x71, 0x05 }, { 0x72, 0x06 }, @@ -3009,7 +3009,7 @@ static void ov518_configure(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; /* For 518 and 518+ */ - const struct ov_regvals init_518[] = { + static const struct ov_regvals init_518[] = { { R51x_SYS_RESET, 0x40 }, { R51x_SYS_INIT, 0xe1 }, { R51x_SYS_RESET, 0x3e }, @@ -3020,7 +3020,7 @@ static void ov518_configure(struct gspca_dev *gspca_dev) { 0x5d, 0x03 }, }; - const struct ov_regvals norm_518[] = { + static const struct ov_regvals norm_518[] = { { R51x_SYS_SNAP, 0x02 }, /* Reset */ { R51x_SYS_SNAP, 0x01 }, /* Enable */ { 0x31, 0x0f }, @@ -3033,7 +3033,7 @@ static void ov518_configure(struct gspca_dev *gspca_dev) { 0x2f, 0x80 }, }; - const struct ov_regvals norm_518_p[] = { + static const struct ov_regvals norm_518_p[] = { { R51x_SYS_SNAP, 0x02 }, /* Reset */ { R51x_SYS_SNAP, 0x01 }, /* Enable */ { 0x31, 0x0f }, -- cgit v1.2.3 From ad62701720dd5d2a17c62f6c3bbd6ee629efcfaa Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Wed, 13 Sep 2017 16:37:50 -0300 Subject: [media] saa7146: make saa7146_use_ops const Make these const as they are not modified in the file referencing them. They are only used when their function pointer fields invokes a function and therefore none of the structure fields are getting modified. Also, add a const to the declaration in the header. Signed-off-by: Bhumika Goyal Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146/saa7146_vbi.c | 2 +- drivers/media/common/saa7146/saa7146_video.c | 2 +- include/media/drv-intf/saa7146_vv.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/common/saa7146/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c index d79e4d7ecd9f..69525ca4f52c 100644 --- a/drivers/media/common/saa7146/saa7146_vbi.c +++ b/drivers/media/common/saa7146/saa7146_vbi.c @@ -488,7 +488,7 @@ static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff return ret; } -struct saa7146_use_ops saa7146_vbi_uops = { +const struct saa7146_use_ops saa7146_vbi_uops = { .init = vbi_init, .open = vbi_open, .release = vbi_close, diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index 37b4654dc21c..51eeed830de4 100644 --- a/drivers/media/common/saa7146/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c @@ -1303,7 +1303,7 @@ out: return ret; } -struct saa7146_use_ops saa7146_video_uops = { +const struct saa7146_use_ops saa7146_video_uops = { .init = video_init, .open = video_open, .release = video_close, diff --git a/include/media/drv-intf/saa7146_vv.h b/include/media/drv-intf/saa7146_vv.h index 0da6ccc0615b..736f4f2d8290 100644 --- a/include/media/drv-intf/saa7146_vv.h +++ b/include/media/drv-intf/saa7146_vv.h @@ -202,14 +202,14 @@ void saa7146_set_gpio(struct saa7146_dev *saa, u8 pin, u8 data); /* from saa7146_video.c */ extern const struct v4l2_ioctl_ops saa7146_video_ioctl_ops; extern const struct v4l2_ioctl_ops saa7146_vbi_ioctl_ops; -extern struct saa7146_use_ops saa7146_video_uops; +extern const struct saa7146_use_ops saa7146_video_uops; int saa7146_start_preview(struct saa7146_fh *fh); int saa7146_stop_preview(struct saa7146_fh *fh); long saa7146_video_do_ioctl(struct file *file, unsigned int cmd, void *arg); int saa7146_s_ctrl(struct v4l2_ctrl *ctrl); /* from saa7146_vbi.c */ -extern struct saa7146_use_ops saa7146_vbi_uops; +extern const struct saa7146_use_ops saa7146_vbi_uops; /* resource management functions */ int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit); -- cgit v1.2.3 From 5dfbf6c51c72ede22975db1e2259c00ee0bfb7ff Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 14 Sep 2017 08:07:27 -0300 Subject: [media] rcar_drif: fix potential uninitialized variable use Older compilers like gcc-4.6 may run into a case that returns an uninitialized variable from rcar_drif_enable_rx() if that function was ever called with an empty cur_ch_mask: drivers/media/platform/rcar_drif.c:658:2: error: ‘ret’ may be used uninitialized in this function [-Werror=uninitialized] Newer compilers don't have that problem as they optimize the 'ret' variable away and just return zero in that case. This changes the function to return -EINVAL for this particular failure, to make it consistent across all compiler versions. In case gcc gets changed to report a warning for it in the future, it's also a good idea to shut it up now. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82203 Signed-off-by: Arnd Bergmann Acked-by: Ramesh Shanmugasundaram Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar_drif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c index 522364ff0d5d..2c6afd38b78a 100644 --- a/drivers/media/platform/rcar_drif.c +++ b/drivers/media/platform/rcar_drif.c @@ -630,7 +630,7 @@ static int rcar_drif_enable_rx(struct rcar_drif_sdr *sdr) { unsigned int i; u32 ctr; - int ret; + int ret = -EINVAL; /* * When both internal channels are enabled, they can be synchronized -- cgit v1.2.3 From b89fdb5e509a7ac56b69e0139e10683efba5d467 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Sep 2017 11:51:44 -0300 Subject: [media] v4l2-tpg: add Y10 and Y12 support Support the 10 and 12 bit luma formats. Signed-off-by: Hans Verkuil Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/v4l2-tpg/v4l2-tpg-core.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index a772976cfe26..f96968c11312 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -238,6 +238,8 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) tpg->color_enc = TGP_COLOR_ENC_RGB; break; case V4L2_PIX_FMT_GREY: + case V4L2_PIX_FMT_Y10: + case V4L2_PIX_FMT_Y12: case V4L2_PIX_FMT_Y16: case V4L2_PIX_FMT_Y16_BE: tpg->color_enc = TGP_COLOR_ENC_LUMA; @@ -352,6 +354,8 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_YUV444: case V4L2_PIX_FMT_YUV555: case V4L2_PIX_FMT_YUV565: + case V4L2_PIX_FMT_Y10: + case V4L2_PIX_FMT_Y12: case V4L2_PIX_FMT_Y16: case V4L2_PIX_FMT_Y16_BE: tpg->twopixelsize[0] = 2 * 2; @@ -1056,6 +1060,14 @@ static void gen_twopix(struct tpg_data *tpg, case V4L2_PIX_FMT_GREY: buf[0][offset] = r_y_h; break; + case V4L2_PIX_FMT_Y10: + buf[0][offset] = (r_y_h << 2) & 0xff; + buf[0][offset+1] = r_y_h >> 6; + break; + case V4L2_PIX_FMT_Y12: + buf[0][offset] = (r_y_h << 4) & 0xff; + buf[0][offset+1] = r_y_h >> 4; + break; case V4L2_PIX_FMT_Y16: /* * Ideally both bytes should be set to r_y_h, but then you won't -- cgit v1.2.3 From 02005cb27ca98792ac97728811e8dd30b3c1e798 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Sep 2017 11:51:45 -0300 Subject: [media] vivid: add support for Y10 and Y12 Add support for 10 and 12 bit luma formats. Signed-off-by: Hans Verkuil Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-common.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index f0f423c7ca41..a651527d80db 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -188,6 +188,22 @@ struct vivid_fmt vivid_formats[] = { .planes = 1, .buffers = 1, }, + { + .fourcc = V4L2_PIX_FMT_Y10, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .color_enc = TGP_COLOR_ENC_LUMA, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_Y12, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .color_enc = TGP_COLOR_ENC_LUMA, + .planes = 1, + .buffers = 1, + }, { .fourcc = V4L2_PIX_FMT_Y16, .vdownsampling = { 1 }, -- cgit v1.2.3 From d17dd2db943272b6d9d1315528cde9dad74fa6ed Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 20 Sep 2017 20:27:41 -0300 Subject: [media] media/i2c/tc358743: Initialize timer This converts to use setup_timer() to set callback and data, though it doesn't look like this would have worked with timer checking enabled since no init_timer() was ever called before. Cc: Mats Randgaard Cc: Mauro Carvalho Chehab Signed-off-by: Kees Cook Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358743.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index e1d8eef7055e..a9355032076f 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -2147,8 +2147,8 @@ static int tc358743_probe(struct i2c_client *client, } else { INIT_WORK(&state->work_i2c_poll, tc358743_work_i2c_poll); - state->timer.data = (unsigned long)state; - state->timer.function = tc358743_irq_poll_timer; + setup_timer(&state->timer, tc358743_irq_poll_timer, + (unsigned long)state); state->timer.expires = jiffies + msecs_to_jiffies(POLL_INTERVAL_MS); add_timer(&state->timer); -- cgit v1.2.3 From 6c3b047fa2d2286d5e438bcb470c7b1a49f415f6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 21 Sep 2017 05:40:18 -0300 Subject: [media] cx231xx-cards: fix NULL-deref on missing association descriptor Make sure to check that we actually have an Interface Association Descriptor before dereferencing it during probe to avoid dereferencing a NULL-pointer. Fixes: e0d3bafd0258 ("V4L/DVB (10954): Add cx231xx USB driver") Cc: stable # 2.6.30 Reported-by: Andrey Konovalov Signed-off-by: Johan Hovold Tested-by: Andrey Konovalov Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-cards.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index e0daa9b6c2a0..9b742d569fb5 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -1684,7 +1684,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface, nr = dev->devno; assoc_desc = udev->actconfig->intf_assoc[0]; - if (assoc_desc->bFirstInterface != ifnum) { + if (!assoc_desc || assoc_desc->bFirstInterface != ifnum) { dev_err(d, "Not found matching IAD interface\n"); retval = -ENODEV; goto err_if; -- cgit v1.2.3 From 5b2c8da1b040c4608c7cfdc0dd96bcaa190af268 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Sep 2017 05:02:57 -0300 Subject: [media] cec-gpio: don't generate spurious HPD events Only send HPD_LOW/HIGH event if the gpio actually changed value. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/cec-gpio/cec-gpio.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/cec-gpio/cec-gpio.c b/drivers/media/platform/cec-gpio/cec-gpio.c index eb982bce99fc..5debdf08fbe7 100644 --- a/drivers/media/platform/cec-gpio/cec-gpio.c +++ b/drivers/media/platform/cec-gpio/cec-gpio.c @@ -80,9 +80,12 @@ static irqreturn_t cec_hpd_gpio_irq_handler_thread(int irq, void *priv) static irqreturn_t cec_hpd_gpio_irq_handler(int irq, void *priv) { struct cec_gpio *cec = priv; + bool is_high = gpiod_get_value(cec->hpd_gpio); + if (is_high == cec->hpd_is_high) + return IRQ_HANDLED; cec->hpd_ts = ktime_get(); - cec->hpd_is_high = gpiod_get_value(cec->hpd_gpio); + cec->hpd_is_high = is_high; return IRQ_WAKE_THREAD; } -- cgit v1.2.3 From cecfe9b8a511ec0c9df456770abf547444c87de6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Sep 2017 06:41:02 -0300 Subject: [media] v4l2-ctrls.c: allow empty control handlers If you have a control handler that does not contain any controls, then currently calling VIDIOC_G/S/TRY_EXT_CTRLS with count == 0 will return -EINVAL in the class_check() function. This is not correct, there is no reason why this should return an error. The purpose of setting count to 0 is to test if the ioctl can mix controls from different control classes. And this is possible. The fact that there are not actually any controls defined is another matter that is unrelated to this test. This caused v4l2-compliance to fail, so that is fixed with this patch applied. Signed-off-by: Hans Verkuil Reported-by: Dave Stevenson Tested-by: Dave Stevenson Acked-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index dd1db678718c..4e53a8654690 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -2818,7 +2818,7 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl, static int class_check(struct v4l2_ctrl_handler *hdl, u32 which) { if (which == 0 || which == V4L2_CTRL_WHICH_DEF_VAL) - return list_empty(&hdl->ctrl_refs) ? -EINVAL : 0; + return 0; return find_ref_lock(hdl, which | 1) ? 0 : -EINVAL; } -- cgit v1.2.3 From 99cd12425dfe9a400b672f112512a3678dfd1eb6 Mon Sep 17 00:00:00 2001 From: Chiranjeevi Rapolu Date: Fri, 25 Aug 2017 01:20:55 -0300 Subject: [media] media: ov5670: Use recommended black level and output bias Previously, images were relatively darker due to non-optimal settings for black target level and bias. Now, use recommended settings for black target level and output bias as default values. The same default settings apply to all the resolutions. Given these recommeneded settings do not change dynamically, add these to existing mode register settings. Signed-off-by: Chiranjeevi Rapolu Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5670.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index 6f7a1d6d2200..759ca6229db9 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -390,7 +390,10 @@ static const struct ov5670_reg mode_2592x1944_regs[] = { {0x5792, 0x00}, {0x5793, 0x52}, {0x5794, 0xa3}, - {0x3503, 0x00} + {0x3503, 0x00}, + {0x5045, 0x05}, + {0x4003, 0x40}, + {0x5048, 0x40} }; static const struct ov5670_reg mode_1296x972_regs[] = { @@ -653,7 +656,10 @@ static const struct ov5670_reg mode_1296x972_regs[] = { {0x5792, 0x00}, {0x5793, 0x52}, {0x5794, 0xa3}, - {0x3503, 0x00} + {0x3503, 0x00}, + {0x5045, 0x05}, + {0x4003, 0x40}, + {0x5048, 0x40} }; static const struct ov5670_reg mode_648x486_regs[] = { @@ -916,7 +922,10 @@ static const struct ov5670_reg mode_648x486_regs[] = { {0x5792, 0x00}, {0x5793, 0x52}, {0x5794, 0xa3}, - {0x3503, 0x00} + {0x3503, 0x00}, + {0x5045, 0x05}, + {0x4003, 0x40}, + {0x5048, 0x40} }; static const struct ov5670_reg mode_2560x1440_regs[] = { @@ -1178,7 +1187,10 @@ static const struct ov5670_reg mode_2560x1440_regs[] = { {0x5791, 0x06}, {0x5792, 0x00}, {0x5793, 0x52}, - {0x5794, 0xa3} + {0x5794, 0xa3}, + {0x5045, 0x05}, + {0x4003, 0x40}, + {0x5048, 0x40} }; static const struct ov5670_reg mode_1280x720_regs[] = { @@ -1441,7 +1453,10 @@ static const struct ov5670_reg mode_1280x720_regs[] = { {0x5792, 0x00}, {0x5793, 0x52}, {0x5794, 0xa3}, - {0x3503, 0x00} + {0x3503, 0x00}, + {0x5045, 0x05}, + {0x4003, 0x40}, + {0x5048, 0x40} }; static const struct ov5670_reg mode_640x360_regs[] = { @@ -1704,7 +1719,10 @@ static const struct ov5670_reg mode_640x360_regs[] = { {0x5792, 0x00}, {0x5793, 0x52}, {0x5794, 0xa3}, - {0x3503, 0x00} + {0x3503, 0x00}, + {0x5045, 0x05}, + {0x4003, 0x40}, + {0x5048, 0x40} }; static const char * const ov5670_test_pattern_menu[] = { -- cgit v1.2.3 From bddb4b53356d3c97ee387c9ae7f290e4c76e8bc6 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 27 Aug 2017 13:30:36 -0300 Subject: [media] mt9m111: Propagate the real error on v4l2_clk_get() failure v4l2_clk_get() may return different error codes other than -EPROBE_DEFER, so it is better to return the real error code instead. Signed-off-by: Fabio Estevam Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9m111.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index 99b992e46702..b1665d97e0fd 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -945,7 +945,7 @@ static int mt9m111_probe(struct i2c_client *client, mt9m111->clk = v4l2_clk_get(&client->dev, "mclk"); if (IS_ERR(mt9m111->clk)) - return -EPROBE_DEFER; + return PTR_ERR(mt9m111->clk); /* Default HIGHPOWER context */ mt9m111->ctx = &context_b; -- cgit v1.2.3 From 877f1af154ec427d9c3c936a39a10afda95dcb97 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 27 Aug 2017 13:30:37 -0300 Subject: [media] ov2640: Propagate the real error on devm_clk_get() failure devm_clk_get() may return different error codes other than -EPROBE_DEFER, so it is better to return the real error code instead. Signed-off-by: Fabio Estevam Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2640.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index e6d0c1f64f0b..e6cbe01bc4cf 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -1107,7 +1107,7 @@ static int ov2640_probe(struct i2c_client *client, if (client->dev.of_node) { priv->clk = devm_clk_get(&client->dev, "xvclk"); if (IS_ERR(priv->clk)) - return -EPROBE_DEFER; + return PTR_ERR(priv->clk); clk_prepare_enable(priv->clk); } -- cgit v1.2.3 From c3d14780249814f200317cfed1e5d288aeefb528 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 27 Aug 2017 13:30:38 -0300 Subject: [media] ov2640: Check the return value from clk_prepare_enable() clk_prepare_enable() may fail, so we should better check its return value and propagate it in the case of error. Signed-off-by: Fabio Estevam Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2640.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index e6cbe01bc4cf..5f013c8cbdb5 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -1108,7 +1108,9 @@ static int ov2640_probe(struct i2c_client *client, priv->clk = devm_clk_get(&client->dev, "xvclk"); if (IS_ERR(priv->clk)) return PTR_ERR(priv->clk); - clk_prepare_enable(priv->clk); + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; } ret = ov2640_probe_dt(client, priv); -- cgit v1.2.3 From 1a58fbf5133c0c016decfa85f20b97a69672e315 Mon Sep 17 00:00:00 2001 From: Rajmohan Mani Date: Wed, 30 Aug 2017 14:48:52 -0300 Subject: [media] dw9714: Set the v4l2 focus ctrl step as 1 Current v4l2 focus ctrl step value of 16, limits the minimum granularity of focus positions to 16. Setting this value as 1, enables more accurate focus positions. Signed-off-by: Rajmohan Mani Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/dw9714.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/dw9714.c b/drivers/media/i2c/dw9714.c index 95af4fc99cd0..ed01e8bd4331 100644 --- a/drivers/media/i2c/dw9714.c +++ b/drivers/media/i2c/dw9714.c @@ -20,6 +20,11 @@ #define DW9714_NAME "dw9714" #define DW9714_MAX_FOCUS_POS 1023 +/* + * This sets the minimum granularity for the focus positions. + * A value of 1 gives maximum accuracy for a desired focus position + */ +#define DW9714_FOCUS_STEPS 1 /* * This acts as the minimum granularity of lens movement. * Keep this value power of 2, so the control steps can be @@ -137,7 +142,7 @@ static int dw9714_init_controls(struct dw9714_device *dev_vcm) v4l2_ctrl_handler_init(hdl, 1); v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FOCUS_ABSOLUTE, - 0, DW9714_MAX_FOCUS_POS, DW9714_CTRL_STEPS, 0); + 0, DW9714_MAX_FOCUS_POS, DW9714_FOCUS_STEPS, 0); if (hdl->error) dev_err(&client->dev, "%s fail error: 0x%x\n", -- cgit v1.2.3 From 3eefbc69bbdc7bca8c3751e525902d779ca1cdd3 Mon Sep 17 00:00:00 2001 From: Chiranjeevi Rapolu Date: Fri, 1 Sep 2017 19:08:31 -0300 Subject: [media] media: ov5670: Fix not streaming issue after resume Previously, the sensor was not streaming after resume from suspend, i.e. on S0->S3->S0 transition. Due to this, camera app preview appeared as stuck. Now, handle streaming state correctly in case of suspend-resume. Signed-off-by: Chiranjeevi Rapolu Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5670.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index 759ca6229db9..a65469f88e36 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -2341,8 +2341,6 @@ static int ov5670_start_streaming(struct ov5670 *ov5670) return ret; } - ov5670->streaming = true; - return 0; } @@ -2356,8 +2354,6 @@ static int ov5670_stop_streaming(struct ov5670 *ov5670) if (ret) dev_err(&client->dev, "%s failed to set stream\n", __func__); - ov5670->streaming = false; - /* Return success even if it was an error, as there is nothing the * caller can do about it. */ @@ -2388,6 +2384,7 @@ static int ov5670_set_stream(struct v4l2_subdev *sd, int enable) ret = ov5670_stop_streaming(ov5670); pm_runtime_put(&client->dev); } + ov5670->streaming = enable; goto unlock_and_return; error: -- cgit v1.2.3 From 0fd58435890aa9f2d44baaa2f328f7f8f512f4dc Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 2 Sep 2017 11:07:31 -0300 Subject: [media] i2c: Delete an error messages for failed memory allocation Omit extra messages for memory allocation failures. This issue was detected by using the Coccinelle software. [mchehab@s-opensource.com: merged similar patches] Signed-off-by: Markus Elfring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2640.c | 5 +---- drivers/media/i2c/ov6650.c | 5 +---- drivers/media/i2c/soc_camera/ov9640.c | 5 +---- drivers/media/i2c/soc_camera/ov9740.c | 4 +--- 4 files changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index 5f013c8cbdb5..c0d0c50f1d02 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -1098,11 +1098,8 @@ static int ov2640_probe(struct i2c_client *client, } priv = devm_kzalloc(&client->dev, sizeof(struct ov2640_priv), GFP_KERNEL); - if (!priv) { - dev_err(&adapter->dev, - "Failed to allocate memory for private data!\n"); + if (!priv) return -ENOMEM; - } if (client->dev.of_node) { priv->clk = devm_clk_get(&client->dev, "xvclk"); diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c index 768f2950ea36..8975d16b2b24 100644 --- a/drivers/media/i2c/ov6650.c +++ b/drivers/media/i2c/ov6650.c @@ -951,11 +951,8 @@ static int ov6650_probe(struct i2c_client *client, int ret; priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(&client->dev, - "Failed to allocate memory for private data!\n"); + if (!priv) return -ENOMEM; - } v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops); v4l2_ctrl_handler_init(&priv->hdl, 13); diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/ov9640.c index dafea6d90ad9..883500805aac 100644 --- a/drivers/media/i2c/soc_camera/ov9640.c +++ b/drivers/media/i2c/soc_camera/ov9640.c @@ -676,11 +676,8 @@ static int ov9640_probe(struct i2c_client *client, } priv = devm_kzalloc(&client->dev, sizeof(struct ov9640_priv), GFP_KERNEL); - if (!priv) { - dev_err(&client->dev, - "Failed to allocate memory for private data!\n"); + if (!priv) return -ENOMEM; - } v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops); diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c index cc07b7ae5407..f44f5da795f9 100644 --- a/drivers/media/i2c/soc_camera/ov9740.c +++ b/drivers/media/i2c/soc_camera/ov9740.c @@ -936,10 +936,8 @@ static int ov9740_probe(struct i2c_client *client, } priv = devm_kzalloc(&client->dev, sizeof(struct ov9740_priv), GFP_KERNEL); - if (!priv) { - dev_err(&client->dev, "Failed to allocate private data!\n"); + if (!priv) return -ENOMEM; - } v4l2_i2c_subdev_init(&priv->subdev, client, &ov9740_subdev_ops); v4l2_ctrl_handler_init(&priv->hdl, 13); -- cgit v1.2.3 From 19fab6fe67d815eb90095e21e3273a1fbe0c8fd9 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 2 Sep 2017 11:09:35 -0300 Subject: [media] i2c: Improve a size determination Replace the specification of a data structure by pointer dereferences as the parameter for the operator "sizeof" to make size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. [mchehab@s-opensource.com: merged similar patches] Signed-off-by: Markus Elfring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2640.c | 2 +- drivers/media/i2c/soc_camera/ov9640.c | 2 +- drivers/media/i2c/soc_camera/ov9740.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index c0d0c50f1d02..cc3882c1e10e 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -1097,7 +1097,7 @@ static int ov2640_probe(struct i2c_client *client, return -EIO; } - priv = devm_kzalloc(&client->dev, sizeof(struct ov2640_priv), GFP_KERNEL); + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/ov9640.c index 883500805aac..c63948989688 100644 --- a/drivers/media/i2c/soc_camera/ov9640.c +++ b/drivers/media/i2c/soc_camera/ov9640.c @@ -675,7 +675,7 @@ static int ov9640_probe(struct i2c_client *client, return -EINVAL; } - priv = devm_kzalloc(&client->dev, sizeof(struct ov9640_priv), GFP_KERNEL); + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c index f44f5da795f9..755de2289c39 100644 --- a/drivers/media/i2c/soc_camera/ov9740.c +++ b/drivers/media/i2c/soc_camera/ov9740.c @@ -935,7 +935,7 @@ static int ov9740_probe(struct i2c_client *client, return -EINVAL; } - priv = devm_kzalloc(&client->dev, sizeof(struct ov9740_priv), GFP_KERNEL); + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; -- cgit v1.2.3 From 885ca801e36d77c2d0025486b178c585a4680a80 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 5 Oct 2015 12:45:29 -0300 Subject: [media] media: Check for active and has_no_links overrun The active and has_no_links arrays will overrun in media_entity_pipeline_start() if there's an entity which has more than MEDIA_ENTITY_MAX_PAD pads. Ensure in media_entity_init() that there are fewer pads than that. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-entity.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index 2ace0410d277..f7c6d64e6031 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c @@ -214,12 +214,20 @@ void media_gobj_destroy(struct media_gobj *gobj) gobj->mdev = NULL; } +/* + * TODO: Get rid of this. + */ +#define MEDIA_ENTITY_MAX_PADS 512 + int media_entity_pads_init(struct media_entity *entity, u16 num_pads, struct media_pad *pads) { struct media_device *mdev = entity->graph_obj.mdev; unsigned int i; + if (num_pads >= MEDIA_ENTITY_MAX_PADS) + return -E2BIG; + entity->num_pads = num_pads; entity->pads = pads; @@ -280,11 +288,6 @@ static struct media_entity *stack_pop(struct media_graph *graph) #define link_top(en) ((en)->stack[(en)->top].link) #define stack_top(en) ((en)->stack[(en)->top].entity) -/* - * TODO: Get rid of this. - */ -#define MEDIA_ENTITY_MAX_PADS 512 - /** * media_graph_walk_init - Allocate resources for graph walk * @graph: Media graph structure that will be used to walk the graph -- cgit v1.2.3 From 91c158dd26b82207c80970b85ff7aa473da42312 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 12 Sep 2017 06:11:15 -0300 Subject: [media] ov2640: make array reset_seq static, reduces object code size Don't populate the array reset_seq on the stack, instead make it static. Makes the object code smaller by over 50 bytes: Before: text data bss dec hex filename 11737 6000 64 17801 4589 drivers/media/i2c/ov2640.o After: text data bss dec hex filename 11582 6096 64 17742 454e drivers/media/i2c/ov2640.o Signed-off-by: Colin Ian King Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2640.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index cc3882c1e10e..38b8bab7e6aa 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -685,7 +685,7 @@ static int ov2640_mask_set(struct i2c_client *client, static int ov2640_reset(struct i2c_client *client) { int ret; - const struct regval_list reset_seq[] = { + static const struct regval_list reset_seq[] = { {BANK_SEL, BANK_SEL_SENS}, {COM7, COM7_SRST}, ENDMARKER, -- cgit v1.2.3 From 6f2a0594aed2b3ac03fdd2e75b9fcb9f951e283a Mon Sep 17 00:00:00 2001 From: Chiranjeevi Rapolu Date: Mon, 18 Sep 2017 17:43:40 -0300 Subject: [media] media: ov13858: Calculate pixel-rate at runtime, use mode Calculate pixel-rate at run time instead of compile time. Instead of using hardcoded pixels-per-line, extract it from current sensor mode. Signed-off-by: Chiranjeevi Rapolu Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov13858.c | 49 +++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index af7af0d14c69..4e331b401a71 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -104,7 +104,6 @@ struct ov13858_reg_list { /* Link frequency config */ struct ov13858_link_freq_config { - u32 pixel_rate; u32 pixels_per_line; /* PLL registers for this link frequency */ @@ -948,6 +947,12 @@ static const char * const ov13858_test_pattern_menu[] = { #define OV13858_LINK_FREQ_INDEX_0 0 #define OV13858_LINK_FREQ_INDEX_1 1 +/* + * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample + * data rate => double data rate; number of lanes => 4; bits per pixel => 10 + */ +#define LINK_FREQ_TO_PIXEL_RATE(f) (((f) * 2 * 4) / 10) + /* Menu items for LINK_FREQ V4L2 control */ static const s64 link_freq_menu_items[OV13858_NUM_OF_LINK_FREQS] = { OV13858_LINK_FREQ_540MHZ, @@ -958,8 +963,6 @@ static const s64 link_freq_menu_items[OV13858_NUM_OF_LINK_FREQS] = { static const struct ov13858_link_freq_config link_freq_configs[OV13858_NUM_OF_LINK_FREQS] = { { - /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ - .pixel_rate = (OV13858_LINK_FREQ_540MHZ * 2 * 4) / 10, .pixels_per_line = OV13858_PPL_540MHZ, .reg_list = { .num_of_regs = ARRAY_SIZE(mipi_data_rate_1080mbps), @@ -967,8 +970,6 @@ static const struct ov13858_link_freq_config } }, { - /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ - .pixel_rate = (OV13858_LINK_FREQ_270MHZ * 2 * 4) / 10, .pixels_per_line = OV13858_PPL_270MHZ, .reg_list = { .num_of_regs = ARRAY_SIZE(mipi_data_rate_540mbps), @@ -1385,6 +1386,8 @@ ov13858_set_pad_format(struct v4l2_subdev *sd, s32 vblank_def; s32 vblank_min; s64 h_blank; + s64 pixel_rate; + s64 link_freq; mutex_lock(&ov13858->mutex); @@ -1400,9 +1403,10 @@ ov13858_set_pad_format(struct v4l2_subdev *sd, } else { ov13858->cur_mode = mode; __v4l2_ctrl_s_ctrl(ov13858->link_freq, mode->link_freq_index); - __v4l2_ctrl_s_ctrl_int64( - ov13858->pixel_rate, - link_freq_configs[mode->link_freq_index].pixel_rate); + link_freq = link_freq_menu_items[mode->link_freq_index]; + pixel_rate = LINK_FREQ_TO_PIXEL_RATE(link_freq); + __v4l2_ctrl_s_ctrl_int64(ov13858->pixel_rate, pixel_rate); + /* Update limits and set FPS to default */ vblank_def = ov13858->cur_mode->vts_def - ov13858->cur_mode->height; @@ -1617,6 +1621,10 @@ static int ov13858_init_controls(struct ov13858 *ov13858) s64 exposure_max; s64 vblank_def; s64 vblank_min; + s64 hblank; + s64 pixel_rate_min; + s64 pixel_rate_max; + const struct ov13858_mode *mode; int ret; ctrl_hdlr = &ov13858->ctrl_handler; @@ -1634,29 +1642,30 @@ static int ov13858_init_controls(struct ov13858 *ov13858) link_freq_menu_items); ov13858->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + pixel_rate_max = LINK_FREQ_TO_PIXEL_RATE(link_freq_menu_items[0]); + pixel_rate_min = LINK_FREQ_TO_PIXEL_RATE(link_freq_menu_items[1]); /* By default, PIXEL_RATE is read only */ ov13858->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov13858_ctrl_ops, - V4L2_CID_PIXEL_RATE, 0, - link_freq_configs[0].pixel_rate, 1, - link_freq_configs[0].pixel_rate); + V4L2_CID_PIXEL_RATE, + pixel_rate_min, pixel_rate_max, + 1, pixel_rate_max); - vblank_def = ov13858->cur_mode->vts_def - ov13858->cur_mode->height; - vblank_min = ov13858->cur_mode->vts_min - ov13858->cur_mode->height; + mode = ov13858->cur_mode; + vblank_def = mode->vts_def - mode->height; + vblank_min = mode->vts_min - mode->height; ov13858->vblank = v4l2_ctrl_new_std( ctrl_hdlr, &ov13858_ctrl_ops, V4L2_CID_VBLANK, - vblank_min, - OV13858_VTS_MAX - ov13858->cur_mode->height, 1, + vblank_min, OV13858_VTS_MAX - mode->height, 1, vblank_def); + hblank = link_freq_configs[mode->link_freq_index].pixels_per_line - + mode->width; ov13858->hblank = v4l2_ctrl_new_std( ctrl_hdlr, &ov13858_ctrl_ops, V4L2_CID_HBLANK, - OV13858_PPL_540MHZ - ov13858->cur_mode->width, - OV13858_PPL_540MHZ - ov13858->cur_mode->width, - 1, - OV13858_PPL_540MHZ - ov13858->cur_mode->width); + hblank, hblank, 1, hblank); ov13858->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; - exposure_max = ov13858->cur_mode->vts_def - 8; + exposure_max = mode->vts_def - 8; ov13858->exposure = v4l2_ctrl_new_std( ctrl_hdlr, &ov13858_ctrl_ops, V4L2_CID_EXPOSURE, OV13858_EXPOSURE_MIN, -- cgit v1.2.3 From 58020c9f14c8d884fd48434fbdbc659257cf46f3 Mon Sep 17 00:00:00 2001 From: Chiranjeevi Rapolu Date: Mon, 18 Sep 2017 19:47:43 -0300 Subject: [media] media: ov13858: Fix 4224x3136 video flickering at some vblanks Previously, with crop (0, 0), (4255, 3167), VTS < 0xC9E was resulting in blank frames sometimes. This appeared as video flickering. But we need VTS < 0xC9E to get ~30fps. Omni Vision recommends to use crop (0,8), (4255, 3159) for 4224x3136. With this crop, VTS 0xC8E is supported and yields ~30fps. Signed-off-by: Chiranjeevi Rapolu Reviewed-by: Tomasz Figa Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov13858.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index 4e331b401a71..2bd659976c30 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -237,11 +237,11 @@ static const struct ov13858_reg mode_4224x3136_regs[] = { {0x3800, 0x00}, {0x3801, 0x00}, {0x3802, 0x00}, - {0x3803, 0x00}, + {0x3803, 0x08}, {0x3804, 0x10}, {0x3805, 0x9f}, {0x3806, 0x0c}, - {0x3807, 0x5f}, + {0x3807, 0x57}, {0x3808, 0x10}, {0x3809, 0x80}, {0x380a, 0x0c}, -- cgit v1.2.3 From 880d45f8fcbacfa239533151f324210975698e0e Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 21 Sep 2017 11:24:53 -0300 Subject: [media] ov13858: Use do_div() for dividing a 64-bit number ov13858 contained a 64-bit division. Use do_div() for calculating it. Signed-off-by: Sakari Ailus Tested-by: Chiranjeevi Rapolu Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov13858.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index 2bd659976c30..fdce2befed02 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -951,7 +951,13 @@ static const char * const ov13858_test_pattern_menu[] = { * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample * data rate => double data rate; number of lanes => 4; bits per pixel => 10 */ -#define LINK_FREQ_TO_PIXEL_RATE(f) (((f) * 2 * 4) / 10) +static u64 link_freq_to_pixel_rate(u64 f) +{ + f *= 2 * 4; + do_div(f, 10); + + return f; +} /* Menu items for LINK_FREQ V4L2 control */ static const s64 link_freq_menu_items[OV13858_NUM_OF_LINK_FREQS] = { @@ -1404,7 +1410,7 @@ ov13858_set_pad_format(struct v4l2_subdev *sd, ov13858->cur_mode = mode; __v4l2_ctrl_s_ctrl(ov13858->link_freq, mode->link_freq_index); link_freq = link_freq_menu_items[mode->link_freq_index]; - pixel_rate = LINK_FREQ_TO_PIXEL_RATE(link_freq); + pixel_rate = link_freq_to_pixel_rate(link_freq); __v4l2_ctrl_s_ctrl_int64(ov13858->pixel_rate, pixel_rate); /* Update limits and set FPS to default */ @@ -1642,8 +1648,8 @@ static int ov13858_init_controls(struct ov13858 *ov13858) link_freq_menu_items); ov13858->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; - pixel_rate_max = LINK_FREQ_TO_PIXEL_RATE(link_freq_menu_items[0]); - pixel_rate_min = LINK_FREQ_TO_PIXEL_RATE(link_freq_menu_items[1]); + pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0]); + pixel_rate_min = link_freq_to_pixel_rate(link_freq_menu_items[1]); /* By default, PIXEL_RATE is read only */ ov13858->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov13858_ctrl_ops, V4L2_CID_PIXEL_RATE, -- cgit v1.2.3 From d339ec6a4261c030d8fdea75625c925f33549a2e Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 29 Aug 2017 09:41:22 -0300 Subject: [media] smiapp: Fix error handling in power on sequence The error handling code in smiapp_power_on() returned in case of a failed I2C write instead of cleaning up the mess. Fix this. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 700f433261d0..d581625d7826 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -1313,7 +1313,7 @@ static int smiapp_power_on(struct device *dev) rval = smiapp_write(sensor, SMIAPP_REG_U8_DPHY_CTRL, SMIAPP_DPHY_CTRL_UI); if (rval < 0) - return rval; + goto out_cci_addr_fail; rval = smiapp_call_quirk(sensor, post_poweron); if (rval) { -- cgit v1.2.3 From f689866aec08f00efc4a098d14b3a17ec8a9193b Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 29 Aug 2017 09:41:23 -0300 Subject: [media] smiapp: Verify clock frequency after setting it, prevent changing it The external clock frequency was set by the driver but the obtained frequency was never verified. Do that. Being able to obtain the exact frequency is important as the value is used for PLL calculations which may result in frequencies that violate the PLL tree limits. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index d581625d7826..55771826b446 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2870,6 +2870,7 @@ static int smiapp_probe(struct i2c_client *client, { struct smiapp_sensor *sensor; struct smiapp_hwconfig *hwcfg = smiapp_get_hwconfig(&client->dev); + unsigned long rate; unsigned int i; int rval; @@ -2908,6 +2909,14 @@ static int smiapp_probe(struct i2c_client *client, return rval; } + rate = clk_get_rate(sensor->ext_clk); + if (rate != sensor->hwcfg->ext_clk) { + dev_err(&client->dev, + "can't set clock freq, asked for %u but got %lu\n", + sensor->hwcfg->ext_clk, rate); + return rval; + } + sensor->xshutdown = devm_gpiod_get_optional(&client->dev, "xshutdown", GPIOD_OUT_LOW); if (IS_ERR(sensor->xshutdown)) -- cgit v1.2.3 From de10c1619c489d1ecaf6b478ef9f5057d946a710 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 29 Aug 2017 09:41:24 -0300 Subject: [media] smiapp: Get clock rate if it's not available through DT Obtain the clock rate from the clock framework if it's not available through DT. The assumption is that the parent device (camera module) defines the rate as clock control is a part of the power on and power off sequences --- which are camera module specific. Also use the clock rate from DT if no clock is provided. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 52 +++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 55771826b446..009b5e26204b 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2829,12 +2829,10 @@ static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev) /* NVM size is not mandatory */ fwnode_property_read_u32(fwnode, "nokia,nvm-size", &hwcfg->nvm_size); - rval = fwnode_property_read_u32(fwnode, "clock-frequency", + rval = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", &hwcfg->ext_clk); - if (rval) { - dev_warn(dev, "can't get clock-frequency\n"); - goto out_err; - } + if (rval) + dev_info(dev, "can't get clock-frequency\n"); dev_dbg(dev, "nvm %d, clk %d, mode %d\n", hwcfg->nvm_size, hwcfg->ext_clk, hwcfg->csi_signalling_mode); @@ -2870,7 +2868,6 @@ static int smiapp_probe(struct i2c_client *client, { struct smiapp_sensor *sensor; struct smiapp_hwconfig *hwcfg = smiapp_get_hwconfig(&client->dev); - unsigned long rate; unsigned int i; int rval; @@ -2901,20 +2898,37 @@ static int smiapp_probe(struct i2c_client *client, return -EPROBE_DEFER; } - rval = clk_set_rate(sensor->ext_clk, sensor->hwcfg->ext_clk); - if (rval < 0) { - dev_err(&client->dev, - "unable to set clock freq to %u\n", - sensor->hwcfg->ext_clk); - return rval; - } + if (sensor->ext_clk) { + if (sensor->hwcfg->ext_clk) { + unsigned long rate; - rate = clk_get_rate(sensor->ext_clk); - if (rate != sensor->hwcfg->ext_clk) { - dev_err(&client->dev, - "can't set clock freq, asked for %u but got %lu\n", - sensor->hwcfg->ext_clk, rate); - return rval; + rval = clk_set_rate(sensor->ext_clk, + sensor->hwcfg->ext_clk); + if (rval < 0) { + dev_err(&client->dev, + "unable to set clock freq to %u\n", + sensor->hwcfg->ext_clk); + return rval; + } + + rate = clk_get_rate(sensor->ext_clk); + if (rate != sensor->hwcfg->ext_clk) { + dev_err(&client->dev, + "can't set clock freq, asked for %u but got %lu\n", + sensor->hwcfg->ext_clk, rate); + return rval; + } + } else { + sensor->hwcfg->ext_clk = clk_get_rate(sensor->ext_clk); + dev_dbg(&client->dev, "obtained clock freq %u\n", + sensor->hwcfg->ext_clk); + } + } else if (sensor->hwcfg->ext_clk) { + dev_dbg(&client->dev, "assuming clock freq %u\n", + sensor->hwcfg->ext_clk); + } else { + dev_err(&client->dev, "unable to obtain clock freq\n"); + return -EINVAL; } sensor->xshutdown = devm_gpiod_get_optional(&client->dev, "xshutdown", -- cgit v1.2.3 From ccec44cc910d1fa94690e0b9f07194be3421cb1a Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 29 Aug 2017 09:41:25 -0300 Subject: [media] smiapp: Make clock control optional The clock control is not explicitly controlled by the driver in two cases: ACPI based systems and when the clock is part of the power sequence of the camera module. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 009b5e26204b..fbd851be51d2 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2892,7 +2892,10 @@ static int smiapp_probe(struct i2c_client *client, } sensor->ext_clk = devm_clk_get(&client->dev, NULL); - if (IS_ERR(sensor->ext_clk)) { + if (PTR_ERR(sensor->ext_clk) == -ENOENT) { + dev_info(&client->dev, "no clock defined, continuing...\n"); + sensor->ext_clk = NULL; + } else if (IS_ERR(sensor->ext_clk)) { dev_err(&client->dev, "could not get clock (%ld)\n", PTR_ERR(sensor->ext_clk)); return -EPROBE_DEFER; -- cgit v1.2.3 From c1301077213d4dca34f01fc372b64d3c4a49a437 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Thu, 5 Oct 2017 09:11:06 -0300 Subject: [media] media: rc: fix gpio-ir-receiver build failure The 0-day robot reports: drivers/media/rc/gpio-ir-recv.c: In function 'gpio_ir_recv_irq': >> drivers/media/rc/gpio-ir-recv.c:38:8: error: implicit declaration of function 'gpiod_get_value' [-Werror=implicit-function-declaration] Fixes: eed008e605d1 ("[media] media: rc: gpio-ir-recv: use gpiolib API") For some reason only partial patch was applied. Also include gpio/consumer.h otherwise compile test fails. Reported-by: kbuild test robot Signed-off-by: Ladislav Michl Acked-by: Sean Young --- drivers/media/rc/Kconfig | 1 + drivers/media/rc/gpio-ir-recv.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 467cf2bdbd42..451cba1fe9bf 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -392,6 +392,7 @@ config RC_LOOPBACK config IR_GPIO_CIR tristate "GPIO IR remote control" depends on RC_CORE + depends on (OF && GPIOLIB) || COMPILE_TEST ---help--- Say Y if you want to use GPIO based IR Receiver. diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 24641a9079da..3d99b51384ac 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3 From 2265425fd9c512cc9977516b5fe78d03ad9311a7 Mon Sep 17 00:00:00 2001 From: David Härdeman Date: Sun, 25 Jun 2017 08:31:30 -0400 Subject: media: lirc_dev: remove min_timeout and max_timeout There are no users of this functionality (ir-lirc-codec.c has its own implementation and lirc_zilog.c doesn't use it) so remove it. This only affects users of the lirc kapi, not rc-core drivers. Signed-off-by: David Härdeman Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 18 ------------------ include/media/lirc_dev.h | 6 ------ 2 files changed, 24 deletions(-) diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index e9dae8621670..e16d1138ca48 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -346,24 +346,6 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case LIRC_GET_LENGTH: result = put_user(d->code_length, (__u32 __user *)arg); break; - case LIRC_GET_MIN_TIMEOUT: - if (!(d->features & LIRC_CAN_SET_REC_TIMEOUT) || - d->min_timeout == 0) { - result = -ENOTTY; - break; - } - - result = put_user(d->min_timeout, (__u32 __user *)arg); - break; - case LIRC_GET_MAX_TIMEOUT: - if (!(d->features & LIRC_CAN_SET_REC_TIMEOUT) || - d->max_timeout == 0) { - result = -ENOTTY; - break; - } - - result = put_user(d->max_timeout, (__u32 __user *)arg); - break; default: result = -ENOTTY; } diff --git a/include/media/lirc_dev.h b/include/media/lirc_dev.h index 981dcabd5fd5..857da67bd931 100644 --- a/include/media/lirc_dev.h +++ b/include/media/lirc_dev.h @@ -125,10 +125,6 @@ static inline unsigned int lirc_buffer_write(struct lirc_buffer *buf, * @chunk_size: Size of each FIFO buffer. * Only used if @rbuf is NULL. * @data: private per-driver data - * @min_timeout: Minimum timeout for record. Valid only if - * LIRC_CAN_SET_REC_TIMEOUT is defined. - * @max_timeout: Maximum timeout for record. Valid only if - * LIRC_CAN_SET_REC_TIMEOUT is defined. * @buf: if %NULL, lirc_dev will allocate and manage the buffer, * otherwise allocated by the caller which will * have to write to the buffer by other means, like irq's @@ -155,8 +151,6 @@ struct lirc_dev { bool buf_internal; void *data; - int min_timeout; - int max_timeout; struct rc_dev *rdev; const struct file_operations *fops; struct module *owner; -- cgit v1.2.3 From 829bbf268894d0866bb9dd2b1e430cfa5c5f0779 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 1 Oct 2017 16:38:29 -0400 Subject: media: rc: nec decoder should not send both repeat and keycode When receiving an nec repeat, rc_repeat() is called and then rc_keydown() with the last decoded scancode. That last call is redundant. Fixes: 265a2988d202 ("media: rc-core: consistent use of rc_repeat()") Cc: # v4.14 Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-nec-decoder.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c index 817c18f2ddd1..a95d09acc22a 100644 --- a/drivers/media/rc/ir-nec-decoder.c +++ b/drivers/media/rc/ir-nec-decoder.c @@ -87,8 +87,6 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) data->state = STATE_BIT_PULSE; return 0; } else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) { - rc_repeat(dev); - IR_dprintk(1, "Repeat last key\n"); data->state = STATE_TRAILER_PULSE; return 0; } @@ -151,19 +149,26 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2)) break; - address = bitrev8((data->bits >> 24) & 0xff); - not_address = bitrev8((data->bits >> 16) & 0xff); - command = bitrev8((data->bits >> 8) & 0xff); - not_command = bitrev8((data->bits >> 0) & 0xff); + if (data->count == NEC_NBITS) { + address = bitrev8((data->bits >> 24) & 0xff); + not_address = bitrev8((data->bits >> 16) & 0xff); + command = bitrev8((data->bits >> 8) & 0xff); + not_command = bitrev8((data->bits >> 0) & 0xff); + + scancode = ir_nec_bytes_to_scancode(address, + not_address, + command, + not_command, + &rc_proto); - scancode = ir_nec_bytes_to_scancode(address, not_address, - command, not_command, - &rc_proto); + if (data->is_nec_x) + data->necx_repeat = true; - if (data->is_nec_x) - data->necx_repeat = true; + rc_keydown(dev, rc_proto, scancode, 0); + } else { + rc_repeat(dev); + } - rc_keydown(dev, rc_proto, scancode, 0); data->state = STATE_INACTIVE; return 0; } -- cgit v1.2.3 From 5288879390388af654da3bb9cdc2c409abf6b4f3 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 5 Oct 2017 17:30:57 -0400 Subject: media: rc: gpio-ir-tx does not work without devicetree or gpiolib If the kernel is built without device tree, this driver cannot be used and without gpiolib it cannot control any gpio pin. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 451cba1fe9bf..946d2ec419db 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -403,6 +403,7 @@ config IR_GPIO_TX tristate "GPIO IR Bit Banging Transmitter" depends on RC_CORE depends on LIRC + depends on (OF && GPIOLIB) || COMPILE_TEST ---help--- Say Y if you want to a GPIO based IR transmitter. This is a bit banging driver. -- cgit v1.2.3 From 2d726aaab2831866846dadbc675f484305041ee9 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 5 Oct 2017 17:30:58 -0400 Subject: media: rc: pwm-ir-tx needs OF Without device tree, there is no way to use this driver. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 946d2ec419db..88c8ecd13044 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -416,6 +416,7 @@ config IR_PWM_TX depends on RC_CORE depends on LIRC depends on PWM + depends on OF || COMPILE_TEST ---help--- Say Y if you want to use a PWM based IR transmitter. This is more power efficient than the bit banging gpio driver. -- cgit v1.2.3 From a840f3c7fb426382b4b2204bc01bf8b474875fcc Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 5 Oct 2017 17:30:59 -0400 Subject: media: rc: hix5hd2 drivers needs OF Without device tree, there is no way to use this driver. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 88c8ecd13044..94db0ed1df54 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -178,6 +178,7 @@ config IR_ENE config IR_HIX5HD2 tristate "Hisilicon hix5hd2 IR remote control" depends on RC_CORE + depends on OF || COMPILE_TEST help Say Y here if you want to use hisilicon hix5hd2 remote control. To compile this driver as a module, choose M here: the module will be -- cgit v1.2.3 From 5248e34b3fa39cdd80ab41f73c545d0bf5428b47 Mon Sep 17 00:00:00 2001 From: Marc Gonzalez Date: Fri, 6 Oct 2017 08:33:41 -0400 Subject: media: rc: Add tango keymap Add a keymap for the Sigma Designs Vantage (dev board) remote control. Signed-off-by: Marc Gonzalez Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/Makefile | 1 + drivers/media/rc/keymaps/rc-tango.c | 92 +++++++++++++++++++++++++++++++++++++ include/media/rc-map.h | 1 + 3 files changed, 94 insertions(+) create mode 100644 drivers/media/rc/keymaps/rc-tango.c diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index af6496d709fb..3c1e31321e21 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -88,6 +88,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-reddo.o \ rc-snapstream-firefly.o \ rc-streamzap.o \ + rc-tango.o \ rc-tbs-nec.o \ rc-technisat-ts35.o \ rc-technisat-usb2.o \ diff --git a/drivers/media/rc/keymaps/rc-tango.c b/drivers/media/rc/keymaps/rc-tango.c new file mode 100644 index 000000000000..1c6e8875d46f --- /dev/null +++ b/drivers/media/rc/keymaps/rc-tango.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2017 Sigma Designs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include +#include + +static struct rc_map_table tango_table[] = { + { 0x4cb4a, KEY_POWER }, + { 0x4cb48, KEY_FILE }, + { 0x4cb0f, KEY_SETUP }, + { 0x4cb4d, KEY_SUSPEND }, + { 0x4cb4e, KEY_VOLUMEUP }, + { 0x4cb44, KEY_EJECTCD }, + { 0x4cb13, KEY_TV }, + { 0x4cb51, KEY_MUTE }, + { 0x4cb52, KEY_VOLUMEDOWN }, + + { 0x4cb41, KEY_1 }, + { 0x4cb03, KEY_2 }, + { 0x4cb42, KEY_3 }, + { 0x4cb45, KEY_4 }, + { 0x4cb07, KEY_5 }, + { 0x4cb46, KEY_6 }, + { 0x4cb55, KEY_7 }, + { 0x4cb17, KEY_8 }, + { 0x4cb56, KEY_9 }, + { 0x4cb1b, KEY_0 }, + { 0x4cb59, KEY_DELETE }, + { 0x4cb5a, KEY_CAPSLOCK }, + + { 0x4cb47, KEY_BACK }, + { 0x4cb05, KEY_SWITCHVIDEOMODE }, + { 0x4cb06, KEY_UP }, + { 0x4cb43, KEY_LEFT }, + { 0x4cb01, KEY_RIGHT }, + { 0x4cb0a, KEY_DOWN }, + { 0x4cb02, KEY_ENTER }, + { 0x4cb4b, KEY_INFO }, + { 0x4cb09, KEY_HOME }, + + { 0x4cb53, KEY_MENU }, + { 0x4cb12, KEY_PREVIOUS }, + { 0x4cb50, KEY_PLAY }, + { 0x4cb11, KEY_NEXT }, + { 0x4cb4f, KEY_TITLE }, + { 0x4cb0e, KEY_REWIND }, + { 0x4cb4c, KEY_STOP }, + { 0x4cb0d, KEY_FORWARD }, + { 0x4cb57, KEY_MEDIA_REPEAT }, + { 0x4cb16, KEY_ANGLE }, + { 0x4cb54, KEY_PAUSE }, + { 0x4cb15, KEY_SLOW }, + { 0x4cb5b, KEY_TIME }, + { 0x4cb1a, KEY_AUDIO }, + { 0x4cb58, KEY_SUBTITLE }, + { 0x4cb19, KEY_ZOOM }, + + { 0x4cb5f, KEY_RED }, + { 0x4cb1e, KEY_GREEN }, + { 0x4cb5c, KEY_YELLOW }, + { 0x4cb1d, KEY_BLUE }, +}; + +static struct rc_map_list tango_map = { + .map = { + .scan = tango_table, + .size = ARRAY_SIZE(tango_table), + .rc_proto = RC_PROTO_NECX, + .name = RC_MAP_TANGO, + } +}; + +static int __init init_rc_map_tango(void) +{ + return rc_map_register(&tango_map); +} + +static void __exit exit_rc_map_tango(void) +{ + rc_map_unregister(&tango_map); +} + +module_init(init_rc_map_tango) +module_exit(exit_rc_map_tango) + +MODULE_AUTHOR("Sigma Designs"); +MODULE_LICENSE("GPL"); diff --git a/include/media/rc-map.h b/include/media/rc-map.h index 2a160e6e823c..b4ddcb62c993 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -300,6 +300,7 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_REDDO "rc-reddo" #define RC_MAP_SNAPSTREAM_FIREFLY "rc-snapstream-firefly" #define RC_MAP_STREAMZAP "rc-streamzap" +#define RC_MAP_TANGO "rc-tango" #define RC_MAP_TBS_NEC "rc-tbs-nec" #define RC_MAP_TECHNISAT_TS35 "rc-technisat-ts35" #define RC_MAP_TECHNISAT_USB2 "rc-technisat-usb2" -- cgit v1.2.3 From d345527331f0ceef1070d4d2f5c41edb4174c6af Mon Sep 17 00:00:00 2001 From: Mans Rullgard Date: Fri, 6 Oct 2017 08:37:50 -0400 Subject: media: rc: Add driver for tango HW IR decoder The tango HW IR decoder supports NEC, RC-5, RC-6 protocols. Signed-off-by: Mans Rullgard Signed-off-by: Marc Gonzalez Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 10 ++ drivers/media/rc/Makefile | 1 + drivers/media/rc/tango-ir.c | 281 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 292 insertions(+) create mode 100644 drivers/media/rc/tango-ir.c diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 94db0ed1df54..bde3c271fb88 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -472,6 +472,16 @@ config IR_SIR To compile this driver as a module, choose M here: the module will be called sir-ir. +config IR_TANGO + tristate "Sigma Designs SMP86xx IR decoder" + depends on RC_CORE + depends on ARCH_TANGO || COMPILE_TEST + ---help--- + Adds support for the HW IR decoder embedded on Sigma Designs + Tango-based systems (SMP86xx, SMP87xx). + The HW decoder supports NEC, RC-5, RC-6 IR protocols. + When compiled as a module, look for tango-ir. + config IR_ZX tristate "ZTE ZX IR remote control" depends on RC_CORE diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 9bc6a3980ed0..643797dc971b 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -44,3 +44,4 @@ obj-$(CONFIG_IR_SERIAL) += serial_ir.o obj-$(CONFIG_IR_SIR) += sir_ir.o obj-$(CONFIG_IR_MTK) += mtk-cir.o obj-$(CONFIG_IR_ZX) += zx-irdec.o +obj-$(CONFIG_IR_TANGO) += tango-ir.o diff --git a/drivers/media/rc/tango-ir.c b/drivers/media/rc/tango-ir.c new file mode 100644 index 000000000000..9d4c17230c3a --- /dev/null +++ b/drivers/media/rc/tango-ir.c @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2015 Mans Rullgard + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "tango-ir" + +#define IR_NEC_CTRL 0x00 +#define IR_NEC_DATA 0x04 +#define IR_CTRL 0x08 +#define IR_RC5_CLK_DIV 0x0c +#define IR_RC5_DATA 0x10 +#define IR_INT 0x14 + +#define NEC_TIME_BASE 560 +#define RC5_TIME_BASE 1778 + +#define RC6_CTRL 0x00 +#define RC6_CLKDIV 0x04 +#define RC6_DATA0 0x08 +#define RC6_DATA1 0x0c +#define RC6_DATA2 0x10 +#define RC6_DATA3 0x14 +#define RC6_DATA4 0x18 + +#define RC6_CARRIER 36000 +#define RC6_TIME_BASE 16 + +#define NEC_CAP(n) ((n) << 24) +#define GPIO_SEL(n) ((n) << 16) +#define DISABLE_NEC (BIT(4) | BIT(8)) +#define ENABLE_RC5 (BIT(0) | BIT(9)) +#define ENABLE_RC6 (BIT(0) | BIT(7)) +#define ACK_IR_INT (BIT(0) | BIT(1)) +#define ACK_RC6_INT (BIT(31)) + +#define NEC_ANY (RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32) + +struct tango_ir { + void __iomem *rc5_base; + void __iomem *rc6_base; + struct rc_dev *rc; + struct clk *clk; +}; + +static void tango_ir_handle_nec(struct tango_ir *ir) +{ + u32 v, code; + enum rc_proto proto; + + v = readl_relaxed(ir->rc5_base + IR_NEC_DATA); + if (!v) { + rc_repeat(ir->rc); + return; + } + + code = ir_nec_bytes_to_scancode(v, v >> 8, v >> 16, v >> 24, &proto); + rc_keydown(ir->rc, proto, code, 0); +} + +static void tango_ir_handle_rc5(struct tango_ir *ir) +{ + u32 data, field, toggle, addr, cmd, code; + + data = readl_relaxed(ir->rc5_base + IR_RC5_DATA); + if (data & BIT(31)) + return; + + field = data >> 12 & 1; + toggle = data >> 11 & 1; + addr = data >> 6 & 0x1f; + cmd = (data & 0x3f) | (field ^ 1) << 6; + + code = RC_SCANCODE_RC5(addr, cmd); + rc_keydown(ir->rc, RC_PROTO_RC5, code, toggle); +} + +static void tango_ir_handle_rc6(struct tango_ir *ir) +{ + u32 data0, data1, toggle, mode, addr, cmd, code; + + data0 = readl_relaxed(ir->rc6_base + RC6_DATA0); + data1 = readl_relaxed(ir->rc6_base + RC6_DATA1); + + mode = data0 >> 1 & 7; + if (mode != 0) + return; + + toggle = data0 & 1; + addr = data0 >> 16; + cmd = data1; + + code = RC_SCANCODE_RC6_0(addr, cmd); + rc_keydown(ir->rc, RC_PROTO_RC6_0, code, toggle); +} + +static irqreturn_t tango_ir_irq(int irq, void *dev_id) +{ + struct tango_ir *ir = dev_id; + unsigned int rc5_stat; + unsigned int rc6_stat; + + rc5_stat = readl_relaxed(ir->rc5_base + IR_INT); + writel_relaxed(rc5_stat, ir->rc5_base + IR_INT); + + rc6_stat = readl_relaxed(ir->rc6_base + RC6_CTRL); + writel_relaxed(rc6_stat, ir->rc6_base + RC6_CTRL); + + if (!(rc5_stat & 3) && !(rc6_stat & BIT(31))) + return IRQ_NONE; + + if (rc5_stat & BIT(0)) + tango_ir_handle_rc5(ir); + + if (rc5_stat & BIT(1)) + tango_ir_handle_nec(ir); + + if (rc6_stat & BIT(31)) + tango_ir_handle_rc6(ir); + + return IRQ_HANDLED; +} + +static int tango_change_protocol(struct rc_dev *dev, u64 *rc_type) +{ + struct tango_ir *ir = dev->priv; + u32 rc5_ctrl = DISABLE_NEC; + u32 rc6_ctrl = 0; + + if (*rc_type & NEC_ANY) + rc5_ctrl = 0; + + if (*rc_type & RC_PROTO_BIT_RC5) + rc5_ctrl |= ENABLE_RC5; + + if (*rc_type & RC_PROTO_BIT_RC6_0) + rc6_ctrl = ENABLE_RC6; + + writel_relaxed(rc5_ctrl, ir->rc5_base + IR_CTRL); + writel_relaxed(rc6_ctrl, ir->rc6_base + RC6_CTRL); + + return 0; +} + +static int tango_ir_probe(struct platform_device *pdev) +{ + const char *map_name = RC_MAP_TANGO; + struct device *dev = &pdev->dev; + struct rc_dev *rc; + struct tango_ir *ir; + struct resource *rc5_res; + struct resource *rc6_res; + u64 clkrate, clkdiv; + int irq, err; + u32 val; + + rc5_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!rc5_res) + return -EINVAL; + + rc6_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!rc6_res) + return -EINVAL; + + irq = platform_get_irq(pdev, 0); + if (irq <= 0) + return -EINVAL; + + ir = devm_kzalloc(dev, sizeof(*ir), GFP_KERNEL); + if (!ir) + return -ENOMEM; + + ir->rc5_base = devm_ioremap_resource(dev, rc5_res); + if (IS_ERR(ir->rc5_base)) + return PTR_ERR(ir->rc5_base); + + ir->rc6_base = devm_ioremap_resource(dev, rc6_res); + if (IS_ERR(ir->rc6_base)) + return PTR_ERR(ir->rc6_base); + + ir->clk = devm_clk_get(dev, NULL); + if (IS_ERR(ir->clk)) + return PTR_ERR(ir->clk); + + rc = devm_rc_allocate_device(dev, RC_DRIVER_SCANCODE); + if (!rc) + return -ENOMEM; + + of_property_read_string(dev->of_node, "linux,rc-map-name", &map_name); + + rc->device_name = DRIVER_NAME; + rc->driver_name = DRIVER_NAME; + rc->input_phys = DRIVER_NAME "/input0"; + rc->map_name = map_name; + rc->allowed_protocols = NEC_ANY | RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC6_0; + rc->change_protocol = tango_change_protocol; + rc->priv = ir; + ir->rc = rc; + + err = clk_prepare_enable(ir->clk); + if (err) + return err; + + clkrate = clk_get_rate(ir->clk); + + clkdiv = clkrate * NEC_TIME_BASE; + do_div(clkdiv, 1000000); + + val = NEC_CAP(31) | GPIO_SEL(12) | clkdiv; + writel_relaxed(val, ir->rc5_base + IR_NEC_CTRL); + + clkdiv = clkrate * RC5_TIME_BASE; + do_div(clkdiv, 1000000); + + writel_relaxed(DISABLE_NEC, ir->rc5_base + IR_CTRL); + writel_relaxed(clkdiv, ir->rc5_base + IR_RC5_CLK_DIV); + writel_relaxed(ACK_IR_INT, ir->rc5_base + IR_INT); + + clkdiv = clkrate * RC6_TIME_BASE; + do_div(clkdiv, RC6_CARRIER); + + writel_relaxed(ACK_RC6_INT, ir->rc6_base + RC6_CTRL); + writel_relaxed((clkdiv >> 2) << 18 | clkdiv, ir->rc6_base + RC6_CLKDIV); + + err = devm_request_irq(dev, irq, tango_ir_irq, IRQF_SHARED, + dev_name(dev), ir); + if (err) + goto err_clk; + + err = devm_rc_register_device(dev, rc); + if (err) + goto err_clk; + + platform_set_drvdata(pdev, ir); + return 0; + +err_clk: + clk_disable_unprepare(ir->clk); + return err; +} + +static int tango_ir_remove(struct platform_device *pdev) +{ + struct tango_ir *ir = platform_get_drvdata(pdev); + + clk_disable_unprepare(ir->clk); + return 0; +} + +static const struct of_device_id tango_ir_dt_ids[] = { + { .compatible = "sigma,smp8642-ir" }, + { } +}; +MODULE_DEVICE_TABLE(of, tango_ir_dt_ids); + +static struct platform_driver tango_ir_driver = { + .probe = tango_ir_probe, + .remove = tango_ir_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = tango_ir_dt_ids, + }, +}; +module_platform_driver(tango_ir_driver); + +MODULE_DESCRIPTION("SMP86xx IR decoder driver"); +MODULE_AUTHOR("Mans Rullgard "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 5ce8c7a0e6945fdd48ed99cfcfcc25568c1e5960 Mon Sep 17 00:00:00 2001 From: Marc Gonzalez Date: Fri, 6 Oct 2017 08:23:37 -0400 Subject: media: dt: bindings: Add binding for tango HW IR decoder Add DT binding for the HW IR decoder embedded in SMP86xx/SMP87xx. Signed-off-by: Marc Gonzalez Acked-by: Rob Herring Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/tango-ir.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/tango-ir.txt diff --git a/Documentation/devicetree/bindings/media/tango-ir.txt b/Documentation/devicetree/bindings/media/tango-ir.txt new file mode 100644 index 000000000000..a9f00c2bf897 --- /dev/null +++ b/Documentation/devicetree/bindings/media/tango-ir.txt @@ -0,0 +1,21 @@ +Sigma Designs Tango IR NEC/RC-5/RC-6 decoder (SMP86xx and SMP87xx) + +Required properties: + +- compatible: "sigma,smp8642-ir" +- reg: address/size of NEC+RC5 area, address/size of RC6 area +- interrupts: spec for IR IRQ +- clocks: spec for IR clock (typically the crystal oscillator) + +Optional properties: + +- linux,rc-map-name: see Documentation/devicetree/bindings/media/rc.txt + +Example: + + ir@10518 { + compatible = "sigma,smp8642-ir"; + reg = <0x10518 0x18>, <0x105e0 0x1c>; + interrupts = <21 IRQ_TYPE_EDGE_RISING>; + clocks = <&xtal>; + }; -- cgit v1.2.3 From 3e45067f94bbd61dec0619b1c32744eb0de480c8 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 8 Oct 2017 14:18:52 -0400 Subject: media: rc: check for integer overflow The ioctl LIRC_SET_REC_TIMEOUT would set a timeout of 704ns if called with a timeout of 4294968us. Cc: Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index bd046c41a53a..8f2f37412fc5 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -298,11 +298,14 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd, if (!dev->max_timeout) return -ENOTTY; + /* Check for multiply overflow */ + if (val > U32_MAX / 1000) + return -EINVAL; + tmp = val * 1000; - if (tmp < dev->min_timeout || - tmp > dev->max_timeout) - return -EINVAL; + if (tmp < dev->min_timeout || tmp > dev->max_timeout) + return -EINVAL; if (dev->s_timeout) ret = dev->s_timeout(dev, tmp); -- cgit v1.2.3 From 950db1a80e6349a25f9af594a45ab45eed5a0020 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 9 Oct 2017 04:30:06 -0400 Subject: media: rc: ir-spi needs OF Without device tree, there is no way to use this driver. Signed-off-by: Sean Young Acked-by: Andi Shyti Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index bde3c271fb88..afb3456d4e20 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -286,6 +286,7 @@ config IR_REDRAT3 config IR_SPI tristate "SPI connected IR LED" depends on SPI && LIRC + depends on OF || COMPILE_TEST ---help--- Say Y if you want to use an IR LED connected through SPI bus. -- cgit v1.2.3 From 473e4b4c1cf3046fc6b3437be9a9f3c89c2e61ef Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 14 Sep 2017 07:44:18 -0400 Subject: media: stv0288: get rid of set_property boilerplate This driver doesn't implement support for set_property(). Yet, it implements a boilerplate for it. Get rid of it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stv0288.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/media/dvb-frontends/stv0288.c b/drivers/media/dvb-frontends/stv0288.c index 45cbc898ad25..67f91814b9f7 100644 --- a/drivers/media/dvb-frontends/stv0288.c +++ b/drivers/media/dvb-frontends/stv0288.c @@ -447,12 +447,6 @@ static int stv0288_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) return 0; } -static int stv0288_set_property(struct dvb_frontend *fe, struct dtv_property *p) -{ - dprintk("%s(..)\n", __func__); - return 0; -} - static int stv0288_set_frontend(struct dvb_frontend *fe) { struct stv0288_state *state = fe->demodulator_priv; @@ -567,7 +561,6 @@ static const struct dvb_frontend_ops stv0288_ops = { .set_tone = stv0288_set_tone, .set_voltage = stv0288_set_voltage, - .set_property = stv0288_set_property, .set_frontend = stv0288_set_frontend, }; -- cgit v1.2.3 From 282996925b4d78f9795d176f7fb409281c98d56d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 14 Sep 2017 07:44:19 -0400 Subject: media: stv6110: get rid of a srate dead code The stv6110 has a weird code that checks if get_property and set_property ioctls are defined. If they're, it initializes a "srate" var from properties cache. Otherwise, it sets to 15MBaud, with won't make any sense. Thankfully, it seems that someone else discovered the issue in the past, as "srate" is currently not used anywhere! So, get rid of that really weird dead code logic. Reported-by: Honza Petrous Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stv6110.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/media/dvb-frontends/stv6110.c b/drivers/media/dvb-frontends/stv6110.c index e4fd9c1b0560..6aad0efa3174 100644 --- a/drivers/media/dvb-frontends/stv6110.c +++ b/drivers/media/dvb-frontends/stv6110.c @@ -258,11 +258,9 @@ static int stv6110_get_frequency(struct dvb_frontend *fe, u32 *frequency) static int stv6110_set_frequency(struct dvb_frontend *fe, u32 frequency) { struct stv6110_priv *priv = fe->tuner_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; u8 ret = 0x04; u32 divider, ref, p, presc, i, result_freq, vco_freq; s32 p_calc, p_calc_opt = 1000, r_div, r_div_opt = 0, p_val; - s32 srate; dprintk("%s, freq=%d kHz, mclk=%d Hz\n", __func__, frequency, priv->mclk); @@ -273,13 +271,6 @@ static int stv6110_set_frequency(struct dvb_frontend *fe, u32 frequency) ((((priv->mclk / 1000000) - 16) & 0x1f) << 3); /* BB_GAIN = db/2 */ - if (fe->ops.set_property && fe->ops.get_property) { - srate = c->symbol_rate; - dprintk("%s: Get Frontend parameters: srate=%d\n", - __func__, srate); - } else - srate = 15000000; - priv->regs[RSTV6110_CTRL2] &= ~0x0f; priv->regs[RSTV6110_CTRL2] |= (priv->gain & 0x0f); -- cgit v1.2.3 From b2c41ca9632e686e79f6c9db9c5f75666d37926e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 14 Sep 2017 07:44:21 -0400 Subject: media: friio-fe: get rid of set_property() This callback is not actually doing anything but making it to return an error depending on the DTV frontend command. Well, that could break userspace for no good reason, and, if needed, should be implemented, instead, at set_frontend() callback. So, get rid of it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/friio-fe.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/drivers/media/usb/dvb-usb/friio-fe.c b/drivers/media/usb/dvb-usb/friio-fe.c index 0251a4e91d47..41261317bd5c 100644 --- a/drivers/media/usb/dvb-usb/friio-fe.c +++ b/drivers/media/usb/dvb-usb/friio-fe.c @@ -261,28 +261,6 @@ static int jdvbt90502_read_signal_strength(struct dvb_frontend *fe, return 0; } - -/* filter out un-supported properties to notify users */ -static int jdvbt90502_set_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - int r = 0; - - switch (tvp->cmd) { - case DTV_DELIVERY_SYSTEM: - if (tvp->u.data != SYS_ISDBT) - r = -EINVAL; - break; - case DTV_CLEAR: - case DTV_TUNE: - case DTV_FREQUENCY: - break; - default: - r = -EINVAL; - } - return r; -} - static int jdvbt90502_set_frontend(struct dvb_frontend *fe) { struct dtv_frontend_properties *p = &fe->dtv_property_cache; @@ -457,8 +435,6 @@ static const struct dvb_frontend_ops jdvbt90502_ops = { .init = jdvbt90502_init, .write = _jdvbt90502_write, - .set_property = jdvbt90502_set_property, - .set_frontend = jdvbt90502_set_frontend, .read_status = jdvbt90502_read_status, -- cgit v1.2.3 From 8f8a19fcc1a89b83d0ab6d7cf2bcdd272dbd4334 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 14 Sep 2017 07:44:20 -0400 Subject: media: dvb_frontend: get rid of get_property() callback Only lg2160 implement gets_property, but there's no need for that, as no other driver calls this callback, as get_frontend() does the same, and set_frontend() also calls lg2160 get_frontend(). So, get rid of it. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Michael Ira Krufky Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 9 +-------- drivers/media/dvb-core/dvb_frontend.h | 3 --- drivers/media/dvb-frontends/lg2160.c | 14 -------------- 3 files changed, 1 insertion(+), 25 deletions(-) diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 2fcba1616168..cafc51b303e2 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -1308,7 +1308,7 @@ static int dtv_property_process_get(struct dvb_frontend *fe, struct dtv_property *tvp, struct file *file) { - int r, ncaps; + int ncaps; switch(tvp->cmd) { case DTV_ENUM_DELSYS: @@ -1519,13 +1519,6 @@ static int dtv_property_process_get(struct dvb_frontend *fe, return -EINVAL; } - /* Allow the frontend to override outgoing properties */ - if (fe->ops.get_property) { - r = fe->ops.get_property(fe, tvp); - if (r < 0) - return r; - } - dtv_property_dump(fe, false, tvp); return 0; diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index 907a05bde162..4d05846f2c1c 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -403,8 +403,6 @@ struct dtv_frontend_properties; * @analog_ops: pointer to struct analog_demod_ops * @set_property: callback function to allow the frontend to validade * incoming properties. Should not be used on new drivers. - * @get_property: callback function to allow the frontend to override - * outcoming properties. Should not be used on new drivers. */ struct dvb_frontend_ops { @@ -468,7 +466,6 @@ struct dvb_frontend_ops { struct analog_demod_ops analog_ops; int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp); - int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp); }; #ifdef __DVB_CORE__ diff --git a/drivers/media/dvb-frontends/lg2160.c b/drivers/media/dvb-frontends/lg2160.c index 5798079add10..9854096839ae 100644 --- a/drivers/media/dvb-frontends/lg2160.c +++ b/drivers/media/dvb-frontends/lg2160.c @@ -1048,16 +1048,6 @@ fail: return ret; } -static int lg216x_get_property(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - - return (DTV_ATSCMH_FIC_VER == tvp->cmd) ? - lg216x_get_frontend(fe, c) : 0; -} - - static int lg2160_set_frontend(struct dvb_frontend *fe) { struct lg216x_state *state = fe->demodulator_priv; @@ -1368,8 +1358,6 @@ static const struct dvb_frontend_ops lg2160_ops = { .init = lg216x_init, .sleep = lg216x_sleep, #endif - .get_property = lg216x_get_property, - .set_frontend = lg2160_set_frontend, .get_frontend = lg216x_get_frontend, .get_tune_settings = lg216x_get_tune_settings, @@ -1396,8 +1384,6 @@ static const struct dvb_frontend_ops lg2161_ops = { .init = lg216x_init, .sleep = lg216x_sleep, #endif - .get_property = lg216x_get_property, - .set_frontend = lg2160_set_frontend, .get_frontend = lg216x_get_frontend, .get_tune_settings = lg216x_get_tune_settings, -- cgit v1.2.3 From 6680e73b5226114992acfc11f9cf5730f706fb01 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 14 Sep 2017 07:44:22 -0400 Subject: media: dvb_frontend: get rid of set_property() callback Now that all clients of set_property() were removed, get rid of this callback. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 7 ------- drivers/media/dvb-core/dvb_frontend.h | 5 ----- 2 files changed, 12 deletions(-) diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index cafc51b303e2..730d9901a977 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -1749,13 +1749,6 @@ static int dtv_property_process_set(struct dvb_frontend *fe, int r = 0; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - /* Allow the frontend to validate incoming properties */ - if (fe->ops.set_property) { - r = fe->ops.set_property(fe, tvp); - if (r < 0) - return r; - } - dtv_property_dump(fe, true, tvp); switch(tvp->cmd) { diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index 4d05846f2c1c..852b91ba49d2 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -401,11 +401,8 @@ struct dtv_frontend_properties; * @search: callback function used on some custom algo search algos. * @tuner_ops: pointer to struct dvb_tuner_ops * @analog_ops: pointer to struct analog_demod_ops - * @set_property: callback function to allow the frontend to validade - * incoming properties. Should not be used on new drivers. */ struct dvb_frontend_ops { - struct dvb_frontend_info info; u8 delsys[MAX_DELSYS]; @@ -464,8 +461,6 @@ struct dvb_frontend_ops { struct dvb_tuner_ops tuner_ops; struct analog_demod_ops analog_ops; - - int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp); }; #ifdef __DVB_CORE__ -- cgit v1.2.3 From 2b5df42b8dec69fb926a242007fd462343db4408 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 18 Sep 2017 06:54:11 -0400 Subject: media: dvb_frontend: cleanup dvb_frontend_ioctl_properties() Use a switch() on this function, just like on other ioctl handlers and handle parameters inside each part of the switch. That makes it easier to integrate with the already existing ioctl handler function. Reviewed-by: Shuah Khan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 83 +++++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 32 deletions(-) diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 730d9901a977..331085e4d426 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -1954,21 +1954,25 @@ static int dvb_frontend_ioctl_properties(struct file *file, struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int err = 0; - - struct dtv_properties *tvps = parg; - struct dtv_property *tvp = NULL; - int i; + int err, i; dev_dbg(fe->dvb->device, "%s:\n", __func__); - if (cmd == FE_SET_PROPERTY) { - dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num); - dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props); + switch(cmd) { + case FE_SET_PROPERTY: { + struct dtv_properties *tvps = parg; + struct dtv_property *tvp = NULL; + + dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", + __func__, tvps->num); + dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", + __func__, tvps->props); - /* Put an arbitrary limit on the number of messages that can - * be sent at once */ - if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) + /* + * Put an arbitrary limit on the number of messages that can + * be sent at once + */ + if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) return -EINVAL; tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); @@ -1977,23 +1981,34 @@ static int dvb_frontend_ioctl_properties(struct file *file, for (i = 0; i < tvps->num; i++) { err = dtv_property_process_set(fe, tvp + i, file); - if (err < 0) - goto out; + if (err < 0) { + kfree(tvp); + return err; + } (tvp + i)->result = err; } if (c->state == DTV_TUNE) dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__); - } else if (cmd == FE_GET_PROPERTY) { + kfree(tvp); + break; + } + case FE_GET_PROPERTY: { + struct dtv_properties *tvps = parg; + struct dtv_property *tvp = NULL; struct dtv_frontend_properties getp = fe->dtv_property_cache; - dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num); - dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props); + dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", + __func__, tvps->num); + dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", + __func__, tvps->props); - /* Put an arbitrary limit on the number of messages that can - * be sent at once */ - if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) + /* + * Put an arbitrary limit on the number of messages that can + * be sent at once + */ + if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) return -EINVAL; tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); @@ -2008,28 +2023,32 @@ static int dvb_frontend_ioctl_properties(struct file *file, */ if (fepriv->state != FESTATE_IDLE) { err = dtv_get_frontend(fe, &getp, NULL); - if (err < 0) - goto out; + if (err < 0) { + kfree(tvp); + return err; + } } for (i = 0; i < tvps->num; i++) { err = dtv_property_process_get(fe, &getp, tvp + i, file); - if (err < 0) - goto out; + if (err < 0) { + kfree(tvp); + return err; + } (tvp + i)->result = err; } if (copy_to_user((void __user *)tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) { - err = -EFAULT; - goto out; + kfree(tvp); + return -EFAULT; } - - } else - err = -EOPNOTSUPP; - -out: - kfree(tvp); - return err; + kfree(tvp); + break; + } + default: + return -ENOTSUPP; + } /* switch */ + return 0; } static int dtv_set_frontend(struct dvb_frontend *fe) -- cgit v1.2.3 From d73dcf0cdb95a47f7e4e991ab63dd30f6eb67b4e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 18 Sep 2017 07:15:13 -0400 Subject: media: dvb_frontend: cleanup ioctl handling logic Currently, there are two handlers for ioctls: - dvb_frontend_ioctl_properties() - dvb_frontend_ioctl_legacy() Despite their names, both handles non-legacy DVB ioctls. Besides that, there's no reason why to not handle all ioctls on a single handler function. So, merge them into a single function (dvb_frontend_handle_ioctl) and reorganize the ioctl's to indicate what's the current DVB API and what's deprecated. Despite the big diff, the handling logic for each ioctl is the same as before. Reviewed-by: Shuah Khan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 328 ++++++++++++++++------------------ 1 file changed, 158 insertions(+), 170 deletions(-) diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 331085e4d426..9911dd91a84d 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -1298,10 +1298,8 @@ static int dtv_get_frontend(struct dvb_frontend *fe, return 0; } -static int dvb_frontend_ioctl_legacy(struct file *file, - unsigned int cmd, void *parg); -static int dvb_frontend_ioctl_properties(struct file *file, - unsigned int cmd, void *parg); +static int dvb_frontend_handle_ioctl(struct file *file, + unsigned int cmd, void *parg); static int dtv_property_process_get(struct dvb_frontend *fe, const struct dtv_frontend_properties *c, @@ -1799,12 +1797,12 @@ static int dtv_property_process_set(struct dvb_frontend *fe, break; case DTV_VOLTAGE: c->voltage = tvp->u.data; - r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE, + r = dvb_frontend_handle_ioctl(file, FE_SET_VOLTAGE, (void *)c->voltage); break; case DTV_TONE: c->sectone = tvp->u.data; - r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE, + r = dvb_frontend_handle_ioctl(file, FE_SET_TONE, (void *)c->sectone); break; case DTV_CODE_RATE_HP: @@ -1911,14 +1909,13 @@ static int dtv_property_process_set(struct dvb_frontend *fe, return r; } -static int dvb_frontend_ioctl(struct file *file, - unsigned int cmd, void *parg) +static int dvb_frontend_ioctl(struct file *file, unsigned int cmd, void *parg) { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_frontend_private *fepriv = fe->frontend_priv; - int err = -EOPNOTSUPP; + int err; dev_dbg(fe->dvb->device, "%s: (%d)\n", __func__, _IOC_NR(cmd)); if (down_interruptible(&fepriv->sem)) @@ -1936,121 +1933,13 @@ static int dvb_frontend_ioctl(struct file *file, return -EPERM; } - if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY)) - err = dvb_frontend_ioctl_properties(file, cmd, parg); - else { - c->state = DTV_UNDEFINED; - err = dvb_frontend_ioctl_legacy(file, cmd, parg); - } + c->state = DTV_UNDEFINED; + err = dvb_frontend_handle_ioctl(file, cmd, parg); up(&fepriv->sem); return err; } -static int dvb_frontend_ioctl_properties(struct file *file, - unsigned int cmd, void *parg) -{ - struct dvb_device *dvbdev = file->private_data; - struct dvb_frontend *fe = dvbdev->priv; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int err, i; - - dev_dbg(fe->dvb->device, "%s:\n", __func__); - - switch(cmd) { - case FE_SET_PROPERTY: { - struct dtv_properties *tvps = parg; - struct dtv_property *tvp = NULL; - - dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", - __func__, tvps->num); - dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", - __func__, tvps->props); - - /* - * Put an arbitrary limit on the number of messages that can - * be sent at once - */ - if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) - return -EINVAL; - - tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); - if (IS_ERR(tvp)) - return PTR_ERR(tvp); - - for (i = 0; i < tvps->num; i++) { - err = dtv_property_process_set(fe, tvp + i, file); - if (err < 0) { - kfree(tvp); - return err; - } - (tvp + i)->result = err; - } - - if (c->state == DTV_TUNE) - dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__); - - kfree(tvp); - break; - } - case FE_GET_PROPERTY: { - struct dtv_properties *tvps = parg; - struct dtv_property *tvp = NULL; - struct dtv_frontend_properties getp = fe->dtv_property_cache; - - dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", - __func__, tvps->num); - dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", - __func__, tvps->props); - - /* - * Put an arbitrary limit on the number of messages that can - * be sent at once - */ - if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) - return -EINVAL; - - tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); - if (IS_ERR(tvp)) - return PTR_ERR(tvp); - - /* - * Let's use our own copy of property cache, in order to - * avoid mangling with DTV zigzag logic, as drivers might - * return crap, if they don't check if the data is available - * before updating the properties cache. - */ - if (fepriv->state != FESTATE_IDLE) { - err = dtv_get_frontend(fe, &getp, NULL); - if (err < 0) { - kfree(tvp); - return err; - } - } - for (i = 0; i < tvps->num; i++) { - err = dtv_property_process_get(fe, &getp, tvp + i, file); - if (err < 0) { - kfree(tvp); - return err; - } - (tvp + i)->result = err; - } - - if (copy_to_user((void __user *)tvps->props, tvp, - tvps->num * sizeof(struct dtv_property))) { - kfree(tvp); - return -EFAULT; - } - kfree(tvp); - break; - } - default: - return -ENOTSUPP; - } /* switch */ - return 0; -} - static int dtv_set_frontend(struct dvb_frontend *fe) { struct dvb_frontend_private *fepriv = fe->frontend_priv; @@ -2188,16 +2077,105 @@ static int dtv_set_frontend(struct dvb_frontend *fe) } -static int dvb_frontend_ioctl_legacy(struct file *file, - unsigned int cmd, void *parg) +static int dvb_frontend_handle_ioctl(struct file *file, + unsigned int cmd, void *parg) { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int err = -EOPNOTSUPP; + int i, err; + + dev_dbg(fe->dvb->device, "%s:\n", __func__); + + switch(cmd) { + case FE_SET_PROPERTY: { + struct dtv_properties *tvps = parg; + struct dtv_property *tvp = NULL; + + dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", + __func__, tvps->num); + dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", + __func__, tvps->props); + + /* + * Put an arbitrary limit on the number of messages that can + * be sent at once + */ + if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) + return -EINVAL; + + tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); + if (IS_ERR(tvp)) + return PTR_ERR(tvp); + + for (i = 0; i < tvps->num; i++) { + err = dtv_property_process_set(fe, tvp + i, file); + if (err < 0) { + kfree(tvp); + return err; + } + (tvp + i)->result = err; + } + + if (c->state == DTV_TUNE) + dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__); + + kfree(tvp); + break; + } + case FE_GET_PROPERTY: { + struct dtv_properties *tvps = parg; + struct dtv_property *tvp = NULL; + struct dtv_frontend_properties getp = fe->dtv_property_cache; + + dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", + __func__, tvps->num); + dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", + __func__, tvps->props); + + /* + * Put an arbitrary limit on the number of messages that can + * be sent at once + */ + if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) + return -EINVAL; + + tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); + if (IS_ERR(tvp)) + return PTR_ERR(tvp); + + /* + * Let's use our own copy of property cache, in order to + * avoid mangling with DTV zigzag logic, as drivers might + * return crap, if they don't check if the data is available + * before updating the properties cache. + */ + if (fepriv->state != FESTATE_IDLE) { + err = dtv_get_frontend(fe, &getp, NULL); + if (err < 0) { + kfree(tvp); + return err; + } + } + for (i = 0; i < tvps->num; i++) { + err = dtv_property_process_get(fe, &getp, tvp + i, file); + if (err < 0) { + kfree(tvp); + return err; + } + (tvp + i)->result = err; + } + + if (copy_to_user((void __user *)tvps->props, tvp, + tvps->num * sizeof(struct dtv_property))) { + kfree(tvp); + return -EFAULT; + } + kfree(tvp); + break; + } - switch (cmd) { case FE_GET_INFO: { struct dvb_frontend_info* info = parg; @@ -2261,42 +2239,6 @@ static int dvb_frontend_ioctl_legacy(struct file *file, break; } - case FE_READ_BER: - if (fe->ops.read_ber) { - if (fepriv->thread) - err = fe->ops.read_ber(fe, (__u32 *) parg); - else - err = -EAGAIN; - } - break; - - case FE_READ_SIGNAL_STRENGTH: - if (fe->ops.read_signal_strength) { - if (fepriv->thread) - err = fe->ops.read_signal_strength(fe, (__u16 *) parg); - else - err = -EAGAIN; - } - break; - - case FE_READ_SNR: - if (fe->ops.read_snr) { - if (fepriv->thread) - err = fe->ops.read_snr(fe, (__u16 *) parg); - else - err = -EAGAIN; - } - break; - - case FE_READ_UNCORRECTED_BLOCKS: - if (fe->ops.read_ucblocks) { - if (fepriv->thread) - err = fe->ops.read_ucblocks(fe, (__u32 *) parg); - else - err = -EAGAIN; - } - break; - case FE_DISEQC_RESET_OVERLOAD: if (fe->ops.diseqc_reset_overload) { err = fe->ops.diseqc_reset_overload(fe); @@ -2348,6 +2290,23 @@ static int dvb_frontend_ioctl_legacy(struct file *file, } break; + case FE_DISEQC_RECV_SLAVE_REPLY: + if (fe->ops.diseqc_recv_slave_reply) + err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg); + break; + + case FE_ENABLE_HIGH_LNB_VOLTAGE: + if (fe->ops.enable_high_lnb_voltage) + err = fe->ops.enable_high_lnb_voltage(fe, (long) parg); + break; + + case FE_SET_FRONTEND_TUNE_MODE: + fepriv->tune_mode_flags = (unsigned long) parg; + err = 0; + break; + + /* DEPRECATED dish control ioctls */ + case FE_DISHNETWORK_SEND_LEGACY_CMD: if (fe->ops.dishnetwork_send_legacy_command) { err = fe->ops.dishnetwork_send_legacy_command(fe, @@ -2413,16 +2372,46 @@ static int dvb_frontend_ioctl_legacy(struct file *file, } break; - case FE_DISEQC_RECV_SLAVE_REPLY: - if (fe->ops.diseqc_recv_slave_reply) - err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg); + /* DEPRECATED statistics ioctls */ + + case FE_READ_BER: + if (fe->ops.read_ber) { + if (fepriv->thread) + err = fe->ops.read_ber(fe, (__u32 *) parg); + else + err = -EAGAIN; + } break; - case FE_ENABLE_HIGH_LNB_VOLTAGE: - if (fe->ops.enable_high_lnb_voltage) - err = fe->ops.enable_high_lnb_voltage(fe, (long) parg); + case FE_READ_SIGNAL_STRENGTH: + if (fe->ops.read_signal_strength) { + if (fepriv->thread) + err = fe->ops.read_signal_strength(fe, (__u16 *) parg); + else + err = -EAGAIN; + } + break; + + case FE_READ_SNR: + if (fe->ops.read_snr) { + if (fepriv->thread) + err = fe->ops.read_snr(fe, (__u16 *) parg); + else + err = -EAGAIN; + } + break; + + case FE_READ_UNCORRECTED_BLOCKS: + if (fe->ops.read_ucblocks) { + if (fepriv->thread) + err = fe->ops.read_ucblocks(fe, (__u32 *) parg); + else + err = -EAGAIN; + } break; + /* DEPRECATED DVBv3 ioctls */ + case FE_SET_FRONTEND: err = dvbv3_set_delivery_system(fe); if (err) @@ -2449,11 +2438,10 @@ static int dvb_frontend_ioctl_legacy(struct file *file, err = dtv_get_frontend(fe, &getp, parg); break; } - case FE_SET_FRONTEND_TUNE_MODE: - fepriv->tune_mode_flags = (unsigned long) parg; - err = 0; - break; - } + + default: + return -ENOTSUPP; + } /* switch */ return err; } -- cgit v1.2.3 From ef2cc27cf860b79874e9fde1419dd67c3372e41c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 18 Sep 2017 07:29:19 -0400 Subject: media: dvb_frontend: get rid of property cache's state In the past, I guess the idea was to use state in order to allow an autofush logic. However, in the current code, it is used only for debug messages, on a poor man's solution, as there's already a debug message to indicate when the properties got flushed. So, just get rid of it for good. Reviewed-by: Shuah Khan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 20 ++++++-------------- drivers/media/dvb-core/dvb_frontend.h | 5 ----- 2 files changed, 6 insertions(+), 19 deletions(-) diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 9911dd91a84d..45d0d488dfcb 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -934,8 +934,6 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) memset(c, 0, offsetof(struct dtv_frontend_properties, strength)); c->delivery_system = delsys; - c->state = DTV_CLEAR; - dev_dbg(fe->dvb->device, "%s: Clearing cache for delivery system %d\n", __func__, c->delivery_system); @@ -1758,13 +1756,13 @@ static int dtv_property_process_set(struct dvb_frontend *fe, dvb_frontend_clear_cache(fe); break; case DTV_TUNE: - /* interpret the cache of data, build either a traditional frontend - * tunerequest so we can pass validation in the FE_SET_FRONTEND - * ioctl. + /* + * Use the cached Digital TV properties to tune the + * frontend */ - c->state = tvp->cmd; - dev_dbg(fe->dvb->device, "%s: Finalised property cache\n", - __func__); + dev_dbg(fe->dvb->device, + "%s: Setting the frontend from property cache\n", + __func__); r = dtv_set_frontend(fe); break; @@ -1913,7 +1911,6 @@ static int dvb_frontend_ioctl(struct file *file, unsigned int cmd, void *parg) { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_frontend_private *fepriv = fe->frontend_priv; int err; @@ -1933,7 +1930,6 @@ static int dvb_frontend_ioctl(struct file *file, unsigned int cmd, void *parg) return -EPERM; } - c->state = DTV_UNDEFINED; err = dvb_frontend_handle_ioctl(file, cmd, parg); up(&fepriv->sem); @@ -2117,10 +2113,6 @@ static int dvb_frontend_handle_ioctl(struct file *file, } (tvp + i)->result = err; } - - if (c->state == DTV_TUNE) - dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__); - kfree(tvp); break; } diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index 852b91ba49d2..1bdeb10f0d78 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -620,11 +620,6 @@ struct dtv_frontend_properties { struct dtv_fe_stats post_bit_count; struct dtv_fe_stats block_error; struct dtv_fe_stats block_count; - - /* private: */ - /* Cache State */ - u32 state; - }; #define DVB_FE_NO_EXIT 0 -- cgit v1.2.3 From ceb22c8eeecaf51f88a49202d00ea599b9e15477 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 18 Sep 2017 07:32:44 -0400 Subject: media: dvb_frontend.h: fix alignment at the cache properties There are too much tabs on several properties, for no good reason. That sounds confusing while reading the struct, so adjust them. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index 1bdeb10f0d78..d273ed2f72c9 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -557,15 +557,15 @@ struct dtv_frontend_properties { enum fe_sec_voltage voltage; enum fe_sec_tone_mode sectone; - enum fe_spectral_inversion inversion; - enum fe_code_rate fec_inner; + enum fe_spectral_inversion inversion; + enum fe_code_rate fec_inner; enum fe_transmit_mode transmission_mode; u32 bandwidth_hz; /* 0 = AUTO */ enum fe_guard_interval guard_interval; - enum fe_hierarchy hierarchy; + enum fe_hierarchy hierarchy; u32 symbol_rate; - enum fe_code_rate code_rate_HP; - enum fe_code_rate code_rate_LP; + enum fe_code_rate code_rate_HP; + enum fe_code_rate code_rate_LP; enum fe_pilot pilot; enum fe_rolloff rolloff; -- cgit v1.2.3 From da5516b5e81d45a96291823620f6c820178dc055 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 18 Sep 2017 08:05:42 -0400 Subject: media: dvb_frontend: better document the -EPERM condition Two readonly ioctls can't be allowed if the frontend device is opened in read only mode. Explain why. Reviewed by: Shuah Khan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 45d0d488dfcb..b19f40be0ab2 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -1923,9 +1923,23 @@ static int dvb_frontend_ioctl(struct file *file, unsigned int cmd, void *parg) return -ENODEV; } - if ((file->f_flags & O_ACCMODE) == O_RDONLY && - (_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT || - cmd == FE_DISEQC_RECV_SLAVE_REPLY)) { + /* + * If the frontend is opened in read-only mode, only the ioctls + * that don't interfere with the tune logic should be accepted. + * That allows an external application to monitor the DVB QoS and + * statistics parameters. + * + * That matches all _IOR() ioctls, except for two special cases: + * - FE_GET_EVENT is part of the tuning logic on a DVB application; + * - FE_DISEQC_RECV_SLAVE_REPLY is part of DiSEqC 2.0 + * setup + * So, those two ioctls should also return -EPERM, as otherwise + * reading from them would interfere with a DVB tune application + */ + if ((file->f_flags & O_ACCMODE) == O_RDONLY + && (_IOC_DIR(cmd) != _IOC_READ + || cmd == FE_GET_EVENT + || cmd == FE_DISEQC_RECV_SLAVE_REPLY)) { up(&fepriv->sem); return -EPERM; } -- cgit v1.2.3 From 259a41d9ae8f3689742267f340ad2b159d00b302 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 18 Sep 2017 08:21:37 -0400 Subject: media: dvb_frontend: fix return values for FE_SET_PROPERTY There are several problems with regards to the return of FE_SET_PROPERTY. The original idea were to return per-property return codes via tvp->result field, and to return an updated set of values. However, that never worked. What's actually implemented is: - the FE_SET_PROPERTY implementation doesn't call .get_frontend callback in order to get the actual parameters after return; - the tvp->result field is only filled if there's no error. So, it is always filled with zero; - FE_SET_PROPERTY doesn't call memdup_user() nor any other copy_to_user() function. So, any changes to the properties will be lost; - FE_SET_PROPERTY is declared as a write-only ioctl (IOW). While we could fix the above, it could cause regressions. So, let's just assume what the code really does, updating the documentation accordingly and removing the logic that would update the discarded tvp->result. Reviewed-by: Shuah Khan Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/uapi/dvb/fe-get-property.rst | 7 +++++-- drivers/media/dvb-core/dvb_frontend.c | 2 -- include/uapi/linux/dvb/frontend.h | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Documentation/media/uapi/dvb/fe-get-property.rst b/Documentation/media/uapi/dvb/fe-get-property.rst index 948d2ba84f2c..b69741d9cedf 100644 --- a/Documentation/media/uapi/dvb/fe-get-property.rst +++ b/Documentation/media/uapi/dvb/fe-get-property.rst @@ -48,8 +48,11 @@ depends on the delivery system and on the device: - This call requires read/write access to the device. - - At return, the values are updated to reflect the actual parameters - used. +.. note:: + + At return, the values aren't updated to reflect the actual + parameters used. If the actual parameters are needed, an explicit + call to ``FE_GET_PROPERTY`` is needed. - ``FE_GET_PROPERTY:`` diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index b19f40be0ab2..5e3bcae477d2 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -2125,7 +2125,6 @@ static int dvb_frontend_handle_ioctl(struct file *file, kfree(tvp); return err; } - (tvp + i)->result = err; } kfree(tvp); break; @@ -2170,7 +2169,6 @@ static int dvb_frontend_handle_ioctl(struct file *file, kfree(tvp); return err; } - (tvp + i)->result = err; } if (copy_to_user((void __user *)tvps->props, tvp, diff --git a/include/uapi/linux/dvb/frontend.h b/include/uapi/linux/dvb/frontend.h index 861cacd5711f..6bc26f35217b 100644 --- a/include/uapi/linux/dvb/frontend.h +++ b/include/uapi/linux/dvb/frontend.h @@ -830,7 +830,7 @@ struct dtv_fe_stats { * @cmd: Digital TV command. * @reserved: Not used. * @u: Union with the values for the command. - * @result: Result of the command set (currently unused). + * @result: Unused * * The @u union may have either one of the values below: * -- cgit v1.2.3 From 6bbf7a855d200ddd83494a9ceb95f9465f953f59 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Sep 2017 14:22:19 -0400 Subject: media: dvbdev: convert DVB device types into an enum Enums can be documented via kernel-doc. So, convert the DVB_DEVICE_* macros to an enum. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvbdev.c | 34 +++++++++++++++++++++++---- drivers/media/dvb-core/dvbdev.h | 51 ++++++++++++++++++++++++++++------------- 2 files changed, 64 insertions(+), 21 deletions(-) diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index 41aad0f99d73..a53eb53a4fd5 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -51,8 +51,15 @@ static LIST_HEAD(dvb_adapter_list); static DEFINE_MUTEX(dvbdev_register_lock); static const char * const dnames[] = { - "video", "audio", "sec", "frontend", "demux", "dvr", "ca", - "net", "osd" + [DVB_DEVICE_VIDEO] = "video", + [DVB_DEVICE_AUDIO] = "audio", + [DVB_DEVICE_SEC] = "sec", + [DVB_DEVICE_FRONTEND] = "frontend", + [DVB_DEVICE_DEMUX] = "demux", + [DVB_DEVICE_DVR] = "dvr", + [DVB_DEVICE_CA] = "ca", + [DVB_DEVICE_NET] = "net", + [DVB_DEVICE_OSD] = "osd" }; #ifdef CONFIG_DVB_DYNAMIC_MINORS @@ -60,7 +67,24 @@ static const char * const dnames[] = { #define DVB_MAX_IDS MAX_DVB_MINORS #else #define DVB_MAX_IDS 4 -#define nums2minor(num, type, id) ((num << 6) | (id << 4) | type) + +static int nums2minor(int num, enum dvb_device_type type, int id) +{ + int n = (num << 6) | (id << 4); + + switch (type) { + case DVB_DEVICE_VIDEO: return n; + case DVB_DEVICE_AUDIO: return n | 1; + case DVB_DEVICE_SEC: return n | 2; + case DVB_DEVICE_FRONTEND: return n | 3; + case DVB_DEVICE_DEMUX: return n | 4; + case DVB_DEVICE_DVR: return n | 5; + case DVB_DEVICE_CA: return n | 6; + case DVB_DEVICE_NET: return n | 7; + case DVB_DEVICE_OSD: return n | 8; + } +} + #define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64) #endif @@ -426,8 +450,8 @@ static int dvb_register_media_device(struct dvb_device *dvbdev, } int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, - const struct dvb_device *template, void *priv, int type, - int demux_sink_pads) + const struct dvb_device *template, void *priv, + enum dvb_device_type type, int demux_sink_pads) { struct dvb_device *dvbdev; struct file_operations *dvbdevfops; diff --git a/drivers/media/dvb-core/dvbdev.h b/drivers/media/dvb-core/dvbdev.h index 49189392cf3b..53058da83873 100644 --- a/drivers/media/dvb-core/dvbdev.h +++ b/drivers/media/dvb-core/dvbdev.h @@ -35,15 +35,37 @@ #define DVB_UNSET (-1) -#define DVB_DEVICE_VIDEO 0 -#define DVB_DEVICE_AUDIO 1 -#define DVB_DEVICE_SEC 2 -#define DVB_DEVICE_FRONTEND 3 -#define DVB_DEVICE_DEMUX 4 -#define DVB_DEVICE_DVR 5 -#define DVB_DEVICE_CA 6 -#define DVB_DEVICE_NET 7 -#define DVB_DEVICE_OSD 8 +/* List of DVB device types */ + +/** + * enum dvb_device_type - type of the Digital TV device + * + * @DVB_DEVICE_SEC: Digital TV standalone Common Interface (CI) + * @DVB_DEVICE_FRONTEND: Digital TV frontend. + * @DVB_DEVICE_DEMUX: Digital TV demux. + * @DVB_DEVICE_DVR: Digital TV digital video record (DVR). + * @DVB_DEVICE_CA: Digital TV Conditional Access (CA). + * @DVB_DEVICE_NET: Digital TV network. + * + * @DVB_DEVICE_VIDEO: Digital TV video decoder. + * Deprecated. Used only on av7110-av. + * @DVB_DEVICE_AUDIO: Digital TV audio decoder. + * Deprecated. Used only on av7110-av. + * @DVB_DEVICE_OSD: Digital TV On Screen Display (OSD). + * Deprecated. Used only on av7110. + */ +enum dvb_device_type { + DVB_DEVICE_SEC, + DVB_DEVICE_FRONTEND, + DVB_DEVICE_DEMUX, + DVB_DEVICE_DVR, + DVB_DEVICE_CA, + DVB_DEVICE_NET, + + DVB_DEVICE_VIDEO, + DVB_DEVICE_AUDIO, + DVB_DEVICE_OSD, +}; #define DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr) \ static short adapter_nr[] = \ @@ -104,8 +126,7 @@ struct dvb_adapter { * @list_head: List head with all DVB devices * @fops: pointer to struct file_operations * @adapter: pointer to the adapter that holds this device node - * @type: type of the device: DVB_DEVICE_SEC, DVB_DEVICE_FRONTEND, - * DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_CA, DVB_DEVICE_NET + * @type: type of the device, as defined by &enum dvb_device_type. * @minor: devnode minor number. Major number is always DVB_MAJOR. * @id: device ID number, inside the adapter * @readers: Initialized by the caller. Each call to open() in Read Only mode @@ -135,7 +156,7 @@ struct dvb_device { struct list_head list_head; const struct file_operations *fops; struct dvb_adapter *adapter; - int type; + enum dvb_device_type type; int minor; u32 id; @@ -194,9 +215,7 @@ int dvb_unregister_adapter(struct dvb_adapter *adap); * stored * @template: Template used to create &pdvbdev; * @priv: private data - * @type: type of the device: %DVB_DEVICE_SEC, %DVB_DEVICE_FRONTEND, - * %DVB_DEVICE_DEMUX, %DVB_DEVICE_DVR, %DVB_DEVICE_CA, - * %DVB_DEVICE_NET + * @type: type of the device, as defined by &enum dvb_device_type. * @demux_sink_pads: Number of demux outputs, to be used to create the TS * outputs via the Media Controller. */ @@ -204,7 +223,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, const struct dvb_device *template, void *priv, - int type, + enum dvb_device_type type, int demux_sink_pads); /** -- cgit v1.2.3 From 400efa8e4e7b01a8f9898669199a42c126ca608d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Sep 2017 16:11:55 -0400 Subject: media: dvbdev: fully document its functions There are several functions at the dvbdev that are common to all digital TV device nodes with aren't documented. Add documentation for them. No functional changes. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvbdev.h | 86 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 8 deletions(-) diff --git a/drivers/media/dvb-core/dvbdev.h b/drivers/media/dvb-core/dvbdev.h index 53058da83873..bbc1c20c0529 100644 --- a/drivers/media/dvb-core/dvbdev.h +++ b/drivers/media/dvb-core/dvbdev.h @@ -261,7 +261,7 @@ void dvb_unregister_device(struct dvb_device *dvbdev); * dvb_create_media_graph - Creates media graph for the Digital TV part of the * device. * - * @adap: pointer to struct dvb_adapter + * @adap: pointer to &struct dvb_adapter * @create_rf_connector: if true, it creates the RF connector too * * This function checks all DVB-related functions at the media controller @@ -274,12 +274,23 @@ void dvb_unregister_device(struct dvb_device *dvbdev); __must_check int dvb_create_media_graph(struct dvb_adapter *adap, bool create_rf_connector); +/** + * dvb_register_media_controller - registers a media controller at DVB adapter + * + * @adap: pointer to &struct dvb_adapter + * @mdev: pointer to &struct media_device + */ static inline void dvb_register_media_controller(struct dvb_adapter *adap, struct media_device *mdev) { adap->mdev = mdev; } +/** + * dvb_get_media_controller - gets the associated media controller + * + * @adap: pointer to &struct dvb_adapter + */ static inline struct media_device *dvb_get_media_controller(struct dvb_adapter *adap) { @@ -296,20 +307,71 @@ int dvb_create_media_graph(struct dvb_adapter *adap, #define dvb_get_media_controller(a) NULL #endif -int dvb_generic_open (struct inode *inode, struct file *file); -int dvb_generic_release (struct inode *inode, struct file *file); -long dvb_generic_ioctl (struct file *file, - unsigned int cmd, unsigned long arg); +/** + * dvb_generic_open - Digital TV open function, used by DVB devices + * + * @inode: pointer to &struct inode. + * @file: pointer to &struct file. + * + * Checks if a DVB devnode is still valid, and if the permissions are + * OK and increment negative use count. + */ +int dvb_generic_open(struct inode *inode, struct file *file); -/* we don't mess with video_usercopy() any more, -we simply define out own dvb_usercopy(), which will hopefully become -generic_usercopy() someday... */ +/** + * dvb_generic_close - Digital TV close function, used by DVB devices + * + * @inode: pointer to &struct inode. + * @file: pointer to &struct file. + * + * Checks if a DVB devnode is still valid, and if the permissions are + * OK and decrement negative use count. + */ +int dvb_generic_release(struct inode *inode, struct file *file); +/** + * dvb_generic_ioctl - Digital TV close function, used by DVB devices + * + * @file: pointer to &struct file. + * @cmd: Ioctl name. + * @arg: Ioctl argument. + * + * Checks if a DVB devnode and struct dvbdev.kernel_ioctl is still valid. + * If so, calls dvb_usercopy(). + */ +long dvb_generic_ioctl(struct file *file, + unsigned int cmd, unsigned long arg); + +/** + * dvb_usercopy - copies data from/to userspace memory when an ioctl is + * issued. + * + * @file: Pointer to struct &file. + * @cmd: Ioctl name. + * @arg: Ioctl argument. + * @func: function that will actually handle the ioctl + * + * Ancillary function that uses ioctl direction and size to copy from + * userspace. Then, it calls @func, and, if needed, data is copied back + * to userspace. + */ int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg, int (*func)(struct file *file, unsigned int cmd, void *arg)); /** generic DVB attach function. */ #ifdef CONFIG_MEDIA_ATTACH + +/** + * dvb_attach - attaches a DVB frontend into the DVB core. + * + * @FUNCTION: function on a frontend module to be called. + * @ARGS...: @FUNCTION arguments. + * + * This ancillary function loads a frontend module in runtime and runs + * the @FUNCTION function there, with @ARGS. + * As it increments symbol usage cont, at unregister, dvb_detach() + * should be called. + */ #define dvb_attach(FUNCTION, ARGS...) ({ \ void *__r = NULL; \ typeof(&FUNCTION) __a = symbol_request(FUNCTION); \ @@ -323,6 +385,14 @@ int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg, __r; \ }) +/** + * dvb_detach - detaches a DVB frontend loaded via dvb_attach() + * + * @FUNC: attach function + * + * Decrements usage count for a function previously called via dvb_attach(). + */ + #define dvb_detach(FUNC) symbol_put_addr(FUNC) #else -- cgit v1.2.3 From 6009367e0d52959aec52a6646f3f0c12856c003f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Sep 2017 16:40:33 -0400 Subject: media: dvb_frontend.h: improve kernel-doc markups Several minor adjustments at the kernel-doc markups: - some syntax fixes; - some cross-references; - add cross-references for the mentioned ioctls; - some constants marked as such. No functional changes. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.h | 94 +++++++++++++++++------------------ 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index d273ed2f72c9..ace0c2fb26c2 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -180,8 +180,8 @@ enum dvbfe_search { /** * struct dvb_tuner_ops - Tuner information and callbacks * - * @info: embedded struct dvb_tuner_info with tuner properties - * @release: callback function called when frontend is dettached. + * @info: embedded &struct dvb_tuner_info with tuner properties + * @release: callback function called when frontend is detached. * drivers should free any allocated memory. * @init: callback function used to initialize the tuner device. * @sleep: callback function used to put the tuner to sleep. @@ -191,14 +191,14 @@ enum dvbfe_search { * resuming from suspend. * @set_params: callback function used to inform the tuner to tune * into a digital TV channel. The properties to be used - * are stored at @dvb_frontend.dtv_property_cache;. The - * tuner demod can change the parameters to reflect the - * changes needed for the channel to be tuned, and + * are stored at &struct dvb_frontend.dtv_property_cache. + * The tuner demod can change the parameters to reflect + * the changes needed for the channel to be tuned, and * update statistics. This is the recommended way to set * the tuner parameters and should be used on newer * drivers. * @set_analog_params: callback function used to tune into an analog TV - * channel on hybrid tuners. It passes @analog_parameters; + * channel on hybrid tuners. It passes @analog_parameters * to the driver. * @set_config: callback function used to send some tuner-specific * parameters. @@ -207,9 +207,9 @@ enum dvbfe_search { * @get_if_frequency: get the Intermediate Frequency, in Hz. For baseband, * should return 0. * @get_status: returns the frontend lock status - * @get_rf_strength: returns the RF signal strengh. Used mostly to support + * @get_rf_strength: returns the RF signal strength. Used mostly to support * analog TV and radio. Digital TV should report, instead, - * via DVBv5 API (@dvb_frontend.dtv_property_cache;). + * via DVBv5 API (&struct dvb_frontend.dtv_property_cache). * @get_afc: Used only by analog TV core. Reports the frequency * drift due to AFC. * @calc_regs: callback function used to pass register data settings @@ -217,7 +217,7 @@ enum dvbfe_search { * @set_frequency: Set a new frequency. Shouldn't be used on newer drivers. * @set_bandwidth: Set a new frequency. Shouldn't be used on newer drivers. * - * NOTE: frequencies used on get_frequency and set_frequency are in Hz for + * NOTE: frequencies used on @get_frequency and @set_frequency are in Hz for * terrestrial/cable or kHz for satellite. * */ @@ -283,14 +283,14 @@ struct analog_demod_info { * @set_params: callback function used to inform the demod to set the * demodulator parameters needed to decode an analog or * radio channel. The properties are passed via - * struct @analog_params;. + * &struct analog_params. * @has_signal: returns 0xffff if has signal, or 0 if it doesn't. * @get_afc: Used only by analog TV core. Reports the frequency * drift due to AFC. * @tuner_status: callback function that returns tuner status bits, e. g. - * TUNER_STATUS_LOCKED and TUNER_STATUS_STEREO. + * %TUNER_STATUS_LOCKED and %TUNER_STATUS_STEREO. * @standby: set the tuner to standby mode. - * @release: callback function called when frontend is dettached. + * @release: callback function called when frontend is detached. * drivers should free any allocated memory. * @i2c_gate_ctrl: controls the I2C gate. Newer drivers should use I2C * mux support instead. @@ -321,10 +321,10 @@ struct dtv_frontend_properties; * struct dvb_frontend_ops - Demodulation information and callbacks for * ditialt TV * - * @info: embedded struct dvb_tuner_info with tuner properties + * @info: embedded &struct dvb_tuner_info with tuner properties * @delsys: Delivery systems supported by the frontend * @detach: callback function called when frontend is detached. - * drivers should clean up, but not yet free the struct + * drivers should clean up, but not yet free the &struct * dvb_frontend allocation. * @release: callback function called when frontend is ready to be * freed. @@ -338,57 +338,57 @@ struct dtv_frontend_properties; * allow other drivers to write data into their registers. * Should not be used on new drivers. * @tune: callback function used by demod drivers that use - * @DVBFE_ALGO_HW; to tune into a frequency. + * @DVBFE_ALGO_HW to tune into a frequency. * @get_frontend_algo: returns the desired hardware algorithm. * @set_frontend: callback function used to inform the demod to set the * parameters for demodulating a digital TV channel. - * The properties to be used are stored at - * @dvb_frontend.dtv_property_cache;. The demod can change + * The properties to be used are stored at &struct + * dvb_frontend.dtv_property_cache. The demod can change * the parameters to reflect the changes needed for the * channel to be decoded, and update statistics. * @get_tune_settings: callback function * @get_frontend: callback function used to inform the parameters * actuall in use. The properties to be used are stored at - * @dvb_frontend.dtv_property_cache; and update + * &struct dvb_frontend.dtv_property_cache and update * statistics. Please notice that it should not return * an error code if the statistics are not available * because the demog is not locked. * @read_status: returns the locking status of the frontend. * @read_ber: legacy callback function to return the bit error rate. * Newer drivers should provide such info via DVBv5 API, - * e. g. @set_frontend;/@get_frontend;, implementing this + * e. g. @set_frontend;/@get_frontend, implementing this * callback only if DVBv3 API compatibility is wanted. * @read_signal_strength: legacy callback function to return the signal * strength. Newer drivers should provide such info via - * DVBv5 API, e. g. @set_frontend;/@get_frontend;, + * DVBv5 API, e. g. @set_frontend/@get_frontend, * implementing this callback only if DVBv3 API * compatibility is wanted. * @read_snr: legacy callback function to return the Signal/Noise * rate. Newer drivers should provide such info via - * DVBv5 API, e. g. @set_frontend;/@get_frontend;, + * DVBv5 API, e. g. @set_frontend/@get_frontend, * implementing this callback only if DVBv3 API * compatibility is wanted. * @read_ucblocks: legacy callback function to return the Uncorrected Error * Blocks. Newer drivers should provide such info via - * DVBv5 API, e. g. @set_frontend;/@get_frontend;, + * DVBv5 API, e. g. @set_frontend/@get_frontend, * implementing this callback only if DVBv3 API * compatibility is wanted. * @diseqc_reset_overload: callback function to implement the - * FE_DISEQC_RESET_OVERLOAD ioctl (only Satellite) + * FE_DISEQC_RESET_OVERLOAD() ioctl (only Satellite) * @diseqc_send_master_cmd: callback function to implement the - * FE_DISEQC_SEND_MASTER_CMD ioctl (only Satellite). + * FE_DISEQC_SEND_MASTER_CMD() ioctl (only Satellite). * @diseqc_recv_slave_reply: callback function to implement the - * FE_DISEQC_RECV_SLAVE_REPLY ioctl (only Satellite) + * FE_DISEQC_RECV_SLAVE_REPLY() ioctl (only Satellite) * @diseqc_send_burst: callback function to implement the - * FE_DISEQC_SEND_BURST ioctl (only Satellite). + * FE_DISEQC_SEND_BURST() ioctl (only Satellite). * @set_tone: callback function to implement the - * FE_SET_TONE ioctl (only Satellite). + * FE_SET_TONE() ioctl (only Satellite). * @set_voltage: callback function to implement the - * FE_SET_VOLTAGE ioctl (only Satellite). + * FE_SET_VOLTAGE() ioctl (only Satellite). * @enable_high_lnb_voltage: callback function to implement the - * FE_ENABLE_HIGH_LNB_VOLTAGE ioctl (only Satellite). + * FE_ENABLE_HIGH_LNB_VOLTAGE() ioctl (only Satellite). * @dishnetwork_send_legacy_command: callback function to implement the - * FE_DISHNETWORK_SEND_LEGACY_CMD ioctl (only Satellite). + * FE_DISHNETWORK_SEND_LEGACY_CMD() ioctl (only Satellite). * Drivers should not use this, except when the DVB * core emulation fails to provide proper support (e.g. * if @set_voltage takes more than 8ms to work), and @@ -399,8 +399,8 @@ struct dtv_frontend_properties; * @ts_bus_ctrl: callback function used to take control of the TS bus. * @set_lna: callback function to power on/off/auto the LNA. * @search: callback function used on some custom algo search algos. - * @tuner_ops: pointer to struct dvb_tuner_ops - * @analog_ops: pointer to struct analog_demod_ops + * @tuner_ops: pointer to &struct dvb_tuner_ops + * @analog_ops: pointer to &struct analog_demod_ops */ struct dvb_frontend_ops { struct dvb_frontend_info info; @@ -630,16 +630,16 @@ struct dtv_frontend_properties { /** * struct dvb_frontend - Frontend structure to be used on drivers. * - * @refcount: refcount to keep track of struct dvb_frontend + * @refcount: refcount to keep track of &struct dvb_frontend * references - * @ops: embedded struct dvb_frontend_ops - * @dvb: pointer to struct dvb_adapter + * @ops: embedded &struct dvb_frontend_ops + * @dvb: pointer to &struct dvb_adapter * @demodulator_priv: demod private data * @tuner_priv: tuner private data * @frontend_priv: frontend private data * @sec_priv: SEC private data * @analog_demod_priv: Analog demod private data - * @dtv_property_cache: embedded struct dtv_frontend_properties + * @dtv_property_cache: embedded &struct dtv_frontend_properties * @callback: callback function used on some drivers to call * either the tuner or the demodulator. * @id: Frontend ID @@ -668,8 +668,8 @@ struct dvb_frontend { /** * dvb_register_frontend() - Registers a DVB frontend at the adapter * - * @dvb: pointer to the dvb adapter - * @fe: pointer to the frontend struct + * @dvb: pointer to &struct dvb_adapter + * @fe: pointer to &struct dvb_frontend * * Allocate and initialize the private data needed by the frontend core to * manage the frontend and calls dvb_register_device() to register a new @@ -682,7 +682,7 @@ int dvb_register_frontend(struct dvb_adapter *dvb, /** * dvb_unregister_frontend() - Unregisters a DVB frontend * - * @fe: pointer to the frontend struct + * @fe: pointer to &struct dvb_frontend * * Stops the frontend kthread, calls dvb_unregister_device() and frees the * private frontend data allocated by dvb_register_frontend(). @@ -696,14 +696,14 @@ int dvb_unregister_frontend(struct dvb_frontend *fe); /** * dvb_frontend_detach() - Detaches and frees frontend specific data * - * @fe: pointer to the frontend struct + * @fe: pointer to &struct dvb_frontend * * This function should be called after dvb_unregister_frontend(). It * calls the SEC, tuner and demod release functions: * &dvb_frontend_ops.release_sec, &dvb_frontend_ops.tuner_ops.release, * &dvb_frontend_ops.analog_ops.release and &dvb_frontend_ops.release. * - * If the driver is compiled with CONFIG_MEDIA_ATTACH, it also decreases + * If the driver is compiled with %CONFIG_MEDIA_ATTACH, it also decreases * the module reference count, needed to allow userspace to remove the * previously used DVB frontend modules. */ @@ -712,7 +712,7 @@ void dvb_frontend_detach(struct dvb_frontend *fe); /** * dvb_frontend_suspend() - Suspends a Digital TV frontend * - * @fe: pointer to the frontend struct + * @fe: pointer to &struct dvb_frontend * * This function prepares a Digital TV frontend to suspend. * @@ -730,7 +730,7 @@ int dvb_frontend_suspend(struct dvb_frontend *fe); /** * dvb_frontend_resume() - Resumes a Digital TV frontend * - * @fe: pointer to the frontend struct + * @fe: pointer to &struct dvb_frontend * * This function resumes the usual operation of the tuner after resume. * @@ -751,7 +751,7 @@ int dvb_frontend_resume(struct dvb_frontend *fe); /** * dvb_frontend_reinitialise() - forces a reinitialisation at the frontend * - * @fe: pointer to the frontend struct + * @fe: pointer to &struct dvb_frontend * * Calls &dvb_frontend_ops.init\(\) and &dvb_frontend_ops.tuner_ops.init\(\), * and resets SEC tone and voltage (for Satellite systems). @@ -766,16 +766,16 @@ void dvb_frontend_reinitialise(struct dvb_frontend *fe); * dvb_frontend_sleep_until() - Sleep for the amount of time given by * add_usec parameter * - * @waketime: pointer to a struct ktime_t + * @waketime: pointer to &struct ktime_t * @add_usec: time to sleep, in microseconds * * This function is used to measure the time required for the - * %FE_DISHNETWORK_SEND_LEGACY_CMD ioctl to work. It needs to be as precise + * FE_DISHNETWORK_SEND_LEGACY_CMD() ioctl to work. It needs to be as precise * as possible, as it affects the detection of the dish tone command at the * satellite subsystem. * * Its used internally by the DVB frontend core, in order to emulate - * %FE_DISHNETWORK_SEND_LEGACY_CMD using the &dvb_frontend_ops.set_voltage\(\) + * FE_DISHNETWORK_SEND_LEGACY_CMD() using the &dvb_frontend_ops.set_voltage\(\) * callback. * * NOTE: it should not be used at the drivers, as the emulation for the -- cgit v1.2.3 From 7af90c04cc8343fb8063d0b3d7ba135daf3aabde Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Sep 2017 16:46:10 -0400 Subject: media: dtv-core.rst: add chapters and introductory tests for common parts Better document the DVB common parts by adding two sections and an introductory text for each. Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/kapi/dtv-core.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Documentation/media/kapi/dtv-core.rst b/Documentation/media/kapi/dtv-core.rst index de9a228aca8a..4cf9cf63bafd 100644 --- a/Documentation/media/kapi/dtv-core.rst +++ b/Documentation/media/kapi/dtv-core.rst @@ -29,8 +29,20 @@ I2C bus. Digital TV Common functions --------------------------- +Math functions +~~~~~~~~~~~~~~ + +Provide some commonly-used math functions, usually required in order to +estimate signal strength and signal to noise measurements in dB. + .. kernel-doc:: drivers/media/dvb-core/dvb_math.h + +DVB devices +~~~~~~~~~~~ + +Those functions are responsible for handling the DVB device nodes. + .. kernel-doc:: drivers/media/dvb-core/dvbdev.h Digital TV Ring buffer -- cgit v1.2.3 From 5b3b8c81b47aa3ca473d310b1aa3ab93f0ec9c6b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Sep 2017 16:54:15 -0400 Subject: media: dtv-core.rst: split into multiple files Instead of document all kAPI into a single file, split it on multiple ones. That makes easier to maintain each part. As a side effect, it will produce multiple html pages, with is a good idea. No changes at the text. Just some chapter levels changed. Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/kapi/dtv-ca.rst | 4 + Documentation/media/kapi/dtv-common.rst | 55 +++ Documentation/media/kapi/dtv-core.rst | 585 +----------------------------- Documentation/media/kapi/dtv-demux.rst | 71 ++++ Documentation/media/kapi/dtv-frontend.rst | 443 ++++++++++++++++++++++ 5 files changed, 579 insertions(+), 579 deletions(-) create mode 100644 Documentation/media/kapi/dtv-ca.rst create mode 100644 Documentation/media/kapi/dtv-common.rst create mode 100644 Documentation/media/kapi/dtv-demux.rst create mode 100644 Documentation/media/kapi/dtv-frontend.rst diff --git a/Documentation/media/kapi/dtv-ca.rst b/Documentation/media/kapi/dtv-ca.rst new file mode 100644 index 000000000000..a4dd700189b0 --- /dev/null +++ b/Documentation/media/kapi/dtv-ca.rst @@ -0,0 +1,4 @@ +Digital TV Conditional Access kABI +---------------------------------- + +.. kernel-doc:: drivers/media/dvb-core/dvb_ca_en50221.h diff --git a/Documentation/media/kapi/dtv-common.rst b/Documentation/media/kapi/dtv-common.rst new file mode 100644 index 000000000000..40cf1033b5e1 --- /dev/null +++ b/Documentation/media/kapi/dtv-common.rst @@ -0,0 +1,55 @@ +Digital TV Common functions +--------------------------- + +Math functions +~~~~~~~~~~~~~~ + +Provide some commonly-used math functions, usually required in order to +estimate signal strength and signal to noise measurements in dB. + +.. kernel-doc:: drivers/media/dvb-core/dvb_math.h + + +DVB devices +~~~~~~~~~~~ + +Those functions are responsible for handling the DVB device nodes. + +.. kernel-doc:: drivers/media/dvb-core/dvbdev.h + +Digital TV Ring buffer +~~~~~~~~~~~~~~~~~~~~~~ + +Those routines implement ring buffers used to handle digital TV data and +copy it from/to userspace. + +.. note:: + + 1) For performance reasons read and write routines don't check buffer sizes + and/or number of bytes free/available. This has to be done before these + routines are called. For example: + + .. code-block:: c + + /* write @buflen: bytes */ + free = dvb_ringbuffer_free(rbuf); + if (free >= buflen) + count = dvb_ringbuffer_write(rbuf, buffer, buflen); + else + /* do something */ + + /* read min. 1000, max. @bufsize: bytes */ + avail = dvb_ringbuffer_avail(rbuf); + if (avail >= 1000) + count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize)); + else + /* do something */ + + 2) If there is exactly one reader and one writer, there is no need + to lock read or write operations. + Two or more readers must be locked against each other. + Flushing the buffer counts as a read operation. + Resetting the buffer counts as a read and write operation. + Two or more writers must be locked against each other. + +.. kernel-doc:: drivers/media/dvb-core/dvb_ringbuffer.h diff --git a/Documentation/media/kapi/dtv-core.rst b/Documentation/media/kapi/dtv-core.rst index 4cf9cf63bafd..8ee384f61fa0 100644 --- a/Documentation/media/kapi/dtv-core.rst +++ b/Documentation/media/kapi/dtv-core.rst @@ -26,584 +26,11 @@ I2C bus. abandoned standard, not used anymore) and ATSC version 3.0 current proposals. Currently, the DVB subsystem doesn't implement those standards. -Digital TV Common functions ---------------------------- -Math functions -~~~~~~~~~~~~~~ +.. toctree:: + :maxdepth: 1 -Provide some commonly-used math functions, usually required in order to -estimate signal strength and signal to noise measurements in dB. - -.. kernel-doc:: drivers/media/dvb-core/dvb_math.h - - -DVB devices -~~~~~~~~~~~ - -Those functions are responsible for handling the DVB device nodes. - -.. kernel-doc:: drivers/media/dvb-core/dvbdev.h - -Digital TV Ring buffer ----------------------- - -Those routines implement ring buffers used to handle digital TV data and -copy it from/to userspace. - -.. note:: - - 1) For performance reasons read and write routines don't check buffer sizes - and/or number of bytes free/available. This has to be done before these - routines are called. For example: - - .. code-block:: c - - /* write @buflen: bytes */ - free = dvb_ringbuffer_free(rbuf); - if (free >= buflen) - count = dvb_ringbuffer_write(rbuf, buffer, buflen); - else - /* do something */ - - /* read min. 1000, max. @bufsize: bytes */ - avail = dvb_ringbuffer_avail(rbuf); - if (avail >= 1000) - count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize)); - else - /* do something */ - - 2) If there is exactly one reader and one writer, there is no need - to lock read or write operations. - Two or more readers must be locked against each other. - Flushing the buffer counts as a read operation. - Resetting the buffer counts as a read and write operation. - Two or more writers must be locked against each other. - -.. kernel-doc:: drivers/media/dvb-core/dvb_ringbuffer.h - - -Digital TV Frontend kABI ------------------------- - -Digital TV Frontend -~~~~~~~~~~~~~~~~~~~ - -The Digital TV Frontend kABI defines a driver-internal interface for -registering low-level, hardware specific driver to a hardware independent -frontend layer. It is only of interest for Digital TV device driver writers. -The header file for this API is named ``dvb_frontend.h`` and located in -``drivers/media/dvb-core``. - -Demodulator driver -^^^^^^^^^^^^^^^^^^ - -The demodulator driver is responsible to talk with the decoding part of the -hardware. Such driver should implement :c:type:`dvb_frontend_ops`, with -tells what type of digital TV standards are supported, and points to a -series of functions that allow the DVB core to command the hardware via -the code under ``drivers/media/dvb-core/dvb_frontend.c``. - -A typical example of such struct in a driver ``foo`` is:: - - static struct dvb_frontend_ops foo_ops = { - .delsys = { SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A }, - .info = { - .name = "foo DVB-T/T2/C driver", - .caps = FE_CAN_FEC_1_2 | - FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | - FE_CAN_FEC_7_8 | - FE_CAN_FEC_AUTO | - FE_CAN_QPSK | - FE_CAN_QAM_16 | - FE_CAN_QAM_32 | - FE_CAN_QAM_64 | - FE_CAN_QAM_128 | - FE_CAN_QAM_256 | - FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO | - FE_CAN_MUTE_TS | - FE_CAN_2G_MODULATION, - .frequency_min = 42000000, /* Hz */ - .frequency_max = 1002000000, /* Hz */ - .symbol_rate_min = 870000, - .symbol_rate_max = 11700000 - }, - .init = foo_init, - .sleep = foo_sleep, - .release = foo_release, - .set_frontend = foo_set_frontend, - .get_frontend = foo_get_frontend, - .read_status = foo_get_status_and_stats, - .tune = foo_tune, - .i2c_gate_ctrl = foo_i2c_gate_ctrl, - .get_frontend_algo = foo_get_algo, - }; - -A typical example of such struct in a driver ``bar`` meant to be used on -Satellite TV reception is:: - - static const struct dvb_frontend_ops bar_ops = { - .delsys = { SYS_DVBS, SYS_DVBS2 }, - .info = { - .name = "Bar DVB-S/S2 demodulator", - .frequency_min = 500000, /* KHz */ - .frequency_max = 2500000, /* KHz */ - .frequency_stepsize = 0, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .symbol_rate_tolerance = 500, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_AUTO | - FE_CAN_QPSK, - }, - .init = bar_init, - .sleep = bar_sleep, - .release = bar_release, - .set_frontend = bar_set_frontend, - .get_frontend = bar_get_frontend, - .read_status = bar_get_status_and_stats, - .i2c_gate_ctrl = bar_i2c_gate_ctrl, - .get_frontend_algo = bar_get_algo, - .tune = bar_tune, - - /* Satellite-specific */ - .diseqc_send_master_cmd = bar_send_diseqc_msg, - .diseqc_send_burst = bar_send_burst, - .set_tone = bar_set_tone, - .set_voltage = bar_set_voltage, - }; - -.. note:: - - #) For satellite digital TV standards (DVB-S, DVB-S2, ISDB-S), the - frequencies are specified in kHz, while, for terrestrial and cable - standards, they're specified in Hz. Due to that, if the same frontend - supports both types, you'll need to have two separate - :c:type:`dvb_frontend_ops` structures, one for each standard. - #) The ``.i2c_gate_ctrl`` field is present only when the hardware has - allows controlling an I2C gate (either directly of via some GPIO pin), - in order to remove the tuner from the I2C bus after a channel is - tuned. - #) All new drivers should implement the - :ref:`DVBv5 statistics ` via ``.read_status``. - Yet, there are a number of callbacks meant to get statistics for - signal strength, S/N and UCB. Those are there to provide backward - compatibility with legacy applications that don't support the DVBv5 - API. Implementing those callbacks are optional. Those callbacks may be - removed in the future, after we have all existing drivers supporting - DVBv5 stats. - #) Other callbacks are required for satellite TV standards, in order to - control LNBf and DiSEqC: ``.diseqc_send_master_cmd``, - ``.diseqc_send_burst``, ``.set_tone``, ``.set_voltage``. - -.. |delta| unicode:: U+00394 - -The ``drivers/media/dvb-core/dvb_frontend.c`` has a kernel thread with is -responsible for tuning the device. It supports multiple algoritms to -detect a channel, as defined at enum :c:func:`dvbfe_algo`. - -The algorithm to be used is obtained via ``.get_frontend_algo``. If the driver -doesn't fill its field at struct :c:type:`dvb_frontend_ops`, it will default to -``DVBFE_ALGO_SW``, meaning that the dvb-core will do a zigzag when tuning, -e. g. it will try first to use the specified center frequency ``f``, -then, it will do ``f`` + |delta|, ``f`` - |delta|, ``f`` + 2 x |delta|, -``f`` - 2 x |delta| and so on. - -If the hardware has internally a some sort of zigzag algorithm, you should -define a ``.get_frontend_algo`` function that would return ``DVBFE_ALGO_HW``. - -.. note:: - - The core frontend support also supports - a third type (``DVBFE_ALGO_CUSTOM``), in order to allow the driver to - define its own hardware-assisted algorithm. Very few hardware need to - use it nowadays. Using ``DVBFE_ALGO_CUSTOM`` require to provide other - function callbacks at struct :c:type:`dvb_frontend_ops`. - -Attaching frontend driver to the bridge driver -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Before using the Digital TV frontend core, the bridge driver should attach -the frontend demod, tuner and SEC devices and call -:c:func:`dvb_register_frontend()`, -in order to register the new frontend at the subsystem. At device -detach/removal, the bridge driver should call -:c:func:`dvb_unregister_frontend()` to -remove the frontend from the core and then :c:func:`dvb_frontend_detach()` -to free the memory allocated by the frontend drivers. - -The drivers should also call :c:func:`dvb_frontend_suspend()` as part of -their handler for the :c:type:`device_driver`.\ ``suspend()``, and -:c:func:`dvb_frontend_resume()` as -part of their handler for :c:type:`device_driver`.\ ``resume()``. - -A few other optional functions are provided to handle some special cases. - -.. _dvbv5_stats: - -Digital TV Frontend statistics -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Introduction -^^^^^^^^^^^^ - -Digital TV frontends provide a range of -:ref:`statistics ` meant to help tuning the device -and measuring the quality of service. - -For each statistics measurement, the driver should set the type of scale used, -or ``FE_SCALE_NOT_AVAILABLE`` if the statistics is not available on a given -time. Drivers should also provide the number of statistics for each type. -that's usually 1 for most video standards [#f2]_. - -Drivers should initialize each statistic counters with length and -scale at its init code. For example, if the frontend provides signal -strength, it should have, on its init code:: - - struct dtv_frontend_properties *c = &state->fe.dtv_property_cache; - - c->strength.len = 1; - c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - -And, when the statistics got updated, set the scale:: - - c->strength.stat[0].scale = FE_SCALE_DECIBEL; - c->strength.stat[0].uvalue = strength; - -.. [#f2] For ISDB-T, it may provide both a global statistics and a per-layer - set of statistics. On such cases, len should be equal to 4. The first - value corresponds to the global stat; the other ones to each layer, e. g.: - - - c->cnr.stat[0] for global S/N carrier ratio, - - c->cnr.stat[1] for Layer A S/N carrier ratio, - - c->cnr.stat[2] for layer B S/N carrier ratio, - - c->cnr.stat[3] for layer C S/N carrier ratio. - -.. note:: Please prefer to use ``FE_SCALE_DECIBEL`` instead of - ``FE_SCALE_RELATIVE`` for signal strength and CNR measurements. - -Groups of statistics -^^^^^^^^^^^^^^^^^^^^ - -There are several groups of statistics currently supported: - -Signal strength (:ref:`DTV-STAT-SIGNAL-STRENGTH`) - - Measures the signal strength level at the analog part of the tuner or - demod. - - - Typically obtained from the gain applied to the tuner and/or frontend - in order to detect the carrier. When no carrier is detected, the gain is - at the maximum value (so, strength is on its minimal). - - - As the gain is visible through the set of registers that adjust the gain, - typically, this statistics is always available [#f3]_. - - - Drivers should try to make it available all the times, as this statistics - can be used when adjusting an antenna position and to check for troubles - at the cabling. - - .. [#f3] On a few devices, the gain keeps floating if no carrier. - On such devices, strength report should check first if carrier is - detected at the tuner (``FE_HAS_CARRIER``, see :c:type:`fe_status`), - and otherwise return the lowest possible value. - -Carrier Signal to Noise ratio (:ref:`DTV-STAT-CNR`) - - Signal to Noise ratio for the main carrier. - - - Signal to Noise measurement depends on the device. On some hardware, is - available when the main carrier is detected. On those hardware, CNR - measurement usually comes from the tuner (e. g. after ``FE_HAS_CARRIER``, - see :c:type:`fe_status`). - - On other devices, it requires inner FEC decoding, - as the frontend measures it indirectly from other parameters (e. g. after - ``FE_HAS_VITERBI``, see :c:type:`fe_status`). - - Having it available after inner FEC is more common. - -Bit counts post-FEC (:ref:`DTV-STAT-POST-ERROR-BIT-COUNT` and :ref:`DTV-STAT-POST-TOTAL-BIT-COUNT`) - - Those counters measure the number of bits and bit errors errors after - the forward error correction (FEC) on the inner coding block - (after Viterbi, LDPC or other inner code). - - - Due to its nature, those statistics depend on full coding lock - (e. g. after ``FE_HAS_SYNC`` or after ``FE_HAS_LOCK``, - see :c:type:`fe_status`). - -Bit counts pre-FEC (:ref:`DTV-STAT-PRE-ERROR-BIT-COUNT` and :ref:`DTV-STAT-PRE-TOTAL-BIT-COUNT`) - - Those counters measure the number of bits and bit errors errors before - the forward error correction (FEC) on the inner coding block - (before Viterbi, LDPC or other inner code). - - - Not all frontends provide this kind of statistics. - - - Due to its nature, those statistics depend on inner coding lock (e. g. - after ``FE_HAS_VITERBI``, see :c:type:`fe_status`). - -Block counts (:ref:`DTV-STAT-ERROR-BLOCK-COUNT` and :ref:`DTV-STAT-TOTAL-BLOCK-COUNT`) - - Those counters measure the number of blocks and block errors errors after - the forward error correction (FEC) on the inner coding block - (before Viterbi, LDPC or other inner code). - - - Due to its nature, those statistics depend on full coding lock - (e. g. after ``FE_HAS_SYNC`` or after - ``FE_HAS_LOCK``, see :c:type:`fe_status`). - -.. note:: All counters should be monotonically increased as they're - collected from the hardware. - -A typical example of the logic that handle status and statistics is:: - - static int foo_get_status_and_stats(struct dvb_frontend *fe) - { - struct foo_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - - int rc; - enum fe_status *status; - - /* Both status and strength are always available */ - rc = foo_read_status(fe, &status); - if (rc < 0) - return rc; - - rc = foo_read_strength(fe); - if (rc < 0) - return rc; - - /* Check if CNR is available */ - if (!(fe->status & FE_HAS_CARRIER)) - return 0; - - rc = foo_read_cnr(fe); - if (rc < 0) - return rc; - - /* Check if pre-BER stats are available */ - if (!(fe->status & FE_HAS_VITERBI)) - return 0; - - rc = foo_get_pre_ber(fe); - if (rc < 0) - return rc; - - /* Check if post-BER stats are available */ - if (!(fe->status & FE_HAS_SYNC)) - return 0; - - rc = foo_get_post_ber(fe); - if (rc < 0) - return rc; - } - - static const struct dvb_frontend_ops ops = { - /* ... */ - .read_status = foo_get_status_and_stats, - }; - -Statistics collect -^^^^^^^^^^^^^^^^^^ - -On almost all frontend hardware, the bit and byte counts are stored by -the hardware after a certain amount of time or after the total bit/block -counter reaches a certain value (usually programable), for example, on -every 1000 ms or after receiving 1,000,000 bits. - -So, if you read the registers too soon, you'll end by reading the same -value as in the previous reading, causing the monotonic value to be -incremented too often. - -Drivers should take the responsibility to avoid too often reads. That -can be done using two approaches: - -if the driver have a bit that indicates when a collected data is ready -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -Driver should check such bit before making the statistics available. - -An example of such behavior can be found at this code snippet (adapted -from mb86a20s driver's logic):: - - static int foo_get_pre_ber(struct dvb_frontend *fe) - { - struct foo_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int rc, bit_error; - - /* Check if the BER measures are already available */ - rc = foo_read_u8(state, 0x54); - if (rc < 0) - return rc; - - if (!rc) - return 0; - - /* Read Bit Error Count */ - bit_error = foo_read_u32(state, 0x55); - if (bit_error < 0) - return bit_error; - - /* Read Total Bit Count */ - rc = foo_read_u32(state, 0x51); - if (rc < 0) - return rc; - - c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; - c->pre_bit_error.stat[0].uvalue += bit_error; - c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; - c->pre_bit_count.stat[0].uvalue += rc; - - return 0; - } - -If the driver doesn't provide a statistics available check bit -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -A few devices, however, may not provide a way to check if the stats are -available (or the way to check it is unknown). They may not even provide -a way to directly read the total number of bits or blocks. - -On those devices, the driver need to ensure that it won't be reading from -the register too often and/or estimate the total number of bits/blocks. - -On such drivers, a typical routine to get statistics would be like -(adapted from dib8000 driver's logic):: - - struct foo_state { - /* ... */ - - unsigned long per_jiffies_stats; - } - - static int foo_get_pre_ber(struct dvb_frontend *fe) - { - struct foo_state *state = fe->demodulator_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int rc, bit_error; - u64 bits; - - /* Check if time for stats was elapsed */ - if (!time_after(jiffies, state->per_jiffies_stats)) - return 0; - - /* Next stat should be collected in 1000 ms */ - state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000); - - /* Read Bit Error Count */ - bit_error = foo_read_u32(state, 0x55); - if (bit_error < 0) - return bit_error; - - /* - * On this particular frontend, there's no register that - * would provide the number of bits per 1000ms sample. So, - * some function would calculate it based on DTV properties - */ - bits = get_number_of_bits_per_1000ms(fe); - - c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; - c->pre_bit_error.stat[0].uvalue += bit_error; - c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; - c->pre_bit_count.stat[0].uvalue += bits; - - return 0; - } - -Please notice that, on both cases, we're getting the statistics using the -:c:type:`dvb_frontend_ops` ``.read_status`` callback. The rationale is that -the frontend core will automatically call this function periodically -(usually, 3 times per second, when the frontend is locked). - -That warrants that we won't miss to collect a counter and increment the -monotonic stats at the right time. - -Digital TV Frontend functions and types -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. kernel-doc:: drivers/media/dvb-core/dvb_frontend.h - - -Digital TV Demux kABI ---------------------- - -Digital TV Demux -~~~~~~~~~~~~~~~~ - -The Kernel Digital TV Demux kABI defines a driver-internal interface for -registering low-level, hardware specific driver to a hardware independent -demux layer. It is only of interest for Digital TV device driver writers. -The header file for this kABI is named demux.h and located in -drivers/media/dvb-core. - -The demux kABI should be implemented for each demux in the system. It is -used to select the TS source of a demux and to manage the demux resources. -When the demux client allocates a resource via the demux kABI, it receives -a pointer to the kABI of that resource. - -Each demux receives its TS input from a DVB front-end or from memory, as -set via this demux kABI. In a system with more than one front-end, the kABI -can be used to select one of the DVB front-ends as a TS source for a demux, -unless this is fixed in the HW platform. - -The demux kABI only controls front-ends regarding to their connections with -demuxes; the kABI used to set the other front-end parameters, such as -tuning, are devined via the Digital TV Frontend kABI. - -The functions that implement the abstract interface demux should be defined -static or module private and registered to the Demux core for external -access. It is not necessary to implement every function in the struct -&dmx_demux. For example, a demux interface might support Section filtering, -but not PES filtering. The kABI client is expected to check the value of any -function pointer before calling the function: the value of ``NULL`` means -that the function is not available. - -Whenever the functions of the demux API modify shared data, the -possibilities of lost update and race condition problems should be -addressed, e.g. by protecting parts of code with mutexes. - -Note that functions called from a bottom half context must not sleep. -Even a simple memory allocation without using ``GFP_ATOMIC`` can result in a -kernel thread being put to sleep if swapping is needed. For example, the -Linux Kernel calls the functions of a network device interface from a -bottom half context. Thus, if a demux kABI function is called from network -device code, the function must not sleep. - - - -Demux Callback API ------------------- - -Demux Callback -~~~~~~~~~~~~~~ - -This kernel-space API comprises the callback functions that deliver filtered -data to the demux client. Unlike the other DVB kABIs, these functions are -provided by the client and called from the demux code. - -The function pointers of this abstract interface are not packed into a -structure as in the other demux APIs, because the callback functions are -registered and used independent of each other. As an example, it is possible -for the API client to provide several callback functions for receiving TS -packets and no callbacks for PES packets or sections. - -The functions that implement the callback API need not be re-entrant: when -a demux driver calls one of these functions, the driver is not allowed to -call the function again before the original call returns. If a callback is -triggered by a hardware interrupt, it is recommended to use the Linux -bottom half mechanism or start a tasklet instead of making the callback -function call directly from a hardware interrupt. - -This mechanism is implemented by :c:func:`dmx_ts_cb()` and :c:func:`dmx_section_cb()` -callbacks. - -.. kernel-doc:: drivers/media/dvb-core/demux.h - -Digital TV Conditional Access kABI ----------------------------------- - -.. kernel-doc:: drivers/media/dvb-core/dvb_ca_en50221.h + dtv-common + dtv-frontend + dtv-demux + dtv-ca diff --git a/Documentation/media/kapi/dtv-demux.rst b/Documentation/media/kapi/dtv-demux.rst new file mode 100644 index 000000000000..8169c479156e --- /dev/null +++ b/Documentation/media/kapi/dtv-demux.rst @@ -0,0 +1,71 @@ +Digital TV Demux kABI +--------------------- + +Digital TV Demux +~~~~~~~~~~~~~~~~ + +The Kernel Digital TV Demux kABI defines a driver-internal interface for +registering low-level, hardware specific driver to a hardware independent +demux layer. It is only of interest for Digital TV device driver writers. +The header file for this kABI is named demux.h and located in +drivers/media/dvb-core. + +The demux kABI should be implemented for each demux in the system. It is +used to select the TS source of a demux and to manage the demux resources. +When the demux client allocates a resource via the demux kABI, it receives +a pointer to the kABI of that resource. + +Each demux receives its TS input from a DVB front-end or from memory, as +set via this demux kABI. In a system with more than one front-end, the kABI +can be used to select one of the DVB front-ends as a TS source for a demux, +unless this is fixed in the HW platform. + +The demux kABI only controls front-ends regarding to their connections with +demuxes; the kABI used to set the other front-end parameters, such as +tuning, are devined via the Digital TV Frontend kABI. + +The functions that implement the abstract interface demux should be defined +static or module private and registered to the Demux core for external +access. It is not necessary to implement every function in the struct +&dmx_demux. For example, a demux interface might support Section filtering, +but not PES filtering. The kABI client is expected to check the value of any +function pointer before calling the function: the value of ``NULL`` means +that the function is not available. + +Whenever the functions of the demux API modify shared data, the +possibilities of lost update and race condition problems should be +addressed, e.g. by protecting parts of code with mutexes. + +Note that functions called from a bottom half context must not sleep. +Even a simple memory allocation without using ``GFP_ATOMIC`` can result in a +kernel thread being put to sleep if swapping is needed. For example, the +Linux Kernel calls the functions of a network device interface from a +bottom half context. Thus, if a demux kABI function is called from network +device code, the function must not sleep. + + + +Demux Callback API +~~~~~~~~~~~~~~~~~~ + +This kernel-space API comprises the callback functions that deliver filtered +data to the demux client. Unlike the other DVB kABIs, these functions are +provided by the client and called from the demux code. + +The function pointers of this abstract interface are not packed into a +structure as in the other demux APIs, because the callback functions are +registered and used independent of each other. As an example, it is possible +for the API client to provide several callback functions for receiving TS +packets and no callbacks for PES packets or sections. + +The functions that implement the callback API need not be re-entrant: when +a demux driver calls one of these functions, the driver is not allowed to +call the function again before the original call returns. If a callback is +triggered by a hardware interrupt, it is recommended to use the Linux +bottom half mechanism or start a tasklet instead of making the callback +function call directly from a hardware interrupt. + +This mechanism is implemented by :c:func:`dmx_ts_cb()` and :c:func:`dmx_section_cb()` +callbacks. + +.. kernel-doc:: drivers/media/dvb-core/demux.h diff --git a/Documentation/media/kapi/dtv-frontend.rst b/Documentation/media/kapi/dtv-frontend.rst new file mode 100644 index 000000000000..9f67b7a7387d --- /dev/null +++ b/Documentation/media/kapi/dtv-frontend.rst @@ -0,0 +1,443 @@ +Digital TV Frontend kABI +------------------------ + +Digital TV Frontend +~~~~~~~~~~~~~~~~~~~ + +The Digital TV Frontend kABI defines a driver-internal interface for +registering low-level, hardware specific driver to a hardware independent +frontend layer. It is only of interest for Digital TV device driver writers. +The header file for this API is named ``dvb_frontend.h`` and located in +``drivers/media/dvb-core``. + +Demodulator driver +^^^^^^^^^^^^^^^^^^ + +The demodulator driver is responsible to talk with the decoding part of the +hardware. Such driver should implement :c:type:`dvb_frontend_ops`, with +tells what type of digital TV standards are supported, and points to a +series of functions that allow the DVB core to command the hardware via +the code under ``drivers/media/dvb-core/dvb_frontend.c``. + +A typical example of such struct in a driver ``foo`` is:: + + static struct dvb_frontend_ops foo_ops = { + .delsys = { SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A }, + .info = { + .name = "foo DVB-T/T2/C driver", + .caps = FE_CAN_FEC_1_2 | + FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK | + FE_CAN_QAM_16 | + FE_CAN_QAM_32 | + FE_CAN_QAM_64 | + FE_CAN_QAM_128 | + FE_CAN_QAM_256 | + FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | + FE_CAN_MUTE_TS | + FE_CAN_2G_MODULATION, + .frequency_min = 42000000, /* Hz */ + .frequency_max = 1002000000, /* Hz */ + .symbol_rate_min = 870000, + .symbol_rate_max = 11700000 + }, + .init = foo_init, + .sleep = foo_sleep, + .release = foo_release, + .set_frontend = foo_set_frontend, + .get_frontend = foo_get_frontend, + .read_status = foo_get_status_and_stats, + .tune = foo_tune, + .i2c_gate_ctrl = foo_i2c_gate_ctrl, + .get_frontend_algo = foo_get_algo, + }; + +A typical example of such struct in a driver ``bar`` meant to be used on +Satellite TV reception is:: + + static const struct dvb_frontend_ops bar_ops = { + .delsys = { SYS_DVBS, SYS_DVBS2 }, + .info = { + .name = "Bar DVB-S/S2 demodulator", + .frequency_min = 500000, /* KHz */ + .frequency_max = 2500000, /* KHz */ + .frequency_stepsize = 0, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .symbol_rate_tolerance = 500, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK, + }, + .init = bar_init, + .sleep = bar_sleep, + .release = bar_release, + .set_frontend = bar_set_frontend, + .get_frontend = bar_get_frontend, + .read_status = bar_get_status_and_stats, + .i2c_gate_ctrl = bar_i2c_gate_ctrl, + .get_frontend_algo = bar_get_algo, + .tune = bar_tune, + + /* Satellite-specific */ + .diseqc_send_master_cmd = bar_send_diseqc_msg, + .diseqc_send_burst = bar_send_burst, + .set_tone = bar_set_tone, + .set_voltage = bar_set_voltage, + }; + +.. note:: + + #) For satellite digital TV standards (DVB-S, DVB-S2, ISDB-S), the + frequencies are specified in kHz, while, for terrestrial and cable + standards, they're specified in Hz. Due to that, if the same frontend + supports both types, you'll need to have two separate + :c:type:`dvb_frontend_ops` structures, one for each standard. + #) The ``.i2c_gate_ctrl`` field is present only when the hardware has + allows controlling an I2C gate (either directly of via some GPIO pin), + in order to remove the tuner from the I2C bus after a channel is + tuned. + #) All new drivers should implement the + :ref:`DVBv5 statistics ` via ``.read_status``. + Yet, there are a number of callbacks meant to get statistics for + signal strength, S/N and UCB. Those are there to provide backward + compatibility with legacy applications that don't support the DVBv5 + API. Implementing those callbacks are optional. Those callbacks may be + removed in the future, after we have all existing drivers supporting + DVBv5 stats. + #) Other callbacks are required for satellite TV standards, in order to + control LNBf and DiSEqC: ``.diseqc_send_master_cmd``, + ``.diseqc_send_burst``, ``.set_tone``, ``.set_voltage``. + +.. |delta| unicode:: U+00394 + +The ``drivers/media/dvb-core/dvb_frontend.c`` has a kernel thread with is +responsible for tuning the device. It supports multiple algoritms to +detect a channel, as defined at enum :c:func:`dvbfe_algo`. + +The algorithm to be used is obtained via ``.get_frontend_algo``. If the driver +doesn't fill its field at struct :c:type:`dvb_frontend_ops`, it will default to +``DVBFE_ALGO_SW``, meaning that the dvb-core will do a zigzag when tuning, +e. g. it will try first to use the specified center frequency ``f``, +then, it will do ``f`` + |delta|, ``f`` - |delta|, ``f`` + 2 x |delta|, +``f`` - 2 x |delta| and so on. + +If the hardware has internally a some sort of zigzag algorithm, you should +define a ``.get_frontend_algo`` function that would return ``DVBFE_ALGO_HW``. + +.. note:: + + The core frontend support also supports + a third type (``DVBFE_ALGO_CUSTOM``), in order to allow the driver to + define its own hardware-assisted algorithm. Very few hardware need to + use it nowadays. Using ``DVBFE_ALGO_CUSTOM`` require to provide other + function callbacks at struct :c:type:`dvb_frontend_ops`. + +Attaching frontend driver to the bridge driver +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Before using the Digital TV frontend core, the bridge driver should attach +the frontend demod, tuner and SEC devices and call +:c:func:`dvb_register_frontend()`, +in order to register the new frontend at the subsystem. At device +detach/removal, the bridge driver should call +:c:func:`dvb_unregister_frontend()` to +remove the frontend from the core and then :c:func:`dvb_frontend_detach()` +to free the memory allocated by the frontend drivers. + +The drivers should also call :c:func:`dvb_frontend_suspend()` as part of +their handler for the :c:type:`device_driver`.\ ``suspend()``, and +:c:func:`dvb_frontend_resume()` as +part of their handler for :c:type:`device_driver`.\ ``resume()``. + +A few other optional functions are provided to handle some special cases. + +.. _dvbv5_stats: + +Digital TV Frontend statistics +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Introduction +^^^^^^^^^^^^ + +Digital TV frontends provide a range of +:ref:`statistics ` meant to help tuning the device +and measuring the quality of service. + +For each statistics measurement, the driver should set the type of scale used, +or ``FE_SCALE_NOT_AVAILABLE`` if the statistics is not available on a given +time. Drivers should also provide the number of statistics for each type. +that's usually 1 for most video standards [#f2]_. + +Drivers should initialize each statistic counters with length and +scale at its init code. For example, if the frontend provides signal +strength, it should have, on its init code:: + + struct dtv_frontend_properties *c = &state->fe.dtv_property_cache; + + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + +And, when the statistics got updated, set the scale:: + + c->strength.stat[0].scale = FE_SCALE_DECIBEL; + c->strength.stat[0].uvalue = strength; + +.. [#f2] For ISDB-T, it may provide both a global statistics and a per-layer + set of statistics. On such cases, len should be equal to 4. The first + value corresponds to the global stat; the other ones to each layer, e. g.: + + - c->cnr.stat[0] for global S/N carrier ratio, + - c->cnr.stat[1] for Layer A S/N carrier ratio, + - c->cnr.stat[2] for layer B S/N carrier ratio, + - c->cnr.stat[3] for layer C S/N carrier ratio. + +.. note:: Please prefer to use ``FE_SCALE_DECIBEL`` instead of + ``FE_SCALE_RELATIVE`` for signal strength and CNR measurements. + +Groups of statistics +^^^^^^^^^^^^^^^^^^^^ + +There are several groups of statistics currently supported: + +Signal strength (:ref:`DTV-STAT-SIGNAL-STRENGTH`) + - Measures the signal strength level at the analog part of the tuner or + demod. + + - Typically obtained from the gain applied to the tuner and/or frontend + in order to detect the carrier. When no carrier is detected, the gain is + at the maximum value (so, strength is on its minimal). + + - As the gain is visible through the set of registers that adjust the gain, + typically, this statistics is always available [#f3]_. + + - Drivers should try to make it available all the times, as this statistics + can be used when adjusting an antenna position and to check for troubles + at the cabling. + + .. [#f3] On a few devices, the gain keeps floating if no carrier. + On such devices, strength report should check first if carrier is + detected at the tuner (``FE_HAS_CARRIER``, see :c:type:`fe_status`), + and otherwise return the lowest possible value. + +Carrier Signal to Noise ratio (:ref:`DTV-STAT-CNR`) + - Signal to Noise ratio for the main carrier. + + - Signal to Noise measurement depends on the device. On some hardware, is + available when the main carrier is detected. On those hardware, CNR + measurement usually comes from the tuner (e. g. after ``FE_HAS_CARRIER``, + see :c:type:`fe_status`). + + On other devices, it requires inner FEC decoding, + as the frontend measures it indirectly from other parameters (e. g. after + ``FE_HAS_VITERBI``, see :c:type:`fe_status`). + + Having it available after inner FEC is more common. + +Bit counts post-FEC (:ref:`DTV-STAT-POST-ERROR-BIT-COUNT` and :ref:`DTV-STAT-POST-TOTAL-BIT-COUNT`) + - Those counters measure the number of bits and bit errors errors after + the forward error correction (FEC) on the inner coding block + (after Viterbi, LDPC or other inner code). + + - Due to its nature, those statistics depend on full coding lock + (e. g. after ``FE_HAS_SYNC`` or after ``FE_HAS_LOCK``, + see :c:type:`fe_status`). + +Bit counts pre-FEC (:ref:`DTV-STAT-PRE-ERROR-BIT-COUNT` and :ref:`DTV-STAT-PRE-TOTAL-BIT-COUNT`) + - Those counters measure the number of bits and bit errors errors before + the forward error correction (FEC) on the inner coding block + (before Viterbi, LDPC or other inner code). + + - Not all frontends provide this kind of statistics. + + - Due to its nature, those statistics depend on inner coding lock (e. g. + after ``FE_HAS_VITERBI``, see :c:type:`fe_status`). + +Block counts (:ref:`DTV-STAT-ERROR-BLOCK-COUNT` and :ref:`DTV-STAT-TOTAL-BLOCK-COUNT`) + - Those counters measure the number of blocks and block errors errors after + the forward error correction (FEC) on the inner coding block + (before Viterbi, LDPC or other inner code). + + - Due to its nature, those statistics depend on full coding lock + (e. g. after ``FE_HAS_SYNC`` or after + ``FE_HAS_LOCK``, see :c:type:`fe_status`). + +.. note:: All counters should be monotonically increased as they're + collected from the hardware. + +A typical example of the logic that handle status and statistics is:: + + static int foo_get_status_and_stats(struct dvb_frontend *fe) + { + struct foo_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + + int rc; + enum fe_status *status; + + /* Both status and strength are always available */ + rc = foo_read_status(fe, &status); + if (rc < 0) + return rc; + + rc = foo_read_strength(fe); + if (rc < 0) + return rc; + + /* Check if CNR is available */ + if (!(fe->status & FE_HAS_CARRIER)) + return 0; + + rc = foo_read_cnr(fe); + if (rc < 0) + return rc; + + /* Check if pre-BER stats are available */ + if (!(fe->status & FE_HAS_VITERBI)) + return 0; + + rc = foo_get_pre_ber(fe); + if (rc < 0) + return rc; + + /* Check if post-BER stats are available */ + if (!(fe->status & FE_HAS_SYNC)) + return 0; + + rc = foo_get_post_ber(fe); + if (rc < 0) + return rc; + } + + static const struct dvb_frontend_ops ops = { + /* ... */ + .read_status = foo_get_status_and_stats, + }; + +Statistics collect +^^^^^^^^^^^^^^^^^^ + +On almost all frontend hardware, the bit and byte counts are stored by +the hardware after a certain amount of time or after the total bit/block +counter reaches a certain value (usually programable), for example, on +every 1000 ms or after receiving 1,000,000 bits. + +So, if you read the registers too soon, you'll end by reading the same +value as in the previous reading, causing the monotonic value to be +incremented too often. + +Drivers should take the responsibility to avoid too often reads. That +can be done using two approaches: + +if the driver have a bit that indicates when a collected data is ready +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +Driver should check such bit before making the statistics available. + +An example of such behavior can be found at this code snippet (adapted +from mb86a20s driver's logic):: + + static int foo_get_pre_ber(struct dvb_frontend *fe) + { + struct foo_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int rc, bit_error; + + /* Check if the BER measures are already available */ + rc = foo_read_u8(state, 0x54); + if (rc < 0) + return rc; + + if (!rc) + return 0; + + /* Read Bit Error Count */ + bit_error = foo_read_u32(state, 0x55); + if (bit_error < 0) + return bit_error; + + /* Read Total Bit Count */ + rc = foo_read_u32(state, 0x51); + if (rc < 0) + return rc; + + c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->pre_bit_error.stat[0].uvalue += bit_error; + c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->pre_bit_count.stat[0].uvalue += rc; + + return 0; + } + +If the driver doesn't provide a statistics available check bit +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +A few devices, however, may not provide a way to check if the stats are +available (or the way to check it is unknown). They may not even provide +a way to directly read the total number of bits or blocks. + +On those devices, the driver need to ensure that it won't be reading from +the register too often and/or estimate the total number of bits/blocks. + +On such drivers, a typical routine to get statistics would be like +(adapted from dib8000 driver's logic):: + + struct foo_state { + /* ... */ + + unsigned long per_jiffies_stats; + } + + static int foo_get_pre_ber(struct dvb_frontend *fe) + { + struct foo_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int rc, bit_error; + u64 bits; + + /* Check if time for stats was elapsed */ + if (!time_after(jiffies, state->per_jiffies_stats)) + return 0; + + /* Next stat should be collected in 1000 ms */ + state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000); + + /* Read Bit Error Count */ + bit_error = foo_read_u32(state, 0x55); + if (bit_error < 0) + return bit_error; + + /* + * On this particular frontend, there's no register that + * would provide the number of bits per 1000ms sample. So, + * some function would calculate it based on DTV properties + */ + bits = get_number_of_bits_per_1000ms(fe); + + c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->pre_bit_error.stat[0].uvalue += bit_error; + c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->pre_bit_count.stat[0].uvalue += bits; + + return 0; + } + +Please notice that, on both cases, we're getting the statistics using the +:c:type:`dvb_frontend_ops` ``.read_status`` callback. The rationale is that +the frontend core will automatically call this function periodically +(usually, 3 times per second, when the frontend is locked). + +That warrants that we won't miss to collect a counter and increment the +monotonic stats at the right time. + +Digital TV Frontend functions and types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. kernel-doc:: drivers/media/dvb-core/dvb_frontend.h -- cgit v1.2.3 From b2fc98fc91647e4b7ec1ac90001729345ec3e790 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 11 Oct 2017 13:06:30 -0400 Subject: media: dtv-frontend.rst fix a typo: algoritms -> algorithms WARNING: 'algoritms' may be misspelled - perhaps 'algorithms'? +responsible for tuning the device. It supports multiple algoritms to Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/kapi/dtv-frontend.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/media/kapi/dtv-frontend.rst b/Documentation/media/kapi/dtv-frontend.rst index 9f67b7a7387d..f1a2fdaab5ba 100644 --- a/Documentation/media/kapi/dtv-frontend.rst +++ b/Documentation/media/kapi/dtv-frontend.rst @@ -119,7 +119,7 @@ Satellite TV reception is:: .. |delta| unicode:: U+00394 The ``drivers/media/dvb-core/dvb_frontend.c`` has a kernel thread with is -responsible for tuning the device. It supports multiple algoritms to +responsible for tuning the device. It supports multiple algorithms to detect a channel, as defined at enum :c:func:`dvbfe_algo`. The algorithm to be used is obtained via ``.get_frontend_algo``. If the driver -- cgit v1.2.3 From 1607b8b574c9318ea58f3f08cf85514ceddf467a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Sep 2017 17:05:14 -0400 Subject: media: dtv-demux.rst: minor markup improvements Add a cross-reference to a mentioned structure and split the kernel-doc stuff on a separate chapter. Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/kapi/dtv-demux.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Documentation/media/kapi/dtv-demux.rst b/Documentation/media/kapi/dtv-demux.rst index 8169c479156e..3ee69266e206 100644 --- a/Documentation/media/kapi/dtv-demux.rst +++ b/Documentation/media/kapi/dtv-demux.rst @@ -7,8 +7,8 @@ Digital TV Demux The Kernel Digital TV Demux kABI defines a driver-internal interface for registering low-level, hardware specific driver to a hardware independent demux layer. It is only of interest for Digital TV device driver writers. -The header file for this kABI is named demux.h and located in -drivers/media/dvb-core. +The header file for this kABI is named ``demux.h`` and located in +``drivers/media/dvb-core``. The demux kABI should be implemented for each demux in the system. It is used to select the TS source of a demux and to manage the demux resources. @@ -27,7 +27,7 @@ tuning, are devined via the Digital TV Frontend kABI. The functions that implement the abstract interface demux should be defined static or module private and registered to the Demux core for external access. It is not necessary to implement every function in the struct -&dmx_demux. For example, a demux interface might support Section filtering, +:c:type:`dmx_demux`. For example, a demux interface might support Section filtering, but not PES filtering. The kABI client is expected to check the value of any function pointer before calling the function: the value of ``NULL`` means that the function is not available. @@ -43,8 +43,6 @@ Linux Kernel calls the functions of a network device interface from a bottom half context. Thus, if a demux kABI function is called from network device code, the function must not sleep. - - Demux Callback API ~~~~~~~~~~~~~~~~~~ @@ -68,4 +66,7 @@ function call directly from a hardware interrupt. This mechanism is implemented by :c:func:`dmx_ts_cb()` and :c:func:`dmx_section_cb()` callbacks. +Digital TV Demux functions and types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + .. kernel-doc:: drivers/media/dvb-core/demux.h -- cgit v1.2.3 From 0463625ee9e7b7c786460b6c20073e8c8e283466 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Sep 2017 17:43:49 -0400 Subject: media: dvb_demux.h: add an enum for DMX_TYPE_* and document kernel-doc allows documenting enums. Also, it makes clearer about the meaning of each field on structures. So, convert DMX_TYPE_* to an enum. While here, get rid of the unused DMX_TYPE_PES. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_demux.h | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h index 6f572ca8d339..6bc4b27dbff3 100644 --- a/drivers/media/dvb-core/dvb_demux.h +++ b/drivers/media/dvb-core/dvb_demux.h @@ -26,9 +26,16 @@ #include "demux.h" -#define DMX_TYPE_TS 0 -#define DMX_TYPE_SEC 1 -#define DMX_TYPE_PES 2 +/** + * enum dvb_dmx_filter_type - type of demux feed. + * + * @DMX_TYPE_TS: feed is in TS mode. + * @DMX_TYPE_SEC: feed is in Section mode. + */ +enum dvb_dmx_filter_type { + DMX_TYPE_TS, + DMX_TYPE_SEC, +}; #define DMX_STATE_FREE 0 #define DMX_STATE_ALLOCATED 1 @@ -52,7 +59,7 @@ struct dvb_demux_filter { struct dvb_demux_feed *feed; int index; int state; - int type; + enum dvb_dmx_filter_type type; u16 hw_handle; struct timer_list timer; @@ -73,7 +80,7 @@ struct dvb_demux_feed { struct dvb_demux *demux; void *priv; - int type; + enum dvb_dmx_filter_type type; int state; u16 pid; -- cgit v1.2.3 From 999f3d25b87feaaadf39627856d235683ad5268d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Sep 2017 17:44:07 -0400 Subject: media: dvb_demux.h: add an enum for DMX_STATE_* and document kernel-doc allows documenting enums. Also, it makes clearer about the meaning of each field on structures. So, convert DMX_STATE_* to an enum. While here, get rid of the unused DMX_STATE_SET. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_demux.h | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h index 6bc4b27dbff3..b24d69b5a20f 100644 --- a/drivers/media/dvb-core/dvb_demux.h +++ b/drivers/media/dvb-core/dvb_demux.h @@ -37,11 +37,22 @@ enum dvb_dmx_filter_type { DMX_TYPE_SEC, }; -#define DMX_STATE_FREE 0 -#define DMX_STATE_ALLOCATED 1 -#define DMX_STATE_SET 2 -#define DMX_STATE_READY 3 -#define DMX_STATE_GO 4 +/** + * enum dvb_dmx_state - state machine for a demux filter. + * + * @DMX_STATE_FREE: indicates that the filter is freed. + * @DMX_STATE_ALLOCATED: indicates that the filter was allocated + * to be used. + * @DMX_STATE_READY: indicates that the filter is ready + * to be used. + * @DMX_STATE_GO: indicates that the filter is running. + */ +enum dvb_dmx_state { + DMX_STATE_FREE, + DMX_STATE_ALLOCATED, + DMX_STATE_READY, + DMX_STATE_GO, +}; #define DVB_DEMUX_MASK_MAX 18 @@ -58,7 +69,7 @@ struct dvb_demux_filter { struct dvb_demux_filter *next; struct dvb_demux_feed *feed; int index; - int state; + enum dvb_dmx_state state; enum dvb_dmx_filter_type type; u16 hw_handle; @@ -81,7 +92,7 @@ struct dvb_demux_feed { struct dvb_demux *demux; void *priv; enum dvb_dmx_filter_type type; - int state; + enum dvb_dmx_state state; u16 pid; ktime_t timeout; -- cgit v1.2.3 From 68d84ae02ff8f2b9c36799058c3ce2a7db7fca67 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Sep 2017 18:08:45 -0400 Subject: media: dvb_demux.h: get rid of unused timer at struct dvb_demux_filter This field is not used. So, get rid of it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_demux.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h index b24d69b5a20f..045f7fd1a8b1 100644 --- a/drivers/media/dvb-core/dvb_demux.h +++ b/drivers/media/dvb-core/dvb_demux.h @@ -73,7 +73,6 @@ struct dvb_demux_filter { enum dvb_dmx_filter_type type; u16 hw_handle; - struct timer_list timer; }; #define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head) -- cgit v1.2.3 From 392cc7afbb4d8a649636f7fdd99ed2278f08457e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Sep 2017 18:10:13 -0400 Subject: media: dvb_demux: mark a boolean field as such The struct dvb_demux_filter.doneq is a boolean. Mark it as such, as it helps to understand what it does. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_demux.c | 4 ++-- drivers/media/dvb-core/dvb_demux.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index 6628f80d184f..68e93362c081 100644 --- a/drivers/media/dvb-core/dvb_demux.c +++ b/drivers/media/dvb-core/dvb_demux.c @@ -898,14 +898,14 @@ static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed) return; do { sf = &f->filter; - doneq = 0; + doneq = false; for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { mode = sf->filter_mode[i]; mask = sf->filter_mask[i]; f->maskandmode[i] = mask & mode; doneq |= f->maskandnotmode[i] = mask & ~mode; } - f->doneq = doneq ? 1 : 0; + f->doneq = doneq ? true : false; } while ((f = f->next)); } diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h index 045f7fd1a8b1..700887938145 100644 --- a/drivers/media/dvb-core/dvb_demux.h +++ b/drivers/media/dvb-core/dvb_demux.h @@ -64,7 +64,7 @@ struct dvb_demux_filter { struct dmx_section_filter filter; u8 maskandmode[DMX_MAX_FILTER_SIZE]; u8 maskandnotmode[DMX_MAX_FILTER_SIZE]; - int doneq; + bool doneq; struct dvb_demux_filter *next; struct dvb_demux_feed *feed; -- cgit v1.2.3 From 2c53275c1edafdb1c404071940de0a7de47c0bbb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Sep 2017 18:57:54 -0400 Subject: media: dvb_demux: dvb_demux_feed.pusi_seen is boolean Instead of using an integer to represent it, use boolean, as this better describes what this field really means. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_demux.c | 12 ++++++------ drivers/media/dvb-core/dvb_demux.h | 2 +- drivers/media/pci/ttpci/av7110.c | 2 +- drivers/media/pci/ttpci/budget-core.c | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index 68e93362c081..b9360cbc3519 100644 --- a/drivers/media/dvb-core/dvb_demux.c +++ b/drivers/media/dvb-core/dvb_demux.c @@ -223,10 +223,10 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) * when the second packet arrives. * * Fix: - * when demux is started, let feed->pusi_seen = 0 to + * when demux is started, let feed->pusi_seen = false to * prevent initial feeding of garbage from the end of * previous section. When you for the first time see PUSI=1 - * then set feed->pusi_seen = 1 + * then set feed->pusi_seen = true */ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, const u8 *buf, u8 len) @@ -318,10 +318,10 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, */ #endif /* - * Discontinuity detected. Reset pusi_seen = 0 to + * Discontinuity detected. Reset pusi_seen to * stop feeding of suspicious data until next PUSI=1 arrives */ - feed->pusi_seen = 0; + feed->pusi_seen = false; dvb_dmx_swfilter_section_new(feed); } @@ -335,8 +335,8 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, dvb_dmx_swfilter_section_copy_dump(feed, before, before_len); - /* before start of new section, set pusi_seen = 1 */ - feed->pusi_seen = 1; + /* before start of new section, set pusi_seen */ + feed->pusi_seen = true; dvb_dmx_swfilter_section_new(feed); dvb_dmx_swfilter_section_copy_dump(feed, after, after_len); diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h index 700887938145..9db3c2b7c64e 100644 --- a/drivers/media/dvb-core/dvb_demux.h +++ b/drivers/media/dvb-core/dvb_demux.h @@ -101,7 +101,7 @@ struct dvb_demux_feed { enum dmx_ts_pes pes_type; int cc; - int pusi_seen; /* prevents feeding of garbage from previous section */ + bool pusi_seen; /* prevents feeding of garbage from previous section */ u16 peslen; diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index f46947d8adf8..f89fb23f6c57 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -1224,7 +1224,7 @@ static int budget_start_feed(struct dvb_demux_feed *feed) dprintk(2, "av7110: %p\n", budget); spin_lock(&budget->feedlock1); - feed->pusi_seen = 0; /* have a clean section start */ + feed->pusi_seen = false; /* have a clean section start */ status = start_ts_capture(budget); spin_unlock(&budget->feedlock1); return status; diff --git a/drivers/media/pci/ttpci/budget-core.c b/drivers/media/pci/ttpci/budget-core.c index 97499b2af714..b3dc45b91101 100644 --- a/drivers/media/pci/ttpci/budget-core.c +++ b/drivers/media/pci/ttpci/budget-core.c @@ -330,7 +330,7 @@ static int budget_start_feed(struct dvb_demux_feed *feed) return -EINVAL; spin_lock(&budget->feedlock); - feed->pusi_seen = 0; /* have a clean section start */ + feed->pusi_seen = false; /* have a clean section start */ if (budget->feeding++ == 0) status = start_ts_capture(budget); spin_unlock(&budget->feedlock); -- cgit v1.2.3 From cd3c6019497c028b23b8b543f73af76ddc1b57c9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Sep 2017 18:59:45 -0400 Subject: media: dvb_demux.h: get rid of DMX_FEED_ENTRY() macro This isn't used anywere. Get rid of it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_demux.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h index 9db3c2b7c64e..d9b30d669bf3 100644 --- a/drivers/media/dvb-core/dvb_demux.h +++ b/drivers/media/dvb-core/dvb_demux.h @@ -75,8 +75,6 @@ struct dvb_demux_filter { u16 hw_handle; }; -#define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head) - struct dvb_demux_feed { union { struct dmx_ts_feed ts; -- cgit v1.2.3 From 4bc8525a34786f14965a2e8e7d932fcc6867afed Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Sep 2017 19:01:09 -0400 Subject: media: dvb_demux: fix type of dvb_demux_feed.ts_type Just like pes_type, this field represents an enum. Properly identify it as such. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_demux.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h index d9b30d669bf3..c9e94bc3a2e5 100644 --- a/drivers/media/dvb-core/dvb_demux.h +++ b/drivers/media/dvb-core/dvb_demux.h @@ -95,7 +95,7 @@ struct dvb_demux_feed { ktime_t timeout; struct dvb_demux_filter *filter; - int ts_type; + enum ts_filter_type ts_type; enum dmx_ts_pes pes_type; int cc; -- cgit v1.2.3 From e5c4be821a18005ed1883c1a82c3498ee8fcedfe Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Sep 2017 19:04:08 -0400 Subject: media: dvb_demux: document dvb_demux_filter and dvb_demux_feed Document those two structs using kernel-doc markups. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_demux.h | 50 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h index c9e94bc3a2e5..08cc86247f08 100644 --- a/drivers/media/dvb-core/dvb_demux.h +++ b/drivers/media/dvb-core/dvb_demux.h @@ -60,6 +60,21 @@ enum dvb_dmx_state { #define SPEED_PKTS_INTERVAL 50000 +/** + * struct dvb_demux_filter - Describes a DVB demux section filter. + * + * @filter: Section filter as defined by &struct dmx_section_filter. + * @maskandmode: logical ``and`` bit mask. + * @maskandnotmode: logical ``and not`` bit mask. + * @doneq: flag that indicates when a filter is ready. + * @next: pointer to the next section filter. + * @feed: &struct dvb_demux_feed pointer. + * @index: index of the used demux filter. + * @state: state of the filter as described by &enum dvb_dmx_state. + * @type: type of the filter as described + * by &enum dvb_dmx_filter_type. + */ + struct dvb_demux_filter { struct dmx_section_filter filter; u8 maskandmode[DMX_MAX_FILTER_SIZE]; @@ -72,9 +87,40 @@ struct dvb_demux_filter { enum dvb_dmx_state state; enum dvb_dmx_filter_type type; + /* private: used only by av7110 */ u16 hw_handle; }; +/** + * struct dvb_demux_feed - describes a DVB field + * + * @feed: a digital TV feed. It can either be a TS or a section feed: + * - if the feed is TS, it contains &struct dvb_ts_feed; + * - if the feed is section, it contains + * &struct dmx_section_feed. + * @cb: digital TV callbacks. depending on the feed type, it can be: + * - if the feed is TS, it contains a dmx_ts_cb() callback; + * - if the feed is section, it contains a dmx_section_cb() + * callback. + * + * @demux: pointer to &struct dvb_demux. + * @priv: private data for the filter handling routine. + * @type: type of the filter, as defined by &enum dvb_dmx_filter_type. + * @state: state of the filter as defined by &enum dvb_dmx_state. + * @pid: PID to be filtered. + * @timeout: feed timeout. + * @filter: pointer to &struct dvb_demux_filter. + * @ts_type: type of TS, as defined by &enum ts_filter_type. + * @pes_type: type of PES, as defined by &enum dmx_ts_pes. + * @cc: MPEG-TS packet continuity counter + * @pusi_seen: if true, indicates that a discontinuity was detected. + * it is used to prevent feeding of garbage from previous section. + * @peslen: length of the PES (Packet Elementary Stream). + * @list_head: head for the list of digital TV demux feeds. + * @index: a unique index for each feed. Can be used as hardware + * pid filter index. + * + */ struct dvb_demux_feed { union { struct dmx_ts_feed ts; @@ -99,12 +145,12 @@ struct dvb_demux_feed { enum dmx_ts_pes pes_type; int cc; - bool pusi_seen; /* prevents feeding of garbage from previous section */ + bool pusi_seen; u16 peslen; struct list_head list_head; - unsigned int index; /* a unique index for each feed (can be used as hardware pid filter index) */ + unsigned int index; }; struct dvb_demux { -- cgit v1.2.3 From c4303473b3a931b2b4ce325d3acae3c6b00ec71f Mon Sep 17 00:00:00 2001 From: Satendra Singh Thakur Date: Wed, 20 Sep 2017 01:15:08 -0400 Subject: media: dvb_frontend: dtv_property_process_set() cleanups Since all properties in the func dtv_property_process_set() use at most 4 bytes arguments, change the code to pass u32 cmd and u32 data as function arguments, instead of passing a pointer to the entire struct dtv_property *tvp. Instead of having a generic dtv_property_dump(), added its own properties debug logic in the dtv_property_process_set(). Signed-off-by: Satendra Singh Thakur Reviewed-by: Shuah Khan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 125 ++++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 53 deletions(-) diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 5e3bcae477d2..e1e9da42cb99 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -1090,22 +1090,19 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { _DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0, 0), }; -static void dtv_property_dump(struct dvb_frontend *fe, - bool is_set, +static void dtv_get_property_dump(struct dvb_frontend *fe, struct dtv_property *tvp) { int i; if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) { - dev_warn(fe->dvb->device, "%s: %s tvp.cmd = 0x%08x undefined\n", - __func__, - is_set ? "SET" : "GET", + dev_warn(fe->dvb->device, "%s: GET tvp.cmd = 0x%08x undefined\n" + , __func__, tvp->cmd); return; } - dev_dbg(fe->dvb->device, "%s: %s tvp.cmd = 0x%08x (%s)\n", __func__, - is_set ? "SET" : "GET", + dev_dbg(fe->dvb->device, "%s: GET tvp.cmd = 0x%08x (%s)\n", __func__, tvp->cmd, dtv_cmds[tvp->cmd].name); @@ -1515,7 +1512,7 @@ static int dtv_property_process_get(struct dvb_frontend *fe, return -EINVAL; } - dtv_property_dump(fe, false, tvp); + dtv_get_property_dump(fe, tvp); return 0; } @@ -1738,16 +1735,36 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe) return emulate_delivery_system(fe, delsys); } +/** + * dtv_property_process_set - Sets a single DTV property + * @fe: Pointer to &struct dvb_frontend + * @file: Pointer to &struct file + * @cmd: Digital TV command + * @data: An unsigned 32-bits number + * + * This routine assigns the property + * value to the corresponding member of + * &struct dtv_frontend_properties + * + * Returns: + * Zero on success, negative errno on failure. + */ static int dtv_property_process_set(struct dvb_frontend *fe, - struct dtv_property *tvp, - struct file *file) + struct file *file, + u32 cmd, u32 data) { int r = 0; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - dtv_property_dump(fe, true, tvp); - - switch(tvp->cmd) { + /** Dump DTV command name and value*/ + if (!cmd || cmd > DTV_MAX_COMMAND) + dev_warn(fe->dvb->device, "%s: SET cmd 0x%08x undefined\n", + __func__, cmd); + else + dev_dbg(fe->dvb->device, + "%s: SET cmd 0x%08x (%s) to 0x%08x\n", + __func__, cmd, dtv_cmds[cmd].name, data); + switch (cmd) { case DTV_CLEAR: /* * Reset a cache of data specific to the frontend here. This does @@ -1767,133 +1784,133 @@ static int dtv_property_process_set(struct dvb_frontend *fe, r = dtv_set_frontend(fe); break; case DTV_FREQUENCY: - c->frequency = tvp->u.data; + c->frequency = data; break; case DTV_MODULATION: - c->modulation = tvp->u.data; + c->modulation = data; break; case DTV_BANDWIDTH_HZ: - c->bandwidth_hz = tvp->u.data; + c->bandwidth_hz = data; break; case DTV_INVERSION: - c->inversion = tvp->u.data; + c->inversion = data; break; case DTV_SYMBOL_RATE: - c->symbol_rate = tvp->u.data; + c->symbol_rate = data; break; case DTV_INNER_FEC: - c->fec_inner = tvp->u.data; + c->fec_inner = data; break; case DTV_PILOT: - c->pilot = tvp->u.data; + c->pilot = data; break; case DTV_ROLLOFF: - c->rolloff = tvp->u.data; + c->rolloff = data; break; case DTV_DELIVERY_SYSTEM: - r = dvbv5_set_delivery_system(fe, tvp->u.data); + r = dvbv5_set_delivery_system(fe, data); break; case DTV_VOLTAGE: - c->voltage = tvp->u.data; + c->voltage = data; r = dvb_frontend_handle_ioctl(file, FE_SET_VOLTAGE, (void *)c->voltage); break; case DTV_TONE: - c->sectone = tvp->u.data; + c->sectone = data; r = dvb_frontend_handle_ioctl(file, FE_SET_TONE, (void *)c->sectone); break; case DTV_CODE_RATE_HP: - c->code_rate_HP = tvp->u.data; + c->code_rate_HP = data; break; case DTV_CODE_RATE_LP: - c->code_rate_LP = tvp->u.data; + c->code_rate_LP = data; break; case DTV_GUARD_INTERVAL: - c->guard_interval = tvp->u.data; + c->guard_interval = data; break; case DTV_TRANSMISSION_MODE: - c->transmission_mode = tvp->u.data; + c->transmission_mode = data; break; case DTV_HIERARCHY: - c->hierarchy = tvp->u.data; + c->hierarchy = data; break; case DTV_INTERLEAVING: - c->interleaving = tvp->u.data; + c->interleaving = data; break; /* ISDB-T Support here */ case DTV_ISDBT_PARTIAL_RECEPTION: - c->isdbt_partial_reception = tvp->u.data; + c->isdbt_partial_reception = data; break; case DTV_ISDBT_SOUND_BROADCASTING: - c->isdbt_sb_mode = tvp->u.data; + c->isdbt_sb_mode = data; break; case DTV_ISDBT_SB_SUBCHANNEL_ID: - c->isdbt_sb_subchannel = tvp->u.data; + c->isdbt_sb_subchannel = data; break; case DTV_ISDBT_SB_SEGMENT_IDX: - c->isdbt_sb_segment_idx = tvp->u.data; + c->isdbt_sb_segment_idx = data; break; case DTV_ISDBT_SB_SEGMENT_COUNT: - c->isdbt_sb_segment_count = tvp->u.data; + c->isdbt_sb_segment_count = data; break; case DTV_ISDBT_LAYER_ENABLED: - c->isdbt_layer_enabled = tvp->u.data; + c->isdbt_layer_enabled = data; break; case DTV_ISDBT_LAYERA_FEC: - c->layer[0].fec = tvp->u.data; + c->layer[0].fec = data; break; case DTV_ISDBT_LAYERA_MODULATION: - c->layer[0].modulation = tvp->u.data; + c->layer[0].modulation = data; break; case DTV_ISDBT_LAYERA_SEGMENT_COUNT: - c->layer[0].segment_count = tvp->u.data; + c->layer[0].segment_count = data; break; case DTV_ISDBT_LAYERA_TIME_INTERLEAVING: - c->layer[0].interleaving = tvp->u.data; + c->layer[0].interleaving = data; break; case DTV_ISDBT_LAYERB_FEC: - c->layer[1].fec = tvp->u.data; + c->layer[1].fec = data; break; case DTV_ISDBT_LAYERB_MODULATION: - c->layer[1].modulation = tvp->u.data; + c->layer[1].modulation = data; break; case DTV_ISDBT_LAYERB_SEGMENT_COUNT: - c->layer[1].segment_count = tvp->u.data; + c->layer[1].segment_count = data; break; case DTV_ISDBT_LAYERB_TIME_INTERLEAVING: - c->layer[1].interleaving = tvp->u.data; + c->layer[1].interleaving = data; break; case DTV_ISDBT_LAYERC_FEC: - c->layer[2].fec = tvp->u.data; + c->layer[2].fec = data; break; case DTV_ISDBT_LAYERC_MODULATION: - c->layer[2].modulation = tvp->u.data; + c->layer[2].modulation = data; break; case DTV_ISDBT_LAYERC_SEGMENT_COUNT: - c->layer[2].segment_count = tvp->u.data; + c->layer[2].segment_count = data; break; case DTV_ISDBT_LAYERC_TIME_INTERLEAVING: - c->layer[2].interleaving = tvp->u.data; + c->layer[2].interleaving = data; break; /* Multistream support */ case DTV_STREAM_ID: case DTV_DVBT2_PLP_ID_LEGACY: - c->stream_id = tvp->u.data; + c->stream_id = data; break; /* ATSC-MH */ case DTV_ATSCMH_PARADE_ID: - fe->dtv_property_cache.atscmh_parade_id = tvp->u.data; + fe->dtv_property_cache.atscmh_parade_id = data; break; case DTV_ATSCMH_RS_FRAME_ENSEMBLE: - fe->dtv_property_cache.atscmh_rs_frame_ensemble = tvp->u.data; + fe->dtv_property_cache.atscmh_rs_frame_ensemble = data; break; case DTV_LNA: - c->lna = tvp->u.data; + c->lna = data; if (fe->ops.set_lna) r = fe->ops.set_lna(fe); if (r < 0) @@ -2120,7 +2137,9 @@ static int dvb_frontend_handle_ioctl(struct file *file, return PTR_ERR(tvp); for (i = 0; i < tvps->num; i++) { - err = dtv_property_process_set(fe, tvp + i, file); + err = dtv_property_process_set(fe, file, + (tvp + i)->cmd, + (tvp + i)->u.data); if (err < 0) { kfree(tvp); return err; -- cgit v1.2.3 From 06133bdcbde952772c14174b1041ac0221f636e9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 20 Sep 2017 07:09:15 -0400 Subject: media: dvb_frontend: get rid of dtv_get_property_dump() Simplify the get property handling and move it to the existing code at dtv_property_process_get() directly. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 43 ++++++++++------------------------- 1 file changed, 12 insertions(+), 31 deletions(-) diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index e1e9da42cb99..30c7357e980b 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -1090,36 +1090,6 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { _DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0, 0), }; -static void dtv_get_property_dump(struct dvb_frontend *fe, - struct dtv_property *tvp) -{ - int i; - - if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) { - dev_warn(fe->dvb->device, "%s: GET tvp.cmd = 0x%08x undefined\n" - , __func__, - tvp->cmd); - return; - } - - dev_dbg(fe->dvb->device, "%s: GET tvp.cmd = 0x%08x (%s)\n", __func__, - tvp->cmd, - dtv_cmds[tvp->cmd].name); - - if (dtv_cmds[tvp->cmd].buffer) { - dev_dbg(fe->dvb->device, "%s: tvp.u.buffer.len = 0x%02x\n", - __func__, tvp->u.buffer.len); - - for(i = 0; i < tvp->u.buffer.len; i++) - dev_dbg(fe->dvb->device, - "%s: tvp.u.buffer.data[0x%02x] = 0x%02x\n", - __func__, i, tvp->u.buffer.data[i]); - } else { - dev_dbg(fe->dvb->device, "%s: tvp.u.data = 0x%08x\n", __func__, - tvp->u.data); - } -} - /* Synchronise the legacy tuning parameters into the cache, so that demodulator * drivers can use a single set_frontend tuning function, regardless of whether * it's being used for the legacy or new API, reducing code and complexity. @@ -1512,7 +1482,18 @@ static int dtv_property_process_get(struct dvb_frontend *fe, return -EINVAL; } - dtv_get_property_dump(fe, tvp); + if (!dtv_cmds[tvp->cmd].buffer) + dev_dbg(fe->dvb->device, + "%s: GET cmd 0x%08x (%s) = 0x%08x\n", + __func__, tvp->cmd, dtv_cmds[tvp->cmd].name, + tvp->u.data); + else + dev_dbg(fe->dvb->device, + "%s: GET cmd 0x%08x (%s) len %d: %*ph\n", + __func__, + tvp->cmd, dtv_cmds[tvp->cmd].name, + tvp->u.buffer.len, + tvp->u.buffer.len, tvp->u.buffer.data); return 0; } -- cgit v1.2.3 From 198688cdc1544061ea1b7df3ff7dbae4f3338bb9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Sep 2017 19:11:22 -0400 Subject: media: dvb_demux.h: document structs defined on it There are three structs defined inside dvb_demux.h. None of them are currently documented. Add documentation for them. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_demux.c | 1 + drivers/media/dvb-core/dvb_demux.h | 59 +++++++++++++++++++++++++++++++------- 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index b9360cbc3519..acade7543b82 100644 --- a/drivers/media/dvb-core/dvb_demux.c +++ b/drivers/media/dvb-core/dvb_demux.c @@ -367,6 +367,7 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, else feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts); } + /* Used only on full-featured devices */ if (feed->ts_type & TS_DECODER) if (feed->demux->write_to_decoder) feed->demux->write_to_decoder(feed, buf, 188); diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h index 08cc86247f08..ed136836ab6e 100644 --- a/drivers/media/dvb-core/dvb_demux.h +++ b/drivers/media/dvb-core/dvb_demux.h @@ -95,16 +95,16 @@ struct dvb_demux_filter { * struct dvb_demux_feed - describes a DVB field * * @feed: a digital TV feed. It can either be a TS or a section feed: - * - if the feed is TS, it contains &struct dvb_ts_feed; - * - if the feed is section, it contains - * &struct dmx_section_feed. + * if the feed is TS, it contains &struct dvb_ts_feed @ts; + * if the feed is section, it contains + * &struct dmx_section_feed @sec. * @cb: digital TV callbacks. depending on the feed type, it can be: - * - if the feed is TS, it contains a dmx_ts_cb() callback; - * - if the feed is section, it contains a dmx_section_cb() - * callback. + * if the feed is TS, it contains a dmx_ts_cb() @ts callback; + * if the feed is section, it contains a dmx_section_cb() @sec + * callback. * * @demux: pointer to &struct dvb_demux. - * @priv: private data for the filter handling routine. + * @priv: private data that can optionally be used by a DVB driver. * @type: type of the filter, as defined by &enum dvb_dmx_filter_type. * @state: state of the filter as defined by &enum dvb_dmx_state. * @pid: PID to be filtered. @@ -119,7 +119,6 @@ struct dvb_demux_filter { * @list_head: head for the list of digital TV demux feeds. * @index: a unique index for each feed. Can be used as hardware * pid filter index. - * */ struct dvb_demux_feed { union { @@ -153,6 +152,44 @@ struct dvb_demux_feed { unsigned int index; }; +/** + * struct dvb_demux - represents a digital TV demux + * @dmx: embedded &struct dmx_demux with demux capabilities + * and callbacks. + * @priv: private data that can optionally be used by + * a DVB driver. + * @filternum: maximum amount of DVB filters. + * @feednum: maximum amount of DVB feeds. + * @start_feed: callback routine to be called in order to start + * a DVB feed. + * @stop_feed: callback routine to be called in order to stop + * a DVB feed. + * @write_to_decoder: callback routine to be called if the feed is TS and + * it is routed to an A/V decoder, when a new TS packet + * is received. + * Used only on av7110-av.c. + * @check_crc32: callback routine to check CRC. If not initialized, + * dvb_demux will use an internal one. + * @memcopy: callback routine to memcopy received data. + * If not initialized, dvb_demux will default to memcpy(). + * @users: counter for the number of demux opened file descriptors. + * Currently, it is limited to 10 users. + * @filter: pointer to &struct dvb_demux_filter. + * @feed: pointer to &struct dvb_demux_feed. + * @frontend_list: &struct list_head with frontends used by the demux. + * @pesfilter: array of &struct dvb_demux_feed with the PES types + * that will be filtered. + * @pids: list of filtered program IDs. + * @feed_list: &struct list_head with feeds. + * @tsbuf: temporary buffer used internally to store TS packets. + * @tsbufp: temporary buffer index used internally. + * @mutex: pointer to &struct mutex used to protect feed set + * logic. + * @lock: pointer to &spinlock_t, used to protect buffer handling. + * @cnt_storage: buffer used for TS/TEI continuity check. + * @speed_last_time: &ktime_t used for TS speed check. + * @speed_pkts_cnt: packets count used for TS speed check. + */ struct dvb_demux { struct dmx_demux dmx; void *priv; @@ -176,8 +213,6 @@ struct dvb_demux { struct dvb_demux_feed *pesfilter[DMX_PES_OTHER]; u16 pids[DMX_PES_OTHER]; - int playing; - int recording; #define DMX_MAX_PID 0x2000 struct list_head feed_list; @@ -191,6 +226,10 @@ struct dvb_demux { ktime_t speed_last_time; /* for TS speed check */ uint32_t speed_pkts_cnt; /* for TS speed check */ + + /* private: used only on av7110 */ + int playing; + int recording; }; int dvb_dmx_init(struct dvb_demux *dvbdemux); -- cgit v1.2.3 From 6128a68dbc0f5032fe9e55fbe5a712e713315ffd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 20 Sep 2017 09:08:20 -0400 Subject: media: dvb_demux.h: document functions The functions used on dvb_demux.h are largely used on DVB drivers. Yet, none of them are documented. No functional changes. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_demux.h | 106 +++++++++++++++++++++++++++++++++++-- 1 file changed, 103 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h index ed136836ab6e..9a77be02cbb1 100644 --- a/drivers/media/dvb-core/dvb_demux.h +++ b/drivers/media/dvb-core/dvb_demux.h @@ -232,13 +232,113 @@ struct dvb_demux { int recording; }; -int dvb_dmx_init(struct dvb_demux *dvbdemux); -void dvb_dmx_release(struct dvb_demux *dvbdemux); -void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, +/** + * dvb_dmx_init - initialize a digital TV demux struct. + * + * @demux: &struct dvb_demux to be initialized. + * + * Before being able to register a digital TV demux struct, drivers + * should call this routine. On its typical usage, some fields should + * be initialized at the driver before calling it. + * + * A typical usecase is:: + * + * dvb->demux.dmx.capabilities = + * DMX_TS_FILTERING | DMX_SECTION_FILTERING | + * DMX_MEMORY_BASED_FILTERING; + * dvb->demux.priv = dvb; + * dvb->demux.filternum = 256; + * dvb->demux.feednum = 256; + * dvb->demux.start_feed = driver_start_feed; + * dvb->demux.stop_feed = driver_stop_feed; + * ret = dvb_dmx_init(&dvb->demux); + * if (ret < 0) + * return ret; + */ +int dvb_dmx_init(struct dvb_demux *demux); + +/** + * dvb_dmx_release - releases a digital TV demux internal buffers. + * + * @demux: &struct dvb_demux to be released. + * + * The DVB core internally allocates data at @demux. This routine + * releases those data. Please notice that the struct itelf is not + * released, as it can be embedded on other structs. + */ +void dvb_dmx_release(struct dvb_demux *demux); + +/** + * dvb_dmx_swfilter_packets - use dvb software filter for a buffer with + * multiple MPEG-TS packets with 188 bytes each. + * + * @demux: pointer to &struct dvb_demux + * @buf: buffer with data to be filtered + * @count: number of MPEG-TS packets with size of 188. + * + * The routine will discard a DVB packet that don't start with 0x47. + * + * Use this routine if the DVB demux fills MPEG-TS buffers that are + * already aligned. + * + * NOTE: The @buf size should have size equal to ``count * 188``. + */ +void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, size_t count); + +/** + * dvb_dmx_swfilter - use dvb software filter for a buffer with + * multiple MPEG-TS packets with 188 bytes each. + * + * @demux: pointer to &struct dvb_demux + * @buf: buffer with data to be filtered + * @count: number of MPEG-TS packets with size of 188. + * + * If a DVB packet doesn't start with 0x47, it will seek for the first + * byte that starts with 0x47. + * + * Use this routine if the DVB demux fill buffers that may not start with + * a packet start mark (0x47). + * + * NOTE: The @buf size should have size equal to ``count * 188``. + */ void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count); + +/** + * dvb_dmx_swfilter_204 - use dvb software filter for a buffer with + * multiple MPEG-TS packets with 204 bytes each. + * + * @demux: pointer to &struct dvb_demux + * @buf: buffer with data to be filtered + * @count: number of MPEG-TS packets with size of 204. + * + * If a DVB packet doesn't start with 0x47, it will seek for the first + * byte that starts with 0x47. + * + * Use this routine if the DVB demux fill buffers that may not start with + * a packet start mark (0x47). + * + * NOTE: The @buf size should have size equal to ``count * 204``. + */ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count); + +/** + * dvb_dmx_swfilter_raw - make the raw data available to userspace without + * filtering + * + * @demux: pointer to &struct dvb_demux + * @buf: buffer with data + * @count: number of packets to be passed. The actual size of each packet + * depends on the &dvb_demux->feed->cb.ts logic. + * + * Use it if the driver needs to deliver the raw payload to userspace without + * passing through the kernel demux. That is meant to support some + * delivery systems that aren't based on MPEG-TS. + * + * This function relies on &dvb_demux->feed->cb.ts to actually handle the + * buffer. + */ void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count); -- cgit v1.2.3 From e7446385fe9131a2c93fb106dbb118d3de7b0138 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 20 Sep 2017 12:10:48 -0400 Subject: media: dmxdev.h: add kernel-doc markups for data types and functions Despite being used by DVB drivers, this header was not documented. Document it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dmxdev.h | 90 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-core/dmxdev.h b/drivers/media/dvb-core/dmxdev.h index 054fd4eb6192..5e795f5f0f41 100644 --- a/drivers/media/dvb-core/dmxdev.h +++ b/drivers/media/dvb-core/dmxdev.h @@ -36,12 +36,33 @@ #include "demux.h" #include "dvb_ringbuffer.h" +/** + * enum dmxdev_type - type of demux filter type. + * + * @DMXDEV_TYPE_NONE: no filter set. + * @DMXDEV_TYPE_SEC: section filter. + * @DMXDEV_TYPE_PES: Program Elementary Stream (PES) filter. + */ enum dmxdev_type { DMXDEV_TYPE_NONE, DMXDEV_TYPE_SEC, DMXDEV_TYPE_PES, }; +/** + * enum dmxdev_state - state machine for the dmxdev. + * + * @DMXDEV_STATE_FREE: indicates that the filter is freed. + * @DMXDEV_STATE_ALLOCATED: indicates that the filter was allocated + * to be used. + * @DMXDEV_STATE_SET: indicates that the filter parameters are set. + * @DMXDEV_STATE_GO: indicates that the filter is running. + * @DMXDEV_STATE_DONE: indicates that a packet was already filtered + * and the filter is now disabled. + * Set only if %DMX_ONESHOT. See + * &dmx_sct_filter_params. + * @DMXDEV_STATE_TIMEDOUT: Indicates a timeout condition. + */ enum dmxdev_state { DMXDEV_STATE_FREE, DMXDEV_STATE_ALLOCATED, @@ -51,12 +72,49 @@ enum dmxdev_state { DMXDEV_STATE_TIMEDOUT }; +/** + * struct dmxdev_feed - digital TV dmxdev feed + * + * @pid: Program ID to be filtered + * @ts: pointer to &struct dmx_ts_feed + * @next: &struct list_head pointing to the next feed. + */ + struct dmxdev_feed { u16 pid; struct dmx_ts_feed *ts; struct list_head next; }; +/** + * struct dmxdev_filter - digital TV dmxdev filter + * + * @filter: a dmxdev filter. Currently used only for section filter: + * if the filter is Section, it contains a + * &struct dmx_section_filter @sec pointer. + * @feed: a dmxdev feed. Depending on the feed type, it can be: + * for TS feed: a &struct list_head @ts list of TS and PES + * feeds; + * for section feed: a &struct dmx_section_feed @sec pointer. + * @params: dmxdev filter parameters. Depending on the feed type, it + * can be: + * for section filter: a &struct dmx_sct_filter_params @sec + * embedded struct; + * for a TS filter: a &struct dmx_pes_filter_params @pes + * embedded struct. + * @type: type of the dmxdev filter, as defined by &enum dmxdev_type. + * @state: state of the dmxdev filter, as defined by &enum dmxdev_state. + * @dev: pointer to &struct dmxdev. + * @buffer: an embedded &struct dvb_ringbuffer buffer. + * @mutex: protects the access to &struct dmxdev_filter. + * @timer: &struct timer_list embedded timer, used to check for + * feed timeouts. + * Only for section filter. + * @todo: index for the @secheader. + * Only for section filter. + * @secheader: buffer cache to parse the section header. + * Only for section filter. + */ struct dmxdev_filter { union { struct dmx_section_filter *sec; @@ -86,7 +144,23 @@ struct dmxdev_filter { u8 secheader[3]; }; - +/** + * struct dmxdev - Describes a digital TV demux device. + * + * @dvbdev: pointer to &struct dvb_device associated with + * the demux device node. + * @dvr_dvbdev: pointer to &struct dvb_device associated with + * the dvr device node. + * @filter: pointer to &struct dmxdev_filter. + * @demux: pointer to &struct dmx_demux. + * @filternum: number of filters. + * @capabilities: demux capabilities as defined by &enum dmx_demux_caps. + * @exit: flag to indicate that the demux is being released. + * @dvr_orig_fe: pointer to &struct dmx_frontend. + * @dvr_buffer: embedded &struct dvb_ringbuffer for DVB output. + * @mutex: protects the usage of this structure. + * @lock: protects access to &dmxdev->filter->data. + */ struct dmxdev { struct dvb_device *dvbdev; struct dvb_device *dvr_dvbdev; @@ -108,8 +182,20 @@ struct dmxdev { spinlock_t lock; }; +/** + * dvb_dmxdev_init - initializes a digital TV demux and registers both demux + * and DVR devices. + * + * @dmxdev: pointer to &struct dmxdev. + * @adap: pointer to &struct dvb_adapter. + */ +int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *adap); -int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *); +/** + * dvb_dmxdev_release - releases a digital TV demux and unregisters it. + * + * @dmxdev: pointer to &struct dmxdev. + */ void dvb_dmxdev_release(struct dmxdev *dmxdev); #endif /* _DMXDEV_H_ */ -- cgit v1.2.3 From 8c6b18631ff6a4823249becb51b428da5f0f9a40 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 19 Sep 2017 19:03:14 -0400 Subject: media: dtv-demux.rst: parse other demux headers with kernel-doc Now that we have kernel-doc markups at dvb_demux.h and dmxdev.h, parse them. Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/kapi/dtv-demux.rst | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Documentation/media/kapi/dtv-demux.rst b/Documentation/media/kapi/dtv-demux.rst index 3ee69266e206..7aa865a2b43f 100644 --- a/Documentation/media/kapi/dtv-demux.rst +++ b/Documentation/media/kapi/dtv-demux.rst @@ -66,7 +66,17 @@ function call directly from a hardware interrupt. This mechanism is implemented by :c:func:`dmx_ts_cb()` and :c:func:`dmx_section_cb()` callbacks. -Digital TV Demux functions and types -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Digital TV Demux device registration functions and data structures +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. kernel-doc:: drivers/media/dvb-core/dmxdev.h + +High-level Digital TV demux interface +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. kernel-doc:: drivers/media/dvb-core/dvb_demux.h + +Driver-internal low-level hardware specific driver demux interface +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. kernel-doc:: drivers/media/dvb-core/demux.h -- cgit v1.2.3 From b5b03a200934cad3c77e85026a3549847234f74e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 20 Sep 2017 13:51:06 -0400 Subject: media: dvb-net.rst: document DVB network kAPI interface That's the last DVB kAPI that misses documentation. Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/kapi/dtv-core.rst | 1 + Documentation/media/kapi/dtv-net.rst | 4 ++++ Documentation/media/uapi/dvb/net-types.rst | 2 +- drivers/media/dvb-core/dvb_net.h | 34 ++++++++++++++++++++++++++++-- 4 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 Documentation/media/kapi/dtv-net.rst diff --git a/Documentation/media/kapi/dtv-core.rst b/Documentation/media/kapi/dtv-core.rst index 8ee384f61fa0..bca743dc6b43 100644 --- a/Documentation/media/kapi/dtv-core.rst +++ b/Documentation/media/kapi/dtv-core.rst @@ -34,3 +34,4 @@ I2C bus. dtv-frontend dtv-demux dtv-ca + dtv-net diff --git a/Documentation/media/kapi/dtv-net.rst b/Documentation/media/kapi/dtv-net.rst new file mode 100644 index 000000000000..ced991b73d69 --- /dev/null +++ b/Documentation/media/kapi/dtv-net.rst @@ -0,0 +1,4 @@ +Digital TV Network kABI +----------------------- + +.. kernel-doc:: drivers/media/dvb-core/dvb_net.h diff --git a/Documentation/media/uapi/dvb/net-types.rst b/Documentation/media/uapi/dvb/net-types.rst index e1177bdcd623..8fa3292eaa42 100644 --- a/Documentation/media/uapi/dvb/net-types.rst +++ b/Documentation/media/uapi/dvb/net-types.rst @@ -1,6 +1,6 @@ .. -*- coding: utf-8; mode: rst -*- -.. _dmx_types: +.. _net_types: ************** Net Data Types diff --git a/drivers/media/dvb-core/dvb_net.h b/drivers/media/dvb-core/dvb_net.h index e9b18aa03e02..1eae8bad7cc1 100644 --- a/drivers/media/dvb-core/dvb_net.h +++ b/drivers/media/dvb-core/dvb_net.h @@ -30,6 +30,22 @@ #ifdef CONFIG_DVB_NET +/** + * struct dvb_net - describes a DVB network interface + * + * @dvbdev: pointer to &struct dvb_device. + * @device: array of pointers to &struct net_device. + * @state: array of integers to each net device. A value + * different than zero means that the interface is + * in usage. + * @exit: flag to indicate when the device is being removed. + * @demux: pointer to &struct dmx_demux. + * @ioctl_mutex: protect access to this struct. + * + * Currently, the core supports up to %DVB_NET_DEVICES_MAX (10) network + * devices. + */ + struct dvb_net { struct dvb_device *dvbdev; struct net_device *device[DVB_NET_DEVICES_MAX]; @@ -39,8 +55,22 @@ struct dvb_net { struct mutex ioctl_mutex; }; -void dvb_net_release(struct dvb_net *); -int dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *); +/** + * dvb_net_init - nitializes a digital TV network device and registers it. + * + * @adap: pointer to &struct dvb_adapter. + * @dvbnet: pointer to &struct dvb_net. + * @dmxdemux: pointer to &struct dmx_demux. + */ +int dvb_net_init(struct dvb_adapter *adap, struct dvb_net *dvbnet, + struct dmx_demux *dmxdemux); + +/** + * dvb_net_release - releases a digital TV network device and unregisters it. + * + * @dvbnet: pointer to &struct dvb_net. + */ +void dvb_net_release(struct dvb_net *dvbnet); #else -- cgit v1.2.3 From b33494e950c6d492c65799252cb8bc2692468221 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 20 Sep 2017 14:42:42 -0400 Subject: media: dvb uAPI docs: get rid of examples section That section is too outdated and got superseded by DVBv5 and by libdvbv5. Maybe some day we'll end adding updated examples there, but while nobody has time or interest of doing that, just mention that there and get rid of the current examples for good. Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/uapi/dvb/examples.rst | 378 +----------------------------- 1 file changed, 6 insertions(+), 372 deletions(-) diff --git a/Documentation/media/uapi/dvb/examples.rst b/Documentation/media/uapi/dvb/examples.rst index e0f627ca2e4d..16dd90fa9e94 100644 --- a/Documentation/media/uapi/dvb/examples.rst +++ b/Documentation/media/uapi/dvb/examples.rst @@ -6,377 +6,11 @@ Examples ******** -In this section we would like to present some examples for using the Digital -TV API. +In the past, we used to have a set of examples here. However, those +examples got out of date and doesn't even compile nowadays. -.. note:: +Also, nowadays, the best is to use the libdvbv5 DVB API nowadays, +with is fully documented. - This section is out of date, and the code below won't even - compile. Please refer to the - `libdvbv5 `__ for - updated/recommended examples. - - -.. _tuning: - -Example: Tuning -=============== - -We will start with a generic tuning subroutine that uses the frontend -and SEC, as well as the demux devices. The example is given for QPSK -tuners, but can easily be adjusted for QAM. - - -.. code-block:: c - - #include - #include - #include - #include - #include - #include - #include - #include - - #include - #include - #include - #include - - #define DMX "/dev/dvb/adapter0/demux1" - #define FRONT "/dev/dvb/adapter0/frontend1" - #define SEC "/dev/dvb/adapter0/sec1" - - /* routine for checking if we have a signal and other status information*/ - int FEReadStatus(int fd, fe_status_t *stat) - { - int ans; - - if ( (ans = ioctl(fd,FE_READ_STATUS,stat) < 0)){ - perror("FE READ STATUS: "); - return -1; - } - - if (*stat & FE_HAS_POWER) - printf("FE HAS POWER\\n"); - - if (*stat & FE_HAS_SIGNAL) - printf("FE HAS SIGNAL\\n"); - - if (*stat & FE_SPECTRUM_INV) - printf("SPEKTRUM INV\\n"); - - return 0; - } - - - /* tune qpsk */ - /* freq: frequency of transponder */ - /* vpid, apid, tpid: PIDs of video, audio and teletext TS packets */ - /* diseqc: DiSEqC address of the used LNB */ - /* pol: Polarisation */ - /* srate: Symbol Rate */ - /* fec. FEC */ - /* lnb_lof1: local frequency of lower LNB band */ - /* lnb_lof2: local frequency of upper LNB band */ - /* lnb_slof: switch frequency of LNB */ - - int set_qpsk_channel(int freq, int vpid, int apid, int tpid, - int diseqc, int pol, int srate, int fec, int lnb_lof1, - int lnb_lof2, int lnb_slof) - { - struct secCommand scmd; - struct secCmdSequence scmds; - struct dmx_pes_filter_params pesFilterParams; - FrontendParameters frp; - struct pollfd pfd[1]; - FrontendEvent event; - int demux1, demux2, demux3, front; - - frequency = (uint32_t) freq; - symbolrate = (uint32_t) srate; - - if((front = open(FRONT,O_RDWR)) < 0){ - perror("FRONTEND DEVICE: "); - return -1; - } - - if((sec = open(SEC,O_RDWR)) < 0){ - perror("SEC DEVICE: "); - return -1; - } - - if (demux1 < 0){ - if ((demux1=open(DMX, O_RDWR|O_NONBLOCK)) - < 0){ - perror("DEMUX DEVICE: "); - return -1; - } - } - - if (demux2 < 0){ - if ((demux2=open(DMX, O_RDWR|O_NONBLOCK)) - < 0){ - perror("DEMUX DEVICE: "); - return -1; - } - } - - if (demux3 < 0){ - if ((demux3=open(DMX, O_RDWR|O_NONBLOCK)) - < 0){ - perror("DEMUX DEVICE: "); - return -1; - } - } - - if (freq < lnb_slof) { - frp.Frequency = (freq - lnb_lof1); - scmds.continuousTone = SEC_TONE_OFF; - } else { - frp.Frequency = (freq - lnb_lof2); - scmds.continuousTone = SEC_TONE_ON; - } - frp.Inversion = INVERSION_AUTO; - if (pol) scmds.voltage = SEC_VOLTAGE_18; - else scmds.voltage = SEC_VOLTAGE_13; - - scmd.type=0; - scmd.u.diseqc.addr=0x10; - scmd.u.diseqc.cmd=0x38; - scmd.u.diseqc.numParams=1; - scmd.u.diseqc.params[0] = 0xF0 | ((diseqc * 4) & 0x0F) | - (scmds.continuousTone == SEC_TONE_ON ? 1 : 0) | - (scmds.voltage==SEC_VOLTAGE_18 ? 2 : 0); - - scmds.miniCommand=SEC_MINI_NONE; - scmds.numCommands=1; - scmds.commands=&scmd; - if (ioctl(sec, SEC_SEND_SEQUENCE, &scmds) < 0){ - perror("SEC SEND: "); - return -1; - } - - if (ioctl(sec, SEC_SEND_SEQUENCE, &scmds) < 0){ - perror("SEC SEND: "); - return -1; - } - - frp.u.qpsk.SymbolRate = srate; - frp.u.qpsk.FEC_inner = fec; - - if (ioctl(front, FE_SET_FRONTEND, &frp) < 0){ - perror("QPSK TUNE: "); - return -1; - } - - pfd[0].fd = front; - pfd[0].events = POLLIN; - - if (poll(pfd,1,3000)){ - if (pfd[0].revents & POLLIN){ - printf("Getting QPSK event\\n"); - if ( ioctl(front, FE_GET_EVENT, &event) - - == -EOVERFLOW){ - perror("qpsk get event"); - return -1; - } - printf("Received "); - switch(event.type){ - case FE_UNEXPECTED_EV: - printf("unexpected event\\n"); - return -1; - case FE_FAILURE_EV: - printf("failure event\\n"); - return -1; - - case FE_COMPLETION_EV: - printf("completion event\\n"); - } - } - } - - - pesFilterParams.pid = vpid; - pesFilterParams.input = DMX_IN_FRONTEND; - pesFilterParams.output = DMX_OUT_DECODER; - pesFilterParams.pes_type = DMX_PES_VIDEO; - pesFilterParams.flags = DMX_IMMEDIATE_START; - if (ioctl(demux1, DMX_SET_PES_FILTER, &pesFilterParams) < 0){ - perror("set_vpid"); - return -1; - } - - pesFilterParams.pid = apid; - pesFilterParams.input = DMX_IN_FRONTEND; - pesFilterParams.output = DMX_OUT_DECODER; - pesFilterParams.pes_type = DMX_PES_AUDIO; - pesFilterParams.flags = DMX_IMMEDIATE_START; - if (ioctl(demux2, DMX_SET_PES_FILTER, &pesFilterParams) < 0){ - perror("set_apid"); - return -1; - } - - pesFilterParams.pid = tpid; - pesFilterParams.input = DMX_IN_FRONTEND; - pesFilterParams.output = DMX_OUT_DECODER; - pesFilterParams.pes_type = DMX_PES_TELETEXT; - pesFilterParams.flags = DMX_IMMEDIATE_START; - if (ioctl(demux3, DMX_SET_PES_FILTER, &pesFilterParams) < 0){ - perror("set_tpid"); - return -1; - } - - return has_signal(fds); - } - -The program assumes that you are using a universal LNB and a standard -DiSEqC switch with up to 4 addresses. Of course, you could build in some -more checking if tuning was successful and maybe try to repeat the -tuning process. Depending on the external hardware, i.e. LNB and DiSEqC -switch, and weather conditions this may be necessary. - - -.. _the_dvr_device: - -Example: The DVR device -======================== - -The following program code shows how to use the DVR device for -recording. - - -.. code-block:: c - - #include - #include - #include - #include - #include - #include - #include - #include - - #include - #include - #include - #define DVR "/dev/dvb/adapter0/dvr1" - #define AUDIO "/dev/dvb/adapter0/audio1" - #define VIDEO "/dev/dvb/adapter0/video1" - - #define BUFFY (188*20) - #define MAX_LENGTH (1024*1024*5) /* record 5MB */ - - - /* switch the demuxes to recording, assuming the transponder is tuned */ - - /* demux1, demux2: file descriptor of video and audio filters */ - /* vpid, apid: PIDs of video and audio channels */ - - int switch_to_record(int demux1, int demux2, uint16_t vpid, uint16_t apid) - { - struct dmx_pes_filter_params pesFilterParams; - - if (demux1 < 0){ - if ((demux1=open(DMX, O_RDWR|O_NONBLOCK)) - < 0){ - perror("DEMUX DEVICE: "); - return -1; - } - } - - if (demux2 < 0){ - if ((demux2=open(DMX, O_RDWR|O_NONBLOCK)) - < 0){ - perror("DEMUX DEVICE: "); - return -1; - } - } - - pesFilterParams.pid = vpid; - pesFilterParams.input = DMX_IN_FRONTEND; - pesFilterParams.output = DMX_OUT_TS_TAP; - pesFilterParams.pes_type = DMX_PES_VIDEO; - pesFilterParams.flags = DMX_IMMEDIATE_START; - if (ioctl(demux1, DMX_SET_PES_FILTER, &pesFilterParams) < 0){ - perror("DEMUX DEVICE"); - return -1; - } - pesFilterParams.pid = apid; - pesFilterParams.input = DMX_IN_FRONTEND; - pesFilterParams.output = DMX_OUT_TS_TAP; - pesFilterParams.pes_type = DMX_PES_AUDIO; - pesFilterParams.flags = DMX_IMMEDIATE_START; - if (ioctl(demux2, DMX_SET_PES_FILTER, &pesFilterParams) < 0){ - perror("DEMUX DEVICE"); - return -1; - } - return 0; - } - - /* start recording MAX_LENGTH , assuming the transponder is tuned */ - - /* demux1, demux2: file descriptor of video and audio filters */ - /* vpid, apid: PIDs of video and audio channels */ - int record_dvr(int demux1, int demux2, uint16_t vpid, uint16_t apid) - { - int i; - int len; - int written; - uint8_t buf[BUFFY]; - uint64_t length; - struct pollfd pfd[1]; - int dvr, dvr_out; - - /* open dvr device */ - if ((dvr = open(DVR, O_RDONLY|O_NONBLOCK)) < 0){ - perror("DVR DEVICE"); - return -1; - } - - /* switch video and audio demuxes to dvr */ - printf ("Switching dvr on\\n"); - i = switch_to_record(demux1, demux2, vpid, apid); - printf("finished: "); - - printf("Recording %2.0f MB of test file in TS format\\n", - MAX_LENGTH/(1024.0*1024.0)); - length = 0; - - /* open output file */ - if ((dvr_out = open(DVR_FILE,O_WRONLY|O_CREAT - |O_TRUNC, S_IRUSR|S_IWUSR - |S_IRGRP|S_IWGRP|S_IROTH| - S_IWOTH)) < 0){ - perror("Can't open file for dvr test"); - return -1; - } - - pfd[0].fd = dvr; - pfd[0].events = POLLIN; - - /* poll for dvr data and write to file */ - while (length < MAX_LENGTH ) { - if (poll(pfd,1,1)){ - if (pfd[0].revents & POLLIN){ - len = read(dvr, buf, BUFFY); - if (len < 0){ - perror("recording"); - return -1; - } - if (len > 0){ - written = 0; - while (written < len) - written += - write (dvr_out, - buf, len); - length += len; - printf("written %2.0f MB\\r", - length/1024./1024.); - } - } - } - } - return 0; - } +Please refer to the `libdvbv5 `__ +for updated/recommended examples. -- cgit v1.2.3 From 01153bf04db18d5fcd30df64ffe428db7ff7bada Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 11 Oct 2017 13:48:57 -0400 Subject: media: dvb: do some coding style cleanup Fix a bunch of coding style issues found by checkpatch on the part of the code that the previous patches touched. WARNING: please, no space before tabs + * ^I^Icallback.$ ERROR: space required before the open parenthesis '(' + switch(cmd) { WARNING: line over 80 characters + err = dtv_property_process_get(fe, &getp, tvp + i, file); WARNING: line over 80 characters + err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg); ERROR: "(foo*)" should be "(foo *)" + err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg); WARNING: line over 80 characters + err = fe->ops.read_signal_strength(fe, (__u16 *) parg); Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_demux.h | 2 +- drivers/media/dvb-core/dvb_frontend.c | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h index 9a77be02cbb1..cc048f09aa85 100644 --- a/drivers/media/dvb-core/dvb_demux.h +++ b/drivers/media/dvb-core/dvb_demux.h @@ -101,7 +101,7 @@ struct dvb_demux_filter { * @cb: digital TV callbacks. depending on the feed type, it can be: * if the feed is TS, it contains a dmx_ts_cb() @ts callback; * if the feed is section, it contains a dmx_section_cb() @sec - * callback. + * callback. * * @demux: pointer to &struct dvb_demux. * @priv: private data that can optionally be used by a DVB driver. diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 30c7357e980b..0c7897379535 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -2096,7 +2096,7 @@ static int dvb_frontend_handle_ioctl(struct file *file, dev_dbg(fe->dvb->device, "%s:\n", __func__); - switch(cmd) { + switch (cmd) { case FE_SET_PROPERTY: { struct dtv_properties *tvps = parg; struct dtv_property *tvp = NULL; @@ -2164,7 +2164,8 @@ static int dvb_frontend_handle_ioctl(struct file *file, } } for (i = 0; i < tvps->num; i++) { - err = dtv_property_process_get(fe, &getp, tvp + i, file); + err = dtv_property_process_get(fe, &getp, + tvp + i, file); if (err < 0) { kfree(tvp); return err; @@ -2296,7 +2297,7 @@ static int dvb_frontend_handle_ioctl(struct file *file, case FE_DISEQC_RECV_SLAVE_REPLY: if (fe->ops.diseqc_recv_slave_reply) - err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg); + err = fe->ops.diseqc_recv_slave_reply(fe, parg); break; case FE_ENABLE_HIGH_LNB_VOLTAGE: @@ -2381,7 +2382,7 @@ static int dvb_frontend_handle_ioctl(struct file *file, case FE_READ_BER: if (fe->ops.read_ber) { if (fepriv->thread) - err = fe->ops.read_ber(fe, (__u32 *) parg); + err = fe->ops.read_ber(fe, parg); else err = -EAGAIN; } @@ -2390,7 +2391,7 @@ static int dvb_frontend_handle_ioctl(struct file *file, case FE_READ_SIGNAL_STRENGTH: if (fe->ops.read_signal_strength) { if (fepriv->thread) - err = fe->ops.read_signal_strength(fe, (__u16 *) parg); + err = fe->ops.read_signal_strength(fe, parg); else err = -EAGAIN; } @@ -2399,7 +2400,7 @@ static int dvb_frontend_handle_ioctl(struct file *file, case FE_READ_SNR: if (fe->ops.read_snr) { if (fepriv->thread) - err = fe->ops.read_snr(fe, (__u16 *) parg); + err = fe->ops.read_snr(fe, parg); else err = -EAGAIN; } @@ -2408,7 +2409,7 @@ static int dvb_frontend_handle_ioctl(struct file *file, case FE_READ_UNCORRECTED_BLOCKS: if (fe->ops.read_ucblocks) { if (fepriv->thread) - err = fe->ops.read_ucblocks(fe, (__u32 *) parg); + err = fe->ops.read_ucblocks(fe, parg); else err = -EAGAIN; } -- cgit v1.2.3 From 8382e556b1a2f30c4bf866f021b33577a64f9ebf Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 11 Oct 2017 15:29:46 -0400 Subject: Simplify major/minor non-dynamic logic changeset 6bbf7a855d20 ("media: dvbdev: convert DVB device types into an enum") added a new warning on gcc 6: >> drivers/media/dvb-core/dvbdev.c:86:1: warning: control reaches end of non-void function [-Wreturn-type] That's because gcc is not smart enough to see that all types are present at the switch. Also, the current code is not too optimized. So, replace it to a more optimized one, based on a static table. Reported-by: kbuild test robot Fixes: 6bbf7a855d20 ("media: dvbdev: convert DVB device types into an enum") Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvbdev.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index a53eb53a4fd5..060c60ddfcc3 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -68,22 +68,20 @@ static const char * const dnames[] = { #else #define DVB_MAX_IDS 4 -static int nums2minor(int num, enum dvb_device_type type, int id) -{ - int n = (num << 6) | (id << 4); +static const u8 minor_type[] = { + [DVB_DEVICE_VIDEO] = 0, + [DVB_DEVICE_AUDIO] = 1, + [DVB_DEVICE_SEC] = 2, + [DVB_DEVICE_FRONTEND] = 3, + [DVB_DEVICE_DEMUX] = 4, + [DVB_DEVICE_DVR] = 5, + [DVB_DEVICE_CA] = 6, + [DVB_DEVICE_NET] = 7, + [DVB_DEVICE_OSD] = 8, +}; - switch (type) { - case DVB_DEVICE_VIDEO: return n; - case DVB_DEVICE_AUDIO: return n | 1; - case DVB_DEVICE_SEC: return n | 2; - case DVB_DEVICE_FRONTEND: return n | 3; - case DVB_DEVICE_DEMUX: return n | 4; - case DVB_DEVICE_DVR: return n | 5; - case DVB_DEVICE_CA: return n | 6; - case DVB_DEVICE_NET: return n | 7; - case DVB_DEVICE_OSD: return n | 8; - } -} +#define nums2minor(num, type, id) \ + (((num) << 6) | ((id) << 4) | minor_type[type]) #define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64) #endif -- cgit v1.2.3 From 7ef3b44ceafb5456b7e43e2bd96e22bb696806c9 Mon Sep 17 00:00:00 2001 From: Jacob Chen Date: Wed, 11 Oct 2017 00:29:34 -0700 Subject: [media] dt-bindings: Document the Rockchip RGA bindings Add DT bindings documentation for Rockchip RGA Signed-off-by: Jacob Chen Signed-off-by: Yakir Yang Acked-by: Rob Herring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/rockchip-rga.txt | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/rockchip-rga.txt diff --git a/Documentation/devicetree/bindings/media/rockchip-rga.txt b/Documentation/devicetree/bindings/media/rockchip-rga.txt new file mode 100644 index 000000000000..fd5276abfad6 --- /dev/null +++ b/Documentation/devicetree/bindings/media/rockchip-rga.txt @@ -0,0 +1,33 @@ +device-tree bindings for rockchip 2D raster graphic acceleration controller (RGA) + +RGA is a standalone 2D raster graphic acceleration unit. It accelerates 2D +graphics operations, such as point/line drawing, image scaling, rotation, +BitBLT, alpha blending and image blur/sharpness. + +Required properties: +- compatible: value should be one of the following + "rockchip,rk3288-rga"; + "rockchip,rk3399-rga"; + +- interrupts: RGA interrupt specifier. + +- clocks: phandle to RGA sclk/hclk/aclk clocks + +- clock-names: should be "aclk", "hclk" and "sclk" + +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: should be "core", "axi" and "ahb" + +Example: +SoC-specific DT entry: + rga: rga@ff680000 { + compatible = "rockchip,rk3399-rga"; + reg = <0xff680000 0x10000>; + interrupts = ; + clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>, <&cru SCLK_RGA_CORE>; + clock-names = "aclk", "hclk", "sclk"; + + resets = <&cru SRST_RGA_CORE>, <&cru SRST_A_RGA>, <&cru SRST_H_RGA>; + reset-names = "core, "axi", "ahb"; + }; -- cgit v1.2.3 From f7e7b48e6d796da85d99b318def20d9313ef61df Mon Sep 17 00:00:00 2001 From: Jacob Chen Date: Wed, 11 Oct 2017 00:29:35 -0700 Subject: [media] rockchip/rga: v4l2 m2m support Rockchip RGA is a separate 2D raster graphic acceleration unit. It accelerates 2D graphics operations, such as point/line drawing, image scaling, rotation, BitBLT, alpha blending and image blur/sharpness The driver supports various operations from the rendering pipeline. - copy - fast solid color fill - rotation - flip - alpha blending The code in rga-hw.c is used to configure regs according to operations The code in rga-buf.c is used to create private mmu table for RGA. Signed-off-by: Jacob Chen Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 15 + drivers/media/platform/Makefile | 2 + drivers/media/platform/rockchip/rga/Makefile | 3 + drivers/media/platform/rockchip/rga/rga-buf.c | 154 ++++ drivers/media/platform/rockchip/rga/rga-hw.c | 421 ++++++++++ drivers/media/platform/rockchip/rga/rga-hw.h | 437 +++++++++++ drivers/media/platform/rockchip/rga/rga.c | 1012 +++++++++++++++++++++++++ drivers/media/platform/rockchip/rga/rga.h | 125 +++ 8 files changed, 2169 insertions(+) create mode 100644 drivers/media/platform/rockchip/rga/Makefile create mode 100644 drivers/media/platform/rockchip/rga/rga-buf.c create mode 100644 drivers/media/platform/rockchip/rga/rga-hw.c create mode 100644 drivers/media/platform/rockchip/rga/rga-hw.h create mode 100644 drivers/media/platform/rockchip/rga/rga.c create mode 100644 drivers/media/platform/rockchip/rga/rga.h diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index e4c89a16a3e7..1bf47e9683ca 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -458,6 +458,21 @@ config VIDEO_RENESAS_VSP1 To compile this driver as a module, choose M here: the module will be called vsp1. +config VIDEO_ROCKCHIP_RGA + tristate "Rockchip Raster 2d Graphic Acceleration Unit" + depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA + depends on ARCH_ROCKCHIP || COMPILE_TEST + select VIDEOBUF2_DMA_SG + select V4L2_MEM2MEM_DEV + default n + ---help--- + This is a v4l2 driver for Rockchip SOC RGA 2d graphics accelerator. + Rockchip RGA is a separate 2D raster graphic acceleration unit. + It accelerates 2D graphics operations, such as point/line drawing, + image scaling, rotation, BitBLT, alpha blending and image blur/sharpness. + + To compile this driver as a module choose m here. + config VIDEO_TI_VPE tristate "TI VPE (Video Processing Engine) driver" depends on VIDEO_DEV && VIDEO_V4L2 diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 9bf48f118537..1530b096db10 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -64,6 +64,8 @@ obj-$(CONFIG_VIDEO_RENESAS_FDP1) += rcar_fdp1.o obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/ +obj-$(CONFIG_VIDEO_ROCKCHIP_RGA) += rockchip/rga/ + obj-y += omap/ obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/ diff --git a/drivers/media/platform/rockchip/rga/Makefile b/drivers/media/platform/rockchip/rga/Makefile new file mode 100644 index 000000000000..92fe25490ccd --- /dev/null +++ b/drivers/media/platform/rockchip/rga/Makefile @@ -0,0 +1,3 @@ +rockchip-rga-objs := rga.o rga-hw.o rga-buf.o + +obj-$(CONFIG_VIDEO_ROCKCHIP_RGA) += rockchip-rga.o diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c new file mode 100644 index 000000000000..49cacc7a48d1 --- /dev/null +++ b/drivers/media/platform/rockchip/rga/rga-buf.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2017 Fuzhou Rockchip Electronics Co.Ltd + * Author: Jacob Chen + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +#include +#include +#include +#include +#include + +#include "rga-hw.h" +#include "rga.h" + +static int +rga_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], struct device *alloc_devs[]) +{ + struct rga_ctx *ctx = vb2_get_drv_priv(vq); + struct rga_frame *f = rga_get_frame(ctx, vq->type); + + if (IS_ERR(f)) + return PTR_ERR(f); + + if (*nplanes) + return sizes[0] < f->size ? -EINVAL : 0; + + sizes[0] = f->size; + *nplanes = 1; + + return 0; +} + +static int rga_buf_prepare(struct vb2_buffer *vb) +{ + struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct rga_frame *f = rga_get_frame(ctx, vb->vb2_queue->type); + + if (IS_ERR(f)) + return PTR_ERR(f); + + vb2_set_plane_payload(vb, 0, f->size); + + return 0; +} + +static void rga_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); +} + +static int rga_buf_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct rga_ctx *ctx = vb2_get_drv_priv(q); + struct rockchip_rga *rga = ctx->rga; + int ret, i; + + ret = pm_runtime_get_sync(rga->dev); + + if (!ret) + return 0; + + for (i = 0; i < q->num_buffers; ++i) { + if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) { + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(q->bufs[i]), + VB2_BUF_STATE_QUEUED); + } + } + + return ret; +} + +static void rga_buf_stop_streaming(struct vb2_queue *q) +{ + struct rga_ctx *ctx = vb2_get_drv_priv(q); + struct rockchip_rga *rga = ctx->rga; + struct vb2_v4l2_buffer *vbuf; + + for (;;) { + if (V4L2_TYPE_IS_OUTPUT(q->type)) + vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + else + vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (!vbuf) + break; + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); + } + + pm_runtime_put(rga->dev); +} + +const struct vb2_ops rga_qops = { + .queue_setup = rga_queue_setup, + .buf_prepare = rga_buf_prepare, + .buf_queue = rga_buf_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = rga_buf_start_streaming, + .stop_streaming = rga_buf_stop_streaming, +}; + +/* RGA MMU is a 1-Level MMU, so it can't be used through the IOMMU API. + * We use it more like a scatter-gather list. + */ +void rga_buf_map(struct vb2_buffer *vb) +{ + struct rga_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct rockchip_rga *rga = ctx->rga; + struct sg_table *sgt; + struct scatterlist *sgl; + unsigned int *pages; + unsigned int address, len, i, p; + unsigned int mapped_size = 0; + + if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + pages = rga->src_mmu_pages; + else + pages = rga->dst_mmu_pages; + + /* Create local MMU table for RGA */ + sgt = vb2_plane_cookie(vb, 0); + + for_each_sg(sgt->sgl, sgl, sgt->nents, i) { + len = sg_dma_len(sgl) >> PAGE_SHIFT; + address = sg_phys(sgl); + + for (p = 0; p < len; p++) { + dma_addr_t phys = address + (p << PAGE_SHIFT); + + pages[mapped_size + p] = phys; + } + + mapped_size += len; + } + + /* sync local MMU table for RGA */ + dma_sync_single_for_device(rga->dev, virt_to_phys(pages), + 8 * PAGE_SIZE, DMA_BIDIRECTIONAL); +} diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c new file mode 100644 index 000000000000..0645481c9a5e --- /dev/null +++ b/drivers/media/platform/rockchip/rga/rga-hw.c @@ -0,0 +1,421 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Jacob Chen + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +#include "rga-hw.h" +#include "rga.h" + +enum e_rga_start_pos { + LT = 0, + LB = 1, + RT = 2, + RB = 3, +}; + +struct rga_addr_offset { + unsigned int y_off; + unsigned int u_off; + unsigned int v_off; +}; + +struct rga_corners_addr_offset { + struct rga_addr_offset left_top; + struct rga_addr_offset right_top; + struct rga_addr_offset left_bottom; + struct rga_addr_offset right_bottom; +}; + +static unsigned int rga_get_scaling(unsigned int src, unsigned int dst) +{ + /* + * The rga hw scaling factor is a normalized inverse of the + * scaling factor. + * For example: When source width is 100 and destination width is 200 + * (scaling of 2x), then the hw factor is NC * 100 / 200. + * The normalization factor (NC) is 2^16 = 0x10000. + */ + + return (src > dst) ? ((dst << 16) / src) : ((src << 16) / dst); +} + +static struct rga_corners_addr_offset +rga_get_addr_offset(struct rga_frame *frm, unsigned int x, unsigned int y, + unsigned int w, unsigned int h) +{ + struct rga_corners_addr_offset offsets; + struct rga_addr_offset *lt, *lb, *rt, *rb; + unsigned int x_div = 0, + y_div = 0, uv_stride = 0, pixel_width = 0, uv_factor = 0; + + lt = &offsets.left_top; + lb = &offsets.left_bottom; + rt = &offsets.right_top; + rb = &offsets.right_bottom; + + x_div = frm->fmt->x_div; + y_div = frm->fmt->y_div; + uv_factor = frm->fmt->uv_factor; + uv_stride = frm->stride / x_div; + pixel_width = frm->stride / frm->width; + + lt->y_off = y * frm->stride + x * pixel_width; + lt->u_off = + frm->width * frm->height + (y / y_div) * uv_stride + x / x_div; + lt->v_off = lt->u_off + frm->width * frm->height / uv_factor; + + lb->y_off = lt->y_off + (h - 1) * frm->stride; + lb->u_off = lt->u_off + (h / y_div - 1) * uv_stride; + lb->v_off = lt->v_off + (h / y_div - 1) * uv_stride; + + rt->y_off = lt->y_off + (w - 1) * pixel_width; + rt->u_off = lt->u_off + w / x_div - 1; + rt->v_off = lt->v_off + w / x_div - 1; + + rb->y_off = lb->y_off + (w - 1) * pixel_width; + rb->u_off = lb->u_off + w / x_div - 1; + rb->v_off = lb->v_off + w / x_div - 1; + + return offsets; +} + +static struct rga_addr_offset *rga_lookup_draw_pos(struct + rga_corners_addr_offset + * offsets, u32 rotate_mode, + u32 mirr_mode) +{ + static enum e_rga_start_pos rot_mir_point_matrix[4][4] = { + { + LT, RT, LB, RB, + }, + { + RT, LT, RB, LB, + }, + { + RB, LB, RT, LT, + }, + { + LB, RB, LT, RT, + }, + }; + + if (!offsets) + return NULL; + + switch (rot_mir_point_matrix[rotate_mode][mirr_mode]) { + case LT: + return &offsets->left_top; + case LB: + return &offsets->left_bottom; + case RT: + return &offsets->right_top; + case RB: + return &offsets->right_bottom; + } + + return NULL; +} + +static void rga_cmd_set_src_addr(struct rga_ctx *ctx, void *mmu_pages) +{ + struct rockchip_rga *rga = ctx->rga; + u32 *dest = rga->cmdbuf_virt; + unsigned int reg; + + reg = RGA_MMU_SRC_BASE - RGA_MODE_BASE_REG; + dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4; + + reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG; + dest[reg >> 2] |= 0x7; +} + +static void rga_cmd_set_src1_addr(struct rga_ctx *ctx, void *mmu_pages) +{ + struct rockchip_rga *rga = ctx->rga; + u32 *dest = rga->cmdbuf_virt; + unsigned int reg; + + reg = RGA_MMU_SRC1_BASE - RGA_MODE_BASE_REG; + dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4; + + reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG; + dest[reg >> 2] |= 0x7 << 4; +} + +static void rga_cmd_set_dst_addr(struct rga_ctx *ctx, void *mmu_pages) +{ + struct rockchip_rga *rga = ctx->rga; + u32 *dest = rga->cmdbuf_virt; + unsigned int reg; + + reg = RGA_MMU_DST_BASE - RGA_MODE_BASE_REG; + dest[reg >> 2] = virt_to_phys(mmu_pages) >> 4; + + reg = RGA_MMU_CTRL1 - RGA_MODE_BASE_REG; + dest[reg >> 2] |= 0x7 << 8; +} + +static void rga_cmd_set_trans_info(struct rga_ctx *ctx) +{ + struct rockchip_rga *rga = ctx->rga; + u32 *dest = rga->cmdbuf_virt; + unsigned int scale_dst_w, scale_dst_h; + unsigned int src_h, src_w, src_x, src_y, dst_h, dst_w, dst_x, dst_y; + union rga_src_info src_info; + union rga_dst_info dst_info; + union rga_src_x_factor x_factor; + union rga_src_y_factor y_factor; + union rga_src_vir_info src_vir_info; + union rga_src_act_info src_act_info; + union rga_dst_vir_info dst_vir_info; + union rga_dst_act_info dst_act_info; + + struct rga_addr_offset *dst_offset; + struct rga_corners_addr_offset offsets; + struct rga_corners_addr_offset src_offsets; + + src_h = ctx->in.crop.height; + src_w = ctx->in.crop.width; + src_x = ctx->in.crop.left; + src_y = ctx->in.crop.top; + dst_h = ctx->out.crop.height; + dst_w = ctx->out.crop.width; + dst_x = ctx->out.crop.left; + dst_y = ctx->out.crop.top; + + src_info.val = dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2]; + dst_info.val = dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2]; + x_factor.val = dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2]; + y_factor.val = dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2]; + src_vir_info.val = dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2]; + src_act_info.val = dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2]; + dst_vir_info.val = dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2]; + dst_act_info.val = dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2]; + + src_info.data.format = ctx->in.fmt->hw_format; + src_info.data.swap = ctx->in.fmt->color_swap; + dst_info.data.format = ctx->out.fmt->hw_format; + dst_info.data.swap = ctx->out.fmt->color_swap; + + if (ctx->in.fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) { + if (ctx->out.fmt->hw_format < RGA_COLOR_FMT_YUV422SP) { + switch (ctx->in.colorspace) { + case V4L2_COLORSPACE_REC709: + src_info.data.csc_mode = + RGA_SRC_CSC_MODE_BT709_R0; + break; + default: + src_info.data.csc_mode = + RGA_SRC_CSC_MODE_BT601_R0; + break; + } + } + } + + if (ctx->out.fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) { + switch (ctx->out.colorspace) { + case V4L2_COLORSPACE_REC709: + dst_info.data.csc_mode = RGA_SRC_CSC_MODE_BT709_R0; + break; + default: + dst_info.data.csc_mode = RGA_DST_CSC_MODE_BT601_R0; + break; + } + } + + if (ctx->vflip) + src_info.data.mir_mode |= RGA_SRC_MIRR_MODE_X; + + if (ctx->hflip) + src_info.data.mir_mode |= RGA_SRC_MIRR_MODE_Y; + + switch (ctx->rotate) { + case 90: + src_info.data.rot_mode = RGA_SRC_ROT_MODE_90_DEGREE; + break; + case 180: + src_info.data.rot_mode = RGA_SRC_ROT_MODE_180_DEGREE; + break; + case 270: + src_info.data.rot_mode = RGA_SRC_ROT_MODE_270_DEGREE; + break; + default: + src_info.data.rot_mode = RGA_SRC_ROT_MODE_0_DEGREE; + break; + } + + /* + * Cacluate the up/down scaling mode/factor. + * + * RGA used to scale the picture first, and then rotate second, + * so we need to swap the w/h when rotate degree is 90/270. + */ + if (src_info.data.rot_mode == RGA_SRC_ROT_MODE_90_DEGREE || + src_info.data.rot_mode == RGA_SRC_ROT_MODE_270_DEGREE) { + if (rga->version.major == 0 || rga->version.minor == 0) { + if (dst_w == src_h) + src_h -= 8; + if (abs(src_w - dst_h) < 16) + src_w -= 16; + } + + scale_dst_h = dst_w; + scale_dst_w = dst_h; + } else { + scale_dst_w = dst_w; + scale_dst_h = dst_h; + } + + if (src_w == scale_dst_w) { + src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_NO; + x_factor.val = 0; + } else if (src_w > scale_dst_w) { + src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_DOWN; + x_factor.data.down_scale_factor = + rga_get_scaling(src_w, scale_dst_w) + 1; + } else { + src_info.data.hscl_mode = RGA_SRC_HSCL_MODE_UP; + x_factor.data.up_scale_factor = + rga_get_scaling(src_w - 1, scale_dst_w - 1); + } + + if (src_h == scale_dst_h) { + src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_NO; + y_factor.val = 0; + } else if (src_h > scale_dst_h) { + src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_DOWN; + y_factor.data.down_scale_factor = + rga_get_scaling(src_h, scale_dst_h) + 1; + } else { + src_info.data.vscl_mode = RGA_SRC_VSCL_MODE_UP; + y_factor.data.up_scale_factor = + rga_get_scaling(src_h - 1, scale_dst_h - 1); + } + + /* + * Cacluate the framebuffer virtual strides and active size, + * note that the step of vir_stride / vir_width is 4 byte words + */ + src_vir_info.data.vir_stride = ctx->in.stride >> 2; + src_vir_info.data.vir_width = ctx->in.stride >> 2; + + src_act_info.data.act_height = src_h - 1; + src_act_info.data.act_width = src_w - 1; + + dst_vir_info.data.vir_stride = ctx->out.stride >> 2; + dst_act_info.data.act_height = dst_h - 1; + dst_act_info.data.act_width = dst_w - 1; + + /* + * Cacluate the source framebuffer base address with offset pixel. + */ + src_offsets = rga_get_addr_offset(&ctx->in, src_x, src_y, + src_w, src_h); + + /* + * Configure the dest framebuffer base address with pixel offset. + */ + offsets = rga_get_addr_offset(&ctx->out, dst_x, dst_y, dst_w, dst_h); + dst_offset = rga_lookup_draw_pos(&offsets, src_info.data.rot_mode, + src_info.data.mir_mode); + + dest[(RGA_SRC_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = + src_offsets.left_top.y_off; + dest[(RGA_SRC_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = + src_offsets.left_top.u_off; + dest[(RGA_SRC_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = + src_offsets.left_top.v_off; + + dest[(RGA_SRC_X_FACTOR - RGA_MODE_BASE_REG) >> 2] = x_factor.val; + dest[(RGA_SRC_Y_FACTOR - RGA_MODE_BASE_REG) >> 2] = y_factor.val; + dest[(RGA_SRC_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = src_vir_info.val; + dest[(RGA_SRC_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = src_act_info.val; + + dest[(RGA_SRC_INFO - RGA_MODE_BASE_REG) >> 2] = src_info.val; + + dest[(RGA_DST_Y_RGB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = + dst_offset->y_off; + dest[(RGA_DST_CB_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = + dst_offset->u_off; + dest[(RGA_DST_CR_BASE_ADDR - RGA_MODE_BASE_REG) >> 2] = + dst_offset->v_off; + + dest[(RGA_DST_VIR_INFO - RGA_MODE_BASE_REG) >> 2] = dst_vir_info.val; + dest[(RGA_DST_ACT_INFO - RGA_MODE_BASE_REG) >> 2] = dst_act_info.val; + + dest[(RGA_DST_INFO - RGA_MODE_BASE_REG) >> 2] = dst_info.val; +} + +static void rga_cmd_set_mode(struct rga_ctx *ctx) +{ + struct rockchip_rga *rga = ctx->rga; + u32 *dest = rga->cmdbuf_virt; + union rga_mode_ctrl mode; + union rga_alpha_ctrl0 alpha_ctrl0; + union rga_alpha_ctrl1 alpha_ctrl1; + + mode.val = 0; + alpha_ctrl0.val = 0; + alpha_ctrl1.val = 0; + + mode.data.gradient_sat = 1; + mode.data.render = RGA_MODE_RENDER_BITBLT; + mode.data.bitblt = RGA_MODE_BITBLT_MODE_SRC_TO_DST; + + /* disable alpha blending */ + dest[(RGA_ALPHA_CTRL0 - RGA_MODE_BASE_REG) >> 2] = alpha_ctrl0.val; + dest[(RGA_ALPHA_CTRL1 - RGA_MODE_BASE_REG) >> 2] = alpha_ctrl1.val; + + dest[(RGA_MODE_CTRL - RGA_MODE_BASE_REG) >> 2] = mode.val; +} + +void rga_cmd_set(struct rga_ctx *ctx) +{ + struct rockchip_rga *rga = ctx->rga; + + memset(rga->cmdbuf_virt, 0, RGA_CMDBUF_SIZE * 4); + + rga_cmd_set_src_addr(ctx, rga->src_mmu_pages); + /* + * Due to hardware bug, + * src1 mmu also should be configured when using alpha blending. + */ + rga_cmd_set_src1_addr(ctx, rga->dst_mmu_pages); + + rga_cmd_set_dst_addr(ctx, rga->dst_mmu_pages); + rga_cmd_set_mode(ctx); + + rga_cmd_set_trans_info(ctx); + + rga_write(rga, RGA_CMD_BASE, rga->cmdbuf_phy); + + /* sync CMD buf for RGA */ + dma_sync_single_for_device(rga->dev, rga->cmdbuf_phy, + PAGE_SIZE, DMA_BIDIRECTIONAL); +} + +void rga_hw_start(struct rockchip_rga *rga) +{ + struct rga_ctx *ctx = rga->curr; + + rga_cmd_set(ctx); + + rga_write(rga, RGA_SYS_CTRL, 0x00); + + rga_write(rga, RGA_SYS_CTRL, 0x22); + + rga_write(rga, RGA_INT, 0x600); + + rga_write(rga, RGA_CMD_CTRL, 0x1); +} diff --git a/drivers/media/platform/rockchip/rga/rga-hw.h b/drivers/media/platform/rockchip/rga/rga-hw.h new file mode 100644 index 000000000000..ca3c204abe42 --- /dev/null +++ b/drivers/media/platform/rockchip/rga/rga-hw.h @@ -0,0 +1,437 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Jacob Chen + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __RGA_HW_H__ +#define __RGA_HW_H__ + +#define RGA_CMDBUF_SIZE 0x20 + +/* Hardware limits */ +#define MAX_WIDTH 8192 +#define MAX_HEIGHT 8192 + +#define MIN_WIDTH 34 +#define MIN_HEIGHT 34 + +#define DEFAULT_WIDTH 100 +#define DEFAULT_HEIGHT 100 + +#define RGA_TIMEOUT 500 + +/* Registers address */ +#define RGA_SYS_CTRL 0x0000 +#define RGA_CMD_CTRL 0x0004 +#define RGA_CMD_BASE 0x0008 +#define RGA_INT 0x0010 +#define RGA_MMU_CTRL0 0x0014 +#define RGA_VERSION_INFO 0x0028 + +#define RGA_MODE_BASE_REG 0x0100 +#define RGA_MODE_MAX_REG 0x017C + +#define RGA_MODE_CTRL 0x0100 +#define RGA_SRC_INFO 0x0104 +#define RGA_SRC_Y_RGB_BASE_ADDR 0x0108 +#define RGA_SRC_CB_BASE_ADDR 0x010c +#define RGA_SRC_CR_BASE_ADDR 0x0110 +#define RGA_SRC1_RGB_BASE_ADDR 0x0114 +#define RGA_SRC_VIR_INFO 0x0118 +#define RGA_SRC_ACT_INFO 0x011c +#define RGA_SRC_X_FACTOR 0x0120 +#define RGA_SRC_Y_FACTOR 0x0124 +#define RGA_SRC_BG_COLOR 0x0128 +#define RGA_SRC_FG_COLOR 0x012c +#define RGA_SRC_TR_COLOR0 0x0130 +#define RGA_SRC_TR_COLOR1 0x0134 + +#define RGA_DST_INFO 0x0138 +#define RGA_DST_Y_RGB_BASE_ADDR 0x013c +#define RGA_DST_CB_BASE_ADDR 0x0140 +#define RGA_DST_CR_BASE_ADDR 0x0144 +#define RGA_DST_VIR_INFO 0x0148 +#define RGA_DST_ACT_INFO 0x014c + +#define RGA_ALPHA_CTRL0 0x0150 +#define RGA_ALPHA_CTRL1 0x0154 +#define RGA_FADING_CTRL 0x0158 +#define RGA_PAT_CON 0x015c +#define RGA_ROP_CON0 0x0160 +#define RGA_ROP_CON1 0x0164 +#define RGA_MASK_BASE 0x0168 + +#define RGA_MMU_CTRL1 0x016C +#define RGA_MMU_SRC_BASE 0x0170 +#define RGA_MMU_SRC1_BASE 0x0174 +#define RGA_MMU_DST_BASE 0x0178 + +/* Registers value */ +#define RGA_MODE_RENDER_BITBLT 0 +#define RGA_MODE_RENDER_COLOR_PALETTE 1 +#define RGA_MODE_RENDER_RECTANGLE_FILL 2 +#define RGA_MODE_RENDER_UPDATE_PALETTE_LUT_RAM 3 + +#define RGA_MODE_BITBLT_MODE_SRC_TO_DST 0 +#define RGA_MODE_BITBLT_MODE_SRC_SRC1_TO_DST 1 + +#define RGA_MODE_CF_ROP4_SOLID 0 +#define RGA_MODE_CF_ROP4_PATTERN 1 + +#define RGA_COLOR_FMT_ABGR8888 0 +#define RGA_COLOR_FMT_XBGR8888 1 +#define RGA_COLOR_FMT_RGB888 2 +#define RGA_COLOR_FMT_BGR565 4 +#define RGA_COLOR_FMT_ABGR1555 5 +#define RGA_COLOR_FMT_ABGR4444 6 +#define RGA_COLOR_FMT_YUV422SP 8 +#define RGA_COLOR_FMT_YUV422P 9 +#define RGA_COLOR_FMT_YUV420SP 10 +#define RGA_COLOR_FMT_YUV420P 11 +/* SRC_COLOR Palette */ +#define RGA_COLOR_FMT_CP_1BPP 12 +#define RGA_COLOR_FMT_CP_2BPP 13 +#define RGA_COLOR_FMT_CP_4BPP 14 +#define RGA_COLOR_FMT_CP_8BPP 15 +#define RGA_COLOR_FMT_MASK 15 + +#define RGA_COLOR_NONE_SWAP 0 +#define RGA_COLOR_RB_SWAP 1 +#define RGA_COLOR_ALPHA_SWAP 2 +#define RGA_COLOR_UV_SWAP 4 + +#define RGA_SRC_CSC_MODE_BYPASS 0 +#define RGA_SRC_CSC_MODE_BT601_R0 1 +#define RGA_SRC_CSC_MODE_BT601_R1 2 +#define RGA_SRC_CSC_MODE_BT709_R0 3 +#define RGA_SRC_CSC_MODE_BT709_R1 4 + +#define RGA_SRC_ROT_MODE_0_DEGREE 0 +#define RGA_SRC_ROT_MODE_90_DEGREE 1 +#define RGA_SRC_ROT_MODE_180_DEGREE 2 +#define RGA_SRC_ROT_MODE_270_DEGREE 3 + +#define RGA_SRC_MIRR_MODE_NO 0 +#define RGA_SRC_MIRR_MODE_X 1 +#define RGA_SRC_MIRR_MODE_Y 2 +#define RGA_SRC_MIRR_MODE_X_Y 3 + +#define RGA_SRC_HSCL_MODE_NO 0 +#define RGA_SRC_HSCL_MODE_DOWN 1 +#define RGA_SRC_HSCL_MODE_UP 2 + +#define RGA_SRC_VSCL_MODE_NO 0 +#define RGA_SRC_VSCL_MODE_DOWN 1 +#define RGA_SRC_VSCL_MODE_UP 2 + +#define RGA_SRC_TRANS_ENABLE_R 1 +#define RGA_SRC_TRANS_ENABLE_G 2 +#define RGA_SRC_TRANS_ENABLE_B 4 +#define RGA_SRC_TRANS_ENABLE_A 8 + +#define RGA_SRC_BIC_COE_SELEC_CATROM 0 +#define RGA_SRC_BIC_COE_SELEC_MITCHELL 1 +#define RGA_SRC_BIC_COE_SELEC_HERMITE 2 +#define RGA_SRC_BIC_COE_SELEC_BSPLINE 3 + +#define RGA_DST_DITHER_MODE_888_TO_666 0 +#define RGA_DST_DITHER_MODE_888_TO_565 1 +#define RGA_DST_DITHER_MODE_888_TO_555 2 +#define RGA_DST_DITHER_MODE_888_TO_444 3 + +#define RGA_DST_CSC_MODE_BYPASS 0 +#define RGA_DST_CSC_MODE_BT601_R0 1 +#define RGA_DST_CSC_MODE_BT601_R1 2 +#define RGA_DST_CSC_MODE_BT709_R0 3 + +#define RGA_ALPHA_ROP_MODE_2 0 +#define RGA_ALPHA_ROP_MODE_3 1 +#define RGA_ALPHA_ROP_MODE_4 2 + +#define RGA_ALPHA_SELECT_ALPHA 0 +#define RGA_ALPHA_SELECT_ROP 1 + +#define RGA_ALPHA_MASK_BIG_ENDIAN 0 +#define RGA_ALPHA_MASK_LITTLE_ENDIAN 1 + +#define RGA_ALPHA_NORMAL 0 +#define RGA_ALPHA_REVERSE 1 + +#define RGA_ALPHA_BLEND_GLOBAL 0 +#define RGA_ALPHA_BLEND_NORMAL 1 +#define RGA_ALPHA_BLEND_MULTIPLY 2 + +#define RGA_ALPHA_CAL_CUT 0 +#define RGA_ALPHA_CAL_NORMAL 1 + +#define RGA_ALPHA_FACTOR_ZERO 0 +#define RGA_ALPHA_FACTOR_ONE 1 +#define RGA_ALPHA_FACTOR_OTHER 2 +#define RGA_ALPHA_FACTOR_OTHER_REVERSE 3 +#define RGA_ALPHA_FACTOR_SELF 4 + +#define RGA_ALPHA_COLOR_NORMAL 0 +#define RGA_ALPHA_COLOR_MULTIPLY_CAL 1 + +/* Registers union */ +union rga_mode_ctrl { + unsigned int val; + struct { + /* [0:2] */ + unsigned int render:3; + /* [3:6] */ + unsigned int bitblt:1; + unsigned int cf_rop4_pat:1; + unsigned int alpha_zero_key:1; + unsigned int gradient_sat:1; + /* [7:31] */ + unsigned int reserved:25; + } data; +}; + +union rga_src_info { + unsigned int val; + struct { + /* [0:3] */ + unsigned int format:4; + /* [4:7] */ + unsigned int swap:3; + unsigned int cp_endian:1; + /* [8:17] */ + unsigned int csc_mode:2; + unsigned int rot_mode:2; + unsigned int mir_mode:2; + unsigned int hscl_mode:2; + unsigned int vscl_mode:2; + /* [18:22] */ + unsigned int trans_mode:1; + unsigned int trans_enable:4; + /* [23:25] */ + unsigned int dither_up_en:1; + unsigned int bic_coe_sel:2; + /* [26:31] */ + unsigned int reserved:6; + } data; +}; + +union rga_src_vir_info { + unsigned int val; + struct { + /* [0:15] */ + unsigned int vir_width:15; + unsigned int reserved:1; + /* [16:25] */ + unsigned int vir_stride:10; + /* [26:31] */ + unsigned int reserved1:6; + } data; +}; + +union rga_src_act_info { + unsigned int val; + struct { + /* [0:15] */ + unsigned int act_width:13; + unsigned int reserved:3; + /* [16:31] */ + unsigned int act_height:13; + unsigned int reserved1:3; + } data; +}; + +union rga_src_x_factor { + unsigned int val; + struct { + /* [0:15] */ + unsigned int down_scale_factor:16; + /* [16:31] */ + unsigned int up_scale_factor:16; + } data; +}; + +union rga_src_y_factor { + unsigned int val; + struct { + /* [0:15] */ + unsigned int down_scale_factor:16; + /* [16:31] */ + unsigned int up_scale_factor:16; + } data; +}; + +/* Alpha / Red / Green / Blue */ +union rga_src_cp_gr_color { + unsigned int val; + struct { + /* [0:15] */ + unsigned int gradient_x:16; + /* [16:31] */ + unsigned int gradient_y:16; + } data; +}; + +union rga_src_transparency_color0 { + unsigned int val; + struct { + /* [0:7] */ + unsigned int trans_rmin:8; + /* [8:15] */ + unsigned int trans_gmin:8; + /* [16:23] */ + unsigned int trans_bmin:8; + /* [24:31] */ + unsigned int trans_amin:8; + } data; +}; + +union rga_src_transparency_color1 { + unsigned int val; + struct { + /* [0:7] */ + unsigned int trans_rmax:8; + /* [8:15] */ + unsigned int trans_gmax:8; + /* [16:23] */ + unsigned int trans_bmax:8; + /* [24:31] */ + unsigned int trans_amax:8; + } data; +}; + +union rga_dst_info { + unsigned int val; + struct { + /* [0:3] */ + unsigned int format:4; + /* [4:6] */ + unsigned int swap:3; + /* [7:9] */ + unsigned int src1_format:3; + /* [10:11] */ + unsigned int src1_swap:2; + /* [12:15] */ + unsigned int dither_up_en:1; + unsigned int dither_down_en:1; + unsigned int dither_down_mode:2; + /* [16:18] */ + unsigned int csc_mode:2; + unsigned int csc_clip:1; + /* [19:31] */ + unsigned int reserved:13; + } data; +}; + +union rga_dst_vir_info { + unsigned int val; + struct { + /* [0:15] */ + unsigned int vir_stride:15; + unsigned int reserved:1; + /* [16:31] */ + unsigned int src1_vir_stride:15; + unsigned int reserved1:1; + } data; +}; + +union rga_dst_act_info { + unsigned int val; + struct { + /* [0:15] */ + unsigned int act_width:12; + unsigned int reserved:4; + /* [16:31] */ + unsigned int act_height:12; + unsigned int reserved1:4; + } data; +}; + +union rga_alpha_ctrl0 { + unsigned int val; + struct { + /* [0:3] */ + unsigned int rop_en:1; + unsigned int rop_select:1; + unsigned int rop_mode:2; + /* [4:11] */ + unsigned int src_fading_val:8; + /* [12:20] */ + unsigned int dst_fading_val:8; + unsigned int mask_endian:1; + /* [21:31] */ + unsigned int reserved:11; + } data; +}; + +union rga_alpha_ctrl1 { + unsigned int val; + struct { + /* [0:1] */ + unsigned int dst_color_m0:1; + unsigned int src_color_m0:1; + /* [2:7] */ + unsigned int dst_factor_m0:3; + unsigned int src_factor_m0:3; + /* [8:9] */ + unsigned int dst_alpha_cal_m0:1; + unsigned int src_alpha_cal_m0:1; + /* [10:13] */ + unsigned int dst_blend_m0:2; + unsigned int src_blend_m0:2; + /* [14:15] */ + unsigned int dst_alpha_m0:1; + unsigned int src_alpha_m0:1; + /* [16:21] */ + unsigned int dst_factor_m1:3; + unsigned int src_factor_m1:3; + /* [22:23] */ + unsigned int dst_alpha_cal_m1:1; + unsigned int src_alpha_cal_m1:1; + /* [24:27] */ + unsigned int dst_blend_m1:2; + unsigned int src_blend_m1:2; + /* [28:29] */ + unsigned int dst_alpha_m1:1; + unsigned int src_alpha_m1:1; + /* [30:31] */ + unsigned int reserved:2; + } data; +}; + +union rga_fading_ctrl { + unsigned int val; + struct { + /* [0:7] */ + unsigned int fading_offset_r:8; + /* [8:15] */ + unsigned int fading_offset_g:8; + /* [16:23] */ + unsigned int fading_offset_b:8; + /* [24:31] */ + unsigned int fading_en:1; + unsigned int reserved:7; + } data; +}; + +union rga_pat_con { + unsigned int val; + struct { + /* [0:7] */ + unsigned int width:8; + /* [8:15] */ + unsigned int height:8; + /* [16:23] */ + unsigned int offset_x:8; + /* [24:31] */ + unsigned int offset_y:8; + } data; +}; + +#endif diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c new file mode 100644 index 000000000000..2cf3bb29a2b3 --- /dev/null +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -0,0 +1,1012 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Jacob Chen + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "rga-hw.h" +#include "rga.h" + +static int debug; +module_param(debug, int, 0644); + +static void job_abort(void *prv) +{ + struct rga_ctx *ctx = prv; + struct rockchip_rga *rga = ctx->rga; + + if (!rga->curr) /* No job currently running */ + return; + + wait_event_timeout(rga->irq_queue, + !rga->curr, msecs_to_jiffies(RGA_TIMEOUT)); +} + +static void device_run(void *prv) +{ + struct rga_ctx *ctx = prv; + struct rockchip_rga *rga = ctx->rga; + struct vb2_buffer *src, *dst; + unsigned long flags; + + spin_lock_irqsave(&rga->ctrl_lock, flags); + + rga->curr = ctx; + + src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + rga_buf_map(src); + rga_buf_map(dst); + + rga_hw_start(rga); + + spin_unlock_irqrestore(&rga->ctrl_lock, flags); +} + +static irqreturn_t rga_isr(int irq, void *prv) +{ + struct rockchip_rga *rga = prv; + int intr; + + intr = rga_read(rga, RGA_INT) & 0xf; + + rga_mod(rga, RGA_INT, intr << 4, 0xf << 4); + + if (intr & 0x04) { + struct vb2_v4l2_buffer *src, *dst; + struct rga_ctx *ctx = rga->curr; + + WARN_ON(!ctx); + + rga->curr = NULL; + + src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + + WARN_ON(!src); + WARN_ON(!dst); + + dst->timecode = src->timecode; + dst->vb2_buf.timestamp = src->vb2_buf.timestamp; + dst->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + dst->flags |= src->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + + v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE); + v4l2_m2m_job_finish(rga->m2m_dev, ctx->fh.m2m_ctx); + + wake_up(&rga->irq_queue); + } + + return IRQ_HANDLED; +} + +static struct v4l2_m2m_ops rga_m2m_ops = { + .device_run = device_run, + .job_abort = job_abort, +}; + +static int +queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) +{ + struct rga_ctx *ctx = priv; + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->ops = &rga_qops; + src_vq->mem_ops = &vb2_dma_sg_memops; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &ctx->rga->mutex; + src_vq->dev = ctx->rga->v4l2_dev.dev; + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->ops = &rga_qops; + dst_vq->mem_ops = &vb2_dma_sg_memops; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &ctx->rga->mutex; + dst_vq->dev = ctx->rga->v4l2_dev.dev; + + return vb2_queue_init(dst_vq); +} + +static int rga_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct rga_ctx *ctx = container_of(ctrl->handler, struct rga_ctx, + ctrl_handler); + unsigned long flags; + + spin_lock_irqsave(&ctx->rga->ctrl_lock, flags); + switch (ctrl->id) { + case V4L2_CID_HFLIP: + ctx->hflip = ctrl->val; + break; + case V4L2_CID_VFLIP: + ctx->vflip = ctrl->val; + break; + case V4L2_CID_ROTATE: + ctx->rotate = ctrl->val; + break; + case V4L2_CID_BG_COLOR: + ctx->fill_color = ctrl->val; + break; + } + spin_unlock_irqrestore(&ctx->rga->ctrl_lock, flags); + return 0; +} + +static const struct v4l2_ctrl_ops rga_ctrl_ops = { + .s_ctrl = rga_s_ctrl, +}; + +static int rga_setup_ctrls(struct rga_ctx *ctx) +{ + struct rockchip_rga *rga = ctx->rga; + + v4l2_ctrl_handler_init(&ctx->ctrl_handler, 4); + + v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + + v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops, + V4L2_CID_ROTATE, 0, 270, 90, 0); + + v4l2_ctrl_new_std(&ctx->ctrl_handler, &rga_ctrl_ops, + V4L2_CID_BG_COLOR, 0, 0xffffffff, 1, 0); + + if (ctx->ctrl_handler.error) { + int err = ctx->ctrl_handler.error; + + v4l2_err(&rga->v4l2_dev, "%s failed\n", __func__); + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + return err; + } + + return 0; +} + +struct rga_fmt formats[] = { + { + .fourcc = V4L2_PIX_FMT_ARGB32, + .color_swap = RGA_COLOR_RB_SWAP, + .hw_format = RGA_COLOR_FMT_ABGR8888, + .depth = 32, + .uv_factor = 1, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_XRGB32, + .color_swap = RGA_COLOR_RB_SWAP, + .hw_format = RGA_COLOR_FMT_XBGR8888, + .depth = 32, + .uv_factor = 1, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_ABGR32, + .color_swap = RGA_COLOR_ALPHA_SWAP, + .hw_format = RGA_COLOR_FMT_ABGR8888, + .depth = 32, + .uv_factor = 1, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_XBGR32, + .color_swap = RGA_COLOR_ALPHA_SWAP, + .hw_format = RGA_COLOR_FMT_XBGR8888, + .depth = 32, + .uv_factor = 1, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_RGB24, + .color_swap = RGA_COLOR_NONE_SWAP, + .hw_format = RGA_COLOR_FMT_RGB888, + .depth = 24, + .uv_factor = 1, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_BGR24, + .color_swap = RGA_COLOR_RB_SWAP, + .hw_format = RGA_COLOR_FMT_RGB888, + .depth = 24, + .uv_factor = 1, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB444, + .color_swap = RGA_COLOR_RB_SWAP, + .hw_format = RGA_COLOR_FMT_ABGR4444, + .depth = 16, + .uv_factor = 1, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB555, + .color_swap = RGA_COLOR_RB_SWAP, + .hw_format = RGA_COLOR_FMT_ABGR1555, + .depth = 16, + .uv_factor = 1, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_RGB565, + .color_swap = RGA_COLOR_RB_SWAP, + .hw_format = RGA_COLOR_FMT_BGR565, + .depth = 16, + .uv_factor = 1, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_NV21, + .color_swap = RGA_COLOR_UV_SWAP, + .hw_format = RGA_COLOR_FMT_YUV420SP, + .depth = 12, + .uv_factor = 4, + .y_div = 2, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_NV61, + .color_swap = RGA_COLOR_UV_SWAP, + .hw_format = RGA_COLOR_FMT_YUV422SP, + .depth = 16, + .uv_factor = 2, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_NV12, + .color_swap = RGA_COLOR_NONE_SWAP, + .hw_format = RGA_COLOR_FMT_YUV420SP, + .depth = 12, + .uv_factor = 4, + .y_div = 2, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_NV16, + .color_swap = RGA_COLOR_NONE_SWAP, + .hw_format = RGA_COLOR_FMT_YUV422SP, + .depth = 16, + .uv_factor = 2, + .y_div = 1, + .x_div = 1, + }, + { + .fourcc = V4L2_PIX_FMT_YUV420, + .color_swap = RGA_COLOR_NONE_SWAP, + .hw_format = RGA_COLOR_FMT_YUV420P, + .depth = 12, + .uv_factor = 4, + .y_div = 2, + .x_div = 2, + }, + { + .fourcc = V4L2_PIX_FMT_YUV422P, + .color_swap = RGA_COLOR_NONE_SWAP, + .hw_format = RGA_COLOR_FMT_YUV422P, + .depth = 16, + .uv_factor = 2, + .y_div = 1, + .x_div = 2, + }, + { + .fourcc = V4L2_PIX_FMT_YVU420, + .color_swap = RGA_COLOR_UV_SWAP, + .hw_format = RGA_COLOR_FMT_YUV420P, + .depth = 12, + .uv_factor = 4, + .y_div = 2, + .x_div = 2, + }, +}; + +#define NUM_FORMATS ARRAY_SIZE(formats) + +struct rga_fmt *rga_fmt_find(struct v4l2_format *f) +{ + unsigned int i; + + for (i = 0; i < NUM_FORMATS; i++) { + if (formats[i].fourcc == f->fmt.pix.pixelformat) + return &formats[i]; + } + return NULL; +} + +static struct rga_frame def_frame = { + .width = DEFAULT_WIDTH, + .height = DEFAULT_HEIGHT, + .colorspace = V4L2_COLORSPACE_DEFAULT, + .crop.left = 0, + .crop.top = 0, + .crop.width = DEFAULT_WIDTH, + .crop.height = DEFAULT_HEIGHT, + .fmt = &formats[0], +}; + +struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return &ctx->in; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return &ctx->out; + default: + return ERR_PTR(-EINVAL); + } +} + +static int rga_open(struct file *file) +{ + struct rockchip_rga *rga = video_drvdata(file); + struct rga_ctx *ctx = NULL; + int ret = 0; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + ctx->rga = rga; + /* Set default formats */ + ctx->in = def_frame; + ctx->out = def_frame; + + if (mutex_lock_interruptible(&rga->mutex)) { + kfree(ctx); + return -ERESTARTSYS; + } + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(rga->m2m_dev, ctx, &queue_init); + if (IS_ERR(ctx->fh.m2m_ctx)) { + ret = PTR_ERR(ctx->fh.m2m_ctx); + mutex_unlock(&rga->mutex); + kfree(ctx); + return ret; + } + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + + rga_setup_ctrls(ctx); + + /* Write the default values to the ctx struct */ + v4l2_ctrl_handler_setup(&ctx->ctrl_handler); + + ctx->fh.ctrl_handler = &ctx->ctrl_handler; + mutex_unlock(&rga->mutex); + + return 0; +} + +static int rga_release(struct file *file) +{ + struct rga_ctx *ctx = + container_of(file->private_data, struct rga_ctx, fh); + struct rockchip_rga *rga = ctx->rga; + + mutex_lock(&rga->mutex); + + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); + + mutex_unlock(&rga->mutex); + + return 0; +} + +static const struct v4l2_file_operations rga_fops = { + .owner = THIS_MODULE, + .open = rga_open, + .release = rga_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static int +vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) +{ + strlcpy(cap->driver, RGA_NAME, sizeof(cap->driver)); + strlcpy(cap->card, "rockchip-rga", sizeof(cap->card)); + strlcpy(cap->bus_info, "platform:rga", sizeof(cap->bus_info)); + + return 0; +} + +static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) +{ + struct rga_fmt *fmt; + + if (f->index >= NUM_FORMATS) + return -EINVAL; + + fmt = &formats[f->index]; + f->pixelformat = fmt->fourcc; + + return 0; +} + +static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f) +{ + struct rga_ctx *ctx = prv; + struct vb2_queue *vq; + struct rga_frame *frm; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (!vq) + return -EINVAL; + frm = rga_get_frame(ctx, f->type); + if (IS_ERR(frm)) + return PTR_ERR(frm); + + f->fmt.pix.width = frm->width; + f->fmt.pix.height = frm->height; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.pixelformat = frm->fmt->fourcc; + f->fmt.pix.bytesperline = frm->stride; + f->fmt.pix.sizeimage = frm->size; + f->fmt.pix.colorspace = frm->colorspace; + + return 0; +} + +static int vidioc_try_fmt(struct file *file, void *prv, struct v4l2_format *f) +{ + struct rga_fmt *fmt; + + fmt = rga_fmt_find(f); + if (!fmt) { + fmt = &formats[0]; + f->fmt.pix.pixelformat = fmt->fourcc; + } + + f->fmt.pix.field = V4L2_FIELD_NONE; + + if (f->fmt.pix.width > MAX_WIDTH) + f->fmt.pix.width = MAX_WIDTH; + if (f->fmt.pix.height > MAX_HEIGHT) + f->fmt.pix.height = MAX_HEIGHT; + + if (f->fmt.pix.width < MIN_WIDTH) + f->fmt.pix.width = MIN_WIDTH; + if (f->fmt.pix.height < MIN_HEIGHT) + f->fmt.pix.height = MIN_HEIGHT; + + if (fmt->hw_format >= RGA_COLOR_FMT_YUV422SP) + f->fmt.pix.bytesperline = f->fmt.pix.width; + else + f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; + + f->fmt.pix.sizeimage = + f->fmt.pix.height * (f->fmt.pix.width * fmt->depth) >> 3; + + return 0; +} + +static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f) +{ + struct rga_ctx *ctx = prv; + struct rockchip_rga *rga = ctx->rga; + struct vb2_queue *vq; + struct rga_frame *frm; + struct rga_fmt *fmt; + int ret = 0; + + /* Adjust all values accordingly to the hardware capabilities + * and chosen format. + */ + ret = vidioc_try_fmt(file, prv, f); + if (ret) + return ret; + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (vb2_is_busy(vq)) { + v4l2_err(&rga->v4l2_dev, "queue (%d) bust\n", f->type); + return -EBUSY; + } + frm = rga_get_frame(ctx, f->type); + if (IS_ERR(frm)) + return PTR_ERR(frm); + fmt = rga_fmt_find(f); + if (!fmt) + return -EINVAL; + frm->width = f->fmt.pix.width; + frm->height = f->fmt.pix.height; + frm->size = f->fmt.pix.sizeimage; + frm->fmt = fmt; + frm->stride = f->fmt.pix.bytesperline; + frm->colorspace = f->fmt.pix.colorspace; + + /* Reset crop settings */ + frm->crop.left = 0; + frm->crop.top = 0; + frm->crop.width = frm->width; + frm->crop.height = frm->height; + + return 0; +} + +static int vidioc_g_selection(struct file *file, void *prv, + struct v4l2_selection *s) +{ + struct rga_ctx *ctx = prv; + struct rga_frame *f; + bool use_frame = false; + + f = rga_get_frame(ctx, s->type); + if (IS_ERR(f)) + return PTR_ERR(f); + + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + break; + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + break; + case V4L2_SEL_TGT_COMPOSE: + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + use_frame = true; + break; + case V4L2_SEL_TGT_CROP: + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + use_frame = true; + break; + default: + return -EINVAL; + } + + if (use_frame) { + s->r = f->crop; + } else { + s->r.left = 0; + s->r.top = 0; + s->r.width = f->width; + s->r.height = f->height; + } + + return 0; +} + +static int vidioc_s_selection(struct file *file, void *prv, + struct v4l2_selection *s) +{ + struct rga_ctx *ctx = prv; + struct rockchip_rga *rga = ctx->rga; + struct rga_frame *f; + int ret = 0; + + f = rga_get_frame(ctx, s->type); + if (IS_ERR(f)) + return PTR_ERR(f); + + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE: + /* + * COMPOSE target is only valid for capture buffer type, return + * error for output buffer type + */ + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + break; + case V4L2_SEL_TGT_CROP: + /* + * CROP target is only valid for output buffer type, return + * error for capture buffer type + */ + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + break; + /* + * bound and default crop/compose targets are invalid targets to + * try/set + */ + default: + return -EINVAL; + } + + if (s->r.top < 0 || s->r.left < 0) { + v4l2_dbg(debug, 1, &rga->v4l2_dev, + "doesn't support negative values for top & left.\n"); + return -EINVAL; + } + + if (s->r.left + s->r.width > f->width || + s->r.top + s->r.height > f->height || + s->r.width < MIN_WIDTH || s->r.height < MIN_HEIGHT) { + v4l2_dbg(debug, 1, &rga->v4l2_dev, "unsupported crop value.\n"); + return -EINVAL; + } + + f->crop = s->r; + + return ret; +} + +static const struct v4l2_ioctl_ops rga_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt, + + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt, + .vidioc_g_fmt_vid_out = vidioc_g_fmt, + .vidioc_try_fmt_vid_out = vidioc_try_fmt, + .vidioc_s_fmt_vid_out = vidioc_s_fmt, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_g_selection = vidioc_g_selection, + .vidioc_s_selection = vidioc_s_selection, +}; + +static struct video_device rga_videodev = { + .name = "rockchip-rga", + .fops = &rga_fops, + .ioctl_ops = &rga_ioctl_ops, + .minor = -1, + .release = video_device_release, + .vfl_dir = VFL_DIR_M2M, + .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, +}; + +static int rga_enable_clocks(struct rockchip_rga *rga) +{ + int ret; + + ret = clk_prepare_enable(rga->sclk); + if (ret) { + dev_err(rga->dev, "Cannot enable rga sclk: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(rga->aclk); + if (ret) { + dev_err(rga->dev, "Cannot enable rga aclk: %d\n", ret); + goto err_disable_sclk; + } + + ret = clk_prepare_enable(rga->hclk); + if (ret) { + dev_err(rga->dev, "Cannot enable rga hclk: %d\n", ret); + goto err_disable_aclk; + } + + return 0; + +err_disable_sclk: + clk_disable_unprepare(rga->sclk); +err_disable_aclk: + clk_disable_unprepare(rga->aclk); + + return ret; +} + +static void rga_disable_clocks(struct rockchip_rga *rga) +{ + clk_disable_unprepare(rga->sclk); + clk_disable_unprepare(rga->hclk); + clk_disable_unprepare(rga->aclk); +} + +static int rga_parse_dt(struct rockchip_rga *rga) +{ + struct reset_control *core_rst, *axi_rst, *ahb_rst; + + core_rst = devm_reset_control_get(rga->dev, "core"); + if (IS_ERR(core_rst)) { + dev_err(rga->dev, "failed to get core reset controller\n"); + return PTR_ERR(core_rst); + } + + axi_rst = devm_reset_control_get(rga->dev, "axi"); + if (IS_ERR(axi_rst)) { + dev_err(rga->dev, "failed to get axi reset controller\n"); + return PTR_ERR(axi_rst); + } + + ahb_rst = devm_reset_control_get(rga->dev, "ahb"); + if (IS_ERR(ahb_rst)) { + dev_err(rga->dev, "failed to get ahb reset controller\n"); + return PTR_ERR(ahb_rst); + } + + reset_control_assert(core_rst); + udelay(1); + reset_control_deassert(core_rst); + + reset_control_assert(axi_rst); + udelay(1); + reset_control_deassert(axi_rst); + + reset_control_assert(ahb_rst); + udelay(1); + reset_control_deassert(ahb_rst); + + rga->sclk = devm_clk_get(rga->dev, "sclk"); + if (IS_ERR(rga->sclk)) { + dev_err(rga->dev, "failed to get sclk clock\n"); + return PTR_ERR(rga->sclk); + } + + rga->aclk = devm_clk_get(rga->dev, "aclk"); + if (IS_ERR(rga->aclk)) { + dev_err(rga->dev, "failed to get aclk clock\n"); + return PTR_ERR(rga->aclk); + } + + rga->hclk = devm_clk_get(rga->dev, "hclk"); + if (IS_ERR(rga->hclk)) { + dev_err(rga->dev, "failed to get hclk clock\n"); + return PTR_ERR(rga->hclk); + } + + return 0; +} + +static int rga_probe(struct platform_device *pdev) +{ + struct rockchip_rga *rga; + struct video_device *vfd; + struct resource *res; + int ret = 0; + int irq; + + if (!pdev->dev.of_node) + return -ENODEV; + + rga = devm_kzalloc(&pdev->dev, sizeof(*rga), GFP_KERNEL); + if (!rga) + return -ENOMEM; + + rga->dev = &pdev->dev; + spin_lock_init(&rga->ctrl_lock); + mutex_init(&rga->mutex); + + init_waitqueue_head(&rga->irq_queue); + + ret = rga_parse_dt(rga); + if (ret) + dev_err(&pdev->dev, "Unable to parse OF data\n"); + + pm_runtime_enable(rga->dev); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + rga->regs = devm_ioremap_resource(rga->dev, res); + if (IS_ERR(rga->regs)) { + ret = PTR_ERR(rga->regs); + goto err_put_clk; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(rga->dev, "failed to get irq\n"); + ret = irq; + goto err_put_clk; + } + + ret = devm_request_irq(rga->dev, irq, rga_isr, 0, + dev_name(rga->dev), rga); + if (ret < 0) { + dev_err(rga->dev, "failed to request irq\n"); + goto err_put_clk; + } + + ret = v4l2_device_register(&pdev->dev, &rga->v4l2_dev); + if (ret) + goto err_put_clk; + vfd = video_device_alloc(); + if (!vfd) { + v4l2_err(&rga->v4l2_dev, "Failed to allocate video device\n"); + ret = -ENOMEM; + goto unreg_v4l2_dev; + } + *vfd = rga_videodev; + vfd->lock = &rga->mutex; + vfd->v4l2_dev = &rga->v4l2_dev; + + video_set_drvdata(vfd, rga); + snprintf(vfd->name, sizeof(vfd->name), "%s", rga_videodev.name); + rga->vfd = vfd; + + platform_set_drvdata(pdev, rga); + rga->m2m_dev = v4l2_m2m_init(&rga_m2m_ops); + if (IS_ERR(rga->m2m_dev)) { + v4l2_err(&rga->v4l2_dev, "Failed to init mem2mem device\n"); + ret = PTR_ERR(rga->m2m_dev); + goto unreg_video_dev; + } + + pm_runtime_get_sync(rga->dev); + + rga->version.major = (rga_read(rga, RGA_VERSION_INFO) >> 24) & 0xFF; + rga->version.minor = (rga_read(rga, RGA_VERSION_INFO) >> 20) & 0x0F; + + v4l2_info(&rga->v4l2_dev, "HW Version: 0x%02x.%02x\n", + rga->version.major, rga->version.minor); + + pm_runtime_put(rga->dev); + + /* Create CMD buffer */ + rga->cmdbuf_virt = dma_alloc_attrs(rga->dev, RGA_CMDBUF_SIZE, + &rga->cmdbuf_phy, GFP_KERNEL, + DMA_ATTR_WRITE_COMBINE); + + rga->src_mmu_pages = + (unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3); + rga->dst_mmu_pages = + (unsigned int *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 3); + + def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3; + def_frame.size = def_frame.stride * def_frame.height; + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); + if (ret) { + v4l2_err(&rga->v4l2_dev, "Failed to register video device\n"); + goto rel_vdev; + } + + v4l2_info(&rga->v4l2_dev, "Registered %s as /dev/%s\n", + vfd->name, video_device_node_name(vfd)); + + return 0; + +rel_vdev: + video_device_release(vfd); +unreg_video_dev: + video_unregister_device(rga->vfd); +unreg_v4l2_dev: + v4l2_device_unregister(&rga->v4l2_dev); +err_put_clk: + pm_runtime_disable(rga->dev); + + return ret; +} + +static int rga_remove(struct platform_device *pdev) +{ + struct rockchip_rga *rga = platform_get_drvdata(pdev); + + dma_free_attrs(rga->dev, RGA_CMDBUF_SIZE, &rga->cmdbuf_virt, + rga->cmdbuf_phy, DMA_ATTR_WRITE_COMBINE); + + free_pages((unsigned long)rga->src_mmu_pages, 3); + free_pages((unsigned long)rga->dst_mmu_pages, 3); + + v4l2_info(&rga->v4l2_dev, "Removing\n"); + + v4l2_m2m_release(rga->m2m_dev); + video_unregister_device(rga->vfd); + v4l2_device_unregister(&rga->v4l2_dev); + + pm_runtime_disable(rga->dev); + + return 0; +} + +#ifdef CONFIG_PM +static int rga_runtime_suspend(struct device *dev) +{ + struct rockchip_rga *rga = dev_get_drvdata(dev); + + rga_disable_clocks(rga); + + return 0; +} + +static int rga_runtime_resume(struct device *dev) +{ + struct rockchip_rga *rga = dev_get_drvdata(dev); + + return rga_enable_clocks(rga); +} +#endif + +static const struct dev_pm_ops rga_pm = { + SET_RUNTIME_PM_OPS(rga_runtime_suspend, + rga_runtime_resume, NULL) +}; + +static const struct of_device_id rockchip_rga_match[] = { + { + .compatible = "rockchip,rk3288-rga", + }, + { + .compatible = "rockchip,rk3399-rga", + }, + {}, +}; + +MODULE_DEVICE_TABLE(of, rockchip_rga_match); + +static struct platform_driver rga_pdrv = { + .probe = rga_probe, + .remove = rga_remove, + .driver = { + .name = RGA_NAME, + .pm = &rga_pm, + .of_match_table = rockchip_rga_match, + }, +}; + +module_platform_driver(rga_pdrv); + +MODULE_AUTHOR("Jacob Chen "); +MODULE_DESCRIPTION("Rockchip Raster 2d Graphic Acceleration Unit"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h new file mode 100644 index 000000000000..5d43e7ea88af --- /dev/null +++ b/drivers/media/platform/rockchip/rga/rga.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd + * Author: Jacob Chen + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __RGA_H__ +#define __RGA_H__ + +#include +#include +#include +#include + +#define RGA_NAME "rockchip-rga" + +struct rga_fmt { + u32 fourcc; + int depth; + u8 uv_factor; + u8 y_div; + u8 x_div; + u8 color_swap; + u8 hw_format; +}; + +struct rga_frame { + /* Original dimensions */ + u32 width; + u32 height; + u32 colorspace; + + /* Crop */ + struct v4l2_rect crop; + + /* Image format */ + struct rga_fmt *fmt; + + /* Variables that can calculated once and reused */ + u32 stride; + u32 size; +}; + +struct rockchip_rga_version { + u32 major; + u32 minor; +}; + +struct rga_ctx { + struct v4l2_fh fh; + struct rockchip_rga *rga; + struct rga_frame in; + struct rga_frame out; + struct v4l2_ctrl_handler ctrl_handler; + + /* Control values */ + u32 op; + u32 hflip; + u32 vflip; + u32 rotate; + u32 fill_color; +}; + +struct rockchip_rga { + struct v4l2_device v4l2_dev; + struct v4l2_m2m_dev *m2m_dev; + struct video_device *vfd; + + struct device *dev; + struct regmap *grf; + void __iomem *regs; + struct clk *sclk; + struct clk *aclk; + struct clk *hclk; + struct rockchip_rga_version version; + + /* vfd lock */ + struct mutex mutex; + /* ctrl parm lock */ + spinlock_t ctrl_lock; + + wait_queue_head_t irq_queue; + + struct rga_ctx *curr; + dma_addr_t cmdbuf_phy; + void *cmdbuf_virt; + unsigned int *src_mmu_pages; + unsigned int *dst_mmu_pages; +}; + +struct rga_frame *rga_get_frame(struct rga_ctx *ctx, enum v4l2_buf_type type); + +/* RGA Buffers Manage */ +extern const struct vb2_ops rga_qops; +void rga_buf_map(struct vb2_buffer *vb); + +/* RGA Hardware */ +static inline void rga_write(struct rockchip_rga *rga, u32 reg, u32 value) +{ + writel(value, rga->regs + reg); +}; + +static inline u32 rga_read(struct rockchip_rga *rga, u32 reg) +{ + return readl(rga->regs + reg); +}; + +static inline void rga_mod(struct rockchip_rga *rga, u32 reg, u32 val, u32 mask) +{ + u32 temp = rga_read(rga, reg) & ~(mask); + + temp |= val & mask; + rga_write(rga, reg, temp); +}; + +void rga_hw_start(struct rockchip_rga *rga); + +#endif -- cgit v1.2.3 From ec8df85f312e299e6d92f7cc3446e67e510ccafb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 16 Oct 2017 16:26:04 -0700 Subject: media: rga: make some functions static drivers/media/platform/rockchip/rga/rga-hw.c:383:6: warning: no previous prototype for 'rga_cmd_set' [-Wmissing-prototypes] void rga_cmd_set(struct rga_ctx *ctx) ^~~~~~~~~~~ drivers/media/platform/rockchip/rga/rga.c:359:17: warning: no previous prototype for 'rga_fmt_find' [-Wmissing-prototypes] struct rga_fmt *rga_fmt_find(struct v4l2_format *f) ^~~~~~~~~~~~ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rga/rga-hw.c | 2 +- drivers/media/platform/rockchip/rga/rga.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/rockchip/rga/rga-hw.c b/drivers/media/platform/rockchip/rga/rga-hw.c index 0645481c9a5e..96d1b1b3fe8e 100644 --- a/drivers/media/platform/rockchip/rga/rga-hw.c +++ b/drivers/media/platform/rockchip/rga/rga-hw.c @@ -380,7 +380,7 @@ static void rga_cmd_set_mode(struct rga_ctx *ctx) dest[(RGA_MODE_CTRL - RGA_MODE_BASE_REG) >> 2] = mode.val; } -void rga_cmd_set(struct rga_ctx *ctx) +static void rga_cmd_set(struct rga_ctx *ctx) { struct rockchip_rga *rga = ctx->rga; diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index 2cf3bb29a2b3..e7d1b34baf1c 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -356,7 +356,7 @@ struct rga_fmt formats[] = { #define NUM_FORMATS ARRAY_SIZE(formats) -struct rga_fmt *rga_fmt_find(struct v4l2_format *f) +static struct rga_fmt *rga_fmt_find(struct v4l2_format *f) { unsigned int i; -- cgit v1.2.3 From 1c860c789f23274c2f4c2fa4577765795fb85139 Mon Sep 17 00:00:00 2001 From: Jacob Chen Date: Wed, 11 Oct 2017 20:33:09 -0700 Subject: [media] MAINTAINERS: add entry for Rockchip RGA driver Add MAINTAINERS entry for the rockchip RGA driver. Signed-off-by: Jacob Chen [hans.verkuil@cisco.com: added commit message] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index a8126830829b..57d25a71864c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11518,6 +11518,13 @@ F: drivers/hid/hid-roccat* F: include/linux/hid-roccat* F: Documentation/ABI/*/sysfs-driver-hid-roccat* +ROCKCHIP RASTER 2D GRAPHIC ACCELERATION UNIT DRIVER +M: Jacob chen +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/platform/rockchip/rga/ +F: Documentation/devicetree/bindings/media/rockchip-rga.txt + ROCKER DRIVER M: Jiri Pirko L: netdev@vger.kernel.org -- cgit v1.2.3 From defc3a47c53d54e933ecb923c064c36be4cf70e6 Mon Sep 17 00:00:00 2001 From: Hoegeun Kwon Date: Wed, 13 Sep 2017 04:41:52 -0700 Subject: media: exynos-gsc: Add compatible for Exynos 5250 and 5420 SoC version Exynos 5250 and 5420 have different hardware rotation limits. Since we have to distinguish between these two, we add different compatible: samsung,exynos5250-gsc and samsung,exynos5420-gsc. Signed-off-by: Hoegeun Kwon Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/exynos5-gsc.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/media/exynos5-gsc.txt b/Documentation/devicetree/bindings/media/exynos5-gsc.txt index 26ca25b6d264..0d4fdaedc6f1 100644 --- a/Documentation/devicetree/bindings/media/exynos5-gsc.txt +++ b/Documentation/devicetree/bindings/media/exynos5-gsc.txt @@ -3,8 +3,11 @@ G-Scaler is used for scaling and color space conversion on EXYNOS5 SoCs. Required properties: -- compatible: should be "samsung,exynos5-gsc" (for Exynos 5250, 5420 and - 5422 SoCs) or "samsung,exynos5433-gsc" (Exynos 5433) +- compatible: should be one of + "samsung,exynos5250-gsc" + "samsung,exynos5420-gsc" + "samsung,exynos5433-gsc" + "samsung,exynos5-gsc" (deprecated) - reg: should contain G-Scaler physical address location and length. - interrupts: should contain G-Scaler interrupt number @@ -15,7 +18,7 @@ Optional properties: Example: gsc_0: gsc@0x13e00000 { - compatible = "samsung,exynos5-gsc"; + compatible = "samsung,exynos5250-gsc"; reg = <0x13e00000 0x1000>; interrupts = <0 85 0>; }; -- cgit v1.2.3 From a2640560a0e006d037918522f5f33d0aa800680c Mon Sep 17 00:00:00 2001 From: Hoegeun Kwon Date: Wed, 13 Sep 2017 04:41:55 -0700 Subject: media: exynos-gsc: Add hardware rotation limits The hardware rotation limits of gsc depends on SOC (Exynos 5250/5420/5433). Distinguish them and add them to the driver data. [s.nawrocki@samsung.com: corrected num_entities in 5420 variant data] Signed-off-by: Hoegeun Kwon Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 127 +++++++++++++++++++++++++-- 1 file changed, 122 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 43801509dabb..17854a379243 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -958,6 +958,51 @@ static struct gsc_pix_max gsc_v_100_max = { .target_rot_en_h = 2016, }; +static struct gsc_pix_max gsc_v_5250_max = { + .org_scaler_bypass_w = 8192, + .org_scaler_bypass_h = 8192, + .org_scaler_input_w = 4800, + .org_scaler_input_h = 3344, + .real_rot_dis_w = 4800, + .real_rot_dis_h = 3344, + .real_rot_en_w = 2016, + .real_rot_en_h = 2016, + .target_rot_dis_w = 4800, + .target_rot_dis_h = 3344, + .target_rot_en_w = 2016, + .target_rot_en_h = 2016, +}; + +static struct gsc_pix_max gsc_v_5420_max = { + .org_scaler_bypass_w = 8192, + .org_scaler_bypass_h = 8192, + .org_scaler_input_w = 4800, + .org_scaler_input_h = 3344, + .real_rot_dis_w = 4800, + .real_rot_dis_h = 3344, + .real_rot_en_w = 2048, + .real_rot_en_h = 2048, + .target_rot_dis_w = 4800, + .target_rot_dis_h = 3344, + .target_rot_en_w = 2016, + .target_rot_en_h = 2016, +}; + +static struct gsc_pix_max gsc_v_5433_max = { + .org_scaler_bypass_w = 8192, + .org_scaler_bypass_h = 8192, + .org_scaler_input_w = 4800, + .org_scaler_input_h = 3344, + .real_rot_dis_w = 4800, + .real_rot_dis_h = 3344, + .real_rot_en_w = 2047, + .real_rot_en_h = 2047, + .target_rot_dis_w = 4800, + .target_rot_dis_h = 3344, + .target_rot_en_w = 2016, + .target_rot_en_h = 2016, +}; + static struct gsc_pix_min gsc_v_100_min = { .org_w = 64, .org_h = 32, @@ -992,6 +1037,45 @@ static struct gsc_variant gsc_v_100_variant = { .local_sc_down = 2, }; +static struct gsc_variant gsc_v_5250_variant = { + .pix_max = &gsc_v_5250_max, + .pix_min = &gsc_v_100_min, + .pix_align = &gsc_v_100_align, + .in_buf_cnt = 32, + .out_buf_cnt = 32, + .sc_up_max = 8, + .sc_down_max = 16, + .poly_sc_down_max = 4, + .pre_sc_down_max = 4, + .local_sc_down = 2, +}; + +static struct gsc_variant gsc_v_5420_variant = { + .pix_max = &gsc_v_5420_max, + .pix_min = &gsc_v_100_min, + .pix_align = &gsc_v_100_align, + .in_buf_cnt = 32, + .out_buf_cnt = 32, + .sc_up_max = 8, + .sc_down_max = 16, + .poly_sc_down_max = 4, + .pre_sc_down_max = 4, + .local_sc_down = 2, +}; + +static struct gsc_variant gsc_v_5433_variant = { + .pix_max = &gsc_v_5433_max, + .pix_min = &gsc_v_100_min, + .pix_align = &gsc_v_100_align, + .in_buf_cnt = 32, + .out_buf_cnt = 32, + .sc_up_max = 8, + .sc_down_max = 16, + .poly_sc_down_max = 4, + .pre_sc_down_max = 4, + .local_sc_down = 2, +}; + static struct gsc_driverdata gsc_v_100_drvdata = { .variant = { [0] = &gsc_v_100_variant, @@ -1004,11 +1088,33 @@ static struct gsc_driverdata gsc_v_100_drvdata = { .num_clocks = 1, }; +static struct gsc_driverdata gsc_v_5250_drvdata = { + .variant = { + [0] = &gsc_v_5250_variant, + [1] = &gsc_v_5250_variant, + [2] = &gsc_v_5250_variant, + [3] = &gsc_v_5250_variant, + }, + .num_entities = 4, + .clk_names = { "gscl" }, + .num_clocks = 1, +}; + +static struct gsc_driverdata gsc_v_5420_drvdata = { + .variant = { + [0] = &gsc_v_5420_variant, + [1] = &gsc_v_5420_variant, + }, + .num_entities = 2, + .clk_names = { "gscl" }, + .num_clocks = 1, +}; + static struct gsc_driverdata gsc_5433_drvdata = { .variant = { - [0] = &gsc_v_100_variant, - [1] = &gsc_v_100_variant, - [2] = &gsc_v_100_variant, + [0] = &gsc_v_5433_variant, + [1] = &gsc_v_5433_variant, + [2] = &gsc_v_5433_variant, }, .num_entities = 3, .clk_names = { "pclk", "aclk", "aclk_xiu", "aclk_gsclbend" }, @@ -1017,13 +1123,21 @@ static struct gsc_driverdata gsc_5433_drvdata = { static const struct of_device_id exynos_gsc_match[] = { { - .compatible = "samsung,exynos5-gsc", - .data = &gsc_v_100_drvdata, + .compatible = "samsung,exynos5250-gsc", + .data = &gsc_v_5250_drvdata, + }, + { + .compatible = "samsung,exynos5420-gsc", + .data = &gsc_v_5420_drvdata, }, { .compatible = "samsung,exynos5433-gsc", .data = &gsc_5433_drvdata, }, + { + .compatible = "samsung,exynos5-gsc", + .data = &gsc_v_100_drvdata, + }, {}, }; MODULE_DEVICE_TABLE(of, exynos_gsc_match); @@ -1045,6 +1159,9 @@ static int gsc_probe(struct platform_device *pdev) if (ret < 0) return ret; + if (drv_data == &gsc_v_100_drvdata) + dev_info(dev, "compatible 'exynos5-gsc' is deprecated\n"); + gsc->id = ret; if (gsc->id >= drv_data->num_entities) { dev_err(dev, "Invalid platform device id: %d\n", gsc->id); -- cgit v1.2.3 From f6cd32328965232ab1af4fd768999e6a0e351b81 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 8 Sep 2017 13:25:17 -0700 Subject: media: s5p-mfc: Delete an error message for a failed memory allocation Omit an extra message for a memory allocation failure in s5p_mfc_probe() function. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 1afde5021ca6..8af45d53846f 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1270,10 +1270,8 @@ static int s5p_mfc_probe(struct platform_device *pdev) pr_debug("%s++\n", __func__); dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&pdev->dev, "Not enough memory for MFC device\n"); + if (!dev) return -ENOMEM; - } spin_lock_init(&dev->irqlock); spin_lock_init(&dev->condlock); -- cgit v1.2.3 From d7f15bde0f25ee8a5ea3aad96522ba851a47a0b0 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 8 Sep 2017 13:30:09 -0700 Subject: media: s5p-mfc: Improve a size determination in s5p_mfc_alloc_memdev() Replace the specification of a data structure by a pointer dereference as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer according to the Linux coding style convention. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 8af45d53846f..abfb70b07032 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1083,7 +1083,7 @@ static struct device *s5p_mfc_alloc_memdev(struct device *dev, struct device *child; int ret; - child = devm_kzalloc(dev, sizeof(struct device), GFP_KERNEL); + child = devm_kzalloc(dev, sizeof(*child), GFP_KERNEL); if (!child) return NULL; -- cgit v1.2.3 From 4449dd0a397536d12c52b599353341135d44b6d0 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 8 Sep 2017 13:37:00 -0700 Subject: media: s5p-mfc: Adjust a null pointer check in four functions The script “checkpatch.pl” pointed information out like the following. Comparison to NULL could be written... Thus fix the affected source code places. Signed-off-by: Markus Elfring Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index abfb70b07032..cf68aed59e0d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -470,7 +470,7 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev, { mfc_err("Interrupt Error: %08x\n", err); - if (ctx != NULL) { + if (ctx) { /* Error recovery is dependent on the state of context */ switch (ctx->state) { case MFCINST_RES_CHANGE_INIT: @@ -508,7 +508,7 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, { struct s5p_mfc_dev *dev; - if (ctx == NULL) + if (!ctx) return; dev = ctx->dev; if (ctx->c_ops->post_seq_start) { @@ -562,7 +562,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, struct s5p_mfc_buf *src_buf; struct s5p_mfc_dev *dev; - if (ctx == NULL) + if (!ctx) return; dev = ctx->dev; s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); @@ -1289,7 +1289,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) return PTR_ERR(dev->regs_base); res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (res == NULL) { + if (!res) { dev_err(&pdev->dev, "failed to get irq resource\n"); return -ENOENT; } -- cgit v1.2.3 From a197c7fccc0d8958ff73e323dcb1985c19d8166f Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 18 Sep 2017 01:15:53 -0700 Subject: media: dt: bindings: media: Document practices for DT bindings, ports, endpoints Port and endpoint numbering has been omitted in DT binding documentation for a large number of devices. Also common properties the device uses have been missed in binding documentation. Make it explicit that these things need to be documented. Signed-off-by: Sakari Ailus Acked-by: Rob Herring Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/video-interfaces.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt index 852041a7480c..bc8f18fb6730 100644 --- a/Documentation/devicetree/bindings/media/video-interfaces.txt +++ b/Documentation/devicetree/bindings/media/video-interfaces.txt @@ -55,6 +55,15 @@ divided into two separate ITU-R BT.656 8-bit busses. In such case bus-width and data-shift properties can be used to assign physical data lines to each endpoint node (logical bus). +Documenting bindings for devices +-------------------------------- + +All required and optional bindings the device supports shall be explicitly +documented in device DT binding documentation. This also includes port and +endpoint nodes for the device, including unit-addresses and reg properties where +relevant. + +Please also see Documentation/devicetree/bindings/graph.txt . Required properties ------------------- -- cgit v1.2.3 From 7571358dd22dc91dea560f0dde62ce23c033b6b6 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 18 Sep 2017 01:20:59 -0700 Subject: media: dt: bindings: media: Document data lane numbering without lane reordering Most devices do not support lane reordering and in many cases the documentation of the data-lanes property is incomplete for such devices. Document that in case the lane reordering isn't supported, monotonically incremented values from 0 or 1 shall be used. Signed-off-by: Sakari Ailus Acked-by: Rob Herring Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/video-interfaces.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt index bc8f18fb6730..bd6474920510 100644 --- a/Documentation/devicetree/bindings/media/video-interfaces.txt +++ b/Documentation/devicetree/bindings/media/video-interfaces.txt @@ -108,7 +108,10 @@ Optional endpoint properties determines the logical lane number, while the value of an entry indicates physical lane, e.g. for 2-lane MIPI CSI-2 bus we could have "data-lanes = <1 2>;", assuming the clock lane is on hardware lane 0. - This property is valid for serial busses only (e.g. MIPI CSI-2). + If the hardware does not support lane reordering, monotonically + incremented values shall be used from 0 or 1 onwards, depending on + whether or not there is also a clock lane. This property is valid for + serial busses only (e.g. MIPI CSI-2). - clock-lanes: an array of physical clock lane indexes. Position of an entry determines the logical lane number, while the value of an entry indicates physical lane, e.g. for a MIPI CSI-2 bus we could have "clock-lanes = <0>;", -- cgit v1.2.3 From 72eaf99f0471d7e03e46f0d87770626430995df2 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 29 Sep 2017 11:54:10 +0200 Subject: media: smiapp: Use __v4l2_ctrl_handler_setup() Use unlocked __v4l2_ctrl_handler_setup() in order to make the control setup atomic. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index fbd851be51d2..8de444080b8f 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -1325,24 +1325,28 @@ static int smiapp_power_on(struct device *dev) if (!sensor->pixel_array) return 0; - rval = v4l2_ctrl_handler_setup(&sensor->pixel_array->ctrl_handler); + mutex_lock(&sensor->mutex); + + rval = __v4l2_ctrl_handler_setup(&sensor->pixel_array->ctrl_handler); if (rval) - goto out_cci_addr_fail; + goto out_unlock; - rval = v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler); + rval = __v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler); if (rval) - goto out_cci_addr_fail; + goto out_unlock; - mutex_lock(&sensor->mutex); rval = smiapp_update_mode(sensor); - mutex_unlock(&sensor->mutex); if (rval < 0) - goto out_cci_addr_fail; + goto out_unlock; + + mutex_unlock(&sensor->mutex); return 0; -out_cci_addr_fail: +out_unlock: + mutex_unlock(&sensor->mutex); +out_cci_addr_fail: gpiod_set_value(sensor->xshutdown, 0); clk_disable_unprepare(sensor->ext_clk); -- cgit v1.2.3 From 6771fce5060e10f6c878b5d644e9d66dd7f68950 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 29 Sep 2017 12:23:56 +0200 Subject: media: smiapp: Rely on runtime PM Instead of relying on a mix of runtime PM and the s_power() callback, drop the s_power() callback altogether and use runtime PM solely. As device access is required during device power-on and power-off sequences, runtime PM alone cannot tell whether the device is available. Thus the "active" field is introduced in struct smiapp_sensor to tell whether it is safe to write to the device. Consequently there is no need to power on the device whenever a file handle is open. This functionality is removed as well. The user may still control the device power management through sysfs. Autosuspend remains enabled, with 1 s delay. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 101 ++++++++++++--------------------- drivers/media/i2c/smiapp/smiapp-regs.c | 3 + drivers/media/i2c/smiapp/smiapp.h | 1 + 3 files changed, 40 insertions(+), 65 deletions(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 8de444080b8f..faf567569799 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -1239,6 +1239,10 @@ static int smiapp_power_on(struct device *dev) sleep = SMIAPP_RESET_DELAY(sensor->hwcfg->ext_clk); usleep_range(sleep, sleep); + mutex_lock(&sensor->mutex); + + sensor->active = true; + /* * Failures to respond to the address change command have been noticed. * Those failures seem to be caused by the sensor requiring a longer @@ -1321,32 +1325,28 @@ static int smiapp_power_on(struct device *dev) goto out_cci_addr_fail; } - /* Are we still initialising...? If yes, return here. */ - if (!sensor->pixel_array) - return 0; - - mutex_lock(&sensor->mutex); - - rval = __v4l2_ctrl_handler_setup(&sensor->pixel_array->ctrl_handler); - if (rval) - goto out_unlock; + /* Are we still initialising...? If not, proceed with control setup. */ + if (sensor->pixel_array) { + rval = __v4l2_ctrl_handler_setup( + &sensor->pixel_array->ctrl_handler); + if (rval) + goto out_cci_addr_fail; - rval = __v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler); - if (rval) - goto out_unlock; + rval = __v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler); + if (rval) + goto out_cci_addr_fail; - rval = smiapp_update_mode(sensor); - if (rval < 0) - goto out_unlock; + rval = smiapp_update_mode(sensor); + if (rval < 0) + goto out_cci_addr_fail; + } mutex_unlock(&sensor->mutex); return 0; -out_unlock: - mutex_unlock(&sensor->mutex); - out_cci_addr_fail: + mutex_unlock(&sensor->mutex); gpiod_set_value(sensor->xshutdown, 0); clk_disable_unprepare(sensor->ext_clk); @@ -1364,6 +1364,8 @@ static int smiapp_power_off(struct device *dev) struct smiapp_sensor *sensor = container_of(ssd, struct smiapp_sensor, ssds[0]); + mutex_lock(&sensor->mutex); + /* * Currently power/clock to lens are enable/disabled separately * but they are essentially the same signals. So if the sensor is @@ -1376,6 +1378,10 @@ static int smiapp_power_off(struct device *dev) SMIAPP_REG_U8_SOFTWARE_RESET, SMIAPP_SOFTWARE_RESET); + sensor->active = false; + + mutex_unlock(&sensor->mutex); + gpiod_set_value(sensor->xshutdown, 0); clk_disable_unprepare(sensor->ext_clk); usleep_range(5000, 5000); @@ -1385,29 +1391,6 @@ static int smiapp_power_off(struct device *dev) return 0; } -static int smiapp_set_power(struct v4l2_subdev *subdev, int on) -{ - int rval; - - if (!on) { - pm_runtime_mark_last_busy(subdev->dev); - pm_runtime_put_autosuspend(subdev->dev); - - return 0; - } - - rval = pm_runtime_get_sync(subdev->dev); - if (rval >= 0) - return 0; - - if (rval != -EBUSY && rval != -EAGAIN) - pm_runtime_set_active(subdev->dev); - - pm_runtime_put(subdev->dev); - - return rval; -} - /* ----------------------------------------------------------------------------- * Video stream management */ @@ -1564,19 +1547,31 @@ out: static int smiapp_set_stream(struct v4l2_subdev *subdev, int enable) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); int rval; if (sensor->streaming == enable) return 0; if (enable) { + rval = pm_runtime_get_sync(&client->dev); + if (rval < 0) { + if (rval != -EBUSY && rval != -EAGAIN) + pm_runtime_set_active(&client->dev); + pm_runtime_put(&client->dev); + return rval; + } + sensor->streaming = true; + rval = smiapp_start_streaming(sensor); if (rval < 0) sensor->streaming = false; } else { rval = smiapp_stop_streaming(sensor); sensor->streaming = false; + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); } return rval; @@ -2654,7 +2649,6 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) struct smiapp_subdev *ssd = to_smiapp_subdev(sd); struct smiapp_sensor *sensor = ssd->sensor; unsigned int i; - int rval; mutex_lock(&sensor->mutex); @@ -2681,22 +2675,6 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) mutex_unlock(&sensor->mutex); - rval = pm_runtime_get_sync(sd->dev); - if (rval >= 0) - return 0; - - if (rval != -EBUSY && rval != -EAGAIN) - pm_runtime_set_active(sd->dev); - pm_runtime_put(sd->dev); - - return rval; -} - -static int smiapp_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - pm_runtime_mark_last_busy(sd->dev); - pm_runtime_put_autosuspend(sd->dev); - return 0; } @@ -2704,10 +2682,6 @@ static const struct v4l2_subdev_video_ops smiapp_video_ops = { .s_stream = smiapp_set_stream, }; -static const struct v4l2_subdev_core_ops smiapp_core_ops = { - .s_power = smiapp_set_power, -}; - static const struct v4l2_subdev_pad_ops smiapp_pad_ops = { .enum_mbus_code = smiapp_enum_mbus_code, .get_fmt = smiapp_get_format, @@ -2722,7 +2696,6 @@ static const struct v4l2_subdev_sensor_ops smiapp_sensor_ops = { }; static const struct v4l2_subdev_ops smiapp_ops = { - .core = &smiapp_core_ops, .video = &smiapp_video_ops, .pad = &smiapp_pad_ops, .sensor = &smiapp_sensor_ops, @@ -2736,12 +2709,10 @@ static const struct v4l2_subdev_internal_ops smiapp_internal_src_ops = { .registered = smiapp_registered, .unregistered = smiapp_unregistered, .open = smiapp_open, - .close = smiapp_close, }; static const struct v4l2_subdev_internal_ops smiapp_internal_ops = { .open = smiapp_open, - .close = smiapp_close, }; /* ----------------------------------------------------------------------------- diff --git a/drivers/media/i2c/smiapp/smiapp-regs.c b/drivers/media/i2c/smiapp/smiapp-regs.c index d6779e35d36f..145653dc81da 100644 --- a/drivers/media/i2c/smiapp/smiapp-regs.c +++ b/drivers/media/i2c/smiapp/smiapp-regs.c @@ -231,6 +231,9 @@ int smiapp_write_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val) len != SMIAPP_REG_32BIT) || flags) return -EINVAL; + if (!sensor->active) + return 0; + msg.addr = client->addr; msg.flags = 0; /* Write */ msg.len = 2 + len; diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index f74d695018b9..e6a5ab402d7f 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h @@ -206,6 +206,7 @@ struct smiapp_sensor { u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */ u8 frame_skip; + bool active; /* is the sensor powered on? */ u16 embedded_start; /* embedded data start line */ u16 embedded_end; u16 image_start; /* image data start line */ -- cgit v1.2.3 From cd1a77e3c9cc6dbb57f02aa50e1740fc144d2dad Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Mon, 9 Oct 2017 14:24:57 +0200 Subject: media: venus: fix wrong size on dma_free This change will fix an issue with dma_free size found with DMA API debug enabled. Signed-off-by: Stanimir Varbanov Signed-off-by: Hans Verkuil Cc: # for v4.13 and up Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/hfi_venus.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c index 1caae8feaa36..734ce11b0ed0 100644 --- a/drivers/media/platform/qcom/venus/hfi_venus.c +++ b/drivers/media/platform/qcom/venus/hfi_venus.c @@ -344,7 +344,7 @@ static int venus_alloc(struct venus_hfi_device *hdev, struct mem_desc *desc, desc->attrs = DMA_ATTR_WRITE_COMBINE; desc->size = ALIGN(size, SZ_4K); - desc->kva = dma_alloc_attrs(dev, size, &desc->da, GFP_KERNEL, + desc->kva = dma_alloc_attrs(dev, desc->size, &desc->da, GFP_KERNEL, desc->attrs); if (!desc->kva) return -ENOMEM; @@ -710,10 +710,8 @@ static int venus_interface_queues_init(struct venus_hfi_device *hdev) if (ret) return ret; - hdev->ifaceq_table.kva = desc.kva; - hdev->ifaceq_table.da = desc.da; - hdev->ifaceq_table.size = IFACEQ_TABLE_SIZE; - offset = hdev->ifaceq_table.size; + hdev->ifaceq_table = desc; + offset = IFACEQ_TABLE_SIZE; for (i = 0; i < IFACEQ_NUM; i++) { queue = &hdev->queues[i]; @@ -755,9 +753,7 @@ static int venus_interface_queues_init(struct venus_hfi_device *hdev) if (ret) { hdev->sfr.da = 0; } else { - hdev->sfr.da = desc.da; - hdev->sfr.kva = desc.kva; - hdev->sfr.size = ALIGNED_SFR_SIZE; + hdev->sfr = desc; sfr = hdev->sfr.kva; sfr->buf_size = ALIGNED_SFR_SIZE; } -- cgit v1.2.3 From cab1dea3be2e51578032c5aee6ac13ff7b4aaeb4 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Tue, 10 Oct 2017 04:46:36 +0200 Subject: media: atmel-isc: Add spin lock for clock enable ops Add the spin lock for the clock enable and disable operations. Signed-off-by: Wenyou Yang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 2f8e345d297e..991f962b7023 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -65,6 +65,7 @@ struct isc_clk { struct clk_hw hw; struct clk *clk; struct regmap *regmap; + spinlock_t lock; u8 id; u8 parent_id; u32 div; @@ -312,26 +313,37 @@ static int isc_clk_enable(struct clk_hw *hw) struct isc_clk *isc_clk = to_isc_clk(hw); u32 id = isc_clk->id; struct regmap *regmap = isc_clk->regmap; + unsigned long flags; + unsigned int status; dev_dbg(isc_clk->dev, "ISC CLK: %s, div = %d, parent id = %d\n", __func__, isc_clk->div, isc_clk->parent_id); + spin_lock_irqsave(&isc_clk->lock, flags); regmap_update_bits(regmap, ISC_CLKCFG, ISC_CLKCFG_DIV_MASK(id) | ISC_CLKCFG_SEL_MASK(id), (isc_clk->div << ISC_CLKCFG_DIV_SHIFT(id)) | (isc_clk->parent_id << ISC_CLKCFG_SEL_SHIFT(id))); regmap_write(regmap, ISC_CLKEN, ISC_CLK(id)); + spin_unlock_irqrestore(&isc_clk->lock, flags); - return 0; + regmap_read(regmap, ISC_CLKSR, &status); + if (status & ISC_CLK(id)) + return 0; + else + return -EINVAL; } static void isc_clk_disable(struct clk_hw *hw) { struct isc_clk *isc_clk = to_isc_clk(hw); u32 id = isc_clk->id; + unsigned long flags; + spin_lock_irqsave(&isc_clk->lock, flags); regmap_write(isc_clk->regmap, ISC_CLKDIS, ISC_CLK(id)); + spin_unlock_irqrestore(&isc_clk->lock, flags); } static int isc_clk_is_enabled(struct clk_hw *hw) @@ -492,6 +504,7 @@ static int isc_clk_register(struct isc_device *isc, unsigned int id) isc_clk->regmap = regmap; isc_clk->id = id; isc_clk->dev = isc->dev; + spin_lock_init(&isc_clk->lock); isc_clk->clk = clk_register(isc->dev, &isc_clk->hw); if (IS_ERR(isc_clk->clk)) { -- cgit v1.2.3 From 64f6306a5af21561ad6b9a3247fc68126b8be88a Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Tue, 10 Oct 2017 04:46:37 +0200 Subject: media: atmel-isc: Add prepare and unprepare ops A software write operation to the ISC_CLKEN or ISC_CLKDIS register requires double clock domain synchronization and is not permitted when the ISC_SR.SIP is asserted. So add the .prepare and .unprepare ops to make sure the ISC_CLKSR.SIP is unasserted before the write operation to the ISC_CLKEN or ISC_CLKDIS register. Signed-off-by: Wenyou Yang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc-regs.h | 1 + drivers/media/platform/atmel/atmel-isc.c | 40 +++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/drivers/media/platform/atmel/atmel-isc-regs.h b/drivers/media/platform/atmel/atmel-isc-regs.h index 6936ac467609..93e58fcf1d5f 100644 --- a/drivers/media/platform/atmel/atmel-isc-regs.h +++ b/drivers/media/platform/atmel/atmel-isc-regs.h @@ -42,6 +42,7 @@ /* ISC Clock Status Register */ #define ISC_CLKSR 0x00000020 +#define ISC_CLKSR_SIP BIT(31) #define ISC_CLK(n) BIT(n) diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 991f962b7023..5f8228fc9c8d 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -308,6 +308,44 @@ module_param(sensor_preferred, uint, 0644); MODULE_PARM_DESC(sensor_preferred, "Sensor is preferred to output the specified format (1-on 0-off), default 1"); +static int isc_wait_clk_stable(struct clk_hw *hw) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + struct regmap *regmap = isc_clk->regmap; + unsigned long timeout = jiffies + usecs_to_jiffies(1000); + unsigned int status; + + while (time_before(jiffies, timeout)) { + regmap_read(regmap, ISC_CLKSR, &status); + if (!(status & ISC_CLKSR_SIP)) + return 0; + + usleep_range(10, 250); + } + + return -ETIMEDOUT; +} + +static int isc_clk_prepare(struct clk_hw *hw) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + + if (isc_clk->id == ISC_MCK) + pm_runtime_get_sync(isc_clk->dev); + + return isc_wait_clk_stable(hw); +} + +static void isc_clk_unprepare(struct clk_hw *hw) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + + isc_wait_clk_stable(hw); + + if (isc_clk->id == ISC_MCK) + pm_runtime_put_sync(isc_clk->dev); +} + static int isc_clk_enable(struct clk_hw *hw) { struct isc_clk *isc_clk = to_isc_clk(hw); @@ -459,6 +497,8 @@ static int isc_clk_set_rate(struct clk_hw *hw, } static const struct clk_ops isc_clk_ops = { + .prepare = isc_clk_prepare, + .unprepare = isc_clk_unprepare, .enable = isc_clk_enable, .disable = isc_clk_disable, .is_enabled = isc_clk_is_enabled, -- cgit v1.2.3 From 01192aa1c5c2a7363cc790ea102c7929ec577240 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Tue, 10 Oct 2017 04:46:38 +0200 Subject: media: atmel-isc: Enable the clocks during probe To meet the relationship, enable the HCLOCK and ispck during the device probe, "isc_pck frequency is less than or equal to isc_ispck, and isc_ispck is greater than or equal to HCLOCK." Meanwhile, call the pm_runtime_enable() in the right place. Signed-off-by: Wenyou Yang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc.c | 34 ++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 5f8228fc9c8d..a44a66ad2c02 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -389,8 +389,14 @@ static int isc_clk_is_enabled(struct clk_hw *hw) struct isc_clk *isc_clk = to_isc_clk(hw); u32 status; + if (isc_clk->id == ISC_MCK) + pm_runtime_get_sync(isc_clk->dev); + regmap_read(isc_clk->regmap, ISC_CLKSR, &status); + if (isc_clk->id == ISC_MCK) + pm_runtime_put_sync(isc_clk->dev); + return status & ISC_CLK(isc_clk->id) ? 1 : 0; } @@ -1866,25 +1872,37 @@ static int atmel_isc_probe(struct platform_device *pdev) return ret; } + ret = clk_prepare_enable(isc->hclock); + if (ret) { + dev_err(dev, "failed to enable hclock: %d\n", ret); + return ret; + } + ret = isc_clk_init(isc); if (ret) { dev_err(dev, "failed to init isc clock: %d\n", ret); - goto clean_isc_clk; + goto unprepare_hclk; } isc->ispck = isc->isc_clks[ISC_ISPCK].clk; + ret = clk_prepare_enable(isc->ispck); + if (ret) { + dev_err(dev, "failed to enable ispck: %d\n", ret); + goto unprepare_hclk; + } + /* ispck should be greater or equal to hclock */ ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock)); if (ret) { dev_err(dev, "failed to set ispck rate: %d\n", ret); - goto clean_isc_clk; + goto unprepare_clk; } ret = v4l2_device_register(dev, &isc->v4l2_dev); if (ret) { dev_err(dev, "unable to register v4l2 device.\n"); - goto clean_isc_clk; + goto unprepare_clk; } ret = isc_parse_dt(dev, isc); @@ -1917,7 +1935,9 @@ static int atmel_isc_probe(struct platform_device *pdev) break; } + pm_runtime_set_active(dev); pm_runtime_enable(dev); + pm_request_idle(dev); return 0; @@ -1927,7 +1947,11 @@ cleanup_subdev: unregister_v4l2_device: v4l2_device_unregister(&isc->v4l2_dev); -clean_isc_clk: +unprepare_clk: + clk_disable_unprepare(isc->ispck); +unprepare_hclk: + clk_disable_unprepare(isc->hclock); + isc_clk_cleanup(isc); return ret; @@ -1938,6 +1962,8 @@ static int atmel_isc_remove(struct platform_device *pdev) struct isc_device *isc = platform_get_drvdata(pdev); pm_runtime_disable(&pdev->dev); + clk_disable_unprepare(isc->ispck); + clk_disable_unprepare(isc->hclock); isc_subdev_cleanup(isc); -- cgit v1.2.3 From b0ea17c589a8b16b4405ab9088d6472cbe08d481 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Tue, 10 Oct 2017 04:46:39 +0200 Subject: media: atmel-isc: Remove unnecessary member Remove the memeber *config from the isc_subdev_entity struct, the member is useless afterward. Signed-off-by: Wenyou Yang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index a44a66ad2c02..29780fcdfc8b 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -83,7 +83,6 @@ struct isc_subdev_entity { struct v4l2_subdev *sd; struct v4l2_async_subdev *asd; struct v4l2_async_notifier notifier; - struct v4l2_subdev_pad_config *config; u32 pfe_cfg0; @@ -1000,6 +999,7 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, { struct isc_format *isc_fmt; struct v4l2_pix_format *pixfmt = &f->fmt.pix; + struct v4l2_subdev_pad_config pad_cfg; struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_TRY, }; @@ -1030,7 +1030,7 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, v4l2_fill_mbus_format(&format.format, pixfmt, mbus_code); ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt, - isc->current_subdev->config, &format); + &pad_cfg, &format); if (ret < 0) return ret; @@ -1495,8 +1495,6 @@ static void isc_async_unbind(struct v4l2_async_notifier *notifier, struct isc_device, v4l2_dev); cancel_work_sync(&isc->awb_work); video_unregister_device(&isc->video_dev); - if (isc->current_subdev->config) - v4l2_subdev_free_pad_config(isc->current_subdev->config); v4l2_ctrl_handler_free(&isc->ctrls.handler); } @@ -1648,10 +1646,6 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) INIT_LIST_HEAD(&isc->dma_queue); spin_lock_init(&isc->dma_queue_lock); - sd_entity->config = v4l2_subdev_alloc_pad_config(sd_entity->sd); - if (!sd_entity->config) - return -ENOMEM; - ret = isc_formats_init(isc); if (ret < 0) { v4l2_err(&isc->v4l2_dev, -- cgit v1.2.3 From f103ea11cd037943b511fa71c852ff14cc6de8ee Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Tue, 10 Oct 2017 04:46:40 +0200 Subject: media: atmel-isc: Rework the format list To improve the readability of code, split the format array into two, one for the format description, other for the register configuration. Meanwhile, add the flag member to indicate the format can be achieved from the sensor or be produced by the controller, and rename members related to the register configuration. Also add more formats support: GREY, ARGB444, ARGB555 and ARGB32. Signed-off-by: Wenyou Yang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc.c | 530 ++++++++++++++++++++++++------- 1 file changed, 411 insertions(+), 119 deletions(-) diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 29780fcdfc8b..2c40a7886542 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -89,34 +89,63 @@ struct isc_subdev_entity { struct list_head list; }; +/* Indicate the format is generated by the sensor */ +#define FMT_FLAG_FROM_SENSOR BIT(0) +/* Indicate the format is produced by ISC itself */ +#define FMT_FLAG_FROM_CONTROLLER BIT(1) +/* Indicate a Raw Bayer format */ +#define FMT_FLAG_RAW_FORMAT BIT(2) + +#define FMT_FLAG_RAW_FROM_SENSOR (FMT_FLAG_FROM_SENSOR | \ + FMT_FLAG_RAW_FORMAT) + /* * struct isc_format - ISC media bus format information * @fourcc: Fourcc code for this format * @mbus_code: V4L2 media bus format code. + * flags: Indicate format from sensor or converted by controller * @bpp: Bits per pixel (when stored in memory) - * @reg_bps: reg value for bits per sample * (when transferred over a bus) - * @pipeline: pipeline switch * @sd_support: Subdev supports this format * @isc_support: ISC can convert raw format to this format */ + struct isc_format { u32 fourcc; u32 mbus_code; + u32 flags; u8 bpp; - u32 reg_bps; - u32 reg_bay_cfg; - u32 reg_rlp_mode; - u32 reg_dcfg_imode; - u32 reg_dctrl_dview; - - u32 pipeline; - bool sd_support; bool isc_support; }; +/* Pipeline bitmap */ +#define WB_ENABLE BIT(0) +#define CFA_ENABLE BIT(1) +#define CC_ENABLE BIT(2) +#define GAM_ENABLE BIT(3) +#define GAM_BENABLE BIT(4) +#define GAM_GENABLE BIT(5) +#define GAM_RENABLE BIT(6) +#define CSC_ENABLE BIT(7) +#define CBC_ENABLE BIT(8) +#define SUB422_ENABLE BIT(9) +#define SUB420_ENABLE BIT(10) + +#define GAM_ENABLES (GAM_RENABLE | GAM_GENABLE | GAM_BENABLE | GAM_ENABLE) + +struct fmt_config { + u32 fourcc; + + u32 pfe_cfg0_bps; + u32 cfa_baycfg; + u32 rlp_cfg_mode; + u32 dcfg_imode; + u32 dctrl_dview; + + u32 bits_pipeline; +}; #define HIST_ENTRIES 512 #define HIST_BAYER (ISC_HIS_CFG_MODE_B + 1) @@ -181,80 +210,320 @@ struct isc_device { struct list_head subdev_entities; }; -#define RAW_FMT_IND_START 0 -#define RAW_FMT_IND_END 11 -#define ISC_FMT_IND_START 12 -#define ISC_FMT_IND_END 14 - -static struct isc_format isc_formats[] = { - { V4L2_PIX_FMT_SBGGR8, MEDIA_BUS_FMT_SBGGR8_1X8, 8, - ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT8, - ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - { V4L2_PIX_FMT_SGBRG8, MEDIA_BUS_FMT_SGBRG8_1X8, 8, - ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_GBGB, ISC_RLP_CFG_MODE_DAT8, - ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - { V4L2_PIX_FMT_SGRBG8, MEDIA_BUS_FMT_SGRBG8_1X8, 8, - ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_GRGR, ISC_RLP_CFG_MODE_DAT8, - ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - { V4L2_PIX_FMT_SRGGB8, MEDIA_BUS_FMT_SRGGB8_1X8, 8, - ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_RGRG, ISC_RLP_CFG_MODE_DAT8, - ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - - { V4L2_PIX_FMT_SBGGR10, MEDIA_BUS_FMT_SBGGR10_1X10, 16, - ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT10, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - { V4L2_PIX_FMT_SGBRG10, MEDIA_BUS_FMT_SGBRG10_1X10, 16, - ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_GBGB, ISC_RLP_CFG_MODE_DAT10, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - { V4L2_PIX_FMT_SGRBG10, MEDIA_BUS_FMT_SGRBG10_1X10, 16, - ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_GRGR, ISC_RLP_CFG_MODE_DAT10, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - { V4L2_PIX_FMT_SRGGB10, MEDIA_BUS_FMT_SRGGB10_1X10, 16, - ISC_PFG_CFG0_BPS_TEN, ISC_BAY_CFG_RGRG, ISC_RLP_CFG_MODE_DAT10, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - - { V4L2_PIX_FMT_SBGGR12, MEDIA_BUS_FMT_SBGGR12_1X12, 16, - ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT12, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - { V4L2_PIX_FMT_SGBRG12, MEDIA_BUS_FMT_SGBRG12_1X12, 16, - ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_GBGB, ISC_RLP_CFG_MODE_DAT12, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - { V4L2_PIX_FMT_SGRBG12, MEDIA_BUS_FMT_SGRBG12_1X12, 16, - ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_GRGR, ISC_RLP_CFG_MODE_DAT12, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - { V4L2_PIX_FMT_SRGGB12, MEDIA_BUS_FMT_SRGGB12_1X12, 16, - ISC_PFG_CFG0_BPS_TWELVE, ISC_BAY_CFG_RGRG, ISC_RLP_CFG_MODE_DAT12, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, - - { V4L2_PIX_FMT_YUV420, 0x0, 12, - ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_YYCC, - ISC_DCFG_IMODE_YC420P, ISC_DCTRL_DVIEW_PLANAR, 0x7fb, - false, false }, - { V4L2_PIX_FMT_YUV422P, 0x0, 16, - ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_YYCC, - ISC_DCFG_IMODE_YC422P, ISC_DCTRL_DVIEW_PLANAR, 0x3fb, - false, false }, - { V4L2_PIX_FMT_RGB565, MEDIA_BUS_FMT_RGB565_2X8_LE, 16, - ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_RGB565, - ISC_DCFG_IMODE_PACKED16, ISC_DCTRL_DVIEW_PACKED, 0x7b, - false, false }, - - { V4L2_PIX_FMT_YUYV, MEDIA_BUS_FMT_YUYV8_2X8, 16, - ISC_PFE_CFG0_BPS_EIGHT, ISC_BAY_CFG_BGBG, ISC_RLP_CFG_MODE_DAT8, - ISC_DCFG_IMODE_PACKED8, ISC_DCTRL_DVIEW_PACKED, 0x0, - false, false }, +static struct isc_format formats_list[] = { + { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 8, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 8, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 8, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 8, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR12, + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG12, + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG12, + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB12, + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, + .flags = FMT_FLAG_RAW_FROM_SENSOR, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_YUV420, + .mbus_code = 0x0, + .flags = FMT_FLAG_FROM_CONTROLLER, + .bpp = 12, + }, + { + .fourcc = V4L2_PIX_FMT_YUV422P, + .mbus_code = 0x0, + .flags = FMT_FLAG_FROM_CONTROLLER, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_GREY, + .mbus_code = MEDIA_BUS_FMT_Y8_1X8, + .flags = FMT_FLAG_FROM_CONTROLLER | + FMT_FLAG_FROM_SENSOR, + .bpp = 8, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB444, + .mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, + .flags = FMT_FLAG_FROM_CONTROLLER, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB555, + .mbus_code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, + .flags = FMT_FLAG_FROM_CONTROLLER, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_RGB565, + .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .flags = FMT_FLAG_FROM_CONTROLLER, + .bpp = 16, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB32, + .mbus_code = MEDIA_BUS_FMT_ARGB8888_1X32, + .flags = FMT_FLAG_FROM_CONTROLLER, + .bpp = 32, + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, + .flags = FMT_FLAG_FROM_CONTROLLER | + FMT_FLAG_FROM_SENSOR, + .bpp = 16, + }, +}; + +struct fmt_config fmt_configs_list[] = { + { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8, + .dcfg_imode = ISC_DCFG_IMODE_PACKED8, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_GBGB, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8, + .dcfg_imode = ISC_DCFG_IMODE_PACKED8, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_GRGR, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8, + .dcfg_imode = ISC_DCFG_IMODE_PACKED8, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_RGRG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8, + .dcfg_imode = ISC_DCFG_IMODE_PACKED8, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, + .cfa_baycfg = ISC_BAY_CFG_GBGB, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, + .cfa_baycfg = ISC_BAY_CFG_GRGR, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, + .cfa_baycfg = ISC_BAY_CFG_RGRG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR12, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG12, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, + .cfa_baycfg = ISC_BAY_CFG_GBGB, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0 + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG12, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, + .cfa_baycfg = ISC_BAY_CFG_GRGR, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB12, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, + .cfa_baycfg = ISC_BAY_CFG_RGRG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0, + }, + { + .fourcc = V4L2_PIX_FMT_YUV420, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC, + .dcfg_imode = ISC_DCFG_IMODE_YC420P, + .dctrl_dview = ISC_DCTRL_DVIEW_PLANAR, + .bits_pipeline = SUB420_ENABLE | SUB422_ENABLE | + CBC_ENABLE | CSC_ENABLE | + GAM_ENABLES | + CFA_ENABLE | WB_ENABLE, + }, + { + .fourcc = V4L2_PIX_FMT_YUV422P, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC, + .dcfg_imode = ISC_DCFG_IMODE_YC422P, + .dctrl_dview = ISC_DCTRL_DVIEW_PLANAR, + .bits_pipeline = SUB422_ENABLE | + CBC_ENABLE | CSC_ENABLE | + GAM_ENABLES | + CFA_ENABLE | WB_ENABLE, + }, + { + .fourcc = V4L2_PIX_FMT_GREY, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY8, + .dcfg_imode = ISC_DCFG_IMODE_PACKED8, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = CBC_ENABLE | CSC_ENABLE | + GAM_ENABLES | + CFA_ENABLE | WB_ENABLE, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB444, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB444, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB555, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB555, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE, + }, + { + .fourcc = V4L2_PIX_FMT_RGB565, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_RGB565, + .dcfg_imode = ISC_DCFG_IMODE_PACKED16, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB32, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB32, + .dcfg_imode = ISC_DCFG_IMODE_PACKED32, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE, + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8, + .dcfg_imode = ISC_DCFG_IMODE_PACKED8, + .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, + .bits_pipeline = 0x0 + }, }; #define GAMMA_MAX 2 @@ -633,11 +902,27 @@ static inline bool sensor_is_preferred(const struct isc_format *isc_fmt) !isc_fmt->isc_support; } +static struct fmt_config *get_fmt_config(u32 fourcc) +{ + struct fmt_config *config; + int i; + + config = &fmt_configs_list[0]; + for (i = 0; i < ARRAY_SIZE(fmt_configs_list); i++) { + if (config->fourcc == fourcc) + return config; + + config++; + } + return NULL; +} + static void isc_start_dma(struct isc_device *isc) { struct regmap *regmap = isc->regmap; struct v4l2_pix_format *pixfmt = &isc->fmt.fmt.pix; u32 sizeimage = pixfmt->sizeimage; + struct fmt_config *config = get_fmt_config(isc->current_fmt->fourcc); u32 dctrl_dview; dma_addr_t addr0; @@ -660,7 +945,7 @@ static void isc_start_dma(struct isc_device *isc) if (sensor_is_preferred(isc->current_fmt)) dctrl_dview = ISC_DCTRL_DVIEW_PACKED; else - dctrl_dview = isc->current_fmt->reg_dctrl_dview; + dctrl_dview = config->dctrl_dview; regmap_write(regmap, ISC_DCTRL, dctrl_dview | ISC_DCTRL_IE_IS); regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE); @@ -670,6 +955,7 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) { struct regmap *regmap = isc->regmap; struct isc_ctrls *ctrls = &isc->ctrls; + struct fmt_config *config = get_fmt_config(isc->raw_fmt->fourcc); u32 val, bay_cfg; const u32 *gamma; unsigned int i; @@ -683,7 +969,7 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) if (!pipeline) return; - bay_cfg = isc->raw_fmt->reg_bay_cfg; + bay_cfg = config->cfa_baycfg; regmap_write(regmap, ISC_WB_CFG, bay_cfg); regmap_write(regmap, ISC_WB_O_RGR, 0x0); @@ -736,11 +1022,13 @@ static void isc_set_histogram(struct isc_device *isc) { struct regmap *regmap = isc->regmap; struct isc_ctrls *ctrls = &isc->ctrls; + struct fmt_config *config = get_fmt_config(isc->raw_fmt->fourcc); if (ctrls->awb && (ctrls->hist_stat != HIST_ENABLED)) { - regmap_write(regmap, ISC_HIS_CFG, ISC_HIS_CFG_MODE_R | - (isc->raw_fmt->reg_bay_cfg << ISC_HIS_CFG_BAYSEL_SHIFT) | - ISC_HIS_CFG_RAR); + regmap_write(regmap, ISC_HIS_CFG, + ISC_HIS_CFG_MODE_R | + (config->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT) | + ISC_HIS_CFG_RAR); regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_EN); regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE); ctrls->hist_id = ISC_HIS_CFG_MODE_R; @@ -757,8 +1045,10 @@ static void isc_set_histogram(struct isc_device *isc) } static inline void isc_get_param(const struct isc_format *fmt, - u32 *rlp_mode, u32 *dcfg) + u32 *rlp_mode, u32 *dcfg) { + struct fmt_config *config = get_fmt_config(fmt->fourcc); + *dcfg = ISC_DCFG_YMBSIZE_BEATS8; switch (fmt->fourcc) { @@ -770,8 +1060,8 @@ static inline void isc_get_param(const struct isc_format *fmt, case V4L2_PIX_FMT_SGBRG12: case V4L2_PIX_FMT_SGRBG12: case V4L2_PIX_FMT_SRGGB12: - *rlp_mode = fmt->reg_rlp_mode; - *dcfg |= fmt->reg_dcfg_imode; + *rlp_mode = config->rlp_cfg_mode; + *dcfg |= config->dcfg_imode; break; default: *rlp_mode = ISC_RLP_CFG_MODE_DAT8; @@ -784,20 +1074,22 @@ static int isc_configure(struct isc_device *isc) { struct regmap *regmap = isc->regmap; const struct isc_format *current_fmt = isc->current_fmt; + struct fmt_config *curfmt_config = get_fmt_config(current_fmt->fourcc); + struct fmt_config *rawfmt_config = get_fmt_config(isc->raw_fmt->fourcc); struct isc_subdev_entity *subdev = isc->current_subdev; u32 pfe_cfg0, rlp_mode, dcfg, mask, pipeline; if (sensor_is_preferred(current_fmt)) { - pfe_cfg0 = current_fmt->reg_bps; + pfe_cfg0 = curfmt_config->pfe_cfg0_bps; pipeline = 0x0; isc_get_param(current_fmt, &rlp_mode, &dcfg); isc->ctrls.hist_stat = HIST_INIT; } else { - pfe_cfg0 = isc->raw_fmt->reg_bps; - pipeline = current_fmt->pipeline; - rlp_mode = current_fmt->reg_rlp_mode; - dcfg = current_fmt->reg_dcfg_imode | ISC_DCFG_YMBSIZE_BEATS8 | - ISC_DCFG_CMBSIZE_BEATS8; + pfe_cfg0 = rawfmt_config->pfe_cfg0_bps; + pipeline = curfmt_config->bits_pipeline; + rlp_mode = curfmt_config->rlp_cfg_mode; + dcfg = curfmt_config->dcfg_imode | + ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8; } pfe_cfg0 |= subdev->pfe_cfg0 | ISC_PFE_CFG0_MODE_PROGRESSIVE; @@ -1382,6 +1674,7 @@ static void isc_awb_work(struct work_struct *w) struct isc_device *isc = container_of(w, struct isc_device, awb_work); struct regmap *regmap = isc->regmap; + struct fmt_config *config = get_fmt_config(isc->raw_fmt->fourcc); struct isc_ctrls *ctrls = &isc->ctrls; u32 hist_id = ctrls->hist_id; u32 baysel; @@ -1399,7 +1692,7 @@ static void isc_awb_work(struct work_struct *w) } ctrls->hist_id = hist_id; - baysel = isc->raw_fmt->reg_bay_cfg << ISC_HIS_CFG_BAYSEL_SHIFT; + baysel = config->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT; pm_runtime_get_sync(isc->dev); @@ -1500,10 +1793,10 @@ static void isc_async_unbind(struct v4l2_async_notifier *notifier, static struct isc_format *find_format_by_code(unsigned int code, int *index) { - struct isc_format *fmt = &isc_formats[0]; + struct isc_format *fmt = &formats_list[0]; unsigned int i; - for (i = 0; i < ARRAY_SIZE(isc_formats); i++) { + for (i = 0; i < ARRAY_SIZE(formats_list); i++) { if (fmt->mbus_code == code) { *index = i; return fmt; @@ -1520,37 +1813,36 @@ static int isc_formats_init(struct isc_device *isc) struct isc_format *fmt; struct v4l2_subdev *subdev = isc->current_subdev->sd; unsigned int num_fmts, i, j; + u32 list_size = ARRAY_SIZE(formats_list); struct v4l2_subdev_mbus_code_enum mbus_code = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; - fmt = &isc_formats[0]; - for (i = 0; i < ARRAY_SIZE(isc_formats); i++) { - fmt->isc_support = false; - fmt->sd_support = false; - - fmt++; - } - while (!v4l2_subdev_call(subdev, pad, enum_mbus_code, NULL, &mbus_code)) { mbus_code.index++; + fmt = find_format_by_code(mbus_code.code, &i); - if (!fmt) + if ((!fmt) || (!(fmt->flags & FMT_FLAG_FROM_SENSOR))) continue; fmt->sd_support = true; - if (i <= RAW_FMT_IND_END) { - for (j = ISC_FMT_IND_START; j <= ISC_FMT_IND_END; j++) - isc_formats[j].isc_support = true; - + if (fmt->flags & FMT_FLAG_RAW_FORMAT) isc->raw_fmt = fmt; - } } - fmt = &isc_formats[0]; - for (i = 0, num_fmts = 0; i < ARRAY_SIZE(isc_formats); i++) { + fmt = &formats_list[0]; + for (i = 0; i < list_size; i++) { + if (fmt->flags & FMT_FLAG_FROM_CONTROLLER) + fmt->isc_support = true; + + fmt++; + } + + fmt = &formats_list[0]; + num_fmts = 0; + for (i = 0; i < list_size; i++) { if (fmt->isc_support || fmt->sd_support) num_fmts++; @@ -1567,8 +1859,8 @@ static int isc_formats_init(struct isc_device *isc) if (!isc->user_formats) return -ENOMEM; - fmt = &isc_formats[0]; - for (i = 0, j = 0; i < ARRAY_SIZE(isc_formats); i++) { + fmt = &formats_list[0]; + for (i = 0, j = 0; i < list_size; i++) { if (fmt->isc_support || fmt->sd_support) isc->user_formats[j++] = fmt; -- cgit v1.2.3 From 5232c37ce244db04fd50d160b92e40d2df46a2e9 Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Tue, 10 Oct 2017 09:52:36 +0200 Subject: media: venus: venc: fix bytesused v4l2_plane field This fixes wrongly filled bytesused field of v4l2_plane structure by include data_offset in the plane, Also fill data_offset and bytesused for capture type of buffers only. Signed-off-by: Stanimir Varbanov Signed-off-by: Hans Verkuil Cc: # for v4.13 and up Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/venc.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 6f123a387cf9..3fcf0e9b7b29 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -963,13 +963,12 @@ static void venc_buf_done(struct venus_inst *inst, unsigned int buf_type, if (!vbuf) return; - vb = &vbuf->vb2_buf; - vb->planes[0].bytesused = bytesused; - vb->planes[0].data_offset = data_offset; - vbuf->flags = flags; if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + vb = &vbuf->vb2_buf; + vb2_set_plane_payload(vb, 0, bytesused + data_offset); + vb->planes[0].data_offset = data_offset; vb->timestamp = timestamp_us * NSEC_PER_USEC; vbuf->sequence = inst->sequence_cap++; } else { -- cgit v1.2.3 From 3863360c15da47e18d894268ad6182fdc7caf0c7 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 11 Oct 2017 13:16:43 +0200 Subject: media: vimc: Fix return value check in vimc_add_subdevs() In case of error, the function platform_device_register_data() returns ERR_PTR() and never returns NULL. The NULL test in the return value check should be replaced with IS_ERR(). Signed-off-by: Wei Yongjun Acked-by: Helen Koike Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vimc/vimc-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/vimc/vimc-core.c b/drivers/media/platform/vimc/vimc-core.c index 51c0eee61ca6..fe088a953860 100644 --- a/drivers/media/platform/vimc/vimc-core.c +++ b/drivers/media/platform/vimc/vimc-core.c @@ -267,11 +267,12 @@ static struct component_match *vimc_add_subdevs(struct vimc_device *vimc) PLATFORM_DEVID_AUTO, &pdata, sizeof(pdata)); - if (!vimc->subdevs[i]) { + if (IS_ERR(vimc->subdevs[i])) { + match = ERR_CAST(vimc->subdevs[i]); while (--i >= 0) platform_device_unregister(vimc->subdevs[i]); - return ERR_PTR(-ENOMEM); + return match; } component_match_add(&vimc->pdev.dev, &match, vimc_comp_compare, -- cgit v1.2.3 From e69b987a97599456b95b5fef4aca8dcdb1505aea Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Fri, 13 Oct 2017 16:13:17 +0200 Subject: media: venus: reimplement decoder stop command This addresses the wrong behavior of decoder stop command by rewriting it. These new implementation enqueue an empty buffer on the decoder input buffer queue to signal end-of-stream. The client should stop queuing buffers on the V4L2 Output queue and continue queuing/dequeuing buffers on Capture queue. This process will continue until the client receives a buffer with V4L2_BUF_FLAG_LAST flag raised, which means that this is last decoded buffer with data. Signed-off-by: Stanimir Varbanov Tested-by: Nicolas Dufresne Signed-off-by: Hans Verkuil Cc: # for v4.13 and up Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/core.h | 2 -- drivers/media/platform/qcom/venus/helpers.c | 7 ------ drivers/media/platform/qcom/venus/hfi.c | 1 + drivers/media/platform/qcom/venus/vdec.c | 34 +++++++++++++++++++---------- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index cba092bcb76d..a0fe80df0cbd 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -194,7 +194,6 @@ struct venus_buffer { * @fh: a holder of v4l file handle structure * @streamon_cap: stream on flag for capture queue * @streamon_out: stream on flag for output queue - * @cmd_stop: a flag to signal encoder/decoder commands * @width: current capture width * @height: current capture height * @out_width: current output width @@ -258,7 +257,6 @@ struct venus_inst { } controls; struct v4l2_fh fh; unsigned int streamon_cap, streamon_out; - bool cmd_stop; u32 width; u32 height; u32 out_width; diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 9b2a401a4891..0ce9559a2924 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -623,13 +623,6 @@ void venus_helper_vb2_buf_queue(struct vb2_buffer *vb) mutex_lock(&inst->lock); - if (inst->cmd_stop) { - vbuf->flags |= V4L2_BUF_FLAG_LAST; - v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); - inst->cmd_stop = false; - goto unlock; - } - v4l2_m2m_buf_queue(m2m_ctx, vbuf); if (!(inst->streamon_out & inst->streamon_cap)) diff --git a/drivers/media/platform/qcom/venus/hfi.c b/drivers/media/platform/qcom/venus/hfi.c index c09490876516..ba29fd4d4984 100644 --- a/drivers/media/platform/qcom/venus/hfi.c +++ b/drivers/media/platform/qcom/venus/hfi.c @@ -484,6 +484,7 @@ int hfi_session_process_buf(struct venus_inst *inst, struct hfi_frame_data *fd) return -EINVAL; } +EXPORT_SYMBOL_GPL(hfi_session_process_buf); irqreturn_t hfi_isr_thread(int irq, void *dev_id) { diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index da611a5eb670..c9e9576bb08a 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -469,8 +469,14 @@ static int vdec_subscribe_event(struct v4l2_fh *fh, static int vdec_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) { - if (cmd->cmd != V4L2_DEC_CMD_STOP) + switch (cmd->cmd) { + case V4L2_DEC_CMD_STOP: + if (cmd->flags & V4L2_DEC_CMD_STOP_TO_BLACK) + return -EINVAL; + break; + default: return -EINVAL; + } return 0; } @@ -479,6 +485,7 @@ static int vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) { struct venus_inst *inst = to_inst(file); + struct hfi_frame_data fdata = {0}; int ret; ret = vdec_try_decoder_cmd(file, fh, cmd); @@ -486,12 +493,23 @@ vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) return ret; mutex_lock(&inst->lock); - inst->cmd_stop = true; - mutex_unlock(&inst->lock); - hfi_session_flush(inst); + /* + * Implement V4L2_DEC_CMD_STOP by enqueue an empty buffer on decoder + * input to signal EOS. + */ + if (!(inst->streamon_out & inst->streamon_cap)) + goto unlock; + + fdata.buffer_type = HFI_BUFFER_INPUT; + fdata.flags |= HFI_BUFFERFLAG_EOS; + fdata.device_addr = 0xdeadbeef; - return 0; + ret = hfi_session_process_buf(inst, &fdata); + +unlock: + mutex_unlock(&inst->lock); + return ret; } static const struct v4l2_ioctl_ops vdec_ioctl_ops = { @@ -718,7 +736,6 @@ static int vdec_start_streaming(struct vb2_queue *q, unsigned int count) inst->reconfig = false; inst->sequence_cap = 0; inst->sequence_out = 0; - inst->cmd_stop = false; ret = vdec_init_session(inst); if (ret) @@ -807,11 +824,6 @@ static void vdec_buf_done(struct venus_inst *inst, unsigned int buf_type, vb->timestamp = timestamp_us * NSEC_PER_USEC; vbuf->sequence = inst->sequence_cap++; - if (inst->cmd_stop) { - vbuf->flags |= V4L2_BUF_FLAG_LAST; - inst->cmd_stop = false; - } - if (vbuf->flags & V4L2_BUF_FLAG_LAST) { const struct v4l2_event ev = { .type = V4L2_EVENT_EOS }; -- cgit v1.2.3 From 5bf24e08b685d862f1249987a6d3423b42989622 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 13 Oct 2017 18:01:32 +0200 Subject: media: cec-pin.h: move non-kAPI parts into cec-pin-priv.h The kAPI cec-pin.h header also defined data structures that did not belong here but were private to the CEC core code. Split that part off into a cec-pin-priv.h header. Signed-off-by: Hans Verkuil Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-api.c | 1 + drivers/media/cec/cec-pin-priv.h | 133 +++++++++++++++++++++++++++++++++++++++ drivers/media/cec/cec-pin.c | 1 + include/media/cec-pin.h | 107 ------------------------------- 4 files changed, 135 insertions(+), 107 deletions(-) create mode 100644 drivers/media/cec/cec-pin-priv.h diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c index 465bb3ec21f6..3dba3aa34a43 100644 --- a/drivers/media/cec/cec-api.c +++ b/drivers/media/cec/cec-api.c @@ -32,6 +32,7 @@ #include #include "cec-priv.h" +#include "cec-pin-priv.h" static inline struct cec_devnode *cec_devnode_data(struct file *filp) { diff --git a/drivers/media/cec/cec-pin-priv.h b/drivers/media/cec/cec-pin-priv.h new file mode 100644 index 000000000000..7d0def199762 --- /dev/null +++ b/drivers/media/cec/cec-pin-priv.h @@ -0,0 +1,133 @@ +/* + * cec-pin-priv.h - internal cec-pin header + * + * Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef LINUX_CEC_PIN_PRIV_H +#define LINUX_CEC_PIN_PRIV_H + +#include +#include +#include + +enum cec_pin_state { + /* CEC is off */ + CEC_ST_OFF, + /* CEC is idle, waiting for Rx or Tx */ + CEC_ST_IDLE, + + /* Tx states */ + + /* Pending Tx, waiting for Signal Free Time to expire */ + CEC_ST_TX_WAIT, + /* Low-drive was detected, wait for bus to go high */ + CEC_ST_TX_WAIT_FOR_HIGH, + /* Drive CEC low for the start bit */ + CEC_ST_TX_START_BIT_LOW, + /* Drive CEC high for the start bit */ + CEC_ST_TX_START_BIT_HIGH, + /* Drive CEC low for the 0 bit */ + CEC_ST_TX_DATA_BIT_0_LOW, + /* Drive CEC high for the 0 bit */ + CEC_ST_TX_DATA_BIT_0_HIGH, + /* Drive CEC low for the 1 bit */ + CEC_ST_TX_DATA_BIT_1_LOW, + /* Drive CEC high for the 1 bit */ + CEC_ST_TX_DATA_BIT_1_HIGH, + /* + * Wait for start of sample time to check for Ack bit or first + * four initiator bits to check for Arbitration Lost. + */ + CEC_ST_TX_DATA_BIT_1_HIGH_PRE_SAMPLE, + /* Wait for end of bit period after sampling */ + CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE, + + /* Rx states */ + + /* Start bit low detected */ + CEC_ST_RX_START_BIT_LOW, + /* Start bit high detected */ + CEC_ST_RX_START_BIT_HIGH, + /* Wait for bit sample time */ + CEC_ST_RX_DATA_SAMPLE, + /* Wait for earliest end of bit period after sampling */ + CEC_ST_RX_DATA_POST_SAMPLE, + /* Wait for CEC to go high (i.e. end of bit period */ + CEC_ST_RX_DATA_HIGH, + /* Drive CEC low to send 0 Ack bit */ + CEC_ST_RX_ACK_LOW, + /* End of 0 Ack time, wait for earliest end of bit period */ + CEC_ST_RX_ACK_LOW_POST, + /* Wait for CEC to go high (i.e. end of bit period */ + CEC_ST_RX_ACK_HIGH_POST, + /* Wait for earliest end of bit period and end of message */ + CEC_ST_RX_ACK_FINISH, + + /* Start low drive */ + CEC_ST_LOW_DRIVE, + /* Monitor pin using interrupts */ + CEC_ST_RX_IRQ, + + /* Total number of pin states */ + CEC_PIN_STATES +}; + +#define CEC_NUM_PIN_EVENTS 128 + +#define CEC_PIN_IRQ_UNCHANGED 0 +#define CEC_PIN_IRQ_DISABLE 1 +#define CEC_PIN_IRQ_ENABLE 2 + +struct cec_pin { + struct cec_adapter *adap; + const struct cec_pin_ops *ops; + struct task_struct *kthread; + wait_queue_head_t kthread_waitq; + struct hrtimer timer; + ktime_t ts; + unsigned int wait_usecs; + u16 la_mask; + bool enabled; + bool monitor_all; + bool rx_eom; + bool enable_irq_failed; + enum cec_pin_state state; + struct cec_msg tx_msg; + u32 tx_bit; + bool tx_nacked; + u32 tx_signal_free_time; + struct cec_msg rx_msg; + u32 rx_bit; + + struct cec_msg work_rx_msg; + u8 work_tx_status; + ktime_t work_tx_ts; + atomic_t work_irq_change; + atomic_t work_pin_events; + unsigned int work_pin_events_wr; + unsigned int work_pin_events_rd; + ktime_t work_pin_ts[CEC_NUM_PIN_EVENTS]; + bool work_pin_is_high[CEC_NUM_PIN_EVENTS]; + ktime_t timer_ts; + u32 timer_cnt; + u32 timer_100ms_overruns; + u32 timer_300ms_overruns; + u32 timer_max_overrun; + u32 timer_sum_overrun; +}; + +#endif diff --git a/drivers/media/cec/cec-pin.c b/drivers/media/cec/cec-pin.c index e2aa5d6e619d..a4c881dc81c4 100644 --- a/drivers/media/cec/cec-pin.c +++ b/drivers/media/cec/cec-pin.c @@ -20,6 +20,7 @@ #include #include +#include "cec-pin-priv.h" /* All timings are in microseconds */ diff --git a/include/media/cec-pin.h b/include/media/cec-pin.h index ea84b9c9e0c3..83b3e17e0a07 100644 --- a/include/media/cec-pin.h +++ b/include/media/cec-pin.h @@ -21,71 +21,8 @@ #define LINUX_CEC_PIN_H #include -#include #include -enum cec_pin_state { - /* CEC is off */ - CEC_ST_OFF, - /* CEC is idle, waiting for Rx or Tx */ - CEC_ST_IDLE, - - /* Tx states */ - - /* Pending Tx, waiting for Signal Free Time to expire */ - CEC_ST_TX_WAIT, - /* Low-drive was detected, wait for bus to go high */ - CEC_ST_TX_WAIT_FOR_HIGH, - /* Drive CEC low for the start bit */ - CEC_ST_TX_START_BIT_LOW, - /* Drive CEC high for the start bit */ - CEC_ST_TX_START_BIT_HIGH, - /* Drive CEC low for the 0 bit */ - CEC_ST_TX_DATA_BIT_0_LOW, - /* Drive CEC high for the 0 bit */ - CEC_ST_TX_DATA_BIT_0_HIGH, - /* Drive CEC low for the 1 bit */ - CEC_ST_TX_DATA_BIT_1_LOW, - /* Drive CEC high for the 1 bit */ - CEC_ST_TX_DATA_BIT_1_HIGH, - /* - * Wait for start of sample time to check for Ack bit or first - * four initiator bits to check for Arbitration Lost. - */ - CEC_ST_TX_DATA_BIT_1_HIGH_PRE_SAMPLE, - /* Wait for end of bit period after sampling */ - CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE, - - /* Rx states */ - - /* Start bit low detected */ - CEC_ST_RX_START_BIT_LOW, - /* Start bit high detected */ - CEC_ST_RX_START_BIT_HIGH, - /* Wait for bit sample time */ - CEC_ST_RX_DATA_SAMPLE, - /* Wait for earliest end of bit period after sampling */ - CEC_ST_RX_DATA_POST_SAMPLE, - /* Wait for CEC to go high (i.e. end of bit period */ - CEC_ST_RX_DATA_HIGH, - /* Drive CEC low to send 0 Ack bit */ - CEC_ST_RX_ACK_LOW, - /* End of 0 Ack time, wait for earliest end of bit period */ - CEC_ST_RX_ACK_LOW_POST, - /* Wait for CEC to go high (i.e. end of bit period */ - CEC_ST_RX_ACK_HIGH_POST, - /* Wait for earliest end of bit period and end of message */ - CEC_ST_RX_ACK_FINISH, - - /* Start low drive */ - CEC_ST_LOW_DRIVE, - /* Monitor pin using interrupts */ - CEC_ST_RX_IRQ, - - /* Total number of pin states */ - CEC_PIN_STATES -}; - /** * struct cec_pin_ops - low-level CEC pin operations * @read: read the CEC pin. Return true if high, false if low. @@ -115,50 +52,6 @@ struct cec_pin_ops { int (*read_hpd)(struct cec_adapter *adap); }; -#define CEC_NUM_PIN_EVENTS 128 - -#define CEC_PIN_IRQ_UNCHANGED 0 -#define CEC_PIN_IRQ_DISABLE 1 -#define CEC_PIN_IRQ_ENABLE 2 - -struct cec_pin { - struct cec_adapter *adap; - const struct cec_pin_ops *ops; - struct task_struct *kthread; - wait_queue_head_t kthread_waitq; - struct hrtimer timer; - ktime_t ts; - unsigned int wait_usecs; - u16 la_mask; - bool enabled; - bool monitor_all; - bool rx_eom; - bool enable_irq_failed; - enum cec_pin_state state; - struct cec_msg tx_msg; - u32 tx_bit; - bool tx_nacked; - u32 tx_signal_free_time; - struct cec_msg rx_msg; - u32 rx_bit; - - struct cec_msg work_rx_msg; - u8 work_tx_status; - ktime_t work_tx_ts; - atomic_t work_irq_change; - atomic_t work_pin_events; - unsigned int work_pin_events_wr; - unsigned int work_pin_events_rd; - ktime_t work_pin_ts[CEC_NUM_PIN_EVENTS]; - bool work_pin_is_high[CEC_NUM_PIN_EVENTS]; - ktime_t timer_ts; - u32 timer_cnt; - u32 timer_100ms_overruns; - u32 timer_300ms_overruns; - u32 timer_max_overrun; - u32 timer_sum_overrun; -}; - /** * cec_pin_changed() - update pin state from interrupt * -- cgit v1.2.3 From 7e11d5027b1fed5bbd0d74842a0a60381a2be823 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 14 Sep 2017 14:34:39 +0200 Subject: media: tm6000: cleanup trival coding style issues - Delete seven error messages for a failed memory allocation - Adjust seven checks for null pointers - Use common error handling code in tm6000_usb_probe() - Adjust jump targets so that the function "kfree" will be always called with a non-null pointer. - Delete an initialisation for the local variable "dev" which became unnecessary with this refactoring. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tm6000/tm6000-cards.c | 27 +++++++++++++-------------- drivers/media/usb/tm6000/tm6000-dvb.c | 11 ++++------- drivers/media/usb/tm6000/tm6000-input.c | 2 +- drivers/media/usb/tm6000/tm6000-video.c | 17 +++++------------ 4 files changed, 23 insertions(+), 34 deletions(-) diff --git a/drivers/media/usb/tm6000/tm6000-cards.c b/drivers/media/usb/tm6000/tm6000-cards.c index 2537643a1808..77347541904d 100644 --- a/drivers/media/usb/tm6000/tm6000-cards.c +++ b/drivers/media/usb/tm6000/tm6000-cards.c @@ -1184,7 +1184,7 @@ static int tm6000_usb_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct usb_device *usbdev; - struct tm6000_core *dev = NULL; + struct tm6000_core *dev; int i, rc = 0; int nr = 0; char *speed; @@ -1194,22 +1194,21 @@ static int tm6000_usb_probe(struct usb_interface *interface, /* Selects the proper interface */ rc = usb_set_interface(usbdev, 0, 1); if (rc < 0) - goto err; + goto report_failure; /* Check to see next free device and mark as used */ nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS); if (nr >= TM6000_MAXBOARDS) { printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS); - usb_put_dev(usbdev); - return -ENOMEM; + rc = -ENOMEM; + goto put_device; } /* Create and initialize dev struct */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - printk(KERN_ERR "tm6000" ": out of memory!\n"); - usb_put_dev(usbdev); - return -ENOMEM; + if (!dev) { + rc = -ENOMEM; + goto put_device; } spin_lock_init(&dev->slock); mutex_init(&dev->usb_lock); @@ -1313,8 +1312,7 @@ static int tm6000_usb_probe(struct usb_interface *interface, if (!dev->isoc_in.endp) { printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n"); rc = -ENODEV; - - goto err; + goto free_device; } /* save our data pointer in this interface device */ @@ -1324,17 +1322,18 @@ static int tm6000_usb_probe(struct usb_interface *interface, rc = tm6000_init_dev(dev); if (rc < 0) - goto err; + goto free_device; return 0; -err: +free_device: + kfree(dev); +report_failure: printk(KERN_ERR "tm6000: Error %d while registering\n", rc); clear_bit(nr, &tm6000_devused); +put_device: usb_put_dev(usbdev); - - kfree(dev); return rc; } diff --git a/drivers/media/usb/tm6000/tm6000-dvb.c b/drivers/media/usb/tm6000/tm6000-dvb.c index 097ac321b7e1..2bc584f75f87 100644 --- a/drivers/media/usb/tm6000/tm6000-dvb.c +++ b/drivers/media/usb/tm6000/tm6000-dvb.c @@ -123,7 +123,7 @@ static int tm6000_start_stream(struct tm6000_core *dev) } dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL); - if (dvb->bulk_urb == NULL) + if (!dvb->bulk_urb) return -ENOMEM; pipe = usb_rcvbulkpipe(dev->udev, dev->bulk_in.endp->desc.bEndpointAddress @@ -133,9 +133,8 @@ static int tm6000_start_stream(struct tm6000_core *dev) size = size * 15; /* 512 x 8 or 12 or 15 */ dvb->bulk_urb->transfer_buffer = kzalloc(size, GFP_KERNEL); - if (dvb->bulk_urb->transfer_buffer == NULL) { + if (!dvb->bulk_urb->transfer_buffer) { usb_free_urb(dvb->bulk_urb); - printk(KERN_ERR "tm6000: couldn't allocate transfer buffer!\n"); return -ENOMEM; } @@ -361,7 +360,7 @@ static void unregister_dvb(struct tm6000_core *dev) { struct tm6000_dvb *dvb = dev->dvb; - if (dvb->bulk_urb != NULL) { + if (dvb->bulk_urb) { struct urb *bulk_urb = dvb->bulk_urb; kfree(bulk_urb->transfer_buffer); @@ -400,10 +399,8 @@ static int dvb_init(struct tm6000_core *dev) } dvb = kzalloc(sizeof(struct tm6000_dvb), GFP_KERNEL); - if (!dvb) { - printk(KERN_INFO "Cannot allocate memory\n"); + if (!dvb) return -ENOMEM; - } dev->dvb = dvb; diff --git a/drivers/media/usb/tm6000/tm6000-input.c b/drivers/media/usb/tm6000/tm6000-input.c index 91889ad9cdd7..397990afe00b 100644 --- a/drivers/media/usb/tm6000/tm6000-input.c +++ b/drivers/media/usb/tm6000/tm6000-input.c @@ -352,7 +352,7 @@ static int __tm6000_ir_int_start(struct rc_dev *rc) dprintk(1, "IR max size: %d\n", size); ir->int_urb->transfer_buffer = kzalloc(size, GFP_ATOMIC); - if (ir->int_urb->transfer_buffer == NULL) { + if (!ir->int_urb->transfer_buffer) { usb_free_urb(ir->int_urb); return err; } diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index ec8c4d2534dc..0d45f35e1697 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -470,20 +470,16 @@ static int tm6000_alloc_urb_buffers(struct tm6000_core *dev) int num_bufs = TM6000_NUM_URB_BUF; int i; - if (dev->urb_buffer != NULL) + if (dev->urb_buffer) return 0; dev->urb_buffer = kmalloc(sizeof(void *)*num_bufs, GFP_KERNEL); - if (!dev->urb_buffer) { - tm6000_err("cannot allocate memory for urb buffers\n"); + if (!dev->urb_buffer) return -ENOMEM; - } dev->urb_dma = kmalloc(sizeof(dma_addr_t *)*num_bufs, GFP_KERNEL); - if (!dev->urb_dma) { - tm6000_err("cannot allocate memory for urb dma pointers\n"); + if (!dev->urb_dma) return -ENOMEM; - } for (i = 0; i < num_bufs; i++) { dev->urb_buffer[i] = usb_alloc_coherent( @@ -507,7 +503,7 @@ static int tm6000_free_urb_buffers(struct tm6000_core *dev) { int i; - if (dev->urb_buffer == NULL) + if (!dev->urb_buffer) return 0; for (i = 0; i < TM6000_NUM_URB_BUF; i++) { @@ -598,15 +594,12 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev) dev->isoc_ctl.num_bufs = num_bufs; dev->isoc_ctl.urb = kmalloc(sizeof(void *)*num_bufs, GFP_KERNEL); - if (!dev->isoc_ctl.urb) { - tm6000_err("cannot alloc memory for usb buffers\n"); + if (!dev->isoc_ctl.urb) return -ENOMEM; - } dev->isoc_ctl.transfer_buffer = kmalloc(sizeof(void *)*num_bufs, GFP_KERNEL); if (!dev->isoc_ctl.transfer_buffer) { - tm6000_err("cannot allocate memory for usbtransfer\n"); kfree(dev->isoc_ctl.urb); return -ENOMEM; } -- cgit v1.2.3 From 3863d4bb554fdbe8cc521ad5653593923edc405b Mon Sep 17 00:00:00 2001 From: Jacob Chen Date: Mon, 18 Sep 2017 06:00:51 +0200 Subject: media: i2c: tc358743: fix spelling mistake It should be "LP-11". Signed-off-by: Jacob Chen Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358743.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index a9355032076f..6c59a460647f 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -1649,7 +1649,7 @@ static int tc358743_s_stream(struct v4l2_subdev *sd, int enable) { enable_stream(sd, enable); if (!enable) { - /* Put all lanes in PL-11 state (STOPSTATE) */ + /* Put all lanes in LP-11 state (STOPSTATE) */ tc358743_set_csi(sd); } -- cgit v1.2.3 From e641e02d78682f7749053d84d1729c5e37655ff9 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 20 Sep 2017 11:40:58 +0200 Subject: media: coda: Handle return value of kasprintf kasprintf() can fail here and we must check its return value. Signed-off-by: Arvind Yadav Reviewed-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 291c40933935..bfc4ecf6f068 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -417,6 +417,10 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, dev->devtype->product != CODA_DX6) size += ysize / 4; name = kasprintf(GFP_KERNEL, "fb%d", i); + if (!name) { + coda_free_framebuffers(ctx); + return -ENOMEM; + } ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i], size, name); kfree(name); -- cgit v1.2.3 From b145ef4f79757dc39488025bfc92481279461034 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Wed, 27 Sep 2017 15:59:42 +0200 Subject: media: bt8xx: make bttv_vbi_qops const Make this const as it is only passed to the const argument of the function videobuf_queue_sg_init in the file referencing it. Also, make the declaration in the header const. Structure found using Coccinelle and changes done by hand. Signed-off-by: Bhumika Goyal Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-vbi.c | 2 +- drivers/media/pci/bt8xx/bttvp.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/pci/bt8xx/bttv-vbi.c b/drivers/media/pci/bt8xx/bttv-vbi.c index e77129c92fa0..67c6583f1d79 100644 --- a/drivers/media/pci/bt8xx/bttv-vbi.c +++ b/drivers/media/pci/bt8xx/bttv-vbi.c @@ -233,7 +233,7 @@ static void vbi_buffer_release(struct videobuf_queue *q, struct videobuf_buffer bttv_dma_free(q,fh->btv,buf); } -struct videobuf_queue_ops bttv_vbi_qops = { +const struct videobuf_queue_ops bttv_vbi_qops = { .buf_setup = vbi_buffer_setup, .buf_prepare = vbi_buffer_prepare, .buf_queue = vbi_buffer_queue, diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index 9efc4559fa8e..853cbb2f24a4 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -281,7 +281,7 @@ int bttv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); int bttv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); int bttv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f); -extern struct videobuf_queue_ops bttv_vbi_qops; +extern const struct videobuf_queue_ops bttv_vbi_qops; /* ---------------------------------------------------------- */ /* bttv-gpio.c */ -- cgit v1.2.3 From 9676593c9060d011aa97f7ab3d2d63a1bf1c01df Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Wed, 27 Sep 2017 16:16:47 +0200 Subject: media: zoran: make zoran_template const Make this const as it is only used in a copy operation in the file referencing it. Make the declaration const too. Done using Coccinelle. Signed-off-by: Bhumika Goyal Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/zoran/zoran_card.h | 2 +- drivers/media/pci/zoran/zoran_driver.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/pci/zoran/zoran_card.h b/drivers/media/pci/zoran/zoran_card.h index 81cba177cd90..0cdb7d34926d 100644 --- a/drivers/media/pci/zoran/zoran_card.h +++ b/drivers/media/pci/zoran/zoran_card.h @@ -37,7 +37,7 @@ extern int zr36067_debug; /* Anybody who uses more than four? */ #define BUZ_MAX 4 -extern struct video_device zoran_template; +extern const struct video_device zoran_template; extern int zoran_check_jpg_settings(struct zoran *zr, struct zoran_jpg_settings *settings, diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c index a11cb501c550..d07840072337 100644 --- a/drivers/media/pci/zoran/zoran_driver.c +++ b/drivers/media/pci/zoran/zoran_driver.c @@ -2839,7 +2839,7 @@ static const struct v4l2_file_operations zoran_fops = { .poll = zoran_poll, }; -struct video_device zoran_template = { +const struct video_device zoran_template = { .name = ZORAN_NAME, .fops = &zoran_fops, .ioctl_ops = &zoran_ioctl_ops, -- cgit v1.2.3 From 0e2d9a9d4aa55dc2d650f9c07069a0b149f02d04 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Wed, 27 Sep 2017 18:59:06 +0200 Subject: media: cx23885/saa7134: make vb2_ops const Make vb2_ops const as they are only stored in the const field of a vb2_queue structure. Make the declarations const too. Done using Coccinelle. Signed-off-by: Bhumika Goyal Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-vbi.c | 2 +- drivers/media/pci/cx23885/cx23885.h | 2 +- drivers/media/pci/saa7134/saa7134-vbi.c | 2 +- drivers/media/pci/saa7134/saa7134.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c index 369e545cac04..70f9f13bded3 100644 --- a/drivers/media/pci/cx23885/cx23885-vbi.c +++ b/drivers/media/pci/cx23885/cx23885-vbi.c @@ -254,7 +254,7 @@ static void cx23885_stop_streaming(struct vb2_queue *q) } -struct vb2_ops cx23885_vbi_qops = { +const struct vb2_ops cx23885_vbi_qops = { .queue_setup = queue_setup, .buf_prepare = buffer_prepare, .buf_finish = buffer_finish, diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index cb714ab60d69..6aab713e0476 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -591,7 +591,7 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm); extern int cx23885_vbi_fmt(struct file *file, void *priv, struct v4l2_format *f); extern void cx23885_vbi_timeout(unsigned long data); -extern struct vb2_ops cx23885_vbi_qops; +extern const struct vb2_ops cx23885_vbi_qops; extern int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status); /* cx23885-i2c.c */ diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c index bcad9b2d9bb3..07a397bb775d 100644 --- a/drivers/media/pci/saa7134/saa7134-vbi.c +++ b/drivers/media/pci/saa7134/saa7134-vbi.c @@ -165,7 +165,7 @@ static int buffer_init(struct vb2_buffer *vb2) return 0; } -struct vb2_ops saa7134_vbi_qops = { +const struct vb2_ops saa7134_vbi_qops = { .queue_setup = queue_setup, .buf_init = buffer_init, .buf_prepare = buffer_prepare, diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h index 816b5282d671..545f7ad8b16d 100644 --- a/drivers/media/pci/saa7134/saa7134.h +++ b/drivers/media/pci/saa7134/saa7134.h @@ -870,7 +870,7 @@ int saa7134_ts_stop(struct saa7134_dev *dev); /* ----------------------------------------------------------- */ /* saa7134-vbi.c */ -extern struct vb2_ops saa7134_vbi_qops; +extern const struct vb2_ops saa7134_vbi_qops; extern struct video_device saa7134_vbi_template; int saa7134_vbi_init1(struct saa7134_dev *dev); -- cgit v1.2.3 From ac71484e89461a22d89ac84fcdc0235bf0a3e011 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Wed, 27 Sep 2017 19:08:19 +0200 Subject: media: au0828/em28xx: make vb2_ops const Make vb2_ops const as they are only stored in the const field of a vb2_queue structure. Make the declarations const too. Done using Coccinelle. Signed-off-by: Bhumika Goyal Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-vbi.c | 2 +- drivers/media/usb/au0828/au0828.h | 2 +- drivers/media/usb/em28xx/em28xx-v4l.h | 2 +- drivers/media/usb/em28xx/em28xx-vbi.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-vbi.c b/drivers/media/usb/au0828/au0828-vbi.c index e0930ce59b8d..9dd6bdb7304f 100644 --- a/drivers/media/usb/au0828/au0828-vbi.c +++ b/drivers/media/usb/au0828/au0828-vbi.c @@ -79,7 +79,7 @@ vbi_buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&dev->slock, flags); } -struct vb2_ops au0828_vbi_qops = { +const struct vb2_ops au0828_vbi_qops = { .queue_setup = vbi_queue_setup, .buf_prepare = vbi_buffer_prepare, .buf_queue = vbi_buffer_queue, diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index 05e445fe0b77..f6f37e8ef51d 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -358,7 +358,7 @@ void au0828_dvb_suspend(struct au0828_dev *dev); void au0828_dvb_resume(struct au0828_dev *dev); /* au0828-vbi.c */ -extern struct vb2_ops au0828_vbi_qops; +extern const struct vb2_ops au0828_vbi_qops; #define dprintk(level, fmt, arg...)\ do { if (au0828_debug & level)\ diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h index 8dfcb56bf4b3..9c411aac3878 100644 --- a/drivers/media/usb/em28xx/em28xx-v4l.h +++ b/drivers/media/usb/em28xx/em28xx-v4l.h @@ -16,4 +16,4 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count); void em28xx_stop_vbi_streaming(struct vb2_queue *vq); -extern struct vb2_ops em28xx_vbi_qops; +extern const struct vb2_ops em28xx_vbi_qops; diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c index 0bac552bbe87..f5123651ef30 100644 --- a/drivers/media/usb/em28xx/em28xx-vbi.c +++ b/drivers/media/usb/em28xx/em28xx-vbi.c @@ -93,7 +93,7 @@ vbi_buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&dev->slock, flags); } -struct vb2_ops em28xx_vbi_qops = { +const struct vb2_ops em28xx_vbi_qops = { .queue_setup = vbi_queue_setup, .buf_prepare = vbi_buffer_prepare, .buf_queue = vbi_buffer_queue, -- cgit v1.2.3 From 7996e5c47fc01ca4bd94b40ba4585054f1d69b0e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 28 Sep 2017 15:03:54 +0200 Subject: media: tc358743: remove an unneeded condition We can remove the check for if "state->cec_adap" is NULL. The cec_allocate_adapter() function never returns NULL and also we verified that "state->cec_adap" is an error pointer. Signed-off-by: Dan Carpenter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358743.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 6c59a460647f..cd995e6a98ef 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -2122,7 +2122,7 @@ static int tc358743_probe(struct i2c_client *client, state, dev_name(&client->dev), CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL, CEC_MAX_LOG_ADDRS); if (IS_ERR(state->cec_adap)) { - err = state->cec_adap ? PTR_ERR(state->cec_adap) : -ENOMEM; + err = PTR_ERR(state->cec_adap); goto err_hdl; } irq_mask |= MASK_CEC_RMSK | MASK_CEC_TMSK; -- cgit v1.2.3 From f9cc48f1b1df312788312cff4b32267e4344ef61 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Tue, 19 Sep 2017 01:08:16 +0200 Subject: media: imx: Fix VDIC CSI1 selection When using VDIC with CSI1, make sure to select the correct CSI in IPU_CONF. Fixes: f0d9c8924e2c3376 ("[media] media: imx: Add IC subdev drivers") Suggested-by: Marek Vasut Signed-off-by: Tim Harvey Acked-by: Steve Longerbeam Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/imx/imx-ic-prp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/imx/imx-ic-prp.c b/drivers/staging/media/imx/imx-ic-prp.c index c2bb5ef2acb4..9e41987f9884 100644 --- a/drivers/staging/media/imx/imx-ic-prp.c +++ b/drivers/staging/media/imx/imx-ic-prp.c @@ -320,9 +320,10 @@ static int prp_link_validate(struct v4l2_subdev *sd, * the ->PRPENC link cannot be enabled if the source * is the VDIC */ - if (priv->sink_sd_prpenc) + if (priv->sink_sd_prpenc) { ret = -EINVAL; - goto out; + goto out; + } } else { /* the source is a CSI */ if (!csi) { -- cgit v1.2.3 From f7480ad0d458b74a9a1a882b56917e4695ffed1f Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 21 Sep 2017 17:32:11 +0200 Subject: media: tc358743: set entity function to video interface bridge The TC358743 is an HDMI to MIPI CSI2-2 bridge. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358743.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index cd995e6a98ef..0b65096613d9 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -2101,6 +2101,7 @@ static int tc358743_probe(struct i2c_client *client, } state->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; err = media_entity_pads_init(&sd->entity, 1, &state->pad); if (err < 0) goto err_hdl; -- cgit v1.2.3 From b2b60bcc7d0940f02858b1721499df9674f685e5 Mon Sep 17 00:00:00 2001 From: Leon Luo Date: Thu, 5 Oct 2017 02:06:20 +0200 Subject: media: imx274: device tree binding file The binding file for imx274 CMOS sensor V4l2 driver Signed-off-by: Leon Luo Acked-by: Sören Brinkmann Acked-by: Rob Herring Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/i2c/imx274.txt | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/i2c/imx274.txt diff --git a/Documentation/devicetree/bindings/media/i2c/imx274.txt b/Documentation/devicetree/bindings/media/i2c/imx274.txt new file mode 100644 index 000000000000..80f2e89568e1 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/imx274.txt @@ -0,0 +1,33 @@ +* Sony 1/2.5-Inch 8.51Mp CMOS Digital Image Sensor + +The Sony imx274 is a 1/2.5-inch CMOS active pixel digital image sensor with +an active array size of 3864H x 2202V. It is programmable through I2C +interface. The I2C address is fixed to 0x1a as per sensor data sheet. +Image data is sent through MIPI CSI-2, which is configured as 4 lanes +at 1440 Mbps. + + +Required Properties: +- compatible: value should be "sony,imx274" for imx274 sensor +- reg: I2C bus address of the device + +Optional Properties: +- reset-gpios: Sensor reset GPIO + +The imx274 device node should contain one 'port' child node with +an 'endpoint' subnode. For further reading on port node refer to +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + sensor@1a { + compatible = "sony,imx274"; + reg = <0x1a>; + #address-cells = <1>; + #size-cells = <0>; + reset-gpios = <&gpio_sensor 0 0>; + port { + sensor_out: endpoint { + remote-endpoint = <&csiss_in>; + }; + }; + }; -- cgit v1.2.3 From 0985dd306f727df6c0e71cd8a8eda93e8fa5206e Mon Sep 17 00:00:00 2001 From: Leon Luo Date: Thu, 5 Oct 2017 02:06:21 +0200 Subject: media: imx274: V4l2 driver for Sony imx274 CMOS sensor The imx274 is a Sony CMOS image sensor that has 1/2.5 image size. It supports up to 3840x2160 (4K) 60fps, 1080p 120fps. The interface is 4-lane MIPI CSI-2 running at 1.44Gbps each. This driver has been tested on Xilinx ZCU102 platform with a Leopard LI-IMX274MIPI-FMC camera board. Support for the following features: -Resolutions: 3840x2160, 1920x1080, 1280x720 -Frame rate: 3840x2160 : 5 – 60fps 1920x1080 : 5 – 120fps 1280x720 : 5 – 120fps -Exposure time: 16 – (frame interval) micro-seconds -Gain: 1x - 180x -VFLIP: enable/disabledrivers/media/i2c/imx274.c -Test pattern: 12 test patterns Signed-off-by: Leon Luo Tested-by: Sören Brinkmann Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 8 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/imx274.c | 1811 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1820 insertions(+) create mode 100644 drivers/media/i2c/imx274.c diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 47113774a297..3c6d6428f525 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -555,6 +555,14 @@ config VIDEO_APTINA_PLL config VIDEO_SMIAPP_PLL tristate +config VIDEO_IMX274 + tristate "Sony IMX274 sensor support" + depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_CAMERA_SUPPORT + ---help--- + This is a V4L2 sensor-level driver for the Sony IMX274 + CMOS image sensor. + config VIDEO_OV2640 tristate "OmniVision OV2640 sensor support" depends on VIDEO_V4L2 && I2C diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index c843c181dfb9..f8d57e453936 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -92,5 +92,6 @@ obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o obj-$(CONFIG_VIDEO_OV2659) += ov2659.o obj-$(CONFIG_VIDEO_TC358743) += tc358743.o +obj-$(CONFIG_VIDEO_IMX274) += imx274.o obj-$(CONFIG_SDR_MAX2175) += max2175.o diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c new file mode 100644 index 000000000000..ab6a5f31da74 --- /dev/null +++ b/drivers/media/i2c/imx274.c @@ -0,0 +1,1811 @@ +/* + * imx274.c - IMX274 CMOS Image Sensor driver + * + * Copyright (C) 2017, Leopard Imaging, Inc. + * + * Leon Luo + * Edwin Zou + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * See "SHR, SVR Setting" in datasheet + */ +#define IMX274_DEFAULT_FRAME_LENGTH (4550) +#define IMX274_MAX_FRAME_LENGTH (0x000fffff) + +/* + * See "Frame Rate Adjustment" in datasheet + */ +#define IMX274_PIXCLK_CONST1 (72000000) +#define IMX274_PIXCLK_CONST2 (1000000) + +/* + * The input gain is shifted by IMX274_GAIN_SHIFT to get + * decimal number. The real gain is + * (float)input_gain_value / (1 << IMX274_GAIN_SHIFT) + */ +#define IMX274_GAIN_SHIFT (8) +#define IMX274_GAIN_SHIFT_MASK ((1 << IMX274_GAIN_SHIFT) - 1) + +/* + * See "Analog Gain" and "Digital Gain" in datasheet + * min gain is 1X + * max gain is calculated based on IMX274_GAIN_REG_MAX + */ +#define IMX274_GAIN_REG_MAX (1957) +#define IMX274_MIN_GAIN (0x01 << IMX274_GAIN_SHIFT) +#define IMX274_MAX_ANALOG_GAIN ((2048 << IMX274_GAIN_SHIFT)\ + / (2048 - IMX274_GAIN_REG_MAX)) +#define IMX274_MAX_DIGITAL_GAIN (8) +#define IMX274_DEF_GAIN (20 << IMX274_GAIN_SHIFT) +#define IMX274_GAIN_CONST (2048) /* for gain formula */ + +/* + * 1 line time in us = (HMAX / 72), minimal is 4 lines + */ +#define IMX274_MIN_EXPOSURE_TIME (4 * 260 / 72) + +#define IMX274_DEFAULT_MODE IMX274_MODE_3840X2160 +#define IMX274_MAX_WIDTH (3840) +#define IMX274_MAX_HEIGHT (2160) +#define IMX274_MAX_FRAME_RATE (120) +#define IMX274_MIN_FRAME_RATE (5) +#define IMX274_DEF_FRAME_RATE (60) + +/* + * register SHR is limited to (SVR value + 1) x VMAX value - 4 + */ +#define IMX274_SHR_LIMIT_CONST (4) + +/* + * Constants for sensor reset delay + */ +#define IMX274_RESET_DELAY1 (2000) +#define IMX274_RESET_DELAY2 (2200) + +/* + * shift and mask constants + */ +#define IMX274_SHIFT_8_BITS (8) +#define IMX274_SHIFT_16_BITS (16) +#define IMX274_MASK_LSB_2_BITS (0x03) +#define IMX274_MASK_LSB_3_BITS (0x07) +#define IMX274_MASK_LSB_4_BITS (0x0f) +#define IMX274_MASK_LSB_8_BITS (0x00ff) + +#define DRIVER_NAME "IMX274" + +/* + * IMX274 register definitions + */ +#define IMX274_FRAME_LENGTH_ADDR_1 0x30FA /* VMAX, MSB */ +#define IMX274_FRAME_LENGTH_ADDR_2 0x30F9 /* VMAX */ +#define IMX274_FRAME_LENGTH_ADDR_3 0x30F8 /* VMAX, LSB */ +#define IMX274_SVR_REG_MSB 0x300F /* SVR */ +#define IMX274_SVR_REG_LSB 0x300E /* SVR */ +#define IMX274_HMAX_REG_MSB 0x30F7 /* HMAX */ +#define IMX274_HMAX_REG_LSB 0x30F6 /* HMAX */ +#define IMX274_COARSE_TIME_ADDR_MSB 0x300D /* SHR */ +#define IMX274_COARSE_TIME_ADDR_LSB 0x300C /* SHR */ +#define IMX274_ANALOG_GAIN_ADDR_LSB 0x300A /* ANALOG GAIN LSB */ +#define IMX274_ANALOG_GAIN_ADDR_MSB 0x300B /* ANALOG GAIN MSB */ +#define IMX274_DIGITAL_GAIN_REG 0x3012 /* Digital Gain */ +#define IMX274_VFLIP_REG 0x301A /* VERTICAL FLIP */ +#define IMX274_TEST_PATTERN_REG 0x303D /* TEST PATTERN */ +#define IMX274_STANDBY_REG 0x3000 /* STANDBY */ + +#define IMX274_TABLE_WAIT_MS 0 +#define IMX274_TABLE_END 1 + +/* + * imx274 I2C operation related structure + */ +struct reg_8 { + u16 addr; + u8 val; +}; + +static const struct regmap_config imx274_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, +}; + +enum imx274_mode { + IMX274_MODE_3840X2160, + IMX274_MODE_1920X1080, + IMX274_MODE_1280X720, + + IMX274_MODE_START_STREAM_1, + IMX274_MODE_START_STREAM_2, + IMX274_MODE_START_STREAM_3, + IMX274_MODE_START_STREAM_4, + IMX274_MODE_STOP_STREAM +}; + +/* + * imx274 format related structure + */ +struct imx274_frmfmt { + u32 mbus_code; + enum v4l2_colorspace colorspace; + struct v4l2_frmsize_discrete size; + enum imx274_mode mode; +}; + +/* + * imx274 test pattern related structure + */ +enum { + TEST_PATTERN_DISABLED = 0, + TEST_PATTERN_ALL_000H, + TEST_PATTERN_ALL_FFFH, + TEST_PATTERN_ALL_555H, + TEST_PATTERN_ALL_AAAH, + TEST_PATTERN_VSP_5AH, /* VERTICAL STRIPE PATTERN 555H/AAAH */ + TEST_PATTERN_VSP_A5H, /* VERTICAL STRIPE PATTERN AAAH/555H */ + TEST_PATTERN_VSP_05H, /* VERTICAL STRIPE PATTERN 000H/555H */ + TEST_PATTERN_VSP_50H, /* VERTICAL STRIPE PATTERN 555H/000H */ + TEST_PATTERN_VSP_0FH, /* VERTICAL STRIPE PATTERN 000H/FFFH */ + TEST_PATTERN_VSP_F0H, /* VERTICAL STRIPE PATTERN FFFH/000H */ + TEST_PATTERN_H_COLOR_BARS, + TEST_PATTERN_V_COLOR_BARS, +}; + +static const char * const tp_qmenu[] = { + "Disabled", + "All 000h Pattern", + "All FFFh Pattern", + "All 555h Pattern", + "All AAAh Pattern", + "Vertical Stripe (555h / AAAh)", + "Vertical Stripe (AAAh / 555h)", + "Vertical Stripe (000h / 555h)", + "Vertical Stripe (555h / 000h)", + "Vertical Stripe (000h / FFFh)", + "Vertical Stripe (FFFh / 000h)", + "Horizontal Color Bars", + "Vertical Color Bars", +}; + +/* + * All-pixel scan mode (10-bit) + * imx274 mode1(refer to datasheet) register configuration with + * 3840x2160 resolution, raw10 data and mipi four lane output + */ +static const struct reg_8 imx274_mode1_3840x2160_raw10[] = { + {0x3004, 0x01}, + {0x3005, 0x01}, + {0x3006, 0x00}, + {0x3007, 0x02}, + + {0x3018, 0xA2}, /* output XVS, HVS */ + + {0x306B, 0x05}, + {0x30E2, 0x01}, + {0x30F6, 0x07}, /* HMAX, 263 */ + {0x30F7, 0x01}, /* HMAX */ + + {0x30dd, 0x01}, /* crop to 2160 */ + {0x30de, 0x06}, + {0x30df, 0x00}, + {0x30e0, 0x12}, + {0x30e1, 0x00}, + {0x3037, 0x01}, /* to crop to 3840 */ + {0x3038, 0x0c}, + {0x3039, 0x00}, + {0x303a, 0x0c}, + {0x303b, 0x0f}, + + {0x30EE, 0x01}, + {0x3130, 0x86}, + {0x3131, 0x08}, + {0x3132, 0x7E}, + {0x3133, 0x08}, + {0x3342, 0x0A}, + {0x3343, 0x00}, + {0x3344, 0x16}, + {0x3345, 0x00}, + {0x33A6, 0x01}, + {0x3528, 0x0E}, + {0x3554, 0x1F}, + {0x3555, 0x01}, + {0x3556, 0x01}, + {0x3557, 0x01}, + {0x3558, 0x01}, + {0x3559, 0x00}, + {0x355A, 0x00}, + {0x35BA, 0x0E}, + {0x366A, 0x1B}, + {0x366B, 0x1A}, + {0x366C, 0x19}, + {0x366D, 0x17}, + {0x3A41, 0x08}, + + {IMX274_TABLE_END, 0x00} +}; + +/* + * Horizontal/vertical 2/2-line binning + * (Horizontal and vertical weightedbinning, 10-bit) + * imx274 mode3(refer to datasheet) register configuration with + * 1920x1080 resolution, raw10 data and mipi four lane output + */ +static const struct reg_8 imx274_mode3_1920x1080_raw10[] = { + {0x3004, 0x02}, + {0x3005, 0x21}, + {0x3006, 0x00}, + {0x3007, 0x11}, + + {0x3018, 0xA2}, /* output XVS, HVS */ + + {0x306B, 0x05}, + {0x30E2, 0x02}, + + {0x30F6, 0x04}, /* HMAX, 260 */ + {0x30F7, 0x01}, /* HMAX */ + + {0x30dd, 0x01}, /* to crop to 1920x1080 */ + {0x30de, 0x05}, + {0x30df, 0x00}, + {0x30e0, 0x04}, + {0x30e1, 0x00}, + {0x3037, 0x01}, + {0x3038, 0x0c}, + {0x3039, 0x00}, + {0x303a, 0x0c}, + {0x303b, 0x0f}, + + {0x30EE, 0x01}, + {0x3130, 0x4E}, + {0x3131, 0x04}, + {0x3132, 0x46}, + {0x3133, 0x04}, + {0x3342, 0x0A}, + {0x3343, 0x00}, + {0x3344, 0x1A}, + {0x3345, 0x00}, + {0x33A6, 0x01}, + {0x3528, 0x0E}, + {0x3554, 0x00}, + {0x3555, 0x01}, + {0x3556, 0x01}, + {0x3557, 0x01}, + {0x3558, 0x01}, + {0x3559, 0x00}, + {0x355A, 0x00}, + {0x35BA, 0x0E}, + {0x366A, 0x1B}, + {0x366B, 0x1A}, + {0x366C, 0x19}, + {0x366D, 0x17}, + {0x3A41, 0x08}, + + {IMX274_TABLE_END, 0x00} +}; + +/* + * Vertical 2/3 subsampling binning horizontal 3 binning + * imx274 mode5(refer to datasheet) register configuration with + * 1280x720 resolution, raw10 data and mipi four lane output + */ +static const struct reg_8 imx274_mode5_1280x720_raw10[] = { + {0x3004, 0x03}, + {0x3005, 0x31}, + {0x3006, 0x00}, + {0x3007, 0x09}, + + {0x3018, 0xA2}, /* output XVS, HVS */ + + {0x306B, 0x05}, + {0x30E2, 0x03}, + + {0x30F6, 0x04}, /* HMAX, 260 */ + {0x30F7, 0x01}, /* HMAX */ + + {0x30DD, 0x01}, + {0x30DE, 0x07}, + {0x30DF, 0x00}, + {0x40E0, 0x04}, + {0x30E1, 0x00}, + {0x3030, 0xD4}, + {0x3031, 0x02}, + {0x3032, 0xD0}, + {0x3033, 0x02}, + + {0x30EE, 0x01}, + {0x3130, 0xE2}, + {0x3131, 0x02}, + {0x3132, 0xDE}, + {0x3133, 0x02}, + {0x3342, 0x0A}, + {0x3343, 0x00}, + {0x3344, 0x1B}, + {0x3345, 0x00}, + {0x33A6, 0x01}, + {0x3528, 0x0E}, + {0x3554, 0x00}, + {0x3555, 0x01}, + {0x3556, 0x01}, + {0x3557, 0x01}, + {0x3558, 0x01}, + {0x3559, 0x00}, + {0x355A, 0x00}, + {0x35BA, 0x0E}, + {0x366A, 0x1B}, + {0x366B, 0x19}, + {0x366C, 0x17}, + {0x366D, 0x17}, + {0x3A41, 0x04}, + + {IMX274_TABLE_END, 0x00} +}; + +/* + * imx274 first step register configuration for + * starting stream + */ +static const struct reg_8 imx274_start_1[] = { + {IMX274_STANDBY_REG, 0x12}, + {IMX274_TABLE_END, 0x00} +}; + +/* + * imx274 second step register configuration for + * starting stream + */ +static const struct reg_8 imx274_start_2[] = { + {0x3120, 0xF0}, /* clock settings */ + {0x3121, 0x00}, /* clock settings */ + {0x3122, 0x02}, /* clock settings */ + {0x3129, 0x9C}, /* clock settings */ + {0x312A, 0x02}, /* clock settings */ + {0x312D, 0x02}, /* clock settings */ + + {0x310B, 0x00}, + + /* PLSTMG */ + {0x304C, 0x00}, /* PLSTMG01 */ + {0x304D, 0x03}, + {0x331C, 0x1A}, + {0x331D, 0x00}, + {0x3502, 0x02}, + {0x3529, 0x0E}, + {0x352A, 0x0E}, + {0x352B, 0x0E}, + {0x3538, 0x0E}, + {0x3539, 0x0E}, + {0x3553, 0x00}, + {0x357D, 0x05}, + {0x357F, 0x05}, + {0x3581, 0x04}, + {0x3583, 0x76}, + {0x3587, 0x01}, + {0x35BB, 0x0E}, + {0x35BC, 0x0E}, + {0x35BD, 0x0E}, + {0x35BE, 0x0E}, + {0x35BF, 0x0E}, + {0x366E, 0x00}, + {0x366F, 0x00}, + {0x3670, 0x00}, + {0x3671, 0x00}, + + /* PSMIPI */ + {0x3304, 0x32}, /* PSMIPI1 */ + {0x3305, 0x00}, + {0x3306, 0x32}, + {0x3307, 0x00}, + {0x3590, 0x32}, + {0x3591, 0x00}, + {0x3686, 0x32}, + {0x3687, 0x00}, + + {IMX274_TABLE_END, 0x00} +}; + +/* + * imx274 third step register configuration for + * starting stream + */ +static const struct reg_8 imx274_start_3[] = { + {IMX274_STANDBY_REG, 0x00}, + {0x303E, 0x02}, /* SYS_MODE = 2 */ + {IMX274_TABLE_END, 0x00} +}; + +/* + * imx274 forth step register configuration for + * starting stream + */ +static const struct reg_8 imx274_start_4[] = { + {0x30F4, 0x00}, + {0x3018, 0xA2}, /* XHS VHS OUTUPT */ + {IMX274_TABLE_END, 0x00} +}; + +/* + * imx274 register configuration for stoping stream + */ +static const struct reg_8 imx274_stop[] = { + {IMX274_STANDBY_REG, 0x01}, + {IMX274_TABLE_END, 0x00} +}; + +/* + * imx274 disable test pattern register configuration + */ +static const struct reg_8 imx274_tp_disabled[] = { + {0x303C, 0x00}, + {0x377F, 0x00}, + {0x3781, 0x00}, + {0x370B, 0x00}, + {IMX274_TABLE_END, 0x00} +}; + +/* + * imx274 test pattern register configuration + * reg 0x303D defines the test pattern modes + */ +static const struct reg_8 imx274_tp_regs[] = { + {0x303C, 0x11}, + {0x370E, 0x01}, + {0x377F, 0x01}, + {0x3781, 0x01}, + {0x370B, 0x11}, + {IMX274_TABLE_END, 0x00} +}; + +static const struct reg_8 *mode_table[] = { + [IMX274_MODE_3840X2160] = imx274_mode1_3840x2160_raw10, + [IMX274_MODE_1920X1080] = imx274_mode3_1920x1080_raw10, + [IMX274_MODE_1280X720] = imx274_mode5_1280x720_raw10, + + [IMX274_MODE_START_STREAM_1] = imx274_start_1, + [IMX274_MODE_START_STREAM_2] = imx274_start_2, + [IMX274_MODE_START_STREAM_3] = imx274_start_3, + [IMX274_MODE_START_STREAM_4] = imx274_start_4, + [IMX274_MODE_STOP_STREAM] = imx274_stop, +}; + +/* + * imx274 format related structure + */ +static const struct imx274_frmfmt imx274_formats[] = { + {MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_COLORSPACE_SRGB, {3840, 2160}, + IMX274_MODE_3840X2160}, + {MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_COLORSPACE_SRGB, {1920, 1080}, + IMX274_MODE_1920X1080}, + {MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_COLORSPACE_SRGB, {1280, 720}, + IMX274_MODE_1280X720}, +}; + +/* + * minimal frame length for each mode + * refer to datasheet section "Frame Rate Adjustment (CSI-2)" + */ +static const int min_frame_len[] = { + 4550, /* mode 1, 4K */ + 2310, /* mode 3, 1080p */ + 2310 /* mode 5, 720p */ +}; + +/* + * minimal numbers of SHR register + * refer to datasheet table "Shutter Setting (CSI-2)" + */ +static const int min_SHR[] = { + 12, /* mode 1, 4K */ + 8, /* mode 3, 1080p */ + 8 /* mode 5, 720p */ +}; + +static const int max_frame_rate[] = { + 60, /* mode 1 , 4K */ + 120, /* mode 3, 1080p */ + 120 /* mode 5, 720p */ +}; + +/* + * Number of clocks per internal offset period + * a constant based on mode + * refer to section "Integration Time in Each Readout Drive Mode (CSI-2)" + * in the datasheet + * for the implemented 3 modes, it happens to be the same number + */ +static const int nocpiop[] = { + 112, /* mode 1 , 4K */ + 112, /* mode 3, 1080p */ + 112 /* mode 5, 720p */ +}; + +/* + * struct imx274_ctrls - imx274 ctrl structure + * @handler: V4L2 ctrl handler structure + * @exposure: Pointer to expsure ctrl structure + * @gain: Pointer to gain ctrl structure + * @vflip: Pointer to vflip ctrl structure + * @test_pattern: Pointer to test pattern ctrl structure + */ +struct imx274_ctrls { + struct v4l2_ctrl_handler handler; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *gain; + struct v4l2_ctrl *vflip; + struct v4l2_ctrl *test_pattern; +}; + +/* + * struct stim274 - imx274 device structure + * @sd: V4L2 subdevice structure + * @pd: Media pad structure + * @client: Pointer to I2C client + * @ctrls: imx274 control structure + * @format: V4L2 media bus frame format structure + * @frame_rate: V4L2 frame rate structure + * @regmap: Pointer to regmap structure + * @reset_gpio: Pointer to reset gpio + * @lock: Mutex structure + * @mode_index: Resolution mode index + */ +struct stimx274 { + struct v4l2_subdev sd; + struct media_pad pad; + struct i2c_client *client; + struct imx274_ctrls ctrls; + struct v4l2_mbus_framefmt format; + struct v4l2_fract frame_interval; + struct regmap *regmap; + struct gpio_desc *reset_gpio; + struct mutex lock; /* mutex lock for operations */ + u32 mode_index; +}; + +/* + * Function declaration + */ +static int imx274_set_gain(struct stimx274 *priv, struct v4l2_ctrl *ctrl); +static int imx274_set_exposure(struct stimx274 *priv, int val); +static int imx274_set_vflip(struct stimx274 *priv, int val); +static int imx274_set_test_pattern(struct stimx274 *priv, int val); +static int imx274_set_frame_interval(struct stimx274 *priv, + struct v4l2_fract frame_interval); + +static inline void msleep_range(unsigned int delay_base) +{ + usleep_range(delay_base * 1000, delay_base * 1000 + 500); +} + +/* + * v4l2_ctrl and v4l2_subdev related operations + */ +static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, + struct stimx274, ctrls.handler)->sd; +} + +static inline struct stimx274 *to_imx274(struct v4l2_subdev *sd) +{ + return container_of(sd, struct stimx274, sd); +} + +/* + * imx274_regmap_util_write_table_8 - Function for writing register table + * @regmap: Pointer to device reg map structure + * @table: Table containing register values + * @wait_ms_addr: Flag for performing delay + * @end_addr: Flag for incating end of table + * + * This is used to write register table into sensor's reg map. + * + * Return: 0 on success, errors otherwise + */ +static int imx274_regmap_util_write_table_8(struct regmap *regmap, + const struct reg_8 table[], + u16 wait_ms_addr, u16 end_addr) +{ + int err; + const struct reg_8 *next; + u8 val; + + int range_start = -1; + int range_count = 0; + u8 range_vals[16]; + int max_range_vals = ARRAY_SIZE(range_vals); + + for (next = table;; next++) { + if ((next->addr != range_start + range_count) || + (next->addr == end_addr) || + (next->addr == wait_ms_addr) || + (range_count == max_range_vals)) { + if (range_count == 1) + err = regmap_write(regmap, + range_start, range_vals[0]); + else if (range_count > 1) + err = regmap_bulk_write(regmap, range_start, + &range_vals[0], + range_count); + + if (err) + return err; + + range_start = -1; + range_count = 0; + + /* Handle special address values */ + if (next->addr == end_addr) + break; + + if (next->addr == wait_ms_addr) { + msleep_range(next->val); + continue; + } + } + + val = next->val; + + if (range_start == -1) + range_start = next->addr; + + range_vals[range_count++] = val; + } + return 0; +} + +static inline int imx274_read_reg(struct stimx274 *priv, u16 addr, u8 *val) +{ + int err; + + err = regmap_read(priv->regmap, addr, (unsigned int *)val); + if (err) + dev_err(&priv->client->dev, + "%s : i2c read failed, addr = %x\n", __func__, addr); + else + dev_dbg(&priv->client->dev, + "%s : addr 0x%x, val=0x%x\n", __func__, + addr, *val); + return err; +} + +static inline int imx274_write_reg(struct stimx274 *priv, u16 addr, u8 val) +{ + int err; + + err = regmap_write(priv->regmap, addr, val); + if (err) + dev_err(&priv->client->dev, + "%s : i2c write failed, %x = %x\n", __func__, + addr, val); + else + dev_dbg(&priv->client->dev, + "%s : addr 0x%x, val=0x%x\n", __func__, + addr, val); + return err; +} + +static int imx274_write_table(struct stimx274 *priv, const struct reg_8 table[]) +{ + return imx274_regmap_util_write_table_8(priv->regmap, + table, IMX274_TABLE_WAIT_MS, IMX274_TABLE_END); +} + +/* + * imx274_mode_regs - Function for set mode registers per mode index + * @priv: Pointer to device structure + * @mode: Mode index value + * + * This is used to start steam per mode index. + * mode = 0, start stream for sensor Mode 1: 4K/raw10 + * mode = 1, start stream for sensor Mode 3: 1080p/raw10 + * mode = 2, start stream for sensor Mode 5: 720p/raw10 + * + * Return: 0 on success, errors otherwise + */ +static int imx274_mode_regs(struct stimx274 *priv, int mode) +{ + int err = 0; + + err = imx274_write_table(priv, mode_table[IMX274_MODE_START_STREAM_1]); + if (err) + return err; + + err = imx274_write_table(priv, mode_table[IMX274_MODE_START_STREAM_2]); + if (err) + return err; + + err = imx274_write_table(priv, mode_table[mode]); + + return err; +} + +/* + * imx274_start_stream - Function for starting stream per mode index + * @priv: Pointer to device structure + * + * Return: 0 on success, errors otherwise + */ +static int imx274_start_stream(struct stimx274 *priv) +{ + int err = 0; + + /* + * Refer to "Standby Cancel Sequence when using CSI-2" in + * imx274 datasheet, it should wait 10ms or more here. + * give it 1 extra ms for margin + */ + msleep_range(11); + err = imx274_write_table(priv, mode_table[IMX274_MODE_START_STREAM_3]); + if (err) + return err; + + /* + * Refer to "Standby Cancel Sequence when using CSI-2" in + * imx274 datasheet, it should wait 7ms or more here. + * give it 1 extra ms for margin + */ + msleep_range(8); + err = imx274_write_table(priv, mode_table[IMX274_MODE_START_STREAM_4]); + if (err) + return err; + + return 0; +} + +/* + * imx274_reset - Function called to reset the sensor + * @priv: Pointer to device structure + * @rst: Input value for determining the sensor's end state after reset + * + * Set the senor in reset and then + * if rst = 0, keep it in reset; + * if rst = 1, bring it out of reset. + * + */ +static void imx274_reset(struct stimx274 *priv, int rst) +{ + gpiod_set_value_cansleep(priv->reset_gpio, 0); + usleep_range(IMX274_RESET_DELAY1, IMX274_RESET_DELAY2); + gpiod_set_value_cansleep(priv->reset_gpio, !!rst); + usleep_range(IMX274_RESET_DELAY1, IMX274_RESET_DELAY2); +} + +/** + * imx274_s_ctrl - This is used to set the imx274 V4L2 controls + * @ctrl: V4L2 control to be set + * + * This function is used to set the V4L2 controls for the imx274 sensor. + * + * Return: 0 on success, errors otherwise + */ +static int imx274_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = ctrl_to_sd(ctrl); + struct stimx274 *imx274 = to_imx274(sd); + int ret = -EINVAL; + + dev_dbg(&imx274->client->dev, + "%s : s_ctrl: %s, value: %d\n", __func__, + ctrl->name, ctrl->val); + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + dev_dbg(&imx274->client->dev, + "%s : set V4L2_CID_EXPOSURE\n", __func__); + ret = imx274_set_exposure(imx274, ctrl->val); + break; + + case V4L2_CID_GAIN: + dev_dbg(&imx274->client->dev, + "%s : set V4L2_CID_GAIN\n", __func__); + ret = imx274_set_gain(imx274, ctrl); + break; + + case V4L2_CID_VFLIP: + dev_dbg(&imx274->client->dev, + "%s : set V4L2_CID_VFLIP\n", __func__); + ret = imx274_set_vflip(imx274, ctrl->val); + break; + + case V4L2_CID_TEST_PATTERN: + dev_dbg(&imx274->client->dev, + "%s : set V4L2_CID_TEST_PATTERN\n", __func__); + ret = imx274_set_test_pattern(imx274, ctrl->val); + break; + } + + return ret; +} + +/** + * imx274_get_fmt - Get the pad format + * @sd: Pointer to V4L2 Sub device structure + * @cfg: Pointer to sub device pad information structure + * @fmt: Pointer to pad level media bus format + * + * This function is used to get the pad format information. + * + * Return: 0 on success + */ +static int imx274_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct stimx274 *imx274 = to_imx274(sd); + + mutex_lock(&imx274->lock); + fmt->format = imx274->format; + mutex_unlock(&imx274->lock); + return 0; +} + +/** + * imx274_set_fmt - This is used to set the pad format + * @sd: Pointer to V4L2 Sub device structure + * @cfg: Pointer to sub device pad information structure + * @format: Pointer to pad level media bus format + * + * This function is used to set the pad format. + * + * Return: 0 on success + */ +static int imx274_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt = &format->format; + struct stimx274 *imx274 = to_imx274(sd); + struct i2c_client *client = imx274->client; + int index; + + dev_dbg(&client->dev, + "%s: width = %d height = %d code = %d mbus_code = %d\n", + __func__, fmt->width, fmt->height, fmt->code, + imx274_formats[imx274->mode_index].mbus_code); + + mutex_lock(&imx274->lock); + + for (index = 0; index < ARRAY_SIZE(imx274_formats); index++) { + if (imx274_formats[index].size.width == fmt->width && + imx274_formats[index].size.height == fmt->height) + break; + } + + if (index >= ARRAY_SIZE(imx274_formats)) { + /* default to first format */ + index = 0; + } + + imx274->mode_index = index; + + if (fmt->width > IMX274_MAX_WIDTH) + fmt->width = IMX274_MAX_WIDTH; + if (fmt->height > IMX274_MAX_HEIGHT) + fmt->height = IMX274_MAX_HEIGHT; + fmt->width = fmt->width & (~IMX274_MASK_LSB_2_BITS); + fmt->height = fmt->height & (~IMX274_MASK_LSB_2_BITS); + fmt->field = V4L2_FIELD_NONE; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + cfg->try_fmt = *fmt; + else + imx274->format = *fmt; + + mutex_unlock(&imx274->lock); + return 0; +} + +/** + * imx274_g_frame_interval - Get the frame interval + * @sd: Pointer to V4L2 Sub device structure + * @fi: Pointer to V4l2 Sub device frame interval structure + * + * This function is used to get the frame interval. + * + * Return: 0 on success + */ +static int imx274_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + struct stimx274 *imx274 = to_imx274(sd); + + fi->interval = imx274->frame_interval; + dev_dbg(&imx274->client->dev, "%s frame rate = %d / %d\n", + __func__, imx274->frame_interval.numerator, + imx274->frame_interval.denominator); + + return 0; +} + +/** + * imx274_s_frame_interval - Set the frame interval + * @sd: Pointer to V4L2 Sub device structure + * @fi: Pointer to V4l2 Sub device frame interval structure + * + * This function is used to set the frame intervavl. + * + * Return: 0 on success + */ +static int imx274_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + struct stimx274 *imx274 = to_imx274(sd); + struct v4l2_ctrl *ctrl = imx274->ctrls.exposure; + int min, max, def; + int ret; + + mutex_lock(&imx274->lock); + ret = imx274_set_frame_interval(imx274, fi->interval); + + if (!ret) { + /* + * exposure time range is decided by frame interval + * need to update it after frame interal changes + */ + min = IMX274_MIN_EXPOSURE_TIME; + max = fi->interval.numerator * 1000000 + / fi->interval.denominator; + def = max; + if (__v4l2_ctrl_modify_range(ctrl, min, max, 1, def)) { + dev_err(&imx274->client->dev, + "Exposure ctrl range update failed\n"); + goto unlock; + } + + /* update exposure time accordingly */ + imx274_set_exposure(imx274, imx274->ctrls.exposure->val); + + dev_dbg(&imx274->client->dev, "set frame interval to %uus\n", + fi->interval.numerator * 1000000 + / fi->interval.denominator); + } + +unlock: + mutex_unlock(&imx274->lock); + + return ret; +} + +/** + * imx274_load_default - load default control values + * @priv: Pointer to device structure + * + * Return: 0 on success, errors otherwise + */ +static int imx274_load_default(struct stimx274 *priv) +{ + int ret; + + /* load default control values */ + priv->frame_interval.numerator = 1; + priv->frame_interval.denominator = IMX274_DEF_FRAME_RATE; + priv->ctrls.exposure->val = 1000000 / IMX274_DEF_FRAME_RATE; + priv->ctrls.gain->val = IMX274_DEF_GAIN; + priv->ctrls.vflip->val = 0; + priv->ctrls.test_pattern->val = TEST_PATTERN_DISABLED; + + /* update frame rate */ + ret = imx274_set_frame_interval(priv, + priv->frame_interval); + if (ret) + return ret; + + /* update exposure time */ + ret = v4l2_ctrl_s_ctrl(priv->ctrls.exposure, priv->ctrls.exposure->val); + if (ret) + return ret; + + /* update gain */ + ret = v4l2_ctrl_s_ctrl(priv->ctrls.gain, priv->ctrls.gain->val); + if (ret) + return ret; + + /* update vflip */ + ret = v4l2_ctrl_s_ctrl(priv->ctrls.vflip, priv->ctrls.vflip->val); + if (ret) + return ret; + + return 0; +} + +/** + * imx274_s_stream - It is used to start/stop the streaming. + * @sd: V4L2 Sub device + * @on: Flag (True / False) + * + * This function controls the start or stop of streaming for the + * imx274 sensor. + * + * Return: 0 on success, errors otherwise + */ +static int imx274_s_stream(struct v4l2_subdev *sd, int on) +{ + struct stimx274 *imx274 = to_imx274(sd); + int ret = 0; + + dev_dbg(&imx274->client->dev, "%s : %s, mode index = %d\n", __func__, + on ? "Stream Start" : "Stream Stop", imx274->mode_index); + + mutex_lock(&imx274->lock); + + if (on) { + /* load mode registers */ + imx274_mode_regs(imx274, imx274->mode_index); + if (ret) + goto fail; + + /* + * update frame rate & expsoure. if the last mode is different, + * HMAX could be changed. As the result, frame rate & exposure + * are changed. + * gain is not affected. + */ + ret = imx274_set_frame_interval(imx274, + imx274->frame_interval); + if (ret) + goto fail; + + /* update exposure time */ + ret = __v4l2_ctrl_s_ctrl(imx274->ctrls.exposure, + imx274->ctrls.exposure->val); + if (ret) + goto fail; + + /* start stream */ + ret = imx274_start_stream(imx274); + if (ret) + goto fail; + } else { + /* stop stream */ + ret = imx274_write_table(imx274, + mode_table[IMX274_MODE_STOP_STREAM]); + if (ret) + goto fail; + } + + mutex_unlock(&imx274->lock); + dev_dbg(&imx274->client->dev, + "%s : Done: mode = %d\n", __func__, imx274->mode_index); + return 0; + +fail: + mutex_unlock(&imx274->lock); + dev_err(&imx274->client->dev, "s_stream failed\n"); + return ret; +} + +/* + * imx274_get_frame_length - Function for obtaining current frame length + * @priv: Pointer to device structure + * @val: Pointer to obainted value + * + * frame_length = vmax x (svr + 1), in unit of hmax. + * + * Return: 0 on success + */ +static int imx274_get_frame_length(struct stimx274 *priv, u32 *val) +{ + int err; + u16 svr; + u32 vmax; + u8 reg_val[3]; + + /* svr */ + err = imx274_read_reg(priv, IMX274_SVR_REG_LSB, ®_val[0]); + if (err) + goto fail; + + err = imx274_read_reg(priv, IMX274_SVR_REG_MSB, ®_val[1]); + if (err) + goto fail; + + svr = (reg_val[1] << IMX274_SHIFT_8_BITS) + reg_val[0]; + + /* vmax */ + err = imx274_read_reg(priv, IMX274_FRAME_LENGTH_ADDR_3, ®_val[0]); + if (err) + goto fail; + + err = imx274_read_reg(priv, IMX274_FRAME_LENGTH_ADDR_2, ®_val[1]); + if (err) + goto fail; + + err = imx274_read_reg(priv, IMX274_FRAME_LENGTH_ADDR_1, ®_val[2]); + if (err) + goto fail; + + vmax = ((reg_val[2] & IMX274_MASK_LSB_3_BITS) << IMX274_SHIFT_16_BITS) + + (reg_val[1] << IMX274_SHIFT_8_BITS) + reg_val[0]; + + *val = vmax * (svr + 1); + + return 0; + +fail: + dev_err(&priv->client->dev, "%s error = %d\n", __func__, err); + return err; +} + +static int imx274_clamp_coarse_time(struct stimx274 *priv, u32 *val, + u32 *frame_length) +{ + int err; + + err = imx274_get_frame_length(priv, frame_length); + if (err) + return err; + + if (*frame_length < min_frame_len[priv->mode_index]) + *frame_length = min_frame_len[priv->mode_index]; + + *val = *frame_length - *val; /* convert to raw shr */ + if (*val > *frame_length - IMX274_SHR_LIMIT_CONST) + *val = *frame_length - IMX274_SHR_LIMIT_CONST; + else if (*val < min_SHR[priv->mode_index]) + *val = min_SHR[priv->mode_index]; + + return 0; +} + +/* + * imx274_set_digital gain - Function called when setting digital gain + * @priv: Pointer to device structure + * @dgain: Value of digital gain. + * + * Digital gain has only 4 steps: 1x, 2x, 4x, and 8x + * + * Return: 0 on success + */ +static int imx274_set_digital_gain(struct stimx274 *priv, u32 dgain) +{ + u8 reg_val; + + reg_val = ffs(dgain); + + if (reg_val) + reg_val--; + + reg_val = clamp(reg_val, (u8)0, (u8)3); + + return imx274_write_reg(priv, IMX274_DIGITAL_GAIN_REG, + reg_val & IMX274_MASK_LSB_4_BITS); +} + +static inline void imx274_calculate_gain_regs(struct reg_8 regs[2], u16 gain) +{ + regs->addr = IMX274_ANALOG_GAIN_ADDR_MSB; + regs->val = (gain >> IMX274_SHIFT_8_BITS) & IMX274_MASK_LSB_3_BITS; + + (regs + 1)->addr = IMX274_ANALOG_GAIN_ADDR_LSB; + (regs + 1)->val = (gain) & IMX274_MASK_LSB_8_BITS; +} + +/* + * imx274_set_gain - Function called when setting gain + * @priv: Pointer to device structure + * @val: Value of gain. the real value = val << IMX274_GAIN_SHIFT; + * @ctrl: v4l2 control pointer + * + * Set the gain based on input value. + * The caller should hold the mutex lock imx274->lock if necessary + * + * Return: 0 on success + */ +static int imx274_set_gain(struct stimx274 *priv, struct v4l2_ctrl *ctrl) +{ + struct reg_8 reg_list[2]; + int err; + u32 gain, analog_gain, digital_gain, gain_reg; + int i; + + gain = (u32)(ctrl->val); + + dev_dbg(&priv->client->dev, + "%s : input gain = %d.%d\n", __func__, + gain >> IMX274_GAIN_SHIFT, + ((gain & IMX274_GAIN_SHIFT_MASK) * 100) >> IMX274_GAIN_SHIFT); + + if (gain > IMX274_MAX_DIGITAL_GAIN * IMX274_MAX_ANALOG_GAIN) + gain = IMX274_MAX_DIGITAL_GAIN * IMX274_MAX_ANALOG_GAIN; + else if (gain < IMX274_MIN_GAIN) + gain = IMX274_MIN_GAIN; + + if (gain <= IMX274_MAX_ANALOG_GAIN) + digital_gain = 1; + else if (gain <= IMX274_MAX_ANALOG_GAIN * 2) + digital_gain = 2; + else if (gain <= IMX274_MAX_ANALOG_GAIN * 4) + digital_gain = 4; + else + digital_gain = IMX274_MAX_DIGITAL_GAIN; + + analog_gain = gain / digital_gain; + + dev_dbg(&priv->client->dev, + "%s : digital gain = %d, analog gain = %d.%d\n", + __func__, digital_gain, analog_gain >> IMX274_GAIN_SHIFT, + ((analog_gain & IMX274_GAIN_SHIFT_MASK) * 100) + >> IMX274_GAIN_SHIFT); + + err = imx274_set_digital_gain(priv, digital_gain); + if (err) + goto fail; + + /* convert to register value, refer to imx274 datasheet */ + gain_reg = (u32)IMX274_GAIN_CONST - + (IMX274_GAIN_CONST << IMX274_GAIN_SHIFT) / analog_gain; + if (gain_reg > IMX274_GAIN_REG_MAX) + gain_reg = IMX274_GAIN_REG_MAX; + + imx274_calculate_gain_regs(reg_list, (u16)gain_reg); + + for (i = 0; i < ARRAY_SIZE(reg_list); i++) { + err = imx274_write_reg(priv, reg_list[i].addr, + reg_list[i].val); + if (err) + goto fail; + } + + if (IMX274_GAIN_CONST - gain_reg == 0) { + err = -EINVAL; + goto fail; + } + + /* convert register value back to gain value */ + ctrl->val = (IMX274_GAIN_CONST << IMX274_GAIN_SHIFT) + / (IMX274_GAIN_CONST - gain_reg) * digital_gain; + + dev_dbg(&priv->client->dev, + "%s : GAIN control success, gain_reg = %d, new gain = %d\n", + __func__, gain_reg, ctrl->val); + + return 0; + +fail: + dev_err(&priv->client->dev, "%s error = %d\n", __func__, err); + return err; +} + +static inline void imx274_calculate_coarse_time_regs(struct reg_8 regs[2], + u32 coarse_time) +{ + regs->addr = IMX274_COARSE_TIME_ADDR_MSB; + regs->val = (coarse_time >> IMX274_SHIFT_8_BITS) + & IMX274_MASK_LSB_8_BITS; + (regs + 1)->addr = IMX274_COARSE_TIME_ADDR_LSB; + (regs + 1)->val = (coarse_time) & IMX274_MASK_LSB_8_BITS; +} + +/* + * imx274_set_coarse_time - Function called when setting SHR value + * @priv: Pointer to device structure + * @val: Value for exposure time in number of line_length, or [HMAX] + * + * Set SHR value based on input value. + * + * Return: 0 on success + */ +static int imx274_set_coarse_time(struct stimx274 *priv, u32 *val) +{ + struct reg_8 reg_list[2]; + int err; + u32 coarse_time, frame_length; + int i; + + coarse_time = *val; + + /* convert exposure_time to appropriate SHR value */ + err = imx274_clamp_coarse_time(priv, &coarse_time, &frame_length); + if (err) + goto fail; + + /* prepare SHR registers */ + imx274_calculate_coarse_time_regs(reg_list, coarse_time); + + /* write to SHR registers */ + for (i = 0; i < ARRAY_SIZE(reg_list); i++) { + err = imx274_write_reg(priv, reg_list[i].addr, + reg_list[i].val); + if (err) + goto fail; + } + + *val = frame_length - coarse_time; + return 0; + +fail: + dev_err(&priv->client->dev, "%s error = %d\n", __func__, err); + return err; +} + +/* + * imx274_set_exposure - Function called when setting exposure time + * @priv: Pointer to device structure + * @val: Variable for exposure time, in the unit of micro-second + * + * Set exposure time based on input value. + * The caller should hold the mutex lock imx274->lock if necessary + * + * Return: 0 on success + */ +static int imx274_set_exposure(struct stimx274 *priv, int val) +{ + int err; + u16 hmax; + u8 reg_val[2]; + u32 coarse_time; /* exposure time in unit of line (HMAX)*/ + + dev_dbg(&priv->client->dev, + "%s : EXPOSURE control input = %d\n", __func__, val); + + /* step 1: convert input exposure_time (val) into number of 1[HMAX] */ + + /* obtain HMAX value */ + err = imx274_read_reg(priv, IMX274_HMAX_REG_LSB, ®_val[0]); + if (err) + goto fail; + err = imx274_read_reg(priv, IMX274_HMAX_REG_MSB, ®_val[1]); + if (err) + goto fail; + hmax = (reg_val[1] << IMX274_SHIFT_8_BITS) + reg_val[0]; + if (hmax == 0) { + err = -EINVAL; + goto fail; + } + + coarse_time = (IMX274_PIXCLK_CONST1 / IMX274_PIXCLK_CONST2 * val + - nocpiop[priv->mode_index]) / hmax; + + /* step 2: convert exposure_time into SHR value */ + + /* set SHR */ + err = imx274_set_coarse_time(priv, &coarse_time); + if (err) + goto fail; + + priv->ctrls.exposure->val = + (coarse_time * hmax + nocpiop[priv->mode_index]) + / (IMX274_PIXCLK_CONST1 / IMX274_PIXCLK_CONST2); + + dev_dbg(&priv->client->dev, + "%s : EXPOSURE control success\n", __func__); + return 0; + +fail: + dev_err(&priv->client->dev, "%s error = %d\n", __func__, err); + + return err; +} + +/* + * imx274_set_vflip - Function called when setting vertical flip + * @priv: Pointer to device structure + * @val: Value for vflip setting + * + * Set vertical flip based on input value. + * val = 0: normal, no vertical flip + * val = 1: vertical flip enabled + * The caller should hold the mutex lock imx274->lock if necessary + * + * Return: 0 on success + */ +static int imx274_set_vflip(struct stimx274 *priv, int val) +{ + int err; + + err = imx274_write_reg(priv, IMX274_VFLIP_REG, val); + if (err) { + dev_err(&priv->client->dev, "VFILP control error\n"); + return err; + } + + dev_dbg(&priv->client->dev, + "%s : VFLIP control success\n", __func__); + + return 0; +} + +/* + * imx274_set_test_pattern - Function called when setting test pattern + * @priv: Pointer to device structure + * @val: Variable for test pattern + * + * Set to different test patterns based on input value. + * + * Return: 0 on success + */ +static int imx274_set_test_pattern(struct stimx274 *priv, int val) +{ + int err = 0; + + if (val == TEST_PATTERN_DISABLED) { + err = imx274_write_table(priv, imx274_tp_disabled); + } else if (val <= TEST_PATTERN_V_COLOR_BARS) { + err = imx274_write_reg(priv, IMX274_TEST_PATTERN_REG, val - 1); + if (!err) + err = imx274_write_table(priv, imx274_tp_regs); + } else { + err = -EINVAL; + } + + if (!err) + dev_dbg(&priv->client->dev, + "%s : TEST PATTERN control success\n", __func__); + else + dev_err(&priv->client->dev, "%s error = %d\n", __func__, err); + + return err; +} + +static inline void imx274_calculate_frame_length_regs(struct reg_8 regs[3], + u32 frame_length) +{ + regs->addr = IMX274_FRAME_LENGTH_ADDR_1; + regs->val = (frame_length >> IMX274_SHIFT_16_BITS) + & IMX274_MASK_LSB_4_BITS; + (regs + 1)->addr = IMX274_FRAME_LENGTH_ADDR_2; + (regs + 1)->val = (frame_length >> IMX274_SHIFT_8_BITS) + & IMX274_MASK_LSB_8_BITS; + (regs + 2)->addr = IMX274_FRAME_LENGTH_ADDR_3; + (regs + 2)->val = (frame_length) & IMX274_MASK_LSB_8_BITS; +} + +/* + * imx274_set_frame_length - Function called when setting frame length + * @priv: Pointer to device structure + * @val: Variable for frame length (= VMAX, i.e. vertical drive period length) + * + * Set frame length based on input value. + * + * Return: 0 on success + */ +static int imx274_set_frame_length(struct stimx274 *priv, u32 val) +{ + struct reg_8 reg_list[3]; + int err; + u32 frame_length; + int i; + + dev_dbg(&priv->client->dev, "%s : input length = %d\n", + __func__, val); + + frame_length = (u32)val; + + imx274_calculate_frame_length_regs(reg_list, frame_length); + for (i = 0; i < ARRAY_SIZE(reg_list); i++) { + err = imx274_write_reg(priv, reg_list[i].addr, + reg_list[i].val); + if (err) + goto fail; + } + + return 0; + +fail: + dev_err(&priv->client->dev, "%s error = %d\n", __func__, err); + return err; +} + +/* + * imx274_set_frame_interval - Function called when setting frame interval + * @priv: Pointer to device structure + * @frame_interval: Variable for frame interval + * + * Change frame interval by updating VMAX value + * The caller should hold the mutex lock imx274->lock if necessary + * + * Return: 0 on success + */ +static int imx274_set_frame_interval(struct stimx274 *priv, + struct v4l2_fract frame_interval) +{ + int err; + u32 frame_length, req_frame_rate; + u16 svr; + u16 hmax; + u8 reg_val[2]; + + dev_dbg(&priv->client->dev, "%s: input frame interval = %d / %d", + __func__, frame_interval.numerator, + frame_interval.denominator); + + if (frame_interval.numerator == 0) { + err = -EINVAL; + goto fail; + } + + req_frame_rate = (u32)(frame_interval.denominator + / frame_interval.numerator); + + /* boundary check */ + if (req_frame_rate > max_frame_rate[priv->mode_index]) { + frame_interval.numerator = 1; + frame_interval.denominator = + max_frame_rate[priv->mode_index]; + } else if (req_frame_rate < IMX274_MIN_FRAME_RATE) { + frame_interval.numerator = 1; + frame_interval.denominator = IMX274_MIN_FRAME_RATE; + } + + /* + * VMAX = 1/frame_rate x 72M / (SVR+1) / HMAX + * frame_length (i.e. VMAX) = (frame_interval) x 72M /(SVR+1) / HMAX + */ + + /* SVR */ + err = imx274_read_reg(priv, IMX274_SVR_REG_LSB, ®_val[0]); + if (err) + goto fail; + err = imx274_read_reg(priv, IMX274_SVR_REG_MSB, ®_val[1]); + if (err) + goto fail; + svr = (reg_val[1] << IMX274_SHIFT_8_BITS) + reg_val[0]; + dev_dbg(&priv->client->dev, + "%s : register SVR = %d\n", __func__, svr); + + /* HMAX */ + err = imx274_read_reg(priv, IMX274_HMAX_REG_LSB, ®_val[0]); + if (err) + goto fail; + err = imx274_read_reg(priv, IMX274_HMAX_REG_MSB, ®_val[1]); + if (err) + goto fail; + hmax = (reg_val[1] << IMX274_SHIFT_8_BITS) + reg_val[0]; + dev_dbg(&priv->client->dev, + "%s : register HMAX = %d\n", __func__, hmax); + + if (hmax == 0 || frame_interval.denominator == 0) { + err = -EINVAL; + goto fail; + } + + frame_length = IMX274_PIXCLK_CONST1 / (svr + 1) / hmax + * frame_interval.numerator + / frame_interval.denominator; + + err = imx274_set_frame_length(priv, frame_length); + if (err) + goto fail; + + priv->frame_interval = frame_interval; + return 0; + +fail: + dev_err(&priv->client->dev, "%s error = %d\n", __func__, err); + return err; +} + +static const struct v4l2_subdev_pad_ops imx274_pad_ops = { + .get_fmt = imx274_get_fmt, + .set_fmt = imx274_set_fmt, +}; + +static const struct v4l2_subdev_video_ops imx274_video_ops = { + .g_frame_interval = imx274_g_frame_interval, + .s_frame_interval = imx274_s_frame_interval, + .s_stream = imx274_s_stream, +}; + +static const struct v4l2_subdev_ops imx274_subdev_ops = { + .pad = &imx274_pad_ops, + .video = &imx274_video_ops, +}; + +static const struct v4l2_ctrl_ops imx274_ctrl_ops = { + .s_ctrl = imx274_s_ctrl, +}; + +static const struct of_device_id imx274_of_id_table[] = { + { .compatible = "sony,imx274" }, + { } +}; +MODULE_DEVICE_TABLE(of, imx274_of_id_table); + +static const struct i2c_device_id imx274_id[] = { + { "IMX274", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, imx274_id); + +static int imx274_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct v4l2_subdev *sd; + struct stimx274 *imx274; + int ret; + + /* initialize imx274 */ + imx274 = devm_kzalloc(&client->dev, sizeof(*imx274), GFP_KERNEL); + if (!imx274) + return -ENOMEM; + + mutex_init(&imx274->lock); + + /* initialize regmap */ + imx274->regmap = devm_regmap_init_i2c(client, &imx274_regmap_config); + if (IS_ERR(imx274->regmap)) { + dev_err(&client->dev, + "regmap init failed: %ld\n", PTR_ERR(imx274->regmap)); + ret = -ENODEV; + goto err_regmap; + } + + /* initialize subdevice */ + imx274->client = client; + sd = &imx274->sd; + v4l2_i2c_subdev_init(sd, client, &imx274_subdev_ops); + strlcpy(sd->name, DRIVER_NAME, sizeof(sd->name)); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + + /* initialize subdev media pad */ + imx274->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sd->entity, 1, &imx274->pad); + if (ret < 0) { + dev_err(&client->dev, + "%s : media entity init Failed %d\n", __func__, ret); + goto err_regmap; + } + + /* initialize sensor reset gpio */ + imx274->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(imx274->reset_gpio)) { + if (PTR_ERR(imx274->reset_gpio) != -EPROBE_DEFER) + dev_err(&client->dev, "Reset GPIO not setup in DT"); + ret = PTR_ERR(imx274->reset_gpio); + goto err_me; + } + + /* pull sensor out of reset */ + imx274_reset(imx274, 1); + + /* initialize controls */ + ret = v4l2_ctrl_handler_init(&imx274->ctrls.handler, 2); + if (ret < 0) { + dev_err(&client->dev, + "%s : ctrl handler init Failed\n", __func__); + goto err_me; + } + + imx274->ctrls.handler.lock = &imx274->lock; + + /* add new controls */ + imx274->ctrls.test_pattern = v4l2_ctrl_new_std_menu_items( + &imx274->ctrls.handler, &imx274_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(tp_qmenu) - 1, 0, 0, tp_qmenu); + + imx274->ctrls.gain = v4l2_ctrl_new_std( + &imx274->ctrls.handler, + &imx274_ctrl_ops, + V4L2_CID_GAIN, IMX274_MIN_GAIN, + IMX274_MAX_DIGITAL_GAIN * IMX274_MAX_ANALOG_GAIN, 1, + IMX274_DEF_GAIN); + + imx274->ctrls.exposure = v4l2_ctrl_new_std( + &imx274->ctrls.handler, + &imx274_ctrl_ops, + V4L2_CID_EXPOSURE, IMX274_MIN_EXPOSURE_TIME, + 1000000 / IMX274_DEF_FRAME_RATE, 1, + IMX274_MIN_EXPOSURE_TIME); + + imx274->ctrls.vflip = v4l2_ctrl_new_std( + &imx274->ctrls.handler, + &imx274_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + + imx274->sd.ctrl_handler = &imx274->ctrls.handler; + if (imx274->ctrls.handler.error) { + ret = imx274->ctrls.handler.error; + goto err_ctrls; + } + + /* setup default controls */ + ret = v4l2_ctrl_handler_setup(&imx274->ctrls.handler); + if (ret) { + dev_err(&client->dev, + "Error %d setup default controls\n", ret); + goto err_ctrls; + } + + /* initialize format */ + imx274->mode_index = IMX274_MODE_3840X2160; + imx274->format.width = imx274_formats[0].size.width; + imx274->format.height = imx274_formats[0].size.height; + imx274->format.field = V4L2_FIELD_NONE; + imx274->format.code = MEDIA_BUS_FMT_SRGGB10_1X10; + imx274->format.colorspace = V4L2_COLORSPACE_SRGB; + imx274->frame_interval.numerator = 1; + imx274->frame_interval.denominator = IMX274_DEF_FRAME_RATE; + + /* load default control values */ + ret = imx274_load_default(imx274); + if (ret) { + dev_err(&client->dev, + "%s : imx274_load_default failed %d\n", + __func__, ret); + goto err_ctrls; + } + + /* register subdevice */ + ret = v4l2_async_register_subdev(sd); + if (ret < 0) { + dev_err(&client->dev, + "%s : v4l2_async_register_subdev failed %d\n", + __func__, ret); + goto err_ctrls; + } + + dev_info(&client->dev, "imx274 : imx274 probe success !\n"); + return 0; + +err_ctrls: + v4l2_async_unregister_subdev(sd); + v4l2_ctrl_handler_free(sd->ctrl_handler); +err_me: + media_entity_cleanup(&sd->entity); +err_regmap: + mutex_destroy(&imx274->lock); + return ret; +} + +static int imx274_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct stimx274 *imx274 = to_imx274(sd); + + /* stop stream */ + imx274_write_table(imx274, mode_table[IMX274_MODE_STOP_STREAM]); + + v4l2_async_unregister_subdev(sd); + v4l2_ctrl_handler_free(sd->ctrl_handler); + media_entity_cleanup(&sd->entity); + mutex_destroy(&imx274->lock); + return 0; +} + +static struct i2c_driver imx274_i2c_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = imx274_of_id_table, + }, + .probe = imx274_probe, + .remove = imx274_remove, + .id_table = imx274_id, +}; + +module_i2c_driver(imx274_i2c_driver); + +MODULE_AUTHOR("Leon Luo "); +MODULE_DESCRIPTION("IMX274 CMOS Image Sensor driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 183c2e048109e2a861bc282b8b814ed37a69c738 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 14 Sep 2017 12:06:26 +0200 Subject: media: staging: media: MAINTAINERS: Add entry for atomisp driver Add the maintainers entry to the atomisp staging media driver. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 90230fe020f3..dbeaa2c44dcd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12679,6 +12679,13 @@ L: stable@vger.kernel.org S: Supported F: Documentation/process/stable-kernel-rules.rst +STAGING - ATOMISP DRIVER +M: Alan Cox +M: Sakari Ailus +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/staging/media/atomisp/ + STAGING - COMEDI M: Ian Abbott M: H Hartley Sweeten -- cgit v1.2.3 From 90ebe55ab88635a19af06d923bb70ef236123399 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 12 Sep 2017 00:46:32 +0200 Subject: media: staging: atomisp: Add driver prefix to Kconfig option and module names By adding the "atomisp-" prefix to module names (and "ATOMISP_" to Kconfig options), the staging drivers for e.g. sensors are labelled as being specific to atomisp, which they effectively are. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/Kconfig | 18 +- drivers/staging/media/atomisp/i2c/Makefile | 20 +- drivers/staging/media/atomisp/i2c/ap1302.c | 1255 ------------ drivers/staging/media/atomisp/i2c/atomisp-ap1302.c | 1255 ++++++++++++ drivers/staging/media/atomisp/i2c/atomisp-gc0310.c | 1490 ++++++++++++++ drivers/staging/media/atomisp/i2c/atomisp-gc2235.c | 1219 ++++++++++++ .../media/atomisp/i2c/atomisp-libmsrlisthelper.c | 209 ++ drivers/staging/media/atomisp/i2c/atomisp-lm3554.c | 1009 ++++++++++ .../staging/media/atomisp/i2c/atomisp-mt9m114.c | 1963 +++++++++++++++++++ drivers/staging/media/atomisp/i2c/atomisp-ov2680.c | 1557 +++++++++++++++ drivers/staging/media/atomisp/i2c/atomisp-ov2722.c | 1373 +++++++++++++ drivers/staging/media/atomisp/i2c/gc0310.c | 1490 -------------- drivers/staging/media/atomisp/i2c/gc2235.c | 1219 ------------ drivers/staging/media/atomisp/i2c/imx/Kconfig | 4 +- drivers/staging/media/atomisp/i2c/imx/Makefile | 8 +- .../staging/media/atomisp/i2c/libmsrlisthelper.c | 209 -- drivers/staging/media/atomisp/i2c/lm3554.c | 1009 ---------- drivers/staging/media/atomisp/i2c/mt9m114.c | 1963 ------------------- drivers/staging/media/atomisp/i2c/ov2680.c | 1557 --------------- drivers/staging/media/atomisp/i2c/ov2722.c | 1373 ------------- drivers/staging/media/atomisp/i2c/ov5693/Kconfig | 2 +- drivers/staging/media/atomisp/i2c/ov5693/Makefile | 2 +- .../media/atomisp/i2c/ov5693/atomisp-ov5693.c | 2059 ++++++++++++++++++++ drivers/staging/media/atomisp/i2c/ov5693/ov5693.c | 2059 -------------------- 24 files changed, 12161 insertions(+), 12161 deletions(-) delete mode 100644 drivers/staging/media/atomisp/i2c/ap1302.c create mode 100644 drivers/staging/media/atomisp/i2c/atomisp-ap1302.c create mode 100644 drivers/staging/media/atomisp/i2c/atomisp-gc0310.c create mode 100644 drivers/staging/media/atomisp/i2c/atomisp-gc2235.c create mode 100644 drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c create mode 100644 drivers/staging/media/atomisp/i2c/atomisp-lm3554.c create mode 100644 drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c create mode 100644 drivers/staging/media/atomisp/i2c/atomisp-ov2680.c create mode 100644 drivers/staging/media/atomisp/i2c/atomisp-ov2722.c delete mode 100644 drivers/staging/media/atomisp/i2c/gc0310.c delete mode 100644 drivers/staging/media/atomisp/i2c/gc2235.c delete mode 100644 drivers/staging/media/atomisp/i2c/libmsrlisthelper.c delete mode 100644 drivers/staging/media/atomisp/i2c/lm3554.c delete mode 100644 drivers/staging/media/atomisp/i2c/mt9m114.c delete mode 100644 drivers/staging/media/atomisp/i2c/ov2680.c delete mode 100644 drivers/staging/media/atomisp/i2c/ov2722.c create mode 100644 drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c delete mode 100644 drivers/staging/media/atomisp/i2c/ov5693/ov5693.c diff --git a/drivers/staging/media/atomisp/i2c/Kconfig b/drivers/staging/media/atomisp/i2c/Kconfig index 57505b7a25ca..09b1a97ce560 100644 --- a/drivers/staging/media/atomisp/i2c/Kconfig +++ b/drivers/staging/media/atomisp/i2c/Kconfig @@ -5,7 +5,7 @@ source "drivers/staging/media/atomisp/i2c/ov5693/Kconfig" source "drivers/staging/media/atomisp/i2c/imx/Kconfig" -config VIDEO_OV2722 +config VIDEO_ATOMISP_OV2722 tristate "OVT ov2722 sensor support" depends on I2C && VIDEO_V4L2 ---help--- @@ -16,7 +16,7 @@ config VIDEO_OV2722 It currently only works with the atomisp driver. -config VIDEO_GC2235 +config VIDEO_ATOMISP_GC2235 tristate "Galaxy gc2235 sensor support" depends on I2C && VIDEO_V4L2 ---help--- @@ -27,7 +27,7 @@ config VIDEO_GC2235 It currently only works with the atomisp driver. -config VIDEO_OV8858 +config VIDEO_ATOMISP_OV8858 tristate "Omnivision ov8858 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_ATOMISP ---help--- @@ -38,7 +38,7 @@ config VIDEO_OV8858 It currently only works with the atomisp driver. -config VIDEO_MSRLIST_HELPER +config VIDEO_ATOMISP_MSRLIST_HELPER tristate "Helper library to load, parse and apply large register lists." depends on I2C ---help--- @@ -48,7 +48,7 @@ config VIDEO_MSRLIST_HELPER To compile this driver as a module, choose M here: the module will be called libmsrlisthelper. -config VIDEO_MT9M114 +config VIDEO_ATOMISP_MT9M114 tristate "Aptina mt9m114 sensor support" depends on I2C && VIDEO_V4L2 ---help--- @@ -59,7 +59,7 @@ config VIDEO_MT9M114 It currently only works with the atomisp driver. -config VIDEO_AP1302 +config VIDEO_ATOMISP_AP1302 tristate "AP1302 external ISP support" depends on I2C && VIDEO_V4L2 select REGMAP_I2C @@ -71,14 +71,14 @@ config VIDEO_AP1302 It currently only works with the atomisp driver. -config VIDEO_GC0310 +config VIDEO_ATOMISP_GC0310 tristate "GC0310 sensor support" depends on I2C && VIDEO_V4L2 ---help--- This is a Video4Linux2 sensor-level driver for the Galaxycore GC0310 0.3MP sensor. -config VIDEO_OV2680 +config VIDEO_ATOMISP_OV2680 tristate "Omnivision OV2680 sensor support" depends on I2C && VIDEO_V4L2 ---help--- @@ -93,7 +93,7 @@ config VIDEO_OV2680 # Kconfig for flash drivers # -config VIDEO_LM3554 +config VIDEO_ATOMISP_LM3554 tristate "LM3554 flash light driver" depends on VIDEO_V4L2 && I2C ---help--- diff --git a/drivers/staging/media/atomisp/i2c/Makefile b/drivers/staging/media/atomisp/i2c/Makefile index be13fab92175..3d27c75f5fc5 100644 --- a/drivers/staging/media/atomisp/i2c/Makefile +++ b/drivers/staging/media/atomisp/i2c/Makefile @@ -2,22 +2,22 @@ # Makefile for sensor drivers # -obj-$(CONFIG_VIDEO_IMX) += imx/ -obj-$(CONFIG_VIDEO_OV5693) += ov5693/ -obj-$(CONFIG_VIDEO_MT9M114) += mt9m114.o -obj-$(CONFIG_VIDEO_GC2235) += gc2235.o -obj-$(CONFIG_VIDEO_OV2722) += ov2722.o -obj-$(CONFIG_VIDEO_OV2680) += ov2680.o -obj-$(CONFIG_VIDEO_GC0310) += gc0310.o +obj-$(CONFIG_VIDEO_ATOMISP_IMX) += imx/ +obj-$(CONFIG_VIDEO_ATOMISP_OV5693) += ov5693/ +obj-$(CONFIG_VIDEO_ATOMISP_MT9M114) += atomisp-mt9m114.o +obj-$(CONFIG_VIDEO_ATOMISP_GC2235) += atomisp-gc2235.o +obj-$(CONFIG_VIDEO_ATOMISP_OV2722) += atomisp-ov2722.o +obj-$(CONFIG_VIDEO_ATOMISP_OV2680) += atomisp-ov2680.o +obj-$(CONFIG_VIDEO_ATOMISP_GC0310) += atomisp-gc0310.o -obj-$(CONFIG_VIDEO_MSRLIST_HELPER) += libmsrlisthelper.o +obj-$(CONFIG_VIDEO_ATOMISP_MSRLIST_HELPER) += atomisp-libmsrlisthelper.o -obj-$(CONFIG_VIDEO_AP1302) += ap1302.o +obj-$(CONFIG_VIDEO_ATOMISP_AP1302) += atomisp-ap1302.o # Makefile for flash drivers # -obj-$(CONFIG_VIDEO_LM3554) += lm3554.o +obj-$(CONFIG_VIDEO_ATOMISP_LM3554) += atomisp-lm3554.o # HACK! While this driver is in bad shape, don't enable several warnings # that would be otherwise enabled with W=1 diff --git a/drivers/staging/media/atomisp/i2c/ap1302.c b/drivers/staging/media/atomisp/i2c/ap1302.c deleted file mode 100644 index 2f772a020c8b..000000000000 --- a/drivers/staging/media/atomisp/i2c/ap1302.c +++ /dev/null @@ -1,1255 +0,0 @@ -/* - * - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include "../include/linux/atomisp.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ap1302.h" - -#define to_ap1302_device(sub_dev) \ - container_of(sub_dev, struct ap1302_device, sd) - -/* Static definitions */ -static struct regmap_config ap1302_reg16_config = { - .reg_bits = 16, - .val_bits = 16, - .reg_format_endian = REGMAP_ENDIAN_BIG, - .val_format_endian = REGMAP_ENDIAN_BIG, -}; - -static struct regmap_config ap1302_reg32_config = { - .reg_bits = 16, - .val_bits = 32, - .reg_format_endian = REGMAP_ENDIAN_BIG, - .val_format_endian = REGMAP_ENDIAN_BIG, -}; - -static enum ap1302_contexts ap1302_cntx_mapping[] = { - CONTEXT_PREVIEW, /* Invalid atomisp run mode */ - CONTEXT_VIDEO, /* ATOMISP_RUN_MODE_VIDEO */ - CONTEXT_SNAPSHOT, /* ATOMISP_RUN_MODE_STILL_CAPTURE */ - CONTEXT_SNAPSHOT, /* ATOMISP_RUN_MODE_CONTINUOUS_CAPTURE */ - CONTEXT_PREVIEW, /* ATOMISP_RUN_MODE_PREVIEW */ -}; - -static struct ap1302_res_struct ap1302_preview_res[] = { - { - .width = 640, - .height = 480, - .fps = 30, - }, - { - .width = 720, - .height = 480, - .fps = 30, - }, - { - .width = 1280, - .height = 720, - .fps = 30, - }, - { - .width = 1920, - .height = 1080, - .fps = 30, - } -}; - -static struct ap1302_res_struct ap1302_snapshot_res[] = { - { - .width = 640, - .height = 480, - .fps = 30, - }, - { - .width = 720, - .height = 480, - .fps = 30, - }, - { - .width = 1280, - .height = 720, - .fps = 30, - }, - { - .width = 1920, - .height = 1080, - .fps = 30, - } -}; - -static struct ap1302_res_struct ap1302_video_res[] = { - { - .width = 640, - .height = 480, - .fps = 30, - }, - { - .width = 720, - .height = 480, - .fps = 30, - }, - { - .width = 1280, - .height = 720, - .fps = 30, - }, - { - .width = 1920, - .height = 1080, - .fps = 30, - } -}; - -static enum ap1302_contexts stream_to_context[] = { - CONTEXT_SNAPSHOT, - CONTEXT_PREVIEW, - CONTEXT_PREVIEW, - CONTEXT_VIDEO -}; - -static u16 aux_stream_config[CONTEXT_NUM][CONTEXT_NUM] = { - {0, 0, 0}, /* Preview: No aux streams. */ - {1, 0, 2}, /* Snapshot: 1 for postview. 2 for video */ - {1, 0, 0}, /* Video: 1 for preview. */ -}; - -static struct ap1302_context_info context_info[] = { - {CNTX_WIDTH, AP1302_REG16, "width"}, - {CNTX_HEIGHT, AP1302_REG16, "height"}, - {CNTX_ROI_X0, AP1302_REG16, "roi_x0"}, - {CNTX_ROI_X1, AP1302_REG16, "roi_x1"}, - {CNTX_ROI_Y0, AP1302_REG16, "roi_y0"}, - {CNTX_ROI_Y1, AP1302_REG16, "roi_y1"}, - {CNTX_ASPECT, AP1302_REG16, "aspect"}, - {CNTX_LOCK, AP1302_REG16, "lock"}, - {CNTX_ENABLE, AP1302_REG16, "enable"}, - {CNTX_OUT_FMT, AP1302_REG16, "out_fmt"}, - {CNTX_SENSOR_MODE, AP1302_REG16, "sensor_mode"}, - {CNTX_MIPI_CTRL, AP1302_REG16, "mipi_ctrl"}, - {CNTX_MIPI_II_CTRL, AP1302_REG16, "mipi_ii_ctrl"}, - {CNTX_LINE_TIME, AP1302_REG32, "line_time"}, - {CNTX_MAX_FPS, AP1302_REG16, "max_fps"}, - {CNTX_AE_USG, AP1302_REG16, "ae_usg"}, - {CNTX_AE_UPPER_ET, AP1302_REG32, "ae_upper_et"}, - {CNTX_AE_MAX_ET, AP1302_REG32, "ae_max_et"}, - {CNTX_SS, AP1302_REG16, "ss"}, - {CNTX_S1_SENSOR_MODE, AP1302_REG16, "s1_sensor_mode"}, - {CNTX_HINF_CTRL, AP1302_REG16, "hinf_ctrl"}, -}; - -/* This array stores the description list for metadata. - The metadata contains exposure settings and face - detection results. */ -static u16 ap1302_ss_list[] = { - 0xb01c, /* From 0x0186 with size 0x1C are exposure settings. */ - 0x0186, - 0xb002, /* 0x71c0 is for F-number */ - 0x71c0, - 0xb010, /* From 0x03dc with size 0x10 are face general infos. */ - 0x03dc, - 0xb0a0, /* From 0x03e4 with size 0xa0 are face detail infos. */ - 0x03e4, - 0xb020, /* From 0x0604 with size 0x20 are smile rate infos. */ - 0x0604, - 0x0000 -}; - -/* End of static definitions */ - -static int ap1302_i2c_read_reg(struct v4l2_subdev *sd, - u16 reg, u16 len, void *val) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (len == AP1302_REG16) - ret = regmap_read(dev->regmap16, reg, val); - else if (len == AP1302_REG32) - ret = regmap_read(dev->regmap32, reg, val); - else - ret = -EINVAL; - if (ret) { - dev_dbg(&client->dev, "Read reg failed. reg=0x%04X\n", reg); - return ret; - } - if (len == AP1302_REG16) - dev_dbg(&client->dev, "read_reg[0x%04X] = 0x%04X\n", - reg, *(u16 *)val); - else - dev_dbg(&client->dev, "read_reg[0x%04X] = 0x%08X\n", - reg, *(u32 *)val); - return ret; -} - -static int ap1302_i2c_write_reg(struct v4l2_subdev *sd, - u16 reg, u16 len, u32 val) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - if (len == AP1302_REG16) - ret = regmap_write(dev->regmap16, reg, val); - else if (len == AP1302_REG32) - ret = regmap_write(dev->regmap32, reg, val); - else - ret = -EINVAL; - if (ret) { - dev_dbg(&client->dev, "Write reg failed. reg=0x%04X\n", reg); - return ret; - } - if (len == AP1302_REG16) - dev_dbg(&client->dev, "write_reg[0x%04X] = 0x%04X\n", - reg, (u16)val); - else - dev_dbg(&client->dev, "write_reg[0x%04X] = 0x%08X\n", - reg, (u32)val); - return ret; -} - -static u16 -ap1302_calculate_context_reg_addr(enum ap1302_contexts context, u16 offset) -{ - u16 reg_addr; - /* The register offset is defined according to preview/video registers. - Preview and video context have the same register definition. - But snapshot context does not have register S1_SENSOR_MODE. - When setting snapshot registers, if the offset exceeds - S1_SENSOR_MODE, the actual offset needs to minus 2. */ - if (context == CONTEXT_SNAPSHOT) { - if (offset == CNTX_S1_SENSOR_MODE) - return 0; - if (offset > CNTX_S1_SENSOR_MODE) - offset -= 2; - } - if (context == CONTEXT_PREVIEW) - reg_addr = REG_PREVIEW_BASE + offset; - else if (context == CONTEXT_VIDEO) - reg_addr = REG_VIDEO_BASE + offset; - else - reg_addr = REG_SNAPSHOT_BASE + offset; - return reg_addr; -} - -static int ap1302_read_context_reg(struct v4l2_subdev *sd, - enum ap1302_contexts context, u16 offset, u16 len) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - u16 reg_addr = ap1302_calculate_context_reg_addr(context, offset); - if (reg_addr == 0) - return -EINVAL; - return ap1302_i2c_read_reg(sd, reg_addr, len, - ((u8 *)&dev->cntx_config[context]) + offset); -} - -static int ap1302_write_context_reg(struct v4l2_subdev *sd, - enum ap1302_contexts context, u16 offset, u16 len) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - u16 reg_addr = ap1302_calculate_context_reg_addr(context, offset); - if (reg_addr == 0) - return -EINVAL; - return ap1302_i2c_write_reg(sd, reg_addr, len, - *(u32 *)(((u8 *)&dev->cntx_config[context]) + offset)); -} - -static int ap1302_dump_context_reg(struct v4l2_subdev *sd, - enum ap1302_contexts context) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ap1302_device *dev = to_ap1302_device(sd); - int i; - dev_dbg(&client->dev, "Dump registers for context[%d]:\n", context); - for (i = 0; i < ARRAY_SIZE(context_info); i++) { - struct ap1302_context_info *info = &context_info[i]; - u8 *var = (u8 *)&dev->cntx_config[context] + info->offset; - /* Snapshot context does not have s1_sensor_mode register. */ - if (context == CONTEXT_SNAPSHOT && - info->offset == CNTX_S1_SENSOR_MODE) - continue; - ap1302_read_context_reg(sd, context, info->offset, info->len); - if (info->len == AP1302_REG16) - dev_dbg(&client->dev, "context.%s = 0x%04X (%d)\n", - info->name, *(u16 *)var, *(u16 *)var); - else - dev_dbg(&client->dev, "context.%s = 0x%08X (%d)\n", - info->name, *(u32 *)var, *(u32 *)var); - } - return 0; -} - -static int ap1302_request_firmware(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ap1302_device *dev = to_ap1302_device(sd); - int ret; - ret = request_firmware(&dev->fw, "ap1302_fw.bin", &client->dev); - if (ret) - dev_err(&client->dev, - "ap1302_request_firmware failed. ret=%d\n", ret); - return ret; -} - -/* When loading firmware, host writes firmware data from address 0x8000. - When the address reaches 0x9FFF, the next address should return to 0x8000. - This function handles this address window and load firmware data to AP1302. - win_pos indicates the offset within this window. Firmware loading procedure - may call this function several times. win_pos records the current position - that has been written to.*/ -static int ap1302_write_fw_window(struct v4l2_subdev *sd, - u16 *win_pos, const u8 *buf, u32 len) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - int ret; - u32 pos; - u32 sub_len; - for (pos = 0; pos < len; pos += sub_len) { - if (len - pos < AP1302_FW_WINDOW_SIZE - *win_pos) - sub_len = len - pos; - else - sub_len = AP1302_FW_WINDOW_SIZE - *win_pos; - ret = regmap_raw_write(dev->regmap16, - *win_pos + AP1302_FW_WINDOW_OFFSET, - buf + pos, sub_len); - if (ret) - return ret; - *win_pos += sub_len; - if (*win_pos >= AP1302_FW_WINDOW_SIZE) - *win_pos = 0; - } - return 0; -} - -static int ap1302_load_firmware(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ap1302_device *dev = to_ap1302_device(sd); - const struct ap1302_firmware *fw; - const u8 *fw_data; - u16 reg_val = 0; - u16 win_pos = 0; - int ret; - - dev_info(&client->dev, "Start to load firmware.\n"); - if (!dev->fw) { - dev_err(&client->dev, "firmware not requested.\n"); - return -EINVAL; - } - fw = (const struct ap1302_firmware *) dev->fw->data; - if (dev->fw->size != (sizeof(*fw) + fw->total_size)) { - dev_err(&client->dev, "firmware size does not match.\n"); - return -EINVAL; - } - /* The fw binary contains a header of struct ap1302_firmware. - Following the header is the bootdata of AP1302. - The bootdata pointer can be referenced as &fw[1]. */ - fw_data = (u8 *)&fw[1]; - - /* Clear crc register. */ - ret = ap1302_i2c_write_reg(sd, REG_SIP_CRC, AP1302_REG16, 0xFFFF); - if (ret) - return ret; - - /* Load FW data for PLL init stage. */ - ret = ap1302_write_fw_window(sd, &win_pos, fw_data, fw->pll_init_size); - if (ret) - return ret; - - /* Write 2 to bootdata_stage register to apply basic_init_hp - settings and enable PLL. */ - ret = ap1302_i2c_write_reg(sd, REG_BOOTDATA_STAGE, - AP1302_REG16, 0x0002); - if (ret) - return ret; - - /* Wait 1ms for PLL to lock. */ - msleep(20); - - /* Load the rest of bootdata content. */ - ret = ap1302_write_fw_window(sd, &win_pos, fw_data + fw->pll_init_size, - fw->total_size - fw->pll_init_size); - if (ret) - return ret; - - /* Check crc. */ - ret = ap1302_i2c_read_reg(sd, REG_SIP_CRC, AP1302_REG16, ®_val); - if (ret) - return ret; - if (reg_val != fw->crc) { - dev_err(&client->dev, - "crc does not match. T:0x%04X F:0x%04X\n", - fw->crc, reg_val); - return -EAGAIN; - } - - /* Write 0xFFFF to bootdata_stage register to indicate AP1302 that - the whole bootdata content has been loaded. */ - ret = ap1302_i2c_write_reg(sd, REG_BOOTDATA_STAGE, - AP1302_REG16, 0xFFFF); - if (ret) - return ret; - dev_info(&client->dev, "Load firmware successfully.\n"); - - return 0; -} - -static int __ap1302_s_power(struct v4l2_subdev *sd, int on, int load_fw) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret, i; - u16 ss_ptr; - - dev_info(&client->dev, "ap1302_s_power is called.\n"); - ret = dev->platform_data->power_ctrl(sd, on); - if (ret) { - dev_err(&client->dev, - "ap1302_s_power error. on=%d ret=%d\n", on, ret); - return ret; - } - dev->power_on = on; - if (!on || !load_fw) - return 0; - /* Load firmware after power on. */ - ret = ap1302_load_firmware(sd); - if (ret) { - dev_err(&client->dev, - "ap1302_load_firmware failed. ret=%d\n", ret); - return ret; - } - ret = ap1302_i2c_read_reg(sd, REG_SS_HEAD_PT0, AP1302_REG16, &ss_ptr); - if (ret) - return ret; - for (i = 0; i < ARRAY_SIZE(ap1302_ss_list); i++) { - ret = ap1302_i2c_write_reg(sd, ss_ptr + i * 2, - AP1302_REG16, ap1302_ss_list[i]); - if (ret) - return ret; - } - return ret; -} - -static int ap1302_s_power(struct v4l2_subdev *sd, int on) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - int ret; - - mutex_lock(&dev->input_lock); - ret = __ap1302_s_power(sd, on, 1); - dev->sys_activated = 0; - mutex_unlock(&dev->input_lock); - - return ret; -} - -static int ap1302_s_config(struct v4l2_subdev *sd, void *pdata) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_mipi_info *mipi_info; - u16 reg_val = 0; - int ret; - - dev_info(&client->dev, "ap1302_s_config is called.\n"); - if (pdata == NULL) - return -ENODEV; - - dev->platform_data = pdata; - - mutex_lock(&dev->input_lock); - - if (dev->platform_data->platform_init) { - ret = dev->platform_data->platform_init(client); - if (ret) - goto fail_power; - } - - ret = __ap1302_s_power(sd, 1, 0); - if (ret) - goto fail_power; - - /* Detect for AP1302 */ - ret = ap1302_i2c_read_reg(sd, REG_CHIP_VERSION, AP1302_REG16, ®_val); - if (ret || (reg_val != AP1302_CHIP_ID)) { - dev_err(&client->dev, - "Chip version does no match. ret=%d ver=0x%04x\n", - ret, reg_val); - goto fail_config; - } - dev_info(&client->dev, "AP1302 Chip ID is 0x%X\n", reg_val); - - /* Detect revision for AP1302 */ - ret = ap1302_i2c_read_reg(sd, REG_CHIP_REV, AP1302_REG16, ®_val); - if (ret) - goto fail_config; - dev_info(&client->dev, "AP1302 Chip Rev is 0x%X\n", reg_val); - ret = dev->platform_data->csi_cfg(sd, 1); - if (ret) - goto fail_config; - - mipi_info = v4l2_get_subdev_hostdata(sd); - if (!mipi_info) - goto fail_config; - dev->num_lanes = mipi_info->num_lanes; - - ret = __ap1302_s_power(sd, 0, 0); - if (ret) - goto fail_power; - - mutex_unlock(&dev->input_lock); - - return ret; - -fail_config: - __ap1302_s_power(sd, 0, 0); -fail_power: - mutex_unlock(&dev->input_lock); - dev_err(&client->dev, "ap1302_s_config failed\n"); - return ret; -} - -static enum ap1302_contexts ap1302_get_context(struct v4l2_subdev *sd) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - return dev->cur_context; -} - -static int ap1302_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->index) - return -EINVAL; - - code->code = MEDIA_BUS_FMT_UYVY8_1X16; - - return 0; -} - -static int ap1302_match_resolution(struct ap1302_context_res *res, - struct v4l2_mbus_framefmt *fmt) -{ - s32 w0, h0, mismatch, distance; - s32 w1 = fmt->width; - s32 h1 = fmt->height; - s32 min_distance = INT_MAX; - s32 i, idx = -1; - - if (w1 == 0 || h1 == 0) - return -1; - - for (i = 0; i < res->res_num; i++) { - w0 = res->res_table[i].width; - h0 = res->res_table[i].height; - if (w0 < w1 || h0 < h1) - continue; - mismatch = abs(w0 * h1 - w1 * h0) * 8192 / w1 / h0; - if (mismatch > 8192 * AP1302_MAX_RATIO_MISMATCH / 100) - continue; - distance = (w0 * h1 + w1 * h0) * 8192 / w1 / h1; - if (distance < min_distance) { - min_distance = distance; - idx = i; - } - } - - return idx; -} - -static s32 ap1302_try_mbus_fmt_locked(struct v4l2_subdev *sd, - enum ap1302_contexts context, - struct v4l2_mbus_framefmt *fmt) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - struct ap1302_res_struct *res_table; - s32 res_num, idx = -1; - - res_table = dev->cntx_res[context].res_table; - res_num = dev->cntx_res[context].res_num; - - if ((fmt->width <= res_table[res_num - 1].width) && - (fmt->height <= res_table[res_num - 1].height)) - idx = ap1302_match_resolution(&dev->cntx_res[context], fmt); - if (idx == -1) - idx = res_num - 1; - - fmt->width = res_table[idx].width; - fmt->height = res_table[idx].height; - fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; - return idx; -} - - -static int ap1302_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) - -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct ap1302_device *dev = to_ap1302_device(sd); - enum ap1302_contexts context; - struct ap1302_res_struct *res_table; - s32 cur_res; - if (format->pad) - return -EINVAL; - mutex_lock(&dev->input_lock); - context = ap1302_get_context(sd); - res_table = dev->cntx_res[context].res_table; - cur_res = dev->cntx_res[context].cur_res; - fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; - fmt->width = res_table[cur_res].width; - fmt->height = res_table[cur_res].height; - mutex_unlock(&dev->input_lock); - return 0; -} - -static int ap1302_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct ap1302_device *dev = to_ap1302_device(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct atomisp_input_stream_info *stream_info = - (struct atomisp_input_stream_info *)fmt->reserved; - enum ap1302_contexts context, main_context; - if (format->pad) - return -EINVAL; - if (!fmt) - return -EINVAL; - mutex_lock(&dev->input_lock); - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - context = ap1302_get_context(sd); - ap1302_try_mbus_fmt_locked(sd, context, fmt); - cfg->try_fmt = *fmt; - mutex_unlock(&dev->input_lock); - return 0; - } - context = stream_to_context[stream_info->stream]; - dev_dbg(&client->dev, "ap1302_set_mbus_fmt. stream=%d context=%d\n", - stream_info->stream, context); - dev->cntx_res[context].cur_res = - ap1302_try_mbus_fmt_locked(sd, context, fmt); - dev->cntx_config[context].width = fmt->width; - dev->cntx_config[context].height = fmt->height; - ap1302_write_context_reg(sd, context, CNTX_WIDTH, AP1302_REG16); - ap1302_write_context_reg(sd, context, CNTX_HEIGHT, AP1302_REG16); - ap1302_read_context_reg(sd, context, CNTX_OUT_FMT, AP1302_REG16); - dev->cntx_config[context].out_fmt &= ~OUT_FMT_TYPE_MASK; - dev->cntx_config[context].out_fmt |= AP1302_FMT_UYVY422; - ap1302_write_context_reg(sd, context, CNTX_OUT_FMT, AP1302_REG16); - - main_context = ap1302_get_context(sd); - if (context == main_context) { - ap1302_read_context_reg(sd, context, - CNTX_MIPI_CTRL, AP1302_REG16); - dev->cntx_config[context].mipi_ctrl &= ~MIPI_CTRL_IMGVC_MASK; - dev->cntx_config[context].mipi_ctrl |= - (context << MIPI_CTRL_IMGVC_OFFSET); - dev->cntx_config[context].mipi_ctrl &= ~MIPI_CTRL_SSVC_MASK; - dev->cntx_config[context].mipi_ctrl |= - (context << MIPI_CTRL_SSVC_OFFSET); - dev->cntx_config[context].mipi_ctrl &= ~MIPI_CTRL_SSTYPE_MASK; - dev->cntx_config[context].mipi_ctrl |= - (0x12 << MIPI_CTRL_SSTYPE_OFFSET); - ap1302_write_context_reg(sd, context, - CNTX_MIPI_CTRL, AP1302_REG16); - ap1302_read_context_reg(sd, context, - CNTX_SS, AP1302_REG16); - dev->cntx_config[context].ss = AP1302_SS_CTRL; - ap1302_write_context_reg(sd, context, - CNTX_SS, AP1302_REG16); - } else { - /* Configure aux stream */ - ap1302_read_context_reg(sd, context, - CNTX_MIPI_II_CTRL, AP1302_REG16); - dev->cntx_config[context].mipi_ii_ctrl &= ~MIPI_CTRL_IMGVC_MASK; - dev->cntx_config[context].mipi_ii_ctrl |= - (context << MIPI_CTRL_IMGVC_OFFSET); - ap1302_write_context_reg(sd, context, - CNTX_MIPI_II_CTRL, AP1302_REG16); - if (stream_info->enable) { - ap1302_read_context_reg(sd, main_context, - CNTX_OUT_FMT, AP1302_REG16); - dev->cntx_config[context].out_fmt |= - (aux_stream_config[main_context][context] - << OUT_FMT_IIS_OFFSET); - ap1302_write_context_reg(sd, main_context, - CNTX_OUT_FMT, AP1302_REG16); - } - } - stream_info->ch_id = context; - mutex_unlock(&dev->input_lock); - - return 0; -} - - -static int ap1302_g_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - enum ap1302_contexts context; - struct ap1302_res_struct *res_table; - u32 cur_res; - - mutex_lock(&dev->input_lock); - context = ap1302_get_context(sd); - res_table = dev->cntx_res[context].res_table; - cur_res = dev->cntx_res[context].cur_res; - interval->interval.denominator = res_table[cur_res].fps; - interval->interval.numerator = 1; - mutex_unlock(&dev->input_lock); - return 0; -} - -static int ap1302_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - enum ap1302_contexts context; - struct ap1302_res_struct *res_table; - int index = fse->index; - - mutex_lock(&dev->input_lock); - context = ap1302_get_context(sd); - if (index >= dev->cntx_res[context].res_num) { - mutex_unlock(&dev->input_lock); - return -EINVAL; - } - - res_table = dev->cntx_res[context].res_table; - fse->min_width = res_table[index].width; - fse->min_height = res_table[index].height; - fse->max_width = res_table[index].width; - fse->max_height = res_table[index].height; - mutex_unlock(&dev->input_lock); - - return 0; -} - - -static int ap1302_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) -{ - *frames = 0; - return 0; -} - -static int ap1302_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - enum ap1302_contexts context; - u32 reg_val; - int ret; - - mutex_lock(&dev->input_lock); - context = ap1302_get_context(sd); - dev_dbg(&client->dev, "ap1302_s_stream. context=%d enable=%d\n", - context, enable); - /* Switch context */ - ap1302_i2c_read_reg(sd, REG_CTRL, - AP1302_REG16, ®_val); - reg_val &= ~CTRL_CNTX_MASK; - reg_val |= (context<dev, "Start stream. context=%d\n", context); - ap1302_dump_context_reg(sd, context); - if (!dev->sys_activated) { - reg_val = AP1302_SYS_ACTIVATE; - dev->sys_activated = 1; - } else { - reg_val = AP1302_SYS_SWITCH; - } - } else { - dev_info(&client->dev, "Stop stream. context=%d\n", context); - reg_val = AP1302_SYS_SWITCH; - } - ret = ap1302_i2c_write_reg(sd, REG_SYS_START, AP1302_REG16, reg_val); - if (ret) - dev_err(&client->dev, - "AP1302 set stream failed. enable=%d\n", enable); - mutex_unlock(&dev->input_lock); - return ret; -} - -static u16 ap1302_ev_values[] = {0xfd00, 0xfe80, 0x0, 0x180, 0x300}; - -static int ap1302_set_exposure_off(struct v4l2_subdev *sd, s32 val) -{ - val -= AP1302_MIN_EV; - return ap1302_i2c_write_reg(sd, REG_AE_BV_OFF, AP1302_REG16, - ap1302_ev_values[val]); -} - -static u16 ap1302_wb_values[] = { - 0, /* V4L2_WHITE_BALANCE_MANUAL */ - 0xf, /* V4L2_WHITE_BALANCE_AUTO */ - 0x2, /* V4L2_WHITE_BALANCE_INCANDESCENT */ - 0x4, /* V4L2_WHITE_BALANCE_FLUORESCENT */ - 0x5, /* V4L2_WHITE_BALANCE_FLUORESCENT_H */ - 0x1, /* V4L2_WHITE_BALANCE_HORIZON */ - 0x5, /* V4L2_WHITE_BALANCE_DAYLIGHT */ - 0xf, /* V4L2_WHITE_BALANCE_FLASH */ - 0x6, /* V4L2_WHITE_BALANCE_CLOUDY */ - 0x6, /* V4L2_WHITE_BALANCE_SHADE */ -}; - -static int ap1302_set_wb_mode(struct v4l2_subdev *sd, s32 val) -{ - int ret = 0; - u16 reg_val; - - ret = ap1302_i2c_read_reg(sd, REG_AWB_CTRL, AP1302_REG16, ®_val); - if (ret) - return ret; - reg_val &= ~AWB_CTRL_MODE_MASK; - reg_val |= ap1302_wb_values[val] << AWB_CTRL_MODE_OFFSET; - if (val == V4L2_WHITE_BALANCE_FLASH) - reg_val |= AWB_CTRL_FLASH_MASK; - else - reg_val &= ~AWB_CTRL_FLASH_MASK; - ret = ap1302_i2c_write_reg(sd, REG_AWB_CTRL, AP1302_REG16, reg_val); - return ret; -} - -static int ap1302_set_zoom(struct v4l2_subdev *sd, s32 val) -{ - ap1302_i2c_write_reg(sd, REG_DZ_TGT_FCT, AP1302_REG16, - val * 4 + 0x100); - return 0; -} - -static u16 ap1302_sfx_values[] = { - 0x00, /* V4L2_COLORFX_NONE */ - 0x03, /* V4L2_COLORFX_BW */ - 0x0d, /* V4L2_COLORFX_SEPIA */ - 0x07, /* V4L2_COLORFX_NEGATIVE */ - 0x04, /* V4L2_COLORFX_EMBOSS */ - 0x0f, /* V4L2_COLORFX_SKETCH */ - 0x08, /* V4L2_COLORFX_SKY_BLUE */ - 0x09, /* V4L2_COLORFX_GRASS_GREEN */ - 0x0a, /* V4L2_COLORFX_SKIN_WHITEN */ - 0x00, /* V4L2_COLORFX_VIVID */ - 0x00, /* V4L2_COLORFX_AQUA */ - 0x00, /* V4L2_COLORFX_ART_FREEZE */ - 0x00, /* V4L2_COLORFX_SILHOUETTE */ - 0x10, /* V4L2_COLORFX_SOLARIZATION */ - 0x02, /* V4L2_COLORFX_ANTIQUE */ - 0x00, /* V4L2_COLORFX_SET_CBCR */ -}; - -static int ap1302_set_special_effect(struct v4l2_subdev *sd, s32 val) -{ - ap1302_i2c_write_reg(sd, REG_SFX_MODE, AP1302_REG16, - ap1302_sfx_values[val]); - return 0; -} - -static u16 ap1302_scene_mode_values[] = { - 0x00, /* V4L2_SCENE_MODE_NONE */ - 0x07, /* V4L2_SCENE_MODE_BACKLIGHT */ - 0x0a, /* V4L2_SCENE_MODE_BEACH_SNOW */ - 0x06, /* V4L2_SCENE_MODE_CANDLE_LIGHT */ - 0x00, /* V4L2_SCENE_MODE_DAWN_DUSK */ - 0x00, /* V4L2_SCENE_MODE_FALL_COLORS */ - 0x0d, /* V4L2_SCENE_MODE_FIREWORKS */ - 0x02, /* V4L2_SCENE_MODE_LANDSCAPE */ - 0x05, /* V4L2_SCENE_MODE_NIGHT */ - 0x0c, /* V4L2_SCENE_MODE_PARTY_INDOOR */ - 0x01, /* V4L2_SCENE_MODE_PORTRAIT */ - 0x03, /* V4L2_SCENE_MODE_SPORTS */ - 0x0e, /* V4L2_SCENE_MODE_SUNSET */ - 0x0b, /* V4L2_SCENE_MODE_TEXT */ -}; - -static int ap1302_set_scene_mode(struct v4l2_subdev *sd, s32 val) -{ - ap1302_i2c_write_reg(sd, REG_SCENE_CTRL, AP1302_REG16, - ap1302_scene_mode_values[val]); - return 0; -} - -static u16 ap1302_flicker_values[] = { - 0x0, /* OFF */ - 0x3201, /* 50HZ */ - 0x3c01, /* 60HZ */ - 0x2 /* AUTO */ -}; - -static int ap1302_set_flicker_freq(struct v4l2_subdev *sd, s32 val) -{ - ap1302_i2c_write_reg(sd, REG_FLICK_CTRL, AP1302_REG16, - ap1302_flicker_values[val]); - return 0; -} - -static int ap1302_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ap1302_device *dev = container_of( - ctrl->handler, struct ap1302_device, ctrl_handler); - - switch (ctrl->id) { - case V4L2_CID_RUN_MODE: - dev->cur_context = ap1302_cntx_mapping[ctrl->val]; - break; - case V4L2_CID_EXPOSURE: - ap1302_set_exposure_off(&dev->sd, ctrl->val); - break; - case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: - ap1302_set_wb_mode(&dev->sd, ctrl->val); - break; - case V4L2_CID_ZOOM_ABSOLUTE: - ap1302_set_zoom(&dev->sd, ctrl->val); - break; - case V4L2_CID_COLORFX: - ap1302_set_special_effect(&dev->sd, ctrl->val); - break; - case V4L2_CID_SCENE_MODE: - ap1302_set_scene_mode(&dev->sd, ctrl->val); - break; - case V4L2_CID_POWER_LINE_FREQUENCY: - ap1302_set_flicker_freq(&dev->sd, ctrl->val); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int ap1302_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - int ret; - u32 reg_val; - - if (reg->size != AP1302_REG16 && - reg->size != AP1302_REG32) - return -EINVAL; - - mutex_lock(&dev->input_lock); - if (dev->power_on) - ret = ap1302_i2c_read_reg(sd, reg->reg, reg->size, ®_val); - else - ret = -EIO; - mutex_unlock(&dev->input_lock); - if (ret) - return ret; - - reg->val = reg_val; - - return 0; -} - -static int ap1302_s_register(struct v4l2_subdev *sd, - const struct v4l2_dbg_register *reg) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - int ret; - - if (reg->size != AP1302_REG16 && - reg->size != AP1302_REG32) - return -EINVAL; - - mutex_lock(&dev->input_lock); - if (dev->power_on) - ret = ap1302_i2c_write_reg(sd, reg->reg, reg->size, reg->val); - else - ret = -EIO; - mutex_unlock(&dev->input_lock); - return ret; -} - -static long ap1302_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - long ret = 0; - switch (cmd) { - case VIDIOC_DBG_G_REGISTER: - ret = ap1302_g_register(sd, arg); - break; - case VIDIOC_DBG_S_REGISTER: - ret = ap1302_s_register(sd, arg); - break; - default: - ret = -EINVAL; - } - return ret; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .s_ctrl = ap1302_s_ctrl, -}; - -static const char * const ctrl_run_mode_menu[] = { - NULL, - "Video", - "Still capture", - "Continuous capture", - "Preview", -}; - -static const struct v4l2_ctrl_config ctrls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_RUN_MODE, - .name = "Run Mode", - .type = V4L2_CTRL_TYPE_MENU, - .min = 1, - .def = 4, - .max = 4, - .qmenu = ctrl_run_mode_menu, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE, - .name = "Exposure", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = AP1302_MIN_EV, - .def = 0, - .max = AP1302_MAX_EV, - .step = 1, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, - .name = "White Balance", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .def = 0, - .max = 9, - .step = 1, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_ZOOM_ABSOLUTE, - .name = "Zoom Absolute", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .def = 0, - .max = 1024, - .step = 1, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_COLORFX, - .name = "Color Special Effect", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .def = 0, - .max = 15, - .step = 1, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_SCENE_MODE, - .name = "Scene Mode", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .def = 0, - .max = 13, - .step = 1, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .name = "Light frequency filter", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .def = 3, - .max = 3, - .step = 1, - }, -}; - -static const struct v4l2_subdev_sensor_ops ap1302_sensor_ops = { - .g_skip_frames = ap1302_g_skip_frames, -}; - -static const struct v4l2_subdev_video_ops ap1302_video_ops = { - .s_stream = ap1302_s_stream, - .g_frame_interval = ap1302_g_frame_interval, -}; - -static const struct v4l2_subdev_core_ops ap1302_core_ops = { - .s_power = ap1302_s_power, - .ioctl = ap1302_ioctl, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = ap1302_g_register, - .s_register = ap1302_s_register, -#endif -}; - -static const struct v4l2_subdev_pad_ops ap1302_pad_ops = { - .enum_mbus_code = ap1302_enum_mbus_code, - .enum_frame_size = ap1302_enum_frame_size, - .get_fmt = ap1302_get_fmt, - .set_fmt = ap1302_set_fmt, -}; - -static const struct v4l2_subdev_ops ap1302_ops = { - .core = &ap1302_core_ops, - .pad = &ap1302_pad_ops, - .video = &ap1302_video_ops, - .sensor = &ap1302_sensor_ops -}; - -static int ap1302_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ap1302_device *dev = to_ap1302_device(sd); - - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); - - release_firmware(dev->fw); - - media_entity_cleanup(&dev->sd.entity); - dev->platform_data->csi_cfg(sd, 0); - v4l2_device_unregister_subdev(sd); - - return 0; -} - -static int ap1302_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct ap1302_device *dev; - int ret; - unsigned int i; - - dev_info(&client->dev, "ap1302 probe called.\n"); - - /* allocate device & init sub device */ - dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "%s: out of memory\n", __func__); - return -ENOMEM; - } - - mutex_init(&dev->input_lock); - - v4l2_i2c_subdev_init(&(dev->sd), client, &ap1302_ops); - - ret = ap1302_request_firmware(&(dev->sd)); - if (ret) { - dev_err(&client->dev, "Cannot request ap1302 firmware.\n"); - goto out_free; - } - - dev->regmap16 = devm_regmap_init_i2c(client, &ap1302_reg16_config); - if (IS_ERR(dev->regmap16)) { - ret = PTR_ERR(dev->regmap16); - dev_err(&client->dev, - "Failed to allocate 16bit register map: %d\n", ret); - return ret; - } - - dev->regmap32 = devm_regmap_init_i2c(client, &ap1302_reg32_config); - if (IS_ERR(dev->regmap32)) { - ret = PTR_ERR(dev->regmap32); - dev_err(&client->dev, - "Failed to allocate 32bit register map: %d\n", ret); - return ret; - } - - if (client->dev.platform_data) { - ret = ap1302_s_config(&dev->sd, client->dev.platform_data); - if (ret) - goto out_free; - } - - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - - dev->cntx_res[CONTEXT_PREVIEW].res_num = ARRAY_SIZE(ap1302_preview_res); - dev->cntx_res[CONTEXT_PREVIEW].res_table = ap1302_preview_res; - dev->cntx_res[CONTEXT_SNAPSHOT].res_num = - ARRAY_SIZE(ap1302_snapshot_res); - dev->cntx_res[CONTEXT_SNAPSHOT].res_table = ap1302_snapshot_res; - dev->cntx_res[CONTEXT_VIDEO].res_num = ARRAY_SIZE(ap1302_video_res); - dev->cntx_res[CONTEXT_VIDEO].res_table = ap1302_video_res; - - ret = v4l2_ctrl_handler_init(&dev->ctrl_handler, ARRAY_SIZE(ctrls)); - if (ret) { - ap1302_remove(client); - return ret; - } - - for (i = 0; i < ARRAY_SIZE(ctrls); i++) - v4l2_ctrl_new_custom(&dev->ctrl_handler, &ctrls[i], NULL); - - if (dev->ctrl_handler.error) { - ap1302_remove(client); - return dev->ctrl_handler.error; - } - - /* Use same lock for controls as for everything else. */ - dev->ctrl_handler.lock = &dev->input_lock; - dev->sd.ctrl_handler = &dev->ctrl_handler; - v4l2_ctrl_handler_setup(&dev->ctrl_handler); - - dev->run_mode = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_RUN_MODE); - v4l2_ctrl_s_ctrl(dev->run_mode, ATOMISP_RUN_MODE_PREVIEW); - - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); - if (ret) - ap1302_remove(client); - return ret; -out_free: - v4l2_device_unregister_subdev(&dev->sd); - return ret; -} - -static const struct i2c_device_id ap1302_id[] = { - {AP1302_NAME, 0}, - {} -}; -MODULE_DEVICE_TABLE(i2c, ap1302_id); - -static struct i2c_driver ap1302_driver = { - .driver = { - .name = AP1302_NAME, - }, - .probe = ap1302_probe, - .remove = ap1302_remove, - .id_table = ap1302_id, -}; - -module_i2c_driver(ap1302_driver); - -MODULE_AUTHOR("Tianshu Qiu "); -MODULE_DESCRIPTION("AP1302 Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ap1302.c b/drivers/staging/media/atomisp/i2c/atomisp-ap1302.c new file mode 100644 index 000000000000..2f772a020c8b --- /dev/null +++ b/drivers/staging/media/atomisp/i2c/atomisp-ap1302.c @@ -0,0 +1,1255 @@ +/* + * + * Copyright (c) 2013 Intel Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "../include/linux/atomisp.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ap1302.h" + +#define to_ap1302_device(sub_dev) \ + container_of(sub_dev, struct ap1302_device, sd) + +/* Static definitions */ +static struct regmap_config ap1302_reg16_config = { + .reg_bits = 16, + .val_bits = 16, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, +}; + +static struct regmap_config ap1302_reg32_config = { + .reg_bits = 16, + .val_bits = 32, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, +}; + +static enum ap1302_contexts ap1302_cntx_mapping[] = { + CONTEXT_PREVIEW, /* Invalid atomisp run mode */ + CONTEXT_VIDEO, /* ATOMISP_RUN_MODE_VIDEO */ + CONTEXT_SNAPSHOT, /* ATOMISP_RUN_MODE_STILL_CAPTURE */ + CONTEXT_SNAPSHOT, /* ATOMISP_RUN_MODE_CONTINUOUS_CAPTURE */ + CONTEXT_PREVIEW, /* ATOMISP_RUN_MODE_PREVIEW */ +}; + +static struct ap1302_res_struct ap1302_preview_res[] = { + { + .width = 640, + .height = 480, + .fps = 30, + }, + { + .width = 720, + .height = 480, + .fps = 30, + }, + { + .width = 1280, + .height = 720, + .fps = 30, + }, + { + .width = 1920, + .height = 1080, + .fps = 30, + } +}; + +static struct ap1302_res_struct ap1302_snapshot_res[] = { + { + .width = 640, + .height = 480, + .fps = 30, + }, + { + .width = 720, + .height = 480, + .fps = 30, + }, + { + .width = 1280, + .height = 720, + .fps = 30, + }, + { + .width = 1920, + .height = 1080, + .fps = 30, + } +}; + +static struct ap1302_res_struct ap1302_video_res[] = { + { + .width = 640, + .height = 480, + .fps = 30, + }, + { + .width = 720, + .height = 480, + .fps = 30, + }, + { + .width = 1280, + .height = 720, + .fps = 30, + }, + { + .width = 1920, + .height = 1080, + .fps = 30, + } +}; + +static enum ap1302_contexts stream_to_context[] = { + CONTEXT_SNAPSHOT, + CONTEXT_PREVIEW, + CONTEXT_PREVIEW, + CONTEXT_VIDEO +}; + +static u16 aux_stream_config[CONTEXT_NUM][CONTEXT_NUM] = { + {0, 0, 0}, /* Preview: No aux streams. */ + {1, 0, 2}, /* Snapshot: 1 for postview. 2 for video */ + {1, 0, 0}, /* Video: 1 for preview. */ +}; + +static struct ap1302_context_info context_info[] = { + {CNTX_WIDTH, AP1302_REG16, "width"}, + {CNTX_HEIGHT, AP1302_REG16, "height"}, + {CNTX_ROI_X0, AP1302_REG16, "roi_x0"}, + {CNTX_ROI_X1, AP1302_REG16, "roi_x1"}, + {CNTX_ROI_Y0, AP1302_REG16, "roi_y0"}, + {CNTX_ROI_Y1, AP1302_REG16, "roi_y1"}, + {CNTX_ASPECT, AP1302_REG16, "aspect"}, + {CNTX_LOCK, AP1302_REG16, "lock"}, + {CNTX_ENABLE, AP1302_REG16, "enable"}, + {CNTX_OUT_FMT, AP1302_REG16, "out_fmt"}, + {CNTX_SENSOR_MODE, AP1302_REG16, "sensor_mode"}, + {CNTX_MIPI_CTRL, AP1302_REG16, "mipi_ctrl"}, + {CNTX_MIPI_II_CTRL, AP1302_REG16, "mipi_ii_ctrl"}, + {CNTX_LINE_TIME, AP1302_REG32, "line_time"}, + {CNTX_MAX_FPS, AP1302_REG16, "max_fps"}, + {CNTX_AE_USG, AP1302_REG16, "ae_usg"}, + {CNTX_AE_UPPER_ET, AP1302_REG32, "ae_upper_et"}, + {CNTX_AE_MAX_ET, AP1302_REG32, "ae_max_et"}, + {CNTX_SS, AP1302_REG16, "ss"}, + {CNTX_S1_SENSOR_MODE, AP1302_REG16, "s1_sensor_mode"}, + {CNTX_HINF_CTRL, AP1302_REG16, "hinf_ctrl"}, +}; + +/* This array stores the description list for metadata. + The metadata contains exposure settings and face + detection results. */ +static u16 ap1302_ss_list[] = { + 0xb01c, /* From 0x0186 with size 0x1C are exposure settings. */ + 0x0186, + 0xb002, /* 0x71c0 is for F-number */ + 0x71c0, + 0xb010, /* From 0x03dc with size 0x10 are face general infos. */ + 0x03dc, + 0xb0a0, /* From 0x03e4 with size 0xa0 are face detail infos. */ + 0x03e4, + 0xb020, /* From 0x0604 with size 0x20 are smile rate infos. */ + 0x0604, + 0x0000 +}; + +/* End of static definitions */ + +static int ap1302_i2c_read_reg(struct v4l2_subdev *sd, + u16 reg, u16 len, void *val) +{ + struct ap1302_device *dev = to_ap1302_device(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + if (len == AP1302_REG16) + ret = regmap_read(dev->regmap16, reg, val); + else if (len == AP1302_REG32) + ret = regmap_read(dev->regmap32, reg, val); + else + ret = -EINVAL; + if (ret) { + dev_dbg(&client->dev, "Read reg failed. reg=0x%04X\n", reg); + return ret; + } + if (len == AP1302_REG16) + dev_dbg(&client->dev, "read_reg[0x%04X] = 0x%04X\n", + reg, *(u16 *)val); + else + dev_dbg(&client->dev, "read_reg[0x%04X] = 0x%08X\n", + reg, *(u32 *)val); + return ret; +} + +static int ap1302_i2c_write_reg(struct v4l2_subdev *sd, + u16 reg, u16 len, u32 val) +{ + struct ap1302_device *dev = to_ap1302_device(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + if (len == AP1302_REG16) + ret = regmap_write(dev->regmap16, reg, val); + else if (len == AP1302_REG32) + ret = regmap_write(dev->regmap32, reg, val); + else + ret = -EINVAL; + if (ret) { + dev_dbg(&client->dev, "Write reg failed. reg=0x%04X\n", reg); + return ret; + } + if (len == AP1302_REG16) + dev_dbg(&client->dev, "write_reg[0x%04X] = 0x%04X\n", + reg, (u16)val); + else + dev_dbg(&client->dev, "write_reg[0x%04X] = 0x%08X\n", + reg, (u32)val); + return ret; +} + +static u16 +ap1302_calculate_context_reg_addr(enum ap1302_contexts context, u16 offset) +{ + u16 reg_addr; + /* The register offset is defined according to preview/video registers. + Preview and video context have the same register definition. + But snapshot context does not have register S1_SENSOR_MODE. + When setting snapshot registers, if the offset exceeds + S1_SENSOR_MODE, the actual offset needs to minus 2. */ + if (context == CONTEXT_SNAPSHOT) { + if (offset == CNTX_S1_SENSOR_MODE) + return 0; + if (offset > CNTX_S1_SENSOR_MODE) + offset -= 2; + } + if (context == CONTEXT_PREVIEW) + reg_addr = REG_PREVIEW_BASE + offset; + else if (context == CONTEXT_VIDEO) + reg_addr = REG_VIDEO_BASE + offset; + else + reg_addr = REG_SNAPSHOT_BASE + offset; + return reg_addr; +} + +static int ap1302_read_context_reg(struct v4l2_subdev *sd, + enum ap1302_contexts context, u16 offset, u16 len) +{ + struct ap1302_device *dev = to_ap1302_device(sd); + u16 reg_addr = ap1302_calculate_context_reg_addr(context, offset); + if (reg_addr == 0) + return -EINVAL; + return ap1302_i2c_read_reg(sd, reg_addr, len, + ((u8 *)&dev->cntx_config[context]) + offset); +} + +static int ap1302_write_context_reg(struct v4l2_subdev *sd, + enum ap1302_contexts context, u16 offset, u16 len) +{ + struct ap1302_device *dev = to_ap1302_device(sd); + u16 reg_addr = ap1302_calculate_context_reg_addr(context, offset); + if (reg_addr == 0) + return -EINVAL; + return ap1302_i2c_write_reg(sd, reg_addr, len, + *(u32 *)(((u8 *)&dev->cntx_config[context]) + offset)); +} + +static int ap1302_dump_context_reg(struct v4l2_subdev *sd, + enum ap1302_contexts context) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ap1302_device *dev = to_ap1302_device(sd); + int i; + dev_dbg(&client->dev, "Dump registers for context[%d]:\n", context); + for (i = 0; i < ARRAY_SIZE(context_info); i++) { + struct ap1302_context_info *info = &context_info[i]; + u8 *var = (u8 *)&dev->cntx_config[context] + info->offset; + /* Snapshot context does not have s1_sensor_mode register. */ + if (context == CONTEXT_SNAPSHOT && + info->offset == CNTX_S1_SENSOR_MODE) + continue; + ap1302_read_context_reg(sd, context, info->offset, info->len); + if (info->len == AP1302_REG16) + dev_dbg(&client->dev, "context.%s = 0x%04X (%d)\n", + info->name, *(u16 *)var, *(u16 *)var); + else + dev_dbg(&client->dev, "context.%s = 0x%08X (%d)\n", + info->name, *(u32 *)var, *(u32 *)var); + } + return 0; +} + +static int ap1302_request_firmware(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ap1302_device *dev = to_ap1302_device(sd); + int ret; + ret = request_firmware(&dev->fw, "ap1302_fw.bin", &client->dev); + if (ret) + dev_err(&client->dev, + "ap1302_request_firmware failed. ret=%d\n", ret); + return ret; +} + +/* When loading firmware, host writes firmware data from address 0x8000. + When the address reaches 0x9FFF, the next address should return to 0x8000. + This function handles this address window and load firmware data to AP1302. + win_pos indicates the offset within this window. Firmware loading procedure + may call this function several times. win_pos records the current position + that has been written to.*/ +static int ap1302_write_fw_window(struct v4l2_subdev *sd, + u16 *win_pos, const u8 *buf, u32 len) +{ + struct ap1302_device *dev = to_ap1302_device(sd); + int ret; + u32 pos; + u32 sub_len; + for (pos = 0; pos < len; pos += sub_len) { + if (len - pos < AP1302_FW_WINDOW_SIZE - *win_pos) + sub_len = len - pos; + else + sub_len = AP1302_FW_WINDOW_SIZE - *win_pos; + ret = regmap_raw_write(dev->regmap16, + *win_pos + AP1302_FW_WINDOW_OFFSET, + buf + pos, sub_len); + if (ret) + return ret; + *win_pos += sub_len; + if (*win_pos >= AP1302_FW_WINDOW_SIZE) + *win_pos = 0; + } + return 0; +} + +static int ap1302_load_firmware(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ap1302_device *dev = to_ap1302_device(sd); + const struct ap1302_firmware *fw; + const u8 *fw_data; + u16 reg_val = 0; + u16 win_pos = 0; + int ret; + + dev_info(&client->dev, "Start to load firmware.\n"); + if (!dev->fw) { + dev_err(&client->dev, "firmware not requested.\n"); + return -EINVAL; + } + fw = (const struct ap1302_firmware *) dev->fw->data; + if (dev->fw->size != (sizeof(*fw) + fw->total_size)) { + dev_err(&client->dev, "firmware size does not match.\n"); + return -EINVAL; + } + /* The fw binary contains a header of struct ap1302_firmware. + Following the header is the bootdata of AP1302. + The bootdata pointer can be referenced as &fw[1]. */ + fw_data = (u8 *)&fw[1]; + + /* Clear crc register. */ + ret = ap1302_i2c_write_reg(sd, REG_SIP_CRC, AP1302_REG16, 0xFFFF); + if (ret) + return ret; + + /* Load FW data for PLL init stage. */ + ret = ap1302_write_fw_window(sd, &win_pos, fw_data, fw->pll_init_size); + if (ret) + return ret; + + /* Write 2 to bootdata_stage register to apply basic_init_hp + settings and enable PLL. */ + ret = ap1302_i2c_write_reg(sd, REG_BOOTDATA_STAGE, + AP1302_REG16, 0x0002); + if (ret) + return ret; + + /* Wait 1ms for PLL to lock. */ + msleep(20); + + /* Load the rest of bootdata content. */ + ret = ap1302_write_fw_window(sd, &win_pos, fw_data + fw->pll_init_size, + fw->total_size - fw->pll_init_size); + if (ret) + return ret; + + /* Check crc. */ + ret = ap1302_i2c_read_reg(sd, REG_SIP_CRC, AP1302_REG16, ®_val); + if (ret) + return ret; + if (reg_val != fw->crc) { + dev_err(&client->dev, + "crc does not match. T:0x%04X F:0x%04X\n", + fw->crc, reg_val); + return -EAGAIN; + } + + /* Write 0xFFFF to bootdata_stage register to indicate AP1302 that + the whole bootdata content has been loaded. */ + ret = ap1302_i2c_write_reg(sd, REG_BOOTDATA_STAGE, + AP1302_REG16, 0xFFFF); + if (ret) + return ret; + dev_info(&client->dev, "Load firmware successfully.\n"); + + return 0; +} + +static int __ap1302_s_power(struct v4l2_subdev *sd, int on, int load_fw) +{ + struct ap1302_device *dev = to_ap1302_device(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret, i; + u16 ss_ptr; + + dev_info(&client->dev, "ap1302_s_power is called.\n"); + ret = dev->platform_data->power_ctrl(sd, on); + if (ret) { + dev_err(&client->dev, + "ap1302_s_power error. on=%d ret=%d\n", on, ret); + return ret; + } + dev->power_on = on; + if (!on || !load_fw) + return 0; + /* Load firmware after power on. */ + ret = ap1302_load_firmware(sd); + if (ret) { + dev_err(&client->dev, + "ap1302_load_firmware failed. ret=%d\n", ret); + return ret; + } + ret = ap1302_i2c_read_reg(sd, REG_SS_HEAD_PT0, AP1302_REG16, &ss_ptr); + if (ret) + return ret; + for (i = 0; i < ARRAY_SIZE(ap1302_ss_list); i++) { + ret = ap1302_i2c_write_reg(sd, ss_ptr + i * 2, + AP1302_REG16, ap1302_ss_list[i]); + if (ret) + return ret; + } + return ret; +} + +static int ap1302_s_power(struct v4l2_subdev *sd, int on) +{ + struct ap1302_device *dev = to_ap1302_device(sd); + int ret; + + mutex_lock(&dev->input_lock); + ret = __ap1302_s_power(sd, on, 1); + dev->sys_activated = 0; + mutex_unlock(&dev->input_lock); + + return ret; +} + +static int ap1302_s_config(struct v4l2_subdev *sd, void *pdata) +{ + struct ap1302_device *dev = to_ap1302_device(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct camera_mipi_info *mipi_info; + u16 reg_val = 0; + int ret; + + dev_info(&client->dev, "ap1302_s_config is called.\n"); + if (pdata == NULL) + return -ENODEV; + + dev->platform_data = pdata; + + mutex_lock(&dev->input_lock); + + if (dev->platform_data->platform_init) { + ret = dev->platform_data->platform_init(client); + if (ret) + goto fail_power; + } + + ret = __ap1302_s_power(sd, 1, 0); + if (ret) + goto fail_power; + + /* Detect for AP1302 */ + ret = ap1302_i2c_read_reg(sd, REG_CHIP_VERSION, AP1302_REG16, ®_val); + if (ret || (reg_val != AP1302_CHIP_ID)) { + dev_err(&client->dev, + "Chip version does no match. ret=%d ver=0x%04x\n", + ret, reg_val); + goto fail_config; + } + dev_info(&client->dev, "AP1302 Chip ID is 0x%X\n", reg_val); + + /* Detect revision for AP1302 */ + ret = ap1302_i2c_read_reg(sd, REG_CHIP_REV, AP1302_REG16, ®_val); + if (ret) + goto fail_config; + dev_info(&client->dev, "AP1302 Chip Rev is 0x%X\n", reg_val); + ret = dev->platform_data->csi_cfg(sd, 1); + if (ret) + goto fail_config; + + mipi_info = v4l2_get_subdev_hostdata(sd); + if (!mipi_info) + goto fail_config; + dev->num_lanes = mipi_info->num_lanes; + + ret = __ap1302_s_power(sd, 0, 0); + if (ret) + goto fail_power; + + mutex_unlock(&dev->input_lock); + + return ret; + +fail_config: + __ap1302_s_power(sd, 0, 0); +fail_power: + mutex_unlock(&dev->input_lock); + dev_err(&client->dev, "ap1302_s_config failed\n"); + return ret; +} + +static enum ap1302_contexts ap1302_get_context(struct v4l2_subdev *sd) +{ + struct ap1302_device *dev = to_ap1302_device(sd); + return dev->cur_context; +} + +static int ap1302_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_UYVY8_1X16; + + return 0; +} + +static int ap1302_match_resolution(struct ap1302_context_res *res, + struct v4l2_mbus_framefmt *fmt) +{ + s32 w0, h0, mismatch, distance; + s32 w1 = fmt->width; + s32 h1 = fmt->height; + s32 min_distance = INT_MAX; + s32 i, idx = -1; + + if (w1 == 0 || h1 == 0) + return -1; + + for (i = 0; i < res->res_num; i++) { + w0 = res->res_table[i].width; + h0 = res->res_table[i].height; + if (w0 < w1 || h0 < h1) + continue; + mismatch = abs(w0 * h1 - w1 * h0) * 8192 / w1 / h0; + if (mismatch > 8192 * AP1302_MAX_RATIO_MISMATCH / 100) + continue; + distance = (w0 * h1 + w1 * h0) * 8192 / w1 / h1; + if (distance < min_distance) { + min_distance = distance; + idx = i; + } + } + + return idx; +} + +static s32 ap1302_try_mbus_fmt_locked(struct v4l2_subdev *sd, + enum ap1302_contexts context, + struct v4l2_mbus_framefmt *fmt) +{ + struct ap1302_device *dev = to_ap1302_device(sd); + struct ap1302_res_struct *res_table; + s32 res_num, idx = -1; + + res_table = dev->cntx_res[context].res_table; + res_num = dev->cntx_res[context].res_num; + + if ((fmt->width <= res_table[res_num - 1].width) && + (fmt->height <= res_table[res_num - 1].height)) + idx = ap1302_match_resolution(&dev->cntx_res[context], fmt); + if (idx == -1) + idx = res_num - 1; + + fmt->width = res_table[idx].width; + fmt->height = res_table[idx].height; + fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; + return idx; +} + + +static int ap1302_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) + +{ + struct v4l2_mbus_framefmt *fmt = &format->format; + struct ap1302_device *dev = to_ap1302_device(sd); + enum ap1302_contexts context; + struct ap1302_res_struct *res_table; + s32 cur_res; + if (format->pad) + return -EINVAL; + mutex_lock(&dev->input_lock); + context = ap1302_get_context(sd); + res_table = dev->cntx_res[context].res_table; + cur_res = dev->cntx_res[context].cur_res; + fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; + fmt->width = res_table[cur_res].width; + fmt->height = res_table[cur_res].height; + mutex_unlock(&dev->input_lock); + return 0; +} + +static int ap1302_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt = &format->format; + struct ap1302_device *dev = to_ap1302_device(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct atomisp_input_stream_info *stream_info = + (struct atomisp_input_stream_info *)fmt->reserved; + enum ap1302_contexts context, main_context; + if (format->pad) + return -EINVAL; + if (!fmt) + return -EINVAL; + mutex_lock(&dev->input_lock); + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + context = ap1302_get_context(sd); + ap1302_try_mbus_fmt_locked(sd, context, fmt); + cfg->try_fmt = *fmt; + mutex_unlock(&dev->input_lock); + return 0; + } + context = stream_to_context[stream_info->stream]; + dev_dbg(&client->dev, "ap1302_set_mbus_fmt. stream=%d context=%d\n", + stream_info->stream, context); + dev->cntx_res[context].cur_res = + ap1302_try_mbus_fmt_locked(sd, context, fmt); + dev->cntx_config[context].width = fmt->width; + dev->cntx_config[context].height = fmt->height; + ap1302_write_context_reg(sd, context, CNTX_WIDTH, AP1302_REG16); + ap1302_write_context_reg(sd, context, CNTX_HEIGHT, AP1302_REG16); + ap1302_read_context_reg(sd, context, CNTX_OUT_FMT, AP1302_REG16); + dev->cntx_config[context].out_fmt &= ~OUT_FMT_TYPE_MASK; + dev->cntx_config[context].out_fmt |= AP1302_FMT_UYVY422; + ap1302_write_context_reg(sd, context, CNTX_OUT_FMT, AP1302_REG16); + + main_context = ap1302_get_context(sd); + if (context == main_context) { + ap1302_read_context_reg(sd, context, + CNTX_MIPI_CTRL, AP1302_REG16); + dev->cntx_config[context].mipi_ctrl &= ~MIPI_CTRL_IMGVC_MASK; + dev->cntx_config[context].mipi_ctrl |= + (context << MIPI_CTRL_IMGVC_OFFSET); + dev->cntx_config[context].mipi_ctrl &= ~MIPI_CTRL_SSVC_MASK; + dev->cntx_config[context].mipi_ctrl |= + (context << MIPI_CTRL_SSVC_OFFSET); + dev->cntx_config[context].mipi_ctrl &= ~MIPI_CTRL_SSTYPE_MASK; + dev->cntx_config[context].mipi_ctrl |= + (0x12 << MIPI_CTRL_SSTYPE_OFFSET); + ap1302_write_context_reg(sd, context, + CNTX_MIPI_CTRL, AP1302_REG16); + ap1302_read_context_reg(sd, context, + CNTX_SS, AP1302_REG16); + dev->cntx_config[context].ss = AP1302_SS_CTRL; + ap1302_write_context_reg(sd, context, + CNTX_SS, AP1302_REG16); + } else { + /* Configure aux stream */ + ap1302_read_context_reg(sd, context, + CNTX_MIPI_II_CTRL, AP1302_REG16); + dev->cntx_config[context].mipi_ii_ctrl &= ~MIPI_CTRL_IMGVC_MASK; + dev->cntx_config[context].mipi_ii_ctrl |= + (context << MIPI_CTRL_IMGVC_OFFSET); + ap1302_write_context_reg(sd, context, + CNTX_MIPI_II_CTRL, AP1302_REG16); + if (stream_info->enable) { + ap1302_read_context_reg(sd, main_context, + CNTX_OUT_FMT, AP1302_REG16); + dev->cntx_config[context].out_fmt |= + (aux_stream_config[main_context][context] + << OUT_FMT_IIS_OFFSET); + ap1302_write_context_reg(sd, main_context, + CNTX_OUT_FMT, AP1302_REG16); + } + } + stream_info->ch_id = context; + mutex_unlock(&dev->input_lock); + + return 0; +} + + +static int ap1302_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct ap1302_device *dev = to_ap1302_device(sd); + enum ap1302_contexts context; + struct ap1302_res_struct *res_table; + u32 cur_res; + + mutex_lock(&dev->input_lock); + context = ap1302_get_context(sd); + res_table = dev->cntx_res[context].res_table; + cur_res = dev->cntx_res[context].cur_res; + interval->interval.denominator = res_table[cur_res].fps; + interval->interval.numerator = 1; + mutex_unlock(&dev->input_lock); + return 0; +} + +static int ap1302_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct ap1302_device *dev = to_ap1302_device(sd); + enum ap1302_contexts context; + struct ap1302_res_struct *res_table; + int index = fse->index; + + mutex_lock(&dev->input_lock); + context = ap1302_get_context(sd); + if (index >= dev->cntx_res[context].res_num) { + mutex_unlock(&dev->input_lock); + return -EINVAL; + } + + res_table = dev->cntx_res[context].res_table; + fse->min_width = res_table[index].width; + fse->min_height = res_table[index].height; + fse->max_width = res_table[index].width; + fse->max_height = res_table[index].height; + mutex_unlock(&dev->input_lock); + + return 0; +} + + +static int ap1302_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) +{ + *frames = 0; + return 0; +} + +static int ap1302_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct ap1302_device *dev = to_ap1302_device(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + enum ap1302_contexts context; + u32 reg_val; + int ret; + + mutex_lock(&dev->input_lock); + context = ap1302_get_context(sd); + dev_dbg(&client->dev, "ap1302_s_stream. context=%d enable=%d\n", + context, enable); + /* Switch context */ + ap1302_i2c_read_reg(sd, REG_CTRL, + AP1302_REG16, ®_val); + reg_val &= ~CTRL_CNTX_MASK; + reg_val |= (context<dev, "Start stream. context=%d\n", context); + ap1302_dump_context_reg(sd, context); + if (!dev->sys_activated) { + reg_val = AP1302_SYS_ACTIVATE; + dev->sys_activated = 1; + } else { + reg_val = AP1302_SYS_SWITCH; + } + } else { + dev_info(&client->dev, "Stop stream. context=%d\n", context); + reg_val = AP1302_SYS_SWITCH; + } + ret = ap1302_i2c_write_reg(sd, REG_SYS_START, AP1302_REG16, reg_val); + if (ret) + dev_err(&client->dev, + "AP1302 set stream failed. enable=%d\n", enable); + mutex_unlock(&dev->input_lock); + return ret; +} + +static u16 ap1302_ev_values[] = {0xfd00, 0xfe80, 0x0, 0x180, 0x300}; + +static int ap1302_set_exposure_off(struct v4l2_subdev *sd, s32 val) +{ + val -= AP1302_MIN_EV; + return ap1302_i2c_write_reg(sd, REG_AE_BV_OFF, AP1302_REG16, + ap1302_ev_values[val]); +} + +static u16 ap1302_wb_values[] = { + 0, /* V4L2_WHITE_BALANCE_MANUAL */ + 0xf, /* V4L2_WHITE_BALANCE_AUTO */ + 0x2, /* V4L2_WHITE_BALANCE_INCANDESCENT */ + 0x4, /* V4L2_WHITE_BALANCE_FLUORESCENT */ + 0x5, /* V4L2_WHITE_BALANCE_FLUORESCENT_H */ + 0x1, /* V4L2_WHITE_BALANCE_HORIZON */ + 0x5, /* V4L2_WHITE_BALANCE_DAYLIGHT */ + 0xf, /* V4L2_WHITE_BALANCE_FLASH */ + 0x6, /* V4L2_WHITE_BALANCE_CLOUDY */ + 0x6, /* V4L2_WHITE_BALANCE_SHADE */ +}; + +static int ap1302_set_wb_mode(struct v4l2_subdev *sd, s32 val) +{ + int ret = 0; + u16 reg_val; + + ret = ap1302_i2c_read_reg(sd, REG_AWB_CTRL, AP1302_REG16, ®_val); + if (ret) + return ret; + reg_val &= ~AWB_CTRL_MODE_MASK; + reg_val |= ap1302_wb_values[val] << AWB_CTRL_MODE_OFFSET; + if (val == V4L2_WHITE_BALANCE_FLASH) + reg_val |= AWB_CTRL_FLASH_MASK; + else + reg_val &= ~AWB_CTRL_FLASH_MASK; + ret = ap1302_i2c_write_reg(sd, REG_AWB_CTRL, AP1302_REG16, reg_val); + return ret; +} + +static int ap1302_set_zoom(struct v4l2_subdev *sd, s32 val) +{ + ap1302_i2c_write_reg(sd, REG_DZ_TGT_FCT, AP1302_REG16, + val * 4 + 0x100); + return 0; +} + +static u16 ap1302_sfx_values[] = { + 0x00, /* V4L2_COLORFX_NONE */ + 0x03, /* V4L2_COLORFX_BW */ + 0x0d, /* V4L2_COLORFX_SEPIA */ + 0x07, /* V4L2_COLORFX_NEGATIVE */ + 0x04, /* V4L2_COLORFX_EMBOSS */ + 0x0f, /* V4L2_COLORFX_SKETCH */ + 0x08, /* V4L2_COLORFX_SKY_BLUE */ + 0x09, /* V4L2_COLORFX_GRASS_GREEN */ + 0x0a, /* V4L2_COLORFX_SKIN_WHITEN */ + 0x00, /* V4L2_COLORFX_VIVID */ + 0x00, /* V4L2_COLORFX_AQUA */ + 0x00, /* V4L2_COLORFX_ART_FREEZE */ + 0x00, /* V4L2_COLORFX_SILHOUETTE */ + 0x10, /* V4L2_COLORFX_SOLARIZATION */ + 0x02, /* V4L2_COLORFX_ANTIQUE */ + 0x00, /* V4L2_COLORFX_SET_CBCR */ +}; + +static int ap1302_set_special_effect(struct v4l2_subdev *sd, s32 val) +{ + ap1302_i2c_write_reg(sd, REG_SFX_MODE, AP1302_REG16, + ap1302_sfx_values[val]); + return 0; +} + +static u16 ap1302_scene_mode_values[] = { + 0x00, /* V4L2_SCENE_MODE_NONE */ + 0x07, /* V4L2_SCENE_MODE_BACKLIGHT */ + 0x0a, /* V4L2_SCENE_MODE_BEACH_SNOW */ + 0x06, /* V4L2_SCENE_MODE_CANDLE_LIGHT */ + 0x00, /* V4L2_SCENE_MODE_DAWN_DUSK */ + 0x00, /* V4L2_SCENE_MODE_FALL_COLORS */ + 0x0d, /* V4L2_SCENE_MODE_FIREWORKS */ + 0x02, /* V4L2_SCENE_MODE_LANDSCAPE */ + 0x05, /* V4L2_SCENE_MODE_NIGHT */ + 0x0c, /* V4L2_SCENE_MODE_PARTY_INDOOR */ + 0x01, /* V4L2_SCENE_MODE_PORTRAIT */ + 0x03, /* V4L2_SCENE_MODE_SPORTS */ + 0x0e, /* V4L2_SCENE_MODE_SUNSET */ + 0x0b, /* V4L2_SCENE_MODE_TEXT */ +}; + +static int ap1302_set_scene_mode(struct v4l2_subdev *sd, s32 val) +{ + ap1302_i2c_write_reg(sd, REG_SCENE_CTRL, AP1302_REG16, + ap1302_scene_mode_values[val]); + return 0; +} + +static u16 ap1302_flicker_values[] = { + 0x0, /* OFF */ + 0x3201, /* 50HZ */ + 0x3c01, /* 60HZ */ + 0x2 /* AUTO */ +}; + +static int ap1302_set_flicker_freq(struct v4l2_subdev *sd, s32 val) +{ + ap1302_i2c_write_reg(sd, REG_FLICK_CTRL, AP1302_REG16, + ap1302_flicker_values[val]); + return 0; +} + +static int ap1302_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ap1302_device *dev = container_of( + ctrl->handler, struct ap1302_device, ctrl_handler); + + switch (ctrl->id) { + case V4L2_CID_RUN_MODE: + dev->cur_context = ap1302_cntx_mapping[ctrl->val]; + break; + case V4L2_CID_EXPOSURE: + ap1302_set_exposure_off(&dev->sd, ctrl->val); + break; + case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: + ap1302_set_wb_mode(&dev->sd, ctrl->val); + break; + case V4L2_CID_ZOOM_ABSOLUTE: + ap1302_set_zoom(&dev->sd, ctrl->val); + break; + case V4L2_CID_COLORFX: + ap1302_set_special_effect(&dev->sd, ctrl->val); + break; + case V4L2_CID_SCENE_MODE: + ap1302_set_scene_mode(&dev->sd, ctrl->val); + break; + case V4L2_CID_POWER_LINE_FREQUENCY: + ap1302_set_flicker_freq(&dev->sd, ctrl->val); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ap1302_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct ap1302_device *dev = to_ap1302_device(sd); + int ret; + u32 reg_val; + + if (reg->size != AP1302_REG16 && + reg->size != AP1302_REG32) + return -EINVAL; + + mutex_lock(&dev->input_lock); + if (dev->power_on) + ret = ap1302_i2c_read_reg(sd, reg->reg, reg->size, ®_val); + else + ret = -EIO; + mutex_unlock(&dev->input_lock); + if (ret) + return ret; + + reg->val = reg_val; + + return 0; +} + +static int ap1302_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) +{ + struct ap1302_device *dev = to_ap1302_device(sd); + int ret; + + if (reg->size != AP1302_REG16 && + reg->size != AP1302_REG32) + return -EINVAL; + + mutex_lock(&dev->input_lock); + if (dev->power_on) + ret = ap1302_i2c_write_reg(sd, reg->reg, reg->size, reg->val); + else + ret = -EIO; + mutex_unlock(&dev->input_lock); + return ret; +} + +static long ap1302_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + long ret = 0; + switch (cmd) { + case VIDIOC_DBG_G_REGISTER: + ret = ap1302_g_register(sd, arg); + break; + case VIDIOC_DBG_S_REGISTER: + ret = ap1302_s_register(sd, arg); + break; + default: + ret = -EINVAL; + } + return ret; +} + +static const struct v4l2_ctrl_ops ctrl_ops = { + .s_ctrl = ap1302_s_ctrl, +}; + +static const char * const ctrl_run_mode_menu[] = { + NULL, + "Video", + "Still capture", + "Continuous capture", + "Preview", +}; + +static const struct v4l2_ctrl_config ctrls[] = { + { + .ops = &ctrl_ops, + .id = V4L2_CID_RUN_MODE, + .name = "Run Mode", + .type = V4L2_CTRL_TYPE_MENU, + .min = 1, + .def = 4, + .max = 4, + .qmenu = ctrl_run_mode_menu, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_EXPOSURE, + .name = "Exposure", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = AP1302_MIN_EV, + .def = 0, + .max = AP1302_MAX_EV, + .step = 1, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, + .name = "White Balance", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .def = 0, + .max = 9, + .step = 1, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_ZOOM_ABSOLUTE, + .name = "Zoom Absolute", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .def = 0, + .max = 1024, + .step = 1, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_COLORFX, + .name = "Color Special Effect", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .def = 0, + .max = 15, + .step = 1, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_SCENE_MODE, + .name = "Scene Mode", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .def = 0, + .max = 13, + .step = 1, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .name = "Light frequency filter", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .def = 3, + .max = 3, + .step = 1, + }, +}; + +static const struct v4l2_subdev_sensor_ops ap1302_sensor_ops = { + .g_skip_frames = ap1302_g_skip_frames, +}; + +static const struct v4l2_subdev_video_ops ap1302_video_ops = { + .s_stream = ap1302_s_stream, + .g_frame_interval = ap1302_g_frame_interval, +}; + +static const struct v4l2_subdev_core_ops ap1302_core_ops = { + .s_power = ap1302_s_power, + .ioctl = ap1302_ioctl, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = ap1302_g_register, + .s_register = ap1302_s_register, +#endif +}; + +static const struct v4l2_subdev_pad_ops ap1302_pad_ops = { + .enum_mbus_code = ap1302_enum_mbus_code, + .enum_frame_size = ap1302_enum_frame_size, + .get_fmt = ap1302_get_fmt, + .set_fmt = ap1302_set_fmt, +}; + +static const struct v4l2_subdev_ops ap1302_ops = { + .core = &ap1302_core_ops, + .pad = &ap1302_pad_ops, + .video = &ap1302_video_ops, + .sensor = &ap1302_sensor_ops +}; + +static int ap1302_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ap1302_device *dev = to_ap1302_device(sd); + + if (dev->platform_data->platform_deinit) + dev->platform_data->platform_deinit(); + + release_firmware(dev->fw); + + media_entity_cleanup(&dev->sd.entity); + dev->platform_data->csi_cfg(sd, 0); + v4l2_device_unregister_subdev(sd); + + return 0; +} + +static int ap1302_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ap1302_device *dev; + int ret; + unsigned int i; + + dev_info(&client->dev, "ap1302 probe called.\n"); + + /* allocate device & init sub device */ + dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) { + dev_err(&client->dev, "%s: out of memory\n", __func__); + return -ENOMEM; + } + + mutex_init(&dev->input_lock); + + v4l2_i2c_subdev_init(&(dev->sd), client, &ap1302_ops); + + ret = ap1302_request_firmware(&(dev->sd)); + if (ret) { + dev_err(&client->dev, "Cannot request ap1302 firmware.\n"); + goto out_free; + } + + dev->regmap16 = devm_regmap_init_i2c(client, &ap1302_reg16_config); + if (IS_ERR(dev->regmap16)) { + ret = PTR_ERR(dev->regmap16); + dev_err(&client->dev, + "Failed to allocate 16bit register map: %d\n", ret); + return ret; + } + + dev->regmap32 = devm_regmap_init_i2c(client, &ap1302_reg32_config); + if (IS_ERR(dev->regmap32)) { + ret = PTR_ERR(dev->regmap32); + dev_err(&client->dev, + "Failed to allocate 32bit register map: %d\n", ret); + return ret; + } + + if (client->dev.platform_data) { + ret = ap1302_s_config(&dev->sd, client->dev.platform_data); + if (ret) + goto out_free; + } + + dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + dev->pad.flags = MEDIA_PAD_FL_SOURCE; + dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + dev->cntx_res[CONTEXT_PREVIEW].res_num = ARRAY_SIZE(ap1302_preview_res); + dev->cntx_res[CONTEXT_PREVIEW].res_table = ap1302_preview_res; + dev->cntx_res[CONTEXT_SNAPSHOT].res_num = + ARRAY_SIZE(ap1302_snapshot_res); + dev->cntx_res[CONTEXT_SNAPSHOT].res_table = ap1302_snapshot_res; + dev->cntx_res[CONTEXT_VIDEO].res_num = ARRAY_SIZE(ap1302_video_res); + dev->cntx_res[CONTEXT_VIDEO].res_table = ap1302_video_res; + + ret = v4l2_ctrl_handler_init(&dev->ctrl_handler, ARRAY_SIZE(ctrls)); + if (ret) { + ap1302_remove(client); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(ctrls); i++) + v4l2_ctrl_new_custom(&dev->ctrl_handler, &ctrls[i], NULL); + + if (dev->ctrl_handler.error) { + ap1302_remove(client); + return dev->ctrl_handler.error; + } + + /* Use same lock for controls as for everything else. */ + dev->ctrl_handler.lock = &dev->input_lock; + dev->sd.ctrl_handler = &dev->ctrl_handler; + v4l2_ctrl_handler_setup(&dev->ctrl_handler); + + dev->run_mode = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_RUN_MODE); + v4l2_ctrl_s_ctrl(dev->run_mode, ATOMISP_RUN_MODE_PREVIEW); + + ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); + if (ret) + ap1302_remove(client); + return ret; +out_free: + v4l2_device_unregister_subdev(&dev->sd); + return ret; +} + +static const struct i2c_device_id ap1302_id[] = { + {AP1302_NAME, 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, ap1302_id); + +static struct i2c_driver ap1302_driver = { + .driver = { + .name = AP1302_NAME, + }, + .probe = ap1302_probe, + .remove = ap1302_remove, + .id_table = ap1302_id, +}; + +module_i2c_driver(ap1302_driver); + +MODULE_AUTHOR("Tianshu Qiu "); +MODULE_DESCRIPTION("AP1302 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c new file mode 100644 index 000000000000..35ed51ffe944 --- /dev/null +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c @@ -0,0 +1,1490 @@ +/* + * Support for GalaxyCore GC0310 VGA camera sensor. + * + * Copyright (c) 2013 Intel Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/linux/atomisp_gmin_platform.h" + +#include "gc0310.h" + +/* i2c read/write stuff */ +static int gc0310_read_reg(struct i2c_client *client, + u16 data_length, u8 reg, u8 *val) +{ + int err; + struct i2c_msg msg[2]; + unsigned char data[1]; + + if (!client->adapter) { + dev_err(&client->dev, "%s error, no client->adapter\n", + __func__); + return -ENODEV; + } + + if (data_length != GC0310_8BIT) { + dev_err(&client->dev, "%s error, invalid data length\n", + __func__); + return -EINVAL; + } + + memset(msg, 0, sizeof(msg)); + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = I2C_MSG_LENGTH; + msg[0].buf = data; + + /* high byte goes out first */ + data[0] = (u8)(reg & 0xff); + + msg[1].addr = client->addr; + msg[1].len = data_length; + msg[1].flags = I2C_M_RD; + msg[1].buf = data; + + err = i2c_transfer(client->adapter, msg, 2); + if (err != 2) { + if (err >= 0) + err = -EIO; + dev_err(&client->dev, + "read from offset 0x%x error %d", reg, err); + return err; + } + + *val = 0; + /* high byte comes first */ + if (data_length == GC0310_8BIT) + *val = (u8)data[0]; + + return 0; +} + +static int gc0310_i2c_write(struct i2c_client *client, u16 len, u8 *data) +{ + struct i2c_msg msg; + const int num_msg = 1; + int ret; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = len; + msg.buf = data; + ret = i2c_transfer(client->adapter, &msg, 1); + + return ret == num_msg ? 0 : -EIO; +} + +static int gc0310_write_reg(struct i2c_client *client, u16 data_length, + u8 reg, u8 val) +{ + int ret; + unsigned char data[2] = {0}; + u8 *wreg = (u8 *)data; + const u16 len = data_length + sizeof(u8); /* 8-bit address + data */ + + if (data_length != GC0310_8BIT) { + dev_err(&client->dev, + "%s error, invalid data_length\n", __func__); + return -EINVAL; + } + + /* high byte goes out first */ + *wreg = (u8)(reg & 0xff); + + if (data_length == GC0310_8BIT) + data[1] = (u8)(val); + + ret = gc0310_i2c_write(client, len, data); + if (ret) + dev_err(&client->dev, + "write error: wrote 0x%x to offset 0x%x error %d", + val, reg, ret); + + return ret; +} + +/* + * gc0310_write_reg_array - Initializes a list of GC0310 registers + * @client: i2c driver client structure + * @reglist: list of registers to be written + * + * This function initializes a list of registers. When consecutive addresses + * are found in a row on the list, this function creates a buffer and sends + * consecutive data in a single i2c_transfer(). + * + * __gc0310_flush_reg_array, __gc0310_buf_reg_array() and + * __gc0310_write_reg_is_consecutive() are internal functions to + * gc0310_write_reg_array_fast() and should be not used anywhere else. + * + */ + +static int __gc0310_flush_reg_array(struct i2c_client *client, + struct gc0310_write_ctrl *ctrl) +{ + u16 size; + + if (ctrl->index == 0) + return 0; + + size = sizeof(u8) + ctrl->index; /* 8-bit address + data */ + ctrl->buffer.addr = (u8)(ctrl->buffer.addr); + ctrl->index = 0; + + return gc0310_i2c_write(client, size, (u8 *)&ctrl->buffer); +} + +static int __gc0310_buf_reg_array(struct i2c_client *client, + struct gc0310_write_ctrl *ctrl, + const struct gc0310_reg *next) +{ + int size; + + switch (next->type) { + case GC0310_8BIT: + size = 1; + ctrl->buffer.data[ctrl->index] = (u8)next->val; + break; + default: + return -EINVAL; + } + + /* When first item is added, we need to store its starting address */ + if (ctrl->index == 0) + ctrl->buffer.addr = next->reg; + + ctrl->index += size; + + /* + * Buffer cannot guarantee free space for u32? Better flush it to avoid + * possible lack of memory for next item. + */ + if (ctrl->index + sizeof(u8) >= GC0310_MAX_WRITE_BUF_SIZE) + return __gc0310_flush_reg_array(client, ctrl); + + return 0; +} + +static int __gc0310_write_reg_is_consecutive(struct i2c_client *client, + struct gc0310_write_ctrl *ctrl, + const struct gc0310_reg *next) +{ + if (ctrl->index == 0) + return 1; + + return ctrl->buffer.addr + ctrl->index == next->reg; +} + +static int gc0310_write_reg_array(struct i2c_client *client, + const struct gc0310_reg *reglist) +{ + const struct gc0310_reg *next = reglist; + struct gc0310_write_ctrl ctrl; + int err; + + ctrl.index = 0; + for (; next->type != GC0310_TOK_TERM; next++) { + switch (next->type & GC0310_TOK_MASK) { + case GC0310_TOK_DELAY: + err = __gc0310_flush_reg_array(client, &ctrl); + if (err) + return err; + msleep(next->val); + break; + default: + /* + * If next address is not consecutive, data needs to be + * flushed before proceed. + */ + if (!__gc0310_write_reg_is_consecutive(client, &ctrl, + next)) { + err = __gc0310_flush_reg_array(client, &ctrl); + if (err) + return err; + } + err = __gc0310_buf_reg_array(client, &ctrl, next); + if (err) { + dev_err(&client->dev, "%s: write error, aborted\n", + __func__); + return err; + } + break; + } + } + + return __gc0310_flush_reg_array(client, &ctrl); +} +static int gc0310_g_focal(struct v4l2_subdev *sd, s32 *val) +{ + *val = (GC0310_FOCAL_LENGTH_NUM << 16) | GC0310_FOCAL_LENGTH_DEM; + return 0; +} + +static int gc0310_g_fnumber(struct v4l2_subdev *sd, s32 *val) +{ + /*const f number for imx*/ + *val = (GC0310_F_NUMBER_DEFAULT_NUM << 16) | GC0310_F_NUMBER_DEM; + return 0; +} + +static int gc0310_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) +{ + *val = (GC0310_F_NUMBER_DEFAULT_NUM << 24) | + (GC0310_F_NUMBER_DEM << 16) | + (GC0310_F_NUMBER_DEFAULT_NUM << 8) | GC0310_F_NUMBER_DEM; + return 0; +} + +static int gc0310_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + + *val = gc0310_res[dev->fmt_idx].bin_factor_x; + + return 0; +} + +static int gc0310_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + + *val = gc0310_res[dev->fmt_idx].bin_factor_y; + + return 0; +} + +static int gc0310_get_intg_factor(struct i2c_client *client, + struct camera_mipi_info *info, + const struct gc0310_resolution *res) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct gc0310_device *dev = to_gc0310_sensor(sd); + struct atomisp_sensor_mode_data *buf = &info->data; + u16 val; + u8 reg_val; + int ret; + unsigned int hori_blanking; + unsigned int vert_blanking; + unsigned int sh_delay; + + if (!info) + return -EINVAL; + + /* pixel clock calculattion */ + dev->vt_pix_clk_freq_mhz = 14400000; // 16.8MHz + buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz; + pr_info("vt_pix_clk_freq_mhz=%d\n", buf->vt_pix_clk_freq_mhz); + + /* get integration time */ + buf->coarse_integration_time_min = GC0310_COARSE_INTG_TIME_MIN; + buf->coarse_integration_time_max_margin = + GC0310_COARSE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_min = GC0310_FINE_INTG_TIME_MIN; + buf->fine_integration_time_max_margin = + GC0310_FINE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_def = GC0310_FINE_INTG_TIME_MIN; + buf->read_mode = res->bin_mode; + + /* get the cropping and output resolution to ISP for this mode. */ + /* Getting crop_horizontal_start */ + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_H_CROP_START_H, ®_val); + if (ret) + return ret; + val = (reg_val & 0xFF) << 8; + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_H_CROP_START_L, ®_val); + if (ret) + return ret; + buf->crop_horizontal_start = val | (reg_val & 0xFF); + pr_info("crop_horizontal_start=%d\n", buf->crop_horizontal_start); + + /* Getting crop_vertical_start */ + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_V_CROP_START_H, ®_val); + if (ret) + return ret; + val = (reg_val & 0xFF) << 8; + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_V_CROP_START_L, ®_val); + if (ret) + return ret; + buf->crop_vertical_start = val | (reg_val & 0xFF); + pr_info("crop_vertical_start=%d\n", buf->crop_vertical_start); + + /* Getting output_width */ + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_H_OUTSIZE_H, ®_val); + if (ret) + return ret; + val = (reg_val & 0xFF) << 8; + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_H_OUTSIZE_L, ®_val); + if (ret) + return ret; + buf->output_width = val | (reg_val & 0xFF); + pr_info("output_width=%d\n", buf->output_width); + + /* Getting output_height */ + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_V_OUTSIZE_H, ®_val); + if (ret) + return ret; + val = (reg_val & 0xFF) << 8; + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_V_OUTSIZE_L, ®_val); + if (ret) + return ret; + buf->output_height = val | (reg_val & 0xFF); + pr_info("output_height=%d\n", buf->output_height); + + buf->crop_horizontal_end = buf->crop_horizontal_start + buf->output_width - 1; + buf->crop_vertical_end = buf->crop_vertical_start + buf->output_height - 1; + pr_info("crop_horizontal_end=%d\n", buf->crop_horizontal_end); + pr_info("crop_vertical_end=%d\n", buf->crop_vertical_end); + + /* Getting line_length_pck */ + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_H_BLANKING_H, ®_val); + if (ret) + return ret; + val = (reg_val & 0xFF) << 8; + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_H_BLANKING_L, ®_val); + if (ret) + return ret; + hori_blanking = val | (reg_val & 0xFF); + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_SH_DELAY, ®_val); + if (ret) + return ret; + sh_delay = reg_val; + buf->line_length_pck = buf->output_width + hori_blanking + sh_delay + 4; + pr_info("hori_blanking=%d sh_delay=%d line_length_pck=%d\n", hori_blanking, sh_delay, buf->line_length_pck); + + /* Getting frame_length_lines */ + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_V_BLANKING_H, ®_val); + if (ret) + return ret; + val = (reg_val & 0xFF) << 8; + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_V_BLANKING_L, ®_val); + if (ret) + return ret; + vert_blanking = val | (reg_val & 0xFF); + buf->frame_length_lines = buf->output_height + vert_blanking; + pr_info("vert_blanking=%d frame_length_lines=%d\n", vert_blanking, buf->frame_length_lines); + + buf->binning_factor_x = res->bin_factor_x ? + res->bin_factor_x : 1; + buf->binning_factor_y = res->bin_factor_y ? + res->bin_factor_y : 1; + return 0; +} + +static int gc0310_set_gain(struct v4l2_subdev *sd, int gain) + +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + u8 again, dgain; + + if (gain < 0x20) + gain = 0x20; + if (gain > 0x80) + gain = 0x80; + + if (gain >= 0x20 && gain < 0x40) { + again = 0x0; /* sqrt(2) */ + dgain = gain; + } else { + again = 0x2; /* 2 * sqrt(2) */ + dgain = gain / 2; + } + + pr_info("gain=0x%x again=0x%x dgain=0x%x\n", gain, again, dgain); + + /* set analog gain */ + ret = gc0310_write_reg(client, GC0310_8BIT, + GC0310_AGC_ADJ, again); + if (ret) + return ret; + + /* set digital gain */ + ret = gc0310_write_reg(client, GC0310_8BIT, + GC0310_DGC_ADJ, dgain); + if (ret) + return ret; + + return 0; +} + +static int __gc0310_set_exposure(struct v4l2_subdev *sd, int coarse_itg, + int gain, int digitgain) + +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + pr_info("coarse_itg=%d gain=%d digitgain=%d\n", coarse_itg, gain, digitgain); + + /* set exposure */ + ret = gc0310_write_reg(client, GC0310_8BIT, + GC0310_AEC_PK_EXPO_L, + coarse_itg & 0xff); + if (ret) + return ret; + + ret = gc0310_write_reg(client, GC0310_8BIT, + GC0310_AEC_PK_EXPO_H, + (coarse_itg >> 8) & 0x0f); + if (ret) + return ret; + + ret = gc0310_set_gain(sd, gain); + if (ret) + return ret; + + return ret; +} + +static int gc0310_set_exposure(struct v4l2_subdev *sd, int exposure, + int gain, int digitgain) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + int ret; + + mutex_lock(&dev->input_lock); + ret = __gc0310_set_exposure(sd, exposure, gain, digitgain); + mutex_unlock(&dev->input_lock); + + return ret; +} + +static long gc0310_s_exposure(struct v4l2_subdev *sd, + struct atomisp_exposure *exposure) +{ + int exp = exposure->integration_time[0]; + int gain = exposure->gain[0]; + int digitgain = exposure->gain[1]; + + /* we should not accept the invalid value below. */ + if (gain == 0) { + struct i2c_client *client = v4l2_get_subdevdata(sd); + v4l2_err(client, "%s: invalid value\n", __func__); + return -EINVAL; + } + + return gc0310_set_exposure(sd, exp, gain, digitgain); +} + +/* TO DO */ +static int gc0310_v_flip(struct v4l2_subdev *sd, s32 value) +{ + return 0; +} + +/* TO DO */ +static int gc0310_h_flip(struct v4l2_subdev *sd, s32 value) +{ + return 0; +} + +static long gc0310_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + + switch (cmd) { + case ATOMISP_IOC_S_EXPOSURE: + return gc0310_s_exposure(sd, arg); + default: + return -EINVAL; + } + return 0; +} + +/* This returns the exposure time being used. This should only be used + * for filling in EXIF data, not for actual image processing. + */ +static int gc0310_q_exposure(struct v4l2_subdev *sd, s32 *value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u8 reg_v; + int ret; + + /* get exposure */ + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_AEC_PK_EXPO_L, + ®_v); + if (ret) + goto err; + + *value = reg_v; + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_AEC_PK_EXPO_H, + ®_v); + if (ret) + goto err; + + *value = *value + (reg_v << 8); +err: + return ret; +} + +static int gc0310_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gc0310_device *dev = + container_of(ctrl->handler, struct gc0310_device, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n", + __func__, ctrl->val); + ret = gc0310_v_flip(&dev->sd, ctrl->val); + break; + case V4L2_CID_HFLIP: + dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n", + __func__, ctrl->val); + ret = gc0310_h_flip(&dev->sd, ctrl->val); + break; + default: + ret = -EINVAL; + } + return ret; +} + +static int gc0310_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gc0310_device *dev = + container_of(ctrl->handler, struct gc0310_device, ctrl_handler); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE_ABSOLUTE: + ret = gc0310_q_exposure(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FOCAL_ABSOLUTE: + ret = gc0310_g_focal(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_ABSOLUTE: + ret = gc0310_g_fnumber(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_RANGE: + ret = gc0310_g_fnumber_range(&dev->sd, &ctrl->val); + break; + case V4L2_CID_BIN_FACTOR_HORZ: + ret = gc0310_g_bin_factor_x(&dev->sd, &ctrl->val); + break; + case V4L2_CID_BIN_FACTOR_VERT: + ret = gc0310_g_bin_factor_y(&dev->sd, &ctrl->val); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops ctrl_ops = { + .s_ctrl = gc0310_s_ctrl, + .g_volatile_ctrl = gc0310_g_volatile_ctrl +}; + +struct v4l2_ctrl_config gc0310_controls[] = { + { + .ops = &ctrl_ops, + .id = V4L2_CID_EXPOSURE_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .min = 0x0, + .max = 0xffff, + .step = 0x01, + .def = 0x00, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip", + .min = 0, + .max = 1, + .step = 1, + .def = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror", + .min = 0, + .max = 1, + .step = 1, + .def = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FOCAL_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "focal length", + .min = GC0310_FOCAL_LENGTH_DEFAULT, + .max = GC0310_FOCAL_LENGTH_DEFAULT, + .step = 0x01, + .def = GC0310_FOCAL_LENGTH_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "f-number", + .min = GC0310_F_NUMBER_DEFAULT, + .max = GC0310_F_NUMBER_DEFAULT, + .step = 0x01, + .def = GC0310_F_NUMBER_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_RANGE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "f-number range", + .min = GC0310_F_NUMBER_RANGE, + .max = GC0310_F_NUMBER_RANGE, + .step = 0x01, + .def = GC0310_F_NUMBER_RANGE, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_BIN_FACTOR_HORZ, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "horizontal binning factor", + .min = 0, + .max = GC0310_BIN_FACTOR_MAX, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_BIN_FACTOR_VERT, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "vertical binning factor", + .min = 0, + .max = GC0310_BIN_FACTOR_MAX, + .step = 1, + .def = 0, + .flags = 0, + }, +}; + +static int gc0310_init(struct v4l2_subdev *sd) +{ + int ret; + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct gc0310_device *dev = to_gc0310_sensor(sd); + + pr_info("%s S\n", __func__); + mutex_lock(&dev->input_lock); + + /* set inital registers */ + ret = gc0310_write_reg_array(client, gc0310_reset_register); + + /* restore settings */ + gc0310_res = gc0310_res_preview; + N_RES = N_RES_PREVIEW; + + mutex_unlock(&dev->input_lock); + + pr_info("%s E\n", __func__); + return 0; +} + +static int power_ctrl(struct v4l2_subdev *sd, bool flag) +{ + int ret = 0; + struct gc0310_device *dev = to_gc0310_sensor(sd); + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->power_ctrl) + return dev->platform_data->power_ctrl(sd, flag); + + if (flag) { + /* The upstream module driver (written to Crystal + * Cove) had this logic to pulse the rails low first. + * This appears to break things on the MRD7 with the + * X-Powers PMIC... + * + * ret = dev->platform_data->v1p8_ctrl(sd, 0); + * ret |= dev->platform_data->v2p8_ctrl(sd, 0); + * mdelay(50); + */ + ret |= dev->platform_data->v1p8_ctrl(sd, 1); + ret |= dev->platform_data->v2p8_ctrl(sd, 1); + usleep_range(10000, 15000); + } + + if (!flag || ret) { + ret |= dev->platform_data->v1p8_ctrl(sd, 0); + ret |= dev->platform_data->v2p8_ctrl(sd, 0); + } + return ret; +} + +static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) +{ + int ret; + struct gc0310_device *dev = to_gc0310_sensor(sd); + + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->gpio_ctrl) + return dev->platform_data->gpio_ctrl(sd, flag); + + /* GPIO0 == "reset" (active low), GPIO1 == "power down" */ + if (flag) { + /* Pulse reset, then release power down */ + ret = dev->platform_data->gpio0_ctrl(sd, 0); + usleep_range(5000, 10000); + ret |= dev->platform_data->gpio0_ctrl(sd, 1); + usleep_range(10000, 15000); + ret |= dev->platform_data->gpio1_ctrl(sd, 0); + usleep_range(10000, 15000); + } else { + ret = dev->platform_data->gpio1_ctrl(sd, 1); + ret |= dev->platform_data->gpio0_ctrl(sd, 0); + } + return ret; +} + + +static int power_down(struct v4l2_subdev *sd); + +static int power_up(struct v4l2_subdev *sd) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + pr_info("%s S\n", __func__); + if (!dev->platform_data) { + dev_err(&client->dev, + "no camera_sensor_platform_data"); + return -ENODEV; + } + + /* power control */ + ret = power_ctrl(sd, 1); + if (ret) + goto fail_power; + + /* flis clock control */ + ret = dev->platform_data->flisclk_ctrl(sd, 1); + if (ret) + goto fail_clk; + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 1); + if (ret) { + ret = gpio_ctrl(sd, 1); + if (ret) + goto fail_gpio; + } + + msleep(100); + + pr_info("%s E\n", __func__); + return 0; + +fail_gpio: + dev->platform_data->flisclk_ctrl(sd, 0); +fail_clk: + power_ctrl(sd, 0); +fail_power: + dev_err(&client->dev, "sensor power-up failed\n"); + + return ret; +} + +static int power_down(struct v4l2_subdev *sd) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + if (!dev->platform_data) { + dev_err(&client->dev, + "no camera_sensor_platform_data"); + return -ENODEV; + } + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 0); + if (ret) { + ret = gpio_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "gpio failed 2\n"); + } + + ret = dev->platform_data->flisclk_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "flisclk failed\n"); + + /* power control */ + ret = power_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "vprog failed.\n"); + + return ret; +} + +static int gc0310_s_power(struct v4l2_subdev *sd, int on) +{ + int ret; + if (on == 0) + return power_down(sd); + else { + ret = power_up(sd); + if (!ret) + return gc0310_init(sd); + } + return ret; +} + +/* + * distance - calculate the distance + * @res: resolution + * @w: width + * @h: height + * + * Get the gap between resolution and w/h. + * res->width/height smaller than w/h wouldn't be considered. + * Returns the value of gap or -1 if fail. + */ +#define LARGEST_ALLOWED_RATIO_MISMATCH 800 +static int distance(struct gc0310_resolution *res, u32 w, u32 h) +{ + unsigned int w_ratio = (res->width << 13) / w; + unsigned int h_ratio; + int match; + + if (h == 0) + return -1; + h_ratio = (res->height << 13) / h; + if (h_ratio == 0) + return -1; + match = abs(((w_ratio << 13) / h_ratio) - ((int)8192)); + + if ((w_ratio < (int)8192) || (h_ratio < (int)8192) || + (match > LARGEST_ALLOWED_RATIO_MISMATCH)) + return -1; + + return w_ratio + h_ratio; +} + +/* Return the nearest higher resolution index */ +static int nearest_resolution_index(int w, int h) +{ + int i; + int idx = -1; + int dist; + int min_dist = INT_MAX; + struct gc0310_resolution *tmp_res = NULL; + + for (i = 0; i < N_RES; i++) { + tmp_res = &gc0310_res[i]; + dist = distance(tmp_res, w, h); + if (dist == -1) + continue; + if (dist < min_dist) { + min_dist = dist; + idx = i; + } + } + + return idx; +} + +static int get_resolution_index(int w, int h) +{ + int i; + + for (i = 0; i < N_RES; i++) { + if (w != gc0310_res[i].width) + continue; + if (h != gc0310_res[i].height) + continue; + + return i; + } + + return -1; +} + + +/* TODO: remove it. */ +static int startup(struct v4l2_subdev *sd) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + pr_info("%s S\n", __func__); + + ret = gc0310_write_reg_array(client, gc0310_res[dev->fmt_idx].regs); + if (ret) { + dev_err(&client->dev, "gc0310 write register err.\n"); + return ret; + } + + pr_info("%s E\n", __func__); + return ret; +} + +static int gc0310_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt = &format->format; + struct gc0310_device *dev = to_gc0310_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct camera_mipi_info *gc0310_info = NULL; + int ret = 0; + int idx = 0; + pr_info("%s S\n", __func__); + + if (format->pad) + return -EINVAL; + + if (!fmt) + return -EINVAL; + + gc0310_info = v4l2_get_subdev_hostdata(sd); + if (!gc0310_info) + return -EINVAL; + + mutex_lock(&dev->input_lock); + + idx = nearest_resolution_index(fmt->width, fmt->height); + if (idx == -1) { + /* return the largest resolution */ + fmt->width = gc0310_res[N_RES - 1].width; + fmt->height = gc0310_res[N_RES - 1].height; + } else { + fmt->width = gc0310_res[idx].width; + fmt->height = gc0310_res[idx].height; + } + fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *fmt; + mutex_unlock(&dev->input_lock); + return 0; + } + + dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); + if (dev->fmt_idx == -1) { + dev_err(&client->dev, "get resolution fail\n"); + mutex_unlock(&dev->input_lock); + return -EINVAL; + } + + printk("%s: before gc0310_write_reg_array %s\n", __FUNCTION__, + gc0310_res[dev->fmt_idx].desc); + ret = startup(sd); + if (ret) { + dev_err(&client->dev, "gc0310 startup err\n"); + goto err; + } + + ret = gc0310_get_intg_factor(client, gc0310_info, + &gc0310_res[dev->fmt_idx]); + if (ret) { + dev_err(&client->dev, "failed to get integration_factor\n"); + goto err; + } + + pr_info("%s E\n", __func__); +err: + mutex_unlock(&dev->input_lock); + return ret; +} + +static int gc0310_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt = &format->format; + struct gc0310_device *dev = to_gc0310_sensor(sd); + + if (format->pad) + return -EINVAL; + + if (!fmt) + return -EINVAL; + + fmt->width = gc0310_res[dev->fmt_idx].width; + fmt->height = gc0310_res[dev->fmt_idx].height; + fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8; + + return 0; +} + +static int gc0310_detect(struct i2c_client *client) +{ + struct i2c_adapter *adapter = client->adapter; + u8 high, low; + int ret; + u16 id; + + pr_info("%s S\n", __func__); + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + return -ENODEV; + + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_SC_CMMN_CHIP_ID_H, &high); + if (ret) { + dev_err(&client->dev, "read sensor_id_high failed\n"); + return -ENODEV; + } + ret = gc0310_read_reg(client, GC0310_8BIT, + GC0310_SC_CMMN_CHIP_ID_L, &low); + if (ret) { + dev_err(&client->dev, "read sensor_id_low failed\n"); + return -ENODEV; + } + id = ((((u16) high) << 8) | (u16) low); + pr_info("sensor ID = 0x%x\n", id); + + if (id != GC0310_ID) { + dev_err(&client->dev, "sensor ID error, read id = 0x%x, target id = 0x%x\n", id, GC0310_ID); + return -ENODEV; + } + + dev_dbg(&client->dev, "detect gc0310 success\n"); + + pr_info("%s E\n", __func__); + + return 0; +} + +static int gc0310_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + pr_info("%s S enable=%d\n", __func__, enable); + mutex_lock(&dev->input_lock); + + if (enable) { + /* enable per frame MIPI and sensor ctrl reset */ + ret = gc0310_write_reg(client, GC0310_8BIT, + 0xFE, 0x30); + if (ret) { + mutex_unlock(&dev->input_lock); + return ret; + } + } + + ret = gc0310_write_reg(client, GC0310_8BIT, + GC0310_RESET_RELATED, GC0310_REGISTER_PAGE_3); + if (ret) { + mutex_unlock(&dev->input_lock); + return ret; + } + + ret = gc0310_write_reg(client, GC0310_8BIT, GC0310_SW_STREAM, + enable ? GC0310_START_STREAMING : + GC0310_STOP_STREAMING); + if (ret) { + mutex_unlock(&dev->input_lock); + return ret; + } + + ret = gc0310_write_reg(client, GC0310_8BIT, + GC0310_RESET_RELATED, GC0310_REGISTER_PAGE_0); + if (ret) { + mutex_unlock(&dev->input_lock); + return ret; + } + + mutex_unlock(&dev->input_lock); + pr_info("%s E\n", __func__); + return ret; +} + + +static int gc0310_s_config(struct v4l2_subdev *sd, + int irq, void *platform_data) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + pr_info("%s S\n", __func__); + if (!platform_data) + return -ENODEV; + + dev->platform_data = + (struct camera_sensor_platform_data *)platform_data; + + mutex_lock(&dev->input_lock); + if (dev->platform_data->platform_init) { + ret = dev->platform_data->platform_init(client); + if (ret) { + dev_err(&client->dev, "platform init err\n"); + goto platform_init_failed; + } + } + /* power off the module, then power on it in future + * as first power on by board may not fulfill the + * power on sequqence needed by the module + */ + ret = power_down(sd); + if (ret) { + dev_err(&client->dev, "gc0310 power-off err.\n"); + goto fail_power_off; + } + + ret = power_up(sd); + if (ret) { + dev_err(&client->dev, "gc0310 power-up err.\n"); + goto fail_power_on; + } + + ret = dev->platform_data->csi_cfg(sd, 1); + if (ret) + goto fail_csi_cfg; + + /* config & detect sensor */ + ret = gc0310_detect(client); + if (ret) { + dev_err(&client->dev, "gc0310_detect err s_config.\n"); + goto fail_csi_cfg; + } + + /* turn off sensor, after probed */ + ret = power_down(sd); + if (ret) { + dev_err(&client->dev, "gc0310 power-off err.\n"); + goto fail_csi_cfg; + } + mutex_unlock(&dev->input_lock); + + pr_info("%s E\n", __func__); + return 0; + +fail_csi_cfg: + dev->platform_data->csi_cfg(sd, 0); +fail_power_on: + power_down(sd); + dev_err(&client->dev, "sensor power-gating failed\n"); +fail_power_off: + if (dev->platform_data->platform_deinit) + dev->platform_data->platform_deinit(); +platform_init_failed: + mutex_unlock(&dev->input_lock); + return ret; +} + +static int gc0310_g_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!param) + return -EINVAL; + + if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + dev_err(&client->dev, "unsupported buffer type.\n"); + return -EINVAL; + } + + memset(param, 0, sizeof(*param)); + param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { + param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + param->parm.capture.timeperframe.numerator = 1; + param->parm.capture.capturemode = dev->run_mode; + param->parm.capture.timeperframe.denominator = + gc0310_res[dev->fmt_idx].fps; + } + return 0; +} + +static int gc0310_s_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + dev->run_mode = param->parm.capture.capturemode; + + mutex_lock(&dev->input_lock); + switch (dev->run_mode) { + case CI_MODE_VIDEO: + gc0310_res = gc0310_res_video; + N_RES = N_RES_VIDEO; + break; + case CI_MODE_STILL_CAPTURE: + gc0310_res = gc0310_res_still; + N_RES = N_RES_STILL; + break; + default: + gc0310_res = gc0310_res_preview; + N_RES = N_RES_PREVIEW; + } + mutex_unlock(&dev->input_lock); + return 0; +} + +static int gc0310_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + + interval->interval.numerator = 1; + interval->interval.denominator = gc0310_res[dev->fmt_idx].fps; + + return 0; +} + +static int gc0310_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= MAX_FMTS) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SGRBG8_1X8; + return 0; +} + +static int gc0310_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + int index = fse->index; + + if (index >= N_RES) + return -EINVAL; + + fse->min_width = gc0310_res[index].width; + fse->min_height = gc0310_res[index].height; + fse->max_width = gc0310_res[index].width; + fse->max_height = gc0310_res[index].height; + + return 0; + +} + + +static int gc0310_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) +{ + struct gc0310_device *dev = to_gc0310_sensor(sd); + + mutex_lock(&dev->input_lock); + *frames = gc0310_res[dev->fmt_idx].skip_frames; + mutex_unlock(&dev->input_lock); + + return 0; +} + +static const struct v4l2_subdev_sensor_ops gc0310_sensor_ops = { + .g_skip_frames = gc0310_g_skip_frames, +}; + +static const struct v4l2_subdev_video_ops gc0310_video_ops = { + .s_stream = gc0310_s_stream, + .g_parm = gc0310_g_parm, + .s_parm = gc0310_s_parm, + .g_frame_interval = gc0310_g_frame_interval, +}; + +static const struct v4l2_subdev_core_ops gc0310_core_ops = { + .s_power = gc0310_s_power, + .ioctl = gc0310_ioctl, +}; + +static const struct v4l2_subdev_pad_ops gc0310_pad_ops = { + .enum_mbus_code = gc0310_enum_mbus_code, + .enum_frame_size = gc0310_enum_frame_size, + .get_fmt = gc0310_get_fmt, + .set_fmt = gc0310_set_fmt, +}; + +static const struct v4l2_subdev_ops gc0310_ops = { + .core = &gc0310_core_ops, + .video = &gc0310_video_ops, + .pad = &gc0310_pad_ops, + .sensor = &gc0310_sensor_ops, +}; + +static int gc0310_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct gc0310_device *dev = to_gc0310_sensor(sd); + dev_dbg(&client->dev, "gc0310_remove...\n"); + + if (dev->platform_data->platform_deinit) + dev->platform_data->platform_deinit(); + + dev->platform_data->csi_cfg(sd, 0); + + v4l2_device_unregister_subdev(sd); + media_entity_cleanup(&dev->sd.entity); + v4l2_ctrl_handler_free(&dev->ctrl_handler); + kfree(dev); + + return 0; +} + +static int gc0310_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct gc0310_device *dev; + int ret; + void *pdata; + unsigned int i; + + pr_info("%s S\n", __func__); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + dev_err(&client->dev, "out of memory\n"); + return -ENOMEM; + } + + mutex_init(&dev->input_lock); + + dev->fmt_idx = 0; + v4l2_i2c_subdev_init(&(dev->sd), client, &gc0310_ops); + + if (ACPI_COMPANION(&client->dev)) + pdata = gmin_camera_platform_data(&dev->sd, + ATOMISP_INPUT_FORMAT_RAW_8, + atomisp_bayer_order_grbg); + else + pdata = client->dev.platform_data; + + if (!pdata) { + ret = -EINVAL; + goto out_free; + } + + ret = gc0310_s_config(&dev->sd, client->irq, pdata); + if (ret) + goto out_free; + + ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); + if (ret) + goto out_free; + + dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + dev->pad.flags = MEDIA_PAD_FL_SOURCE; + dev->format.code = MEDIA_BUS_FMT_SGRBG8_1X8; + dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = + v4l2_ctrl_handler_init(&dev->ctrl_handler, + ARRAY_SIZE(gc0310_controls)); + if (ret) { + gc0310_remove(client); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(gc0310_controls); i++) + v4l2_ctrl_new_custom(&dev->ctrl_handler, &gc0310_controls[i], + NULL); + + if (dev->ctrl_handler.error) { + gc0310_remove(client); + return dev->ctrl_handler.error; + } + + /* Use same lock for controls as for everything else. */ + dev->ctrl_handler.lock = &dev->input_lock; + dev->sd.ctrl_handler = &dev->ctrl_handler; + + ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); + if (ret) + gc0310_remove(client); + + pr_info("%s E\n", __func__); + return ret; +out_free: + v4l2_device_unregister_subdev(&dev->sd); + kfree(dev); + return ret; +} + +static const struct acpi_device_id gc0310_acpi_match[] = { + {"XXGC0310"}, + {"INT0310"}, + {}, +}; + +MODULE_DEVICE_TABLE(acpi, gc0310_acpi_match); + +MODULE_DEVICE_TABLE(i2c, gc0310_id); +static struct i2c_driver gc0310_driver = { + .driver = { + .name = GC0310_NAME, + .acpi_match_table = ACPI_PTR(gc0310_acpi_match), + }, + .probe = gc0310_probe, + .remove = gc0310_remove, + .id_table = gc0310_id, +}; + +static int init_gc0310(void) +{ + return i2c_add_driver(&gc0310_driver); +} + +static void exit_gc0310(void) +{ + + i2c_del_driver(&gc0310_driver); +} + +module_init(init_gc0310); +module_exit(exit_gc0310); + +MODULE_AUTHOR("Lai, Angie "); +MODULE_DESCRIPTION("A low-level driver for GalaxyCore GC0310 sensors"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c new file mode 100644 index 000000000000..e43d31ea9676 --- /dev/null +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -0,0 +1,1219 @@ +/* + * Support for GalaxyCore GC2235 2M camera sensor. + * + * Copyright (c) 2014 Intel Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/linux/atomisp_gmin_platform.h" +#include +#include + +#include "gc2235.h" + +/* i2c read/write stuff */ +static int gc2235_read_reg(struct i2c_client *client, + u16 data_length, u16 reg, u16 *val) +{ + int err; + struct i2c_msg msg[2]; + unsigned char data[6]; + + if (!client->adapter) { + dev_err(&client->dev, "%s error, no client->adapter\n", + __func__); + return -ENODEV; + } + + if (data_length != GC2235_8BIT) { + dev_err(&client->dev, "%s error, invalid data length\n", + __func__); + return -EINVAL; + } + + memset(msg, 0, sizeof(msg)); + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 1; + msg[0].buf = data; + + /* high byte goes out first */ + data[0] = (u8)(reg & 0xff); + + msg[1].addr = client->addr; + msg[1].len = data_length; + msg[1].flags = I2C_M_RD; + msg[1].buf = data; + + err = i2c_transfer(client->adapter, msg, 2); + if (err != 2) { + if (err >= 0) + err = -EIO; + dev_err(&client->dev, + "read from offset 0x%x error %d", reg, err); + return err; + } + + *val = 0; + /* high byte comes first */ + if (data_length == GC2235_8BIT) + *val = (u8)data[0]; + + return 0; +} + +static int gc2235_i2c_write(struct i2c_client *client, u16 len, u8 *data) +{ + struct i2c_msg msg; + const int num_msg = 1; + int ret; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = len; + msg.buf = data; + ret = i2c_transfer(client->adapter, &msg, 1); + + return ret == num_msg ? 0 : -EIO; +} + +static int gc2235_write_reg(struct i2c_client *client, u16 data_length, + u8 reg, u8 val) +{ + int ret; + unsigned char data[4] = {0}; + const u16 len = data_length + sizeof(u8); /* 16-bit address + data */ + + if (data_length != GC2235_8BIT) { + dev_err(&client->dev, + "%s error, invalid data_length\n", __func__); + return -EINVAL; + } + + /* high byte goes out first */ + data[0] = reg; + data[1] = val; + + ret = gc2235_i2c_write(client, len, data); + if (ret) + dev_err(&client->dev, + "write error: wrote 0x%x to offset 0x%x error %d", + val, reg, ret); + + return ret; +} + +static int __gc2235_flush_reg_array(struct i2c_client *client, + struct gc2235_write_ctrl *ctrl) +{ + u16 size; + + if (ctrl->index == 0) + return 0; + + size = sizeof(u8) + ctrl->index; /* 8-bit address + data */ + ctrl->index = 0; + + return gc2235_i2c_write(client, size, (u8 *)&ctrl->buffer); +} + +static int __gc2235_buf_reg_array(struct i2c_client *client, + struct gc2235_write_ctrl *ctrl, + const struct gc2235_reg *next) +{ + int size; + + if (next->type != GC2235_8BIT) + return -EINVAL; + + size = 1; + ctrl->buffer.data[ctrl->index] = (u8)next->val; + + /* When first item is added, we need to store its starting address */ + if (ctrl->index == 0) + ctrl->buffer.addr = next->reg; + + ctrl->index += size; + + /* + * Buffer cannot guarantee free space for u32? Better flush it to avoid + * possible lack of memory for next item. + */ + if (ctrl->index + sizeof(u8) >= GC2235_MAX_WRITE_BUF_SIZE) + return __gc2235_flush_reg_array(client, ctrl); + + return 0; +} +static int __gc2235_write_reg_is_consecutive(struct i2c_client *client, + struct gc2235_write_ctrl *ctrl, + const struct gc2235_reg *next) +{ + if (ctrl->index == 0) + return 1; + + return ctrl->buffer.addr + ctrl->index == next->reg; +} +static int gc2235_write_reg_array(struct i2c_client *client, + const struct gc2235_reg *reglist) +{ + const struct gc2235_reg *next = reglist; + struct gc2235_write_ctrl ctrl; + int err; + + ctrl.index = 0; + for (; next->type != GC2235_TOK_TERM; next++) { + switch (next->type & GC2235_TOK_MASK) { + case GC2235_TOK_DELAY: + err = __gc2235_flush_reg_array(client, &ctrl); + if (err) + return err; + msleep(next->val); + break; + default: + /* + * If next address is not consecutive, data needs to be + * flushed before proceed. + */ + if (!__gc2235_write_reg_is_consecutive(client, &ctrl, + next)) { + err = __gc2235_flush_reg_array(client, &ctrl); + if (err) + return err; + } + err = __gc2235_buf_reg_array(client, &ctrl, next); + if (err) { + dev_err(&client->dev, "%s: write error, aborted\n", + __func__); + return err; + } + break; + } + } + + return __gc2235_flush_reg_array(client, &ctrl); +} + +static int gc2235_g_focal(struct v4l2_subdev *sd, s32 *val) +{ + *val = (GC2235_FOCAL_LENGTH_NUM << 16) | GC2235_FOCAL_LENGTH_DEM; + return 0; +} + +static int gc2235_g_fnumber(struct v4l2_subdev *sd, s32 *val) +{ + /*const f number for imx*/ + *val = (GC2235_F_NUMBER_DEFAULT_NUM << 16) | GC2235_F_NUMBER_DEM; + return 0; +} + +static int gc2235_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) +{ + *val = (GC2235_F_NUMBER_DEFAULT_NUM << 24) | + (GC2235_F_NUMBER_DEM << 16) | + (GC2235_F_NUMBER_DEFAULT_NUM << 8) | GC2235_F_NUMBER_DEM; + return 0; +} + + +static int gc2235_get_intg_factor(struct i2c_client *client, + struct camera_mipi_info *info, + const struct gc2235_resolution *res) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct gc2235_device *dev = to_gc2235_sensor(sd); + struct atomisp_sensor_mode_data *buf = &info->data; + u16 reg_val, reg_val_h, dummy; + int ret; + + if (!info) + return -EINVAL; + + /* pixel clock calculattion */ + buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz = 30000000; + + /* get integration time */ + buf->coarse_integration_time_min = GC2235_COARSE_INTG_TIME_MIN; + buf->coarse_integration_time_max_margin = + GC2235_COARSE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_min = GC2235_FINE_INTG_TIME_MIN; + buf->fine_integration_time_max_margin = + GC2235_FINE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_def = GC2235_FINE_INTG_TIME_MIN; + buf->frame_length_lines = res->lines_per_frame; + buf->line_length_pck = res->pixels_per_line; + buf->read_mode = res->bin_mode; + + /* get the cropping and output resolution to ISP for this mode. */ + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_H_CROP_START_H, ®_val_h); + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_H_CROP_START_L, ®_val); + if (ret) + return ret; + + buf->crop_horizontal_start = (reg_val_h << 8) | reg_val; + + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_V_CROP_START_H, ®_val_h); + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_V_CROP_START_L, ®_val); + if (ret) + return ret; + + buf->crop_vertical_start = (reg_val_h << 8) | reg_val; + + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_H_OUTSIZE_H, ®_val_h); + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_H_OUTSIZE_L, ®_val); + if (ret) + return ret; + buf->output_width = (reg_val_h << 8) | reg_val; + + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_V_OUTSIZE_H, ®_val_h); + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_V_OUTSIZE_L, ®_val); + if (ret) + return ret; + buf->output_height = (reg_val_h << 8) | reg_val; + + buf->crop_horizontal_end = buf->crop_horizontal_start + + buf->output_width - 1; + buf->crop_vertical_end = buf->crop_vertical_start + + buf->output_height - 1; + + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_HB_H, ®_val_h); + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_HB_L, ®_val); + if (ret) + return ret; + + dummy = (reg_val_h << 8) | reg_val; + + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_SH_DELAY_H, ®_val_h); + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_SH_DELAY_L, ®_val); + +#if 0 + buf->line_length_pck = buf->output_width + 16 + dummy + + (((u16)reg_val_h << 8) | (u16)reg_val) + 4; +#endif + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_VB_H, ®_val_h); + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_VB_L, ®_val); + if (ret) + return ret; + +#if 0 + buf->frame_length_lines = buf->output_height + 32 + + (((u16)reg_val_h << 8) | (u16)reg_val); +#endif + buf->binning_factor_x = res->bin_factor_x ? + res->bin_factor_x : 1; + buf->binning_factor_y = res->bin_factor_y ? + res->bin_factor_y : 1; + return 0; +} + +static long __gc2235_set_exposure(struct v4l2_subdev *sd, int coarse_itg, + int gain, int digitgain) + +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u16 coarse_integration = (u16)coarse_itg; + int ret = 0; + u16 expo_coarse_h, expo_coarse_l, gain_val = 0xF0, gain_val2 = 0xF0; + expo_coarse_h = coarse_integration >> 8; + expo_coarse_l = coarse_integration & 0xff; + + ret = gc2235_write_reg(client, GC2235_8BIT, + GC2235_EXPOSURE_H, expo_coarse_h); + ret = gc2235_write_reg(client, GC2235_8BIT, + GC2235_EXPOSURE_L, expo_coarse_l); + + if (gain <= 0x58) { + gain_val = 0x40; + gain_val2 = 0x58; + } else if (gain < 256) { + gain_val = 0x40; + gain_val2 = gain; + } else { + gain_val2 = 64 * gain / 256; + gain_val = 0xff; + } + + ret = gc2235_write_reg(client, GC2235_8BIT, + GC2235_GLOBAL_GAIN, (u8)gain_val); + ret = gc2235_write_reg(client, GC2235_8BIT, + GC2235_PRE_GAIN, (u8)gain_val2); + + return ret; +} + + +static int gc2235_set_exposure(struct v4l2_subdev *sd, int exposure, + int gain, int digitgain) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + int ret; + + mutex_lock(&dev->input_lock); + ret = __gc2235_set_exposure(sd, exposure, gain, digitgain); + mutex_unlock(&dev->input_lock); + + return ret; +} + +static long gc2235_s_exposure(struct v4l2_subdev *sd, + struct atomisp_exposure *exposure) +{ + int exp = exposure->integration_time[0]; + int gain = exposure->gain[0]; + int digitgain = exposure->gain[1]; + + /* we should not accept the invalid value below. */ + if (gain == 0) { + struct i2c_client *client = v4l2_get_subdevdata(sd); + v4l2_err(client, "%s: invalid value\n", __func__); + return -EINVAL; + } + + return gc2235_set_exposure(sd, exp, gain, digitgain); +} +static long gc2235_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + switch (cmd) { + case ATOMISP_IOC_S_EXPOSURE: + return gc2235_s_exposure(sd, arg); + default: + return -EINVAL; + } + return 0; +} +/* This returns the exposure time being used. This should only be used + * for filling in EXIF data, not for actual image processing. + */ +static int gc2235_q_exposure(struct v4l2_subdev *sd, s32 *value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u16 reg_v, reg_v2; + int ret; + + /* get exposure */ + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_EXPOSURE_L, + ®_v); + if (ret) + goto err; + + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_EXPOSURE_H, + ®_v2); + if (ret) + goto err; + + reg_v += reg_v2 << 8; + + *value = reg_v; +err: + return ret; +} + +static int gc2235_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gc2235_device *dev = + container_of(ctrl->handler, struct gc2235_device, ctrl_handler); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE_ABSOLUTE: + ret = gc2235_q_exposure(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FOCAL_ABSOLUTE: + ret = gc2235_g_focal(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_ABSOLUTE: + ret = gc2235_g_fnumber(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_RANGE: + ret = gc2235_g_fnumber_range(&dev->sd, &ctrl->val); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops ctrl_ops = { + .g_volatile_ctrl = gc2235_g_volatile_ctrl +}; + +static struct v4l2_ctrl_config gc2235_controls[] = { + { + .ops = &ctrl_ops, + .id = V4L2_CID_EXPOSURE_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .min = 0x0, + .max = 0xffff, + .step = 0x01, + .def = 0x00, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FOCAL_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "focal length", + .min = GC2235_FOCAL_LENGTH_DEFAULT, + .max = GC2235_FOCAL_LENGTH_DEFAULT, + .step = 0x01, + .def = GC2235_FOCAL_LENGTH_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "f-number", + .min = GC2235_F_NUMBER_DEFAULT, + .max = GC2235_F_NUMBER_DEFAULT, + .step = 0x01, + .def = GC2235_F_NUMBER_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_RANGE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "f-number range", + .min = GC2235_F_NUMBER_RANGE, + .max = GC2235_F_NUMBER_RANGE, + .step = 0x01, + .def = GC2235_F_NUMBER_RANGE, + .flags = 0, + }, +}; + +static int __gc2235_init(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + /* restore settings */ + gc2235_res = gc2235_res_preview; + N_RES = N_RES_PREVIEW; + + return gc2235_write_reg_array(client, gc2235_init_settings); +} + +static int is_init; + +static int power_ctrl(struct v4l2_subdev *sd, bool flag) +{ + int ret = -1; + struct gc2235_device *dev = to_gc2235_sensor(sd); + + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->power_ctrl) + return dev->platform_data->power_ctrl(sd, flag); + + if (flag) { + ret = dev->platform_data->v1p8_ctrl(sd, 1); + usleep_range(60, 90); + if (ret == 0) + ret |= dev->platform_data->v2p8_ctrl(sd, 1); + } else { + ret = dev->platform_data->v1p8_ctrl(sd, 0); + ret |= dev->platform_data->v2p8_ctrl(sd, 0); + } + return ret; +} + +static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + int ret = -1; + + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->gpio_ctrl) + return dev->platform_data->gpio_ctrl(sd, flag); + + ret |= dev->platform_data->gpio1_ctrl(sd, !flag); + usleep_range(60, 90); + return dev->platform_data->gpio0_ctrl(sd, flag); +} + +static int power_up(struct v4l2_subdev *sd) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + if (!dev->platform_data) { + dev_err(&client->dev, + "no camera_sensor_platform_data"); + return -ENODEV; + } + /* power control */ + ret = power_ctrl(sd, 1); + if (ret) + goto fail_power; + + /* according to DS, at least 5ms is needed between DOVDD and PWDN */ + usleep_range(5000, 6000); + + ret = dev->platform_data->flisclk_ctrl(sd, 1); + if (ret) + goto fail_clk; + usleep_range(5000, 6000); + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 1); + if (ret) { + ret = gpio_ctrl(sd, 1); + if (ret) + goto fail_power; + } + + msleep(5); + return 0; + +fail_clk: + gpio_ctrl(sd, 0); +fail_power: + power_ctrl(sd, 0); + dev_err(&client->dev, "sensor power-up failed\n"); + + return ret; +} + +static int power_down(struct v4l2_subdev *sd) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + if (!dev->platform_data) { + dev_err(&client->dev, + "no camera_sensor_platform_data"); + return -ENODEV; + } + /* gpio ctrl */ + ret = gpio_ctrl(sd, 0); + if (ret) { + ret = gpio_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "gpio failed 2\n"); + } + + ret = dev->platform_data->flisclk_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "flisclk failed\n"); + + /* power control */ + ret = power_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "vprog failed.\n"); + + return ret; +} + +static int gc2235_s_power(struct v4l2_subdev *sd, int on) +{ + int ret; + + if (on == 0) + ret = power_down(sd); + else { + ret = power_up(sd); + if (!ret) + ret = __gc2235_init(sd); + is_init = 1; + } + return ret; +} + +/* + * distance - calculate the distance + * @res: resolution + * @w: width + * @h: height + * + * Get the gap between resolution and w/h. + * res->width/height smaller than w/h wouldn't be considered. + * Returns the value of gap or -1 if fail. + */ +#define LARGEST_ALLOWED_RATIO_MISMATCH 800 +static int distance(struct gc2235_resolution *res, u32 w, u32 h) +{ + unsigned int w_ratio = (res->width << 13) / w; + unsigned int h_ratio; + int match; + + if (h == 0) + return -1; + h_ratio = (res->height << 13) / h; + if (h_ratio == 0) + return -1; + match = abs(((w_ratio << 13) / h_ratio) - 8192); + + if ((w_ratio < 8192) || (h_ratio < 8192) || + (match > LARGEST_ALLOWED_RATIO_MISMATCH)) + return -1; + + return w_ratio + h_ratio; +} + +/* Return the nearest higher resolution index */ +static int nearest_resolution_index(int w, int h) +{ + int i; + int idx = -1; + int dist; + int min_dist = INT_MAX; + struct gc2235_resolution *tmp_res = NULL; + + for (i = 0; i < N_RES; i++) { + tmp_res = &gc2235_res[i]; + dist = distance(tmp_res, w, h); + if (dist == -1) + continue; + if (dist < min_dist) { + min_dist = dist; + idx = i; + } + } + + return idx; +} + +static int get_resolution_index(int w, int h) +{ + int i; + + for (i = 0; i < N_RES; i++) { + if (w != gc2235_res[i].width) + continue; + if (h != gc2235_res[i].height) + continue; + + return i; + } + + return -1; +} + +static int startup(struct v4l2_subdev *sd) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + if (is_init == 0) { + /* force gc2235 to do a reset in res change, otherwise it + * can not output normal after switching res. and it is not + * necessary for first time run up after power on, for the sack + * of performance + */ + power_down(sd); + power_up(sd); + gc2235_write_reg_array(client, gc2235_init_settings); + } + + ret = gc2235_write_reg_array(client, gc2235_res[dev->fmt_idx].regs); + if (ret) { + dev_err(&client->dev, "gc2235 write register err.\n"); + return ret; + } + is_init = 0; + + return ret; +} + +static int gc2235_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + + struct v4l2_mbus_framefmt *fmt = &format->format; + struct gc2235_device *dev = to_gc2235_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct camera_mipi_info *gc2235_info = NULL; + int ret = 0; + int idx; + + gc2235_info = v4l2_get_subdev_hostdata(sd); + if (!gc2235_info) + return -EINVAL; + if (format->pad) + return -EINVAL; + if (!fmt) + return -EINVAL; + mutex_lock(&dev->input_lock); + idx = nearest_resolution_index(fmt->width, fmt->height); + if (idx == -1) { + /* return the largest resolution */ + fmt->width = gc2235_res[N_RES - 1].width; + fmt->height = gc2235_res[N_RES - 1].height; + } else { + fmt->width = gc2235_res[idx].width; + fmt->height = gc2235_res[idx].height; + } + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *fmt; + mutex_unlock(&dev->input_lock); + return 0; + } + + dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); + if (dev->fmt_idx == -1) { + dev_err(&client->dev, "get resolution fail\n"); + mutex_unlock(&dev->input_lock); + return -EINVAL; + } + + ret = startup(sd); + if (ret) { + dev_err(&client->dev, "gc2235 startup err\n"); + goto err; + } + + ret = gc2235_get_intg_factor(client, gc2235_info, + &gc2235_res[dev->fmt_idx]); + if (ret) + dev_err(&client->dev, "failed to get integration_factor\n"); + +err: + mutex_unlock(&dev->input_lock); + return ret; +} + +static int gc2235_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt = &format->format; + struct gc2235_device *dev = to_gc2235_sensor(sd); + + if (format->pad) + return -EINVAL; + + if (!fmt) + return -EINVAL; + + fmt->width = gc2235_res[dev->fmt_idx].width; + fmt->height = gc2235_res[dev->fmt_idx].height; + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + + return 0; +} + +static int gc2235_detect(struct i2c_client *client) +{ + struct i2c_adapter *adapter = client->adapter; + u16 high, low; + int ret; + u16 id; + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + return -ENODEV; + + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_SENSOR_ID_H, &high); + if (ret) { + dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); + return -ENODEV; + } + ret = gc2235_read_reg(client, GC2235_8BIT, + GC2235_SENSOR_ID_L, &low); + id = ((high << 8) | low); + + if (id != GC2235_ID) { + dev_err(&client->dev, "sensor ID error, 0x%x\n", id); + return -ENODEV; + } + + dev_info(&client->dev, "detect gc2235 success\n"); + return 0; +} + +static int gc2235_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + mutex_lock(&dev->input_lock); + + if (enable) + ret = gc2235_write_reg_array(client, gc2235_stream_on); + else + ret = gc2235_write_reg_array(client, gc2235_stream_off); + + mutex_unlock(&dev->input_lock); + return ret; +} + + +static int gc2235_s_config(struct v4l2_subdev *sd, + int irq, void *platform_data) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + if (!platform_data) + return -ENODEV; + + dev->platform_data = + (struct camera_sensor_platform_data *)platform_data; + + mutex_lock(&dev->input_lock); + if (dev->platform_data->platform_init) { + ret = dev->platform_data->platform_init(client); + if (ret) { + dev_err(&client->dev, "platform init err\n"); + goto platform_init_failed; + } + } + /* power off the module, then power on it in future + * as first power on by board may not fulfill the + * power on sequqence needed by the module + */ + ret = power_down(sd); + if (ret) { + dev_err(&client->dev, "gc2235 power-off err.\n"); + goto fail_power_off; + } + + ret = power_up(sd); + if (ret) { + dev_err(&client->dev, "gc2235 power-up err.\n"); + goto fail_power_on; + } + + ret = dev->platform_data->csi_cfg(sd, 1); + if (ret) + goto fail_csi_cfg; + + /* config & detect sensor */ + ret = gc2235_detect(client); + if (ret) { + dev_err(&client->dev, "gc2235_detect err s_config.\n"); + goto fail_csi_cfg; + } + + /* turn off sensor, after probed */ + ret = power_down(sd); + if (ret) { + dev_err(&client->dev, "gc2235 power-off err.\n"); + goto fail_csi_cfg; + } + mutex_unlock(&dev->input_lock); + + return 0; + +fail_csi_cfg: + dev->platform_data->csi_cfg(sd, 0); +fail_power_on: + power_down(sd); + dev_err(&client->dev, "sensor power-gating failed\n"); +fail_power_off: + if (dev->platform_data->platform_deinit) + dev->platform_data->platform_deinit(); +platform_init_failed: + mutex_unlock(&dev->input_lock); + return ret; +} + +static int gc2235_g_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!param) + return -EINVAL; + + if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + dev_err(&client->dev, "unsupported buffer type.\n"); + return -EINVAL; + } + + memset(param, 0, sizeof(*param)); + param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { + param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + param->parm.capture.timeperframe.numerator = 1; + param->parm.capture.capturemode = dev->run_mode; + param->parm.capture.timeperframe.denominator = + gc2235_res[dev->fmt_idx].fps; + } + return 0; +} + +static int gc2235_s_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + dev->run_mode = param->parm.capture.capturemode; + + mutex_lock(&dev->input_lock); + switch (dev->run_mode) { + case CI_MODE_VIDEO: + gc2235_res = gc2235_res_video; + N_RES = N_RES_VIDEO; + break; + case CI_MODE_STILL_CAPTURE: + gc2235_res = gc2235_res_still; + N_RES = N_RES_STILL; + break; + default: + gc2235_res = gc2235_res_preview; + N_RES = N_RES_PREVIEW; + } + mutex_unlock(&dev->input_lock); + return 0; +} + +static int gc2235_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + + interval->interval.numerator = 1; + interval->interval.denominator = gc2235_res[dev->fmt_idx].fps; + + return 0; +} + +static int gc2235_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= MAX_FMTS) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SBGGR10_1X10; + return 0; +} + +static int gc2235_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + int index = fse->index; + + if (index >= N_RES) + return -EINVAL; + + fse->min_width = gc2235_res[index].width; + fse->min_height = gc2235_res[index].height; + fse->max_width = gc2235_res[index].width; + fse->max_height = gc2235_res[index].height; + + return 0; + +} + +static int gc2235_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) +{ + struct gc2235_device *dev = to_gc2235_sensor(sd); + + mutex_lock(&dev->input_lock); + *frames = gc2235_res[dev->fmt_idx].skip_frames; + mutex_unlock(&dev->input_lock); + + return 0; +} + +static const struct v4l2_subdev_sensor_ops gc2235_sensor_ops = { + .g_skip_frames = gc2235_g_skip_frames, +}; + +static const struct v4l2_subdev_video_ops gc2235_video_ops = { + .s_stream = gc2235_s_stream, + .g_parm = gc2235_g_parm, + .s_parm = gc2235_s_parm, + .g_frame_interval = gc2235_g_frame_interval, +}; + +static const struct v4l2_subdev_core_ops gc2235_core_ops = { + .s_power = gc2235_s_power, + .ioctl = gc2235_ioctl, +}; + +static const struct v4l2_subdev_pad_ops gc2235_pad_ops = { + .enum_mbus_code = gc2235_enum_mbus_code, + .enum_frame_size = gc2235_enum_frame_size, + .get_fmt = gc2235_get_fmt, + .set_fmt = gc2235_set_fmt, +}; + +static const struct v4l2_subdev_ops gc2235_ops = { + .core = &gc2235_core_ops, + .video = &gc2235_video_ops, + .pad = &gc2235_pad_ops, + .sensor = &gc2235_sensor_ops, +}; + +static int gc2235_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct gc2235_device *dev = to_gc2235_sensor(sd); + dev_dbg(&client->dev, "gc2235_remove...\n"); + + if (dev->platform_data->platform_deinit) + dev->platform_data->platform_deinit(); + + dev->platform_data->csi_cfg(sd, 0); + + v4l2_device_unregister_subdev(sd); + media_entity_cleanup(&dev->sd.entity); + v4l2_ctrl_handler_free(&dev->ctrl_handler); + kfree(dev); + + return 0; +} + +static int gc2235_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct gc2235_device *dev; + void *gcpdev; + int ret; + unsigned int i; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + dev_err(&client->dev, "out of memory\n"); + return -ENOMEM; + } + + mutex_init(&dev->input_lock); + + dev->fmt_idx = 0; + v4l2_i2c_subdev_init(&(dev->sd), client, &gc2235_ops); + + gcpdev = client->dev.platform_data; + if (ACPI_COMPANION(&client->dev)) + gcpdev = gmin_camera_platform_data(&dev->sd, + ATOMISP_INPUT_FORMAT_RAW_10, + atomisp_bayer_order_grbg); + + ret = gc2235_s_config(&dev->sd, client->irq, gcpdev); + if (ret) + goto out_free; + + dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + dev->pad.flags = MEDIA_PAD_FL_SOURCE; + dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; + dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = + v4l2_ctrl_handler_init(&dev->ctrl_handler, + ARRAY_SIZE(gc2235_controls)); + if (ret) { + gc2235_remove(client); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(gc2235_controls); i++) + v4l2_ctrl_new_custom(&dev->ctrl_handler, &gc2235_controls[i], + NULL); + + if (dev->ctrl_handler.error) { + gc2235_remove(client); + return dev->ctrl_handler.error; + } + + /* Use same lock for controls as for everything else. */ + dev->ctrl_handler.lock = &dev->input_lock; + dev->sd.ctrl_handler = &dev->ctrl_handler; + + ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); + if (ret) + gc2235_remove(client); + + if (ACPI_HANDLE(&client->dev)) + ret = atomisp_register_i2c_module(&dev->sd, gcpdev, RAW_CAMERA); + + return ret; +out_free: + v4l2_device_unregister_subdev(&dev->sd); + kfree(dev); + + return ret; +} + +static const struct acpi_device_id gc2235_acpi_match[] = { + { "INT33F8" }, + {}, +}; + +MODULE_DEVICE_TABLE(acpi, gc2235_acpi_match); +MODULE_DEVICE_TABLE(i2c, gc2235_id); +static struct i2c_driver gc2235_driver = { + .driver = { + .name = GC2235_NAME, + .acpi_match_table = ACPI_PTR(gc2235_acpi_match), + }, + .probe = gc2235_probe, + .remove = gc2235_remove, + .id_table = gc2235_id, +}; + +static int init_gc2235(void) +{ + return i2c_add_driver(&gc2235_driver); +} + +static void exit_gc2235(void) +{ + + i2c_del_driver(&gc2235_driver); +} + +module_init(init_gc2235); +module_exit(exit_gc2235); + +MODULE_AUTHOR("Shuguang Gong "); +MODULE_DESCRIPTION("A low-level driver for GC2235 sensors"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c b/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c new file mode 100644 index 000000000000..decb65cfd7c9 --- /dev/null +++ b/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2013 Intel Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ +#include +#include +#include +#include +#include "../include/linux/libmsrlisthelper.h" +#include +#include + +/* Tagged binary data container structure definitions. */ +struct tbd_header { + uint32_t tag; /*!< Tag identifier, also checks endianness */ + uint32_t size; /*!< Container size including this header */ + uint32_t version; /*!< Version, format 0xYYMMDDVV */ + uint32_t revision; /*!< Revision, format 0xYYMMDDVV */ + uint32_t config_bits; /*!< Configuration flag bits set */ + uint32_t checksum; /*!< Global checksum, header included */ +} __packed; + +struct tbd_record_header { + uint32_t size; /*!< Size of record including header */ + uint8_t format_id; /*!< tbd_format_t enumeration values used */ + uint8_t packing_key; /*!< Packing method; 0 = no packing */ + uint16_t class_id; /*!< tbd_class_t enumeration values used */ +} __packed; + +struct tbd_data_record_header { + uint16_t next_offset; + uint16_t flags; + uint16_t data_offset; + uint16_t data_size; +} __packed; + +#define TBD_CLASS_DRV_ID 2 + +static int set_msr_configuration(struct i2c_client *client, uint8_t *bufptr, + unsigned int size) +{ + /* The configuration data contains any number of sequences where + * the first byte (that is, uint8_t) that marks the number of bytes + * in the sequence to follow, is indeed followed by the indicated + * number of bytes of actual data to be written to sensor. + * By convention, the first two bytes of actual data should be + * understood as an address in the sensor address space (hibyte + * followed by lobyte) where the remaining data in the sequence + * will be written. */ + + uint8_t *ptr = bufptr; + while (ptr < bufptr + size) { + struct i2c_msg msg = { + .addr = client->addr, + .flags = 0, + }; + int ret; + + /* How many bytes */ + msg.len = *ptr++; + /* Where the bytes are located */ + msg.buf = ptr; + ptr += msg.len; + + if (ptr > bufptr + size) + /* Accessing data beyond bounds is not tolerated */ + return -EINVAL; + + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret < 0) { + dev_err(&client->dev, "i2c write error: %d", ret); + return ret; + } + } + return 0; +} + +static int parse_and_apply(struct i2c_client *client, uint8_t *buffer, + unsigned int size) +{ + uint8_t *endptr8 = buffer + size; + struct tbd_data_record_header *header = + (struct tbd_data_record_header *)buffer; + + /* There may be any number of datasets present */ + unsigned int dataset = 0; + + do { + /* In below, four variables are read from buffer */ + if ((uint8_t *)header + sizeof(*header) > endptr8) + return -EINVAL; + + /* All data should be located within given buffer */ + if ((uint8_t *)header + header->data_offset + + header->data_size > endptr8) + return -EINVAL; + + /* We have a new valid dataset */ + dataset++; + /* See whether there is MSR data */ + /* If yes, update the reg info */ + if (header->data_size && (header->flags & 1)) { + int ret; + + dev_info(&client->dev, + "New MSR data for sensor driver (dataset %02d) size:%d\n", + dataset, header->data_size); + ret = set_msr_configuration(client, + buffer + header->data_offset, + header->data_size); + if (ret) + return ret; + } + header = (struct tbd_data_record_header *)(buffer + + header->next_offset); + } while (header->next_offset); + + return 0; +} + +int apply_msr_data(struct i2c_client *client, const struct firmware *fw) +{ + struct tbd_header *header; + struct tbd_record_header *record; + + if (!fw) { + dev_warn(&client->dev, "Drv data is not loaded.\n"); + return -EINVAL; + } + + if (sizeof(*header) > fw->size) + return -EINVAL; + + header = (struct tbd_header *)fw->data; + /* Check that we have drvb block. */ + if (memcmp(&header->tag, "DRVB", 4)) + return -EINVAL; + + /* Check the size */ + if (header->size != fw->size) + return -EINVAL; + + if (sizeof(*header) + sizeof(*record) > fw->size) + return -EINVAL; + + record = (struct tbd_record_header *)(header + 1); + /* Check that class id mathes tbd's drv id. */ + if (record->class_id != TBD_CLASS_DRV_ID) + return -EINVAL; + + /* Size 0 shall not be treated as an error */ + if (!record->size) + return 0; + + return parse_and_apply(client, (uint8_t *)(record + 1), record->size); +} +EXPORT_SYMBOL_GPL(apply_msr_data); + +int load_msr_list(struct i2c_client *client, char *name, + const struct firmware **fw) +{ + int ret = request_firmware(fw, name, &client->dev); + if (ret) { + dev_err(&client->dev, + "Error %d while requesting firmware %s\n", + ret, name); + return ret; + } + dev_info(&client->dev, "Received %lu bytes drv data\n", + (unsigned long)(*fw)->size); + + return 0; +} +EXPORT_SYMBOL_GPL(load_msr_list); + +void release_msr_list(struct i2c_client *client, const struct firmware *fw) +{ + release_firmware(fw); +} +EXPORT_SYMBOL_GPL(release_msr_list); + +static int init_msrlisthelper(void) +{ + return 0; +} + +static void exit_msrlisthelper(void) +{ +} + +module_init(init_msrlisthelper); +module_exit(exit_msrlisthelper); + +MODULE_AUTHOR("Jukka Kaartinen "); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c new file mode 100644 index 000000000000..679176f7c542 --- /dev/null +++ b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c @@ -0,0 +1,1009 @@ +/* + * LED flash driver for LM3554 + * + * Copyright (c) 2010-2012 Intel Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ +#include +#include +#include +#include +#include +#include + +#include "../include/media/lm3554.h" +#include +#include +#include +#include +#include "../include/linux/atomisp_gmin_platform.h" +#include "../include/linux/atomisp.h" + +/* Registers */ + +#define LM3554_TORCH_BRIGHTNESS_REG 0xA0 +#define LM3554_TORCH_MODE_SHIFT 0 +#define LM3554_TORCH_CURRENT_SHIFT 3 +#define LM3554_INDICATOR_CURRENT_SHIFT 6 + +#define LM3554_FLASH_BRIGHTNESS_REG 0xB0 +#define LM3554_FLASH_MODE_SHIFT 0 +#define LM3554_FLASH_CURRENT_SHIFT 3 +#define LM3554_STROBE_SENSITIVITY_SHIFT 7 + +#define LM3554_FLASH_DURATION_REG 0xC0 +#define LM3554_FLASH_TIMEOUT_SHIFT 0 +#define LM3554_CURRENT_LIMIT_SHIFT 5 + +#define LM3554_FLAGS_REG 0xD0 +#define LM3554_FLAG_TIMEOUT (1 << 0) +#define LM3554_FLAG_THERMAL_SHUTDOWN (1 << 1) +#define LM3554_FLAG_LED_FAULT (1 << 2) +#define LM3554_FLAG_TX1_INTERRUPT (1 << 3) +#define LM3554_FLAG_TX2_INTERRUPT (1 << 4) +#define LM3554_FLAG_LED_THERMAL_FAULT (1 << 5) +#define LM3554_FLAG_UNUSED (1 << 6) +#define LM3554_FLAG_INPUT_VOLTAGE_LOW (1 << 7) + +#define LM3554_CONFIG_REG_1 0xE0 +#define LM3554_ENVM_TX2_SHIFT 5 +#define LM3554_TX2_POLARITY_SHIFT 6 + +struct lm3554 { + struct v4l2_subdev sd; + + struct mutex power_lock; + struct v4l2_ctrl_handler ctrl_handler; + int power_count; + + unsigned int mode; + int timeout; + u8 torch_current; + u8 indicator_current; + u8 flash_current; + + struct timer_list flash_off_delay; + struct lm3554_platform_data *pdata; +}; + +#define to_lm3554(p_sd) container_of(p_sd, struct lm3554, sd) + +/* Return negative errno else zero on success */ +static int lm3554_write(struct lm3554 *flash, u8 addr, u8 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(&flash->sd); + int ret; + + ret = i2c_smbus_write_byte_data(client, addr, val); + + dev_dbg(&client->dev, "Write Addr:%02X Val:%02X %s\n", addr, val, + ret < 0 ? "fail" : "ok"); + + return ret; +} + +/* Return negative errno else a data byte received from the device. */ +static int lm3554_read(struct lm3554 *flash, u8 addr) +{ + struct i2c_client *client = v4l2_get_subdevdata(&flash->sd); + int ret; + + ret = i2c_smbus_read_byte_data(client, addr); + + dev_dbg(&client->dev, "Read Addr:%02X Val:%02X %s\n", addr, ret, + ret < 0 ? "fail" : "ok"); + + return ret; +} + +/* ----------------------------------------------------------------------------- + * Hardware configuration + */ + +static int lm3554_set_mode(struct lm3554 *flash, unsigned int mode) +{ + u8 val; + int ret; + + val = (mode << LM3554_FLASH_MODE_SHIFT) | + (flash->flash_current << LM3554_FLASH_CURRENT_SHIFT); + + ret = lm3554_write(flash, LM3554_FLASH_BRIGHTNESS_REG, val); + if (ret == 0) + flash->mode = mode; + return ret; +} + +static int lm3554_set_torch(struct lm3554 *flash) +{ + u8 val; + + val = (flash->mode << LM3554_TORCH_MODE_SHIFT) | + (flash->torch_current << LM3554_TORCH_CURRENT_SHIFT) | + (flash->indicator_current << LM3554_INDICATOR_CURRENT_SHIFT); + + return lm3554_write(flash, LM3554_TORCH_BRIGHTNESS_REG, val); +} + +static int lm3554_set_flash(struct lm3554 *flash) +{ + u8 val; + + val = (flash->mode << LM3554_FLASH_MODE_SHIFT) | + (flash->flash_current << LM3554_FLASH_CURRENT_SHIFT); + + return lm3554_write(flash, LM3554_FLASH_BRIGHTNESS_REG, val); +} + +static int lm3554_set_duration(struct lm3554 *flash) +{ + u8 val; + + val = (flash->timeout << LM3554_FLASH_TIMEOUT_SHIFT) | + (flash->pdata->current_limit << LM3554_CURRENT_LIMIT_SHIFT); + + return lm3554_write(flash, LM3554_FLASH_DURATION_REG, val); +} + +static int lm3554_set_config1(struct lm3554 *flash) +{ + u8 val; + + val = (flash->pdata->envm_tx2 << LM3554_ENVM_TX2_SHIFT) | + (flash->pdata->tx2_polarity << LM3554_TX2_POLARITY_SHIFT); + return lm3554_write(flash, LM3554_CONFIG_REG_1, val); +} + +/* ----------------------------------------------------------------------------- + * Hardware trigger + */ +static void lm3554_flash_off_delay(long unsigned int arg) +{ + struct v4l2_subdev *sd = i2c_get_clientdata((struct i2c_client *)arg); + struct lm3554 *flash = to_lm3554(sd); + struct lm3554_platform_data *pdata = flash->pdata; + + gpio_set_value(pdata->gpio_strobe, 0); +} + +static int lm3554_hw_strobe(struct i2c_client *client, bool strobe) +{ + int ret, timer_pending; + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct lm3554 *flash = to_lm3554(sd); + struct lm3554_platform_data *pdata = flash->pdata; + + /* + * An abnormal high flash current is observed when strobe off the + * flash. Workaround here is firstly set flash current to lower level, + * wait a short moment, and then strobe off the flash. + */ + + timer_pending = del_timer_sync(&flash->flash_off_delay); + + /* Flash off */ + if (!strobe) { + /* set current to 70mA and wait a while */ + ret = lm3554_write(flash, LM3554_FLASH_BRIGHTNESS_REG, 0); + if (ret < 0) + goto err; + mod_timer(&flash->flash_off_delay, + jiffies + msecs_to_jiffies(LM3554_TIMER_DELAY)); + return 0; + } + + /* Flash on */ + + /* + * If timer is killed before run, flash is not strobe off, + * so must strobe off here + */ + if (timer_pending) + gpio_set_value(pdata->gpio_strobe, 0); + + /* Restore flash current settings */ + ret = lm3554_set_flash(flash); + if (ret < 0) + goto err; + + /* Strobe on Flash */ + gpio_set_value(pdata->gpio_strobe, 1); + + return 0; +err: + dev_err(&client->dev, "failed to %s flash strobe (%d)\n", + strobe ? "on" : "off", ret); + return ret; +} + +/* ----------------------------------------------------------------------------- + * V4L2 controls + */ + +static int lm3554_read_status(struct lm3554 *flash) +{ + int ret; + struct i2c_client *client = v4l2_get_subdevdata(&flash->sd); + + /* NOTE: reading register clear fault status */ + ret = lm3554_read(flash, LM3554_FLAGS_REG); + if (ret < 0) + return ret; + + /* + * Accordingly to datasheet we read back '1' in bit 6. + * Clear it first. + */ + ret &= ~LM3554_FLAG_UNUSED; + + /* + * Do not take TX1/TX2 signal as an error + * because MSIC will not turn off flash, but turn to + * torch mode according to gsm modem signal by hardware. + */ + ret &= ~(LM3554_FLAG_TX1_INTERRUPT | LM3554_FLAG_TX2_INTERRUPT); + + if (ret > 0) + dev_dbg(&client->dev, "LM3554 flag status: %02x\n", ret); + + return ret; +} + +static int lm3554_s_flash_timeout(struct v4l2_subdev *sd, u32 val) +{ + struct lm3554 *flash = to_lm3554(sd); + + val = clamp(val, LM3554_MIN_TIMEOUT, LM3554_MAX_TIMEOUT); + val = val / LM3554_TIMEOUT_STEPSIZE - 1; + + flash->timeout = val; + + return lm3554_set_duration(flash); +} + +static int lm3554_g_flash_timeout(struct v4l2_subdev *sd, s32 *val) +{ + struct lm3554 *flash = to_lm3554(sd); + + *val = (u32)(flash->timeout + 1) * LM3554_TIMEOUT_STEPSIZE; + + return 0; +} + +static int lm3554_s_flash_intensity(struct v4l2_subdev *sd, u32 intensity) +{ + struct lm3554 *flash = to_lm3554(sd); + + intensity = LM3554_CLAMP_PERCENTAGE(intensity); + intensity = LM3554_PERCENT_TO_VALUE(intensity, LM3554_FLASH_STEP); + + flash->flash_current = intensity; + + return lm3554_set_flash(flash); +} + +static int lm3554_g_flash_intensity(struct v4l2_subdev *sd, s32 *val) +{ + struct lm3554 *flash = to_lm3554(sd); + + *val = LM3554_VALUE_TO_PERCENT((u32)flash->flash_current, + LM3554_FLASH_STEP); + + return 0; +} + +static int lm3554_s_torch_intensity(struct v4l2_subdev *sd, u32 intensity) +{ + struct lm3554 *flash = to_lm3554(sd); + + intensity = LM3554_CLAMP_PERCENTAGE(intensity); + intensity = LM3554_PERCENT_TO_VALUE(intensity, LM3554_TORCH_STEP); + + flash->torch_current = intensity; + + return lm3554_set_torch(flash); +} + +static int lm3554_g_torch_intensity(struct v4l2_subdev *sd, s32 *val) +{ + struct lm3554 *flash = to_lm3554(sd); + + *val = LM3554_VALUE_TO_PERCENT((u32)flash->torch_current, + LM3554_TORCH_STEP); + + return 0; +} + +static int lm3554_s_indicator_intensity(struct v4l2_subdev *sd, u32 intensity) +{ + struct lm3554 *flash = to_lm3554(sd); + + intensity = LM3554_CLAMP_PERCENTAGE(intensity); + intensity = LM3554_PERCENT_TO_VALUE(intensity, LM3554_INDICATOR_STEP); + + flash->indicator_current = intensity; + + return lm3554_set_torch(flash); +} + +static int lm3554_g_indicator_intensity(struct v4l2_subdev *sd, s32 *val) +{ + struct lm3554 *flash = to_lm3554(sd); + + *val = LM3554_VALUE_TO_PERCENT((u32)flash->indicator_current, + LM3554_INDICATOR_STEP); + + return 0; +} + +static int lm3554_s_flash_strobe(struct v4l2_subdev *sd, u32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return lm3554_hw_strobe(client, val); +} + +static int lm3554_s_flash_mode(struct v4l2_subdev *sd, u32 new_mode) +{ + struct lm3554 *flash = to_lm3554(sd); + unsigned int mode; + + switch (new_mode) { + case ATOMISP_FLASH_MODE_OFF: + mode = LM3554_MODE_SHUTDOWN; + break; + case ATOMISP_FLASH_MODE_FLASH: + mode = LM3554_MODE_FLASH; + break; + case ATOMISP_FLASH_MODE_INDICATOR: + mode = LM3554_MODE_INDICATOR; + break; + case ATOMISP_FLASH_MODE_TORCH: + mode = LM3554_MODE_TORCH; + break; + default: + return -EINVAL; + } + + return lm3554_set_mode(flash, mode); +} + +static int lm3554_g_flash_mode(struct v4l2_subdev *sd, s32 *val) +{ + struct lm3554 *flash = to_lm3554(sd); + *val = flash->mode; + return 0; +} + +static int lm3554_g_flash_status(struct v4l2_subdev *sd, s32 *val) +{ + struct lm3554 *flash = to_lm3554(sd); + int value; + + value = lm3554_read_status(flash); + if (value < 0) + return value; + + if (value & LM3554_FLAG_TIMEOUT) + *val = ATOMISP_FLASH_STATUS_TIMEOUT; + else if (value > 0) + *val = ATOMISP_FLASH_STATUS_HW_ERROR; + else + *val = ATOMISP_FLASH_STATUS_OK; + + return 0; +} + +#ifndef CSS15 +static int lm3554_g_flash_status_register(struct v4l2_subdev *sd, s32 *val) +{ + struct lm3554 *flash = to_lm3554(sd); + int ret; + + ret = lm3554_read(flash, LM3554_FLAGS_REG); + + if (ret < 0) + return ret; + + *val = ret; + return 0; +} +#endif + +static int lm3554_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct lm3554 *dev = + container_of(ctrl->handler, struct lm3554, ctrl_handler); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_FLASH_TIMEOUT: + ret = lm3554_s_flash_timeout(&dev->sd, ctrl->val); + break; + case V4L2_CID_FLASH_INTENSITY: + ret = lm3554_s_flash_intensity(&dev->sd, ctrl->val); + break; + case V4L2_CID_FLASH_TORCH_INTENSITY: + ret = lm3554_s_torch_intensity(&dev->sd, ctrl->val); + break; + case V4L2_CID_FLASH_INDICATOR_INTENSITY: + ret = lm3554_s_indicator_intensity(&dev->sd, ctrl->val); + break; + case V4L2_CID_FLASH_STROBE: + ret = lm3554_s_flash_strobe(&dev->sd, ctrl->val); + break; + case V4L2_CID_FLASH_MODE: + ret = lm3554_s_flash_mode(&dev->sd, ctrl->val); + break; + default: + ret = -EINVAL; + } + return ret; +} + +static int lm3554_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct lm3554 *dev = + container_of(ctrl->handler, struct lm3554, ctrl_handler); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_FLASH_TIMEOUT: + ret = lm3554_g_flash_timeout(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FLASH_INTENSITY: + ret = lm3554_g_flash_intensity(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FLASH_TORCH_INTENSITY: + ret = lm3554_g_torch_intensity(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FLASH_INDICATOR_INTENSITY: + ret = lm3554_g_indicator_intensity(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FLASH_MODE: + ret = lm3554_g_flash_mode(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FLASH_STATUS: + ret = lm3554_g_flash_status(&dev->sd, &ctrl->val); + break; +#ifndef CSS15 + case V4L2_CID_FLASH_STATUS_REGISTER: + ret = lm3554_g_flash_status_register(&dev->sd, &ctrl->val); + break; +#endif + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops ctrl_ops = { + .s_ctrl = lm3554_s_ctrl, + .g_volatile_ctrl = lm3554_g_volatile_ctrl +}; + +static const struct v4l2_ctrl_config lm3554_controls[] = { + { + .ops = &ctrl_ops, + .id = V4L2_CID_FLASH_TIMEOUT, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Flash Timeout", + .min = 0x0, + .max = LM3554_MAX_TIMEOUT, + .step = 0x01, + .def = LM3554_DEFAULT_TIMEOUT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FLASH_INTENSITY, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Flash Intensity", + .min = LM3554_MIN_PERCENT, + .max = LM3554_MAX_PERCENT, + .step = 0x01, + .def = LM3554_FLASH_DEFAULT_BRIGHTNESS, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FLASH_TORCH_INTENSITY, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Torch Intensity", + .min = LM3554_MIN_PERCENT, + .max = LM3554_MAX_PERCENT, + .step = 0x01, + .def = LM3554_TORCH_DEFAULT_BRIGHTNESS, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FLASH_INDICATOR_INTENSITY, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Indicator Intensity", + .min = LM3554_MIN_PERCENT, + .max = LM3554_MAX_PERCENT, + .step = 0x01, + .def = LM3554_INDICATOR_DEFAULT_BRIGHTNESS, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FLASH_STROBE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flash Strobe", + .min = 0, + .max = 1, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FLASH_MODE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Flash Mode", + .min = 0, + .max = 100, + .step = 1, + .def = ATOMISP_FLASH_MODE_OFF, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FLASH_STATUS, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flash Status", + .min = 0, + .max = 100, + .step = 1, + .def = ATOMISP_FLASH_STATUS_OK, + .flags = 0, + }, +#ifndef CSS15 + { + .ops = &ctrl_ops, + .id = V4L2_CID_FLASH_STATUS_REGISTER, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flash Status Register", + .min = 0, + .max = 100, + .step = 1, + .def = 0, + .flags = 0, + }, +#endif +}; + +/* ----------------------------------------------------------------------------- + * V4L2 subdev core operations + */ + +/* Put device into known state. */ +static int lm3554_setup(struct lm3554 *flash) +{ + struct i2c_client *client = v4l2_get_subdevdata(&flash->sd); + int ret; + + /* clear the flags register */ + ret = lm3554_read(flash, LM3554_FLAGS_REG); + if (ret < 0) + return ret; + + dev_dbg(&client->dev, "Fault info: %02x\n", ret); + + ret = lm3554_set_config1(flash); + if (ret < 0) + return ret; + + ret = lm3554_set_duration(flash); + if (ret < 0) + return ret; + + ret = lm3554_set_torch(flash); + if (ret < 0) + return ret; + + ret = lm3554_set_flash(flash); + if (ret < 0) + return ret; + + /* read status */ + ret = lm3554_read_status(flash); + if (ret < 0) + return ret; + + return ret ? -EIO : 0; +} + +static int __lm3554_s_power(struct lm3554 *flash, int power) +{ + struct lm3554_platform_data *pdata = flash->pdata; + int ret; + + /*initialize flash driver*/ + gpio_set_value(pdata->gpio_reset, power); + usleep_range(100, 100 + 1); + + if (power) { + /* Setup default values. This makes sure that the chip + * is in a known state. + */ + ret = lm3554_setup(flash); + if (ret < 0) { + __lm3554_s_power(flash, 0); + return ret; + } + } + + return 0; +} + +static int lm3554_s_power(struct v4l2_subdev *sd, int power) +{ + struct lm3554 *flash = to_lm3554(sd); + int ret = 0; + + mutex_lock(&flash->power_lock); + + if (flash->power_count == !power) { + ret = __lm3554_s_power(flash, !!power); + if (ret < 0) + goto done; + } + + flash->power_count += power ? 1 : -1; + WARN_ON(flash->power_count < 0); + +done: + mutex_unlock(&flash->power_lock); + return ret; +} + +static const struct v4l2_subdev_core_ops lm3554_core_ops = { + .s_power = lm3554_s_power, +}; + +static const struct v4l2_subdev_ops lm3554_ops = { + .core = &lm3554_core_ops, +}; + +static int lm3554_detect(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct i2c_adapter *adapter = client->adapter; + struct lm3554 *flash = to_lm3554(sd); + int ret; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&client->dev, "lm3554_detect i2c error\n"); + return -ENODEV; + } + + /* Power up the flash driver and reset it */ + ret = lm3554_s_power(&flash->sd, 1); + if (ret < 0) { + dev_err(&client->dev, "Failed to power on lm3554 LED flash\n"); + } else { + dev_dbg(&client->dev, "Successfully detected lm3554 LED flash\n"); + lm3554_s_power(&flash->sd, 0); + } + + return ret; +} + +static int lm3554_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return lm3554_s_power(sd, 1); +} + +static int lm3554_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return lm3554_s_power(sd, 0); +} + +static const struct v4l2_subdev_internal_ops lm3554_internal_ops = { + .registered = lm3554_detect, + .open = lm3554_open, + .close = lm3554_close, +}; + +/* ----------------------------------------------------------------------------- + * I2C driver + */ +#ifdef CONFIG_PM + +static int lm3554_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct lm3554 *flash = to_lm3554(subdev); + int rval; + + if (flash->power_count == 0) + return 0; + + rval = __lm3554_s_power(flash, 0); + + dev_dbg(&client->dev, "Suspend %s\n", rval < 0 ? "failed" : "ok"); + + return rval; +} + +static int lm3554_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct lm3554 *flash = to_lm3554(subdev); + int rval; + + if (flash->power_count == 0) + return 0; + + rval = __lm3554_s_power(flash, 1); + + dev_dbg(&client->dev, "Resume %s\n", rval < 0 ? "fail" : "ok"); + + return rval; +} + +#else + +#define lm3554_suspend NULL +#define lm3554_resume NULL + +#endif /* CONFIG_PM */ + +static int lm3554_gpio_init(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct lm3554 *flash = to_lm3554(sd); + struct lm3554_platform_data *pdata = flash->pdata; + int ret; + + if (!gpio_is_valid(pdata->gpio_reset)) + return -EINVAL; + + ret = gpio_direction_output(pdata->gpio_reset, 0); + if (ret < 0) + goto err_gpio_reset; + dev_info(&client->dev, "flash led reset successfully\n"); + + if (!gpio_is_valid(pdata->gpio_strobe)) { + ret = -EINVAL; + goto err_gpio_dir_reset; + } + + ret = gpio_direction_output(pdata->gpio_strobe, 0); + if (ret < 0) + goto err_gpio_strobe; + + return 0; + +err_gpio_strobe: + gpio_free(pdata->gpio_strobe); +err_gpio_dir_reset: + gpio_direction_output(pdata->gpio_reset, 0); +err_gpio_reset: + gpio_free(pdata->gpio_reset); + + return ret; +} + +static int lm3554_gpio_uninit(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct lm3554 *flash = to_lm3554(sd); + struct lm3554_platform_data *pdata = flash->pdata; + int ret; + + ret = gpio_direction_output(pdata->gpio_strobe, 0); + if (ret < 0) + return ret; + + ret = gpio_direction_output(pdata->gpio_reset, 0); + if (ret < 0) + return ret; + + gpio_free(pdata->gpio_strobe); + gpio_free(pdata->gpio_reset); + return 0; +} + +static void *lm3554_platform_data_func(struct i2c_client *client) +{ + static struct lm3554_platform_data platform_data; + + if (ACPI_COMPANION(&client->dev)) { + platform_data.gpio_reset = + desc_to_gpio(gpiod_get_index(&(client->dev), + NULL, 2, GPIOD_OUT_LOW)); + platform_data.gpio_strobe = + desc_to_gpio(gpiod_get_index(&(client->dev), + NULL, 0, GPIOD_OUT_LOW)); + platform_data.gpio_torch = + desc_to_gpio(gpiod_get_index(&(client->dev), + NULL, 1, GPIOD_OUT_LOW)); + } else { + platform_data.gpio_reset = -1; + platform_data.gpio_strobe = -1; + platform_data.gpio_torch = -1; + } + + dev_info(&client->dev, "camera pdata: lm3554: reset: %d strobe %d torch %d\n", + platform_data.gpio_reset, platform_data.gpio_strobe, + platform_data.gpio_torch); + + /* Set to TX2 mode, then ENVM/TX2 pin is a power amplifier sync input: + * ENVM/TX pin asserted, flash forced into torch; + * ENVM/TX pin desserted, flash set back; + */ + platform_data.envm_tx2 = 1; + platform_data.tx2_polarity = 0; + + /* set peak current limit to be 1000mA */ + platform_data.current_limit = 0; + + return &platform_data; +} + +static int lm3554_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err = 0; + struct lm3554 *flash; + unsigned int i; + int ret; + + flash = kzalloc(sizeof(*flash), GFP_KERNEL); + if (!flash) { + dev_err(&client->dev, "out of memory\n"); + return -ENOMEM; + } + + flash->pdata = client->dev.platform_data; + + if (!flash->pdata || ACPI_COMPANION(&client->dev)) + flash->pdata = lm3554_platform_data_func(client); + + v4l2_i2c_subdev_init(&flash->sd, client, &lm3554_ops); + flash->sd.internal_ops = &lm3554_internal_ops; + flash->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + flash->mode = ATOMISP_FLASH_MODE_OFF; + flash->timeout = LM3554_MAX_TIMEOUT / LM3554_TIMEOUT_STEPSIZE - 1; + ret = + v4l2_ctrl_handler_init(&flash->ctrl_handler, + ARRAY_SIZE(lm3554_controls)); + if (ret) { + dev_err(&client->dev, "error initialize a ctrl_handler.\n"); + goto fail2; + } + + for (i = 0; i < ARRAY_SIZE(lm3554_controls); i++) + v4l2_ctrl_new_custom(&flash->ctrl_handler, &lm3554_controls[i], + NULL); + + if (flash->ctrl_handler.error) { + + dev_err(&client->dev, "ctrl_handler error.\n"); + goto fail2; + } + + flash->sd.ctrl_handler = &flash->ctrl_handler; + err = media_entity_pads_init(&flash->sd.entity, 0, NULL); + if (err) { + dev_err(&client->dev, "error initialize a media entity.\n"); + goto fail1; + } + + flash->sd.entity.function = MEDIA_ENT_F_FLASH; + + mutex_init(&flash->power_lock); + + setup_timer(&flash->flash_off_delay, lm3554_flash_off_delay, + (unsigned long)client); + + err = lm3554_gpio_init(client); + if (err) { + dev_err(&client->dev, "gpio request/direction_output fail"); + goto fail2; + } + if (ACPI_HANDLE(&client->dev)) + err = atomisp_register_i2c_module(&flash->sd, NULL, LED_FLASH); + return 0; +fail2: + media_entity_cleanup(&flash->sd.entity); + v4l2_ctrl_handler_free(&flash->ctrl_handler); +fail1: + v4l2_device_unregister_subdev(&flash->sd); + kfree(flash); + + return err; +} + +static int lm3554_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct lm3554 *flash = to_lm3554(sd); + int ret; + + media_entity_cleanup(&flash->sd.entity); + v4l2_ctrl_handler_free(&flash->ctrl_handler); + v4l2_device_unregister_subdev(sd); + + atomisp_gmin_remove_subdev(sd); + + del_timer_sync(&flash->flash_off_delay); + + ret = lm3554_gpio_uninit(client); + if (ret < 0) + goto fail; + + kfree(flash); + + return 0; +fail: + dev_err(&client->dev, "gpio request/direction_output fail"); + return ret; +} + +static const struct i2c_device_id lm3554_id[] = { + {LM3554_NAME, 0}, + {}, +}; + +MODULE_DEVICE_TABLE(i2c, lm3554_id); + +static const struct dev_pm_ops lm3554_pm_ops = { + .suspend = lm3554_suspend, + .resume = lm3554_resume, +}; + +static const struct acpi_device_id lm3554_acpi_match[] = { + { "INTCF1C" }, + {}, +}; + +MODULE_DEVICE_TABLE(acpi, lm3554_acpi_match); + +static struct i2c_driver lm3554_driver = { + .driver = { + .name = LM3554_NAME, + .pm = &lm3554_pm_ops, + .acpi_match_table = ACPI_PTR(lm3554_acpi_match), + }, + .probe = lm3554_probe, + .remove = lm3554_remove, + .id_table = lm3554_id, +}; + +static __init int init_lm3554(void) +{ + return i2c_add_driver(&lm3554_driver); +} + +static __exit void exit_lm3554(void) +{ + i2c_del_driver(&lm3554_driver); +} + +module_init(init_lm3554); +module_exit(exit_lm3554); +MODULE_AUTHOR("Jing Tao "); +MODULE_DESCRIPTION("LED flash driver for LM3554"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c new file mode 100644 index 000000000000..3c837cb8859c --- /dev/null +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -0,0 +1,1963 @@ +/* + * Support for mt9m114 Camera Sensor. + * + * Copyright (c) 2010 Intel Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/linux/atomisp_gmin_platform.h" +#include + +#include "mt9m114.h" + +#define to_mt9m114_sensor(sd) container_of(sd, struct mt9m114_device, sd) + +/* + * TODO: use debug parameter to actually define when debug messages should + * be printed. + */ +static int debug; +static int aaalock; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level (0-1)"); + +static int mt9m114_t_vflip(struct v4l2_subdev *sd, int value); +static int mt9m114_t_hflip(struct v4l2_subdev *sd, int value); +static int mt9m114_wait_state(struct i2c_client *client, int timeout); + +static int +mt9m114_read_reg(struct i2c_client *client, u16 data_length, u32 reg, u32 *val) +{ + int err; + struct i2c_msg msg[2]; + unsigned char data[4]; + + if (!client->adapter) { + v4l2_err(client, "%s error, no client->adapter\n", __func__); + return -ENODEV; + } + + if (data_length != MISENSOR_8BIT && data_length != MISENSOR_16BIT + && data_length != MISENSOR_32BIT) { + v4l2_err(client, "%s error, invalid data length\n", __func__); + return -EINVAL; + } + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = MSG_LEN_OFFSET; + msg[0].buf = data; + + /* high byte goes out first */ + data[0] = (u16) (reg >> 8); + data[1] = (u16) (reg & 0xff); + + msg[1].addr = client->addr; + msg[1].len = data_length; + msg[1].flags = I2C_M_RD; + msg[1].buf = data; + + err = i2c_transfer(client->adapter, msg, 2); + + if (err >= 0) { + *val = 0; + /* high byte comes first */ + if (data_length == MISENSOR_8BIT) + *val = data[0]; + else if (data_length == MISENSOR_16BIT) + *val = data[1] + (data[0] << 8); + else + *val = data[3] + (data[2] << 8) + + (data[1] << 16) + (data[0] << 24); + + return 0; + } + + dev_err(&client->dev, "read from offset 0x%x error %d", reg, err); + return err; +} + +static int +mt9m114_write_reg(struct i2c_client *client, u16 data_length, u16 reg, u32 val) +{ + int num_msg; + struct i2c_msg msg; + unsigned char data[6] = {0}; + u16 *wreg; + int retry = 0; + + if (!client->adapter) { + v4l2_err(client, "%s error, no client->adapter\n", __func__); + return -ENODEV; + } + + if (data_length != MISENSOR_8BIT && data_length != MISENSOR_16BIT + && data_length != MISENSOR_32BIT) { + v4l2_err(client, "%s error, invalid data_length\n", __func__); + return -EINVAL; + } + + memset(&msg, 0, sizeof(msg)); + +again: + msg.addr = client->addr; + msg.flags = 0; + msg.len = 2 + data_length; + msg.buf = data; + + /* high byte goes out first */ + wreg = (u16 *)data; + *wreg = cpu_to_be16(reg); + + if (data_length == MISENSOR_8BIT) { + data[2] = (u8)(val); + } else if (data_length == MISENSOR_16BIT) { + u16 *wdata = (u16 *)&data[2]; + *wdata = be16_to_cpu((u16)val); + } else { + /* MISENSOR_32BIT */ + u32 *wdata = (u32 *)&data[2]; + *wdata = be32_to_cpu(val); + } + + num_msg = i2c_transfer(client->adapter, &msg, 1); + + /* + * HACK: Need some delay here for Rev 2 sensors otherwise some + * registers do not seem to load correctly. + */ + mdelay(1); + + if (num_msg >= 0) + return 0; + + dev_err(&client->dev, "write error: wrote 0x%x to offset 0x%x error %d", + val, reg, num_msg); + if (retry <= I2C_RETRY_COUNT) { + dev_dbg(&client->dev, "retrying... %d", retry); + retry++; + msleep(20); + goto again; + } + + return num_msg; +} + +/** + * misensor_rmw_reg - Read/Modify/Write a value to a register in the sensor + * device + * @client: i2c driver client structure + * @data_length: 8/16/32-bits length + * @reg: register address + * @mask: masked out bits + * @set: bits set + * + * Read/modify/write a value to a register in the sensor device. + * Returns zero if successful, or non-zero otherwise. + */ +static int +misensor_rmw_reg(struct i2c_client *client, u16 data_length, u16 reg, + u32 mask, u32 set) +{ + int err; + u32 val; + + /* Exit when no mask */ + if (mask == 0) + return 0; + + /* @mask must not exceed data length */ + switch (data_length) { + case MISENSOR_8BIT: + if (mask & ~0xff) + return -EINVAL; + break; + case MISENSOR_16BIT: + if (mask & ~0xffff) + return -EINVAL; + break; + case MISENSOR_32BIT: + break; + default: + /* Wrong @data_length */ + return -EINVAL; + } + + err = mt9m114_read_reg(client, data_length, reg, &val); + if (err) { + v4l2_err(client, "misensor_rmw_reg error exit, read failed\n"); + return -EINVAL; + } + + val &= ~mask; + + /* + * Perform the OR function if the @set exists. + * Shift @set value to target bit location. @set should set only + * bits included in @mask. + * + * REVISIT: This function expects @set to be non-shifted. Its shift + * value is then defined to be equal to mask's LSB position. + * How about to inform values in their right offset position and avoid + * this unneeded shift operation? + */ + set <<= ffs(mask) - 1; + val |= set & mask; + + err = mt9m114_write_reg(client, data_length, reg, val); + if (err) { + v4l2_err(client, "misensor_rmw_reg error exit, write failed\n"); + return -EINVAL; + } + + return 0; +} + + +static int __mt9m114_flush_reg_array(struct i2c_client *client, + struct mt9m114_write_ctrl *ctrl) +{ + struct i2c_msg msg; + const int num_msg = 1; + int ret; + int retry = 0; + + if (ctrl->index == 0) + return 0; + +again: + msg.addr = client->addr; + msg.flags = 0; + msg.len = 2 + ctrl->index; + ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr); + msg.buf = (u8 *)&ctrl->buffer; + + ret = i2c_transfer(client->adapter, &msg, num_msg); + if (ret != num_msg) { + if (++retry <= I2C_RETRY_COUNT) { + dev_dbg(&client->dev, "retrying... %d\n", retry); + msleep(20); + goto again; + } + dev_err(&client->dev, "%s: i2c transfer error\n", __func__); + return -EIO; + } + + ctrl->index = 0; + + /* + * REVISIT: Previously we had a delay after writing data to sensor. + * But it was removed as our tests have shown it is not necessary + * anymore. + */ + + return 0; +} + +static int __mt9m114_buf_reg_array(struct i2c_client *client, + struct mt9m114_write_ctrl *ctrl, + const struct misensor_reg *next) +{ + u16 *data16; + u32 *data32; + int err; + + /* Insufficient buffer? Let's flush and get more free space. */ + if (ctrl->index + next->length >= MT9M114_MAX_WRITE_BUF_SIZE) { + err = __mt9m114_flush_reg_array(client, ctrl); + if (err) + return err; + } + + switch (next->length) { + case MISENSOR_8BIT: + ctrl->buffer.data[ctrl->index] = (u8)next->val; + break; + case MISENSOR_16BIT: + data16 = (u16 *)&ctrl->buffer.data[ctrl->index]; + *data16 = cpu_to_be16((u16)next->val); + break; + case MISENSOR_32BIT: + data32 = (u32 *)&ctrl->buffer.data[ctrl->index]; + *data32 = cpu_to_be32(next->val); + break; + default: + return -EINVAL; + } + + /* When first item is added, we need to store its starting address */ + if (ctrl->index == 0) + ctrl->buffer.addr = next->reg; + + ctrl->index += next->length; + + return 0; +} + +static int +__mt9m114_write_reg_is_consecutive(struct i2c_client *client, + struct mt9m114_write_ctrl *ctrl, + const struct misensor_reg *next) +{ + if (ctrl->index == 0) + return 1; + + return ctrl->buffer.addr + ctrl->index == next->reg; +} + +/* + * mt9m114_write_reg_array - Initializes a list of mt9m114 registers + * @client: i2c driver client structure + * @reglist: list of registers to be written + * @poll: completion polling requirement + * This function initializes a list of registers. When consecutive addresses + * are found in a row on the list, this function creates a buffer and sends + * consecutive data in a single i2c_transfer(). + * + * __mt9m114_flush_reg_array, __mt9m114_buf_reg_array() and + * __mt9m114_write_reg_is_consecutive() are internal functions to + * mt9m114_write_reg_array() and should be not used anywhere else. + * + */ +static int mt9m114_write_reg_array(struct i2c_client *client, + const struct misensor_reg *reglist, + int poll) +{ + const struct misensor_reg *next = reglist; + struct mt9m114_write_ctrl ctrl; + int err; + + if (poll == PRE_POLLING) { + err = mt9m114_wait_state(client, MT9M114_WAIT_STAT_TIMEOUT); + if (err) + return err; + } + + ctrl.index = 0; + for (; next->length != MISENSOR_TOK_TERM; next++) { + switch (next->length & MISENSOR_TOK_MASK) { + case MISENSOR_TOK_DELAY: + err = __mt9m114_flush_reg_array(client, &ctrl); + if (err) + return err; + msleep(next->val); + break; + case MISENSOR_TOK_RMW: + err = __mt9m114_flush_reg_array(client, &ctrl); + err |= misensor_rmw_reg(client, + next->length & + ~MISENSOR_TOK_RMW, + next->reg, next->val, + next->val2); + if (err) { + dev_err(&client->dev, "%s read err. aborted\n", + __func__); + return -EINVAL; + } + break; + default: + /* + * If next address is not consecutive, data needs to be + * flushed before proceed. + */ + if (!__mt9m114_write_reg_is_consecutive(client, &ctrl, + next)) { + err = __mt9m114_flush_reg_array(client, &ctrl); + if (err) + return err; + } + err = __mt9m114_buf_reg_array(client, &ctrl, next); + if (err) { + v4l2_err(client, "%s: write error, aborted\n", + __func__); + return err; + } + break; + } + } + + err = __mt9m114_flush_reg_array(client, &ctrl); + if (err) + return err; + + if (poll == POST_POLLING) + return mt9m114_wait_state(client, MT9M114_WAIT_STAT_TIMEOUT); + + return 0; +} + +static int mt9m114_wait_state(struct i2c_client *client, int timeout) +{ + int ret; + unsigned int val; + + while (timeout-- > 0) { + ret = mt9m114_read_reg(client, MISENSOR_16BIT, 0x0080, &val); + if (ret) + return ret; + if ((val & 0x2) == 0) + return 0; + msleep(20); + } + + return -EINVAL; + +} + +static int mt9m114_set_suspend(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + return mt9m114_write_reg_array(client, + mt9m114_standby_reg, POST_POLLING); +} + +static int mt9m114_init_common(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return mt9m114_write_reg_array(client, mt9m114_common, PRE_POLLING); +} + +static int power_ctrl(struct v4l2_subdev *sd, bool flag) +{ + int ret; + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->power_ctrl) + return dev->platform_data->power_ctrl(sd, flag); + + if (flag) { + ret = dev->platform_data->v2p8_ctrl(sd, 1); + if (ret == 0) { + ret = dev->platform_data->v1p8_ctrl(sd, 1); + if (ret) + ret = dev->platform_data->v2p8_ctrl(sd, 0); + } + } else { + ret = dev->platform_data->v2p8_ctrl(sd, 0); + ret = dev->platform_data->v1p8_ctrl(sd, 0); + } + return ret; +} + +static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) +{ + int ret; + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->gpio_ctrl) + return dev->platform_data->gpio_ctrl(sd, flag); + + /* Note: current modules wire only one GPIO signal (RESET#), + * but the schematic wires up two to the connector. BIOS + * versions have been unfortunately inconsistent with which + * ACPI index RESET# is on, so hit both */ + + if (flag) { + ret = dev->platform_data->gpio0_ctrl(sd, 0); + ret = dev->platform_data->gpio1_ctrl(sd, 0); + msleep(60); + ret |= dev->platform_data->gpio0_ctrl(sd, 1); + ret |= dev->platform_data->gpio1_ctrl(sd, 1); + } else { + ret = dev->platform_data->gpio0_ctrl(sd, 0); + ret = dev->platform_data->gpio1_ctrl(sd, 0); + } + return ret; +} + +static int power_up(struct v4l2_subdev *sd) +{ + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + if (NULL == dev->platform_data) { + dev_err(&client->dev, "no camera_sensor_platform_data"); + return -ENODEV; + } + + /* power control */ + ret = power_ctrl(sd, 1); + if (ret) + goto fail_power; + + /* flis clock control */ + ret = dev->platform_data->flisclk_ctrl(sd, 1); + if (ret) + goto fail_clk; + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 1); + if (ret) + dev_err(&client->dev, "gpio failed 1\n"); + /* + * according to DS, 44ms is needed between power up and first i2c + * commend + */ + msleep(50); + + return 0; + +fail_clk: + dev->platform_data->flisclk_ctrl(sd, 0); +fail_power: + power_ctrl(sd, 0); + dev_err(&client->dev, "sensor power-up failed\n"); + + return ret; +} + +static int power_down(struct v4l2_subdev *sd) +{ + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + if (NULL == dev->platform_data) { + dev_err(&client->dev, "no camera_sensor_platform_data"); + return -ENODEV; + } + + ret = dev->platform_data->flisclk_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "flisclk failed\n"); + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "gpio failed 1\n"); + + /* power control */ + ret = power_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "vprog failed.\n"); + + /*according to DS, 20ms is needed after power down*/ + msleep(20); + + return ret; +} + +static int mt9m114_s_power(struct v4l2_subdev *sd, int power) +{ + if (power == 0) + return power_down(sd); + else { + if (power_up(sd)) + return -EINVAL; + + return mt9m114_init_common(sd); + } +} + +/* + * distance - calculate the distance + * @res: resolution + * @w: width + * @h: height + * + * Get the gap between resolution and w/h. + * res->width/height smaller than w/h wouldn't be considered. + * Returns the value of gap or -1 if fail. + */ +#define LARGEST_ALLOWED_RATIO_MISMATCH 600 +static int distance(struct mt9m114_res_struct const *res, u32 w, u32 h) +{ + unsigned int w_ratio; + unsigned int h_ratio; + int match; + + if (w == 0) + return -1; + w_ratio = (res->width << 13) / w; + if (h == 0) + return -1; + h_ratio = (res->height << 13) / h; + if (h_ratio == 0) + return -1; + match = abs(((w_ratio << 13) / h_ratio) - 8192); + + if ((w_ratio < 8192) || (h_ratio < 8192) || + (match > LARGEST_ALLOWED_RATIO_MISMATCH)) + return -1; + + return w_ratio + h_ratio; +} + +/* Return the nearest higher resolution index */ +static int nearest_resolution_index(int w, int h) +{ + int i; + int idx = -1; + int dist; + int min_dist = INT_MAX; + const struct mt9m114_res_struct *tmp_res = NULL; + + for (i = 0; i < ARRAY_SIZE(mt9m114_res); i++) { + tmp_res = &mt9m114_res[i]; + dist = distance(tmp_res, w, h); + if (dist == -1) + continue; + if (dist < min_dist) { + min_dist = dist; + idx = i; + } + } + + return idx; +} + +static int mt9m114_try_res(u32 *w, u32 *h) +{ + int idx = 0; + + if ((*w > MT9M114_RES_960P_SIZE_H) + || (*h > MT9M114_RES_960P_SIZE_V)) { + *w = MT9M114_RES_960P_SIZE_H; + *h = MT9M114_RES_960P_SIZE_V; + } else { + idx = nearest_resolution_index(*w, *h); + + /* + * nearest_resolution_index() doesn't return smaller + * resolutions. If it fails, it means the requested + * resolution is higher than wecan support. Fallback + * to highest possible resolution in this case. + */ + if (idx == -1) + idx = ARRAY_SIZE(mt9m114_res) - 1; + + *w = mt9m114_res[idx].width; + *h = mt9m114_res[idx].height; + } + + return 0; +} + +static struct mt9m114_res_struct *mt9m114_to_res(u32 w, u32 h) +{ + int index; + + for (index = 0; index < N_RES; index++) { + if ((mt9m114_res[index].width == w) && + (mt9m114_res[index].height == h)) + break; + } + + /* No mode found */ + if (index >= N_RES) + return NULL; + + return &mt9m114_res[index]; +} + +static int mt9m114_res2size(struct v4l2_subdev *sd, int *h_size, int *v_size) +{ + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + unsigned short hsize; + unsigned short vsize; + + switch (dev->res) { + case MT9M114_RES_736P: + hsize = MT9M114_RES_736P_SIZE_H; + vsize = MT9M114_RES_736P_SIZE_V; + break; + case MT9M114_RES_864P: + hsize = MT9M114_RES_864P_SIZE_H; + vsize = MT9M114_RES_864P_SIZE_V; + break; + case MT9M114_RES_960P: + hsize = MT9M114_RES_960P_SIZE_H; + vsize = MT9M114_RES_960P_SIZE_V; + break; + default: + v4l2_err(sd, "%s: Resolution 0x%08x unknown\n", __func__, + dev->res); + return -EINVAL; + } + + if (h_size != NULL) + *h_size = hsize; + if (v_size != NULL) + *v_size = vsize; + + return 0; +} + +static int mt9m114_get_intg_factor(struct i2c_client *client, + struct camera_mipi_info *info, + const struct mt9m114_res_struct *res) +{ + struct atomisp_sensor_mode_data *buf = &info->data; + u32 reg_val; + int ret; + + if (info == NULL) + return -EINVAL; + + ret = mt9m114_read_reg(client, MISENSOR_32BIT, + REG_PIXEL_CLK, ®_val); + if (ret) + return ret; + buf->vt_pix_clk_freq_mhz = reg_val; + + /* get integration time */ + buf->coarse_integration_time_min = MT9M114_COARSE_INTG_TIME_MIN; + buf->coarse_integration_time_max_margin = + MT9M114_COARSE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_min = MT9M114_FINE_INTG_TIME_MIN; + buf->fine_integration_time_max_margin = + MT9M114_FINE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_def = MT9M114_FINE_INTG_TIME_MIN; + + buf->frame_length_lines = res->lines_per_frame; + buf->line_length_pck = res->pixels_per_line; + buf->read_mode = res->bin_mode; + + /* get the cropping and output resolution to ISP for this mode. */ + ret = mt9m114_read_reg(client, MISENSOR_16BIT, + REG_H_START, ®_val); + if (ret) + return ret; + buf->crop_horizontal_start = reg_val; + + ret = mt9m114_read_reg(client, MISENSOR_16BIT, + REG_V_START, ®_val); + if (ret) + return ret; + buf->crop_vertical_start = reg_val; + + ret = mt9m114_read_reg(client, MISENSOR_16BIT, + REG_H_END, ®_val); + if (ret) + return ret; + buf->crop_horizontal_end = reg_val; + + ret = mt9m114_read_reg(client, MISENSOR_16BIT, + REG_V_END, ®_val); + if (ret) + return ret; + buf->crop_vertical_end = reg_val; + + ret = mt9m114_read_reg(client, MISENSOR_16BIT, + REG_WIDTH, ®_val); + if (ret) + return ret; + buf->output_width = reg_val; + + ret = mt9m114_read_reg(client, MISENSOR_16BIT, + REG_HEIGHT, ®_val); + if (ret) + return ret; + buf->output_height = reg_val; + + ret = mt9m114_read_reg(client, MISENSOR_16BIT, + REG_TIMING_HTS, ®_val); + if (ret) + return ret; + buf->line_length_pck = reg_val; + + ret = mt9m114_read_reg(client, MISENSOR_16BIT, + REG_TIMING_VTS, ®_val); + if (ret) + return ret; + buf->frame_length_lines = reg_val; + + buf->binning_factor_x = res->bin_factor_x ? + res->bin_factor_x : 1; + buf->binning_factor_y = res->bin_factor_y ? + res->bin_factor_y : 1; + return 0; +} + +static int mt9m114_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt = &format->format; + int width, height; + int ret; + if (format->pad) + return -EINVAL; + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + + ret = mt9m114_res2size(sd, &width, &height); + if (ret) + return ret; + fmt->width = width; + fmt->height = height; + + return 0; +} + +static int mt9m114_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt = &format->format; + struct i2c_client *c = v4l2_get_subdevdata(sd); + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + struct mt9m114_res_struct *res_index; + u32 width = fmt->width; + u32 height = fmt->height; + struct camera_mipi_info *mt9m114_info = NULL; + + int ret; + if (format->pad) + return -EINVAL; + dev->streamon = 0; + dev->first_exp = MT9M114_DEFAULT_FIRST_EXP; + + mt9m114_info = v4l2_get_subdev_hostdata(sd); + if (mt9m114_info == NULL) + return -EINVAL; + + mt9m114_try_res(&width, &height); + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *fmt; + return 0; + } + res_index = mt9m114_to_res(width, height); + + /* Sanity check */ + if (unlikely(!res_index)) { + WARN_ON(1); + return -EINVAL; + } + + switch (res_index->res) { + case MT9M114_RES_736P: + ret = mt9m114_write_reg_array(c, mt9m114_736P_init, NO_POLLING); + ret += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, + MISENSOR_R_MODE_MASK, MISENSOR_NORMAL_SET); + break; + case MT9M114_RES_864P: + ret = mt9m114_write_reg_array(c, mt9m114_864P_init, NO_POLLING); + ret += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, + MISENSOR_R_MODE_MASK, MISENSOR_NORMAL_SET); + break; + case MT9M114_RES_960P: + ret = mt9m114_write_reg_array(c, mt9m114_976P_init, NO_POLLING); + /* set sensor read_mode to Normal */ + ret += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, + MISENSOR_R_MODE_MASK, MISENSOR_NORMAL_SET); + break; + default: + v4l2_err(sd, "set resolution: %d failed!\n", res_index->res); + return -EINVAL; + } + + if (ret) + return -EINVAL; + + ret = mt9m114_write_reg_array(c, mt9m114_chgstat_reg, POST_POLLING); + if (ret < 0) + return ret; + + if (mt9m114_set_suspend(sd)) + return -EINVAL; + + if (dev->res != res_index->res) { + int index; + + /* Switch to different size */ + if (width <= 640) { + dev->nctx = 0x00; /* Set for context A */ + } else { + /* + * Context B is used for resolutions larger than 640x480 + * Using YUV for Context B. + */ + dev->nctx = 0x01; /* set for context B */ + } + + /* + * Marked current sensor res as being "used" + * + * REVISIT: We don't need to use an "used" field on each mode + * list entry to know which mode is selected. If this + * information is really necessary, how about to use a single + * variable on sensor dev struct? + */ + for (index = 0; index < N_RES; index++) { + if ((width == mt9m114_res[index].width) && + (height == mt9m114_res[index].height)) { + mt9m114_res[index].used = true; + continue; + } + mt9m114_res[index].used = false; + } + } + ret = mt9m114_get_intg_factor(c, mt9m114_info, + &mt9m114_res[res_index->res]); + if (ret) { + dev_err(&c->dev, "failed to get integration_factor\n"); + return -EINVAL; + } + /* + * mt9m114 - we don't poll for context switch + * because it does not happen with streaming disabled. + */ + dev->res = res_index->res; + + fmt->width = width; + fmt->height = height; + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + return 0; +} + +/* TODO: Update to SOC functions, remove exposure and gain */ +static int mt9m114_g_focal(struct v4l2_subdev *sd, s32 *val) +{ + *val = (MT9M114_FOCAL_LENGTH_NUM << 16) | MT9M114_FOCAL_LENGTH_DEM; + return 0; +} + +static int mt9m114_g_fnumber(struct v4l2_subdev *sd, s32 *val) +{ + /*const f number for mt9m114*/ + *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 16) | MT9M114_F_NUMBER_DEM; + return 0; +} + +static int mt9m114_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) +{ + *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 24) | + (MT9M114_F_NUMBER_DEM << 16) | + (MT9M114_F_NUMBER_DEFAULT_NUM << 8) | MT9M114_F_NUMBER_DEM; + return 0; +} + +/* Horizontal flip the image. */ +static int mt9m114_g_hflip(struct v4l2_subdev *sd, s32 *val) +{ + struct i2c_client *c = v4l2_get_subdevdata(sd); + int ret; + u32 data; + ret = mt9m114_read_reg(c, MISENSOR_16BIT, + (u32)MISENSOR_READ_MODE, &data); + if (ret) + return ret; + *val = !!(data & MISENSOR_HFLIP_MASK); + + return 0; +} + +static int mt9m114_g_vflip(struct v4l2_subdev *sd, s32 *val) +{ + struct i2c_client *c = v4l2_get_subdevdata(sd); + int ret; + u32 data; + + ret = mt9m114_read_reg(c, MISENSOR_16BIT, + (u32)MISENSOR_READ_MODE, &data); + if (ret) + return ret; + *val = !!(data & MISENSOR_VFLIP_MASK); + + return 0; +} + +static long mt9m114_s_exposure(struct v4l2_subdev *sd, + struct atomisp_exposure *exposure) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + int ret = 0; + unsigned int coarse_integration = 0; + unsigned int fine_integration = 0; + unsigned int FLines = 0; + unsigned int FrameLengthLines = 0; /* ExposureTime.FrameLengthLines; */ + unsigned int AnalogGain, DigitalGain; + u32 AnalogGainToWrite = 0; + u16 exposure_local[3]; + + dev_dbg(&client->dev, "%s(0x%X 0x%X 0x%X)\n", __func__, + exposure->integration_time[0], exposure->gain[0], + exposure->gain[1]); + + coarse_integration = exposure->integration_time[0]; + /* fine_integration = ExposureTime.FineIntegrationTime; */ + /* FrameLengthLines = ExposureTime.FrameLengthLines; */ + FLines = mt9m114_res[dev->res].lines_per_frame; + AnalogGain = exposure->gain[0]; + DigitalGain = exposure->gain[1]; + if (!dev->streamon) { + /*Save the first exposure values while stream is off*/ + dev->first_exp = coarse_integration; + dev->first_gain = AnalogGain; + dev->first_diggain = DigitalGain; + } + /* DigitalGain = 0x400 * (((u16) DigitalGain) >> 8) + + ((unsigned int)(0x400 * (((u16) DigitalGain) & 0xFF)) >>8); */ + + /* set frame length */ + if (FLines < coarse_integration + 6) + FLines = coarse_integration + 6; + if (FLines < FrameLengthLines) + FLines = FrameLengthLines; + ret = mt9m114_write_reg(client, MISENSOR_16BIT, 0x300A, FLines); + if (ret) { + v4l2_err(client, "%s: fail to set FLines\n", __func__); + return -EINVAL; + } + + /* set coarse/fine integration */ + exposure_local[0] = REG_EXPO_COARSE; + exposure_local[1] = (u16)coarse_integration; + exposure_local[2] = (u16)fine_integration; + /* 3A provide real exposure time. + should not translate to any value here. */ + ret = mt9m114_write_reg(client, MISENSOR_16BIT, + REG_EXPO_COARSE, (u16)(coarse_integration)); + if (ret) { + v4l2_err(client, "%s: fail to set exposure time\n", __func__); + return -EINVAL; + } + + /* + // set analog/digital gain + switch(AnalogGain) + { + case 0: + AnalogGainToWrite = 0x0; + break; + case 1: + AnalogGainToWrite = 0x20; + break; + case 2: + AnalogGainToWrite = 0x60; + break; + case 4: + AnalogGainToWrite = 0xA0; + break; + case 8: + AnalogGainToWrite = 0xE0; + break; + default: + AnalogGainToWrite = 0x20; + break; + } + */ + if (DigitalGain >= 16 || DigitalGain <= 1) + DigitalGain = 1; + /* AnalogGainToWrite = + (u16)((DigitalGain << 12) | AnalogGainToWrite); */ + AnalogGainToWrite = (u16)((DigitalGain << 12) | (u16)AnalogGain); + ret = mt9m114_write_reg(client, MISENSOR_16BIT, + REG_GAIN, AnalogGainToWrite); + if (ret) { + v4l2_err(client, "%s: fail to set AnalogGainToWrite\n", + __func__); + return -EINVAL; + } + + return ret; +} + +static long mt9m114_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + + switch (cmd) { + case ATOMISP_IOC_S_EXPOSURE: + return mt9m114_s_exposure(sd, arg); + default: + return -EINVAL; + } + + return 0; +} + +/* This returns the exposure time being used. This should only be used + for filling in EXIF data, not for actual image processing. */ +static int mt9m114_g_exposure(struct v4l2_subdev *sd, s32 *value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u32 coarse; + int ret; + + /* the fine integration time is currently not calculated */ + ret = mt9m114_read_reg(client, MISENSOR_16BIT, + REG_EXPO_COARSE, &coarse); + if (ret) + return ret; + + *value = coarse; + return 0; +} +#ifndef CSS15 +/* + * This function will return the sensor supported max exposure zone number. + * the sensor which supports max exposure zone number is 1. + */ +static int mt9m114_g_exposure_zone_num(struct v4l2_subdev *sd, s32 *val) +{ + *val = 1; + + return 0; +} + +/* + * set exposure metering, average/center_weighted/spot/matrix. + */ +static int mt9m114_s_exposure_metering(struct v4l2_subdev *sd, s32 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + switch (val) { + case V4L2_EXPOSURE_METERING_SPOT: + ret = mt9m114_write_reg_array(client, mt9m114_exp_average, + NO_POLLING); + if (ret) { + dev_err(&client->dev, "write exp_average reg err.\n"); + return ret; + } + break; + case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED: + default: + ret = mt9m114_write_reg_array(client, mt9m114_exp_center, + NO_POLLING); + if (ret) { + dev_err(&client->dev, "write exp_default reg err"); + return ret; + } + } + + return 0; +} + +/* + * This function is for touch exposure feature. + */ +static int mt9m114_s_exposure_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct misensor_reg exp_reg; + int width, height; + int grid_width, grid_height; + int grid_left, grid_top, grid_right, grid_bottom; + int win_left, win_top, win_right, win_bottom; + int i, j; + int ret; + + if (sel->which != V4L2_SUBDEV_FORMAT_TRY && + sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; + + grid_left = sel->r.left; + grid_top = sel->r.top; + grid_right = sel->r.left + sel->r.width - 1; + grid_bottom = sel->r.top + sel->r.height - 1; + + ret = mt9m114_res2size(sd, &width, &height); + if (ret) + return ret; + + grid_width = width / 5; + grid_height = height / 5; + + if (grid_width && grid_height) { + win_left = grid_left / grid_width; + win_top = grid_top / grid_height; + win_right = grid_right / grid_width; + win_bottom = grid_bottom / grid_height; + } else { + dev_err(&client->dev, "Incorrect exp grid.\n"); + return -EINVAL; + } + + win_left = clamp_t(int, win_left, 0, 4); + win_top = clamp_t(int, win_top, 0, 4); + win_right = clamp_t(int, win_right, 0, 4); + win_bottom = clamp_t(int, win_bottom, 0, 4); + + ret = mt9m114_write_reg_array(client, mt9m114_exp_average, NO_POLLING); + if (ret) { + dev_err(&client->dev, "write exp_average reg err.\n"); + return ret; + } + + for (i = win_top; i <= win_bottom; i++) { + for (j = win_left; j <= win_right; j++) { + exp_reg = mt9m114_exp_win[i][j]; + + ret = mt9m114_write_reg(client, exp_reg.length, + exp_reg.reg, exp_reg.val); + if (ret) { + dev_err(&client->dev, "write exp_reg err.\n"); + return ret; + } + } + } + + return 0; +} +#endif + +static int mt9m114_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) +{ + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + + *val = mt9m114_res[dev->res].bin_factor_x; + + return 0; +} + +static int mt9m114_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) +{ + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + + *val = mt9m114_res[dev->res].bin_factor_y; + + return 0; +} + +static int mt9m114_s_ev(struct v4l2_subdev *sd, s32 val) +{ + struct i2c_client *c = v4l2_get_subdevdata(sd); + s32 luma = 0x37; + int err; + + /* EV value only support -2 to 2 + * 0: 0x37, 1:0x47, 2:0x57, -1:0x27, -2:0x17 + */ + if (val < -2 || val > 2) + return -EINVAL; + luma += 0x10 * val; + dev_dbg(&c->dev, "%s val:%d luma:0x%x\n", __func__, val, luma); + err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC87A); + if (err) { + dev_err(&c->dev, "%s logic addr access error\n", __func__); + return err; + } + err = mt9m114_write_reg(c, MISENSOR_8BIT, 0xC87A, (u32)luma); + if (err) { + dev_err(&c->dev, "%s write target_average_luma failed\n", + __func__); + return err; + } + udelay(10); + + return 0; +} + +static int mt9m114_g_ev(struct v4l2_subdev *sd, s32 *val) +{ + struct i2c_client *c = v4l2_get_subdevdata(sd); + int err; + u32 luma; + + err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC87A); + if (err) { + dev_err(&c->dev, "%s logic addr access error\n", __func__); + return err; + } + err = mt9m114_read_reg(c, MISENSOR_8BIT, 0xC87A, &luma); + if (err) { + dev_err(&c->dev, "%s read target_average_luma failed\n", + __func__); + return err; + } + luma -= 0x17; + luma /= 0x10; + *val = (s32)luma - 2; + dev_dbg(&c->dev, "%s val:%d\n", __func__, *val); + + return 0; +} + +/* Fake interface + * mt9m114 now can not support 3a_lock +*/ +static int mt9m114_s_3a_lock(struct v4l2_subdev *sd, s32 val) +{ + aaalock = val; + return 0; +} + +static int mt9m114_g_3a_lock(struct v4l2_subdev *sd, s32 *val) +{ + if (aaalock) + return V4L2_LOCK_EXPOSURE | V4L2_LOCK_WHITE_BALANCE + | V4L2_LOCK_FOCUS; + return 0; +} + +static int mt9m114_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mt9m114_device *dev = + container_of(ctrl->handler, struct mt9m114_device, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n", + __func__, ctrl->val); + ret = mt9m114_t_vflip(&dev->sd, ctrl->val); + break; + case V4L2_CID_HFLIP: + dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n", + __func__, ctrl->val); + ret = mt9m114_t_hflip(&dev->sd, ctrl->val); + break; +#ifndef CSS15 + case V4L2_CID_EXPOSURE_METERING: + ret = mt9m114_s_exposure_metering(&dev->sd, ctrl->val); + break; +#endif + case V4L2_CID_EXPOSURE: + ret = mt9m114_s_ev(&dev->sd, ctrl->val); + break; + case V4L2_CID_3A_LOCK: + ret = mt9m114_s_3a_lock(&dev->sd, ctrl->val); + break; + default: + ret = -EINVAL; + } + return ret; +} + +static int mt9m114_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mt9m114_device *dev = + container_of(ctrl->handler, struct mt9m114_device, ctrl_handler); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + ret = mt9m114_g_vflip(&dev->sd, &ctrl->val); + break; + case V4L2_CID_HFLIP: + ret = mt9m114_g_hflip(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FOCAL_ABSOLUTE: + ret = mt9m114_g_focal(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_ABSOLUTE: + ret = mt9m114_g_fnumber(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_RANGE: + ret = mt9m114_g_fnumber_range(&dev->sd, &ctrl->val); + break; + case V4L2_CID_EXPOSURE_ABSOLUTE: + ret = mt9m114_g_exposure(&dev->sd, &ctrl->val); + break; +#ifndef CSS15 + case V4L2_CID_EXPOSURE_ZONE_NUM: + ret = mt9m114_g_exposure_zone_num(&dev->sd, &ctrl->val); + break; +#endif + case V4L2_CID_BIN_FACTOR_HORZ: + ret = mt9m114_g_bin_factor_x(&dev->sd, &ctrl->val); + break; + case V4L2_CID_BIN_FACTOR_VERT: + ret = mt9m114_g_bin_factor_y(&dev->sd, &ctrl->val); + break; + case V4L2_CID_EXPOSURE: + ret = mt9m114_g_ev(&dev->sd, &ctrl->val); + break; + case V4L2_CID_3A_LOCK: + ret = mt9m114_g_3a_lock(&dev->sd, &ctrl->val); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops ctrl_ops = { + .s_ctrl = mt9m114_s_ctrl, + .g_volatile_ctrl = mt9m114_g_volatile_ctrl +}; + +static struct v4l2_ctrl_config mt9m114_controls[] = { + { + .ops = &ctrl_ops, + .id = V4L2_CID_VFLIP, + .name = "Image v-Flip", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 1, + .step = 1, + .def = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_HFLIP, + .name = "Image h-Flip", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 1, + .step = 1, + .def = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FOCAL_ABSOLUTE, + .name = "focal length", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = MT9M114_FOCAL_LENGTH_DEFAULT, + .max = MT9M114_FOCAL_LENGTH_DEFAULT, + .step = 1, + .def = MT9M114_FOCAL_LENGTH_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_ABSOLUTE, + .name = "f-number", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = MT9M114_F_NUMBER_DEFAULT, + .max = MT9M114_F_NUMBER_DEFAULT, + .step = 1, + .def = MT9M114_F_NUMBER_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_RANGE, + .name = "f-number range", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = MT9M114_F_NUMBER_RANGE, + .max = MT9M114_F_NUMBER_RANGE, + .step = 1, + .def = MT9M114_F_NUMBER_RANGE, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_EXPOSURE_ABSOLUTE, + .name = "exposure", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 0xffff, + .step = 1, + .def = 0, + .flags = 0, + }, +#ifndef CSS15 + { + .ops = &ctrl_ops, + .id = V4L2_CID_EXPOSURE_ZONE_NUM, + .name = "one-time exposure zone number", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 0xffff, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_EXPOSURE_METERING, + .name = "metering", + .type = V4L2_CTRL_TYPE_MENU, + .min = 0, + .max = 3, + .step = 0, + .def = 1, + .flags = 0, + }, +#endif + { + .ops = &ctrl_ops, + .id = V4L2_CID_BIN_FACTOR_HORZ, + .name = "horizontal binning factor", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = MT9M114_BIN_FACTOR_MAX, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_BIN_FACTOR_VERT, + .name = "vertical binning factor", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = MT9M114_BIN_FACTOR_MAX, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_EXPOSURE, + .name = "exposure biasx", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = -2, + .max = 2, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_3A_LOCK, + .name = "3a lock", + .type = V4L2_CTRL_TYPE_BITMASK, + .min = 0, + .max = V4L2_LOCK_EXPOSURE | V4L2_LOCK_WHITE_BALANCE | V4L2_LOCK_FOCUS, + .step = 1, + .def = 0, + .flags = 0, + }, +}; + +static int mt9m114_detect(struct mt9m114_device *dev, struct i2c_client *client) +{ + struct i2c_adapter *adapter = client->adapter; + u32 retvalue; + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "%s: i2c error", __func__); + return -ENODEV; + } + mt9m114_read_reg(client, MISENSOR_16BIT, (u32)MT9M114_PID, &retvalue); + dev->real_model_id = retvalue; + + if (retvalue != MT9M114_MOD_ID) { + dev_err(&client->dev, "%s: failed: client->addr = %x\n", + __func__, client->addr); + return -ENODEV; + } + + return 0; +} + +static int +mt9m114_s_config(struct v4l2_subdev *sd, int irq, void *platform_data) +{ + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + if (NULL == platform_data) + return -ENODEV; + + dev->platform_data = + (struct camera_sensor_platform_data *)platform_data; + + if (dev->platform_data->platform_init) { + ret = dev->platform_data->platform_init(client); + if (ret) { + v4l2_err(client, "mt9m114 platform init err\n"); + return ret; + } + } + ret = power_up(sd); + if (ret) { + v4l2_err(client, "mt9m114 power-up err"); + return ret; + } + + /* config & detect sensor */ + ret = mt9m114_detect(dev, client); + if (ret) { + v4l2_err(client, "mt9m114_detect err s_config.\n"); + goto fail_detect; + } + + ret = dev->platform_data->csi_cfg(sd, 1); + if (ret) + goto fail_csi_cfg; + + ret = mt9m114_set_suspend(sd); + if (ret) { + v4l2_err(client, "mt9m114 suspend err"); + return ret; + } + + ret = power_down(sd); + if (ret) { + v4l2_err(client, "mt9m114 power down err"); + return ret; + } + + return ret; + +fail_csi_cfg: + dev->platform_data->csi_cfg(sd, 0); +fail_detect: + power_down(sd); + dev_err(&client->dev, "sensor power-gating failed\n"); + return ret; +} + +/* Horizontal flip the image. */ +static int mt9m114_t_hflip(struct v4l2_subdev *sd, int value) +{ + struct i2c_client *c = v4l2_get_subdevdata(sd); + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + int err; + /* set for direct mode */ + err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC850); + if (value) { + /* enable H flip ctx A */ + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x01, 0x01); + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x01, 0x01); + /* ctx B */ + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x01, 0x01); + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x01, 0x01); + + err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, + MISENSOR_HFLIP_MASK, MISENSOR_FLIP_EN); + + dev->bpat = MT9M114_BPAT_GRGRBGBG; + } else { + /* disable H flip ctx A */ + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x01, 0x00); + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x01, 0x00); + /* ctx B */ + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x01, 0x00); + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x01, 0x00); + + err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, + MISENSOR_HFLIP_MASK, MISENSOR_FLIP_DIS); + + dev->bpat = MT9M114_BPAT_BGBGGRGR; + } + + err += mt9m114_write_reg(c, MISENSOR_8BIT, 0x8404, 0x06); + udelay(10); + + return !!err; +} + +/* Vertically flip the image */ +static int mt9m114_t_vflip(struct v4l2_subdev *sd, int value) +{ + struct i2c_client *c = v4l2_get_subdevdata(sd); + int err; + /* set for direct mode */ + err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC850); + if (value >= 1) { + /* enable H flip - ctx A */ + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x02, 0x01); + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x02, 0x01); + /* ctx B */ + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x02, 0x01); + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x02, 0x01); + + err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, + MISENSOR_VFLIP_MASK, MISENSOR_FLIP_EN); + } else { + /* disable H flip - ctx A */ + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x02, 0x00); + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x02, 0x00); + /* ctx B */ + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x02, 0x00); + err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x02, 0x00); + + err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, + MISENSOR_VFLIP_MASK, MISENSOR_FLIP_DIS); + } + + err += mt9m114_write_reg(c, MISENSOR_8BIT, 0x8404, 0x06); + udelay(10); + + return !!err; +} +static int mt9m114_s_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + return 0; +} + +static int mt9m114_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + + interval->interval.numerator = 1; + interval->interval.denominator = mt9m114_res[dev->res].fps; + + return 0; +} + +static int mt9m114_s_stream(struct v4l2_subdev *sd, int enable) +{ + int ret; + struct i2c_client *c = v4l2_get_subdevdata(sd); + struct mt9m114_device *dev = to_mt9m114_sensor(sd); + struct atomisp_exposure exposure; + + if (enable) { + ret = mt9m114_write_reg_array(c, mt9m114_chgstat_reg, + POST_POLLING); + if (ret < 0) + return ret; + + if (dev->first_exp > MT9M114_MAX_FIRST_EXP) { + exposure.integration_time[0] = dev->first_exp; + exposure.gain[0] = dev->first_gain; + exposure.gain[1] = dev->first_diggain; + mt9m114_s_exposure(sd, &exposure); + } + dev->streamon = 1; + + } else { + dev->streamon = 0; + ret = mt9m114_set_suspend(sd); + } + + return ret; +} + +static int mt9m114_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index) + return -EINVAL; + code->code = MEDIA_BUS_FMT_SGRBG10_1X10; + + return 0; +} + +static int mt9m114_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + + unsigned int index = fse->index; + + if (index >= N_RES) + return -EINVAL; + + fse->min_width = mt9m114_res[index].width; + fse->min_height = mt9m114_res[index].height; + fse->max_width = mt9m114_res[index].width; + fse->max_height = mt9m114_res[index].height; + + return 0; +} + +static int mt9m114_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) +{ + int index; + struct mt9m114_device *snr = to_mt9m114_sensor(sd); + + if (frames == NULL) + return -EINVAL; + + for (index = 0; index < N_RES; index++) { + if (mt9m114_res[index].res == snr->res) + break; + } + + if (index >= N_RES) + return -EINVAL; + + *frames = mt9m114_res[index].skip_frames; + + return 0; +} + +static const struct v4l2_subdev_video_ops mt9m114_video_ops = { + .s_parm = mt9m114_s_parm, + .s_stream = mt9m114_s_stream, + .g_frame_interval = mt9m114_g_frame_interval, +}; + +static const struct v4l2_subdev_sensor_ops mt9m114_sensor_ops = { + .g_skip_frames = mt9m114_g_skip_frames, +}; + +static const struct v4l2_subdev_core_ops mt9m114_core_ops = { + .s_power = mt9m114_s_power, + .ioctl = mt9m114_ioctl, +}; + +/* REVISIT: Do we need pad operations? */ +static const struct v4l2_subdev_pad_ops mt9m114_pad_ops = { + .enum_mbus_code = mt9m114_enum_mbus_code, + .enum_frame_size = mt9m114_enum_frame_size, + .get_fmt = mt9m114_get_fmt, + .set_fmt = mt9m114_set_fmt, +#ifndef CSS15 + .set_selection = mt9m114_s_exposure_selection, +#endif +}; + +static const struct v4l2_subdev_ops mt9m114_ops = { + .core = &mt9m114_core_ops, + .video = &mt9m114_video_ops, + .pad = &mt9m114_pad_ops, + .sensor = &mt9m114_sensor_ops, +}; + +static const struct media_entity_operations mt9m114_entity_ops = { + .link_setup = NULL, +}; + +static int mt9m114_remove(struct i2c_client *client) +{ + struct mt9m114_device *dev; + struct v4l2_subdev *sd = i2c_get_clientdata(client); + + dev = container_of(sd, struct mt9m114_device, sd); + dev->platform_data->csi_cfg(sd, 0); + if (dev->platform_data->platform_deinit) + dev->platform_data->platform_deinit(); + v4l2_device_unregister_subdev(sd); + media_entity_cleanup(&dev->sd.entity); + v4l2_ctrl_handler_free(&dev->ctrl_handler); + kfree(dev); + return 0; +} + +static int mt9m114_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct mt9m114_device *dev; + int ret = 0; + unsigned int i; + void *pdata; + + /* Setup sensor configuration structure */ + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + dev_err(&client->dev, "out of memory\n"); + return -ENOMEM; + } + + v4l2_i2c_subdev_init(&dev->sd, client, &mt9m114_ops); + pdata = client->dev.platform_data; + if (ACPI_COMPANION(&client->dev)) + pdata = gmin_camera_platform_data(&dev->sd, + ATOMISP_INPUT_FORMAT_RAW_10, + atomisp_bayer_order_grbg); + if (pdata) + ret = mt9m114_s_config(&dev->sd, client->irq, pdata); + if (!pdata || ret) { + v4l2_device_unregister_subdev(&dev->sd); + kfree(dev); + return ret; + } + + ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); + if (ret) { + v4l2_device_unregister_subdev(&dev->sd); + kfree(dev); + /* Coverity CID 298095 - return on error */ + return ret; + } + + /*TODO add format code here*/ + dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + dev->pad.flags = MEDIA_PAD_FL_SOURCE; + dev->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; + dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + ret = + v4l2_ctrl_handler_init(&dev->ctrl_handler, + ARRAY_SIZE(mt9m114_controls)); + if (ret) { + mt9m114_remove(client); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(mt9m114_controls); i++) + v4l2_ctrl_new_custom(&dev->ctrl_handler, &mt9m114_controls[i], + NULL); + + if (dev->ctrl_handler.error) { + mt9m114_remove(client); + return dev->ctrl_handler.error; + } + + /* Use same lock for controls as for everything else. */ + dev->ctrl_handler.lock = &dev->input_lock; + dev->sd.ctrl_handler = &dev->ctrl_handler; + + /* REVISIT: Do we need media controller? */ + ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); + if (ret) { + mt9m114_remove(client); + return ret; + } + return 0; +} + +MODULE_DEVICE_TABLE(i2c, mt9m114_id); + +static const struct acpi_device_id mt9m114_acpi_match[] = { + { "INT33F0" }, + { "CRMT1040" }, + {}, +}; + +MODULE_DEVICE_TABLE(acpi, mt9m114_acpi_match); + +static struct i2c_driver mt9m114_driver = { + .driver = { + .name = "mt9m114", + .acpi_match_table = ACPI_PTR(mt9m114_acpi_match), + }, + .probe = mt9m114_probe, + .remove = mt9m114_remove, + .id_table = mt9m114_id, +}; + +static __init int init_mt9m114(void) +{ + return i2c_add_driver(&mt9m114_driver); +} + +static __exit void exit_mt9m114(void) +{ + i2c_del_driver(&mt9m114_driver); +} + +module_init(init_mt9m114); +module_exit(exit_mt9m114); + +MODULE_AUTHOR("Shuguang Gong "); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c new file mode 100644 index 000000000000..51b7d61df0f5 --- /dev/null +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -0,0 +1,1557 @@ +/* + * Support for OmniVision OV2680 1080p HD camera sensor. + * + * Copyright (c) 2013 Intel Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/linux/atomisp_gmin_platform.h" + +#include "ov2680.h" + +static int h_flag = 0; +static int v_flag = 0; +static enum atomisp_bayer_order ov2680_bayer_order_mapping[] = { + atomisp_bayer_order_bggr, + atomisp_bayer_order_grbg, + atomisp_bayer_order_gbrg, + atomisp_bayer_order_rggb, +}; + +/* i2c read/write stuff */ +static int ov2680_read_reg(struct i2c_client *client, + u16 data_length, u16 reg, u16 *val) +{ + int err; + struct i2c_msg msg[2]; + unsigned char data[6]; + + if (!client->adapter) { + dev_err(&client->dev, "%s error, no client->adapter\n", + __func__); + return -ENODEV; + } + + if (data_length != OV2680_8BIT && data_length != OV2680_16BIT + && data_length != OV2680_32BIT) { + dev_err(&client->dev, "%s error, invalid data length\n", + __func__); + return -EINVAL; + } + + memset(msg, 0 , sizeof(msg)); + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = I2C_MSG_LENGTH; + msg[0].buf = data; + + /* high byte goes out first */ + data[0] = (u8)(reg >> 8); + data[1] = (u8)(reg & 0xff); + + msg[1].addr = client->addr; + msg[1].len = data_length; + msg[1].flags = I2C_M_RD; + msg[1].buf = data; + + err = i2c_transfer(client->adapter, msg, 2); + if (err != 2) { + if (err >= 0) + err = -EIO; + dev_err(&client->dev, + "read from offset 0x%x error %d", reg, err); + return err; + } + + *val = 0; + /* high byte comes first */ + if (data_length == OV2680_8BIT) + *val = (u8)data[0]; + else if (data_length == OV2680_16BIT) + *val = be16_to_cpu(*(u16 *)&data[0]); + else + *val = be32_to_cpu(*(u32 *)&data[0]); + //dev_dbg(&client->dev, "++++i2c read adr%x = %x\n", reg,*val); + return 0; +} + +static int ov2680_i2c_write(struct i2c_client *client, u16 len, u8 *data) +{ + struct i2c_msg msg; + const int num_msg = 1; + int ret; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = len; + msg.buf = data; + ret = i2c_transfer(client->adapter, &msg, 1); + //dev_dbg(&client->dev, "+++i2c write reg=%x->%x\n", data[0]*256 +data[1],data[2]); + return ret == num_msg ? 0 : -EIO; +} + +static int ov2680_write_reg(struct i2c_client *client, u16 data_length, + u16 reg, u16 val) +{ + int ret; + unsigned char data[4] = {0}; + u16 *wreg = (u16 *)data; + const u16 len = data_length + sizeof(u16); /* 16-bit address + data */ + + if (data_length != OV2680_8BIT && data_length != OV2680_16BIT) { + dev_err(&client->dev, + "%s error, invalid data_length\n", __func__); + return -EINVAL; + } + + /* high byte goes out first */ + *wreg = cpu_to_be16(reg); + + if (data_length == OV2680_8BIT) { + data[2] = (u8)(val); + } else { + /* OV2680_16BIT */ + u16 *wdata = (u16 *)&data[2]; + *wdata = cpu_to_be16(val); + } + + ret = ov2680_i2c_write(client, len, data); + if (ret) + dev_err(&client->dev, + "write error: wrote 0x%x to offset 0x%x error %d", + val, reg, ret); + + return ret; +} + +/* + * ov2680_write_reg_array - Initializes a list of OV2680 registers + * @client: i2c driver client structure + * @reglist: list of registers to be written + * + * This function initializes a list of registers. When consecutive addresses + * are found in a row on the list, this function creates a buffer and sends + * consecutive data in a single i2c_transfer(). + * + * __ov2680_flush_reg_array, __ov2680_buf_reg_array() and + * __ov2680_write_reg_is_consecutive() are internal functions to + * ov2680_write_reg_array_fast() and should be not used anywhere else. + * + */ + +static int __ov2680_flush_reg_array(struct i2c_client *client, + struct ov2680_write_ctrl *ctrl) +{ + u16 size; + + if (ctrl->index == 0) + return 0; + + size = sizeof(u16) + ctrl->index; /* 16-bit address + data */ + ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr); + ctrl->index = 0; + + return ov2680_i2c_write(client, size, (u8 *)&ctrl->buffer); +} + +static int __ov2680_buf_reg_array(struct i2c_client *client, + struct ov2680_write_ctrl *ctrl, + const struct ov2680_reg *next) +{ + int size; + u16 *data16; + + switch (next->type) { + case OV2680_8BIT: + size = 1; + ctrl->buffer.data[ctrl->index] = (u8)next->val; + break; + case OV2680_16BIT: + size = 2; + data16 = (u16 *)&ctrl->buffer.data[ctrl->index]; + *data16 = cpu_to_be16((u16)next->val); + break; + default: + return -EINVAL; + } + + /* When first item is added, we need to store its starting address */ + if (ctrl->index == 0) + ctrl->buffer.addr = next->reg; + + ctrl->index += size; + + /* + * Buffer cannot guarantee free space for u32? Better flush it to avoid + * possible lack of memory for next item. + */ + if (ctrl->index + sizeof(u16) >= OV2680_MAX_WRITE_BUF_SIZE) + return __ov2680_flush_reg_array(client, ctrl); + + return 0; +} + +static int __ov2680_write_reg_is_consecutive(struct i2c_client *client, + struct ov2680_write_ctrl *ctrl, + const struct ov2680_reg *next) +{ + if (ctrl->index == 0) + return 1; + + return ctrl->buffer.addr + ctrl->index == next->reg; +} + +static int ov2680_write_reg_array(struct i2c_client *client, + const struct ov2680_reg *reglist) +{ + const struct ov2680_reg *next = reglist; + struct ov2680_write_ctrl ctrl; + int err; + dev_dbg(&client->dev, "++++write reg array\n"); + ctrl.index = 0; + for (; next->type != OV2680_TOK_TERM; next++) { + switch (next->type & OV2680_TOK_MASK) { + case OV2680_TOK_DELAY: + err = __ov2680_flush_reg_array(client, &ctrl); + if (err) + return err; + msleep(next->val); + break; + default: + /* + * If next address is not consecutive, data needs to be + * flushed before proceed. + */ + dev_dbg(&client->dev, "+++ov2680_write_reg_array reg=%x->%x\n", next->reg,next->val); + if (!__ov2680_write_reg_is_consecutive(client, &ctrl, + next)) { + err = __ov2680_flush_reg_array(client, &ctrl); + if (err) + return err; + } + err = __ov2680_buf_reg_array(client, &ctrl, next); + if (err) { + dev_err(&client->dev, "%s: write error, aborted\n", + __func__); + return err; + } + break; + } + } + + return __ov2680_flush_reg_array(client, &ctrl); +} +static int ov2680_g_focal(struct v4l2_subdev *sd, s32 *val) +{ + + *val = (OV2680_FOCAL_LENGTH_NUM << 16) | OV2680_FOCAL_LENGTH_DEM; + return 0; +} + +static int ov2680_g_fnumber(struct v4l2_subdev *sd, s32 *val) +{ + /*const f number for ov2680*/ + + *val = (OV2680_F_NUMBER_DEFAULT_NUM << 16) | OV2680_F_NUMBER_DEM; + return 0; +} + +static int ov2680_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) +{ + *val = (OV2680_F_NUMBER_DEFAULT_NUM << 24) | + (OV2680_F_NUMBER_DEM << 16) | + (OV2680_F_NUMBER_DEFAULT_NUM << 8) | OV2680_F_NUMBER_DEM; + return 0; +} + +static int ov2680_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + dev_dbg(&client->dev, "++++ov2680_g_bin_factor_x\n"); + *val = ov2680_res[dev->fmt_idx].bin_factor_x; + + return 0; +} + +static int ov2680_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + *val = ov2680_res[dev->fmt_idx].bin_factor_y; + dev_dbg(&client->dev, "++++ov2680_g_bin_factor_y\n"); + return 0; +} + + +static int ov2680_get_intg_factor(struct i2c_client *client, + struct camera_mipi_info *info, + const struct ov2680_resolution *res) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct atomisp_sensor_mode_data *buf = &info->data; + unsigned int pix_clk_freq_hz; + u16 reg_val; + int ret; + dev_dbg(&client->dev, "++++ov2680_get_intg_factor\n"); + if (!info) + return -EINVAL; + + /* pixel clock */ + pix_clk_freq_hz = res->pix_clk_freq * 1000000; + + dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz; + buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz; + + /* get integration time */ + buf->coarse_integration_time_min = OV2680_COARSE_INTG_TIME_MIN; + buf->coarse_integration_time_max_margin = + OV2680_COARSE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_min = OV2680_FINE_INTG_TIME_MIN; + buf->fine_integration_time_max_margin = + OV2680_FINE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_def = OV2680_FINE_INTG_TIME_MIN; + buf->frame_length_lines = res->lines_per_frame; + buf->line_length_pck = res->pixels_per_line; + buf->read_mode = res->bin_mode; + + /* get the cropping and output resolution to ISP for this mode. */ + ret = ov2680_read_reg(client, OV2680_16BIT, + OV2680_HORIZONTAL_START_H, ®_val); + if (ret) + return ret; + buf->crop_horizontal_start = reg_val; + + ret = ov2680_read_reg(client, OV2680_16BIT, + OV2680_VERTICAL_START_H, ®_val); + if (ret) + return ret; + buf->crop_vertical_start = reg_val; + + ret = ov2680_read_reg(client, OV2680_16BIT, + OV2680_HORIZONTAL_END_H, ®_val); + if (ret) + return ret; + buf->crop_horizontal_end = reg_val; + + ret = ov2680_read_reg(client, OV2680_16BIT, + OV2680_VERTICAL_END_H, ®_val); + if (ret) + return ret; + buf->crop_vertical_end = reg_val; + + ret = ov2680_read_reg(client, OV2680_16BIT, + OV2680_HORIZONTAL_OUTPUT_SIZE_H, ®_val); + if (ret) + return ret; + buf->output_width = reg_val; + + ret = ov2680_read_reg(client, OV2680_16BIT, + OV2680_VERTICAL_OUTPUT_SIZE_H, ®_val); + if (ret) + return ret; + buf->output_height = reg_val; + + buf->binning_factor_x = res->bin_factor_x ? + (res->bin_factor_x * 2) : 1; + buf->binning_factor_y = res->bin_factor_y ? + (res->bin_factor_y * 2) : 1; + return 0; +} + +static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, + int gain, int digitgain) + +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov2680_device *dev = to_ov2680_sensor(sd); + u16 vts,hts; + int ret,exp_val; + + dev_dbg(&client->dev, "+++++++__ov2680_set_exposure coarse_itg %d, gain %d, digitgain %d++\n",coarse_itg, gain, digitgain); + + hts = ov2680_res[dev->fmt_idx].pixels_per_line; + vts = ov2680_res[dev->fmt_idx].lines_per_frame; + + /* group hold */ + ret = ov2680_write_reg(client, OV2680_8BIT, + OV2680_GROUP_ACCESS, 0x00); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV2680_GROUP_ACCESS); + return ret; + } + + /* Increase the VTS to match exposure + MARGIN */ + if (coarse_itg > vts - OV2680_INTEGRATION_TIME_MARGIN) + vts = (u16) coarse_itg + OV2680_INTEGRATION_TIME_MARGIN; + + ret = ov2680_write_reg(client, OV2680_16BIT, OV2680_TIMING_VTS_H, vts); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV2680_TIMING_VTS_H); + return ret; + } + + /* set exposure */ + + /* Lower four bit should be 0*/ + exp_val = coarse_itg << 4; + ret = ov2680_write_reg(client, OV2680_8BIT, + OV2680_EXPOSURE_L, exp_val & 0xFF); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV2680_EXPOSURE_L); + return ret; + } + + ret = ov2680_write_reg(client, OV2680_8BIT, + OV2680_EXPOSURE_M, (exp_val >> 8) & 0xFF); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV2680_EXPOSURE_M); + return ret; + } + + ret = ov2680_write_reg(client, OV2680_8BIT, + OV2680_EXPOSURE_H, (exp_val >> 16) & 0x0F); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV2680_EXPOSURE_H); + return ret; + } + + /* Analog gain */ + ret = ov2680_write_reg(client, OV2680_16BIT, OV2680_AGC_H, gain); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV2680_AGC_H); + return ret; + } + /* Digital gain */ + if (digitgain) { + ret = ov2680_write_reg(client, OV2680_16BIT, + OV2680_MWB_RED_GAIN_H, digitgain); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV2680_MWB_RED_GAIN_H); + return ret; + } + + ret = ov2680_write_reg(client, OV2680_16BIT, + OV2680_MWB_GREEN_GAIN_H, digitgain); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV2680_MWB_RED_GAIN_H); + return ret; + } + + ret = ov2680_write_reg(client, OV2680_16BIT, + OV2680_MWB_BLUE_GAIN_H, digitgain); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV2680_MWB_RED_GAIN_H); + return ret; + } + } + + /* End group */ + ret = ov2680_write_reg(client, OV2680_8BIT, + OV2680_GROUP_ACCESS, 0x10); + if (ret) + return ret; + + /* Delay launch group */ + ret = ov2680_write_reg(client, OV2680_8BIT, + OV2680_GROUP_ACCESS, 0xa0); + if (ret) + return ret; + return ret; +} + +static int ov2680_set_exposure(struct v4l2_subdev *sd, int exposure, + int gain, int digitgain) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + int ret; + + mutex_lock(&dev->input_lock); + ret = __ov2680_set_exposure(sd, exposure, gain, digitgain); + mutex_unlock(&dev->input_lock); + + return ret; +} + +static long ov2680_s_exposure(struct v4l2_subdev *sd, + struct atomisp_exposure *exposure) +{ + u16 coarse_itg = exposure->integration_time[0]; + u16 analog_gain = exposure->gain[0]; + u16 digital_gain = exposure->gain[1]; + + /* we should not accept the invalid value below */ + if (analog_gain == 0) { + struct i2c_client *client = v4l2_get_subdevdata(sd); + v4l2_err(client, "%s: invalid value\n", __func__); + return -EINVAL; + } + + // EXPOSURE CONTROL DISABLED FOR INITIAL CHECKIN, TUNING DOESN'T WORK + return ov2680_set_exposure(sd, coarse_itg, analog_gain, digital_gain); +} + + + + + +static long ov2680_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + + switch (cmd) { + case ATOMISP_IOC_S_EXPOSURE: + return ov2680_s_exposure(sd, arg); + + default: + return -EINVAL; + } + return 0; +} + +/* This returns the exposure time being used. This should only be used + * for filling in EXIF data, not for actual image processing. + */ +static int ov2680_q_exposure(struct v4l2_subdev *sd, s32 *value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u16 reg_v, reg_v2; + int ret; + + /* get exposure */ + ret = ov2680_read_reg(client, OV2680_8BIT, + OV2680_EXPOSURE_L, + ®_v); + if (ret) + goto err; + + ret = ov2680_read_reg(client, OV2680_8BIT, + OV2680_EXPOSURE_M, + ®_v2); + if (ret) + goto err; + + reg_v += reg_v2 << 8; + ret = ov2680_read_reg(client, OV2680_8BIT, + OV2680_EXPOSURE_H, + ®_v2); + if (ret) + goto err; + + *value = reg_v + (((u32)reg_v2 << 16)); +err: + return ret; +} + +static u32 ov2680_translate_bayer_order(enum atomisp_bayer_order code) +{ + switch (code) { + case atomisp_bayer_order_rggb: + return MEDIA_BUS_FMT_SRGGB10_1X10; + case atomisp_bayer_order_grbg: + return MEDIA_BUS_FMT_SGRBG10_1X10; + case atomisp_bayer_order_bggr: + return MEDIA_BUS_FMT_SBGGR10_1X10; + case atomisp_bayer_order_gbrg: + return MEDIA_BUS_FMT_SGBRG10_1X10; + } + return 0; +} + +static int ov2680_v_flip(struct v4l2_subdev *sd, s32 value) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct camera_mipi_info *ov2680_info = NULL; + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + u16 val; + u8 index; + dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value); + ret = ov2680_read_reg(client, OV2680_8BIT, OV2680_FLIP_REG, &val); + if (ret) + return ret; + if (value) { + val |= OV2680_FLIP_MIRROR_BIT_ENABLE; + } else { + val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE; + } + ret = ov2680_write_reg(client, OV2680_8BIT, + OV2680_FLIP_REG, val); + if (ret) + return ret; + index = (v_flag>0?OV2680_FLIP_BIT:0) | (h_flag>0?OV2680_MIRROR_BIT:0); + ov2680_info = v4l2_get_subdev_hostdata(sd); + if (ov2680_info) { + ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[index]; + dev->format.code = ov2680_translate_bayer_order( + ov2680_info->raw_bayer_order); + } + return ret; +} + +static int ov2680_h_flip(struct v4l2_subdev *sd, s32 value) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct camera_mipi_info *ov2680_info = NULL; + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + u16 val; + u8 index; + dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value); + + ret = ov2680_read_reg(client, OV2680_8BIT, OV2680_MIRROR_REG, &val); + if (ret) + return ret; + if (value) { + val |= OV2680_FLIP_MIRROR_BIT_ENABLE; + } else { + val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE; + } + ret = ov2680_write_reg(client, OV2680_8BIT, + OV2680_MIRROR_REG, val); + if (ret) + return ret; + index = (v_flag>0?OV2680_FLIP_BIT:0) | (h_flag>0?OV2680_MIRROR_BIT:0); + ov2680_info = v4l2_get_subdev_hostdata(sd); + if (ov2680_info) { + ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[index]; + dev->format.code = ov2680_translate_bayer_order( + ov2680_info->raw_bayer_order); + } + return ret; +} + +static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov2680_device *dev = + container_of(ctrl->handler, struct ov2680_device, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n", + __func__, ctrl->val); + ret = ov2680_v_flip(&dev->sd, ctrl->val); + break; + case V4L2_CID_HFLIP: + dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n", + __func__, ctrl->val); + ret = ov2680_h_flip(&dev->sd, ctrl->val); + break; + default: + ret = -EINVAL; + } + return ret; +} + +static int ov2680_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov2680_device *dev = + container_of(ctrl->handler, struct ov2680_device, ctrl_handler); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE_ABSOLUTE: + ret = ov2680_q_exposure(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FOCAL_ABSOLUTE: + ret = ov2680_g_focal(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_ABSOLUTE: + ret = ov2680_g_fnumber(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_RANGE: + ret = ov2680_g_fnumber_range(&dev->sd, &ctrl->val); + break; + case V4L2_CID_BIN_FACTOR_HORZ: + ret = ov2680_g_bin_factor_x(&dev->sd, &ctrl->val); + break; + case V4L2_CID_BIN_FACTOR_VERT: + ret = ov2680_g_bin_factor_y(&dev->sd, &ctrl->val); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops ctrl_ops = { + .s_ctrl = ov2680_s_ctrl, + .g_volatile_ctrl = ov2680_g_volatile_ctrl +}; + +struct v4l2_ctrl_config ov2680_controls[] = { + { + .ops = &ctrl_ops, + .id = V4L2_CID_EXPOSURE_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .min = 0x0, + .max = 0xffff, + .step = 0x01, + .def = 0x00, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FOCAL_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "focal length", + .min = OV2680_FOCAL_LENGTH_DEFAULT, + .max = OV2680_FOCAL_LENGTH_DEFAULT, + .step = 0x01, + .def = OV2680_FOCAL_LENGTH_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "f-number", + .min = OV2680_F_NUMBER_DEFAULT, + .max = OV2680_F_NUMBER_DEFAULT, + .step = 0x01, + .def = OV2680_F_NUMBER_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_RANGE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "f-number range", + .min = OV2680_F_NUMBER_RANGE, + .max = OV2680_F_NUMBER_RANGE, + .step = 0x01, + .def = OV2680_F_NUMBER_RANGE, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_BIN_FACTOR_HORZ, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "horizontal binning factor", + .min = 0, + .max = OV2680_BIN_FACTOR_MAX, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_BIN_FACTOR_VERT, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "vertical binning factor", + .min = 0, + .max = OV2680_BIN_FACTOR_MAX, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip", + .min = 0, + .max = 1, + .step = 1, + .def = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror", + .min = 0, + .max = 1, + .step = 1, + .def = 0, + }, +}; + +static int ov2680_init_registers(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + ret = ov2680_write_reg(client, OV2680_8BIT, OV2680_SW_RESET, 0x01); + ret |= ov2680_write_reg_array(client, ov2680_global_setting); + + return ret; +} + +static int ov2680_init(struct v4l2_subdev *sd) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + + int ret; + + mutex_lock(&dev->input_lock); + + /* restore settings */ + ov2680_res = ov2680_res_preview; + N_RES = N_RES_PREVIEW; + + ret = ov2680_init_registers(sd); + + mutex_unlock(&dev->input_lock); + + return ret; +} + +static int power_ctrl(struct v4l2_subdev *sd, bool flag) +{ + int ret = 0; + struct ov2680_device *dev = to_ov2680_sensor(sd); + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->power_ctrl) + return dev->platform_data->power_ctrl(sd, flag); + + if (flag) { + ret |= dev->platform_data->v1p8_ctrl(sd, 1); + ret |= dev->platform_data->v2p8_ctrl(sd, 1); + usleep_range(10000, 15000); + } + + if (!flag || ret) { + ret |= dev->platform_data->v1p8_ctrl(sd, 0); + ret |= dev->platform_data->v2p8_ctrl(sd, 0); + } + return ret; +} + +static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) +{ + int ret; + struct ov2680_device *dev = to_ov2680_sensor(sd); + + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->gpio_ctrl) + return dev->platform_data->gpio_ctrl(sd, flag); + + /* The OV2680 documents only one GPIO input (#XSHUTDN), but + * existing integrations often wire two (reset/power_down) + * because that is the way other sensors work. There is no + * way to tell how it is wired internally, so existing + * firmwares expose both and we drive them symmetrically. */ + if (flag) { + ret = dev->platform_data->gpio0_ctrl(sd, 1); + usleep_range(10000, 15000); + /* Ignore return from second gpio, it may not be there */ + dev->platform_data->gpio1_ctrl(sd, 1); + usleep_range(10000, 15000); + } else { + dev->platform_data->gpio1_ctrl(sd, 0); + ret = dev->platform_data->gpio0_ctrl(sd, 0); + } + return ret; +} + +static int power_up(struct v4l2_subdev *sd) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + if (!dev->platform_data) { + dev_err(&client->dev, + "no camera_sensor_platform_data"); + return -ENODEV; + } + + /* power control */ + ret = power_ctrl(sd, 1); + if (ret) + goto fail_power; + + /* according to DS, at least 5ms is needed between DOVDD and PWDN */ + usleep_range(5000, 6000); + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 1); + if (ret) { + ret = gpio_ctrl(sd, 1); + if (ret) + goto fail_power; + } + + /* flis clock control */ + ret = dev->platform_data->flisclk_ctrl(sd, 1); + if (ret) + goto fail_clk; + + /* according to DS, 20ms is needed between PWDN and i2c access */ + msleep(20); + + return 0; + +fail_clk: + gpio_ctrl(sd, 0); +fail_power: + power_ctrl(sd, 0); + dev_err(&client->dev, "sensor power-up failed\n"); + + return ret; +} + +static int power_down(struct v4l2_subdev *sd) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + h_flag = 0; + v_flag = 0; + if (!dev->platform_data) { + dev_err(&client->dev, + "no camera_sensor_platform_data"); + return -ENODEV; + } + + ret = dev->platform_data->flisclk_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "flisclk failed\n"); + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 0); + if (ret) { + ret = gpio_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "gpio failed 2\n"); + } + + /* power control */ + ret = power_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "vprog failed.\n"); + + return ret; +} + +static int ov2680_s_power(struct v4l2_subdev *sd, int on) +{ + int ret; + + if (on == 0){ + ret = power_down(sd); + } else { + ret = power_up(sd); + if (!ret) + return ov2680_init(sd); + } + return ret; +} + +/* + * distance - calculate the distance + * @res: resolution + * @w: width + * @h: height + * + * Get the gap between resolution and w/h. + * res->width/height smaller than w/h wouldn't be considered. + * Returns the value of gap or -1 if fail. + */ +#define LARGEST_ALLOWED_RATIO_MISMATCH 600 +static int distance(struct ov2680_resolution *res, u32 w, u32 h) +{ + unsigned int w_ratio = (res->width << 13) / w; + unsigned int h_ratio; + int match; + + if (h == 0) + return -1; + h_ratio = (res->height << 13) / h; + if (h_ratio == 0) + return -1; + match = abs(((w_ratio << 13) / h_ratio) - ((int)8192)); + + + if ((w_ratio < (int)8192) || (h_ratio < (int)8192) || + (match > LARGEST_ALLOWED_RATIO_MISMATCH)) + return -1; + + return w_ratio + h_ratio; +} + +/* Return the nearest higher resolution index */ +static int nearest_resolution_index(int w, int h) +{ + int i; + int idx = -1; + int dist; + int min_dist = INT_MAX; + struct ov2680_resolution *tmp_res = NULL; + + for (i = 0; i < N_RES; i++) { + tmp_res = &ov2680_res[i]; + dist = distance(tmp_res, w, h); + if (dist == -1) + continue; + if (dist < min_dist) { + min_dist = dist; + idx = i; + } + } + + return idx; +} + +static int get_resolution_index(int w, int h) +{ + int i; + + for (i = 0; i < N_RES; i++) { + if (w != ov2680_res[i].width) + continue; + if (h != ov2680_res[i].height) + continue; + + return i; + } + + return -1; +} + +static int ov2680_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt = &format->format; + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct camera_mipi_info *ov2680_info = NULL; + int ret = 0; + int idx = 0; + dev_dbg(&client->dev, "+++++ov2680_s_mbus_fmt+++++l\n"); + if (format->pad) + return -EINVAL; + + if (!fmt) + return -EINVAL; + + ov2680_info = v4l2_get_subdev_hostdata(sd); + if (!ov2680_info) + return -EINVAL; + + mutex_lock(&dev->input_lock); + idx = nearest_resolution_index(fmt->width, fmt->height); + if (idx == -1) { + /* return the largest resolution */ + fmt->width = ov2680_res[N_RES - 1].width; + fmt->height = ov2680_res[N_RES - 1].height; + } else { + fmt->width = ov2680_res[idx].width; + fmt->height = ov2680_res[idx].height; + } + fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *fmt; + mutex_unlock(&dev->input_lock); + return 0; + } + dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); + dev_dbg(&client->dev, "+++++get_resolution_index=%d+++++l\n", + dev->fmt_idx); + if (dev->fmt_idx == -1) { + dev_err(&client->dev, "get resolution fail\n"); + mutex_unlock(&dev->input_lock); + return -EINVAL; + } + v4l2_info(client, "__s_mbus_fmt i=%d, w=%d, h=%d\n", dev->fmt_idx, + fmt->width, fmt->height); + dev_dbg(&client->dev, "__s_mbus_fmt i=%d, w=%d, h=%d\n", + dev->fmt_idx, fmt->width, fmt->height); + + ret = ov2680_write_reg_array(client, ov2680_res[dev->fmt_idx].regs); + if (ret) + dev_err(&client->dev, "ov2680 write resolution register err\n"); + + ret = ov2680_get_intg_factor(client, ov2680_info, + &ov2680_res[dev->fmt_idx]); + if (ret) { + dev_err(&client->dev, "failed to get integration_factor\n"); + goto err; + } + + /*recall flip functions to avoid flip registers + * were overridden by default setting + */ + if (h_flag) + ov2680_h_flip(sd, h_flag); + if (v_flag) + ov2680_v_flip(sd, v_flag); + + v4l2_info(client, "\n%s idx %d \n", __func__, dev->fmt_idx); + + /*ret = startup(sd); + * if (ret) + * dev_err(&client->dev, "ov2680 startup err\n"); + */ +err: + mutex_unlock(&dev->input_lock); + return ret; +} + +static int ov2680_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt = &format->format; + struct ov2680_device *dev = to_ov2680_sensor(sd); + + if (format->pad) + return -EINVAL; + + if (!fmt) + return -EINVAL; + + fmt->width = ov2680_res[dev->fmt_idx].width; + fmt->height = ov2680_res[dev->fmt_idx].height; + fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; + + return 0; +} + +static int ov2680_detect(struct i2c_client *client) +{ + struct i2c_adapter *adapter = client->adapter; + u16 high, low; + int ret; + u16 id; + u8 revision; + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + return -ENODEV; + + ret = ov2680_read_reg(client, OV2680_8BIT, + OV2680_SC_CMMN_CHIP_ID_H, &high); + if (ret) { + dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); + return -ENODEV; + } + ret = ov2680_read_reg(client, OV2680_8BIT, + OV2680_SC_CMMN_CHIP_ID_L, &low); + id = ((((u16) high) << 8) | (u16) low); + + if (id != OV2680_ID) { + dev_err(&client->dev, "sensor ID error 0x%x\n", id); + return -ENODEV; + } + + ret = ov2680_read_reg(client, OV2680_8BIT, + OV2680_SC_CMMN_SUB_ID, &high); + revision = (u8) high & 0x0f; + + dev_info(&client->dev, "sensor_revision id = 0x%x\n", id); + + return 0; +} + +static int ov2680_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + mutex_lock(&dev->input_lock); + if(enable ) + dev_dbg(&client->dev, "ov2680_s_stream one \n"); + else + dev_dbg(&client->dev, "ov2680_s_stream off \n"); + + ret = ov2680_write_reg(client, OV2680_8BIT, OV2680_SW_STREAM, + enable ? OV2680_START_STREAMING : + OV2680_STOP_STREAMING); +#if 0 + /* restore settings */ + ov2680_res = ov2680_res_preview; + N_RES = N_RES_PREVIEW; +#endif + + //otp valid at stream on state + //if(!dev->otp_data) + // dev->otp_data = ov2680_otp_read(sd); + + mutex_unlock(&dev->input_lock); + + return ret; +} + + +static int ov2680_s_config(struct v4l2_subdev *sd, + int irq, void *platform_data) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + if (!platform_data) + return -ENODEV; + + dev->platform_data = + (struct camera_sensor_platform_data *)platform_data; + + mutex_lock(&dev->input_lock); + /* power off the module, then power on it in future + * as first power on by board may not fulfill the + * power on sequqence needed by the module + */ + ret = power_down(sd); + if (ret) { + dev_err(&client->dev, "ov2680 power-off err.\n"); + goto fail_power_off; + } + + ret = power_up(sd); + if (ret) { + dev_err(&client->dev, "ov2680 power-up err.\n"); + goto fail_power_on; + } + + ret = dev->platform_data->csi_cfg(sd, 1); + if (ret) + goto fail_csi_cfg; + + /* config & detect sensor */ + ret = ov2680_detect(client); + if (ret) { + dev_err(&client->dev, "ov2680_detect err s_config.\n"); + goto fail_csi_cfg; + } + + /* turn off sensor, after probed */ + ret = power_down(sd); + if (ret) { + dev_err(&client->dev, "ov2680 power-off err.\n"); + goto fail_csi_cfg; + } + mutex_unlock(&dev->input_lock); + + return 0; + +fail_csi_cfg: + dev->platform_data->csi_cfg(sd, 0); +fail_power_on: + power_down(sd); + dev_err(&client->dev, "sensor power-gating failed\n"); +fail_power_off: + mutex_unlock(&dev->input_lock); + return ret; +} + +static int ov2680_g_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!param) + return -EINVAL; + + if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + dev_err(&client->dev, "unsupported buffer type.\n"); + return -EINVAL; + } + + memset(param, 0, sizeof(*param)); + param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { + param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + param->parm.capture.timeperframe.numerator = 1; + param->parm.capture.capturemode = dev->run_mode; + param->parm.capture.timeperframe.denominator = + ov2680_res[dev->fmt_idx].fps; + } + return 0; +} + +static int ov2680_s_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + dev->run_mode = param->parm.capture.capturemode; + + v4l2_info(client, "\n%s:run_mode :%x\n", __func__, dev->run_mode); + + mutex_lock(&dev->input_lock); + switch (dev->run_mode) { + case CI_MODE_VIDEO: + ov2680_res = ov2680_res_video; + N_RES = N_RES_VIDEO; + break; + case CI_MODE_STILL_CAPTURE: + ov2680_res = ov2680_res_still; + N_RES = N_RES_STILL; + break; + default: + ov2680_res = ov2680_res_preview; + N_RES = N_RES_PREVIEW; + } + mutex_unlock(&dev->input_lock); + return 0; +} + +static int ov2680_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + + interval->interval.numerator = 1; + interval->interval.denominator = ov2680_res[dev->fmt_idx].fps; + + return 0; +} + +static int ov2680_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= MAX_FMTS) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SBGGR10_1X10; + return 0; +} + +static int ov2680_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + int index = fse->index; + + if (index >= N_RES) + return -EINVAL; + + fse->min_width = ov2680_res[index].width; + fse->min_height = ov2680_res[index].height; + fse->max_width = ov2680_res[index].width; + fse->max_height = ov2680_res[index].height; + + return 0; + +} + +static int ov2680_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) +{ + struct ov2680_device *dev = to_ov2680_sensor(sd); + + mutex_lock(&dev->input_lock); + *frames = ov2680_res[dev->fmt_idx].skip_frames; + mutex_unlock(&dev->input_lock); + + return 0; +} + +static const struct v4l2_subdev_video_ops ov2680_video_ops = { + .s_stream = ov2680_s_stream, + .g_parm = ov2680_g_parm, + .s_parm = ov2680_s_parm, + .g_frame_interval = ov2680_g_frame_interval, +}; + +static const struct v4l2_subdev_sensor_ops ov2680_sensor_ops = { + .g_skip_frames = ov2680_g_skip_frames, +}; + +static const struct v4l2_subdev_core_ops ov2680_core_ops = { + .s_power = ov2680_s_power, + .ioctl = ov2680_ioctl, +}; + +static const struct v4l2_subdev_pad_ops ov2680_pad_ops = { + .enum_mbus_code = ov2680_enum_mbus_code, + .enum_frame_size = ov2680_enum_frame_size, + .get_fmt = ov2680_get_fmt, + .set_fmt = ov2680_set_fmt, +}; + +static const struct v4l2_subdev_ops ov2680_ops = { + .core = &ov2680_core_ops, + .video = &ov2680_video_ops, + .pad = &ov2680_pad_ops, + .sensor = &ov2680_sensor_ops, +}; + +static int ov2680_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2680_device *dev = to_ov2680_sensor(sd); + dev_dbg(&client->dev, "ov2680_remove...\n"); + + dev->platform_data->csi_cfg(sd, 0); + + v4l2_device_unregister_subdev(sd); + media_entity_cleanup(&dev->sd.entity); + v4l2_ctrl_handler_free(&dev->ctrl_handler); + kfree(dev); + + return 0; +} + +static int ov2680_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ov2680_device *dev; + int ret; + void *pdata; + unsigned int i; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + dev_err(&client->dev, "out of memory\n"); + return -ENOMEM; + } + + mutex_init(&dev->input_lock); + + dev->fmt_idx = 0; + v4l2_i2c_subdev_init(&(dev->sd), client, &ov2680_ops); + + if (ACPI_COMPANION(&client->dev)) + pdata = gmin_camera_platform_data(&dev->sd, + ATOMISP_INPUT_FORMAT_RAW_10, + atomisp_bayer_order_bggr); + else + pdata = client->dev.platform_data; + + if (!pdata) { + ret = -EINVAL; + goto out_free; + } + + ret = ov2680_s_config(&dev->sd, client->irq, pdata); + if (ret) + goto out_free; + + ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); + if (ret) + goto out_free; + + dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + dev->pad.flags = MEDIA_PAD_FL_SOURCE; + dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; + dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = + v4l2_ctrl_handler_init(&dev->ctrl_handler, + ARRAY_SIZE(ov2680_controls)); + if (ret) { + ov2680_remove(client); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(ov2680_controls); i++) + v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov2680_controls[i], + NULL); + + if (dev->ctrl_handler.error) { + ov2680_remove(client); + return dev->ctrl_handler.error; + } + + /* Use same lock for controls as for everything else. */ + dev->ctrl_handler.lock = &dev->input_lock; + dev->sd.ctrl_handler = &dev->ctrl_handler; + + ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); + if (ret) + { + ov2680_remove(client); + dev_dbg(&client->dev, "+++ remove ov2680 \n"); + } + return ret; +out_free: + dev_dbg(&client->dev, "+++ out free \n"); + v4l2_device_unregister_subdev(&dev->sd); + kfree(dev); + return ret; +} + +static const struct acpi_device_id ov2680_acpi_match[] = { + {"XXOV2680"}, + {"OVTI2680"}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, ov2680_acpi_match); + + +MODULE_DEVICE_TABLE(i2c, ov2680_id); +static struct i2c_driver ov2680_driver = { + .driver = { + .owner = THIS_MODULE, + .name = OV2680_NAME, + .acpi_match_table = ACPI_PTR(ov2680_acpi_match), + + }, + .probe = ov2680_probe, + .remove = ov2680_remove, + .id_table = ov2680_id, +}; + +static int init_ov2680(void) +{ + return i2c_add_driver(&ov2680_driver); +} + +static void exit_ov2680(void) +{ + + i2c_del_driver(&ov2680_driver); +} + +module_init(init_ov2680); +module_exit(exit_ov2680); + +MODULE_AUTHOR("Jacky Wang "); +MODULE_DESCRIPTION("A low-level driver for OmniVision 2680 sensors"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c new file mode 100644 index 000000000000..10094ac56561 --- /dev/null +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -0,0 +1,1373 @@ +/* + * Support for OmniVision OV2722 1080p HD camera sensor. + * + * Copyright (c) 2013 Intel Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../include/linux/atomisp_gmin_platform.h" +#include +#include + +#include "ov2722.h" + +/* i2c read/write stuff */ +static int ov2722_read_reg(struct i2c_client *client, + u16 data_length, u16 reg, u16 *val) +{ + int err; + struct i2c_msg msg[2]; + unsigned char data[6]; + + if (!client->adapter) { + dev_err(&client->dev, "%s error, no client->adapter\n", + __func__); + return -ENODEV; + } + + if (data_length != OV2722_8BIT && data_length != OV2722_16BIT + && data_length != OV2722_32BIT) { + dev_err(&client->dev, "%s error, invalid data length\n", + __func__); + return -EINVAL; + } + + memset(msg, 0 , sizeof(msg)); + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = I2C_MSG_LENGTH; + msg[0].buf = data; + + /* high byte goes out first */ + data[0] = (u8)(reg >> 8); + data[1] = (u8)(reg & 0xff); + + msg[1].addr = client->addr; + msg[1].len = data_length; + msg[1].flags = I2C_M_RD; + msg[1].buf = data; + + err = i2c_transfer(client->adapter, msg, 2); + if (err != 2) { + if (err >= 0) + err = -EIO; + dev_err(&client->dev, + "read from offset 0x%x error %d", reg, err); + return err; + } + + *val = 0; + /* high byte comes first */ + if (data_length == OV2722_8BIT) + *val = (u8)data[0]; + else if (data_length == OV2722_16BIT) + *val = be16_to_cpu(*(u16 *)&data[0]); + else + *val = be32_to_cpu(*(u32 *)&data[0]); + + return 0; +} + +static int ov2722_i2c_write(struct i2c_client *client, u16 len, u8 *data) +{ + struct i2c_msg msg; + const int num_msg = 1; + int ret; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = len; + msg.buf = data; + ret = i2c_transfer(client->adapter, &msg, 1); + + return ret == num_msg ? 0 : -EIO; +} + +static int ov2722_write_reg(struct i2c_client *client, u16 data_length, + u16 reg, u16 val) +{ + int ret; + unsigned char data[4] = {0}; + u16 *wreg = (u16 *)data; + const u16 len = data_length + sizeof(u16); /* 16-bit address + data */ + + if (data_length != OV2722_8BIT && data_length != OV2722_16BIT) { + dev_err(&client->dev, + "%s error, invalid data_length\n", __func__); + return -EINVAL; + } + + /* high byte goes out first */ + *wreg = cpu_to_be16(reg); + + if (data_length == OV2722_8BIT) { + data[2] = (u8)(val); + } else { + /* OV2722_16BIT */ + u16 *wdata = (u16 *)&data[2]; + *wdata = cpu_to_be16(val); + } + + ret = ov2722_i2c_write(client, len, data); + if (ret) + dev_err(&client->dev, + "write error: wrote 0x%x to offset 0x%x error %d", + val, reg, ret); + + return ret; +} + +/* + * ov2722_write_reg_array - Initializes a list of OV2722 registers + * @client: i2c driver client structure + * @reglist: list of registers to be written + * + * This function initializes a list of registers. When consecutive addresses + * are found in a row on the list, this function creates a buffer and sends + * consecutive data in a single i2c_transfer(). + * + * __ov2722_flush_reg_array, __ov2722_buf_reg_array() and + * __ov2722_write_reg_is_consecutive() are internal functions to + * ov2722_write_reg_array_fast() and should be not used anywhere else. + * + */ + +static int __ov2722_flush_reg_array(struct i2c_client *client, + struct ov2722_write_ctrl *ctrl) +{ + u16 size; + + if (ctrl->index == 0) + return 0; + + size = sizeof(u16) + ctrl->index; /* 16-bit address + data */ + ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr); + ctrl->index = 0; + + return ov2722_i2c_write(client, size, (u8 *)&ctrl->buffer); +} + +static int __ov2722_buf_reg_array(struct i2c_client *client, + struct ov2722_write_ctrl *ctrl, + const struct ov2722_reg *next) +{ + int size; + u16 *data16; + + switch (next->type) { + case OV2722_8BIT: + size = 1; + ctrl->buffer.data[ctrl->index] = (u8)next->val; + break; + case OV2722_16BIT: + size = 2; + data16 = (u16 *)&ctrl->buffer.data[ctrl->index]; + *data16 = cpu_to_be16((u16)next->val); + break; + default: + return -EINVAL; + } + + /* When first item is added, we need to store its starting address */ + if (ctrl->index == 0) + ctrl->buffer.addr = next->reg; + + ctrl->index += size; + + /* + * Buffer cannot guarantee free space for u32? Better flush it to avoid + * possible lack of memory for next item. + */ + if (ctrl->index + sizeof(u16) >= OV2722_MAX_WRITE_BUF_SIZE) + return __ov2722_flush_reg_array(client, ctrl); + + return 0; +} + +static int __ov2722_write_reg_is_consecutive(struct i2c_client *client, + struct ov2722_write_ctrl *ctrl, + const struct ov2722_reg *next) +{ + if (ctrl->index == 0) + return 1; + + return ctrl->buffer.addr + ctrl->index == next->reg; +} + +static int ov2722_write_reg_array(struct i2c_client *client, + const struct ov2722_reg *reglist) +{ + const struct ov2722_reg *next = reglist; + struct ov2722_write_ctrl ctrl; + int err; + + ctrl.index = 0; + for (; next->type != OV2722_TOK_TERM; next++) { + switch (next->type & OV2722_TOK_MASK) { + case OV2722_TOK_DELAY: + err = __ov2722_flush_reg_array(client, &ctrl); + if (err) + return err; + msleep(next->val); + break; + default: + /* + * If next address is not consecutive, data needs to be + * flushed before proceed. + */ + if (!__ov2722_write_reg_is_consecutive(client, &ctrl, + next)) { + err = __ov2722_flush_reg_array(client, &ctrl); + if (err) + return err; + } + err = __ov2722_buf_reg_array(client, &ctrl, next); + if (err) { + dev_err(&client->dev, "%s: write error, aborted\n", + __func__); + return err; + } + break; + } + } + + return __ov2722_flush_reg_array(client, &ctrl); +} +static int ov2722_g_focal(struct v4l2_subdev *sd, s32 *val) +{ + *val = (OV2722_FOCAL_LENGTH_NUM << 16) | OV2722_FOCAL_LENGTH_DEM; + return 0; +} + +static int ov2722_g_fnumber(struct v4l2_subdev *sd, s32 *val) +{ + /*const f number for imx*/ + *val = (OV2722_F_NUMBER_DEFAULT_NUM << 16) | OV2722_F_NUMBER_DEM; + return 0; +} + +static int ov2722_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) +{ + *val = (OV2722_F_NUMBER_DEFAULT_NUM << 24) | + (OV2722_F_NUMBER_DEM << 16) | + (OV2722_F_NUMBER_DEFAULT_NUM << 8) | OV2722_F_NUMBER_DEM; + return 0; +} + +static int ov2722_get_intg_factor(struct i2c_client *client, + struct camera_mipi_info *info, + const struct ov2722_resolution *res) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2722_device *dev = NULL; + struct atomisp_sensor_mode_data *buf = &info->data; + const unsigned int ext_clk_freq_hz = 19200000; + const unsigned int pll_invariant_div = 10; + unsigned int pix_clk_freq_hz; + u16 pre_pll_clk_div; + u16 pll_multiplier; + u16 op_pix_clk_div; + u16 reg_val; + int ret; + + if (!info) + return -EINVAL; + + dev = to_ov2722_sensor(sd); + + /* pixel clock calculattion */ + ret = ov2722_read_reg(client, OV2722_8BIT, + OV2722_SC_CMMN_PLL_CTRL3, &pre_pll_clk_div); + if (ret) + return ret; + + ret = ov2722_read_reg(client, OV2722_8BIT, + OV2722_SC_CMMN_PLL_MULTIPLIER, &pll_multiplier); + if (ret) + return ret; + + ret = ov2722_read_reg(client, OV2722_8BIT, + OV2722_SC_CMMN_PLL_DEBUG_OPT, &op_pix_clk_div); + if (ret) + return ret; + + pre_pll_clk_div = (pre_pll_clk_div & 0x70) >> 4; + if (0 == pre_pll_clk_div) + return -EINVAL; + + pll_multiplier = pll_multiplier & 0x7f; + op_pix_clk_div = op_pix_clk_div & 0x03; + pix_clk_freq_hz = ext_clk_freq_hz / pre_pll_clk_div * pll_multiplier + * op_pix_clk_div / pll_invariant_div; + + dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz; + buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz; + + /* get integration time */ + buf->coarse_integration_time_min = OV2722_COARSE_INTG_TIME_MIN; + buf->coarse_integration_time_max_margin = + OV2722_COARSE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_min = OV2722_FINE_INTG_TIME_MIN; + buf->fine_integration_time_max_margin = + OV2722_FINE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_def = OV2722_FINE_INTG_TIME_MIN; + buf->frame_length_lines = res->lines_per_frame; + buf->line_length_pck = res->pixels_per_line; + buf->read_mode = res->bin_mode; + + /* get the cropping and output resolution to ISP for this mode. */ + ret = ov2722_read_reg(client, OV2722_16BIT, + OV2722_H_CROP_START_H, ®_val); + if (ret) + return ret; + buf->crop_horizontal_start = reg_val; + + ret = ov2722_read_reg(client, OV2722_16BIT, + OV2722_V_CROP_START_H, ®_val); + if (ret) + return ret; + buf->crop_vertical_start = reg_val; + + ret = ov2722_read_reg(client, OV2722_16BIT, + OV2722_H_CROP_END_H, ®_val); + if (ret) + return ret; + buf->crop_horizontal_end = reg_val; + + ret = ov2722_read_reg(client, OV2722_16BIT, + OV2722_V_CROP_END_H, ®_val); + if (ret) + return ret; + buf->crop_vertical_end = reg_val; + + ret = ov2722_read_reg(client, OV2722_16BIT, + OV2722_H_OUTSIZE_H, ®_val); + if (ret) + return ret; + buf->output_width = reg_val; + + ret = ov2722_read_reg(client, OV2722_16BIT, + OV2722_V_OUTSIZE_H, ®_val); + if (ret) + return ret; + buf->output_height = reg_val; + + buf->binning_factor_x = res->bin_factor_x ? + res->bin_factor_x : 1; + buf->binning_factor_y = res->bin_factor_y ? + res->bin_factor_y : 1; + return 0; +} + +static long __ov2722_set_exposure(struct v4l2_subdev *sd, int coarse_itg, + int gain, int digitgain) + +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov2722_device *dev = to_ov2722_sensor(sd); + u16 hts, vts; + int ret; + + dev_dbg(&client->dev, "set_exposure without group hold\n"); + + /* clear VTS_DIFF on manual mode */ + ret = ov2722_write_reg(client, OV2722_16BIT, OV2722_VTS_DIFF_H, 0); + if (ret) + return ret; + + hts = dev->pixels_per_line; + vts = dev->lines_per_frame; + + if ((coarse_itg + OV2722_COARSE_INTG_TIME_MAX_MARGIN) > vts) + vts = coarse_itg + OV2722_COARSE_INTG_TIME_MAX_MARGIN; + + coarse_itg <<= 4; + digitgain <<= 2; + + ret = ov2722_write_reg(client, OV2722_16BIT, + OV2722_VTS_H, vts); + if (ret) + return ret; + + ret = ov2722_write_reg(client, OV2722_16BIT, + OV2722_HTS_H, hts); + if (ret) + return ret; + + /* set exposure */ + ret = ov2722_write_reg(client, OV2722_8BIT, + OV2722_AEC_PK_EXPO_L, + coarse_itg & 0xff); + if (ret) + return ret; + + ret = ov2722_write_reg(client, OV2722_16BIT, + OV2722_AEC_PK_EXPO_H, + (coarse_itg >> 8) & 0xfff); + if (ret) + return ret; + + /* set analog gain */ + ret = ov2722_write_reg(client, OV2722_16BIT, + OV2722_AGC_ADJ_H, gain); + if (ret) + return ret; + + /* set digital gain */ + ret = ov2722_write_reg(client, OV2722_16BIT, + OV2722_MWB_GAIN_R_H, digitgain); + if (ret) + return ret; + + ret = ov2722_write_reg(client, OV2722_16BIT, + OV2722_MWB_GAIN_G_H, digitgain); + if (ret) + return ret; + + ret = ov2722_write_reg(client, OV2722_16BIT, + OV2722_MWB_GAIN_B_H, digitgain); + + return ret; +} + +static int ov2722_set_exposure(struct v4l2_subdev *sd, int exposure, + int gain, int digitgain) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + int ret; + + mutex_lock(&dev->input_lock); + ret = __ov2722_set_exposure(sd, exposure, gain, digitgain); + mutex_unlock(&dev->input_lock); + + return ret; +} + +static long ov2722_s_exposure(struct v4l2_subdev *sd, + struct atomisp_exposure *exposure) +{ + int exp = exposure->integration_time[0]; + int gain = exposure->gain[0]; + int digitgain = exposure->gain[1]; + + /* we should not accept the invalid value below. */ + if (gain == 0) { + struct i2c_client *client = v4l2_get_subdevdata(sd); + v4l2_err(client, "%s: invalid value\n", __func__); + return -EINVAL; + } + + return ov2722_set_exposure(sd, exp, gain, digitgain); +} + +static long ov2722_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + + switch (cmd) { + case ATOMISP_IOC_S_EXPOSURE: + return ov2722_s_exposure(sd, arg); + default: + return -EINVAL; + } + return 0; +} + +/* This returns the exposure time being used. This should only be used + * for filling in EXIF data, not for actual image processing. + */ +static int ov2722_q_exposure(struct v4l2_subdev *sd, s32 *value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u16 reg_v, reg_v2; + int ret; + + /* get exposure */ + ret = ov2722_read_reg(client, OV2722_8BIT, + OV2722_AEC_PK_EXPO_L, + ®_v); + if (ret) + goto err; + + ret = ov2722_read_reg(client, OV2722_8BIT, + OV2722_AEC_PK_EXPO_M, + ®_v2); + if (ret) + goto err; + + reg_v += reg_v2 << 8; + ret = ov2722_read_reg(client, OV2722_8BIT, + OV2722_AEC_PK_EXPO_H, + ®_v2); + if (ret) + goto err; + + *value = reg_v + (((u32)reg_v2 << 16)); +err: + return ret; +} + +static int ov2722_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov2722_device *dev = + container_of(ctrl->handler, struct ov2722_device, ctrl_handler); + int ret = 0; + unsigned int val; + switch (ctrl->id) { + case V4L2_CID_EXPOSURE_ABSOLUTE: + ret = ov2722_q_exposure(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FOCAL_ABSOLUTE: + ret = ov2722_g_focal(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_ABSOLUTE: + ret = ov2722_g_fnumber(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_RANGE: + ret = ov2722_g_fnumber_range(&dev->sd, &ctrl->val); + break; + case V4L2_CID_LINK_FREQ: + val = ov2722_res[dev->fmt_idx].mipi_freq; + if (val == 0) + return -EINVAL; + + ctrl->val = val * 1000; /* To Hz */ + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops ctrl_ops = { + .g_volatile_ctrl = ov2722_g_volatile_ctrl +}; + +struct v4l2_ctrl_config ov2722_controls[] = { + { + .ops = &ctrl_ops, + .id = V4L2_CID_EXPOSURE_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .min = 0x0, + .max = 0xffff, + .step = 0x01, + .def = 0x00, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FOCAL_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "focal length", + .min = OV2722_FOCAL_LENGTH_DEFAULT, + .max = OV2722_FOCAL_LENGTH_DEFAULT, + .step = 0x01, + .def = OV2722_FOCAL_LENGTH_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "f-number", + .min = OV2722_F_NUMBER_DEFAULT, + .max = OV2722_F_NUMBER_DEFAULT, + .step = 0x01, + .def = OV2722_F_NUMBER_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_RANGE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "f-number range", + .min = OV2722_F_NUMBER_RANGE, + .max = OV2722_F_NUMBER_RANGE, + .step = 0x01, + .def = OV2722_F_NUMBER_RANGE, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_LINK_FREQ, + .name = "Link Frequency", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 1, + .max = 1500000 * 1000, + .step = 1, + .def = 1, + .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY, + }, +}; + +static int ov2722_init(struct v4l2_subdev *sd) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + + mutex_lock(&dev->input_lock); + + /* restore settings */ + ov2722_res = ov2722_res_preview; + N_RES = N_RES_PREVIEW; + + mutex_unlock(&dev->input_lock); + + return 0; +} + +static int power_ctrl(struct v4l2_subdev *sd, bool flag) +{ + int ret = -1; + struct ov2722_device *dev = to_ov2722_sensor(sd); + + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->power_ctrl) + return dev->platform_data->power_ctrl(sd, flag); + + if (flag) { + ret = dev->platform_data->v1p8_ctrl(sd, 1); + if (ret == 0) { + ret = dev->platform_data->v2p8_ctrl(sd, 1); + if (ret) + dev->platform_data->v1p8_ctrl(sd, 0); + } + } else { + ret = dev->platform_data->v1p8_ctrl(sd, 0); + ret |= dev->platform_data->v2p8_ctrl(sd, 0); + } + + return ret; +} + +static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + int ret = -1; + + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->gpio_ctrl) + return dev->platform_data->gpio_ctrl(sd, flag); + + /* Note: the GPIO order is asymmetric: always RESET# + * before PWDN# when turning it on or off. + */ + ret = dev->platform_data->gpio0_ctrl(sd, flag); + /* + *ov2722 PWDN# active high when pull down,opposite to the convention + */ + ret |= dev->platform_data->gpio1_ctrl(sd, !flag); + return ret; +} + +static int power_up(struct v4l2_subdev *sd) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + if (!dev->platform_data) { + dev_err(&client->dev, + "no camera_sensor_platform_data"); + return -ENODEV; + } + + /* power control */ + ret = power_ctrl(sd, 1); + if (ret) + goto fail_power; + + /* according to DS, at least 5ms is needed between DOVDD and PWDN */ + usleep_range(5000, 6000); + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 1); + if (ret) { + ret = gpio_ctrl(sd, 0); + if (ret) + goto fail_power; + } + + /* flis clock control */ + ret = dev->platform_data->flisclk_ctrl(sd, 1); + if (ret) + goto fail_clk; + + /* according to DS, 20ms is needed between PWDN and i2c access */ + msleep(20); + + return 0; + +fail_clk: + gpio_ctrl(sd, 0); +fail_power: + power_ctrl(sd, 0); + dev_err(&client->dev, "sensor power-up failed\n"); + + return ret; +} + +static int power_down(struct v4l2_subdev *sd) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + if (!dev->platform_data) { + dev_err(&client->dev, + "no camera_sensor_platform_data"); + return -ENODEV; + } + + ret = dev->platform_data->flisclk_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "flisclk failed\n"); + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 0); + if (ret) { + ret = gpio_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "gpio failed 2\n"); + } + + /* power control */ + ret = power_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "vprog failed.\n"); + + return ret; +} + +static int ov2722_s_power(struct v4l2_subdev *sd, int on) +{ + int ret; + if (on == 0) + return power_down(sd); + else { + ret = power_up(sd); + if (!ret) + return ov2722_init(sd); + } + return ret; +} + +/* + * distance - calculate the distance + * @res: resolution + * @w: width + * @h: height + * + * Get the gap between resolution and w/h. + * res->width/height smaller than w/h wouldn't be considered. + * Returns the value of gap or -1 if fail. + */ +#define LARGEST_ALLOWED_RATIO_MISMATCH 800 +static int distance(struct ov2722_resolution *res, u32 w, u32 h) +{ + unsigned int w_ratio = (res->width << 13) / w; + unsigned int h_ratio; + int match; + + if (h == 0) + return -1; + h_ratio = (res->height << 13) / h; + if (h_ratio == 0) + return -1; + match = abs(((w_ratio << 13) / h_ratio) - 8192); + + if ((w_ratio < 8192) || (h_ratio < 8192) || + (match > LARGEST_ALLOWED_RATIO_MISMATCH)) + return -1; + + return w_ratio + h_ratio; +} + +/* Return the nearest higher resolution index */ +static int nearest_resolution_index(int w, int h) +{ + int i; + int idx = -1; + int dist; + int min_dist = INT_MAX; + struct ov2722_resolution *tmp_res = NULL; + + for (i = 0; i < N_RES; i++) { + tmp_res = &ov2722_res[i]; + dist = distance(tmp_res, w, h); + if (dist == -1) + continue; + if (dist < min_dist) { + min_dist = dist; + idx = i; + } + } + + return idx; +} + +static int get_resolution_index(int w, int h) +{ + int i; + + for (i = 0; i < N_RES; i++) { + if (w != ov2722_res[i].width) + continue; + if (h != ov2722_res[i].height) + continue; + + return i; + } + + return -1; +} + +/* TODO: remove it. */ +static int startup(struct v4l2_subdev *sd) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + ret = ov2722_write_reg(client, OV2722_8BIT, + OV2722_SW_RESET, 0x01); + if (ret) { + dev_err(&client->dev, "ov2722 reset err.\n"); + return ret; + } + + ret = ov2722_write_reg_array(client, ov2722_res[dev->fmt_idx].regs); + if (ret) { + dev_err(&client->dev, "ov2722 write register err.\n"); + return ret; + } + + return ret; +} + +static int ov2722_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt = &format->format; + struct ov2722_device *dev = to_ov2722_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct camera_mipi_info *ov2722_info = NULL; + int ret = 0; + int idx; + if (format->pad) + return -EINVAL; + if (!fmt) + return -EINVAL; + ov2722_info = v4l2_get_subdev_hostdata(sd); + if (!ov2722_info) + return -EINVAL; + + mutex_lock(&dev->input_lock); + idx = nearest_resolution_index(fmt->width, fmt->height); + if (idx == -1) { + /* return the largest resolution */ + fmt->width = ov2722_res[N_RES - 1].width; + fmt->height = ov2722_res[N_RES - 1].height; + } else { + fmt->width = ov2722_res[idx].width; + fmt->height = ov2722_res[idx].height; + } + fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *fmt; + mutex_unlock(&dev->input_lock); + return 0; + } + + dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); + if (dev->fmt_idx == -1) { + dev_err(&client->dev, "get resolution fail\n"); + mutex_unlock(&dev->input_lock); + return -EINVAL; + } + + dev->pixels_per_line = ov2722_res[dev->fmt_idx].pixels_per_line; + dev->lines_per_frame = ov2722_res[dev->fmt_idx].lines_per_frame; + + ret = startup(sd); + if (ret) { + int i = 0; + dev_err(&client->dev, "ov2722 startup err, retry to power up\n"); + for (i = 0; i < OV2722_POWER_UP_RETRY_NUM; i++) { + dev_err(&client->dev, + "ov2722 retry to power up %d/%d times, result: ", + i + 1, OV2722_POWER_UP_RETRY_NUM); + power_down(sd); + ret = power_up(sd); + if (ret) { + dev_err(&client->dev, "power up failed, continue\n"); + continue; + } + ret = startup(sd); + if (ret) { + dev_err(&client->dev, " startup FAILED!\n"); + } else { + dev_err(&client->dev, " startup SUCCESS!\n"); + break; + } + } + if (ret) { + dev_err(&client->dev, "ov2722 startup err\n"); + goto err; + } + } + + ret = ov2722_get_intg_factor(client, ov2722_info, + &ov2722_res[dev->fmt_idx]); + if (ret) + dev_err(&client->dev, "failed to get integration_factor\n"); + +err: + mutex_unlock(&dev->input_lock); + return ret; +} +static int ov2722_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt = &format->format; + struct ov2722_device *dev = to_ov2722_sensor(sd); + + if (format->pad) + return -EINVAL; + if (!fmt) + return -EINVAL; + + fmt->width = ov2722_res[dev->fmt_idx].width; + fmt->height = ov2722_res[dev->fmt_idx].height; + fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; + + return 0; +} + +static int ov2722_detect(struct i2c_client *client) +{ + struct i2c_adapter *adapter = client->adapter; + u16 high, low; + int ret; + u16 id; + u8 revision; + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + return -ENODEV; + + ret = ov2722_read_reg(client, OV2722_8BIT, + OV2722_SC_CMMN_CHIP_ID_H, &high); + if (ret) { + dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); + return -ENODEV; + } + ret = ov2722_read_reg(client, OV2722_8BIT, + OV2722_SC_CMMN_CHIP_ID_L, &low); + id = (high << 8) | low; + + if ((id != OV2722_ID) && (id != OV2720_ID)) { + dev_err(&client->dev, "sensor ID error\n"); + return -ENODEV; + } + + ret = ov2722_read_reg(client, OV2722_8BIT, + OV2722_SC_CMMN_SUB_ID, &high); + revision = (u8) high & 0x0f; + + dev_dbg(&client->dev, "sensor_revision = 0x%x\n", revision); + dev_dbg(&client->dev, "detect ov2722 success\n"); + return 0; +} + +static int ov2722_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + mutex_lock(&dev->input_lock); + + ret = ov2722_write_reg(client, OV2722_8BIT, OV2722_SW_STREAM, + enable ? OV2722_START_STREAMING : + OV2722_STOP_STREAMING); + + mutex_unlock(&dev->input_lock); + return ret; +} + +static int ov2722_s_config(struct v4l2_subdev *sd, + int irq, void *platform_data) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + if (!platform_data) + return -ENODEV; + + dev->platform_data = + (struct camera_sensor_platform_data *)platform_data; + + mutex_lock(&dev->input_lock); + if (dev->platform_data->platform_init) { + ret = dev->platform_data->platform_init(client); + if (ret) { + dev_err(&client->dev, "platform init err\n"); + goto platform_init_failed; + } + } + + /* power off the module, then power on it in future + * as first power on by board may not fulfill the + * power on sequqence needed by the module + */ + ret = power_down(sd); + if (ret) { + dev_err(&client->dev, "ov2722 power-off err.\n"); + goto fail_power_off; + } + + ret = power_up(sd); + if (ret) { + dev_err(&client->dev, "ov2722 power-up err.\n"); + goto fail_power_on; + } + + ret = dev->platform_data->csi_cfg(sd, 1); + if (ret) + goto fail_csi_cfg; + + /* config & detect sensor */ + ret = ov2722_detect(client); + if (ret) { + dev_err(&client->dev, "ov2722_detect err s_config.\n"); + goto fail_csi_cfg; + } + + /* turn off sensor, after probed */ + ret = power_down(sd); + if (ret) { + dev_err(&client->dev, "ov2722 power-off err.\n"); + goto fail_csi_cfg; + } + mutex_unlock(&dev->input_lock); + + return 0; + +fail_csi_cfg: + dev->platform_data->csi_cfg(sd, 0); +fail_power_on: + power_down(sd); + dev_err(&client->dev, "sensor power-gating failed\n"); +fail_power_off: + if (dev->platform_data->platform_deinit) + dev->platform_data->platform_deinit(); +platform_init_failed: + mutex_unlock(&dev->input_lock); + return ret; +} + +static int ov2722_g_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!param) + return -EINVAL; + + if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + dev_err(&client->dev, "unsupported buffer type.\n"); + return -EINVAL; + } + + memset(param, 0, sizeof(*param)); + param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { + param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + param->parm.capture.timeperframe.numerator = 1; + param->parm.capture.capturemode = dev->run_mode; + param->parm.capture.timeperframe.denominator = + ov2722_res[dev->fmt_idx].fps; + } + return 0; +} + +static int ov2722_s_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + dev->run_mode = param->parm.capture.capturemode; + + mutex_lock(&dev->input_lock); + switch (dev->run_mode) { + case CI_MODE_VIDEO: + ov2722_res = ov2722_res_video; + N_RES = N_RES_VIDEO; + break; + case CI_MODE_STILL_CAPTURE: + ov2722_res = ov2722_res_still; + N_RES = N_RES_STILL; + break; + default: + ov2722_res = ov2722_res_preview; + N_RES = N_RES_PREVIEW; + } + mutex_unlock(&dev->input_lock); + return 0; +} + +static int ov2722_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + + interval->interval.numerator = 1; + interval->interval.denominator = ov2722_res[dev->fmt_idx].fps; + + return 0; +} + +static int ov2722_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= MAX_FMTS) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SBGGR10_1X10; + return 0; +} + +static int ov2722_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + int index = fse->index; + + if (index >= N_RES) + return -EINVAL; + + fse->min_width = ov2722_res[index].width; + fse->min_height = ov2722_res[index].height; + fse->max_width = ov2722_res[index].width; + fse->max_height = ov2722_res[index].height; + + return 0; + +} + + +static int ov2722_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) +{ + struct ov2722_device *dev = to_ov2722_sensor(sd); + + mutex_lock(&dev->input_lock); + *frames = ov2722_res[dev->fmt_idx].skip_frames; + mutex_unlock(&dev->input_lock); + + return 0; +} + +static const struct v4l2_subdev_sensor_ops ov2722_sensor_ops = { + .g_skip_frames = ov2722_g_skip_frames, +}; + +static const struct v4l2_subdev_video_ops ov2722_video_ops = { + .s_stream = ov2722_s_stream, + .g_parm = ov2722_g_parm, + .s_parm = ov2722_s_parm, + .g_frame_interval = ov2722_g_frame_interval, +}; + +static const struct v4l2_subdev_core_ops ov2722_core_ops = { + .s_power = ov2722_s_power, + .ioctl = ov2722_ioctl, +}; + +static const struct v4l2_subdev_pad_ops ov2722_pad_ops = { + .enum_mbus_code = ov2722_enum_mbus_code, + .enum_frame_size = ov2722_enum_frame_size, + .get_fmt = ov2722_get_fmt, + .set_fmt = ov2722_set_fmt, +}; + +static const struct v4l2_subdev_ops ov2722_ops = { + .core = &ov2722_core_ops, + .video = &ov2722_video_ops, + .pad = &ov2722_pad_ops, + .sensor = &ov2722_sensor_ops, +}; + +static int ov2722_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2722_device *dev = to_ov2722_sensor(sd); + dev_dbg(&client->dev, "ov2722_remove...\n"); + + if (dev->platform_data->platform_deinit) + dev->platform_data->platform_deinit(); + + dev->platform_data->csi_cfg(sd, 0); + v4l2_ctrl_handler_free(&dev->ctrl_handler); + v4l2_device_unregister_subdev(sd); + + atomisp_gmin_remove_subdev(sd); + + media_entity_cleanup(&dev->sd.entity); + kfree(dev); + + return 0; +} + +static int __ov2722_init_ctrl_handler(struct ov2722_device *dev) +{ + struct v4l2_ctrl_handler *hdl; + unsigned int i; + hdl = &dev->ctrl_handler; + v4l2_ctrl_handler_init(&dev->ctrl_handler, ARRAY_SIZE(ov2722_controls)); + for (i = 0; i < ARRAY_SIZE(ov2722_controls); i++) + v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov2722_controls[i], + NULL); + + dev->link_freq = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_LINK_FREQ); + + if (dev->ctrl_handler.error || !dev->link_freq) + return dev->ctrl_handler.error; + + dev->sd.ctrl_handler = hdl; + + return 0; +} + +static int ov2722_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ov2722_device *dev; + void *ovpdev; + int ret; + struct acpi_device *adev; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + dev_err(&client->dev, "out of memory\n"); + return -ENOMEM; + } + + mutex_init(&dev->input_lock); + + dev->fmt_idx = 0; + v4l2_i2c_subdev_init(&(dev->sd), client, &ov2722_ops); + + ovpdev = client->dev.platform_data; + adev = ACPI_COMPANION(&client->dev); + if (adev) { + adev->power.flags.power_resources = 0; + ovpdev = gmin_camera_platform_data(&dev->sd, + ATOMISP_INPUT_FORMAT_RAW_10, + atomisp_bayer_order_grbg); + } + + ret = ov2722_s_config(&dev->sd, client->irq, ovpdev); + if (ret) + goto out_free; + + ret = __ov2722_init_ctrl_handler(dev); + if (ret) + goto out_ctrl_handler_free; + + dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + dev->pad.flags = MEDIA_PAD_FL_SOURCE; + dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; + dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); + if (ret) + ov2722_remove(client); + + if (ACPI_HANDLE(&client->dev)) + ret = atomisp_register_i2c_module(&dev->sd, ovpdev, RAW_CAMERA); + + return ret; + +out_ctrl_handler_free: + v4l2_ctrl_handler_free(&dev->ctrl_handler); + +out_free: + v4l2_device_unregister_subdev(&dev->sd); + kfree(dev); + return ret; +} + +MODULE_DEVICE_TABLE(i2c, ov2722_id); + +static const struct acpi_device_id ov2722_acpi_match[] = { + { "INT33FB" }, + {}, +}; + +MODULE_DEVICE_TABLE(acpi, ov2722_acpi_match); + +static struct i2c_driver ov2722_driver = { + .driver = { + .name = OV2722_NAME, + .acpi_match_table = ACPI_PTR(ov2722_acpi_match), + }, + .probe = ov2722_probe, + .remove = ov2722_remove, + .id_table = ov2722_id, +}; + +static int init_ov2722(void) +{ + return i2c_add_driver(&ov2722_driver); +} + +static void exit_ov2722(void) +{ + + i2c_del_driver(&ov2722_driver); +} + +module_init(init_ov2722); +module_exit(exit_ov2722); + +MODULE_AUTHOR("Wei Liu "); +MODULE_DESCRIPTION("A low-level driver for OmniVision 2722 sensors"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/gc0310.c b/drivers/staging/media/atomisp/i2c/gc0310.c deleted file mode 100644 index 35ed51ffe944..000000000000 --- a/drivers/staging/media/atomisp/i2c/gc0310.c +++ /dev/null @@ -1,1490 +0,0 @@ -/* - * Support for GalaxyCore GC0310 VGA camera sensor. - * - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../include/linux/atomisp_gmin_platform.h" - -#include "gc0310.h" - -/* i2c read/write stuff */ -static int gc0310_read_reg(struct i2c_client *client, - u16 data_length, u8 reg, u8 *val) -{ - int err; - struct i2c_msg msg[2]; - unsigned char data[1]; - - if (!client->adapter) { - dev_err(&client->dev, "%s error, no client->adapter\n", - __func__); - return -ENODEV; - } - - if (data_length != GC0310_8BIT) { - dev_err(&client->dev, "%s error, invalid data length\n", - __func__); - return -EINVAL; - } - - memset(msg, 0, sizeof(msg)); - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = I2C_MSG_LENGTH; - msg[0].buf = data; - - /* high byte goes out first */ - data[0] = (u8)(reg & 0xff); - - msg[1].addr = client->addr; - msg[1].len = data_length; - msg[1].flags = I2C_M_RD; - msg[1].buf = data; - - err = i2c_transfer(client->adapter, msg, 2); - if (err != 2) { - if (err >= 0) - err = -EIO; - dev_err(&client->dev, - "read from offset 0x%x error %d", reg, err); - return err; - } - - *val = 0; - /* high byte comes first */ - if (data_length == GC0310_8BIT) - *val = (u8)data[0]; - - return 0; -} - -static int gc0310_i2c_write(struct i2c_client *client, u16 len, u8 *data) -{ - struct i2c_msg msg; - const int num_msg = 1; - int ret; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = len; - msg.buf = data; - ret = i2c_transfer(client->adapter, &msg, 1); - - return ret == num_msg ? 0 : -EIO; -} - -static int gc0310_write_reg(struct i2c_client *client, u16 data_length, - u8 reg, u8 val) -{ - int ret; - unsigned char data[2] = {0}; - u8 *wreg = (u8 *)data; - const u16 len = data_length + sizeof(u8); /* 8-bit address + data */ - - if (data_length != GC0310_8BIT) { - dev_err(&client->dev, - "%s error, invalid data_length\n", __func__); - return -EINVAL; - } - - /* high byte goes out first */ - *wreg = (u8)(reg & 0xff); - - if (data_length == GC0310_8BIT) - data[1] = (u8)(val); - - ret = gc0310_i2c_write(client, len, data); - if (ret) - dev_err(&client->dev, - "write error: wrote 0x%x to offset 0x%x error %d", - val, reg, ret); - - return ret; -} - -/* - * gc0310_write_reg_array - Initializes a list of GC0310 registers - * @client: i2c driver client structure - * @reglist: list of registers to be written - * - * This function initializes a list of registers. When consecutive addresses - * are found in a row on the list, this function creates a buffer and sends - * consecutive data in a single i2c_transfer(). - * - * __gc0310_flush_reg_array, __gc0310_buf_reg_array() and - * __gc0310_write_reg_is_consecutive() are internal functions to - * gc0310_write_reg_array_fast() and should be not used anywhere else. - * - */ - -static int __gc0310_flush_reg_array(struct i2c_client *client, - struct gc0310_write_ctrl *ctrl) -{ - u16 size; - - if (ctrl->index == 0) - return 0; - - size = sizeof(u8) + ctrl->index; /* 8-bit address + data */ - ctrl->buffer.addr = (u8)(ctrl->buffer.addr); - ctrl->index = 0; - - return gc0310_i2c_write(client, size, (u8 *)&ctrl->buffer); -} - -static int __gc0310_buf_reg_array(struct i2c_client *client, - struct gc0310_write_ctrl *ctrl, - const struct gc0310_reg *next) -{ - int size; - - switch (next->type) { - case GC0310_8BIT: - size = 1; - ctrl->buffer.data[ctrl->index] = (u8)next->val; - break; - default: - return -EINVAL; - } - - /* When first item is added, we need to store its starting address */ - if (ctrl->index == 0) - ctrl->buffer.addr = next->reg; - - ctrl->index += size; - - /* - * Buffer cannot guarantee free space for u32? Better flush it to avoid - * possible lack of memory for next item. - */ - if (ctrl->index + sizeof(u8) >= GC0310_MAX_WRITE_BUF_SIZE) - return __gc0310_flush_reg_array(client, ctrl); - - return 0; -} - -static int __gc0310_write_reg_is_consecutive(struct i2c_client *client, - struct gc0310_write_ctrl *ctrl, - const struct gc0310_reg *next) -{ - if (ctrl->index == 0) - return 1; - - return ctrl->buffer.addr + ctrl->index == next->reg; -} - -static int gc0310_write_reg_array(struct i2c_client *client, - const struct gc0310_reg *reglist) -{ - const struct gc0310_reg *next = reglist; - struct gc0310_write_ctrl ctrl; - int err; - - ctrl.index = 0; - for (; next->type != GC0310_TOK_TERM; next++) { - switch (next->type & GC0310_TOK_MASK) { - case GC0310_TOK_DELAY: - err = __gc0310_flush_reg_array(client, &ctrl); - if (err) - return err; - msleep(next->val); - break; - default: - /* - * If next address is not consecutive, data needs to be - * flushed before proceed. - */ - if (!__gc0310_write_reg_is_consecutive(client, &ctrl, - next)) { - err = __gc0310_flush_reg_array(client, &ctrl); - if (err) - return err; - } - err = __gc0310_buf_reg_array(client, &ctrl, next); - if (err) { - dev_err(&client->dev, "%s: write error, aborted\n", - __func__); - return err; - } - break; - } - } - - return __gc0310_flush_reg_array(client, &ctrl); -} -static int gc0310_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (GC0310_FOCAL_LENGTH_NUM << 16) | GC0310_FOCAL_LENGTH_DEM; - return 0; -} - -static int gc0310_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /*const f number for imx*/ - *val = (GC0310_F_NUMBER_DEFAULT_NUM << 16) | GC0310_F_NUMBER_DEM; - return 0; -} - -static int gc0310_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (GC0310_F_NUMBER_DEFAULT_NUM << 24) | - (GC0310_F_NUMBER_DEM << 16) | - (GC0310_F_NUMBER_DEFAULT_NUM << 8) | GC0310_F_NUMBER_DEM; - return 0; -} - -static int gc0310_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - - *val = gc0310_res[dev->fmt_idx].bin_factor_x; - - return 0; -} - -static int gc0310_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - - *val = gc0310_res[dev->fmt_idx].bin_factor_y; - - return 0; -} - -static int gc0310_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct gc0310_resolution *res) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct gc0310_device *dev = to_gc0310_sensor(sd); - struct atomisp_sensor_mode_data *buf = &info->data; - u16 val; - u8 reg_val; - int ret; - unsigned int hori_blanking; - unsigned int vert_blanking; - unsigned int sh_delay; - - if (!info) - return -EINVAL; - - /* pixel clock calculattion */ - dev->vt_pix_clk_freq_mhz = 14400000; // 16.8MHz - buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz; - pr_info("vt_pix_clk_freq_mhz=%d\n", buf->vt_pix_clk_freq_mhz); - - /* get integration time */ - buf->coarse_integration_time_min = GC0310_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - GC0310_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = GC0310_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - GC0310_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = GC0310_FINE_INTG_TIME_MIN; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - /* Getting crop_horizontal_start */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_CROP_START_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_CROP_START_L, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = val | (reg_val & 0xFF); - pr_info("crop_horizontal_start=%d\n", buf->crop_horizontal_start); - - /* Getting crop_vertical_start */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_CROP_START_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_CROP_START_L, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = val | (reg_val & 0xFF); - pr_info("crop_vertical_start=%d\n", buf->crop_vertical_start); - - /* Getting output_width */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_OUTSIZE_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_OUTSIZE_L, ®_val); - if (ret) - return ret; - buf->output_width = val | (reg_val & 0xFF); - pr_info("output_width=%d\n", buf->output_width); - - /* Getting output_height */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_OUTSIZE_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_OUTSIZE_L, ®_val); - if (ret) - return ret; - buf->output_height = val | (reg_val & 0xFF); - pr_info("output_height=%d\n", buf->output_height); - - buf->crop_horizontal_end = buf->crop_horizontal_start + buf->output_width - 1; - buf->crop_vertical_end = buf->crop_vertical_start + buf->output_height - 1; - pr_info("crop_horizontal_end=%d\n", buf->crop_horizontal_end); - pr_info("crop_vertical_end=%d\n", buf->crop_vertical_end); - - /* Getting line_length_pck */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_BLANKING_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_H_BLANKING_L, ®_val); - if (ret) - return ret; - hori_blanking = val | (reg_val & 0xFF); - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_SH_DELAY, ®_val); - if (ret) - return ret; - sh_delay = reg_val; - buf->line_length_pck = buf->output_width + hori_blanking + sh_delay + 4; - pr_info("hori_blanking=%d sh_delay=%d line_length_pck=%d\n", hori_blanking, sh_delay, buf->line_length_pck); - - /* Getting frame_length_lines */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_BLANKING_H, ®_val); - if (ret) - return ret; - val = (reg_val & 0xFF) << 8; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_V_BLANKING_L, ®_val); - if (ret) - return ret; - vert_blanking = val | (reg_val & 0xFF); - buf->frame_length_lines = buf->output_height + vert_blanking; - pr_info("vert_blanking=%d frame_length_lines=%d\n", vert_blanking, buf->frame_length_lines); - - buf->binning_factor_x = res->bin_factor_x ? - res->bin_factor_x : 1; - buf->binning_factor_y = res->bin_factor_y ? - res->bin_factor_y : 1; - return 0; -} - -static int gc0310_set_gain(struct v4l2_subdev *sd, int gain) - -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u8 again, dgain; - - if (gain < 0x20) - gain = 0x20; - if (gain > 0x80) - gain = 0x80; - - if (gain >= 0x20 && gain < 0x40) { - again = 0x0; /* sqrt(2) */ - dgain = gain; - } else { - again = 0x2; /* 2 * sqrt(2) */ - dgain = gain / 2; - } - - pr_info("gain=0x%x again=0x%x dgain=0x%x\n", gain, again, dgain); - - /* set analog gain */ - ret = gc0310_write_reg(client, GC0310_8BIT, - GC0310_AGC_ADJ, again); - if (ret) - return ret; - - /* set digital gain */ - ret = gc0310_write_reg(client, GC0310_8BIT, - GC0310_DGC_ADJ, dgain); - if (ret) - return ret; - - return 0; -} - -static int __gc0310_set_exposure(struct v4l2_subdev *sd, int coarse_itg, - int gain, int digitgain) - -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - pr_info("coarse_itg=%d gain=%d digitgain=%d\n", coarse_itg, gain, digitgain); - - /* set exposure */ - ret = gc0310_write_reg(client, GC0310_8BIT, - GC0310_AEC_PK_EXPO_L, - coarse_itg & 0xff); - if (ret) - return ret; - - ret = gc0310_write_reg(client, GC0310_8BIT, - GC0310_AEC_PK_EXPO_H, - (coarse_itg >> 8) & 0x0f); - if (ret) - return ret; - - ret = gc0310_set_gain(sd, gain); - if (ret) - return ret; - - return ret; -} - -static int gc0310_set_exposure(struct v4l2_subdev *sd, int exposure, - int gain, int digitgain) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - int ret; - - mutex_lock(&dev->input_lock); - ret = __gc0310_set_exposure(sd, exposure, gain, digitgain); - mutex_unlock(&dev->input_lock); - - return ret; -} - -static long gc0310_s_exposure(struct v4l2_subdev *sd, - struct atomisp_exposure *exposure) -{ - int exp = exposure->integration_time[0]; - int gain = exposure->gain[0]; - int digitgain = exposure->gain[1]; - - /* we should not accept the invalid value below. */ - if (gain == 0) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - v4l2_err(client, "%s: invalid value\n", __func__); - return -EINVAL; - } - - return gc0310_set_exposure(sd, exp, gain, digitgain); -} - -/* TO DO */ -static int gc0310_v_flip(struct v4l2_subdev *sd, s32 value) -{ - return 0; -} - -/* TO DO */ -static int gc0310_h_flip(struct v4l2_subdev *sd, s32 value) -{ - return 0; -} - -static long gc0310_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - - switch (cmd) { - case ATOMISP_IOC_S_EXPOSURE: - return gc0310_s_exposure(sd, arg); - default: - return -EINVAL; - } - return 0; -} - -/* This returns the exposure time being used. This should only be used - * for filling in EXIF data, not for actual image processing. - */ -static int gc0310_q_exposure(struct v4l2_subdev *sd, s32 *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 reg_v; - int ret; - - /* get exposure */ - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_AEC_PK_EXPO_L, - ®_v); - if (ret) - goto err; - - *value = reg_v; - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_AEC_PK_EXPO_H, - ®_v); - if (ret) - goto err; - - *value = *value + (reg_v << 8); -err: - return ret; -} - -static int gc0310_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct gc0310_device *dev = - container_of(ctrl->handler, struct gc0310_device, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n", - __func__, ctrl->val); - ret = gc0310_v_flip(&dev->sd, ctrl->val); - break; - case V4L2_CID_HFLIP: - dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n", - __func__, ctrl->val); - ret = gc0310_h_flip(&dev->sd, ctrl->val); - break; - default: - ret = -EINVAL; - } - return ret; -} - -static int gc0310_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct gc0310_device *dev = - container_of(ctrl->handler, struct gc0310_device, ctrl_handler); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE_ABSOLUTE: - ret = gc0310_q_exposure(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = gc0310_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = gc0310_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = gc0310_g_fnumber_range(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_HORZ: - ret = gc0310_g_bin_factor_x(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_VERT: - ret = gc0310_g_bin_factor_y(&dev->sd, &ctrl->val); - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .s_ctrl = gc0310_s_ctrl, - .g_volatile_ctrl = gc0310_g_volatile_ctrl -}; - -struct v4l2_ctrl_config gc0310_controls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .min = 0x0, - .max = 0xffff, - .step = 0x01, - .def = 0x00, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip", - .min = 0, - .max = 1, - .step = 1, - .def = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror", - .min = 0, - .max = 1, - .step = 1, - .def = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = GC0310_FOCAL_LENGTH_DEFAULT, - .max = GC0310_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = GC0310_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = GC0310_F_NUMBER_DEFAULT, - .max = GC0310_F_NUMBER_DEFAULT, - .step = 0x01, - .def = GC0310_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = GC0310_F_NUMBER_RANGE, - .max = GC0310_F_NUMBER_RANGE, - .step = 0x01, - .def = GC0310_F_NUMBER_RANGE, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_HORZ, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "horizontal binning factor", - .min = 0, - .max = GC0310_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_VERT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vertical binning factor", - .min = 0, - .max = GC0310_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, -}; - -static int gc0310_init(struct v4l2_subdev *sd) -{ - int ret; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct gc0310_device *dev = to_gc0310_sensor(sd); - - pr_info("%s S\n", __func__); - mutex_lock(&dev->input_lock); - - /* set inital registers */ - ret = gc0310_write_reg_array(client, gc0310_reset_register); - - /* restore settings */ - gc0310_res = gc0310_res_preview; - N_RES = N_RES_PREVIEW; - - mutex_unlock(&dev->input_lock); - - pr_info("%s E\n", __func__); - return 0; -} - -static int power_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret = 0; - struct gc0310_device *dev = to_gc0310_sensor(sd); - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->power_ctrl) - return dev->platform_data->power_ctrl(sd, flag); - - if (flag) { - /* The upstream module driver (written to Crystal - * Cove) had this logic to pulse the rails low first. - * This appears to break things on the MRD7 with the - * X-Powers PMIC... - * - * ret = dev->platform_data->v1p8_ctrl(sd, 0); - * ret |= dev->platform_data->v2p8_ctrl(sd, 0); - * mdelay(50); - */ - ret |= dev->platform_data->v1p8_ctrl(sd, 1); - ret |= dev->platform_data->v2p8_ctrl(sd, 1); - usleep_range(10000, 15000); - } - - if (!flag || ret) { - ret |= dev->platform_data->v1p8_ctrl(sd, 0); - ret |= dev->platform_data->v2p8_ctrl(sd, 0); - } - return ret; -} - -static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret; - struct gc0310_device *dev = to_gc0310_sensor(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->gpio_ctrl) - return dev->platform_data->gpio_ctrl(sd, flag); - - /* GPIO0 == "reset" (active low), GPIO1 == "power down" */ - if (flag) { - /* Pulse reset, then release power down */ - ret = dev->platform_data->gpio0_ctrl(sd, 0); - usleep_range(5000, 10000); - ret |= dev->platform_data->gpio0_ctrl(sd, 1); - usleep_range(10000, 15000); - ret |= dev->platform_data->gpio1_ctrl(sd, 0); - usleep_range(10000, 15000); - } else { - ret = dev->platform_data->gpio1_ctrl(sd, 1); - ret |= dev->platform_data->gpio0_ctrl(sd, 0); - } - return ret; -} - - -static int power_down(struct v4l2_subdev *sd); - -static int power_up(struct v4l2_subdev *sd) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - pr_info("%s S\n", __func__); - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - - /* power control */ - ret = power_ctrl(sd, 1); - if (ret) - goto fail_power; - - /* flis clock control */ - ret = dev->platform_data->flisclk_ctrl(sd, 1); - if (ret) - goto fail_clk; - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 1); - if (ret) { - ret = gpio_ctrl(sd, 1); - if (ret) - goto fail_gpio; - } - - msleep(100); - - pr_info("%s E\n", __func__); - return 0; - -fail_gpio: - dev->platform_data->flisclk_ctrl(sd, 0); -fail_clk: - power_ctrl(sd, 0); -fail_power: - dev_err(&client->dev, "sensor power-up failed\n"); - - return ret; -} - -static int power_down(struct v4l2_subdev *sd) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 0); - if (ret) { - ret = gpio_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "gpio failed 2\n"); - } - - ret = dev->platform_data->flisclk_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "flisclk failed\n"); - - /* power control */ - ret = power_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "vprog failed.\n"); - - return ret; -} - -static int gc0310_s_power(struct v4l2_subdev *sd, int on) -{ - int ret; - if (on == 0) - return power_down(sd); - else { - ret = power_up(sd); - if (!ret) - return gc0310_init(sd); - } - return ret; -} - -/* - * distance - calculate the distance - * @res: resolution - * @w: width - * @h: height - * - * Get the gap between resolution and w/h. - * res->width/height smaller than w/h wouldn't be considered. - * Returns the value of gap or -1 if fail. - */ -#define LARGEST_ALLOWED_RATIO_MISMATCH 800 -static int distance(struct gc0310_resolution *res, u32 w, u32 h) -{ - unsigned int w_ratio = (res->width << 13) / w; - unsigned int h_ratio; - int match; - - if (h == 0) - return -1; - h_ratio = (res->height << 13) / h; - if (h_ratio == 0) - return -1; - match = abs(((w_ratio << 13) / h_ratio) - ((int)8192)); - - if ((w_ratio < (int)8192) || (h_ratio < (int)8192) || - (match > LARGEST_ALLOWED_RATIO_MISMATCH)) - return -1; - - return w_ratio + h_ratio; -} - -/* Return the nearest higher resolution index */ -static int nearest_resolution_index(int w, int h) -{ - int i; - int idx = -1; - int dist; - int min_dist = INT_MAX; - struct gc0310_resolution *tmp_res = NULL; - - for (i = 0; i < N_RES; i++) { - tmp_res = &gc0310_res[i]; - dist = distance(tmp_res, w, h); - if (dist == -1) - continue; - if (dist < min_dist) { - min_dist = dist; - idx = i; - } - } - - return idx; -} - -static int get_resolution_index(int w, int h) -{ - int i; - - for (i = 0; i < N_RES; i++) { - if (w != gc0310_res[i].width) - continue; - if (h != gc0310_res[i].height) - continue; - - return i; - } - - return -1; -} - - -/* TODO: remove it. */ -static int startup(struct v4l2_subdev *sd) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - pr_info("%s S\n", __func__); - - ret = gc0310_write_reg_array(client, gc0310_res[dev->fmt_idx].regs); - if (ret) { - dev_err(&client->dev, "gc0310 write register err.\n"); - return ret; - } - - pr_info("%s E\n", __func__); - return ret; -} - -static int gc0310_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct gc0310_device *dev = to_gc0310_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_mipi_info *gc0310_info = NULL; - int ret = 0; - int idx = 0; - pr_info("%s S\n", __func__); - - if (format->pad) - return -EINVAL; - - if (!fmt) - return -EINVAL; - - gc0310_info = v4l2_get_subdev_hostdata(sd); - if (!gc0310_info) - return -EINVAL; - - mutex_lock(&dev->input_lock); - - idx = nearest_resolution_index(fmt->width, fmt->height); - if (idx == -1) { - /* return the largest resolution */ - fmt->width = gc0310_res[N_RES - 1].width; - fmt->height = gc0310_res[N_RES - 1].height; - } else { - fmt->width = gc0310_res[idx].width; - fmt->height = gc0310_res[idx].height; - } - fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8; - - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; - mutex_unlock(&dev->input_lock); - return 0; - } - - dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); - if (dev->fmt_idx == -1) { - dev_err(&client->dev, "get resolution fail\n"); - mutex_unlock(&dev->input_lock); - return -EINVAL; - } - - printk("%s: before gc0310_write_reg_array %s\n", __FUNCTION__, - gc0310_res[dev->fmt_idx].desc); - ret = startup(sd); - if (ret) { - dev_err(&client->dev, "gc0310 startup err\n"); - goto err; - } - - ret = gc0310_get_intg_factor(client, gc0310_info, - &gc0310_res[dev->fmt_idx]); - if (ret) { - dev_err(&client->dev, "failed to get integration_factor\n"); - goto err; - } - - pr_info("%s E\n", __func__); -err: - mutex_unlock(&dev->input_lock); - return ret; -} - -static int gc0310_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct gc0310_device *dev = to_gc0310_sensor(sd); - - if (format->pad) - return -EINVAL; - - if (!fmt) - return -EINVAL; - - fmt->width = gc0310_res[dev->fmt_idx].width; - fmt->height = gc0310_res[dev->fmt_idx].height; - fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8; - - return 0; -} - -static int gc0310_detect(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - u8 high, low; - int ret; - u16 id; - - pr_info("%s S\n", __func__); - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) - return -ENODEV; - - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_SC_CMMN_CHIP_ID_H, &high); - if (ret) { - dev_err(&client->dev, "read sensor_id_high failed\n"); - return -ENODEV; - } - ret = gc0310_read_reg(client, GC0310_8BIT, - GC0310_SC_CMMN_CHIP_ID_L, &low); - if (ret) { - dev_err(&client->dev, "read sensor_id_low failed\n"); - return -ENODEV; - } - id = ((((u16) high) << 8) | (u16) low); - pr_info("sensor ID = 0x%x\n", id); - - if (id != GC0310_ID) { - dev_err(&client->dev, "sensor ID error, read id = 0x%x, target id = 0x%x\n", id, GC0310_ID); - return -ENODEV; - } - - dev_dbg(&client->dev, "detect gc0310 success\n"); - - pr_info("%s E\n", __func__); - - return 0; -} - -static int gc0310_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - pr_info("%s S enable=%d\n", __func__, enable); - mutex_lock(&dev->input_lock); - - if (enable) { - /* enable per frame MIPI and sensor ctrl reset */ - ret = gc0310_write_reg(client, GC0310_8BIT, - 0xFE, 0x30); - if (ret) { - mutex_unlock(&dev->input_lock); - return ret; - } - } - - ret = gc0310_write_reg(client, GC0310_8BIT, - GC0310_RESET_RELATED, GC0310_REGISTER_PAGE_3); - if (ret) { - mutex_unlock(&dev->input_lock); - return ret; - } - - ret = gc0310_write_reg(client, GC0310_8BIT, GC0310_SW_STREAM, - enable ? GC0310_START_STREAMING : - GC0310_STOP_STREAMING); - if (ret) { - mutex_unlock(&dev->input_lock); - return ret; - } - - ret = gc0310_write_reg(client, GC0310_8BIT, - GC0310_RESET_RELATED, GC0310_REGISTER_PAGE_0); - if (ret) { - mutex_unlock(&dev->input_lock); - return ret; - } - - mutex_unlock(&dev->input_lock); - pr_info("%s E\n", __func__); - return ret; -} - - -static int gc0310_s_config(struct v4l2_subdev *sd, - int irq, void *platform_data) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - pr_info("%s S\n", __func__); - if (!platform_data) - return -ENODEV; - - dev->platform_data = - (struct camera_sensor_platform_data *)platform_data; - - mutex_lock(&dev->input_lock); - if (dev->platform_data->platform_init) { - ret = dev->platform_data->platform_init(client); - if (ret) { - dev_err(&client->dev, "platform init err\n"); - goto platform_init_failed; - } - } - /* power off the module, then power on it in future - * as first power on by board may not fulfill the - * power on sequqence needed by the module - */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "gc0310 power-off err.\n"); - goto fail_power_off; - } - - ret = power_up(sd); - if (ret) { - dev_err(&client->dev, "gc0310 power-up err.\n"); - goto fail_power_on; - } - - ret = dev->platform_data->csi_cfg(sd, 1); - if (ret) - goto fail_csi_cfg; - - /* config & detect sensor */ - ret = gc0310_detect(client); - if (ret) { - dev_err(&client->dev, "gc0310_detect err s_config.\n"); - goto fail_csi_cfg; - } - - /* turn off sensor, after probed */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "gc0310 power-off err.\n"); - goto fail_csi_cfg; - } - mutex_unlock(&dev->input_lock); - - pr_info("%s E\n", __func__); - return 0; - -fail_csi_cfg: - dev->platform_data->csi_cfg(sd, 0); -fail_power_on: - power_down(sd); - dev_err(&client->dev, "sensor power-gating failed\n"); -fail_power_off: - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); -platform_init_failed: - mutex_unlock(&dev->input_lock); - return ret; -} - -static int gc0310_g_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!param) - return -EINVAL; - - if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&client->dev, "unsupported buffer type.\n"); - return -EINVAL; - } - - memset(param, 0, sizeof(*param)); - param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { - param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - param->parm.capture.timeperframe.numerator = 1; - param->parm.capture.capturemode = dev->run_mode; - param->parm.capture.timeperframe.denominator = - gc0310_res[dev->fmt_idx].fps; - } - return 0; -} - -static int gc0310_s_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - dev->run_mode = param->parm.capture.capturemode; - - mutex_lock(&dev->input_lock); - switch (dev->run_mode) { - case CI_MODE_VIDEO: - gc0310_res = gc0310_res_video; - N_RES = N_RES_VIDEO; - break; - case CI_MODE_STILL_CAPTURE: - gc0310_res = gc0310_res_still; - N_RES = N_RES_STILL; - break; - default: - gc0310_res = gc0310_res_preview; - N_RES = N_RES_PREVIEW; - } - mutex_unlock(&dev->input_lock); - return 0; -} - -static int gc0310_g_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - - interval->interval.numerator = 1; - interval->interval.denominator = gc0310_res[dev->fmt_idx].fps; - - return 0; -} - -static int gc0310_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->index >= MAX_FMTS) - return -EINVAL; - - code->code = MEDIA_BUS_FMT_SGRBG8_1X8; - return 0; -} - -static int gc0310_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - int index = fse->index; - - if (index >= N_RES) - return -EINVAL; - - fse->min_width = gc0310_res[index].width; - fse->min_height = gc0310_res[index].height; - fse->max_width = gc0310_res[index].width; - fse->max_height = gc0310_res[index].height; - - return 0; - -} - - -static int gc0310_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) -{ - struct gc0310_device *dev = to_gc0310_sensor(sd); - - mutex_lock(&dev->input_lock); - *frames = gc0310_res[dev->fmt_idx].skip_frames; - mutex_unlock(&dev->input_lock); - - return 0; -} - -static const struct v4l2_subdev_sensor_ops gc0310_sensor_ops = { - .g_skip_frames = gc0310_g_skip_frames, -}; - -static const struct v4l2_subdev_video_ops gc0310_video_ops = { - .s_stream = gc0310_s_stream, - .g_parm = gc0310_g_parm, - .s_parm = gc0310_s_parm, - .g_frame_interval = gc0310_g_frame_interval, -}; - -static const struct v4l2_subdev_core_ops gc0310_core_ops = { - .s_power = gc0310_s_power, - .ioctl = gc0310_ioctl, -}; - -static const struct v4l2_subdev_pad_ops gc0310_pad_ops = { - .enum_mbus_code = gc0310_enum_mbus_code, - .enum_frame_size = gc0310_enum_frame_size, - .get_fmt = gc0310_get_fmt, - .set_fmt = gc0310_set_fmt, -}; - -static const struct v4l2_subdev_ops gc0310_ops = { - .core = &gc0310_core_ops, - .video = &gc0310_video_ops, - .pad = &gc0310_pad_ops, - .sensor = &gc0310_sensor_ops, -}; - -static int gc0310_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct gc0310_device *dev = to_gc0310_sensor(sd); - dev_dbg(&client->dev, "gc0310_remove...\n"); - - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); - - dev->platform_data->csi_cfg(sd, 0); - - v4l2_device_unregister_subdev(sd); - media_entity_cleanup(&dev->sd.entity); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - kfree(dev); - - return 0; -} - -static int gc0310_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct gc0310_device *dev; - int ret; - void *pdata; - unsigned int i; - - pr_info("%s S\n", __func__); - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "out of memory\n"); - return -ENOMEM; - } - - mutex_init(&dev->input_lock); - - dev->fmt_idx = 0; - v4l2_i2c_subdev_init(&(dev->sd), client, &gc0310_ops); - - if (ACPI_COMPANION(&client->dev)) - pdata = gmin_camera_platform_data(&dev->sd, - ATOMISP_INPUT_FORMAT_RAW_8, - atomisp_bayer_order_grbg); - else - pdata = client->dev.platform_data; - - if (!pdata) { - ret = -EINVAL; - goto out_free; - } - - ret = gc0310_s_config(&dev->sd, client->irq, pdata); - if (ret) - goto out_free; - - ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); - if (ret) - goto out_free; - - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->format.code = MEDIA_BUS_FMT_SGRBG8_1X8; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - ret = - v4l2_ctrl_handler_init(&dev->ctrl_handler, - ARRAY_SIZE(gc0310_controls)); - if (ret) { - gc0310_remove(client); - return ret; - } - - for (i = 0; i < ARRAY_SIZE(gc0310_controls); i++) - v4l2_ctrl_new_custom(&dev->ctrl_handler, &gc0310_controls[i], - NULL); - - if (dev->ctrl_handler.error) { - gc0310_remove(client); - return dev->ctrl_handler.error; - } - - /* Use same lock for controls as for everything else. */ - dev->ctrl_handler.lock = &dev->input_lock; - dev->sd.ctrl_handler = &dev->ctrl_handler; - - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); - if (ret) - gc0310_remove(client); - - pr_info("%s E\n", __func__); - return ret; -out_free: - v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); - return ret; -} - -static const struct acpi_device_id gc0310_acpi_match[] = { - {"XXGC0310"}, - {"INT0310"}, - {}, -}; - -MODULE_DEVICE_TABLE(acpi, gc0310_acpi_match); - -MODULE_DEVICE_TABLE(i2c, gc0310_id); -static struct i2c_driver gc0310_driver = { - .driver = { - .name = GC0310_NAME, - .acpi_match_table = ACPI_PTR(gc0310_acpi_match), - }, - .probe = gc0310_probe, - .remove = gc0310_remove, - .id_table = gc0310_id, -}; - -static int init_gc0310(void) -{ - return i2c_add_driver(&gc0310_driver); -} - -static void exit_gc0310(void) -{ - - i2c_del_driver(&gc0310_driver); -} - -module_init(init_gc0310); -module_exit(exit_gc0310); - -MODULE_AUTHOR("Lai, Angie "); -MODULE_DESCRIPTION("A low-level driver for GalaxyCore GC0310 sensors"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/gc2235.c b/drivers/staging/media/atomisp/i2c/gc2235.c deleted file mode 100644 index e43d31ea9676..000000000000 --- a/drivers/staging/media/atomisp/i2c/gc2235.c +++ /dev/null @@ -1,1219 +0,0 @@ -/* - * Support for GalaxyCore GC2235 2M camera sensor. - * - * Copyright (c) 2014 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../include/linux/atomisp_gmin_platform.h" -#include -#include - -#include "gc2235.h" - -/* i2c read/write stuff */ -static int gc2235_read_reg(struct i2c_client *client, - u16 data_length, u16 reg, u16 *val) -{ - int err; - struct i2c_msg msg[2]; - unsigned char data[6]; - - if (!client->adapter) { - dev_err(&client->dev, "%s error, no client->adapter\n", - __func__); - return -ENODEV; - } - - if (data_length != GC2235_8BIT) { - dev_err(&client->dev, "%s error, invalid data length\n", - __func__); - return -EINVAL; - } - - memset(msg, 0, sizeof(msg)); - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = 1; - msg[0].buf = data; - - /* high byte goes out first */ - data[0] = (u8)(reg & 0xff); - - msg[1].addr = client->addr; - msg[1].len = data_length; - msg[1].flags = I2C_M_RD; - msg[1].buf = data; - - err = i2c_transfer(client->adapter, msg, 2); - if (err != 2) { - if (err >= 0) - err = -EIO; - dev_err(&client->dev, - "read from offset 0x%x error %d", reg, err); - return err; - } - - *val = 0; - /* high byte comes first */ - if (data_length == GC2235_8BIT) - *val = (u8)data[0]; - - return 0; -} - -static int gc2235_i2c_write(struct i2c_client *client, u16 len, u8 *data) -{ - struct i2c_msg msg; - const int num_msg = 1; - int ret; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = len; - msg.buf = data; - ret = i2c_transfer(client->adapter, &msg, 1); - - return ret == num_msg ? 0 : -EIO; -} - -static int gc2235_write_reg(struct i2c_client *client, u16 data_length, - u8 reg, u8 val) -{ - int ret; - unsigned char data[4] = {0}; - const u16 len = data_length + sizeof(u8); /* 16-bit address + data */ - - if (data_length != GC2235_8BIT) { - dev_err(&client->dev, - "%s error, invalid data_length\n", __func__); - return -EINVAL; - } - - /* high byte goes out first */ - data[0] = reg; - data[1] = val; - - ret = gc2235_i2c_write(client, len, data); - if (ret) - dev_err(&client->dev, - "write error: wrote 0x%x to offset 0x%x error %d", - val, reg, ret); - - return ret; -} - -static int __gc2235_flush_reg_array(struct i2c_client *client, - struct gc2235_write_ctrl *ctrl) -{ - u16 size; - - if (ctrl->index == 0) - return 0; - - size = sizeof(u8) + ctrl->index; /* 8-bit address + data */ - ctrl->index = 0; - - return gc2235_i2c_write(client, size, (u8 *)&ctrl->buffer); -} - -static int __gc2235_buf_reg_array(struct i2c_client *client, - struct gc2235_write_ctrl *ctrl, - const struct gc2235_reg *next) -{ - int size; - - if (next->type != GC2235_8BIT) - return -EINVAL; - - size = 1; - ctrl->buffer.data[ctrl->index] = (u8)next->val; - - /* When first item is added, we need to store its starting address */ - if (ctrl->index == 0) - ctrl->buffer.addr = next->reg; - - ctrl->index += size; - - /* - * Buffer cannot guarantee free space for u32? Better flush it to avoid - * possible lack of memory for next item. - */ - if (ctrl->index + sizeof(u8) >= GC2235_MAX_WRITE_BUF_SIZE) - return __gc2235_flush_reg_array(client, ctrl); - - return 0; -} -static int __gc2235_write_reg_is_consecutive(struct i2c_client *client, - struct gc2235_write_ctrl *ctrl, - const struct gc2235_reg *next) -{ - if (ctrl->index == 0) - return 1; - - return ctrl->buffer.addr + ctrl->index == next->reg; -} -static int gc2235_write_reg_array(struct i2c_client *client, - const struct gc2235_reg *reglist) -{ - const struct gc2235_reg *next = reglist; - struct gc2235_write_ctrl ctrl; - int err; - - ctrl.index = 0; - for (; next->type != GC2235_TOK_TERM; next++) { - switch (next->type & GC2235_TOK_MASK) { - case GC2235_TOK_DELAY: - err = __gc2235_flush_reg_array(client, &ctrl); - if (err) - return err; - msleep(next->val); - break; - default: - /* - * If next address is not consecutive, data needs to be - * flushed before proceed. - */ - if (!__gc2235_write_reg_is_consecutive(client, &ctrl, - next)) { - err = __gc2235_flush_reg_array(client, &ctrl); - if (err) - return err; - } - err = __gc2235_buf_reg_array(client, &ctrl, next); - if (err) { - dev_err(&client->dev, "%s: write error, aborted\n", - __func__); - return err; - } - break; - } - } - - return __gc2235_flush_reg_array(client, &ctrl); -} - -static int gc2235_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (GC2235_FOCAL_LENGTH_NUM << 16) | GC2235_FOCAL_LENGTH_DEM; - return 0; -} - -static int gc2235_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /*const f number for imx*/ - *val = (GC2235_F_NUMBER_DEFAULT_NUM << 16) | GC2235_F_NUMBER_DEM; - return 0; -} - -static int gc2235_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (GC2235_F_NUMBER_DEFAULT_NUM << 24) | - (GC2235_F_NUMBER_DEM << 16) | - (GC2235_F_NUMBER_DEFAULT_NUM << 8) | GC2235_F_NUMBER_DEM; - return 0; -} - - -static int gc2235_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct gc2235_resolution *res) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct gc2235_device *dev = to_gc2235_sensor(sd); - struct atomisp_sensor_mode_data *buf = &info->data; - u16 reg_val, reg_val_h, dummy; - int ret; - - if (!info) - return -EINVAL; - - /* pixel clock calculattion */ - buf->vt_pix_clk_freq_mhz = dev->vt_pix_clk_freq_mhz = 30000000; - - /* get integration time */ - buf->coarse_integration_time_min = GC2235_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - GC2235_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = GC2235_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - GC2235_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = GC2235_FINE_INTG_TIME_MIN; - buf->frame_length_lines = res->lines_per_frame; - buf->line_length_pck = res->pixels_per_line; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_H_CROP_START_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_H_CROP_START_L, ®_val); - if (ret) - return ret; - - buf->crop_horizontal_start = (reg_val_h << 8) | reg_val; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_V_CROP_START_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_V_CROP_START_L, ®_val); - if (ret) - return ret; - - buf->crop_vertical_start = (reg_val_h << 8) | reg_val; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_H_OUTSIZE_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_H_OUTSIZE_L, ®_val); - if (ret) - return ret; - buf->output_width = (reg_val_h << 8) | reg_val; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_V_OUTSIZE_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_V_OUTSIZE_L, ®_val); - if (ret) - return ret; - buf->output_height = (reg_val_h << 8) | reg_val; - - buf->crop_horizontal_end = buf->crop_horizontal_start + - buf->output_width - 1; - buf->crop_vertical_end = buf->crop_vertical_start + - buf->output_height - 1; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_HB_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_HB_L, ®_val); - if (ret) - return ret; - - dummy = (reg_val_h << 8) | reg_val; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_SH_DELAY_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_SH_DELAY_L, ®_val); - -#if 0 - buf->line_length_pck = buf->output_width + 16 + dummy + - (((u16)reg_val_h << 8) | (u16)reg_val) + 4; -#endif - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_VB_H, ®_val_h); - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_VB_L, ®_val); - if (ret) - return ret; - -#if 0 - buf->frame_length_lines = buf->output_height + 32 + - (((u16)reg_val_h << 8) | (u16)reg_val); -#endif - buf->binning_factor_x = res->bin_factor_x ? - res->bin_factor_x : 1; - buf->binning_factor_y = res->bin_factor_y ? - res->bin_factor_y : 1; - return 0; -} - -static long __gc2235_set_exposure(struct v4l2_subdev *sd, int coarse_itg, - int gain, int digitgain) - -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 coarse_integration = (u16)coarse_itg; - int ret = 0; - u16 expo_coarse_h, expo_coarse_l, gain_val = 0xF0, gain_val2 = 0xF0; - expo_coarse_h = coarse_integration >> 8; - expo_coarse_l = coarse_integration & 0xff; - - ret = gc2235_write_reg(client, GC2235_8BIT, - GC2235_EXPOSURE_H, expo_coarse_h); - ret = gc2235_write_reg(client, GC2235_8BIT, - GC2235_EXPOSURE_L, expo_coarse_l); - - if (gain <= 0x58) { - gain_val = 0x40; - gain_val2 = 0x58; - } else if (gain < 256) { - gain_val = 0x40; - gain_val2 = gain; - } else { - gain_val2 = 64 * gain / 256; - gain_val = 0xff; - } - - ret = gc2235_write_reg(client, GC2235_8BIT, - GC2235_GLOBAL_GAIN, (u8)gain_val); - ret = gc2235_write_reg(client, GC2235_8BIT, - GC2235_PRE_GAIN, (u8)gain_val2); - - return ret; -} - - -static int gc2235_set_exposure(struct v4l2_subdev *sd, int exposure, - int gain, int digitgain) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - int ret; - - mutex_lock(&dev->input_lock); - ret = __gc2235_set_exposure(sd, exposure, gain, digitgain); - mutex_unlock(&dev->input_lock); - - return ret; -} - -static long gc2235_s_exposure(struct v4l2_subdev *sd, - struct atomisp_exposure *exposure) -{ - int exp = exposure->integration_time[0]; - int gain = exposure->gain[0]; - int digitgain = exposure->gain[1]; - - /* we should not accept the invalid value below. */ - if (gain == 0) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - v4l2_err(client, "%s: invalid value\n", __func__); - return -EINVAL; - } - - return gc2235_set_exposure(sd, exp, gain, digitgain); -} -static long gc2235_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - switch (cmd) { - case ATOMISP_IOC_S_EXPOSURE: - return gc2235_s_exposure(sd, arg); - default: - return -EINVAL; - } - return 0; -} -/* This returns the exposure time being used. This should only be used - * for filling in EXIF data, not for actual image processing. - */ -static int gc2235_q_exposure(struct v4l2_subdev *sd, s32 *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 reg_v, reg_v2; - int ret; - - /* get exposure */ - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_EXPOSURE_L, - ®_v); - if (ret) - goto err; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_EXPOSURE_H, - ®_v2); - if (ret) - goto err; - - reg_v += reg_v2 << 8; - - *value = reg_v; -err: - return ret; -} - -static int gc2235_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct gc2235_device *dev = - container_of(ctrl->handler, struct gc2235_device, ctrl_handler); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE_ABSOLUTE: - ret = gc2235_q_exposure(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = gc2235_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = gc2235_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = gc2235_g_fnumber_range(&dev->sd, &ctrl->val); - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .g_volatile_ctrl = gc2235_g_volatile_ctrl -}; - -static struct v4l2_ctrl_config gc2235_controls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .min = 0x0, - .max = 0xffff, - .step = 0x01, - .def = 0x00, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = GC2235_FOCAL_LENGTH_DEFAULT, - .max = GC2235_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = GC2235_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = GC2235_F_NUMBER_DEFAULT, - .max = GC2235_F_NUMBER_DEFAULT, - .step = 0x01, - .def = GC2235_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = GC2235_F_NUMBER_RANGE, - .max = GC2235_F_NUMBER_RANGE, - .step = 0x01, - .def = GC2235_F_NUMBER_RANGE, - .flags = 0, - }, -}; - -static int __gc2235_init(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - /* restore settings */ - gc2235_res = gc2235_res_preview; - N_RES = N_RES_PREVIEW; - - return gc2235_write_reg_array(client, gc2235_init_settings); -} - -static int is_init; - -static int power_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret = -1; - struct gc2235_device *dev = to_gc2235_sensor(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->power_ctrl) - return dev->platform_data->power_ctrl(sd, flag); - - if (flag) { - ret = dev->platform_data->v1p8_ctrl(sd, 1); - usleep_range(60, 90); - if (ret == 0) - ret |= dev->platform_data->v2p8_ctrl(sd, 1); - } else { - ret = dev->platform_data->v1p8_ctrl(sd, 0); - ret |= dev->platform_data->v2p8_ctrl(sd, 0); - } - return ret; -} - -static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - int ret = -1; - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->gpio_ctrl) - return dev->platform_data->gpio_ctrl(sd, flag); - - ret |= dev->platform_data->gpio1_ctrl(sd, !flag); - usleep_range(60, 90); - return dev->platform_data->gpio0_ctrl(sd, flag); -} - -static int power_up(struct v4l2_subdev *sd) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - /* power control */ - ret = power_ctrl(sd, 1); - if (ret) - goto fail_power; - - /* according to DS, at least 5ms is needed between DOVDD and PWDN */ - usleep_range(5000, 6000); - - ret = dev->platform_data->flisclk_ctrl(sd, 1); - if (ret) - goto fail_clk; - usleep_range(5000, 6000); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 1); - if (ret) { - ret = gpio_ctrl(sd, 1); - if (ret) - goto fail_power; - } - - msleep(5); - return 0; - -fail_clk: - gpio_ctrl(sd, 0); -fail_power: - power_ctrl(sd, 0); - dev_err(&client->dev, "sensor power-up failed\n"); - - return ret; -} - -static int power_down(struct v4l2_subdev *sd) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - /* gpio ctrl */ - ret = gpio_ctrl(sd, 0); - if (ret) { - ret = gpio_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "gpio failed 2\n"); - } - - ret = dev->platform_data->flisclk_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "flisclk failed\n"); - - /* power control */ - ret = power_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "vprog failed.\n"); - - return ret; -} - -static int gc2235_s_power(struct v4l2_subdev *sd, int on) -{ - int ret; - - if (on == 0) - ret = power_down(sd); - else { - ret = power_up(sd); - if (!ret) - ret = __gc2235_init(sd); - is_init = 1; - } - return ret; -} - -/* - * distance - calculate the distance - * @res: resolution - * @w: width - * @h: height - * - * Get the gap between resolution and w/h. - * res->width/height smaller than w/h wouldn't be considered. - * Returns the value of gap or -1 if fail. - */ -#define LARGEST_ALLOWED_RATIO_MISMATCH 800 -static int distance(struct gc2235_resolution *res, u32 w, u32 h) -{ - unsigned int w_ratio = (res->width << 13) / w; - unsigned int h_ratio; - int match; - - if (h == 0) - return -1; - h_ratio = (res->height << 13) / h; - if (h_ratio == 0) - return -1; - match = abs(((w_ratio << 13) / h_ratio) - 8192); - - if ((w_ratio < 8192) || (h_ratio < 8192) || - (match > LARGEST_ALLOWED_RATIO_MISMATCH)) - return -1; - - return w_ratio + h_ratio; -} - -/* Return the nearest higher resolution index */ -static int nearest_resolution_index(int w, int h) -{ - int i; - int idx = -1; - int dist; - int min_dist = INT_MAX; - struct gc2235_resolution *tmp_res = NULL; - - for (i = 0; i < N_RES; i++) { - tmp_res = &gc2235_res[i]; - dist = distance(tmp_res, w, h); - if (dist == -1) - continue; - if (dist < min_dist) { - min_dist = dist; - idx = i; - } - } - - return idx; -} - -static int get_resolution_index(int w, int h) -{ - int i; - - for (i = 0; i < N_RES; i++) { - if (w != gc2235_res[i].width) - continue; - if (h != gc2235_res[i].height) - continue; - - return i; - } - - return -1; -} - -static int startup(struct v4l2_subdev *sd) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - if (is_init == 0) { - /* force gc2235 to do a reset in res change, otherwise it - * can not output normal after switching res. and it is not - * necessary for first time run up after power on, for the sack - * of performance - */ - power_down(sd); - power_up(sd); - gc2235_write_reg_array(client, gc2235_init_settings); - } - - ret = gc2235_write_reg_array(client, gc2235_res[dev->fmt_idx].regs); - if (ret) { - dev_err(&client->dev, "gc2235 write register err.\n"); - return ret; - } - is_init = 0; - - return ret; -} - -static int gc2235_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - - struct v4l2_mbus_framefmt *fmt = &format->format; - struct gc2235_device *dev = to_gc2235_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_mipi_info *gc2235_info = NULL; - int ret = 0; - int idx; - - gc2235_info = v4l2_get_subdev_hostdata(sd); - if (!gc2235_info) - return -EINVAL; - if (format->pad) - return -EINVAL; - if (!fmt) - return -EINVAL; - mutex_lock(&dev->input_lock); - idx = nearest_resolution_index(fmt->width, fmt->height); - if (idx == -1) { - /* return the largest resolution */ - fmt->width = gc2235_res[N_RES - 1].width; - fmt->height = gc2235_res[N_RES - 1].height; - } else { - fmt->width = gc2235_res[idx].width; - fmt->height = gc2235_res[idx].height; - } - fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; - mutex_unlock(&dev->input_lock); - return 0; - } - - dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); - if (dev->fmt_idx == -1) { - dev_err(&client->dev, "get resolution fail\n"); - mutex_unlock(&dev->input_lock); - return -EINVAL; - } - - ret = startup(sd); - if (ret) { - dev_err(&client->dev, "gc2235 startup err\n"); - goto err; - } - - ret = gc2235_get_intg_factor(client, gc2235_info, - &gc2235_res[dev->fmt_idx]); - if (ret) - dev_err(&client->dev, "failed to get integration_factor\n"); - -err: - mutex_unlock(&dev->input_lock); - return ret; -} - -static int gc2235_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct gc2235_device *dev = to_gc2235_sensor(sd); - - if (format->pad) - return -EINVAL; - - if (!fmt) - return -EINVAL; - - fmt->width = gc2235_res[dev->fmt_idx].width; - fmt->height = gc2235_res[dev->fmt_idx].height; - fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; - - return 0; -} - -static int gc2235_detect(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - u16 high, low; - int ret; - u16 id; - - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) - return -ENODEV; - - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_SENSOR_ID_H, &high); - if (ret) { - dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); - return -ENODEV; - } - ret = gc2235_read_reg(client, GC2235_8BIT, - GC2235_SENSOR_ID_L, &low); - id = ((high << 8) | low); - - if (id != GC2235_ID) { - dev_err(&client->dev, "sensor ID error, 0x%x\n", id); - return -ENODEV; - } - - dev_info(&client->dev, "detect gc2235 success\n"); - return 0; -} - -static int gc2235_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - mutex_lock(&dev->input_lock); - - if (enable) - ret = gc2235_write_reg_array(client, gc2235_stream_on); - else - ret = gc2235_write_reg_array(client, gc2235_stream_off); - - mutex_unlock(&dev->input_lock); - return ret; -} - - -static int gc2235_s_config(struct v4l2_subdev *sd, - int irq, void *platform_data) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - if (!platform_data) - return -ENODEV; - - dev->platform_data = - (struct camera_sensor_platform_data *)platform_data; - - mutex_lock(&dev->input_lock); - if (dev->platform_data->platform_init) { - ret = dev->platform_data->platform_init(client); - if (ret) { - dev_err(&client->dev, "platform init err\n"); - goto platform_init_failed; - } - } - /* power off the module, then power on it in future - * as first power on by board may not fulfill the - * power on sequqence needed by the module - */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "gc2235 power-off err.\n"); - goto fail_power_off; - } - - ret = power_up(sd); - if (ret) { - dev_err(&client->dev, "gc2235 power-up err.\n"); - goto fail_power_on; - } - - ret = dev->platform_data->csi_cfg(sd, 1); - if (ret) - goto fail_csi_cfg; - - /* config & detect sensor */ - ret = gc2235_detect(client); - if (ret) { - dev_err(&client->dev, "gc2235_detect err s_config.\n"); - goto fail_csi_cfg; - } - - /* turn off sensor, after probed */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "gc2235 power-off err.\n"); - goto fail_csi_cfg; - } - mutex_unlock(&dev->input_lock); - - return 0; - -fail_csi_cfg: - dev->platform_data->csi_cfg(sd, 0); -fail_power_on: - power_down(sd); - dev_err(&client->dev, "sensor power-gating failed\n"); -fail_power_off: - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); -platform_init_failed: - mutex_unlock(&dev->input_lock); - return ret; -} - -static int gc2235_g_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!param) - return -EINVAL; - - if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&client->dev, "unsupported buffer type.\n"); - return -EINVAL; - } - - memset(param, 0, sizeof(*param)); - param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { - param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - param->parm.capture.timeperframe.numerator = 1; - param->parm.capture.capturemode = dev->run_mode; - param->parm.capture.timeperframe.denominator = - gc2235_res[dev->fmt_idx].fps; - } - return 0; -} - -static int gc2235_s_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - dev->run_mode = param->parm.capture.capturemode; - - mutex_lock(&dev->input_lock); - switch (dev->run_mode) { - case CI_MODE_VIDEO: - gc2235_res = gc2235_res_video; - N_RES = N_RES_VIDEO; - break; - case CI_MODE_STILL_CAPTURE: - gc2235_res = gc2235_res_still; - N_RES = N_RES_STILL; - break; - default: - gc2235_res = gc2235_res_preview; - N_RES = N_RES_PREVIEW; - } - mutex_unlock(&dev->input_lock); - return 0; -} - -static int gc2235_g_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - - interval->interval.numerator = 1; - interval->interval.denominator = gc2235_res[dev->fmt_idx].fps; - - return 0; -} - -static int gc2235_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->index >= MAX_FMTS) - return -EINVAL; - - code->code = MEDIA_BUS_FMT_SBGGR10_1X10; - return 0; -} - -static int gc2235_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - int index = fse->index; - - if (index >= N_RES) - return -EINVAL; - - fse->min_width = gc2235_res[index].width; - fse->min_height = gc2235_res[index].height; - fse->max_width = gc2235_res[index].width; - fse->max_height = gc2235_res[index].height; - - return 0; - -} - -static int gc2235_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) -{ - struct gc2235_device *dev = to_gc2235_sensor(sd); - - mutex_lock(&dev->input_lock); - *frames = gc2235_res[dev->fmt_idx].skip_frames; - mutex_unlock(&dev->input_lock); - - return 0; -} - -static const struct v4l2_subdev_sensor_ops gc2235_sensor_ops = { - .g_skip_frames = gc2235_g_skip_frames, -}; - -static const struct v4l2_subdev_video_ops gc2235_video_ops = { - .s_stream = gc2235_s_stream, - .g_parm = gc2235_g_parm, - .s_parm = gc2235_s_parm, - .g_frame_interval = gc2235_g_frame_interval, -}; - -static const struct v4l2_subdev_core_ops gc2235_core_ops = { - .s_power = gc2235_s_power, - .ioctl = gc2235_ioctl, -}; - -static const struct v4l2_subdev_pad_ops gc2235_pad_ops = { - .enum_mbus_code = gc2235_enum_mbus_code, - .enum_frame_size = gc2235_enum_frame_size, - .get_fmt = gc2235_get_fmt, - .set_fmt = gc2235_set_fmt, -}; - -static const struct v4l2_subdev_ops gc2235_ops = { - .core = &gc2235_core_ops, - .video = &gc2235_video_ops, - .pad = &gc2235_pad_ops, - .sensor = &gc2235_sensor_ops, -}; - -static int gc2235_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct gc2235_device *dev = to_gc2235_sensor(sd); - dev_dbg(&client->dev, "gc2235_remove...\n"); - - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); - - dev->platform_data->csi_cfg(sd, 0); - - v4l2_device_unregister_subdev(sd); - media_entity_cleanup(&dev->sd.entity); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - kfree(dev); - - return 0; -} - -static int gc2235_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct gc2235_device *dev; - void *gcpdev; - int ret; - unsigned int i; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "out of memory\n"); - return -ENOMEM; - } - - mutex_init(&dev->input_lock); - - dev->fmt_idx = 0; - v4l2_i2c_subdev_init(&(dev->sd), client, &gc2235_ops); - - gcpdev = client->dev.platform_data; - if (ACPI_COMPANION(&client->dev)) - gcpdev = gmin_camera_platform_data(&dev->sd, - ATOMISP_INPUT_FORMAT_RAW_10, - atomisp_bayer_order_grbg); - - ret = gc2235_s_config(&dev->sd, client->irq, gcpdev); - if (ret) - goto out_free; - - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - ret = - v4l2_ctrl_handler_init(&dev->ctrl_handler, - ARRAY_SIZE(gc2235_controls)); - if (ret) { - gc2235_remove(client); - return ret; - } - - for (i = 0; i < ARRAY_SIZE(gc2235_controls); i++) - v4l2_ctrl_new_custom(&dev->ctrl_handler, &gc2235_controls[i], - NULL); - - if (dev->ctrl_handler.error) { - gc2235_remove(client); - return dev->ctrl_handler.error; - } - - /* Use same lock for controls as for everything else. */ - dev->ctrl_handler.lock = &dev->input_lock; - dev->sd.ctrl_handler = &dev->ctrl_handler; - - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); - if (ret) - gc2235_remove(client); - - if (ACPI_HANDLE(&client->dev)) - ret = atomisp_register_i2c_module(&dev->sd, gcpdev, RAW_CAMERA); - - return ret; -out_free: - v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); - - return ret; -} - -static const struct acpi_device_id gc2235_acpi_match[] = { - { "INT33F8" }, - {}, -}; - -MODULE_DEVICE_TABLE(acpi, gc2235_acpi_match); -MODULE_DEVICE_TABLE(i2c, gc2235_id); -static struct i2c_driver gc2235_driver = { - .driver = { - .name = GC2235_NAME, - .acpi_match_table = ACPI_PTR(gc2235_acpi_match), - }, - .probe = gc2235_probe, - .remove = gc2235_remove, - .id_table = gc2235_id, -}; - -static int init_gc2235(void) -{ - return i2c_add_driver(&gc2235_driver); -} - -static void exit_gc2235(void) -{ - - i2c_del_driver(&gc2235_driver); -} - -module_init(init_gc2235); -module_exit(exit_gc2235); - -MODULE_AUTHOR("Shuguang Gong "); -MODULE_DESCRIPTION("A low-level driver for GC2235 sensors"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/imx/Kconfig b/drivers/staging/media/atomisp/i2c/imx/Kconfig index a39eeb3b6ad4..c4356c1a8aca 100644 --- a/drivers/staging/media/atomisp/i2c/imx/Kconfig +++ b/drivers/staging/media/atomisp/i2c/imx/Kconfig @@ -1,6 +1,6 @@ -config VIDEO_IMX +config VIDEO_ATOMISP_IMX tristate "sony imx sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_MSRLIST_HELPER && m + depends on I2C && VIDEO_V4L2 && VIDEO_ATOMISP_MSRLIST_HELPER && m ---help--- This is a Video4Linux2 sensor-level driver for the Sony IMX RAW sensor. diff --git a/drivers/staging/media/atomisp/i2c/imx/Makefile b/drivers/staging/media/atomisp/i2c/imx/Makefile index b6578f09546e..f3e2891cdfec 100644 --- a/drivers/staging/media/atomisp/i2c/imx/Makefile +++ b/drivers/staging/media/atomisp/i2c/imx/Makefile @@ -1,9 +1,9 @@ -obj-$(CONFIG_VIDEO_IMX) += imx1x5.o +obj-$(CONFIG_VIDEO_ATOMISP_IMX) += atomisp-imx1x5.o -imx1x5-objs := imx.o drv201.o ad5816g.o dw9714.o dw9719.o dw9718.o vcm.o otp.o otp_imx.o otp_brcc064_e2prom.o otp_e2prom.o +atomisp-imx1x5-objs := imx.o drv201.o ad5816g.o dw9714.o dw9719.o dw9718.o vcm.o otp.o otp_imx.o otp_brcc064_e2prom.o otp_e2prom.o -ov8858_driver-objs := ../ov8858.o dw9718.o vcm.o -obj-$(CONFIG_VIDEO_OV8858) += ov8858_driver.o +atomisp-ov8858-objs := ../ov8858.o dw9718.o vcm.o +obj-$(CONFIG_VIDEO_ATOMISP_OV8858) += atomisp-ov8858.o # HACK! While this driver is in bad shape, don't enable several warnings # that would be otherwise enabled with W=1 diff --git a/drivers/staging/media/atomisp/i2c/libmsrlisthelper.c b/drivers/staging/media/atomisp/i2c/libmsrlisthelper.c deleted file mode 100644 index decb65cfd7c9..000000000000 --- a/drivers/staging/media/atomisp/i2c/libmsrlisthelper.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ -#include -#include -#include -#include -#include "../include/linux/libmsrlisthelper.h" -#include -#include - -/* Tagged binary data container structure definitions. */ -struct tbd_header { - uint32_t tag; /*!< Tag identifier, also checks endianness */ - uint32_t size; /*!< Container size including this header */ - uint32_t version; /*!< Version, format 0xYYMMDDVV */ - uint32_t revision; /*!< Revision, format 0xYYMMDDVV */ - uint32_t config_bits; /*!< Configuration flag bits set */ - uint32_t checksum; /*!< Global checksum, header included */ -} __packed; - -struct tbd_record_header { - uint32_t size; /*!< Size of record including header */ - uint8_t format_id; /*!< tbd_format_t enumeration values used */ - uint8_t packing_key; /*!< Packing method; 0 = no packing */ - uint16_t class_id; /*!< tbd_class_t enumeration values used */ -} __packed; - -struct tbd_data_record_header { - uint16_t next_offset; - uint16_t flags; - uint16_t data_offset; - uint16_t data_size; -} __packed; - -#define TBD_CLASS_DRV_ID 2 - -static int set_msr_configuration(struct i2c_client *client, uint8_t *bufptr, - unsigned int size) -{ - /* The configuration data contains any number of sequences where - * the first byte (that is, uint8_t) that marks the number of bytes - * in the sequence to follow, is indeed followed by the indicated - * number of bytes of actual data to be written to sensor. - * By convention, the first two bytes of actual data should be - * understood as an address in the sensor address space (hibyte - * followed by lobyte) where the remaining data in the sequence - * will be written. */ - - uint8_t *ptr = bufptr; - while (ptr < bufptr + size) { - struct i2c_msg msg = { - .addr = client->addr, - .flags = 0, - }; - int ret; - - /* How many bytes */ - msg.len = *ptr++; - /* Where the bytes are located */ - msg.buf = ptr; - ptr += msg.len; - - if (ptr > bufptr + size) - /* Accessing data beyond bounds is not tolerated */ - return -EINVAL; - - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret < 0) { - dev_err(&client->dev, "i2c write error: %d", ret); - return ret; - } - } - return 0; -} - -static int parse_and_apply(struct i2c_client *client, uint8_t *buffer, - unsigned int size) -{ - uint8_t *endptr8 = buffer + size; - struct tbd_data_record_header *header = - (struct tbd_data_record_header *)buffer; - - /* There may be any number of datasets present */ - unsigned int dataset = 0; - - do { - /* In below, four variables are read from buffer */ - if ((uint8_t *)header + sizeof(*header) > endptr8) - return -EINVAL; - - /* All data should be located within given buffer */ - if ((uint8_t *)header + header->data_offset + - header->data_size > endptr8) - return -EINVAL; - - /* We have a new valid dataset */ - dataset++; - /* See whether there is MSR data */ - /* If yes, update the reg info */ - if (header->data_size && (header->flags & 1)) { - int ret; - - dev_info(&client->dev, - "New MSR data for sensor driver (dataset %02d) size:%d\n", - dataset, header->data_size); - ret = set_msr_configuration(client, - buffer + header->data_offset, - header->data_size); - if (ret) - return ret; - } - header = (struct tbd_data_record_header *)(buffer + - header->next_offset); - } while (header->next_offset); - - return 0; -} - -int apply_msr_data(struct i2c_client *client, const struct firmware *fw) -{ - struct tbd_header *header; - struct tbd_record_header *record; - - if (!fw) { - dev_warn(&client->dev, "Drv data is not loaded.\n"); - return -EINVAL; - } - - if (sizeof(*header) > fw->size) - return -EINVAL; - - header = (struct tbd_header *)fw->data; - /* Check that we have drvb block. */ - if (memcmp(&header->tag, "DRVB", 4)) - return -EINVAL; - - /* Check the size */ - if (header->size != fw->size) - return -EINVAL; - - if (sizeof(*header) + sizeof(*record) > fw->size) - return -EINVAL; - - record = (struct tbd_record_header *)(header + 1); - /* Check that class id mathes tbd's drv id. */ - if (record->class_id != TBD_CLASS_DRV_ID) - return -EINVAL; - - /* Size 0 shall not be treated as an error */ - if (!record->size) - return 0; - - return parse_and_apply(client, (uint8_t *)(record + 1), record->size); -} -EXPORT_SYMBOL_GPL(apply_msr_data); - -int load_msr_list(struct i2c_client *client, char *name, - const struct firmware **fw) -{ - int ret = request_firmware(fw, name, &client->dev); - if (ret) { - dev_err(&client->dev, - "Error %d while requesting firmware %s\n", - ret, name); - return ret; - } - dev_info(&client->dev, "Received %lu bytes drv data\n", - (unsigned long)(*fw)->size); - - return 0; -} -EXPORT_SYMBOL_GPL(load_msr_list); - -void release_msr_list(struct i2c_client *client, const struct firmware *fw) -{ - release_firmware(fw); -} -EXPORT_SYMBOL_GPL(release_msr_list); - -static int init_msrlisthelper(void) -{ - return 0; -} - -static void exit_msrlisthelper(void) -{ -} - -module_init(init_msrlisthelper); -module_exit(exit_msrlisthelper); - -MODULE_AUTHOR("Jukka Kaartinen "); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/lm3554.c b/drivers/staging/media/atomisp/i2c/lm3554.c deleted file mode 100644 index 679176f7c542..000000000000 --- a/drivers/staging/media/atomisp/i2c/lm3554.c +++ /dev/null @@ -1,1009 +0,0 @@ -/* - * LED flash driver for LM3554 - * - * Copyright (c) 2010-2012 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ -#include -#include -#include -#include -#include -#include - -#include "../include/media/lm3554.h" -#include -#include -#include -#include -#include "../include/linux/atomisp_gmin_platform.h" -#include "../include/linux/atomisp.h" - -/* Registers */ - -#define LM3554_TORCH_BRIGHTNESS_REG 0xA0 -#define LM3554_TORCH_MODE_SHIFT 0 -#define LM3554_TORCH_CURRENT_SHIFT 3 -#define LM3554_INDICATOR_CURRENT_SHIFT 6 - -#define LM3554_FLASH_BRIGHTNESS_REG 0xB0 -#define LM3554_FLASH_MODE_SHIFT 0 -#define LM3554_FLASH_CURRENT_SHIFT 3 -#define LM3554_STROBE_SENSITIVITY_SHIFT 7 - -#define LM3554_FLASH_DURATION_REG 0xC0 -#define LM3554_FLASH_TIMEOUT_SHIFT 0 -#define LM3554_CURRENT_LIMIT_SHIFT 5 - -#define LM3554_FLAGS_REG 0xD0 -#define LM3554_FLAG_TIMEOUT (1 << 0) -#define LM3554_FLAG_THERMAL_SHUTDOWN (1 << 1) -#define LM3554_FLAG_LED_FAULT (1 << 2) -#define LM3554_FLAG_TX1_INTERRUPT (1 << 3) -#define LM3554_FLAG_TX2_INTERRUPT (1 << 4) -#define LM3554_FLAG_LED_THERMAL_FAULT (1 << 5) -#define LM3554_FLAG_UNUSED (1 << 6) -#define LM3554_FLAG_INPUT_VOLTAGE_LOW (1 << 7) - -#define LM3554_CONFIG_REG_1 0xE0 -#define LM3554_ENVM_TX2_SHIFT 5 -#define LM3554_TX2_POLARITY_SHIFT 6 - -struct lm3554 { - struct v4l2_subdev sd; - - struct mutex power_lock; - struct v4l2_ctrl_handler ctrl_handler; - int power_count; - - unsigned int mode; - int timeout; - u8 torch_current; - u8 indicator_current; - u8 flash_current; - - struct timer_list flash_off_delay; - struct lm3554_platform_data *pdata; -}; - -#define to_lm3554(p_sd) container_of(p_sd, struct lm3554, sd) - -/* Return negative errno else zero on success */ -static int lm3554_write(struct lm3554 *flash, u8 addr, u8 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(&flash->sd); - int ret; - - ret = i2c_smbus_write_byte_data(client, addr, val); - - dev_dbg(&client->dev, "Write Addr:%02X Val:%02X %s\n", addr, val, - ret < 0 ? "fail" : "ok"); - - return ret; -} - -/* Return negative errno else a data byte received from the device. */ -static int lm3554_read(struct lm3554 *flash, u8 addr) -{ - struct i2c_client *client = v4l2_get_subdevdata(&flash->sd); - int ret; - - ret = i2c_smbus_read_byte_data(client, addr); - - dev_dbg(&client->dev, "Read Addr:%02X Val:%02X %s\n", addr, ret, - ret < 0 ? "fail" : "ok"); - - return ret; -} - -/* ----------------------------------------------------------------------------- - * Hardware configuration - */ - -static int lm3554_set_mode(struct lm3554 *flash, unsigned int mode) -{ - u8 val; - int ret; - - val = (mode << LM3554_FLASH_MODE_SHIFT) | - (flash->flash_current << LM3554_FLASH_CURRENT_SHIFT); - - ret = lm3554_write(flash, LM3554_FLASH_BRIGHTNESS_REG, val); - if (ret == 0) - flash->mode = mode; - return ret; -} - -static int lm3554_set_torch(struct lm3554 *flash) -{ - u8 val; - - val = (flash->mode << LM3554_TORCH_MODE_SHIFT) | - (flash->torch_current << LM3554_TORCH_CURRENT_SHIFT) | - (flash->indicator_current << LM3554_INDICATOR_CURRENT_SHIFT); - - return lm3554_write(flash, LM3554_TORCH_BRIGHTNESS_REG, val); -} - -static int lm3554_set_flash(struct lm3554 *flash) -{ - u8 val; - - val = (flash->mode << LM3554_FLASH_MODE_SHIFT) | - (flash->flash_current << LM3554_FLASH_CURRENT_SHIFT); - - return lm3554_write(flash, LM3554_FLASH_BRIGHTNESS_REG, val); -} - -static int lm3554_set_duration(struct lm3554 *flash) -{ - u8 val; - - val = (flash->timeout << LM3554_FLASH_TIMEOUT_SHIFT) | - (flash->pdata->current_limit << LM3554_CURRENT_LIMIT_SHIFT); - - return lm3554_write(flash, LM3554_FLASH_DURATION_REG, val); -} - -static int lm3554_set_config1(struct lm3554 *flash) -{ - u8 val; - - val = (flash->pdata->envm_tx2 << LM3554_ENVM_TX2_SHIFT) | - (flash->pdata->tx2_polarity << LM3554_TX2_POLARITY_SHIFT); - return lm3554_write(flash, LM3554_CONFIG_REG_1, val); -} - -/* ----------------------------------------------------------------------------- - * Hardware trigger - */ -static void lm3554_flash_off_delay(long unsigned int arg) -{ - struct v4l2_subdev *sd = i2c_get_clientdata((struct i2c_client *)arg); - struct lm3554 *flash = to_lm3554(sd); - struct lm3554_platform_data *pdata = flash->pdata; - - gpio_set_value(pdata->gpio_strobe, 0); -} - -static int lm3554_hw_strobe(struct i2c_client *client, bool strobe) -{ - int ret, timer_pending; - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct lm3554 *flash = to_lm3554(sd); - struct lm3554_platform_data *pdata = flash->pdata; - - /* - * An abnormal high flash current is observed when strobe off the - * flash. Workaround here is firstly set flash current to lower level, - * wait a short moment, and then strobe off the flash. - */ - - timer_pending = del_timer_sync(&flash->flash_off_delay); - - /* Flash off */ - if (!strobe) { - /* set current to 70mA and wait a while */ - ret = lm3554_write(flash, LM3554_FLASH_BRIGHTNESS_REG, 0); - if (ret < 0) - goto err; - mod_timer(&flash->flash_off_delay, - jiffies + msecs_to_jiffies(LM3554_TIMER_DELAY)); - return 0; - } - - /* Flash on */ - - /* - * If timer is killed before run, flash is not strobe off, - * so must strobe off here - */ - if (timer_pending) - gpio_set_value(pdata->gpio_strobe, 0); - - /* Restore flash current settings */ - ret = lm3554_set_flash(flash); - if (ret < 0) - goto err; - - /* Strobe on Flash */ - gpio_set_value(pdata->gpio_strobe, 1); - - return 0; -err: - dev_err(&client->dev, "failed to %s flash strobe (%d)\n", - strobe ? "on" : "off", ret); - return ret; -} - -/* ----------------------------------------------------------------------------- - * V4L2 controls - */ - -static int lm3554_read_status(struct lm3554 *flash) -{ - int ret; - struct i2c_client *client = v4l2_get_subdevdata(&flash->sd); - - /* NOTE: reading register clear fault status */ - ret = lm3554_read(flash, LM3554_FLAGS_REG); - if (ret < 0) - return ret; - - /* - * Accordingly to datasheet we read back '1' in bit 6. - * Clear it first. - */ - ret &= ~LM3554_FLAG_UNUSED; - - /* - * Do not take TX1/TX2 signal as an error - * because MSIC will not turn off flash, but turn to - * torch mode according to gsm modem signal by hardware. - */ - ret &= ~(LM3554_FLAG_TX1_INTERRUPT | LM3554_FLAG_TX2_INTERRUPT); - - if (ret > 0) - dev_dbg(&client->dev, "LM3554 flag status: %02x\n", ret); - - return ret; -} - -static int lm3554_s_flash_timeout(struct v4l2_subdev *sd, u32 val) -{ - struct lm3554 *flash = to_lm3554(sd); - - val = clamp(val, LM3554_MIN_TIMEOUT, LM3554_MAX_TIMEOUT); - val = val / LM3554_TIMEOUT_STEPSIZE - 1; - - flash->timeout = val; - - return lm3554_set_duration(flash); -} - -static int lm3554_g_flash_timeout(struct v4l2_subdev *sd, s32 *val) -{ - struct lm3554 *flash = to_lm3554(sd); - - *val = (u32)(flash->timeout + 1) * LM3554_TIMEOUT_STEPSIZE; - - return 0; -} - -static int lm3554_s_flash_intensity(struct v4l2_subdev *sd, u32 intensity) -{ - struct lm3554 *flash = to_lm3554(sd); - - intensity = LM3554_CLAMP_PERCENTAGE(intensity); - intensity = LM3554_PERCENT_TO_VALUE(intensity, LM3554_FLASH_STEP); - - flash->flash_current = intensity; - - return lm3554_set_flash(flash); -} - -static int lm3554_g_flash_intensity(struct v4l2_subdev *sd, s32 *val) -{ - struct lm3554 *flash = to_lm3554(sd); - - *val = LM3554_VALUE_TO_PERCENT((u32)flash->flash_current, - LM3554_FLASH_STEP); - - return 0; -} - -static int lm3554_s_torch_intensity(struct v4l2_subdev *sd, u32 intensity) -{ - struct lm3554 *flash = to_lm3554(sd); - - intensity = LM3554_CLAMP_PERCENTAGE(intensity); - intensity = LM3554_PERCENT_TO_VALUE(intensity, LM3554_TORCH_STEP); - - flash->torch_current = intensity; - - return lm3554_set_torch(flash); -} - -static int lm3554_g_torch_intensity(struct v4l2_subdev *sd, s32 *val) -{ - struct lm3554 *flash = to_lm3554(sd); - - *val = LM3554_VALUE_TO_PERCENT((u32)flash->torch_current, - LM3554_TORCH_STEP); - - return 0; -} - -static int lm3554_s_indicator_intensity(struct v4l2_subdev *sd, u32 intensity) -{ - struct lm3554 *flash = to_lm3554(sd); - - intensity = LM3554_CLAMP_PERCENTAGE(intensity); - intensity = LM3554_PERCENT_TO_VALUE(intensity, LM3554_INDICATOR_STEP); - - flash->indicator_current = intensity; - - return lm3554_set_torch(flash); -} - -static int lm3554_g_indicator_intensity(struct v4l2_subdev *sd, s32 *val) -{ - struct lm3554 *flash = to_lm3554(sd); - - *val = LM3554_VALUE_TO_PERCENT((u32)flash->indicator_current, - LM3554_INDICATOR_STEP); - - return 0; -} - -static int lm3554_s_flash_strobe(struct v4l2_subdev *sd, u32 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return lm3554_hw_strobe(client, val); -} - -static int lm3554_s_flash_mode(struct v4l2_subdev *sd, u32 new_mode) -{ - struct lm3554 *flash = to_lm3554(sd); - unsigned int mode; - - switch (new_mode) { - case ATOMISP_FLASH_MODE_OFF: - mode = LM3554_MODE_SHUTDOWN; - break; - case ATOMISP_FLASH_MODE_FLASH: - mode = LM3554_MODE_FLASH; - break; - case ATOMISP_FLASH_MODE_INDICATOR: - mode = LM3554_MODE_INDICATOR; - break; - case ATOMISP_FLASH_MODE_TORCH: - mode = LM3554_MODE_TORCH; - break; - default: - return -EINVAL; - } - - return lm3554_set_mode(flash, mode); -} - -static int lm3554_g_flash_mode(struct v4l2_subdev *sd, s32 *val) -{ - struct lm3554 *flash = to_lm3554(sd); - *val = flash->mode; - return 0; -} - -static int lm3554_g_flash_status(struct v4l2_subdev *sd, s32 *val) -{ - struct lm3554 *flash = to_lm3554(sd); - int value; - - value = lm3554_read_status(flash); - if (value < 0) - return value; - - if (value & LM3554_FLAG_TIMEOUT) - *val = ATOMISP_FLASH_STATUS_TIMEOUT; - else if (value > 0) - *val = ATOMISP_FLASH_STATUS_HW_ERROR; - else - *val = ATOMISP_FLASH_STATUS_OK; - - return 0; -} - -#ifndef CSS15 -static int lm3554_g_flash_status_register(struct v4l2_subdev *sd, s32 *val) -{ - struct lm3554 *flash = to_lm3554(sd); - int ret; - - ret = lm3554_read(flash, LM3554_FLAGS_REG); - - if (ret < 0) - return ret; - - *val = ret; - return 0; -} -#endif - -static int lm3554_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct lm3554 *dev = - container_of(ctrl->handler, struct lm3554, ctrl_handler); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_FLASH_TIMEOUT: - ret = lm3554_s_flash_timeout(&dev->sd, ctrl->val); - break; - case V4L2_CID_FLASH_INTENSITY: - ret = lm3554_s_flash_intensity(&dev->sd, ctrl->val); - break; - case V4L2_CID_FLASH_TORCH_INTENSITY: - ret = lm3554_s_torch_intensity(&dev->sd, ctrl->val); - break; - case V4L2_CID_FLASH_INDICATOR_INTENSITY: - ret = lm3554_s_indicator_intensity(&dev->sd, ctrl->val); - break; - case V4L2_CID_FLASH_STROBE: - ret = lm3554_s_flash_strobe(&dev->sd, ctrl->val); - break; - case V4L2_CID_FLASH_MODE: - ret = lm3554_s_flash_mode(&dev->sd, ctrl->val); - break; - default: - ret = -EINVAL; - } - return ret; -} - -static int lm3554_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct lm3554 *dev = - container_of(ctrl->handler, struct lm3554, ctrl_handler); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_FLASH_TIMEOUT: - ret = lm3554_g_flash_timeout(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FLASH_INTENSITY: - ret = lm3554_g_flash_intensity(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FLASH_TORCH_INTENSITY: - ret = lm3554_g_torch_intensity(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FLASH_INDICATOR_INTENSITY: - ret = lm3554_g_indicator_intensity(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FLASH_MODE: - ret = lm3554_g_flash_mode(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FLASH_STATUS: - ret = lm3554_g_flash_status(&dev->sd, &ctrl->val); - break; -#ifndef CSS15 - case V4L2_CID_FLASH_STATUS_REGISTER: - ret = lm3554_g_flash_status_register(&dev->sd, &ctrl->val); - break; -#endif - default: - ret = -EINVAL; - } - - return ret; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .s_ctrl = lm3554_s_ctrl, - .g_volatile_ctrl = lm3554_g_volatile_ctrl -}; - -static const struct v4l2_ctrl_config lm3554_controls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_FLASH_TIMEOUT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Flash Timeout", - .min = 0x0, - .max = LM3554_MAX_TIMEOUT, - .step = 0x01, - .def = LM3554_DEFAULT_TIMEOUT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FLASH_INTENSITY, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Flash Intensity", - .min = LM3554_MIN_PERCENT, - .max = LM3554_MAX_PERCENT, - .step = 0x01, - .def = LM3554_FLASH_DEFAULT_BRIGHTNESS, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FLASH_TORCH_INTENSITY, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Torch Intensity", - .min = LM3554_MIN_PERCENT, - .max = LM3554_MAX_PERCENT, - .step = 0x01, - .def = LM3554_TORCH_DEFAULT_BRIGHTNESS, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FLASH_INDICATOR_INTENSITY, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Indicator Intensity", - .min = LM3554_MIN_PERCENT, - .max = LM3554_MAX_PERCENT, - .step = 0x01, - .def = LM3554_INDICATOR_DEFAULT_BRIGHTNESS, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FLASH_STROBE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flash Strobe", - .min = 0, - .max = 1, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FLASH_MODE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Flash Mode", - .min = 0, - .max = 100, - .step = 1, - .def = ATOMISP_FLASH_MODE_OFF, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FLASH_STATUS, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flash Status", - .min = 0, - .max = 100, - .step = 1, - .def = ATOMISP_FLASH_STATUS_OK, - .flags = 0, - }, -#ifndef CSS15 - { - .ops = &ctrl_ops, - .id = V4L2_CID_FLASH_STATUS_REGISTER, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flash Status Register", - .min = 0, - .max = 100, - .step = 1, - .def = 0, - .flags = 0, - }, -#endif -}; - -/* ----------------------------------------------------------------------------- - * V4L2 subdev core operations - */ - -/* Put device into known state. */ -static int lm3554_setup(struct lm3554 *flash) -{ - struct i2c_client *client = v4l2_get_subdevdata(&flash->sd); - int ret; - - /* clear the flags register */ - ret = lm3554_read(flash, LM3554_FLAGS_REG); - if (ret < 0) - return ret; - - dev_dbg(&client->dev, "Fault info: %02x\n", ret); - - ret = lm3554_set_config1(flash); - if (ret < 0) - return ret; - - ret = lm3554_set_duration(flash); - if (ret < 0) - return ret; - - ret = lm3554_set_torch(flash); - if (ret < 0) - return ret; - - ret = lm3554_set_flash(flash); - if (ret < 0) - return ret; - - /* read status */ - ret = lm3554_read_status(flash); - if (ret < 0) - return ret; - - return ret ? -EIO : 0; -} - -static int __lm3554_s_power(struct lm3554 *flash, int power) -{ - struct lm3554_platform_data *pdata = flash->pdata; - int ret; - - /*initialize flash driver*/ - gpio_set_value(pdata->gpio_reset, power); - usleep_range(100, 100 + 1); - - if (power) { - /* Setup default values. This makes sure that the chip - * is in a known state. - */ - ret = lm3554_setup(flash); - if (ret < 0) { - __lm3554_s_power(flash, 0); - return ret; - } - } - - return 0; -} - -static int lm3554_s_power(struct v4l2_subdev *sd, int power) -{ - struct lm3554 *flash = to_lm3554(sd); - int ret = 0; - - mutex_lock(&flash->power_lock); - - if (flash->power_count == !power) { - ret = __lm3554_s_power(flash, !!power); - if (ret < 0) - goto done; - } - - flash->power_count += power ? 1 : -1; - WARN_ON(flash->power_count < 0); - -done: - mutex_unlock(&flash->power_lock); - return ret; -} - -static const struct v4l2_subdev_core_ops lm3554_core_ops = { - .s_power = lm3554_s_power, -}; - -static const struct v4l2_subdev_ops lm3554_ops = { - .core = &lm3554_core_ops, -}; - -static int lm3554_detect(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct i2c_adapter *adapter = client->adapter; - struct lm3554 *flash = to_lm3554(sd); - int ret; - - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_err(&client->dev, "lm3554_detect i2c error\n"); - return -ENODEV; - } - - /* Power up the flash driver and reset it */ - ret = lm3554_s_power(&flash->sd, 1); - if (ret < 0) { - dev_err(&client->dev, "Failed to power on lm3554 LED flash\n"); - } else { - dev_dbg(&client->dev, "Successfully detected lm3554 LED flash\n"); - lm3554_s_power(&flash->sd, 0); - } - - return ret; -} - -static int lm3554_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - return lm3554_s_power(sd, 1); -} - -static int lm3554_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) -{ - return lm3554_s_power(sd, 0); -} - -static const struct v4l2_subdev_internal_ops lm3554_internal_ops = { - .registered = lm3554_detect, - .open = lm3554_open, - .close = lm3554_close, -}; - -/* ----------------------------------------------------------------------------- - * I2C driver - */ -#ifdef CONFIG_PM - -static int lm3554_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); - struct lm3554 *flash = to_lm3554(subdev); - int rval; - - if (flash->power_count == 0) - return 0; - - rval = __lm3554_s_power(flash, 0); - - dev_dbg(&client->dev, "Suspend %s\n", rval < 0 ? "failed" : "ok"); - - return rval; -} - -static int lm3554_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct v4l2_subdev *subdev = i2c_get_clientdata(client); - struct lm3554 *flash = to_lm3554(subdev); - int rval; - - if (flash->power_count == 0) - return 0; - - rval = __lm3554_s_power(flash, 1); - - dev_dbg(&client->dev, "Resume %s\n", rval < 0 ? "fail" : "ok"); - - return rval; -} - -#else - -#define lm3554_suspend NULL -#define lm3554_resume NULL - -#endif /* CONFIG_PM */ - -static int lm3554_gpio_init(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct lm3554 *flash = to_lm3554(sd); - struct lm3554_platform_data *pdata = flash->pdata; - int ret; - - if (!gpio_is_valid(pdata->gpio_reset)) - return -EINVAL; - - ret = gpio_direction_output(pdata->gpio_reset, 0); - if (ret < 0) - goto err_gpio_reset; - dev_info(&client->dev, "flash led reset successfully\n"); - - if (!gpio_is_valid(pdata->gpio_strobe)) { - ret = -EINVAL; - goto err_gpio_dir_reset; - } - - ret = gpio_direction_output(pdata->gpio_strobe, 0); - if (ret < 0) - goto err_gpio_strobe; - - return 0; - -err_gpio_strobe: - gpio_free(pdata->gpio_strobe); -err_gpio_dir_reset: - gpio_direction_output(pdata->gpio_reset, 0); -err_gpio_reset: - gpio_free(pdata->gpio_reset); - - return ret; -} - -static int lm3554_gpio_uninit(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct lm3554 *flash = to_lm3554(sd); - struct lm3554_platform_data *pdata = flash->pdata; - int ret; - - ret = gpio_direction_output(pdata->gpio_strobe, 0); - if (ret < 0) - return ret; - - ret = gpio_direction_output(pdata->gpio_reset, 0); - if (ret < 0) - return ret; - - gpio_free(pdata->gpio_strobe); - gpio_free(pdata->gpio_reset); - return 0; -} - -static void *lm3554_platform_data_func(struct i2c_client *client) -{ - static struct lm3554_platform_data platform_data; - - if (ACPI_COMPANION(&client->dev)) { - platform_data.gpio_reset = - desc_to_gpio(gpiod_get_index(&(client->dev), - NULL, 2, GPIOD_OUT_LOW)); - platform_data.gpio_strobe = - desc_to_gpio(gpiod_get_index(&(client->dev), - NULL, 0, GPIOD_OUT_LOW)); - platform_data.gpio_torch = - desc_to_gpio(gpiod_get_index(&(client->dev), - NULL, 1, GPIOD_OUT_LOW)); - } else { - platform_data.gpio_reset = -1; - platform_data.gpio_strobe = -1; - platform_data.gpio_torch = -1; - } - - dev_info(&client->dev, "camera pdata: lm3554: reset: %d strobe %d torch %d\n", - platform_data.gpio_reset, platform_data.gpio_strobe, - platform_data.gpio_torch); - - /* Set to TX2 mode, then ENVM/TX2 pin is a power amplifier sync input: - * ENVM/TX pin asserted, flash forced into torch; - * ENVM/TX pin desserted, flash set back; - */ - platform_data.envm_tx2 = 1; - platform_data.tx2_polarity = 0; - - /* set peak current limit to be 1000mA */ - platform_data.current_limit = 0; - - return &platform_data; -} - -static int lm3554_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - int err = 0; - struct lm3554 *flash; - unsigned int i; - int ret; - - flash = kzalloc(sizeof(*flash), GFP_KERNEL); - if (!flash) { - dev_err(&client->dev, "out of memory\n"); - return -ENOMEM; - } - - flash->pdata = client->dev.platform_data; - - if (!flash->pdata || ACPI_COMPANION(&client->dev)) - flash->pdata = lm3554_platform_data_func(client); - - v4l2_i2c_subdev_init(&flash->sd, client, &lm3554_ops); - flash->sd.internal_ops = &lm3554_internal_ops; - flash->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - flash->mode = ATOMISP_FLASH_MODE_OFF; - flash->timeout = LM3554_MAX_TIMEOUT / LM3554_TIMEOUT_STEPSIZE - 1; - ret = - v4l2_ctrl_handler_init(&flash->ctrl_handler, - ARRAY_SIZE(lm3554_controls)); - if (ret) { - dev_err(&client->dev, "error initialize a ctrl_handler.\n"); - goto fail2; - } - - for (i = 0; i < ARRAY_SIZE(lm3554_controls); i++) - v4l2_ctrl_new_custom(&flash->ctrl_handler, &lm3554_controls[i], - NULL); - - if (flash->ctrl_handler.error) { - - dev_err(&client->dev, "ctrl_handler error.\n"); - goto fail2; - } - - flash->sd.ctrl_handler = &flash->ctrl_handler; - err = media_entity_pads_init(&flash->sd.entity, 0, NULL); - if (err) { - dev_err(&client->dev, "error initialize a media entity.\n"); - goto fail1; - } - - flash->sd.entity.function = MEDIA_ENT_F_FLASH; - - mutex_init(&flash->power_lock); - - setup_timer(&flash->flash_off_delay, lm3554_flash_off_delay, - (unsigned long)client); - - err = lm3554_gpio_init(client); - if (err) { - dev_err(&client->dev, "gpio request/direction_output fail"); - goto fail2; - } - if (ACPI_HANDLE(&client->dev)) - err = atomisp_register_i2c_module(&flash->sd, NULL, LED_FLASH); - return 0; -fail2: - media_entity_cleanup(&flash->sd.entity); - v4l2_ctrl_handler_free(&flash->ctrl_handler); -fail1: - v4l2_device_unregister_subdev(&flash->sd); - kfree(flash); - - return err; -} - -static int lm3554_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct lm3554 *flash = to_lm3554(sd); - int ret; - - media_entity_cleanup(&flash->sd.entity); - v4l2_ctrl_handler_free(&flash->ctrl_handler); - v4l2_device_unregister_subdev(sd); - - atomisp_gmin_remove_subdev(sd); - - del_timer_sync(&flash->flash_off_delay); - - ret = lm3554_gpio_uninit(client); - if (ret < 0) - goto fail; - - kfree(flash); - - return 0; -fail: - dev_err(&client->dev, "gpio request/direction_output fail"); - return ret; -} - -static const struct i2c_device_id lm3554_id[] = { - {LM3554_NAME, 0}, - {}, -}; - -MODULE_DEVICE_TABLE(i2c, lm3554_id); - -static const struct dev_pm_ops lm3554_pm_ops = { - .suspend = lm3554_suspend, - .resume = lm3554_resume, -}; - -static const struct acpi_device_id lm3554_acpi_match[] = { - { "INTCF1C" }, - {}, -}; - -MODULE_DEVICE_TABLE(acpi, lm3554_acpi_match); - -static struct i2c_driver lm3554_driver = { - .driver = { - .name = LM3554_NAME, - .pm = &lm3554_pm_ops, - .acpi_match_table = ACPI_PTR(lm3554_acpi_match), - }, - .probe = lm3554_probe, - .remove = lm3554_remove, - .id_table = lm3554_id, -}; - -static __init int init_lm3554(void) -{ - return i2c_add_driver(&lm3554_driver); -} - -static __exit void exit_lm3554(void) -{ - i2c_del_driver(&lm3554_driver); -} - -module_init(init_lm3554); -module_exit(exit_lm3554); -MODULE_AUTHOR("Jing Tao "); -MODULE_DESCRIPTION("LED flash driver for LM3554"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/mt9m114.c b/drivers/staging/media/atomisp/i2c/mt9m114.c deleted file mode 100644 index 3c837cb8859c..000000000000 --- a/drivers/staging/media/atomisp/i2c/mt9m114.c +++ /dev/null @@ -1,1963 +0,0 @@ -/* - * Support for mt9m114 Camera Sensor. - * - * Copyright (c) 2010 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../include/linux/atomisp_gmin_platform.h" -#include - -#include "mt9m114.h" - -#define to_mt9m114_sensor(sd) container_of(sd, struct mt9m114_device, sd) - -/* - * TODO: use debug parameter to actually define when debug messages should - * be printed. - */ -static int debug; -static int aaalock; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - -static int mt9m114_t_vflip(struct v4l2_subdev *sd, int value); -static int mt9m114_t_hflip(struct v4l2_subdev *sd, int value); -static int mt9m114_wait_state(struct i2c_client *client, int timeout); - -static int -mt9m114_read_reg(struct i2c_client *client, u16 data_length, u32 reg, u32 *val) -{ - int err; - struct i2c_msg msg[2]; - unsigned char data[4]; - - if (!client->adapter) { - v4l2_err(client, "%s error, no client->adapter\n", __func__); - return -ENODEV; - } - - if (data_length != MISENSOR_8BIT && data_length != MISENSOR_16BIT - && data_length != MISENSOR_32BIT) { - v4l2_err(client, "%s error, invalid data length\n", __func__); - return -EINVAL; - } - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = MSG_LEN_OFFSET; - msg[0].buf = data; - - /* high byte goes out first */ - data[0] = (u16) (reg >> 8); - data[1] = (u16) (reg & 0xff); - - msg[1].addr = client->addr; - msg[1].len = data_length; - msg[1].flags = I2C_M_RD; - msg[1].buf = data; - - err = i2c_transfer(client->adapter, msg, 2); - - if (err >= 0) { - *val = 0; - /* high byte comes first */ - if (data_length == MISENSOR_8BIT) - *val = data[0]; - else if (data_length == MISENSOR_16BIT) - *val = data[1] + (data[0] << 8); - else - *val = data[3] + (data[2] << 8) + - (data[1] << 16) + (data[0] << 24); - - return 0; - } - - dev_err(&client->dev, "read from offset 0x%x error %d", reg, err); - return err; -} - -static int -mt9m114_write_reg(struct i2c_client *client, u16 data_length, u16 reg, u32 val) -{ - int num_msg; - struct i2c_msg msg; - unsigned char data[6] = {0}; - u16 *wreg; - int retry = 0; - - if (!client->adapter) { - v4l2_err(client, "%s error, no client->adapter\n", __func__); - return -ENODEV; - } - - if (data_length != MISENSOR_8BIT && data_length != MISENSOR_16BIT - && data_length != MISENSOR_32BIT) { - v4l2_err(client, "%s error, invalid data_length\n", __func__); - return -EINVAL; - } - - memset(&msg, 0, sizeof(msg)); - -again: - msg.addr = client->addr; - msg.flags = 0; - msg.len = 2 + data_length; - msg.buf = data; - - /* high byte goes out first */ - wreg = (u16 *)data; - *wreg = cpu_to_be16(reg); - - if (data_length == MISENSOR_8BIT) { - data[2] = (u8)(val); - } else if (data_length == MISENSOR_16BIT) { - u16 *wdata = (u16 *)&data[2]; - *wdata = be16_to_cpu((u16)val); - } else { - /* MISENSOR_32BIT */ - u32 *wdata = (u32 *)&data[2]; - *wdata = be32_to_cpu(val); - } - - num_msg = i2c_transfer(client->adapter, &msg, 1); - - /* - * HACK: Need some delay here for Rev 2 sensors otherwise some - * registers do not seem to load correctly. - */ - mdelay(1); - - if (num_msg >= 0) - return 0; - - dev_err(&client->dev, "write error: wrote 0x%x to offset 0x%x error %d", - val, reg, num_msg); - if (retry <= I2C_RETRY_COUNT) { - dev_dbg(&client->dev, "retrying... %d", retry); - retry++; - msleep(20); - goto again; - } - - return num_msg; -} - -/** - * misensor_rmw_reg - Read/Modify/Write a value to a register in the sensor - * device - * @client: i2c driver client structure - * @data_length: 8/16/32-bits length - * @reg: register address - * @mask: masked out bits - * @set: bits set - * - * Read/modify/write a value to a register in the sensor device. - * Returns zero if successful, or non-zero otherwise. - */ -static int -misensor_rmw_reg(struct i2c_client *client, u16 data_length, u16 reg, - u32 mask, u32 set) -{ - int err; - u32 val; - - /* Exit when no mask */ - if (mask == 0) - return 0; - - /* @mask must not exceed data length */ - switch (data_length) { - case MISENSOR_8BIT: - if (mask & ~0xff) - return -EINVAL; - break; - case MISENSOR_16BIT: - if (mask & ~0xffff) - return -EINVAL; - break; - case MISENSOR_32BIT: - break; - default: - /* Wrong @data_length */ - return -EINVAL; - } - - err = mt9m114_read_reg(client, data_length, reg, &val); - if (err) { - v4l2_err(client, "misensor_rmw_reg error exit, read failed\n"); - return -EINVAL; - } - - val &= ~mask; - - /* - * Perform the OR function if the @set exists. - * Shift @set value to target bit location. @set should set only - * bits included in @mask. - * - * REVISIT: This function expects @set to be non-shifted. Its shift - * value is then defined to be equal to mask's LSB position. - * How about to inform values in their right offset position and avoid - * this unneeded shift operation? - */ - set <<= ffs(mask) - 1; - val |= set & mask; - - err = mt9m114_write_reg(client, data_length, reg, val); - if (err) { - v4l2_err(client, "misensor_rmw_reg error exit, write failed\n"); - return -EINVAL; - } - - return 0; -} - - -static int __mt9m114_flush_reg_array(struct i2c_client *client, - struct mt9m114_write_ctrl *ctrl) -{ - struct i2c_msg msg; - const int num_msg = 1; - int ret; - int retry = 0; - - if (ctrl->index == 0) - return 0; - -again: - msg.addr = client->addr; - msg.flags = 0; - msg.len = 2 + ctrl->index; - ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr); - msg.buf = (u8 *)&ctrl->buffer; - - ret = i2c_transfer(client->adapter, &msg, num_msg); - if (ret != num_msg) { - if (++retry <= I2C_RETRY_COUNT) { - dev_dbg(&client->dev, "retrying... %d\n", retry); - msleep(20); - goto again; - } - dev_err(&client->dev, "%s: i2c transfer error\n", __func__); - return -EIO; - } - - ctrl->index = 0; - - /* - * REVISIT: Previously we had a delay after writing data to sensor. - * But it was removed as our tests have shown it is not necessary - * anymore. - */ - - return 0; -} - -static int __mt9m114_buf_reg_array(struct i2c_client *client, - struct mt9m114_write_ctrl *ctrl, - const struct misensor_reg *next) -{ - u16 *data16; - u32 *data32; - int err; - - /* Insufficient buffer? Let's flush and get more free space. */ - if (ctrl->index + next->length >= MT9M114_MAX_WRITE_BUF_SIZE) { - err = __mt9m114_flush_reg_array(client, ctrl); - if (err) - return err; - } - - switch (next->length) { - case MISENSOR_8BIT: - ctrl->buffer.data[ctrl->index] = (u8)next->val; - break; - case MISENSOR_16BIT: - data16 = (u16 *)&ctrl->buffer.data[ctrl->index]; - *data16 = cpu_to_be16((u16)next->val); - break; - case MISENSOR_32BIT: - data32 = (u32 *)&ctrl->buffer.data[ctrl->index]; - *data32 = cpu_to_be32(next->val); - break; - default: - return -EINVAL; - } - - /* When first item is added, we need to store its starting address */ - if (ctrl->index == 0) - ctrl->buffer.addr = next->reg; - - ctrl->index += next->length; - - return 0; -} - -static int -__mt9m114_write_reg_is_consecutive(struct i2c_client *client, - struct mt9m114_write_ctrl *ctrl, - const struct misensor_reg *next) -{ - if (ctrl->index == 0) - return 1; - - return ctrl->buffer.addr + ctrl->index == next->reg; -} - -/* - * mt9m114_write_reg_array - Initializes a list of mt9m114 registers - * @client: i2c driver client structure - * @reglist: list of registers to be written - * @poll: completion polling requirement - * This function initializes a list of registers. When consecutive addresses - * are found in a row on the list, this function creates a buffer and sends - * consecutive data in a single i2c_transfer(). - * - * __mt9m114_flush_reg_array, __mt9m114_buf_reg_array() and - * __mt9m114_write_reg_is_consecutive() are internal functions to - * mt9m114_write_reg_array() and should be not used anywhere else. - * - */ -static int mt9m114_write_reg_array(struct i2c_client *client, - const struct misensor_reg *reglist, - int poll) -{ - const struct misensor_reg *next = reglist; - struct mt9m114_write_ctrl ctrl; - int err; - - if (poll == PRE_POLLING) { - err = mt9m114_wait_state(client, MT9M114_WAIT_STAT_TIMEOUT); - if (err) - return err; - } - - ctrl.index = 0; - for (; next->length != MISENSOR_TOK_TERM; next++) { - switch (next->length & MISENSOR_TOK_MASK) { - case MISENSOR_TOK_DELAY: - err = __mt9m114_flush_reg_array(client, &ctrl); - if (err) - return err; - msleep(next->val); - break; - case MISENSOR_TOK_RMW: - err = __mt9m114_flush_reg_array(client, &ctrl); - err |= misensor_rmw_reg(client, - next->length & - ~MISENSOR_TOK_RMW, - next->reg, next->val, - next->val2); - if (err) { - dev_err(&client->dev, "%s read err. aborted\n", - __func__); - return -EINVAL; - } - break; - default: - /* - * If next address is not consecutive, data needs to be - * flushed before proceed. - */ - if (!__mt9m114_write_reg_is_consecutive(client, &ctrl, - next)) { - err = __mt9m114_flush_reg_array(client, &ctrl); - if (err) - return err; - } - err = __mt9m114_buf_reg_array(client, &ctrl, next); - if (err) { - v4l2_err(client, "%s: write error, aborted\n", - __func__); - return err; - } - break; - } - } - - err = __mt9m114_flush_reg_array(client, &ctrl); - if (err) - return err; - - if (poll == POST_POLLING) - return mt9m114_wait_state(client, MT9M114_WAIT_STAT_TIMEOUT); - - return 0; -} - -static int mt9m114_wait_state(struct i2c_client *client, int timeout) -{ - int ret; - unsigned int val; - - while (timeout-- > 0) { - ret = mt9m114_read_reg(client, MISENSOR_16BIT, 0x0080, &val); - if (ret) - return ret; - if ((val & 0x2) == 0) - return 0; - msleep(20); - } - - return -EINVAL; - -} - -static int mt9m114_set_suspend(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - return mt9m114_write_reg_array(client, - mt9m114_standby_reg, POST_POLLING); -} - -static int mt9m114_init_common(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return mt9m114_write_reg_array(client, mt9m114_common, PRE_POLLING); -} - -static int power_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret; - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->power_ctrl) - return dev->platform_data->power_ctrl(sd, flag); - - if (flag) { - ret = dev->platform_data->v2p8_ctrl(sd, 1); - if (ret == 0) { - ret = dev->platform_data->v1p8_ctrl(sd, 1); - if (ret) - ret = dev->platform_data->v2p8_ctrl(sd, 0); - } - } else { - ret = dev->platform_data->v2p8_ctrl(sd, 0); - ret = dev->platform_data->v1p8_ctrl(sd, 0); - } - return ret; -} - -static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret; - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->gpio_ctrl) - return dev->platform_data->gpio_ctrl(sd, flag); - - /* Note: current modules wire only one GPIO signal (RESET#), - * but the schematic wires up two to the connector. BIOS - * versions have been unfortunately inconsistent with which - * ACPI index RESET# is on, so hit both */ - - if (flag) { - ret = dev->platform_data->gpio0_ctrl(sd, 0); - ret = dev->platform_data->gpio1_ctrl(sd, 0); - msleep(60); - ret |= dev->platform_data->gpio0_ctrl(sd, 1); - ret |= dev->platform_data->gpio1_ctrl(sd, 1); - } else { - ret = dev->platform_data->gpio0_ctrl(sd, 0); - ret = dev->platform_data->gpio1_ctrl(sd, 0); - } - return ret; -} - -static int power_up(struct v4l2_subdev *sd) -{ - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (NULL == dev->platform_data) { - dev_err(&client->dev, "no camera_sensor_platform_data"); - return -ENODEV; - } - - /* power control */ - ret = power_ctrl(sd, 1); - if (ret) - goto fail_power; - - /* flis clock control */ - ret = dev->platform_data->flisclk_ctrl(sd, 1); - if (ret) - goto fail_clk; - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 1); - if (ret) - dev_err(&client->dev, "gpio failed 1\n"); - /* - * according to DS, 44ms is needed between power up and first i2c - * commend - */ - msleep(50); - - return 0; - -fail_clk: - dev->platform_data->flisclk_ctrl(sd, 0); -fail_power: - power_ctrl(sd, 0); - dev_err(&client->dev, "sensor power-up failed\n"); - - return ret; -} - -static int power_down(struct v4l2_subdev *sd) -{ - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (NULL == dev->platform_data) { - dev_err(&client->dev, "no camera_sensor_platform_data"); - return -ENODEV; - } - - ret = dev->platform_data->flisclk_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "flisclk failed\n"); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "gpio failed 1\n"); - - /* power control */ - ret = power_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "vprog failed.\n"); - - /*according to DS, 20ms is needed after power down*/ - msleep(20); - - return ret; -} - -static int mt9m114_s_power(struct v4l2_subdev *sd, int power) -{ - if (power == 0) - return power_down(sd); - else { - if (power_up(sd)) - return -EINVAL; - - return mt9m114_init_common(sd); - } -} - -/* - * distance - calculate the distance - * @res: resolution - * @w: width - * @h: height - * - * Get the gap between resolution and w/h. - * res->width/height smaller than w/h wouldn't be considered. - * Returns the value of gap or -1 if fail. - */ -#define LARGEST_ALLOWED_RATIO_MISMATCH 600 -static int distance(struct mt9m114_res_struct const *res, u32 w, u32 h) -{ - unsigned int w_ratio; - unsigned int h_ratio; - int match; - - if (w == 0) - return -1; - w_ratio = (res->width << 13) / w; - if (h == 0) - return -1; - h_ratio = (res->height << 13) / h; - if (h_ratio == 0) - return -1; - match = abs(((w_ratio << 13) / h_ratio) - 8192); - - if ((w_ratio < 8192) || (h_ratio < 8192) || - (match > LARGEST_ALLOWED_RATIO_MISMATCH)) - return -1; - - return w_ratio + h_ratio; -} - -/* Return the nearest higher resolution index */ -static int nearest_resolution_index(int w, int h) -{ - int i; - int idx = -1; - int dist; - int min_dist = INT_MAX; - const struct mt9m114_res_struct *tmp_res = NULL; - - for (i = 0; i < ARRAY_SIZE(mt9m114_res); i++) { - tmp_res = &mt9m114_res[i]; - dist = distance(tmp_res, w, h); - if (dist == -1) - continue; - if (dist < min_dist) { - min_dist = dist; - idx = i; - } - } - - return idx; -} - -static int mt9m114_try_res(u32 *w, u32 *h) -{ - int idx = 0; - - if ((*w > MT9M114_RES_960P_SIZE_H) - || (*h > MT9M114_RES_960P_SIZE_V)) { - *w = MT9M114_RES_960P_SIZE_H; - *h = MT9M114_RES_960P_SIZE_V; - } else { - idx = nearest_resolution_index(*w, *h); - - /* - * nearest_resolution_index() doesn't return smaller - * resolutions. If it fails, it means the requested - * resolution is higher than wecan support. Fallback - * to highest possible resolution in this case. - */ - if (idx == -1) - idx = ARRAY_SIZE(mt9m114_res) - 1; - - *w = mt9m114_res[idx].width; - *h = mt9m114_res[idx].height; - } - - return 0; -} - -static struct mt9m114_res_struct *mt9m114_to_res(u32 w, u32 h) -{ - int index; - - for (index = 0; index < N_RES; index++) { - if ((mt9m114_res[index].width == w) && - (mt9m114_res[index].height == h)) - break; - } - - /* No mode found */ - if (index >= N_RES) - return NULL; - - return &mt9m114_res[index]; -} - -static int mt9m114_res2size(struct v4l2_subdev *sd, int *h_size, int *v_size) -{ - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - unsigned short hsize; - unsigned short vsize; - - switch (dev->res) { - case MT9M114_RES_736P: - hsize = MT9M114_RES_736P_SIZE_H; - vsize = MT9M114_RES_736P_SIZE_V; - break; - case MT9M114_RES_864P: - hsize = MT9M114_RES_864P_SIZE_H; - vsize = MT9M114_RES_864P_SIZE_V; - break; - case MT9M114_RES_960P: - hsize = MT9M114_RES_960P_SIZE_H; - vsize = MT9M114_RES_960P_SIZE_V; - break; - default: - v4l2_err(sd, "%s: Resolution 0x%08x unknown\n", __func__, - dev->res); - return -EINVAL; - } - - if (h_size != NULL) - *h_size = hsize; - if (v_size != NULL) - *v_size = vsize; - - return 0; -} - -static int mt9m114_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct mt9m114_res_struct *res) -{ - struct atomisp_sensor_mode_data *buf = &info->data; - u32 reg_val; - int ret; - - if (info == NULL) - return -EINVAL; - - ret = mt9m114_read_reg(client, MISENSOR_32BIT, - REG_PIXEL_CLK, ®_val); - if (ret) - return ret; - buf->vt_pix_clk_freq_mhz = reg_val; - - /* get integration time */ - buf->coarse_integration_time_min = MT9M114_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - MT9M114_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = MT9M114_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - MT9M114_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = MT9M114_FINE_INTG_TIME_MIN; - - buf->frame_length_lines = res->lines_per_frame; - buf->line_length_pck = res->pixels_per_line; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_H_START, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_V_START, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_H_END, ®_val); - if (ret) - return ret; - buf->crop_horizontal_end = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_V_END, ®_val); - if (ret) - return ret; - buf->crop_vertical_end = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_WIDTH, ®_val); - if (ret) - return ret; - buf->output_width = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_HEIGHT, ®_val); - if (ret) - return ret; - buf->output_height = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_TIMING_HTS, ®_val); - if (ret) - return ret; - buf->line_length_pck = reg_val; - - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_TIMING_VTS, ®_val); - if (ret) - return ret; - buf->frame_length_lines = reg_val; - - buf->binning_factor_x = res->bin_factor_x ? - res->bin_factor_x : 1; - buf->binning_factor_y = res->bin_factor_y ? - res->bin_factor_y : 1; - return 0; -} - -static int mt9m114_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - int width, height; - int ret; - if (format->pad) - return -EINVAL; - fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; - - ret = mt9m114_res2size(sd, &width, &height); - if (ret) - return ret; - fmt->width = width; - fmt->height = height; - - return 0; -} - -static int mt9m114_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct i2c_client *c = v4l2_get_subdevdata(sd); - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - struct mt9m114_res_struct *res_index; - u32 width = fmt->width; - u32 height = fmt->height; - struct camera_mipi_info *mt9m114_info = NULL; - - int ret; - if (format->pad) - return -EINVAL; - dev->streamon = 0; - dev->first_exp = MT9M114_DEFAULT_FIRST_EXP; - - mt9m114_info = v4l2_get_subdev_hostdata(sd); - if (mt9m114_info == NULL) - return -EINVAL; - - mt9m114_try_res(&width, &height); - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; - return 0; - } - res_index = mt9m114_to_res(width, height); - - /* Sanity check */ - if (unlikely(!res_index)) { - WARN_ON(1); - return -EINVAL; - } - - switch (res_index->res) { - case MT9M114_RES_736P: - ret = mt9m114_write_reg_array(c, mt9m114_736P_init, NO_POLLING); - ret += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, - MISENSOR_R_MODE_MASK, MISENSOR_NORMAL_SET); - break; - case MT9M114_RES_864P: - ret = mt9m114_write_reg_array(c, mt9m114_864P_init, NO_POLLING); - ret += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, - MISENSOR_R_MODE_MASK, MISENSOR_NORMAL_SET); - break; - case MT9M114_RES_960P: - ret = mt9m114_write_reg_array(c, mt9m114_976P_init, NO_POLLING); - /* set sensor read_mode to Normal */ - ret += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, - MISENSOR_R_MODE_MASK, MISENSOR_NORMAL_SET); - break; - default: - v4l2_err(sd, "set resolution: %d failed!\n", res_index->res); - return -EINVAL; - } - - if (ret) - return -EINVAL; - - ret = mt9m114_write_reg_array(c, mt9m114_chgstat_reg, POST_POLLING); - if (ret < 0) - return ret; - - if (mt9m114_set_suspend(sd)) - return -EINVAL; - - if (dev->res != res_index->res) { - int index; - - /* Switch to different size */ - if (width <= 640) { - dev->nctx = 0x00; /* Set for context A */ - } else { - /* - * Context B is used for resolutions larger than 640x480 - * Using YUV for Context B. - */ - dev->nctx = 0x01; /* set for context B */ - } - - /* - * Marked current sensor res as being "used" - * - * REVISIT: We don't need to use an "used" field on each mode - * list entry to know which mode is selected. If this - * information is really necessary, how about to use a single - * variable on sensor dev struct? - */ - for (index = 0; index < N_RES; index++) { - if ((width == mt9m114_res[index].width) && - (height == mt9m114_res[index].height)) { - mt9m114_res[index].used = true; - continue; - } - mt9m114_res[index].used = false; - } - } - ret = mt9m114_get_intg_factor(c, mt9m114_info, - &mt9m114_res[res_index->res]); - if (ret) { - dev_err(&c->dev, "failed to get integration_factor\n"); - return -EINVAL; - } - /* - * mt9m114 - we don't poll for context switch - * because it does not happen with streaming disabled. - */ - dev->res = res_index->res; - - fmt->width = width; - fmt->height = height; - fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; - return 0; -} - -/* TODO: Update to SOC functions, remove exposure and gain */ -static int mt9m114_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (MT9M114_FOCAL_LENGTH_NUM << 16) | MT9M114_FOCAL_LENGTH_DEM; - return 0; -} - -static int mt9m114_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /*const f number for mt9m114*/ - *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 16) | MT9M114_F_NUMBER_DEM; - return 0; -} - -static int mt9m114_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (MT9M114_F_NUMBER_DEFAULT_NUM << 24) | - (MT9M114_F_NUMBER_DEM << 16) | - (MT9M114_F_NUMBER_DEFAULT_NUM << 8) | MT9M114_F_NUMBER_DEM; - return 0; -} - -/* Horizontal flip the image. */ -static int mt9m114_g_hflip(struct v4l2_subdev *sd, s32 *val) -{ - struct i2c_client *c = v4l2_get_subdevdata(sd); - int ret; - u32 data; - ret = mt9m114_read_reg(c, MISENSOR_16BIT, - (u32)MISENSOR_READ_MODE, &data); - if (ret) - return ret; - *val = !!(data & MISENSOR_HFLIP_MASK); - - return 0; -} - -static int mt9m114_g_vflip(struct v4l2_subdev *sd, s32 *val) -{ - struct i2c_client *c = v4l2_get_subdevdata(sd); - int ret; - u32 data; - - ret = mt9m114_read_reg(c, MISENSOR_16BIT, - (u32)MISENSOR_READ_MODE, &data); - if (ret) - return ret; - *val = !!(data & MISENSOR_VFLIP_MASK); - - return 0; -} - -static long mt9m114_s_exposure(struct v4l2_subdev *sd, - struct atomisp_exposure *exposure) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - int ret = 0; - unsigned int coarse_integration = 0; - unsigned int fine_integration = 0; - unsigned int FLines = 0; - unsigned int FrameLengthLines = 0; /* ExposureTime.FrameLengthLines; */ - unsigned int AnalogGain, DigitalGain; - u32 AnalogGainToWrite = 0; - u16 exposure_local[3]; - - dev_dbg(&client->dev, "%s(0x%X 0x%X 0x%X)\n", __func__, - exposure->integration_time[0], exposure->gain[0], - exposure->gain[1]); - - coarse_integration = exposure->integration_time[0]; - /* fine_integration = ExposureTime.FineIntegrationTime; */ - /* FrameLengthLines = ExposureTime.FrameLengthLines; */ - FLines = mt9m114_res[dev->res].lines_per_frame; - AnalogGain = exposure->gain[0]; - DigitalGain = exposure->gain[1]; - if (!dev->streamon) { - /*Save the first exposure values while stream is off*/ - dev->first_exp = coarse_integration; - dev->first_gain = AnalogGain; - dev->first_diggain = DigitalGain; - } - /* DigitalGain = 0x400 * (((u16) DigitalGain) >> 8) + - ((unsigned int)(0x400 * (((u16) DigitalGain) & 0xFF)) >>8); */ - - /* set frame length */ - if (FLines < coarse_integration + 6) - FLines = coarse_integration + 6; - if (FLines < FrameLengthLines) - FLines = FrameLengthLines; - ret = mt9m114_write_reg(client, MISENSOR_16BIT, 0x300A, FLines); - if (ret) { - v4l2_err(client, "%s: fail to set FLines\n", __func__); - return -EINVAL; - } - - /* set coarse/fine integration */ - exposure_local[0] = REG_EXPO_COARSE; - exposure_local[1] = (u16)coarse_integration; - exposure_local[2] = (u16)fine_integration; - /* 3A provide real exposure time. - should not translate to any value here. */ - ret = mt9m114_write_reg(client, MISENSOR_16BIT, - REG_EXPO_COARSE, (u16)(coarse_integration)); - if (ret) { - v4l2_err(client, "%s: fail to set exposure time\n", __func__); - return -EINVAL; - } - - /* - // set analog/digital gain - switch(AnalogGain) - { - case 0: - AnalogGainToWrite = 0x0; - break; - case 1: - AnalogGainToWrite = 0x20; - break; - case 2: - AnalogGainToWrite = 0x60; - break; - case 4: - AnalogGainToWrite = 0xA0; - break; - case 8: - AnalogGainToWrite = 0xE0; - break; - default: - AnalogGainToWrite = 0x20; - break; - } - */ - if (DigitalGain >= 16 || DigitalGain <= 1) - DigitalGain = 1; - /* AnalogGainToWrite = - (u16)((DigitalGain << 12) | AnalogGainToWrite); */ - AnalogGainToWrite = (u16)((DigitalGain << 12) | (u16)AnalogGain); - ret = mt9m114_write_reg(client, MISENSOR_16BIT, - REG_GAIN, AnalogGainToWrite); - if (ret) { - v4l2_err(client, "%s: fail to set AnalogGainToWrite\n", - __func__); - return -EINVAL; - } - - return ret; -} - -static long mt9m114_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - - switch (cmd) { - case ATOMISP_IOC_S_EXPOSURE: - return mt9m114_s_exposure(sd, arg); - default: - return -EINVAL; - } - - return 0; -} - -/* This returns the exposure time being used. This should only be used - for filling in EXIF data, not for actual image processing. */ -static int mt9m114_g_exposure(struct v4l2_subdev *sd, s32 *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u32 coarse; - int ret; - - /* the fine integration time is currently not calculated */ - ret = mt9m114_read_reg(client, MISENSOR_16BIT, - REG_EXPO_COARSE, &coarse); - if (ret) - return ret; - - *value = coarse; - return 0; -} -#ifndef CSS15 -/* - * This function will return the sensor supported max exposure zone number. - * the sensor which supports max exposure zone number is 1. - */ -static int mt9m114_g_exposure_zone_num(struct v4l2_subdev *sd, s32 *val) -{ - *val = 1; - - return 0; -} - -/* - * set exposure metering, average/center_weighted/spot/matrix. - */ -static int mt9m114_s_exposure_metering(struct v4l2_subdev *sd, s32 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - switch (val) { - case V4L2_EXPOSURE_METERING_SPOT: - ret = mt9m114_write_reg_array(client, mt9m114_exp_average, - NO_POLLING); - if (ret) { - dev_err(&client->dev, "write exp_average reg err.\n"); - return ret; - } - break; - case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED: - default: - ret = mt9m114_write_reg_array(client, mt9m114_exp_center, - NO_POLLING); - if (ret) { - dev_err(&client->dev, "write exp_default reg err"); - return ret; - } - } - - return 0; -} - -/* - * This function is for touch exposure feature. - */ -static int mt9m114_s_exposure_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct misensor_reg exp_reg; - int width, height; - int grid_width, grid_height; - int grid_left, grid_top, grid_right, grid_bottom; - int win_left, win_top, win_right, win_bottom; - int i, j; - int ret; - - if (sel->which != V4L2_SUBDEV_FORMAT_TRY && - sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - grid_left = sel->r.left; - grid_top = sel->r.top; - grid_right = sel->r.left + sel->r.width - 1; - grid_bottom = sel->r.top + sel->r.height - 1; - - ret = mt9m114_res2size(sd, &width, &height); - if (ret) - return ret; - - grid_width = width / 5; - grid_height = height / 5; - - if (grid_width && grid_height) { - win_left = grid_left / grid_width; - win_top = grid_top / grid_height; - win_right = grid_right / grid_width; - win_bottom = grid_bottom / grid_height; - } else { - dev_err(&client->dev, "Incorrect exp grid.\n"); - return -EINVAL; - } - - win_left = clamp_t(int, win_left, 0, 4); - win_top = clamp_t(int, win_top, 0, 4); - win_right = clamp_t(int, win_right, 0, 4); - win_bottom = clamp_t(int, win_bottom, 0, 4); - - ret = mt9m114_write_reg_array(client, mt9m114_exp_average, NO_POLLING); - if (ret) { - dev_err(&client->dev, "write exp_average reg err.\n"); - return ret; - } - - for (i = win_top; i <= win_bottom; i++) { - for (j = win_left; j <= win_right; j++) { - exp_reg = mt9m114_exp_win[i][j]; - - ret = mt9m114_write_reg(client, exp_reg.length, - exp_reg.reg, exp_reg.val); - if (ret) { - dev_err(&client->dev, "write exp_reg err.\n"); - return ret; - } - } - } - - return 0; -} -#endif - -static int mt9m114_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) -{ - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - - *val = mt9m114_res[dev->res].bin_factor_x; - - return 0; -} - -static int mt9m114_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) -{ - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - - *val = mt9m114_res[dev->res].bin_factor_y; - - return 0; -} - -static int mt9m114_s_ev(struct v4l2_subdev *sd, s32 val) -{ - struct i2c_client *c = v4l2_get_subdevdata(sd); - s32 luma = 0x37; - int err; - - /* EV value only support -2 to 2 - * 0: 0x37, 1:0x47, 2:0x57, -1:0x27, -2:0x17 - */ - if (val < -2 || val > 2) - return -EINVAL; - luma += 0x10 * val; - dev_dbg(&c->dev, "%s val:%d luma:0x%x\n", __func__, val, luma); - err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC87A); - if (err) { - dev_err(&c->dev, "%s logic addr access error\n", __func__); - return err; - } - err = mt9m114_write_reg(c, MISENSOR_8BIT, 0xC87A, (u32)luma); - if (err) { - dev_err(&c->dev, "%s write target_average_luma failed\n", - __func__); - return err; - } - udelay(10); - - return 0; -} - -static int mt9m114_g_ev(struct v4l2_subdev *sd, s32 *val) -{ - struct i2c_client *c = v4l2_get_subdevdata(sd); - int err; - u32 luma; - - err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC87A); - if (err) { - dev_err(&c->dev, "%s logic addr access error\n", __func__); - return err; - } - err = mt9m114_read_reg(c, MISENSOR_8BIT, 0xC87A, &luma); - if (err) { - dev_err(&c->dev, "%s read target_average_luma failed\n", - __func__); - return err; - } - luma -= 0x17; - luma /= 0x10; - *val = (s32)luma - 2; - dev_dbg(&c->dev, "%s val:%d\n", __func__, *val); - - return 0; -} - -/* Fake interface - * mt9m114 now can not support 3a_lock -*/ -static int mt9m114_s_3a_lock(struct v4l2_subdev *sd, s32 val) -{ - aaalock = val; - return 0; -} - -static int mt9m114_g_3a_lock(struct v4l2_subdev *sd, s32 *val) -{ - if (aaalock) - return V4L2_LOCK_EXPOSURE | V4L2_LOCK_WHITE_BALANCE - | V4L2_LOCK_FOCUS; - return 0; -} - -static int mt9m114_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct mt9m114_device *dev = - container_of(ctrl->handler, struct mt9m114_device, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n", - __func__, ctrl->val); - ret = mt9m114_t_vflip(&dev->sd, ctrl->val); - break; - case V4L2_CID_HFLIP: - dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n", - __func__, ctrl->val); - ret = mt9m114_t_hflip(&dev->sd, ctrl->val); - break; -#ifndef CSS15 - case V4L2_CID_EXPOSURE_METERING: - ret = mt9m114_s_exposure_metering(&dev->sd, ctrl->val); - break; -#endif - case V4L2_CID_EXPOSURE: - ret = mt9m114_s_ev(&dev->sd, ctrl->val); - break; - case V4L2_CID_3A_LOCK: - ret = mt9m114_s_3a_lock(&dev->sd, ctrl->val); - break; - default: - ret = -EINVAL; - } - return ret; -} - -static int mt9m114_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct mt9m114_device *dev = - container_of(ctrl->handler, struct mt9m114_device, ctrl_handler); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - ret = mt9m114_g_vflip(&dev->sd, &ctrl->val); - break; - case V4L2_CID_HFLIP: - ret = mt9m114_g_hflip(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = mt9m114_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = mt9m114_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = mt9m114_g_fnumber_range(&dev->sd, &ctrl->val); - break; - case V4L2_CID_EXPOSURE_ABSOLUTE: - ret = mt9m114_g_exposure(&dev->sd, &ctrl->val); - break; -#ifndef CSS15 - case V4L2_CID_EXPOSURE_ZONE_NUM: - ret = mt9m114_g_exposure_zone_num(&dev->sd, &ctrl->val); - break; -#endif - case V4L2_CID_BIN_FACTOR_HORZ: - ret = mt9m114_g_bin_factor_x(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_VERT: - ret = mt9m114_g_bin_factor_y(&dev->sd, &ctrl->val); - break; - case V4L2_CID_EXPOSURE: - ret = mt9m114_g_ev(&dev->sd, &ctrl->val); - break; - case V4L2_CID_3A_LOCK: - ret = mt9m114_g_3a_lock(&dev->sd, &ctrl->val); - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .s_ctrl = mt9m114_s_ctrl, - .g_volatile_ctrl = mt9m114_g_volatile_ctrl -}; - -static struct v4l2_ctrl_config mt9m114_controls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_VFLIP, - .name = "Image v-Flip", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = 1, - .step = 1, - .def = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_HFLIP, - .name = "Image h-Flip", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = 1, - .step = 1, - .def = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .name = "focal length", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = MT9M114_FOCAL_LENGTH_DEFAULT, - .max = MT9M114_FOCAL_LENGTH_DEFAULT, - .step = 1, - .def = MT9M114_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .name = "f-number", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = MT9M114_F_NUMBER_DEFAULT, - .max = MT9M114_F_NUMBER_DEFAULT, - .step = 1, - .def = MT9M114_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .name = "f-number range", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = MT9M114_F_NUMBER_RANGE, - .max = MT9M114_F_NUMBER_RANGE, - .step = 1, - .def = MT9M114_F_NUMBER_RANGE, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_ABSOLUTE, - .name = "exposure", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = 0xffff, - .step = 1, - .def = 0, - .flags = 0, - }, -#ifndef CSS15 - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_ZONE_NUM, - .name = "one-time exposure zone number", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = 0xffff, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_METERING, - .name = "metering", - .type = V4L2_CTRL_TYPE_MENU, - .min = 0, - .max = 3, - .step = 0, - .def = 1, - .flags = 0, - }, -#endif - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_HORZ, - .name = "horizontal binning factor", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = MT9M114_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_VERT, - .name = "vertical binning factor", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = MT9M114_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE, - .name = "exposure biasx", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = -2, - .max = 2, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_3A_LOCK, - .name = "3a lock", - .type = V4L2_CTRL_TYPE_BITMASK, - .min = 0, - .max = V4L2_LOCK_EXPOSURE | V4L2_LOCK_WHITE_BALANCE | V4L2_LOCK_FOCUS, - .step = 1, - .def = 0, - .flags = 0, - }, -}; - -static int mt9m114_detect(struct mt9m114_device *dev, struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - u32 retvalue; - - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { - dev_err(&client->dev, "%s: i2c error", __func__); - return -ENODEV; - } - mt9m114_read_reg(client, MISENSOR_16BIT, (u32)MT9M114_PID, &retvalue); - dev->real_model_id = retvalue; - - if (retvalue != MT9M114_MOD_ID) { - dev_err(&client->dev, "%s: failed: client->addr = %x\n", - __func__, client->addr); - return -ENODEV; - } - - return 0; -} - -static int -mt9m114_s_config(struct v4l2_subdev *sd, int irq, void *platform_data) -{ - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (NULL == platform_data) - return -ENODEV; - - dev->platform_data = - (struct camera_sensor_platform_data *)platform_data; - - if (dev->platform_data->platform_init) { - ret = dev->platform_data->platform_init(client); - if (ret) { - v4l2_err(client, "mt9m114 platform init err\n"); - return ret; - } - } - ret = power_up(sd); - if (ret) { - v4l2_err(client, "mt9m114 power-up err"); - return ret; - } - - /* config & detect sensor */ - ret = mt9m114_detect(dev, client); - if (ret) { - v4l2_err(client, "mt9m114_detect err s_config.\n"); - goto fail_detect; - } - - ret = dev->platform_data->csi_cfg(sd, 1); - if (ret) - goto fail_csi_cfg; - - ret = mt9m114_set_suspend(sd); - if (ret) { - v4l2_err(client, "mt9m114 suspend err"); - return ret; - } - - ret = power_down(sd); - if (ret) { - v4l2_err(client, "mt9m114 power down err"); - return ret; - } - - return ret; - -fail_csi_cfg: - dev->platform_data->csi_cfg(sd, 0); -fail_detect: - power_down(sd); - dev_err(&client->dev, "sensor power-gating failed\n"); - return ret; -} - -/* Horizontal flip the image. */ -static int mt9m114_t_hflip(struct v4l2_subdev *sd, int value) -{ - struct i2c_client *c = v4l2_get_subdevdata(sd); - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - int err; - /* set for direct mode */ - err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC850); - if (value) { - /* enable H flip ctx A */ - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x01, 0x01); - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x01, 0x01); - /* ctx B */ - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x01, 0x01); - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x01, 0x01); - - err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, - MISENSOR_HFLIP_MASK, MISENSOR_FLIP_EN); - - dev->bpat = MT9M114_BPAT_GRGRBGBG; - } else { - /* disable H flip ctx A */ - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x01, 0x00); - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x01, 0x00); - /* ctx B */ - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x01, 0x00); - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x01, 0x00); - - err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, - MISENSOR_HFLIP_MASK, MISENSOR_FLIP_DIS); - - dev->bpat = MT9M114_BPAT_BGBGGRGR; - } - - err += mt9m114_write_reg(c, MISENSOR_8BIT, 0x8404, 0x06); - udelay(10); - - return !!err; -} - -/* Vertically flip the image */ -static int mt9m114_t_vflip(struct v4l2_subdev *sd, int value) -{ - struct i2c_client *c = v4l2_get_subdevdata(sd); - int err; - /* set for direct mode */ - err = mt9m114_write_reg(c, MISENSOR_16BIT, 0x098E, 0xC850); - if (value >= 1) { - /* enable H flip - ctx A */ - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x02, 0x01); - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x02, 0x01); - /* ctx B */ - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x02, 0x01); - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x02, 0x01); - - err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, - MISENSOR_VFLIP_MASK, MISENSOR_FLIP_EN); - } else { - /* disable H flip - ctx A */ - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC850, 0x02, 0x00); - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC851, 0x02, 0x00); - /* ctx B */ - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC888, 0x02, 0x00); - err += misensor_rmw_reg(c, MISENSOR_8BIT, 0xC889, 0x02, 0x00); - - err += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE, - MISENSOR_VFLIP_MASK, MISENSOR_FLIP_DIS); - } - - err += mt9m114_write_reg(c, MISENSOR_8BIT, 0x8404, 0x06); - udelay(10); - - return !!err; -} -static int mt9m114_s_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - return 0; -} - -static int mt9m114_g_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - - interval->interval.numerator = 1; - interval->interval.denominator = mt9m114_res[dev->res].fps; - - return 0; -} - -static int mt9m114_s_stream(struct v4l2_subdev *sd, int enable) -{ - int ret; - struct i2c_client *c = v4l2_get_subdevdata(sd); - struct mt9m114_device *dev = to_mt9m114_sensor(sd); - struct atomisp_exposure exposure; - - if (enable) { - ret = mt9m114_write_reg_array(c, mt9m114_chgstat_reg, - POST_POLLING); - if (ret < 0) - return ret; - - if (dev->first_exp > MT9M114_MAX_FIRST_EXP) { - exposure.integration_time[0] = dev->first_exp; - exposure.gain[0] = dev->first_gain; - exposure.gain[1] = dev->first_diggain; - mt9m114_s_exposure(sd, &exposure); - } - dev->streamon = 1; - - } else { - dev->streamon = 0; - ret = mt9m114_set_suspend(sd); - } - - return ret; -} - -static int mt9m114_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->index) - return -EINVAL; - code->code = MEDIA_BUS_FMT_SGRBG10_1X10; - - return 0; -} - -static int mt9m114_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - - unsigned int index = fse->index; - - if (index >= N_RES) - return -EINVAL; - - fse->min_width = mt9m114_res[index].width; - fse->min_height = mt9m114_res[index].height; - fse->max_width = mt9m114_res[index].width; - fse->max_height = mt9m114_res[index].height; - - return 0; -} - -static int mt9m114_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) -{ - int index; - struct mt9m114_device *snr = to_mt9m114_sensor(sd); - - if (frames == NULL) - return -EINVAL; - - for (index = 0; index < N_RES; index++) { - if (mt9m114_res[index].res == snr->res) - break; - } - - if (index >= N_RES) - return -EINVAL; - - *frames = mt9m114_res[index].skip_frames; - - return 0; -} - -static const struct v4l2_subdev_video_ops mt9m114_video_ops = { - .s_parm = mt9m114_s_parm, - .s_stream = mt9m114_s_stream, - .g_frame_interval = mt9m114_g_frame_interval, -}; - -static const struct v4l2_subdev_sensor_ops mt9m114_sensor_ops = { - .g_skip_frames = mt9m114_g_skip_frames, -}; - -static const struct v4l2_subdev_core_ops mt9m114_core_ops = { - .s_power = mt9m114_s_power, - .ioctl = mt9m114_ioctl, -}; - -/* REVISIT: Do we need pad operations? */ -static const struct v4l2_subdev_pad_ops mt9m114_pad_ops = { - .enum_mbus_code = mt9m114_enum_mbus_code, - .enum_frame_size = mt9m114_enum_frame_size, - .get_fmt = mt9m114_get_fmt, - .set_fmt = mt9m114_set_fmt, -#ifndef CSS15 - .set_selection = mt9m114_s_exposure_selection, -#endif -}; - -static const struct v4l2_subdev_ops mt9m114_ops = { - .core = &mt9m114_core_ops, - .video = &mt9m114_video_ops, - .pad = &mt9m114_pad_ops, - .sensor = &mt9m114_sensor_ops, -}; - -static const struct media_entity_operations mt9m114_entity_ops = { - .link_setup = NULL, -}; - -static int mt9m114_remove(struct i2c_client *client) -{ - struct mt9m114_device *dev; - struct v4l2_subdev *sd = i2c_get_clientdata(client); - - dev = container_of(sd, struct mt9m114_device, sd); - dev->platform_data->csi_cfg(sd, 0); - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); - v4l2_device_unregister_subdev(sd); - media_entity_cleanup(&dev->sd.entity); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - kfree(dev); - return 0; -} - -static int mt9m114_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct mt9m114_device *dev; - int ret = 0; - unsigned int i; - void *pdata; - - /* Setup sensor configuration structure */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "out of memory\n"); - return -ENOMEM; - } - - v4l2_i2c_subdev_init(&dev->sd, client, &mt9m114_ops); - pdata = client->dev.platform_data; - if (ACPI_COMPANION(&client->dev)) - pdata = gmin_camera_platform_data(&dev->sd, - ATOMISP_INPUT_FORMAT_RAW_10, - atomisp_bayer_order_grbg); - if (pdata) - ret = mt9m114_s_config(&dev->sd, client->irq, pdata); - if (!pdata || ret) { - v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); - return ret; - } - - ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); - if (ret) { - v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); - /* Coverity CID 298095 - return on error */ - return ret; - } - - /*TODO add format code here*/ - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - - ret = - v4l2_ctrl_handler_init(&dev->ctrl_handler, - ARRAY_SIZE(mt9m114_controls)); - if (ret) { - mt9m114_remove(client); - return ret; - } - - for (i = 0; i < ARRAY_SIZE(mt9m114_controls); i++) - v4l2_ctrl_new_custom(&dev->ctrl_handler, &mt9m114_controls[i], - NULL); - - if (dev->ctrl_handler.error) { - mt9m114_remove(client); - return dev->ctrl_handler.error; - } - - /* Use same lock for controls as for everything else. */ - dev->ctrl_handler.lock = &dev->input_lock; - dev->sd.ctrl_handler = &dev->ctrl_handler; - - /* REVISIT: Do we need media controller? */ - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); - if (ret) { - mt9m114_remove(client); - return ret; - } - return 0; -} - -MODULE_DEVICE_TABLE(i2c, mt9m114_id); - -static const struct acpi_device_id mt9m114_acpi_match[] = { - { "INT33F0" }, - { "CRMT1040" }, - {}, -}; - -MODULE_DEVICE_TABLE(acpi, mt9m114_acpi_match); - -static struct i2c_driver mt9m114_driver = { - .driver = { - .name = "mt9m114", - .acpi_match_table = ACPI_PTR(mt9m114_acpi_match), - }, - .probe = mt9m114_probe, - .remove = mt9m114_remove, - .id_table = mt9m114_id, -}; - -static __init int init_mt9m114(void) -{ - return i2c_add_driver(&mt9m114_driver); -} - -static __exit void exit_mt9m114(void) -{ - i2c_del_driver(&mt9m114_driver); -} - -module_init(init_mt9m114); -module_exit(exit_mt9m114); - -MODULE_AUTHOR("Shuguang Gong "); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/ov2680.c b/drivers/staging/media/atomisp/i2c/ov2680.c deleted file mode 100644 index 51b7d61df0f5..000000000000 --- a/drivers/staging/media/atomisp/i2c/ov2680.c +++ /dev/null @@ -1,1557 +0,0 @@ -/* - * Support for OmniVision OV2680 1080p HD camera sensor. - * - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../include/linux/atomisp_gmin_platform.h" - -#include "ov2680.h" - -static int h_flag = 0; -static int v_flag = 0; -static enum atomisp_bayer_order ov2680_bayer_order_mapping[] = { - atomisp_bayer_order_bggr, - atomisp_bayer_order_grbg, - atomisp_bayer_order_gbrg, - atomisp_bayer_order_rggb, -}; - -/* i2c read/write stuff */ -static int ov2680_read_reg(struct i2c_client *client, - u16 data_length, u16 reg, u16 *val) -{ - int err; - struct i2c_msg msg[2]; - unsigned char data[6]; - - if (!client->adapter) { - dev_err(&client->dev, "%s error, no client->adapter\n", - __func__); - return -ENODEV; - } - - if (data_length != OV2680_8BIT && data_length != OV2680_16BIT - && data_length != OV2680_32BIT) { - dev_err(&client->dev, "%s error, invalid data length\n", - __func__); - return -EINVAL; - } - - memset(msg, 0 , sizeof(msg)); - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = I2C_MSG_LENGTH; - msg[0].buf = data; - - /* high byte goes out first */ - data[0] = (u8)(reg >> 8); - data[1] = (u8)(reg & 0xff); - - msg[1].addr = client->addr; - msg[1].len = data_length; - msg[1].flags = I2C_M_RD; - msg[1].buf = data; - - err = i2c_transfer(client->adapter, msg, 2); - if (err != 2) { - if (err >= 0) - err = -EIO; - dev_err(&client->dev, - "read from offset 0x%x error %d", reg, err); - return err; - } - - *val = 0; - /* high byte comes first */ - if (data_length == OV2680_8BIT) - *val = (u8)data[0]; - else if (data_length == OV2680_16BIT) - *val = be16_to_cpu(*(u16 *)&data[0]); - else - *val = be32_to_cpu(*(u32 *)&data[0]); - //dev_dbg(&client->dev, "++++i2c read adr%x = %x\n", reg,*val); - return 0; -} - -static int ov2680_i2c_write(struct i2c_client *client, u16 len, u8 *data) -{ - struct i2c_msg msg; - const int num_msg = 1; - int ret; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = len; - msg.buf = data; - ret = i2c_transfer(client->adapter, &msg, 1); - //dev_dbg(&client->dev, "+++i2c write reg=%x->%x\n", data[0]*256 +data[1],data[2]); - return ret == num_msg ? 0 : -EIO; -} - -static int ov2680_write_reg(struct i2c_client *client, u16 data_length, - u16 reg, u16 val) -{ - int ret; - unsigned char data[4] = {0}; - u16 *wreg = (u16 *)data; - const u16 len = data_length + sizeof(u16); /* 16-bit address + data */ - - if (data_length != OV2680_8BIT && data_length != OV2680_16BIT) { - dev_err(&client->dev, - "%s error, invalid data_length\n", __func__); - return -EINVAL; - } - - /* high byte goes out first */ - *wreg = cpu_to_be16(reg); - - if (data_length == OV2680_8BIT) { - data[2] = (u8)(val); - } else { - /* OV2680_16BIT */ - u16 *wdata = (u16 *)&data[2]; - *wdata = cpu_to_be16(val); - } - - ret = ov2680_i2c_write(client, len, data); - if (ret) - dev_err(&client->dev, - "write error: wrote 0x%x to offset 0x%x error %d", - val, reg, ret); - - return ret; -} - -/* - * ov2680_write_reg_array - Initializes a list of OV2680 registers - * @client: i2c driver client structure - * @reglist: list of registers to be written - * - * This function initializes a list of registers. When consecutive addresses - * are found in a row on the list, this function creates a buffer and sends - * consecutive data in a single i2c_transfer(). - * - * __ov2680_flush_reg_array, __ov2680_buf_reg_array() and - * __ov2680_write_reg_is_consecutive() are internal functions to - * ov2680_write_reg_array_fast() and should be not used anywhere else. - * - */ - -static int __ov2680_flush_reg_array(struct i2c_client *client, - struct ov2680_write_ctrl *ctrl) -{ - u16 size; - - if (ctrl->index == 0) - return 0; - - size = sizeof(u16) + ctrl->index; /* 16-bit address + data */ - ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr); - ctrl->index = 0; - - return ov2680_i2c_write(client, size, (u8 *)&ctrl->buffer); -} - -static int __ov2680_buf_reg_array(struct i2c_client *client, - struct ov2680_write_ctrl *ctrl, - const struct ov2680_reg *next) -{ - int size; - u16 *data16; - - switch (next->type) { - case OV2680_8BIT: - size = 1; - ctrl->buffer.data[ctrl->index] = (u8)next->val; - break; - case OV2680_16BIT: - size = 2; - data16 = (u16 *)&ctrl->buffer.data[ctrl->index]; - *data16 = cpu_to_be16((u16)next->val); - break; - default: - return -EINVAL; - } - - /* When first item is added, we need to store its starting address */ - if (ctrl->index == 0) - ctrl->buffer.addr = next->reg; - - ctrl->index += size; - - /* - * Buffer cannot guarantee free space for u32? Better flush it to avoid - * possible lack of memory for next item. - */ - if (ctrl->index + sizeof(u16) >= OV2680_MAX_WRITE_BUF_SIZE) - return __ov2680_flush_reg_array(client, ctrl); - - return 0; -} - -static int __ov2680_write_reg_is_consecutive(struct i2c_client *client, - struct ov2680_write_ctrl *ctrl, - const struct ov2680_reg *next) -{ - if (ctrl->index == 0) - return 1; - - return ctrl->buffer.addr + ctrl->index == next->reg; -} - -static int ov2680_write_reg_array(struct i2c_client *client, - const struct ov2680_reg *reglist) -{ - const struct ov2680_reg *next = reglist; - struct ov2680_write_ctrl ctrl; - int err; - dev_dbg(&client->dev, "++++write reg array\n"); - ctrl.index = 0; - for (; next->type != OV2680_TOK_TERM; next++) { - switch (next->type & OV2680_TOK_MASK) { - case OV2680_TOK_DELAY: - err = __ov2680_flush_reg_array(client, &ctrl); - if (err) - return err; - msleep(next->val); - break; - default: - /* - * If next address is not consecutive, data needs to be - * flushed before proceed. - */ - dev_dbg(&client->dev, "+++ov2680_write_reg_array reg=%x->%x\n", next->reg,next->val); - if (!__ov2680_write_reg_is_consecutive(client, &ctrl, - next)) { - err = __ov2680_flush_reg_array(client, &ctrl); - if (err) - return err; - } - err = __ov2680_buf_reg_array(client, &ctrl, next); - if (err) { - dev_err(&client->dev, "%s: write error, aborted\n", - __func__); - return err; - } - break; - } - } - - return __ov2680_flush_reg_array(client, &ctrl); -} -static int ov2680_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - - *val = (OV2680_FOCAL_LENGTH_NUM << 16) | OV2680_FOCAL_LENGTH_DEM; - return 0; -} - -static int ov2680_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /*const f number for ov2680*/ - - *val = (OV2680_F_NUMBER_DEFAULT_NUM << 16) | OV2680_F_NUMBER_DEM; - return 0; -} - -static int ov2680_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV2680_F_NUMBER_DEFAULT_NUM << 24) | - (OV2680_F_NUMBER_DEM << 16) | - (OV2680_F_NUMBER_DEFAULT_NUM << 8) | OV2680_F_NUMBER_DEM; - return 0; -} - -static int ov2680_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - dev_dbg(&client->dev, "++++ov2680_g_bin_factor_x\n"); - *val = ov2680_res[dev->fmt_idx].bin_factor_x; - - return 0; -} - -static int ov2680_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - *val = ov2680_res[dev->fmt_idx].bin_factor_y; - dev_dbg(&client->dev, "++++ov2680_g_bin_factor_y\n"); - return 0; -} - - -static int ov2680_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct ov2680_resolution *res) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct atomisp_sensor_mode_data *buf = &info->data; - unsigned int pix_clk_freq_hz; - u16 reg_val; - int ret; - dev_dbg(&client->dev, "++++ov2680_get_intg_factor\n"); - if (!info) - return -EINVAL; - - /* pixel clock */ - pix_clk_freq_hz = res->pix_clk_freq * 1000000; - - dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - - /* get integration time */ - buf->coarse_integration_time_min = OV2680_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - OV2680_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = OV2680_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - OV2680_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = OV2680_FINE_INTG_TIME_MIN; - buf->frame_length_lines = res->lines_per_frame; - buf->line_length_pck = res->pixels_per_line; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - ret = ov2680_read_reg(client, OV2680_16BIT, - OV2680_HORIZONTAL_START_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = reg_val; - - ret = ov2680_read_reg(client, OV2680_16BIT, - OV2680_VERTICAL_START_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = reg_val; - - ret = ov2680_read_reg(client, OV2680_16BIT, - OV2680_HORIZONTAL_END_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_end = reg_val; - - ret = ov2680_read_reg(client, OV2680_16BIT, - OV2680_VERTICAL_END_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_end = reg_val; - - ret = ov2680_read_reg(client, OV2680_16BIT, - OV2680_HORIZONTAL_OUTPUT_SIZE_H, ®_val); - if (ret) - return ret; - buf->output_width = reg_val; - - ret = ov2680_read_reg(client, OV2680_16BIT, - OV2680_VERTICAL_OUTPUT_SIZE_H, ®_val); - if (ret) - return ret; - buf->output_height = reg_val; - - buf->binning_factor_x = res->bin_factor_x ? - (res->bin_factor_x * 2) : 1; - buf->binning_factor_y = res->bin_factor_y ? - (res->bin_factor_y * 2) : 1; - return 0; -} - -static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, - int gain, int digitgain) - -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov2680_device *dev = to_ov2680_sensor(sd); - u16 vts,hts; - int ret,exp_val; - - dev_dbg(&client->dev, "+++++++__ov2680_set_exposure coarse_itg %d, gain %d, digitgain %d++\n",coarse_itg, gain, digitgain); - - hts = ov2680_res[dev->fmt_idx].pixels_per_line; - vts = ov2680_res[dev->fmt_idx].lines_per_frame; - - /* group hold */ - ret = ov2680_write_reg(client, OV2680_8BIT, - OV2680_GROUP_ACCESS, 0x00); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV2680_GROUP_ACCESS); - return ret; - } - - /* Increase the VTS to match exposure + MARGIN */ - if (coarse_itg > vts - OV2680_INTEGRATION_TIME_MARGIN) - vts = (u16) coarse_itg + OV2680_INTEGRATION_TIME_MARGIN; - - ret = ov2680_write_reg(client, OV2680_16BIT, OV2680_TIMING_VTS_H, vts); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV2680_TIMING_VTS_H); - return ret; - } - - /* set exposure */ - - /* Lower four bit should be 0*/ - exp_val = coarse_itg << 4; - ret = ov2680_write_reg(client, OV2680_8BIT, - OV2680_EXPOSURE_L, exp_val & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV2680_EXPOSURE_L); - return ret; - } - - ret = ov2680_write_reg(client, OV2680_8BIT, - OV2680_EXPOSURE_M, (exp_val >> 8) & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV2680_EXPOSURE_M); - return ret; - } - - ret = ov2680_write_reg(client, OV2680_8BIT, - OV2680_EXPOSURE_H, (exp_val >> 16) & 0x0F); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV2680_EXPOSURE_H); - return ret; - } - - /* Analog gain */ - ret = ov2680_write_reg(client, OV2680_16BIT, OV2680_AGC_H, gain); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV2680_AGC_H); - return ret; - } - /* Digital gain */ - if (digitgain) { - ret = ov2680_write_reg(client, OV2680_16BIT, - OV2680_MWB_RED_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV2680_MWB_RED_GAIN_H); - return ret; - } - - ret = ov2680_write_reg(client, OV2680_16BIT, - OV2680_MWB_GREEN_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV2680_MWB_RED_GAIN_H); - return ret; - } - - ret = ov2680_write_reg(client, OV2680_16BIT, - OV2680_MWB_BLUE_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV2680_MWB_RED_GAIN_H); - return ret; - } - } - - /* End group */ - ret = ov2680_write_reg(client, OV2680_8BIT, - OV2680_GROUP_ACCESS, 0x10); - if (ret) - return ret; - - /* Delay launch group */ - ret = ov2680_write_reg(client, OV2680_8BIT, - OV2680_GROUP_ACCESS, 0xa0); - if (ret) - return ret; - return ret; -} - -static int ov2680_set_exposure(struct v4l2_subdev *sd, int exposure, - int gain, int digitgain) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - int ret; - - mutex_lock(&dev->input_lock); - ret = __ov2680_set_exposure(sd, exposure, gain, digitgain); - mutex_unlock(&dev->input_lock); - - return ret; -} - -static long ov2680_s_exposure(struct v4l2_subdev *sd, - struct atomisp_exposure *exposure) -{ - u16 coarse_itg = exposure->integration_time[0]; - u16 analog_gain = exposure->gain[0]; - u16 digital_gain = exposure->gain[1]; - - /* we should not accept the invalid value below */ - if (analog_gain == 0) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - v4l2_err(client, "%s: invalid value\n", __func__); - return -EINVAL; - } - - // EXPOSURE CONTROL DISABLED FOR INITIAL CHECKIN, TUNING DOESN'T WORK - return ov2680_set_exposure(sd, coarse_itg, analog_gain, digital_gain); -} - - - - - -static long ov2680_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - - switch (cmd) { - case ATOMISP_IOC_S_EXPOSURE: - return ov2680_s_exposure(sd, arg); - - default: - return -EINVAL; - } - return 0; -} - -/* This returns the exposure time being used. This should only be used - * for filling in EXIF data, not for actual image processing. - */ -static int ov2680_q_exposure(struct v4l2_subdev *sd, s32 *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 reg_v, reg_v2; - int ret; - - /* get exposure */ - ret = ov2680_read_reg(client, OV2680_8BIT, - OV2680_EXPOSURE_L, - ®_v); - if (ret) - goto err; - - ret = ov2680_read_reg(client, OV2680_8BIT, - OV2680_EXPOSURE_M, - ®_v2); - if (ret) - goto err; - - reg_v += reg_v2 << 8; - ret = ov2680_read_reg(client, OV2680_8BIT, - OV2680_EXPOSURE_H, - ®_v2); - if (ret) - goto err; - - *value = reg_v + (((u32)reg_v2 << 16)); -err: - return ret; -} - -static u32 ov2680_translate_bayer_order(enum atomisp_bayer_order code) -{ - switch (code) { - case atomisp_bayer_order_rggb: - return MEDIA_BUS_FMT_SRGGB10_1X10; - case atomisp_bayer_order_grbg: - return MEDIA_BUS_FMT_SGRBG10_1X10; - case atomisp_bayer_order_bggr: - return MEDIA_BUS_FMT_SBGGR10_1X10; - case atomisp_bayer_order_gbrg: - return MEDIA_BUS_FMT_SGBRG10_1X10; - } - return 0; -} - -static int ov2680_v_flip(struct v4l2_subdev *sd, s32 value) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct camera_mipi_info *ov2680_info = NULL; - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u16 val; - u8 index; - dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value); - ret = ov2680_read_reg(client, OV2680_8BIT, OV2680_FLIP_REG, &val); - if (ret) - return ret; - if (value) { - val |= OV2680_FLIP_MIRROR_BIT_ENABLE; - } else { - val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE; - } - ret = ov2680_write_reg(client, OV2680_8BIT, - OV2680_FLIP_REG, val); - if (ret) - return ret; - index = (v_flag>0?OV2680_FLIP_BIT:0) | (h_flag>0?OV2680_MIRROR_BIT:0); - ov2680_info = v4l2_get_subdev_hostdata(sd); - if (ov2680_info) { - ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[index]; - dev->format.code = ov2680_translate_bayer_order( - ov2680_info->raw_bayer_order); - } - return ret; -} - -static int ov2680_h_flip(struct v4l2_subdev *sd, s32 value) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct camera_mipi_info *ov2680_info = NULL; - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u16 val; - u8 index; - dev_dbg(&client->dev, "@%s: value:%d\n", __func__, value); - - ret = ov2680_read_reg(client, OV2680_8BIT, OV2680_MIRROR_REG, &val); - if (ret) - return ret; - if (value) { - val |= OV2680_FLIP_MIRROR_BIT_ENABLE; - } else { - val &= ~OV2680_FLIP_MIRROR_BIT_ENABLE; - } - ret = ov2680_write_reg(client, OV2680_8BIT, - OV2680_MIRROR_REG, val); - if (ret) - return ret; - index = (v_flag>0?OV2680_FLIP_BIT:0) | (h_flag>0?OV2680_MIRROR_BIT:0); - ov2680_info = v4l2_get_subdev_hostdata(sd); - if (ov2680_info) { - ov2680_info->raw_bayer_order = ov2680_bayer_order_mapping[index]; - dev->format.code = ov2680_translate_bayer_order( - ov2680_info->raw_bayer_order); - } - return ret; -} - -static int ov2680_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov2680_device *dev = - container_of(ctrl->handler, struct ov2680_device, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_VFLIP: - dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n", - __func__, ctrl->val); - ret = ov2680_v_flip(&dev->sd, ctrl->val); - break; - case V4L2_CID_HFLIP: - dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n", - __func__, ctrl->val); - ret = ov2680_h_flip(&dev->sd, ctrl->val); - break; - default: - ret = -EINVAL; - } - return ret; -} - -static int ov2680_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov2680_device *dev = - container_of(ctrl->handler, struct ov2680_device, ctrl_handler); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE_ABSOLUTE: - ret = ov2680_q_exposure(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = ov2680_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = ov2680_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = ov2680_g_fnumber_range(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_HORZ: - ret = ov2680_g_bin_factor_x(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_VERT: - ret = ov2680_g_bin_factor_y(&dev->sd, &ctrl->val); - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .s_ctrl = ov2680_s_ctrl, - .g_volatile_ctrl = ov2680_g_volatile_ctrl -}; - -struct v4l2_ctrl_config ov2680_controls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .min = 0x0, - .max = 0xffff, - .step = 0x01, - .def = 0x00, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = OV2680_FOCAL_LENGTH_DEFAULT, - .max = OV2680_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = OV2680_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = OV2680_F_NUMBER_DEFAULT, - .max = OV2680_F_NUMBER_DEFAULT, - .step = 0x01, - .def = OV2680_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = OV2680_F_NUMBER_RANGE, - .max = OV2680_F_NUMBER_RANGE, - .step = 0x01, - .def = OV2680_F_NUMBER_RANGE, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_HORZ, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "horizontal binning factor", - .min = 0, - .max = OV2680_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_VERT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vertical binning factor", - .min = 0, - .max = OV2680_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip", - .min = 0, - .max = 1, - .step = 1, - .def = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror", - .min = 0, - .max = 1, - .step = 1, - .def = 0, - }, -}; - -static int ov2680_init_registers(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - ret = ov2680_write_reg(client, OV2680_8BIT, OV2680_SW_RESET, 0x01); - ret |= ov2680_write_reg_array(client, ov2680_global_setting); - - return ret; -} - -static int ov2680_init(struct v4l2_subdev *sd) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - - int ret; - - mutex_lock(&dev->input_lock); - - /* restore settings */ - ov2680_res = ov2680_res_preview; - N_RES = N_RES_PREVIEW; - - ret = ov2680_init_registers(sd); - - mutex_unlock(&dev->input_lock); - - return ret; -} - -static int power_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret = 0; - struct ov2680_device *dev = to_ov2680_sensor(sd); - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->power_ctrl) - return dev->platform_data->power_ctrl(sd, flag); - - if (flag) { - ret |= dev->platform_data->v1p8_ctrl(sd, 1); - ret |= dev->platform_data->v2p8_ctrl(sd, 1); - usleep_range(10000, 15000); - } - - if (!flag || ret) { - ret |= dev->platform_data->v1p8_ctrl(sd, 0); - ret |= dev->platform_data->v2p8_ctrl(sd, 0); - } - return ret; -} - -static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret; - struct ov2680_device *dev = to_ov2680_sensor(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->gpio_ctrl) - return dev->platform_data->gpio_ctrl(sd, flag); - - /* The OV2680 documents only one GPIO input (#XSHUTDN), but - * existing integrations often wire two (reset/power_down) - * because that is the way other sensors work. There is no - * way to tell how it is wired internally, so existing - * firmwares expose both and we drive them symmetrically. */ - if (flag) { - ret = dev->platform_data->gpio0_ctrl(sd, 1); - usleep_range(10000, 15000); - /* Ignore return from second gpio, it may not be there */ - dev->platform_data->gpio1_ctrl(sd, 1); - usleep_range(10000, 15000); - } else { - dev->platform_data->gpio1_ctrl(sd, 0); - ret = dev->platform_data->gpio0_ctrl(sd, 0); - } - return ret; -} - -static int power_up(struct v4l2_subdev *sd) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - - /* power control */ - ret = power_ctrl(sd, 1); - if (ret) - goto fail_power; - - /* according to DS, at least 5ms is needed between DOVDD and PWDN */ - usleep_range(5000, 6000); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 1); - if (ret) { - ret = gpio_ctrl(sd, 1); - if (ret) - goto fail_power; - } - - /* flis clock control */ - ret = dev->platform_data->flisclk_ctrl(sd, 1); - if (ret) - goto fail_clk; - - /* according to DS, 20ms is needed between PWDN and i2c access */ - msleep(20); - - return 0; - -fail_clk: - gpio_ctrl(sd, 0); -fail_power: - power_ctrl(sd, 0); - dev_err(&client->dev, "sensor power-up failed\n"); - - return ret; -} - -static int power_down(struct v4l2_subdev *sd) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - h_flag = 0; - v_flag = 0; - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - - ret = dev->platform_data->flisclk_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "flisclk failed\n"); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 0); - if (ret) { - ret = gpio_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "gpio failed 2\n"); - } - - /* power control */ - ret = power_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "vprog failed.\n"); - - return ret; -} - -static int ov2680_s_power(struct v4l2_subdev *sd, int on) -{ - int ret; - - if (on == 0){ - ret = power_down(sd); - } else { - ret = power_up(sd); - if (!ret) - return ov2680_init(sd); - } - return ret; -} - -/* - * distance - calculate the distance - * @res: resolution - * @w: width - * @h: height - * - * Get the gap between resolution and w/h. - * res->width/height smaller than w/h wouldn't be considered. - * Returns the value of gap or -1 if fail. - */ -#define LARGEST_ALLOWED_RATIO_MISMATCH 600 -static int distance(struct ov2680_resolution *res, u32 w, u32 h) -{ - unsigned int w_ratio = (res->width << 13) / w; - unsigned int h_ratio; - int match; - - if (h == 0) - return -1; - h_ratio = (res->height << 13) / h; - if (h_ratio == 0) - return -1; - match = abs(((w_ratio << 13) / h_ratio) - ((int)8192)); - - - if ((w_ratio < (int)8192) || (h_ratio < (int)8192) || - (match > LARGEST_ALLOWED_RATIO_MISMATCH)) - return -1; - - return w_ratio + h_ratio; -} - -/* Return the nearest higher resolution index */ -static int nearest_resolution_index(int w, int h) -{ - int i; - int idx = -1; - int dist; - int min_dist = INT_MAX; - struct ov2680_resolution *tmp_res = NULL; - - for (i = 0; i < N_RES; i++) { - tmp_res = &ov2680_res[i]; - dist = distance(tmp_res, w, h); - if (dist == -1) - continue; - if (dist < min_dist) { - min_dist = dist; - idx = i; - } - } - - return idx; -} - -static int get_resolution_index(int w, int h) -{ - int i; - - for (i = 0; i < N_RES; i++) { - if (w != ov2680_res[i].width) - continue; - if (h != ov2680_res[i].height) - continue; - - return i; - } - - return -1; -} - -static int ov2680_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_mipi_info *ov2680_info = NULL; - int ret = 0; - int idx = 0; - dev_dbg(&client->dev, "+++++ov2680_s_mbus_fmt+++++l\n"); - if (format->pad) - return -EINVAL; - - if (!fmt) - return -EINVAL; - - ov2680_info = v4l2_get_subdev_hostdata(sd); - if (!ov2680_info) - return -EINVAL; - - mutex_lock(&dev->input_lock); - idx = nearest_resolution_index(fmt->width, fmt->height); - if (idx == -1) { - /* return the largest resolution */ - fmt->width = ov2680_res[N_RES - 1].width; - fmt->height = ov2680_res[N_RES - 1].height; - } else { - fmt->width = ov2680_res[idx].width; - fmt->height = ov2680_res[idx].height; - } - fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; - mutex_unlock(&dev->input_lock); - return 0; - } - dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); - dev_dbg(&client->dev, "+++++get_resolution_index=%d+++++l\n", - dev->fmt_idx); - if (dev->fmt_idx == -1) { - dev_err(&client->dev, "get resolution fail\n"); - mutex_unlock(&dev->input_lock); - return -EINVAL; - } - v4l2_info(client, "__s_mbus_fmt i=%d, w=%d, h=%d\n", dev->fmt_idx, - fmt->width, fmt->height); - dev_dbg(&client->dev, "__s_mbus_fmt i=%d, w=%d, h=%d\n", - dev->fmt_idx, fmt->width, fmt->height); - - ret = ov2680_write_reg_array(client, ov2680_res[dev->fmt_idx].regs); - if (ret) - dev_err(&client->dev, "ov2680 write resolution register err\n"); - - ret = ov2680_get_intg_factor(client, ov2680_info, - &ov2680_res[dev->fmt_idx]); - if (ret) { - dev_err(&client->dev, "failed to get integration_factor\n"); - goto err; - } - - /*recall flip functions to avoid flip registers - * were overridden by default setting - */ - if (h_flag) - ov2680_h_flip(sd, h_flag); - if (v_flag) - ov2680_v_flip(sd, v_flag); - - v4l2_info(client, "\n%s idx %d \n", __func__, dev->fmt_idx); - - /*ret = startup(sd); - * if (ret) - * dev_err(&client->dev, "ov2680 startup err\n"); - */ -err: - mutex_unlock(&dev->input_lock); - return ret; -} - -static int ov2680_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct ov2680_device *dev = to_ov2680_sensor(sd); - - if (format->pad) - return -EINVAL; - - if (!fmt) - return -EINVAL; - - fmt->width = ov2680_res[dev->fmt_idx].width; - fmt->height = ov2680_res[dev->fmt_idx].height; - fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; - - return 0; -} - -static int ov2680_detect(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - u16 high, low; - int ret; - u16 id; - u8 revision; - - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) - return -ENODEV; - - ret = ov2680_read_reg(client, OV2680_8BIT, - OV2680_SC_CMMN_CHIP_ID_H, &high); - if (ret) { - dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); - return -ENODEV; - } - ret = ov2680_read_reg(client, OV2680_8BIT, - OV2680_SC_CMMN_CHIP_ID_L, &low); - id = ((((u16) high) << 8) | (u16) low); - - if (id != OV2680_ID) { - dev_err(&client->dev, "sensor ID error 0x%x\n", id); - return -ENODEV; - } - - ret = ov2680_read_reg(client, OV2680_8BIT, - OV2680_SC_CMMN_SUB_ID, &high); - revision = (u8) high & 0x0f; - - dev_info(&client->dev, "sensor_revision id = 0x%x\n", id); - - return 0; -} - -static int ov2680_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - mutex_lock(&dev->input_lock); - if(enable ) - dev_dbg(&client->dev, "ov2680_s_stream one \n"); - else - dev_dbg(&client->dev, "ov2680_s_stream off \n"); - - ret = ov2680_write_reg(client, OV2680_8BIT, OV2680_SW_STREAM, - enable ? OV2680_START_STREAMING : - OV2680_STOP_STREAMING); -#if 0 - /* restore settings */ - ov2680_res = ov2680_res_preview; - N_RES = N_RES_PREVIEW; -#endif - - //otp valid at stream on state - //if(!dev->otp_data) - // dev->otp_data = ov2680_otp_read(sd); - - mutex_unlock(&dev->input_lock); - - return ret; -} - - -static int ov2680_s_config(struct v4l2_subdev *sd, - int irq, void *platform_data) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - if (!platform_data) - return -ENODEV; - - dev->platform_data = - (struct camera_sensor_platform_data *)platform_data; - - mutex_lock(&dev->input_lock); - /* power off the module, then power on it in future - * as first power on by board may not fulfill the - * power on sequqence needed by the module - */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "ov2680 power-off err.\n"); - goto fail_power_off; - } - - ret = power_up(sd); - if (ret) { - dev_err(&client->dev, "ov2680 power-up err.\n"); - goto fail_power_on; - } - - ret = dev->platform_data->csi_cfg(sd, 1); - if (ret) - goto fail_csi_cfg; - - /* config & detect sensor */ - ret = ov2680_detect(client); - if (ret) { - dev_err(&client->dev, "ov2680_detect err s_config.\n"); - goto fail_csi_cfg; - } - - /* turn off sensor, after probed */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "ov2680 power-off err.\n"); - goto fail_csi_cfg; - } - mutex_unlock(&dev->input_lock); - - return 0; - -fail_csi_cfg: - dev->platform_data->csi_cfg(sd, 0); -fail_power_on: - power_down(sd); - dev_err(&client->dev, "sensor power-gating failed\n"); -fail_power_off: - mutex_unlock(&dev->input_lock); - return ret; -} - -static int ov2680_g_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!param) - return -EINVAL; - - if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&client->dev, "unsupported buffer type.\n"); - return -EINVAL; - } - - memset(param, 0, sizeof(*param)); - param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { - param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - param->parm.capture.timeperframe.numerator = 1; - param->parm.capture.capturemode = dev->run_mode; - param->parm.capture.timeperframe.denominator = - ov2680_res[dev->fmt_idx].fps; - } - return 0; -} - -static int ov2680_s_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - dev->run_mode = param->parm.capture.capturemode; - - v4l2_info(client, "\n%s:run_mode :%x\n", __func__, dev->run_mode); - - mutex_lock(&dev->input_lock); - switch (dev->run_mode) { - case CI_MODE_VIDEO: - ov2680_res = ov2680_res_video; - N_RES = N_RES_VIDEO; - break; - case CI_MODE_STILL_CAPTURE: - ov2680_res = ov2680_res_still; - N_RES = N_RES_STILL; - break; - default: - ov2680_res = ov2680_res_preview; - N_RES = N_RES_PREVIEW; - } - mutex_unlock(&dev->input_lock); - return 0; -} - -static int ov2680_g_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - - interval->interval.numerator = 1; - interval->interval.denominator = ov2680_res[dev->fmt_idx].fps; - - return 0; -} - -static int ov2680_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->index >= MAX_FMTS) - return -EINVAL; - - code->code = MEDIA_BUS_FMT_SBGGR10_1X10; - return 0; -} - -static int ov2680_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - int index = fse->index; - - if (index >= N_RES) - return -EINVAL; - - fse->min_width = ov2680_res[index].width; - fse->min_height = ov2680_res[index].height; - fse->max_width = ov2680_res[index].width; - fse->max_height = ov2680_res[index].height; - - return 0; - -} - -static int ov2680_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) -{ - struct ov2680_device *dev = to_ov2680_sensor(sd); - - mutex_lock(&dev->input_lock); - *frames = ov2680_res[dev->fmt_idx].skip_frames; - mutex_unlock(&dev->input_lock); - - return 0; -} - -static const struct v4l2_subdev_video_ops ov2680_video_ops = { - .s_stream = ov2680_s_stream, - .g_parm = ov2680_g_parm, - .s_parm = ov2680_s_parm, - .g_frame_interval = ov2680_g_frame_interval, -}; - -static const struct v4l2_subdev_sensor_ops ov2680_sensor_ops = { - .g_skip_frames = ov2680_g_skip_frames, -}; - -static const struct v4l2_subdev_core_ops ov2680_core_ops = { - .s_power = ov2680_s_power, - .ioctl = ov2680_ioctl, -}; - -static const struct v4l2_subdev_pad_ops ov2680_pad_ops = { - .enum_mbus_code = ov2680_enum_mbus_code, - .enum_frame_size = ov2680_enum_frame_size, - .get_fmt = ov2680_get_fmt, - .set_fmt = ov2680_set_fmt, -}; - -static const struct v4l2_subdev_ops ov2680_ops = { - .core = &ov2680_core_ops, - .video = &ov2680_video_ops, - .pad = &ov2680_pad_ops, - .sensor = &ov2680_sensor_ops, -}; - -static int ov2680_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov2680_device *dev = to_ov2680_sensor(sd); - dev_dbg(&client->dev, "ov2680_remove...\n"); - - dev->platform_data->csi_cfg(sd, 0); - - v4l2_device_unregister_subdev(sd); - media_entity_cleanup(&dev->sd.entity); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - kfree(dev); - - return 0; -} - -static int ov2680_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct ov2680_device *dev; - int ret; - void *pdata; - unsigned int i; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "out of memory\n"); - return -ENOMEM; - } - - mutex_init(&dev->input_lock); - - dev->fmt_idx = 0; - v4l2_i2c_subdev_init(&(dev->sd), client, &ov2680_ops); - - if (ACPI_COMPANION(&client->dev)) - pdata = gmin_camera_platform_data(&dev->sd, - ATOMISP_INPUT_FORMAT_RAW_10, - atomisp_bayer_order_bggr); - else - pdata = client->dev.platform_data; - - if (!pdata) { - ret = -EINVAL; - goto out_free; - } - - ret = ov2680_s_config(&dev->sd, client->irq, pdata); - if (ret) - goto out_free; - - ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); - if (ret) - goto out_free; - - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - ret = - v4l2_ctrl_handler_init(&dev->ctrl_handler, - ARRAY_SIZE(ov2680_controls)); - if (ret) { - ov2680_remove(client); - return ret; - } - - for (i = 0; i < ARRAY_SIZE(ov2680_controls); i++) - v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov2680_controls[i], - NULL); - - if (dev->ctrl_handler.error) { - ov2680_remove(client); - return dev->ctrl_handler.error; - } - - /* Use same lock for controls as for everything else. */ - dev->ctrl_handler.lock = &dev->input_lock; - dev->sd.ctrl_handler = &dev->ctrl_handler; - - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); - if (ret) - { - ov2680_remove(client); - dev_dbg(&client->dev, "+++ remove ov2680 \n"); - } - return ret; -out_free: - dev_dbg(&client->dev, "+++ out free \n"); - v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); - return ret; -} - -static const struct acpi_device_id ov2680_acpi_match[] = { - {"XXOV2680"}, - {"OVTI2680"}, - {}, -}; -MODULE_DEVICE_TABLE(acpi, ov2680_acpi_match); - - -MODULE_DEVICE_TABLE(i2c, ov2680_id); -static struct i2c_driver ov2680_driver = { - .driver = { - .owner = THIS_MODULE, - .name = OV2680_NAME, - .acpi_match_table = ACPI_PTR(ov2680_acpi_match), - - }, - .probe = ov2680_probe, - .remove = ov2680_remove, - .id_table = ov2680_id, -}; - -static int init_ov2680(void) -{ - return i2c_add_driver(&ov2680_driver); -} - -static void exit_ov2680(void) -{ - - i2c_del_driver(&ov2680_driver); -} - -module_init(init_ov2680); -module_exit(exit_ov2680); - -MODULE_AUTHOR("Jacky Wang "); -MODULE_DESCRIPTION("A low-level driver for OmniVision 2680 sensors"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/staging/media/atomisp/i2c/ov2722.c b/drivers/staging/media/atomisp/i2c/ov2722.c deleted file mode 100644 index 10094ac56561..000000000000 --- a/drivers/staging/media/atomisp/i2c/ov2722.c +++ /dev/null @@ -1,1373 +0,0 @@ -/* - * Support for OmniVision OV2722 1080p HD camera sensor. - * - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../include/linux/atomisp_gmin_platform.h" -#include -#include - -#include "ov2722.h" - -/* i2c read/write stuff */ -static int ov2722_read_reg(struct i2c_client *client, - u16 data_length, u16 reg, u16 *val) -{ - int err; - struct i2c_msg msg[2]; - unsigned char data[6]; - - if (!client->adapter) { - dev_err(&client->dev, "%s error, no client->adapter\n", - __func__); - return -ENODEV; - } - - if (data_length != OV2722_8BIT && data_length != OV2722_16BIT - && data_length != OV2722_32BIT) { - dev_err(&client->dev, "%s error, invalid data length\n", - __func__); - return -EINVAL; - } - - memset(msg, 0 , sizeof(msg)); - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = I2C_MSG_LENGTH; - msg[0].buf = data; - - /* high byte goes out first */ - data[0] = (u8)(reg >> 8); - data[1] = (u8)(reg & 0xff); - - msg[1].addr = client->addr; - msg[1].len = data_length; - msg[1].flags = I2C_M_RD; - msg[1].buf = data; - - err = i2c_transfer(client->adapter, msg, 2); - if (err != 2) { - if (err >= 0) - err = -EIO; - dev_err(&client->dev, - "read from offset 0x%x error %d", reg, err); - return err; - } - - *val = 0; - /* high byte comes first */ - if (data_length == OV2722_8BIT) - *val = (u8)data[0]; - else if (data_length == OV2722_16BIT) - *val = be16_to_cpu(*(u16 *)&data[0]); - else - *val = be32_to_cpu(*(u32 *)&data[0]); - - return 0; -} - -static int ov2722_i2c_write(struct i2c_client *client, u16 len, u8 *data) -{ - struct i2c_msg msg; - const int num_msg = 1; - int ret; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = len; - msg.buf = data; - ret = i2c_transfer(client->adapter, &msg, 1); - - return ret == num_msg ? 0 : -EIO; -} - -static int ov2722_write_reg(struct i2c_client *client, u16 data_length, - u16 reg, u16 val) -{ - int ret; - unsigned char data[4] = {0}; - u16 *wreg = (u16 *)data; - const u16 len = data_length + sizeof(u16); /* 16-bit address + data */ - - if (data_length != OV2722_8BIT && data_length != OV2722_16BIT) { - dev_err(&client->dev, - "%s error, invalid data_length\n", __func__); - return -EINVAL; - } - - /* high byte goes out first */ - *wreg = cpu_to_be16(reg); - - if (data_length == OV2722_8BIT) { - data[2] = (u8)(val); - } else { - /* OV2722_16BIT */ - u16 *wdata = (u16 *)&data[2]; - *wdata = cpu_to_be16(val); - } - - ret = ov2722_i2c_write(client, len, data); - if (ret) - dev_err(&client->dev, - "write error: wrote 0x%x to offset 0x%x error %d", - val, reg, ret); - - return ret; -} - -/* - * ov2722_write_reg_array - Initializes a list of OV2722 registers - * @client: i2c driver client structure - * @reglist: list of registers to be written - * - * This function initializes a list of registers. When consecutive addresses - * are found in a row on the list, this function creates a buffer and sends - * consecutive data in a single i2c_transfer(). - * - * __ov2722_flush_reg_array, __ov2722_buf_reg_array() and - * __ov2722_write_reg_is_consecutive() are internal functions to - * ov2722_write_reg_array_fast() and should be not used anywhere else. - * - */ - -static int __ov2722_flush_reg_array(struct i2c_client *client, - struct ov2722_write_ctrl *ctrl) -{ - u16 size; - - if (ctrl->index == 0) - return 0; - - size = sizeof(u16) + ctrl->index; /* 16-bit address + data */ - ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr); - ctrl->index = 0; - - return ov2722_i2c_write(client, size, (u8 *)&ctrl->buffer); -} - -static int __ov2722_buf_reg_array(struct i2c_client *client, - struct ov2722_write_ctrl *ctrl, - const struct ov2722_reg *next) -{ - int size; - u16 *data16; - - switch (next->type) { - case OV2722_8BIT: - size = 1; - ctrl->buffer.data[ctrl->index] = (u8)next->val; - break; - case OV2722_16BIT: - size = 2; - data16 = (u16 *)&ctrl->buffer.data[ctrl->index]; - *data16 = cpu_to_be16((u16)next->val); - break; - default: - return -EINVAL; - } - - /* When first item is added, we need to store its starting address */ - if (ctrl->index == 0) - ctrl->buffer.addr = next->reg; - - ctrl->index += size; - - /* - * Buffer cannot guarantee free space for u32? Better flush it to avoid - * possible lack of memory for next item. - */ - if (ctrl->index + sizeof(u16) >= OV2722_MAX_WRITE_BUF_SIZE) - return __ov2722_flush_reg_array(client, ctrl); - - return 0; -} - -static int __ov2722_write_reg_is_consecutive(struct i2c_client *client, - struct ov2722_write_ctrl *ctrl, - const struct ov2722_reg *next) -{ - if (ctrl->index == 0) - return 1; - - return ctrl->buffer.addr + ctrl->index == next->reg; -} - -static int ov2722_write_reg_array(struct i2c_client *client, - const struct ov2722_reg *reglist) -{ - const struct ov2722_reg *next = reglist; - struct ov2722_write_ctrl ctrl; - int err; - - ctrl.index = 0; - for (; next->type != OV2722_TOK_TERM; next++) { - switch (next->type & OV2722_TOK_MASK) { - case OV2722_TOK_DELAY: - err = __ov2722_flush_reg_array(client, &ctrl); - if (err) - return err; - msleep(next->val); - break; - default: - /* - * If next address is not consecutive, data needs to be - * flushed before proceed. - */ - if (!__ov2722_write_reg_is_consecutive(client, &ctrl, - next)) { - err = __ov2722_flush_reg_array(client, &ctrl); - if (err) - return err; - } - err = __ov2722_buf_reg_array(client, &ctrl, next); - if (err) { - dev_err(&client->dev, "%s: write error, aborted\n", - __func__); - return err; - } - break; - } - } - - return __ov2722_flush_reg_array(client, &ctrl); -} -static int ov2722_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV2722_FOCAL_LENGTH_NUM << 16) | OV2722_FOCAL_LENGTH_DEM; - return 0; -} - -static int ov2722_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /*const f number for imx*/ - *val = (OV2722_F_NUMBER_DEFAULT_NUM << 16) | OV2722_F_NUMBER_DEM; - return 0; -} - -static int ov2722_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV2722_F_NUMBER_DEFAULT_NUM << 24) | - (OV2722_F_NUMBER_DEM << 16) | - (OV2722_F_NUMBER_DEFAULT_NUM << 8) | OV2722_F_NUMBER_DEM; - return 0; -} - -static int ov2722_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct ov2722_resolution *res) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov2722_device *dev = NULL; - struct atomisp_sensor_mode_data *buf = &info->data; - const unsigned int ext_clk_freq_hz = 19200000; - const unsigned int pll_invariant_div = 10; - unsigned int pix_clk_freq_hz; - u16 pre_pll_clk_div; - u16 pll_multiplier; - u16 op_pix_clk_div; - u16 reg_val; - int ret; - - if (!info) - return -EINVAL; - - dev = to_ov2722_sensor(sd); - - /* pixel clock calculattion */ - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_PLL_CTRL3, &pre_pll_clk_div); - if (ret) - return ret; - - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_PLL_MULTIPLIER, &pll_multiplier); - if (ret) - return ret; - - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_PLL_DEBUG_OPT, &op_pix_clk_div); - if (ret) - return ret; - - pre_pll_clk_div = (pre_pll_clk_div & 0x70) >> 4; - if (0 == pre_pll_clk_div) - return -EINVAL; - - pll_multiplier = pll_multiplier & 0x7f; - op_pix_clk_div = op_pix_clk_div & 0x03; - pix_clk_freq_hz = ext_clk_freq_hz / pre_pll_clk_div * pll_multiplier - * op_pix_clk_div / pll_invariant_div; - - dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - - /* get integration time */ - buf->coarse_integration_time_min = OV2722_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - OV2722_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = OV2722_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - OV2722_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = OV2722_FINE_INTG_TIME_MIN; - buf->frame_length_lines = res->lines_per_frame; - buf->line_length_pck = res->pixels_per_line; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_H_CROP_START_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = reg_val; - - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_V_CROP_START_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = reg_val; - - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_H_CROP_END_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_end = reg_val; - - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_V_CROP_END_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_end = reg_val; - - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_H_OUTSIZE_H, ®_val); - if (ret) - return ret; - buf->output_width = reg_val; - - ret = ov2722_read_reg(client, OV2722_16BIT, - OV2722_V_OUTSIZE_H, ®_val); - if (ret) - return ret; - buf->output_height = reg_val; - - buf->binning_factor_x = res->bin_factor_x ? - res->bin_factor_x : 1; - buf->binning_factor_y = res->bin_factor_y ? - res->bin_factor_y : 1; - return 0; -} - -static long __ov2722_set_exposure(struct v4l2_subdev *sd, int coarse_itg, - int gain, int digitgain) - -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov2722_device *dev = to_ov2722_sensor(sd); - u16 hts, vts; - int ret; - - dev_dbg(&client->dev, "set_exposure without group hold\n"); - - /* clear VTS_DIFF on manual mode */ - ret = ov2722_write_reg(client, OV2722_16BIT, OV2722_VTS_DIFF_H, 0); - if (ret) - return ret; - - hts = dev->pixels_per_line; - vts = dev->lines_per_frame; - - if ((coarse_itg + OV2722_COARSE_INTG_TIME_MAX_MARGIN) > vts) - vts = coarse_itg + OV2722_COARSE_INTG_TIME_MAX_MARGIN; - - coarse_itg <<= 4; - digitgain <<= 2; - - ret = ov2722_write_reg(client, OV2722_16BIT, - OV2722_VTS_H, vts); - if (ret) - return ret; - - ret = ov2722_write_reg(client, OV2722_16BIT, - OV2722_HTS_H, hts); - if (ret) - return ret; - - /* set exposure */ - ret = ov2722_write_reg(client, OV2722_8BIT, - OV2722_AEC_PK_EXPO_L, - coarse_itg & 0xff); - if (ret) - return ret; - - ret = ov2722_write_reg(client, OV2722_16BIT, - OV2722_AEC_PK_EXPO_H, - (coarse_itg >> 8) & 0xfff); - if (ret) - return ret; - - /* set analog gain */ - ret = ov2722_write_reg(client, OV2722_16BIT, - OV2722_AGC_ADJ_H, gain); - if (ret) - return ret; - - /* set digital gain */ - ret = ov2722_write_reg(client, OV2722_16BIT, - OV2722_MWB_GAIN_R_H, digitgain); - if (ret) - return ret; - - ret = ov2722_write_reg(client, OV2722_16BIT, - OV2722_MWB_GAIN_G_H, digitgain); - if (ret) - return ret; - - ret = ov2722_write_reg(client, OV2722_16BIT, - OV2722_MWB_GAIN_B_H, digitgain); - - return ret; -} - -static int ov2722_set_exposure(struct v4l2_subdev *sd, int exposure, - int gain, int digitgain) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - int ret; - - mutex_lock(&dev->input_lock); - ret = __ov2722_set_exposure(sd, exposure, gain, digitgain); - mutex_unlock(&dev->input_lock); - - return ret; -} - -static long ov2722_s_exposure(struct v4l2_subdev *sd, - struct atomisp_exposure *exposure) -{ - int exp = exposure->integration_time[0]; - int gain = exposure->gain[0]; - int digitgain = exposure->gain[1]; - - /* we should not accept the invalid value below. */ - if (gain == 0) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - v4l2_err(client, "%s: invalid value\n", __func__); - return -EINVAL; - } - - return ov2722_set_exposure(sd, exp, gain, digitgain); -} - -static long ov2722_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - - switch (cmd) { - case ATOMISP_IOC_S_EXPOSURE: - return ov2722_s_exposure(sd, arg); - default: - return -EINVAL; - } - return 0; -} - -/* This returns the exposure time being used. This should only be used - * for filling in EXIF data, not for actual image processing. - */ -static int ov2722_q_exposure(struct v4l2_subdev *sd, s32 *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 reg_v, reg_v2; - int ret; - - /* get exposure */ - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_AEC_PK_EXPO_L, - ®_v); - if (ret) - goto err; - - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_AEC_PK_EXPO_M, - ®_v2); - if (ret) - goto err; - - reg_v += reg_v2 << 8; - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_AEC_PK_EXPO_H, - ®_v2); - if (ret) - goto err; - - *value = reg_v + (((u32)reg_v2 << 16)); -err: - return ret; -} - -static int ov2722_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov2722_device *dev = - container_of(ctrl->handler, struct ov2722_device, ctrl_handler); - int ret = 0; - unsigned int val; - switch (ctrl->id) { - case V4L2_CID_EXPOSURE_ABSOLUTE: - ret = ov2722_q_exposure(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = ov2722_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = ov2722_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = ov2722_g_fnumber_range(&dev->sd, &ctrl->val); - break; - case V4L2_CID_LINK_FREQ: - val = ov2722_res[dev->fmt_idx].mipi_freq; - if (val == 0) - return -EINVAL; - - ctrl->val = val * 1000; /* To Hz */ - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .g_volatile_ctrl = ov2722_g_volatile_ctrl -}; - -struct v4l2_ctrl_config ov2722_controls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .min = 0x0, - .max = 0xffff, - .step = 0x01, - .def = 0x00, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = OV2722_FOCAL_LENGTH_DEFAULT, - .max = OV2722_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = OV2722_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = OV2722_F_NUMBER_DEFAULT, - .max = OV2722_F_NUMBER_DEFAULT, - .step = 0x01, - .def = OV2722_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = OV2722_F_NUMBER_RANGE, - .max = OV2722_F_NUMBER_RANGE, - .step = 0x01, - .def = OV2722_F_NUMBER_RANGE, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_LINK_FREQ, - .name = "Link Frequency", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 1, - .max = 1500000 * 1000, - .step = 1, - .def = 1, - .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY, - }, -}; - -static int ov2722_init(struct v4l2_subdev *sd) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - - mutex_lock(&dev->input_lock); - - /* restore settings */ - ov2722_res = ov2722_res_preview; - N_RES = N_RES_PREVIEW; - - mutex_unlock(&dev->input_lock); - - return 0; -} - -static int power_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret = -1; - struct ov2722_device *dev = to_ov2722_sensor(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->power_ctrl) - return dev->platform_data->power_ctrl(sd, flag); - - if (flag) { - ret = dev->platform_data->v1p8_ctrl(sd, 1); - if (ret == 0) { - ret = dev->platform_data->v2p8_ctrl(sd, 1); - if (ret) - dev->platform_data->v1p8_ctrl(sd, 0); - } - } else { - ret = dev->platform_data->v1p8_ctrl(sd, 0); - ret |= dev->platform_data->v2p8_ctrl(sd, 0); - } - - return ret; -} - -static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - int ret = -1; - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->gpio_ctrl) - return dev->platform_data->gpio_ctrl(sd, flag); - - /* Note: the GPIO order is asymmetric: always RESET# - * before PWDN# when turning it on or off. - */ - ret = dev->platform_data->gpio0_ctrl(sd, flag); - /* - *ov2722 PWDN# active high when pull down,opposite to the convention - */ - ret |= dev->platform_data->gpio1_ctrl(sd, !flag); - return ret; -} - -static int power_up(struct v4l2_subdev *sd) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - - /* power control */ - ret = power_ctrl(sd, 1); - if (ret) - goto fail_power; - - /* according to DS, at least 5ms is needed between DOVDD and PWDN */ - usleep_range(5000, 6000); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 1); - if (ret) { - ret = gpio_ctrl(sd, 0); - if (ret) - goto fail_power; - } - - /* flis clock control */ - ret = dev->platform_data->flisclk_ctrl(sd, 1); - if (ret) - goto fail_clk; - - /* according to DS, 20ms is needed between PWDN and i2c access */ - msleep(20); - - return 0; - -fail_clk: - gpio_ctrl(sd, 0); -fail_power: - power_ctrl(sd, 0); - dev_err(&client->dev, "sensor power-up failed\n"); - - return ret; -} - -static int power_down(struct v4l2_subdev *sd) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - if (!dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - - ret = dev->platform_data->flisclk_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "flisclk failed\n"); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 0); - if (ret) { - ret = gpio_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "gpio failed 2\n"); - } - - /* power control */ - ret = power_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "vprog failed.\n"); - - return ret; -} - -static int ov2722_s_power(struct v4l2_subdev *sd, int on) -{ - int ret; - if (on == 0) - return power_down(sd); - else { - ret = power_up(sd); - if (!ret) - return ov2722_init(sd); - } - return ret; -} - -/* - * distance - calculate the distance - * @res: resolution - * @w: width - * @h: height - * - * Get the gap between resolution and w/h. - * res->width/height smaller than w/h wouldn't be considered. - * Returns the value of gap or -1 if fail. - */ -#define LARGEST_ALLOWED_RATIO_MISMATCH 800 -static int distance(struct ov2722_resolution *res, u32 w, u32 h) -{ - unsigned int w_ratio = (res->width << 13) / w; - unsigned int h_ratio; - int match; - - if (h == 0) - return -1; - h_ratio = (res->height << 13) / h; - if (h_ratio == 0) - return -1; - match = abs(((w_ratio << 13) / h_ratio) - 8192); - - if ((w_ratio < 8192) || (h_ratio < 8192) || - (match > LARGEST_ALLOWED_RATIO_MISMATCH)) - return -1; - - return w_ratio + h_ratio; -} - -/* Return the nearest higher resolution index */ -static int nearest_resolution_index(int w, int h) -{ - int i; - int idx = -1; - int dist; - int min_dist = INT_MAX; - struct ov2722_resolution *tmp_res = NULL; - - for (i = 0; i < N_RES; i++) { - tmp_res = &ov2722_res[i]; - dist = distance(tmp_res, w, h); - if (dist == -1) - continue; - if (dist < min_dist) { - min_dist = dist; - idx = i; - } - } - - return idx; -} - -static int get_resolution_index(int w, int h) -{ - int i; - - for (i = 0; i < N_RES; i++) { - if (w != ov2722_res[i].width) - continue; - if (h != ov2722_res[i].height) - continue; - - return i; - } - - return -1; -} - -/* TODO: remove it. */ -static int startup(struct v4l2_subdev *sd) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - ret = ov2722_write_reg(client, OV2722_8BIT, - OV2722_SW_RESET, 0x01); - if (ret) { - dev_err(&client->dev, "ov2722 reset err.\n"); - return ret; - } - - ret = ov2722_write_reg_array(client, ov2722_res[dev->fmt_idx].regs); - if (ret) { - dev_err(&client->dev, "ov2722 write register err.\n"); - return ret; - } - - return ret; -} - -static int ov2722_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct ov2722_device *dev = to_ov2722_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_mipi_info *ov2722_info = NULL; - int ret = 0; - int idx; - if (format->pad) - return -EINVAL; - if (!fmt) - return -EINVAL; - ov2722_info = v4l2_get_subdev_hostdata(sd); - if (!ov2722_info) - return -EINVAL; - - mutex_lock(&dev->input_lock); - idx = nearest_resolution_index(fmt->width, fmt->height); - if (idx == -1) { - /* return the largest resolution */ - fmt->width = ov2722_res[N_RES - 1].width; - fmt->height = ov2722_res[N_RES - 1].height; - } else { - fmt->width = ov2722_res[idx].width; - fmt->height = ov2722_res[idx].height; - } - fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; - mutex_unlock(&dev->input_lock); - return 0; - } - - dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); - if (dev->fmt_idx == -1) { - dev_err(&client->dev, "get resolution fail\n"); - mutex_unlock(&dev->input_lock); - return -EINVAL; - } - - dev->pixels_per_line = ov2722_res[dev->fmt_idx].pixels_per_line; - dev->lines_per_frame = ov2722_res[dev->fmt_idx].lines_per_frame; - - ret = startup(sd); - if (ret) { - int i = 0; - dev_err(&client->dev, "ov2722 startup err, retry to power up\n"); - for (i = 0; i < OV2722_POWER_UP_RETRY_NUM; i++) { - dev_err(&client->dev, - "ov2722 retry to power up %d/%d times, result: ", - i + 1, OV2722_POWER_UP_RETRY_NUM); - power_down(sd); - ret = power_up(sd); - if (ret) { - dev_err(&client->dev, "power up failed, continue\n"); - continue; - } - ret = startup(sd); - if (ret) { - dev_err(&client->dev, " startup FAILED!\n"); - } else { - dev_err(&client->dev, " startup SUCCESS!\n"); - break; - } - } - if (ret) { - dev_err(&client->dev, "ov2722 startup err\n"); - goto err; - } - } - - ret = ov2722_get_intg_factor(client, ov2722_info, - &ov2722_res[dev->fmt_idx]); - if (ret) - dev_err(&client->dev, "failed to get integration_factor\n"); - -err: - mutex_unlock(&dev->input_lock); - return ret; -} -static int ov2722_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct ov2722_device *dev = to_ov2722_sensor(sd); - - if (format->pad) - return -EINVAL; - if (!fmt) - return -EINVAL; - - fmt->width = ov2722_res[dev->fmt_idx].width; - fmt->height = ov2722_res[dev->fmt_idx].height; - fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; - - return 0; -} - -static int ov2722_detect(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - u16 high, low; - int ret; - u16 id; - u8 revision; - - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) - return -ENODEV; - - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_CHIP_ID_H, &high); - if (ret) { - dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); - return -ENODEV; - } - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_CHIP_ID_L, &low); - id = (high << 8) | low; - - if ((id != OV2722_ID) && (id != OV2720_ID)) { - dev_err(&client->dev, "sensor ID error\n"); - return -ENODEV; - } - - ret = ov2722_read_reg(client, OV2722_8BIT, - OV2722_SC_CMMN_SUB_ID, &high); - revision = (u8) high & 0x0f; - - dev_dbg(&client->dev, "sensor_revision = 0x%x\n", revision); - dev_dbg(&client->dev, "detect ov2722 success\n"); - return 0; -} - -static int ov2722_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - mutex_lock(&dev->input_lock); - - ret = ov2722_write_reg(client, OV2722_8BIT, OV2722_SW_STREAM, - enable ? OV2722_START_STREAMING : - OV2722_STOP_STREAMING); - - mutex_unlock(&dev->input_lock); - return ret; -} - -static int ov2722_s_config(struct v4l2_subdev *sd, - int irq, void *platform_data) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - if (!platform_data) - return -ENODEV; - - dev->platform_data = - (struct camera_sensor_platform_data *)platform_data; - - mutex_lock(&dev->input_lock); - if (dev->platform_data->platform_init) { - ret = dev->platform_data->platform_init(client); - if (ret) { - dev_err(&client->dev, "platform init err\n"); - goto platform_init_failed; - } - } - - /* power off the module, then power on it in future - * as first power on by board may not fulfill the - * power on sequqence needed by the module - */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "ov2722 power-off err.\n"); - goto fail_power_off; - } - - ret = power_up(sd); - if (ret) { - dev_err(&client->dev, "ov2722 power-up err.\n"); - goto fail_power_on; - } - - ret = dev->platform_data->csi_cfg(sd, 1); - if (ret) - goto fail_csi_cfg; - - /* config & detect sensor */ - ret = ov2722_detect(client); - if (ret) { - dev_err(&client->dev, "ov2722_detect err s_config.\n"); - goto fail_csi_cfg; - } - - /* turn off sensor, after probed */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "ov2722 power-off err.\n"); - goto fail_csi_cfg; - } - mutex_unlock(&dev->input_lock); - - return 0; - -fail_csi_cfg: - dev->platform_data->csi_cfg(sd, 0); -fail_power_on: - power_down(sd); - dev_err(&client->dev, "sensor power-gating failed\n"); -fail_power_off: - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); -platform_init_failed: - mutex_unlock(&dev->input_lock); - return ret; -} - -static int ov2722_g_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!param) - return -EINVAL; - - if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&client->dev, "unsupported buffer type.\n"); - return -EINVAL; - } - - memset(param, 0, sizeof(*param)); - param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { - param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - param->parm.capture.timeperframe.numerator = 1; - param->parm.capture.capturemode = dev->run_mode; - param->parm.capture.timeperframe.denominator = - ov2722_res[dev->fmt_idx].fps; - } - return 0; -} - -static int ov2722_s_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - dev->run_mode = param->parm.capture.capturemode; - - mutex_lock(&dev->input_lock); - switch (dev->run_mode) { - case CI_MODE_VIDEO: - ov2722_res = ov2722_res_video; - N_RES = N_RES_VIDEO; - break; - case CI_MODE_STILL_CAPTURE: - ov2722_res = ov2722_res_still; - N_RES = N_RES_STILL; - break; - default: - ov2722_res = ov2722_res_preview; - N_RES = N_RES_PREVIEW; - } - mutex_unlock(&dev->input_lock); - return 0; -} - -static int ov2722_g_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - - interval->interval.numerator = 1; - interval->interval.denominator = ov2722_res[dev->fmt_idx].fps; - - return 0; -} - -static int ov2722_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->index >= MAX_FMTS) - return -EINVAL; - - code->code = MEDIA_BUS_FMT_SBGGR10_1X10; - return 0; -} - -static int ov2722_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - int index = fse->index; - - if (index >= N_RES) - return -EINVAL; - - fse->min_width = ov2722_res[index].width; - fse->min_height = ov2722_res[index].height; - fse->max_width = ov2722_res[index].width; - fse->max_height = ov2722_res[index].height; - - return 0; - -} - - -static int ov2722_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) -{ - struct ov2722_device *dev = to_ov2722_sensor(sd); - - mutex_lock(&dev->input_lock); - *frames = ov2722_res[dev->fmt_idx].skip_frames; - mutex_unlock(&dev->input_lock); - - return 0; -} - -static const struct v4l2_subdev_sensor_ops ov2722_sensor_ops = { - .g_skip_frames = ov2722_g_skip_frames, -}; - -static const struct v4l2_subdev_video_ops ov2722_video_ops = { - .s_stream = ov2722_s_stream, - .g_parm = ov2722_g_parm, - .s_parm = ov2722_s_parm, - .g_frame_interval = ov2722_g_frame_interval, -}; - -static const struct v4l2_subdev_core_ops ov2722_core_ops = { - .s_power = ov2722_s_power, - .ioctl = ov2722_ioctl, -}; - -static const struct v4l2_subdev_pad_ops ov2722_pad_ops = { - .enum_mbus_code = ov2722_enum_mbus_code, - .enum_frame_size = ov2722_enum_frame_size, - .get_fmt = ov2722_get_fmt, - .set_fmt = ov2722_set_fmt, -}; - -static const struct v4l2_subdev_ops ov2722_ops = { - .core = &ov2722_core_ops, - .video = &ov2722_video_ops, - .pad = &ov2722_pad_ops, - .sensor = &ov2722_sensor_ops, -}; - -static int ov2722_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov2722_device *dev = to_ov2722_sensor(sd); - dev_dbg(&client->dev, "ov2722_remove...\n"); - - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); - - dev->platform_data->csi_cfg(sd, 0); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - v4l2_device_unregister_subdev(sd); - - atomisp_gmin_remove_subdev(sd); - - media_entity_cleanup(&dev->sd.entity); - kfree(dev); - - return 0; -} - -static int __ov2722_init_ctrl_handler(struct ov2722_device *dev) -{ - struct v4l2_ctrl_handler *hdl; - unsigned int i; - hdl = &dev->ctrl_handler; - v4l2_ctrl_handler_init(&dev->ctrl_handler, ARRAY_SIZE(ov2722_controls)); - for (i = 0; i < ARRAY_SIZE(ov2722_controls); i++) - v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov2722_controls[i], - NULL); - - dev->link_freq = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_LINK_FREQ); - - if (dev->ctrl_handler.error || !dev->link_freq) - return dev->ctrl_handler.error; - - dev->sd.ctrl_handler = hdl; - - return 0; -} - -static int ov2722_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct ov2722_device *dev; - void *ovpdev; - int ret; - struct acpi_device *adev; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "out of memory\n"); - return -ENOMEM; - } - - mutex_init(&dev->input_lock); - - dev->fmt_idx = 0; - v4l2_i2c_subdev_init(&(dev->sd), client, &ov2722_ops); - - ovpdev = client->dev.platform_data; - adev = ACPI_COMPANION(&client->dev); - if (adev) { - adev->power.flags.power_resources = 0; - ovpdev = gmin_camera_platform_data(&dev->sd, - ATOMISP_INPUT_FORMAT_RAW_10, - atomisp_bayer_order_grbg); - } - - ret = ov2722_s_config(&dev->sd, client->irq, ovpdev); - if (ret) - goto out_free; - - ret = __ov2722_init_ctrl_handler(dev); - if (ret) - goto out_ctrl_handler_free; - - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); - if (ret) - ov2722_remove(client); - - if (ACPI_HANDLE(&client->dev)) - ret = atomisp_register_i2c_module(&dev->sd, ovpdev, RAW_CAMERA); - - return ret; - -out_ctrl_handler_free: - v4l2_ctrl_handler_free(&dev->ctrl_handler); - -out_free: - v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); - return ret; -} - -MODULE_DEVICE_TABLE(i2c, ov2722_id); - -static const struct acpi_device_id ov2722_acpi_match[] = { - { "INT33FB" }, - {}, -}; - -MODULE_DEVICE_TABLE(acpi, ov2722_acpi_match); - -static struct i2c_driver ov2722_driver = { - .driver = { - .name = OV2722_NAME, - .acpi_match_table = ACPI_PTR(ov2722_acpi_match), - }, - .probe = ov2722_probe, - .remove = ov2722_remove, - .id_table = ov2722_id, -}; - -static int init_ov2722(void) -{ - return i2c_add_driver(&ov2722_driver); -} - -static void exit_ov2722(void) -{ - - i2c_del_driver(&ov2722_driver); -} - -module_init(init_ov2722); -module_exit(exit_ov2722); - -MODULE_AUTHOR("Wei Liu "); -MODULE_DESCRIPTION("A low-level driver for OmniVision 2722 sensors"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/ov5693/Kconfig b/drivers/staging/media/atomisp/i2c/ov5693/Kconfig index 9e8d32521e7e..5fe4113bbf08 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/Kconfig +++ b/drivers/staging/media/atomisp/i2c/ov5693/Kconfig @@ -1,4 +1,4 @@ -config VIDEO_OV5693 +config VIDEO_ATOMISP_OV5693 tristate "Omnivision ov5693 sensor support" depends on I2C && VIDEO_V4L2 ---help--- diff --git a/drivers/staging/media/atomisp/i2c/ov5693/Makefile b/drivers/staging/media/atomisp/i2c/ov5693/Makefile index 4e3833aaec05..2de70003658a 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/Makefile +++ b/drivers/staging/media/atomisp/i2c/ov5693/Makefile @@ -1,4 +1,4 @@ -obj-$(CONFIG_VIDEO_OV5693) += ov5693.o +obj-$(CONFIG_VIDEO_ATOMISP_OV5693) += atomisp-ov5693.o # HACK! While this driver is in bad shape, don't enable several warnings # that would be otherwise enabled with W=1 diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c new file mode 100644 index 000000000000..219501167584 --- /dev/null +++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c @@ -0,0 +1,2059 @@ +/* + * Support for OmniVision OV5693 1080p HD camera sensor. + * + * Copyright (c) 2013 Intel Corporation. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../include/linux/atomisp_gmin_platform.h" + +#include "ov5693.h" +#include "ad5823.h" + +#define __cci_delay(t) \ + do { \ + if ((t) < 10) { \ + usleep_range((t) * 1000, ((t) + 1) * 1000); \ + } else { \ + msleep((t)); \ + } \ + } while (0) + +/* Value 30ms reached through experimentation on byt ecs. + * The DS specifies a much lower value but when using a smaller value + * the I2C bus sometimes locks up permanently when starting the camera. + * This issue could not be reproduced on cht, so we can reduce the + * delay value to a lower value when insmod. + */ +static uint up_delay = 30; +module_param(up_delay, uint, 0644); +MODULE_PARM_DESC(up_delay, "Delay prior to the first CCI transaction for ov5693"); + +static int vcm_ad_i2c_wr8(struct i2c_client *client, u8 reg, u8 val) +{ + int err; + struct i2c_msg msg; + u8 buf[2]; + + buf[0] = reg; + buf[1] = val; + + msg.addr = VCM_ADDR; + msg.flags = 0; + msg.len = 2; + msg.buf = &buf[0]; + + err = i2c_transfer(client->adapter, &msg, 1); + if (err != 1) { + dev_err(&client->dev, "%s: vcm i2c fail, err code = %d\n", + __func__, err); + return -EIO; + } + return 0; +} + +static int ad5823_i2c_write(struct i2c_client *client, u8 reg, u8 val) +{ + struct i2c_msg msg; + u8 buf[2]; + buf[0] = reg; + buf[1] = val; + msg.addr = AD5823_VCM_ADDR; + msg.flags = 0; + msg.len = 0x02; + msg.buf = &buf[0]; + + if (i2c_transfer(client->adapter, &msg, 1) != 1) + return -EIO; + return 0; +} + +static int ad5823_i2c_read(struct i2c_client *client, u8 reg, u8 *val) +{ + struct i2c_msg msg[2]; + u8 buf[2]; + buf[0] = reg; + buf[1] = 0; + + msg[0].addr = AD5823_VCM_ADDR; + msg[0].flags = 0; + msg[0].len = 0x01; + msg[0].buf = &buf[0]; + + msg[1].addr = 0x0c; + msg[1].flags = I2C_M_RD; + msg[1].len = 0x01; + msg[1].buf = &buf[1]; + *val = 0; + if (i2c_transfer(client->adapter, msg, 2) != 2) + return -EIO; + *val = buf[1]; + return 0; +} + + +static const uint32_t ov5693_embedded_effective_size = 28; + +/* i2c read/write stuff */ +static int ov5693_read_reg(struct i2c_client *client, + u16 data_length, u16 reg, u16 *val) +{ + int err; + struct i2c_msg msg[2]; + unsigned char data[6]; + + if (!client->adapter) { + dev_err(&client->dev, "%s error, no client->adapter\n", + __func__); + return -ENODEV; + } + + if (data_length != OV5693_8BIT && data_length != OV5693_16BIT + && data_length != OV5693_32BIT) { + dev_err(&client->dev, "%s error, invalid data length\n", + __func__); + return -EINVAL; + } + + memset(msg, 0, sizeof(msg)); + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = I2C_MSG_LENGTH; + msg[0].buf = data; + + /* high byte goes out first */ + data[0] = (u8)(reg >> 8); + data[1] = (u8)(reg & 0xff); + + msg[1].addr = client->addr; + msg[1].len = data_length; + msg[1].flags = I2C_M_RD; + msg[1].buf = data; + + err = i2c_transfer(client->adapter, msg, 2); + if (err != 2) { + if (err >= 0) + err = -EIO; + dev_err(&client->dev, + "read from offset 0x%x error %d", reg, err); + return err; + } + + *val = 0; + /* high byte comes first */ + if (data_length == OV5693_8BIT) + *val = (u8)data[0]; + else if (data_length == OV5693_16BIT) + *val = be16_to_cpu(*(u16 *)&data[0]); + else + *val = be32_to_cpu(*(u32 *)&data[0]); + + return 0; +} + +static int ov5693_i2c_write(struct i2c_client *client, u16 len, u8 *data) +{ + struct i2c_msg msg; + const int num_msg = 1; + int ret; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = len; + msg.buf = data; + ret = i2c_transfer(client->adapter, &msg, 1); + + return ret == num_msg ? 0 : -EIO; +} + +static int vcm_dw_i2c_write(struct i2c_client *client, u16 data) +{ + struct i2c_msg msg; + const int num_msg = 1; + int ret; + u16 val; + + val = cpu_to_be16(data); + msg.addr = VCM_ADDR; + msg.flags = 0; + msg.len = OV5693_16BIT; + msg.buf = (u8 *)&val; + + ret = i2c_transfer(client->adapter, &msg, 1); + + return ret == num_msg ? 0 : -EIO; +} + +/* Theory: per datasheet, the two VCMs both allow for a 2-byte read. + * The DW9714 doesn't actually specify what this does (it has a + * two-byte write-only protocol, but specifies the read sequence as + * legal), but it returns the same data (zeroes) always, after an + * undocumented initial NAK. The AD5823 has a one-byte address + * register to which all writes go, and subsequent reads will cycle + * through the 8 bytes of registers. Notably, the default values (the + * device is always power-cycled affirmatively, so we can rely on + * these) in AD5823 are not pairwise repetitions of the same 16 bit + * word. So all we have to do is sequentially read two bytes at a + * time and see if we detect a difference in any of the first four + * pairs. */ +static int vcm_detect(struct i2c_client *client) +{ + int i, ret; + struct i2c_msg msg; + u16 data0 = 0, data; + for (i = 0; i < 4; i++) { + msg.addr = VCM_ADDR; + msg.flags = I2C_M_RD; + msg.len = sizeof(data); + msg.buf = (u8 *)&data; + ret = i2c_transfer(client->adapter, &msg, 1); + + /* DW9714 always fails the first read and returns + * zeroes for subsequent ones */ + if (i == 0 && ret == -EREMOTEIO) { + data0 = 0; + continue; + } + + if (i == 0) + data0 = data; + + if (data != data0) + return VCM_AD5823; + } + return ret == 1 ? VCM_DW9714 : ret; +} + +static int ov5693_write_reg(struct i2c_client *client, u16 data_length, + u16 reg, u16 val) +{ + int ret; + unsigned char data[4] = {0}; + u16 *wreg = (u16 *)data; + const u16 len = data_length + sizeof(u16); /* 16-bit address + data */ + + if (data_length != OV5693_8BIT && data_length != OV5693_16BIT) { + dev_err(&client->dev, + "%s error, invalid data_length\n", __func__); + return -EINVAL; + } + + /* high byte goes out first */ + *wreg = cpu_to_be16(reg); + + if (data_length == OV5693_8BIT) { + data[2] = (u8)(val); + } else { + /* OV5693_16BIT */ + u16 *wdata = (u16 *)&data[2]; + *wdata = cpu_to_be16(val); + } + + ret = ov5693_i2c_write(client, len, data); + if (ret) + dev_err(&client->dev, + "write error: wrote 0x%x to offset 0x%x error %d", + val, reg, ret); + + return ret; +} + +/* + * ov5693_write_reg_array - Initializes a list of OV5693 registers + * @client: i2c driver client structure + * @reglist: list of registers to be written + * + * This function initializes a list of registers. When consecutive addresses + * are found in a row on the list, this function creates a buffer and sends + * consecutive data in a single i2c_transfer(). + * + * __ov5693_flush_reg_array, __ov5693_buf_reg_array() and + * __ov5693_write_reg_is_consecutive() are internal functions to + * ov5693_write_reg_array_fast() and should be not used anywhere else. + * + */ + +static int __ov5693_flush_reg_array(struct i2c_client *client, + struct ov5693_write_ctrl *ctrl) +{ + u16 size; + + if (ctrl->index == 0) + return 0; + + size = sizeof(u16) + ctrl->index; /* 16-bit address + data */ + ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr); + ctrl->index = 0; + + return ov5693_i2c_write(client, size, (u8 *)&ctrl->buffer); +} + +static int __ov5693_buf_reg_array(struct i2c_client *client, + struct ov5693_write_ctrl *ctrl, + const struct ov5693_reg *next) +{ + int size; + u16 *data16; + + switch (next->type) { + case OV5693_8BIT: + size = 1; + ctrl->buffer.data[ctrl->index] = (u8)next->val; + break; + case OV5693_16BIT: + size = 2; + data16 = (u16 *)&ctrl->buffer.data[ctrl->index]; + *data16 = cpu_to_be16((u16)next->val); + break; + default: + return -EINVAL; + } + + /* When first item is added, we need to store its starting address */ + if (ctrl->index == 0) + ctrl->buffer.addr = next->reg; + + ctrl->index += size; + + /* + * Buffer cannot guarantee free space for u32? Better flush it to avoid + * possible lack of memory for next item. + */ + if (ctrl->index + sizeof(u16) >= OV5693_MAX_WRITE_BUF_SIZE) + return __ov5693_flush_reg_array(client, ctrl); + + return 0; +} + +static int __ov5693_write_reg_is_consecutive(struct i2c_client *client, + struct ov5693_write_ctrl *ctrl, + const struct ov5693_reg *next) +{ + if (ctrl->index == 0) + return 1; + + return ctrl->buffer.addr + ctrl->index == next->reg; +} + +static int ov5693_write_reg_array(struct i2c_client *client, + const struct ov5693_reg *reglist) +{ + const struct ov5693_reg *next = reglist; + struct ov5693_write_ctrl ctrl; + int err; + + ctrl.index = 0; + for (; next->type != OV5693_TOK_TERM; next++) { + switch (next->type & OV5693_TOK_MASK) { + case OV5693_TOK_DELAY: + err = __ov5693_flush_reg_array(client, &ctrl); + if (err) + return err; + msleep(next->val); + break; + default: + /* + * If next address is not consecutive, data needs to be + * flushed before proceed. + */ + if (!__ov5693_write_reg_is_consecutive(client, &ctrl, + next)) { + err = __ov5693_flush_reg_array(client, &ctrl); + if (err) + return err; + } + err = __ov5693_buf_reg_array(client, &ctrl, next); + if (err) { + dev_err(&client->dev, + "%s: write error, aborted\n", + __func__); + return err; + } + break; + } + } + + return __ov5693_flush_reg_array(client, &ctrl); +} +static int ov5693_g_focal(struct v4l2_subdev *sd, s32 *val) +{ + *val = (OV5693_FOCAL_LENGTH_NUM << 16) | OV5693_FOCAL_LENGTH_DEM; + return 0; +} + +static int ov5693_g_fnumber(struct v4l2_subdev *sd, s32 *val) +{ + /*const f number for imx*/ + *val = (OV5693_F_NUMBER_DEFAULT_NUM << 16) | OV5693_F_NUMBER_DEM; + return 0; +} + +static int ov5693_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) +{ + *val = (OV5693_F_NUMBER_DEFAULT_NUM << 24) | + (OV5693_F_NUMBER_DEM << 16) | + (OV5693_F_NUMBER_DEFAULT_NUM << 8) | OV5693_F_NUMBER_DEM; + return 0; +} + +static int ov5693_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + + *val = ov5693_res[dev->fmt_idx].bin_factor_x; + + return 0; +} + +static int ov5693_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + + *val = ov5693_res[dev->fmt_idx].bin_factor_y; + + return 0; +} + +static int ov5693_get_intg_factor(struct i2c_client *client, + struct camera_mipi_info *info, + const struct ov5693_resolution *res) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct atomisp_sensor_mode_data *buf = &info->data; + unsigned int pix_clk_freq_hz; + u16 reg_val; + int ret; + + if (info == NULL) + return -EINVAL; + + /* pixel clock */ + pix_clk_freq_hz = res->pix_clk_freq * 1000000; + + dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz; + buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz; + + /* get integration time */ + buf->coarse_integration_time_min = OV5693_COARSE_INTG_TIME_MIN; + buf->coarse_integration_time_max_margin = + OV5693_COARSE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_min = OV5693_FINE_INTG_TIME_MIN; + buf->fine_integration_time_max_margin = + OV5693_FINE_INTG_TIME_MAX_MARGIN; + + buf->fine_integration_time_def = OV5693_FINE_INTG_TIME_MIN; + buf->frame_length_lines = res->lines_per_frame; + buf->line_length_pck = res->pixels_per_line; + buf->read_mode = res->bin_mode; + + /* get the cropping and output resolution to ISP for this mode. */ + ret = ov5693_read_reg(client, OV5693_16BIT, + OV5693_HORIZONTAL_START_H, ®_val); + if (ret) + return ret; + buf->crop_horizontal_start = reg_val; + + ret = ov5693_read_reg(client, OV5693_16BIT, + OV5693_VERTICAL_START_H, ®_val); + if (ret) + return ret; + buf->crop_vertical_start = reg_val; + + ret = ov5693_read_reg(client, OV5693_16BIT, + OV5693_HORIZONTAL_END_H, ®_val); + if (ret) + return ret; + buf->crop_horizontal_end = reg_val; + + ret = ov5693_read_reg(client, OV5693_16BIT, + OV5693_VERTICAL_END_H, ®_val); + if (ret) + return ret; + buf->crop_vertical_end = reg_val; + + ret = ov5693_read_reg(client, OV5693_16BIT, + OV5693_HORIZONTAL_OUTPUT_SIZE_H, ®_val); + if (ret) + return ret; + buf->output_width = reg_val; + + ret = ov5693_read_reg(client, OV5693_16BIT, + OV5693_VERTICAL_OUTPUT_SIZE_H, ®_val); + if (ret) + return ret; + buf->output_height = reg_val; + + buf->binning_factor_x = res->bin_factor_x ? + res->bin_factor_x : 1; + buf->binning_factor_y = res->bin_factor_y ? + res->bin_factor_y : 1; + return 0; +} + +static long __ov5693_set_exposure(struct v4l2_subdev *sd, int coarse_itg, + int gain, int digitgain) + +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5693_device *dev = to_ov5693_sensor(sd); + u16 vts, hts; + int ret, exp_val; + + hts = ov5693_res[dev->fmt_idx].pixels_per_line; + vts = ov5693_res[dev->fmt_idx].lines_per_frame; + /*If coarse_itg is larger than 1<<15, can not write to reg directly. + The way is to write coarse_itg/2 to the reg, meanwhile write 2*hts + to the reg. */ + if (coarse_itg > (1 << 15)) { + hts = hts * 2; + coarse_itg = (int)coarse_itg / 2; + } + /* group hold */ + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_GROUP_ACCESS, 0x00); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_GROUP_ACCESS); + return ret; + } + + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_TIMING_HTS_H, (hts >> 8) & 0xFF); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_TIMING_HTS_H); + return ret; + } + + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_TIMING_HTS_L, hts & 0xFF); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_TIMING_HTS_L); + return ret; + } + /* Increase the VTS to match exposure + MARGIN */ + if (coarse_itg > vts - OV5693_INTEGRATION_TIME_MARGIN) + vts = (u16) coarse_itg + OV5693_INTEGRATION_TIME_MARGIN; + + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_TIMING_VTS_H, (vts >> 8) & 0xFF); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_TIMING_VTS_H); + return ret; + } + + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_TIMING_VTS_L, vts & 0xFF); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_TIMING_VTS_L); + return ret; + } + + /* set exposure */ + + /* Lower four bit should be 0*/ + exp_val = coarse_itg << 4; + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_EXPOSURE_L, exp_val & 0xFF); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_EXPOSURE_L); + return ret; + } + + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_EXPOSURE_M, (exp_val >> 8) & 0xFF); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_EXPOSURE_M); + return ret; + } + + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_EXPOSURE_H, (exp_val >> 16) & 0x0F); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_EXPOSURE_H); + return ret; + } + + /* Analog gain */ + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_AGC_L, gain & 0xff); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_AGC_L); + return ret; + } + + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_AGC_H, (gain >> 8) & 0xff); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_AGC_H); + return ret; + } + + /* Digital gain */ + if (digitgain) { + ret = ov5693_write_reg(client, OV5693_16BIT, + OV5693_MWB_RED_GAIN_H, digitgain); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_MWB_RED_GAIN_H); + return ret; + } + + ret = ov5693_write_reg(client, OV5693_16BIT, + OV5693_MWB_GREEN_GAIN_H, digitgain); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_MWB_RED_GAIN_H); + return ret; + } + + ret = ov5693_write_reg(client, OV5693_16BIT, + OV5693_MWB_BLUE_GAIN_H, digitgain); + if (ret) { + dev_err(&client->dev, "%s: write %x error, aborted\n", + __func__, OV5693_MWB_RED_GAIN_H); + return ret; + } + } + + /* End group */ + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_GROUP_ACCESS, 0x10); + if (ret) + return ret; + + /* Delay launch group */ + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_GROUP_ACCESS, 0xa0); + if (ret) + return ret; + return ret; +} + +static int ov5693_set_exposure(struct v4l2_subdev *sd, int exposure, + int gain, int digitgain) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + int ret; + + mutex_lock(&dev->input_lock); + ret = __ov5693_set_exposure(sd, exposure, gain, digitgain); + mutex_unlock(&dev->input_lock); + + return ret; +} + +static long ov5693_s_exposure(struct v4l2_subdev *sd, + struct atomisp_exposure *exposure) +{ + u16 coarse_itg = exposure->integration_time[0]; + u16 analog_gain = exposure->gain[0]; + u16 digital_gain = exposure->gain[1]; + + /* we should not accept the invalid value below */ + if (analog_gain == 0) { + struct i2c_client *client = v4l2_get_subdevdata(sd); + v4l2_err(client, "%s: invalid value\n", __func__); + return -EINVAL; + } + return ov5693_set_exposure(sd, coarse_itg, analog_gain, digital_gain); +} + +static int ov5693_read_otp_reg_array(struct i2c_client *client, u16 size, + u16 addr, u8 *buf) +{ + u16 index; + int ret; + u16 *pVal = NULL; + + for (index = 0; index <= size; index++) { + pVal = (u16 *) (buf + index); + ret = + ov5693_read_reg(client, OV5693_8BIT, addr + index, + pVal); + if (ret) + return ret; + } + + return 0; +} + +static int __ov5693_otp_read(struct v4l2_subdev *sd, u8 *buf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5693_device *dev = to_ov5693_sensor(sd); + int ret; + int i; + u8 *b = buf; + dev->otp_size = 0; + for (i = 1; i < OV5693_OTP_BANK_MAX; i++) { + /*set bank NO and OTP read mode. */ + ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_BANK_REG, (i | 0xc0)); //[7:6] 2'b11 [5:0] bank no + if (ret) { + dev_err(&client->dev, "failed to prepare OTP page\n"); + return ret; + } + //pr_debug("write 0x%x->0x%x\n",OV5693_OTP_BANK_REG,(i|0xc0)); + + /*enable read */ + ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_READ_REG, OV5693_OTP_MODE_READ); // enable :1 + if (ret) { + dev_err(&client->dev, + "failed to set OTP reading mode page"); + return ret; + } + //pr_debug("write 0x%x->0x%x\n",OV5693_OTP_READ_REG,OV5693_OTP_MODE_READ); + + /* Reading the OTP data array */ + ret = ov5693_read_otp_reg_array(client, OV5693_OTP_BANK_SIZE, + OV5693_OTP_START_ADDR, + b); + if (ret) { + dev_err(&client->dev, "failed to read OTP data\n"); + return ret; + } + + //pr_debug("BANK[%2d] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", i, *b, *(b+1), *(b+2), *(b+3), *(b+4), *(b+5), *(b+6), *(b+7), *(b+8), *(b+9), *(b+10), *(b+11), *(b+12), *(b+13), *(b+14), *(b+15)); + + //Intel OTP map, try to read 320byts first. + if (21 == i) { + if ((*b) == 0) { + dev->otp_size = 320; + break; + } else { + b = buf; + continue; + } + } else if (24 == i) { //if the first 320bytes data doesn't not exist, try to read the next 32bytes data. + if ((*b) == 0) { + dev->otp_size = 32; + break; + } else { + b = buf; + continue; + } + } else if (27 == i) { //if the prvious 32bytes data doesn't exist, try to read the next 32bytes data again. + if ((*b) == 0) { + dev->otp_size = 32; + break; + } else { + dev->otp_size = 0; // no OTP data. + break; + } + } + + b = b + OV5693_OTP_BANK_SIZE; + } + return 0; +} + +/* + * Read otp data and store it into a kmalloced buffer. + * The caller must kfree the buffer when no more needed. + * @size: set to the size of the returned otp data. + */ +static void *ov5693_otp_read(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u8 *buf; + int ret; + + buf = devm_kzalloc(&client->dev, (OV5693_OTP_DATA_SIZE + 16), GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + + //otp valid after mipi on and sw stream on + ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_FRAME_OFF_NUM, 0x00); + + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_SW_STREAM, OV5693_START_STREAMING); + + ret = __ov5693_otp_read(sd, buf); + + //mipi off and sw stream off after otp read + ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_FRAME_OFF_NUM, 0x0f); + + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_SW_STREAM, OV5693_STOP_STREAMING); + + /* Driver has failed to find valid data */ + if (ret) { + dev_err(&client->dev, "sensor found no valid OTP data\n"); + return ERR_PTR(ret); + } + + return buf; +} + +static int ov5693_g_priv_int_data(struct v4l2_subdev *sd, + struct v4l2_private_int_data *priv) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov5693_device *dev = to_ov5693_sensor(sd); + u8 __user *to = priv->data; + u32 read_size = priv->size; + int ret; + + /* No need to copy data if size is 0 */ + if (!read_size) + goto out; + + if (IS_ERR(dev->otp_data)) { + dev_err(&client->dev, "OTP data not available"); + return PTR_ERR(dev->otp_data); + } + + /* Correct read_size value only if bigger than maximum */ + if (read_size > OV5693_OTP_DATA_SIZE) + read_size = OV5693_OTP_DATA_SIZE; + + ret = copy_to_user(to, dev->otp_data, read_size); + if (ret) { + dev_err(&client->dev, "%s: failed to copy OTP data to user\n", + __func__); + return -EFAULT; + } + + pr_debug("%s read_size:%d\n", __func__, read_size); + +out: + /* Return correct size */ + priv->size = dev->otp_size; + + return 0; + +} + +static long ov5693_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +{ + + switch (cmd) { + case ATOMISP_IOC_S_EXPOSURE: + return ov5693_s_exposure(sd, arg); + case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA: + return ov5693_g_priv_int_data(sd, arg); + default: + return -EINVAL; + } + return 0; +} + +/* This returns the exposure time being used. This should only be used + for filling in EXIF data, not for actual image processing. */ +static int ov5693_q_exposure(struct v4l2_subdev *sd, s32 *value) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + u16 reg_v, reg_v2; + int ret; + + /* get exposure */ + ret = ov5693_read_reg(client, OV5693_8BIT, + OV5693_EXPOSURE_L, + ®_v); + if (ret) + goto err; + + ret = ov5693_read_reg(client, OV5693_8BIT, + OV5693_EXPOSURE_M, + ®_v2); + if (ret) + goto err; + + reg_v += reg_v2 << 8; + ret = ov5693_read_reg(client, OV5693_8BIT, + OV5693_EXPOSURE_H, + ®_v2); + if (ret) + goto err; + + *value = reg_v + (((u32)reg_v2 << 16)); +err: + return ret; +} + +static int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = -EINVAL; + u8 vcm_code; + + ret = ad5823_i2c_read(client, AD5823_REG_VCM_CODE_MSB, &vcm_code); + if (ret) + return ret; + + /* set reg VCM_CODE_MSB Bit[1:0] */ + vcm_code = (vcm_code & VCM_CODE_MSB_MASK) | + ((val >> 8) & ~VCM_CODE_MSB_MASK); + ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB, vcm_code); + if (ret) + return ret; + + /* set reg VCM_CODE_LSB Bit[7:0] */ + ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_LSB, (val & 0xff)); + if (ret) + return ret; + + /* set required vcm move time */ + vcm_code = AD5823_RESONANCE_PERIOD / AD5823_RESONANCE_COEF + - AD5823_HIGH_FREQ_RANGE; + ret = ad5823_i2c_write(client, AD5823_REG_VCM_MOVE_TIME, vcm_code); + + return ret; +} + +int ad5823_t_focus_abs(struct v4l2_subdev *sd, s32 value) +{ + value = min(value, AD5823_MAX_FOCUS_POS); + return ad5823_t_focus_vcm(sd, value); +} + +static int ov5693_t_focus_abs(struct v4l2_subdev *sd, s32 value) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + dev_dbg(&client->dev, "%s: FOCUS_POS: 0x%x\n", __func__, value); + value = clamp(value, 0, OV5693_VCM_MAX_FOCUS_POS); + if (dev->vcm == VCM_DW9714) { + if (dev->vcm_update) { + ret = vcm_dw_i2c_write(client, VCM_PROTECTION_OFF); + if (ret) + return ret; + ret = vcm_dw_i2c_write(client, DIRECT_VCM); + if (ret) + return ret; + ret = vcm_dw_i2c_write(client, VCM_PROTECTION_ON); + if (ret) + return ret; + dev->vcm_update = false; + } + ret = vcm_dw_i2c_write(client, + vcm_val(value, VCM_DEFAULT_S)); + } else if (dev->vcm == VCM_AD5823) { + ad5823_t_focus_abs(sd, value); + } + if (ret == 0) { + dev->number_of_steps = value - dev->focus; + dev->focus = value; + getnstimeofday(&(dev->timestamp_t_focus_abs)); + } else + dev_err(&client->dev, + "%s: i2c failed. ret %d\n", __func__, ret); + + return ret; +} + +static int ov5693_t_focus_rel(struct v4l2_subdev *sd, s32 value) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + return ov5693_t_focus_abs(sd, dev->focus + value); +} + +#define DELAY_PER_STEP_NS 1000000 +#define DELAY_MAX_PER_STEP_NS (1000000 * 1023) +static int ov5693_q_focus_status(struct v4l2_subdev *sd, s32 *value) +{ + u32 status = 0; + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct timespec temptime; + const struct timespec timedelay = { + 0, + min((u32)abs(dev->number_of_steps) * DELAY_PER_STEP_NS, + (u32)DELAY_MAX_PER_STEP_NS), + }; + + getnstimeofday(&temptime); + temptime = timespec_sub(temptime, (dev->timestamp_t_focus_abs)); + if (timespec_compare(&temptime, &timedelay) <= 0) { + status |= ATOMISP_FOCUS_STATUS_MOVING; + status |= ATOMISP_FOCUS_HP_IN_PROGRESS; + } else { + status |= ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE; + status |= ATOMISP_FOCUS_HP_COMPLETE; + } + + *value = status; + + return 0; +} + +static int ov5693_q_focus_abs(struct v4l2_subdev *sd, s32 *value) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + s32 val; + + ov5693_q_focus_status(sd, &val); + + if (val & ATOMISP_FOCUS_STATUS_MOVING) + *value = dev->focus - dev->number_of_steps; + else + *value = dev->focus; + + return 0; +} + +static int ov5693_t_vcm_slew(struct v4l2_subdev *sd, s32 value) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + dev->number_of_steps = value; + dev->vcm_update = true; + return 0; +} + +static int ov5693_t_vcm_timing(struct v4l2_subdev *sd, s32 value) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + dev->number_of_steps = value; + dev->vcm_update = true; + return 0; +} + +static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov5693_device *dev = + container_of(ctrl->handler, struct ov5693_device, ctrl_handler); + struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_FOCUS_ABSOLUTE: + dev_dbg(&client->dev, "%s: CID_FOCUS_ABSOLUTE:%d.\n", + __func__, ctrl->val); + ret = ov5693_t_focus_abs(&dev->sd, ctrl->val); + break; + case V4L2_CID_FOCUS_RELATIVE: + dev_dbg(&client->dev, "%s: CID_FOCUS_RELATIVE:%d.\n", + __func__, ctrl->val); + ret = ov5693_t_focus_rel(&dev->sd, ctrl->val); + break; + case V4L2_CID_VCM_SLEW: + ret = ov5693_t_vcm_slew(&dev->sd, ctrl->val); + break; + case V4L2_CID_VCM_TIMEING: + ret = ov5693_t_vcm_timing(&dev->sd, ctrl->val); + break; + default: + ret = -EINVAL; + } + return ret; +} + +static int ov5693_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov5693_device *dev = + container_of(ctrl->handler, struct ov5693_device, ctrl_handler); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE_ABSOLUTE: + ret = ov5693_q_exposure(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FOCAL_ABSOLUTE: + ret = ov5693_g_focal(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_ABSOLUTE: + ret = ov5693_g_fnumber(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FNUMBER_RANGE: + ret = ov5693_g_fnumber_range(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FOCUS_ABSOLUTE: + ret = ov5693_q_focus_abs(&dev->sd, &ctrl->val); + break; + case V4L2_CID_FOCUS_STATUS: + ret = ov5693_q_focus_status(&dev->sd, &ctrl->val); + break; + case V4L2_CID_BIN_FACTOR_HORZ: + ret = ov5693_g_bin_factor_x(&dev->sd, &ctrl->val); + break; + case V4L2_CID_BIN_FACTOR_VERT: + ret = ov5693_g_bin_factor_y(&dev->sd, &ctrl->val); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops ctrl_ops = { + .s_ctrl = ov5693_s_ctrl, + .g_volatile_ctrl = ov5693_g_volatile_ctrl +}; + +struct v4l2_ctrl_config ov5693_controls[] = { + { + .ops = &ctrl_ops, + .id = V4L2_CID_EXPOSURE_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "exposure", + .min = 0x0, + .max = 0xffff, + .step = 0x01, + .def = 0x00, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FOCAL_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "focal length", + .min = OV5693_FOCAL_LENGTH_DEFAULT, + .max = OV5693_FOCAL_LENGTH_DEFAULT, + .step = 0x01, + .def = OV5693_FOCAL_LENGTH_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "f-number", + .min = OV5693_F_NUMBER_DEFAULT, + .max = OV5693_F_NUMBER_DEFAULT, + .step = 0x01, + .def = OV5693_F_NUMBER_DEFAULT, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FNUMBER_RANGE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "f-number range", + .min = OV5693_F_NUMBER_RANGE, + .max = OV5693_F_NUMBER_RANGE, + .step = 0x01, + .def = OV5693_F_NUMBER_RANGE, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FOCUS_ABSOLUTE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "focus move absolute", + .min = 0, + .max = OV5693_VCM_MAX_FOCUS_POS, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FOCUS_RELATIVE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "focus move relative", + .min = OV5693_VCM_MAX_FOCUS_NEG, + .max = OV5693_VCM_MAX_FOCUS_POS, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_FOCUS_STATUS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "focus status", + .min = 0, + .max = 100, /* allow enum to grow in the future */ + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_VCM_SLEW, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "vcm slew", + .min = 0, + .max = OV5693_VCM_SLEW_STEP_MAX, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_VCM_TIMEING, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "vcm step time", + .min = 0, + .max = OV5693_VCM_SLEW_TIME_MAX, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_BIN_FACTOR_HORZ, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "horizontal binning factor", + .min = 0, + .max = OV5693_BIN_FACTOR_MAX, + .step = 1, + .def = 0, + .flags = 0, + }, + { + .ops = &ctrl_ops, + .id = V4L2_CID_BIN_FACTOR_VERT, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "vertical binning factor", + .min = 0, + .max = OV5693_BIN_FACTOR_MAX, + .step = 1, + .def = 0, + .flags = 0, + }, +}; + +static int ov5693_init(struct v4l2_subdev *sd) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + pr_info("%s\n", __func__); + mutex_lock(&dev->input_lock); + dev->vcm_update = false; + + if (dev->vcm == VCM_AD5823) { + ret = vcm_ad_i2c_wr8(client, 0x01, 0x01); /* vcm init test */ + if (ret) + dev_err(&client->dev, + "vcm reset failed\n"); + /*change the mode*/ + ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB, + AD5823_RING_CTRL_ENABLE); + if (ret) + dev_err(&client->dev, + "vcm enable ringing failed\n"); + ret = ad5823_i2c_write(client, AD5823_REG_MODE, + AD5823_ARC_RES1); + if (ret) + dev_err(&client->dev, + "vcm change mode failed\n"); + } + + /*change initial focus value for ad5823*/ + if (dev->vcm == VCM_AD5823) { + dev->focus = AD5823_INIT_FOCUS_POS; + ov5693_t_focus_abs(sd, AD5823_INIT_FOCUS_POS); + } else { + dev->focus = 0; + ov5693_t_focus_abs(sd, 0); + } + + mutex_unlock(&dev->input_lock); + + return 0; +} + +static int power_ctrl(struct v4l2_subdev *sd, bool flag) +{ + int ret; + struct ov5693_device *dev = to_ov5693_sensor(sd); + + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->power_ctrl) + return dev->platform_data->power_ctrl(sd, flag); + + /* This driver assumes "internal DVDD, PWDNB tied to DOVDD". + * In this set up only gpio0 (XSHUTDN) should be available + * but in some products (for example ECS) gpio1 (PWDNB) is + * also available. If gpio1 is available we emulate it being + * tied to DOVDD here. */ + if (flag) { + ret = dev->platform_data->v2p8_ctrl(sd, 1); + dev->platform_data->gpio1_ctrl(sd, 1); + if (ret == 0) { + ret = dev->platform_data->v1p8_ctrl(sd, 1); + if (ret) { + dev->platform_data->gpio1_ctrl(sd, 0); + ret = dev->platform_data->v2p8_ctrl(sd, 0); + } + } + } else { + dev->platform_data->gpio1_ctrl(sd, 0); + ret = dev->platform_data->v1p8_ctrl(sd, 0); + ret |= dev->platform_data->v2p8_ctrl(sd, 0); + } + + return ret; +} + +static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + + if (!dev || !dev->platform_data) + return -ENODEV; + + /* Non-gmin platforms use the legacy callback */ + if (dev->platform_data->gpio_ctrl) + return dev->platform_data->gpio_ctrl(sd, flag); + + return dev->platform_data->gpio0_ctrl(sd, flag); +} + +static int __power_up(struct v4l2_subdev *sd) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + if (NULL == dev->platform_data) { + dev_err(&client->dev, + "no camera_sensor_platform_data"); + return -ENODEV; + } + + /* power control */ + ret = power_ctrl(sd, 1); + if (ret) + goto fail_power; + + /* according to DS, at least 5ms is needed between DOVDD and PWDN */ + /* add this delay time to 10~11ms*/ + usleep_range(10000, 11000); + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 1); + if (ret) { + ret = gpio_ctrl(sd, 1); + if (ret) + goto fail_power; + } + + /* flis clock control */ + ret = dev->platform_data->flisclk_ctrl(sd, 1); + if (ret) + goto fail_clk; + + __cci_delay(up_delay); + + return 0; + +fail_clk: + gpio_ctrl(sd, 0); +fail_power: + power_ctrl(sd, 0); + dev_err(&client->dev, "sensor power-up failed\n"); + + return ret; +} + +static int power_down(struct v4l2_subdev *sd) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + dev->focus = OV5693_INVALID_CONFIG; + if (NULL == dev->platform_data) { + dev_err(&client->dev, + "no camera_sensor_platform_data"); + return -ENODEV; + } + + ret = dev->platform_data->flisclk_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "flisclk failed\n"); + + /* gpio ctrl */ + ret = gpio_ctrl(sd, 0); + if (ret) { + ret = gpio_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "gpio failed 2\n"); + } + + /* power control */ + ret = power_ctrl(sd, 0); + if (ret) + dev_err(&client->dev, "vprog failed.\n"); + + return ret; +} + +static int power_up(struct v4l2_subdev *sd) +{ + static const int retry_count = 4; + int i, ret; + + for (i = 0; i < retry_count; i++) { + ret = __power_up(sd); + if (!ret) + return 0; + + power_down(sd); + } + return ret; +} + +static int ov5693_s_power(struct v4l2_subdev *sd, int on) +{ + int ret; + + pr_info("%s: on %d\n", __func__, on); + if (on == 0) + return power_down(sd); + else { + ret = power_up(sd); + if (!ret) { + ret = ov5693_init(sd); + /* restore settings */ + ov5693_res = ov5693_res_preview; + N_RES = N_RES_PREVIEW; + } + } + return ret; +} + +/* + * distance - calculate the distance + * @res: resolution + * @w: width + * @h: height + * + * Get the gap between res_w/res_h and w/h. + * distance = (res_w/res_h - w/h) / (w/h) * 8192 + * res->width/height smaller than w/h wouldn't be considered. + * The gap of ratio larger than 1/8 wouldn't be considered. + * Returns the value of gap or -1 if fail. + */ +#define LARGEST_ALLOWED_RATIO_MISMATCH 1024 +static int distance(struct ov5693_resolution *res, u32 w, u32 h) +{ + int ratio; + int distance; + + if (w == 0 || h == 0 || + res->width < w || res->height < h) + return -1; + + ratio = res->width << 13; + ratio /= w; + ratio *= h; + ratio /= res->height; + + distance = abs(ratio - 8192); + + if (distance > LARGEST_ALLOWED_RATIO_MISMATCH) + return -1; + + return distance; +} + +/* Return the nearest higher resolution index + * Firstly try to find the approximate aspect ratio resolution + * If we find multiple same AR resolutions, choose the + * minimal size. + */ +static int nearest_resolution_index(int w, int h) +{ + int i; + int idx = -1; + int dist; + int min_dist = INT_MAX; + int min_res_w = INT_MAX; + struct ov5693_resolution *tmp_res = NULL; + + for (i = 0; i < N_RES; i++) { + tmp_res = &ov5693_res[i]; + dist = distance(tmp_res, w, h); + if (dist == -1) + continue; + if (dist < min_dist) { + min_dist = dist; + idx = i; + min_res_w = ov5693_res[i].width; + continue; + } + if (dist == min_dist && ov5693_res[i].width < min_res_w) + idx = i; + } + + return idx; +} + +static int get_resolution_index(int w, int h) +{ + int i; + + for (i = 0; i < N_RES; i++) { + if (w != ov5693_res[i].width) + continue; + if (h != ov5693_res[i].height) + continue; + + return i; + } + + return -1; +} + +/* TODO: remove it. */ +static int startup(struct v4l2_subdev *sd) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + ret = ov5693_write_reg(client, OV5693_8BIT, + OV5693_SW_RESET, 0x01); + if (ret) { + dev_err(&client->dev, "ov5693 reset err.\n"); + return ret; + } + + ret = ov5693_write_reg_array(client, ov5693_global_setting); + if (ret) { + dev_err(&client->dev, "ov5693 write register err.\n"); + return ret; + } + + ret = ov5693_write_reg_array(client, ov5693_res[dev->fmt_idx].regs); + if (ret) { + dev_err(&client->dev, "ov5693 write register err.\n"); + return ret; + } + + return ret; +} + +static int ov5693_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt = &format->format; + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct camera_mipi_info *ov5693_info = NULL; + int ret = 0; + int idx; + if (format->pad) + return -EINVAL; + if (!fmt) + return -EINVAL; + ov5693_info = v4l2_get_subdev_hostdata(sd); + if (ov5693_info == NULL) + return -EINVAL; + + mutex_lock(&dev->input_lock); + idx = nearest_resolution_index(fmt->width, fmt->height); + if (idx == -1) { + /* return the largest resolution */ + fmt->width = ov5693_res[N_RES - 1].width; + fmt->height = ov5693_res[N_RES - 1].height; + } else { + fmt->width = ov5693_res[idx].width; + fmt->height = ov5693_res[idx].height; + } + + fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *fmt; + mutex_unlock(&dev->input_lock); + return 0; + } + + dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); + if (dev->fmt_idx == -1) { + dev_err(&client->dev, "get resolution fail\n"); + mutex_unlock(&dev->input_lock); + return -EINVAL; + } + + ret = startup(sd); + if (ret) { + int i = 0; + dev_err(&client->dev, "ov5693 startup err, retry to power up\n"); + for (i = 0; i < OV5693_POWER_UP_RETRY_NUM; i++) { + dev_err(&client->dev, + "ov5693 retry to power up %d/%d times, result: ", + i+1, OV5693_POWER_UP_RETRY_NUM); + power_down(sd); + ret = power_up(sd); + if (!ret) { + mutex_unlock(&dev->input_lock); + ov5693_init(sd); + mutex_lock(&dev->input_lock); + } else { + dev_err(&client->dev, "power up failed, continue\n"); + continue; + } + ret = startup(sd); + if (ret) { + dev_err(&client->dev, " startup FAILED!\n"); + } else { + dev_err(&client->dev, " startup SUCCESS!\n"); + break; + } + } + } + + /* + * After sensor settings are set to HW, sometimes stream is started. + * This would cause ISP timeout because ISP is not ready to receive + * data yet. So add stop streaming here. + */ + ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM, + OV5693_STOP_STREAMING); + if (ret) + dev_warn(&client->dev, "ov5693 stream off err\n"); + + ret = ov5693_get_intg_factor(client, ov5693_info, + &ov5693_res[dev->fmt_idx]); + if (ret) { + dev_err(&client->dev, "failed to get integration_factor\n"); + goto err; + } + + ov5693_info->metadata_width = fmt->width * 10 / 8; + ov5693_info->metadata_height = 1; + ov5693_info->metadata_effective_width = &ov5693_embedded_effective_size; + +err: + mutex_unlock(&dev->input_lock); + return ret; +} +static int ov5693_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *fmt = &format->format; + struct ov5693_device *dev = to_ov5693_sensor(sd); + if (format->pad) + return -EINVAL; + + if (!fmt) + return -EINVAL; + + fmt->width = ov5693_res[dev->fmt_idx].width; + fmt->height = ov5693_res[dev->fmt_idx].height; + fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; + + return 0; +} + +static int ov5693_detect(struct i2c_client *client) +{ + struct i2c_adapter *adapter = client->adapter; + u16 high, low; + int ret; + u16 id; + u8 revision; + + if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + return -ENODEV; + + ret = ov5693_read_reg(client, OV5693_8BIT, + OV5693_SC_CMMN_CHIP_ID_H, &high); + if (ret) { + dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); + return -ENODEV; + } + ret = ov5693_read_reg(client, OV5693_8BIT, + OV5693_SC_CMMN_CHIP_ID_L, &low); + id = ((((u16) high) << 8) | (u16) low); + + if (id != OV5693_ID) { + dev_err(&client->dev, "sensor ID error 0x%x\n", id); + return -ENODEV; + } + + ret = ov5693_read_reg(client, OV5693_8BIT, + OV5693_SC_CMMN_SUB_ID, &high); + revision = (u8) high & 0x0f; + + dev_dbg(&client->dev, "sensor_revision = 0x%x\n", revision); + dev_dbg(&client->dev, "detect ov5693 success\n"); + return 0; +} + +static int ov5693_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + mutex_lock(&dev->input_lock); + + ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM, + enable ? OV5693_START_STREAMING : + OV5693_STOP_STREAMING); + + mutex_unlock(&dev->input_lock); + + return ret; +} + + +static int ov5693_s_config(struct v4l2_subdev *sd, + int irq, void *platform_data) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + if (platform_data == NULL) + return -ENODEV; + + dev->platform_data = + (struct camera_sensor_platform_data *)platform_data; + + mutex_lock(&dev->input_lock); + /* power off the module, then power on it in future + * as first power on by board may not fulfill the + * power on sequqence needed by the module + */ + ret = power_down(sd); + if (ret) { + dev_err(&client->dev, "ov5693 power-off err.\n"); + goto fail_power_off; + } + + ret = power_up(sd); + if (ret) { + dev_err(&client->dev, "ov5693 power-up err.\n"); + goto fail_power_on; + } + + if (!dev->vcm) + dev->vcm = vcm_detect(client); + + ret = dev->platform_data->csi_cfg(sd, 1); + if (ret) + goto fail_csi_cfg; + + /* config & detect sensor */ + ret = ov5693_detect(client); + if (ret) { + dev_err(&client->dev, "ov5693_detect err s_config.\n"); + goto fail_csi_cfg; + } + + dev->otp_data = ov5693_otp_read(sd); + + /* turn off sensor, after probed */ + ret = power_down(sd); + if (ret) { + dev_err(&client->dev, "ov5693 power-off err.\n"); + goto fail_csi_cfg; + } + mutex_unlock(&dev->input_lock); + + return ret; + +fail_csi_cfg: + dev->platform_data->csi_cfg(sd, 0); +fail_power_on: + power_down(sd); + dev_err(&client->dev, "sensor power-gating failed\n"); +fail_power_off: + mutex_unlock(&dev->input_lock); + return ret; +} + +static int ov5693_g_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (!param) + return -EINVAL; + + if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + dev_err(&client->dev, "unsupported buffer type.\n"); + return -EINVAL; + } + + memset(param, 0, sizeof(*param)); + param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + + if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { + param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + param->parm.capture.timeperframe.numerator = 1; + param->parm.capture.capturemode = dev->run_mode; + param->parm.capture.timeperframe.denominator = + ov5693_res[dev->fmt_idx].fps; + } + return 0; +} + +static int ov5693_s_parm(struct v4l2_subdev *sd, + struct v4l2_streamparm *param) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + dev->run_mode = param->parm.capture.capturemode; + + mutex_lock(&dev->input_lock); + switch (dev->run_mode) { + case CI_MODE_VIDEO: + ov5693_res = ov5693_res_video; + N_RES = N_RES_VIDEO; + break; + case CI_MODE_STILL_CAPTURE: + ov5693_res = ov5693_res_still; + N_RES = N_RES_STILL; + break; + default: + ov5693_res = ov5693_res_preview; + N_RES = N_RES_PREVIEW; + } + mutex_unlock(&dev->input_lock); + return 0; +} + +static int ov5693_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *interval) +{ + struct ov5693_device *dev = to_ov5693_sensor(sd); + + interval->interval.numerator = 1; + interval->interval.denominator = ov5693_res[dev->fmt_idx].fps; + + return 0; +} + +static int ov5693_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= MAX_FMTS) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SBGGR10_1X10; + return 0; +} + +static int ov5693_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + int index = fse->index; + + if (index >= N_RES) + return -EINVAL; + + fse->min_width = ov5693_res[index].width; + fse->min_height = ov5693_res[index].height; + fse->max_width = ov5693_res[index].width; + fse->max_height = ov5693_res[index].height; + + return 0; + +} + +static const struct v4l2_subdev_video_ops ov5693_video_ops = { + .s_stream = ov5693_s_stream, + .g_parm = ov5693_g_parm, + .s_parm = ov5693_s_parm, + .g_frame_interval = ov5693_g_frame_interval, +}; + +static const struct v4l2_subdev_core_ops ov5693_core_ops = { + .s_power = ov5693_s_power, + .ioctl = ov5693_ioctl, +}; + +static const struct v4l2_subdev_pad_ops ov5693_pad_ops = { + .enum_mbus_code = ov5693_enum_mbus_code, + .enum_frame_size = ov5693_enum_frame_size, + .get_fmt = ov5693_get_fmt, + .set_fmt = ov5693_set_fmt, +}; + +static const struct v4l2_subdev_ops ov5693_ops = { + .core = &ov5693_core_ops, + .video = &ov5693_video_ops, + .pad = &ov5693_pad_ops, +}; + +static int ov5693_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov5693_device *dev = to_ov5693_sensor(sd); + dev_dbg(&client->dev, "ov5693_remove...\n"); + + dev->platform_data->csi_cfg(sd, 0); + + v4l2_device_unregister_subdev(sd); + + atomisp_gmin_remove_subdev(sd); + + media_entity_cleanup(&dev->sd.entity); + v4l2_ctrl_handler_free(&dev->ctrl_handler); + kfree(dev); + + return 0; +} + +static int ov5693_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ov5693_device *dev; + int i2c; + int ret = 0; + void *pdata = client->dev.platform_data; + struct acpi_device *adev; + unsigned int i; + + /* Firmware workaround: Some modules use a "secondary default" + * address of 0x10 which doesn't appear on schematics, and + * some BIOS versions haven't gotten the memo. Work around + * via config. */ + i2c = gmin_get_var_int(&client->dev, "I2CAddr", -1); + if (i2c != -1) { + dev_info(&client->dev, + "Overriding firmware-provided I2C address (0x%x) with 0x%x\n", + client->addr, i2c); + client->addr = i2c; + } + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + dev_err(&client->dev, "out of memory\n"); + return -ENOMEM; + } + + mutex_init(&dev->input_lock); + + dev->fmt_idx = 0; + v4l2_i2c_subdev_init(&(dev->sd), client, &ov5693_ops); + + adev = ACPI_COMPANION(&client->dev); + if (adev) { + adev->power.flags.power_resources = 0; + pdata = gmin_camera_platform_data(&dev->sd, + ATOMISP_INPUT_FORMAT_RAW_10, + atomisp_bayer_order_bggr); + } + + if (!pdata) + goto out_free; + + ret = ov5693_s_config(&dev->sd, client->irq, pdata); + if (ret) + goto out_free; + + ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); + if (ret) + goto out_free; + + dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + dev->pad.flags = MEDIA_PAD_FL_SOURCE; + dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; + dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = + v4l2_ctrl_handler_init(&dev->ctrl_handler, + ARRAY_SIZE(ov5693_controls)); + if (ret) { + ov5693_remove(client); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(ov5693_controls); i++) + v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov5693_controls[i], + NULL); + + if (dev->ctrl_handler.error) { + ov5693_remove(client); + return dev->ctrl_handler.error; + } + + /* Use same lock for controls as for everything else. */ + dev->ctrl_handler.lock = &dev->input_lock; + dev->sd.ctrl_handler = &dev->ctrl_handler; + + ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); + if (ret) + ov5693_remove(client); + + return ret; +out_free: + v4l2_device_unregister_subdev(&dev->sd); + kfree(dev); + return ret; +} + +MODULE_DEVICE_TABLE(i2c, ov5693_id); + +static const struct acpi_device_id ov5693_acpi_match[] = { + {"INT33BE"}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match); + +static struct i2c_driver ov5693_driver = { + .driver = { + .name = OV5693_NAME, + .acpi_match_table = ACPI_PTR(ov5693_acpi_match), + }, + .probe = ov5693_probe, + .remove = ov5693_remove, + .id_table = ov5693_id, +}; + +static int init_ov5693(void) +{ + return i2c_add_driver(&ov5693_driver); +} + +static void exit_ov5693(void) +{ + + i2c_del_driver(&ov5693_driver); +} + +module_init(init_ov5693); +module_exit(exit_ov5693); + +MODULE_DESCRIPTION("A low-level driver for OmniVision 5693 sensors"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.c deleted file mode 100644 index 219501167584..000000000000 --- a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.c +++ /dev/null @@ -1,2059 +0,0 @@ -/* - * Support for OmniVision OV5693 1080p HD camera sensor. - * - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../../include/linux/atomisp_gmin_platform.h" - -#include "ov5693.h" -#include "ad5823.h" - -#define __cci_delay(t) \ - do { \ - if ((t) < 10) { \ - usleep_range((t) * 1000, ((t) + 1) * 1000); \ - } else { \ - msleep((t)); \ - } \ - } while (0) - -/* Value 30ms reached through experimentation on byt ecs. - * The DS specifies a much lower value but when using a smaller value - * the I2C bus sometimes locks up permanently when starting the camera. - * This issue could not be reproduced on cht, so we can reduce the - * delay value to a lower value when insmod. - */ -static uint up_delay = 30; -module_param(up_delay, uint, 0644); -MODULE_PARM_DESC(up_delay, "Delay prior to the first CCI transaction for ov5693"); - -static int vcm_ad_i2c_wr8(struct i2c_client *client, u8 reg, u8 val) -{ - int err; - struct i2c_msg msg; - u8 buf[2]; - - buf[0] = reg; - buf[1] = val; - - msg.addr = VCM_ADDR; - msg.flags = 0; - msg.len = 2; - msg.buf = &buf[0]; - - err = i2c_transfer(client->adapter, &msg, 1); - if (err != 1) { - dev_err(&client->dev, "%s: vcm i2c fail, err code = %d\n", - __func__, err); - return -EIO; - } - return 0; -} - -static int ad5823_i2c_write(struct i2c_client *client, u8 reg, u8 val) -{ - struct i2c_msg msg; - u8 buf[2]; - buf[0] = reg; - buf[1] = val; - msg.addr = AD5823_VCM_ADDR; - msg.flags = 0; - msg.len = 0x02; - msg.buf = &buf[0]; - - if (i2c_transfer(client->adapter, &msg, 1) != 1) - return -EIO; - return 0; -} - -static int ad5823_i2c_read(struct i2c_client *client, u8 reg, u8 *val) -{ - struct i2c_msg msg[2]; - u8 buf[2]; - buf[0] = reg; - buf[1] = 0; - - msg[0].addr = AD5823_VCM_ADDR; - msg[0].flags = 0; - msg[0].len = 0x01; - msg[0].buf = &buf[0]; - - msg[1].addr = 0x0c; - msg[1].flags = I2C_M_RD; - msg[1].len = 0x01; - msg[1].buf = &buf[1]; - *val = 0; - if (i2c_transfer(client->adapter, msg, 2) != 2) - return -EIO; - *val = buf[1]; - return 0; -} - - -static const uint32_t ov5693_embedded_effective_size = 28; - -/* i2c read/write stuff */ -static int ov5693_read_reg(struct i2c_client *client, - u16 data_length, u16 reg, u16 *val) -{ - int err; - struct i2c_msg msg[2]; - unsigned char data[6]; - - if (!client->adapter) { - dev_err(&client->dev, "%s error, no client->adapter\n", - __func__); - return -ENODEV; - } - - if (data_length != OV5693_8BIT && data_length != OV5693_16BIT - && data_length != OV5693_32BIT) { - dev_err(&client->dev, "%s error, invalid data length\n", - __func__); - return -EINVAL; - } - - memset(msg, 0, sizeof(msg)); - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = I2C_MSG_LENGTH; - msg[0].buf = data; - - /* high byte goes out first */ - data[0] = (u8)(reg >> 8); - data[1] = (u8)(reg & 0xff); - - msg[1].addr = client->addr; - msg[1].len = data_length; - msg[1].flags = I2C_M_RD; - msg[1].buf = data; - - err = i2c_transfer(client->adapter, msg, 2); - if (err != 2) { - if (err >= 0) - err = -EIO; - dev_err(&client->dev, - "read from offset 0x%x error %d", reg, err); - return err; - } - - *val = 0; - /* high byte comes first */ - if (data_length == OV5693_8BIT) - *val = (u8)data[0]; - else if (data_length == OV5693_16BIT) - *val = be16_to_cpu(*(u16 *)&data[0]); - else - *val = be32_to_cpu(*(u32 *)&data[0]); - - return 0; -} - -static int ov5693_i2c_write(struct i2c_client *client, u16 len, u8 *data) -{ - struct i2c_msg msg; - const int num_msg = 1; - int ret; - - msg.addr = client->addr; - msg.flags = 0; - msg.len = len; - msg.buf = data; - ret = i2c_transfer(client->adapter, &msg, 1); - - return ret == num_msg ? 0 : -EIO; -} - -static int vcm_dw_i2c_write(struct i2c_client *client, u16 data) -{ - struct i2c_msg msg; - const int num_msg = 1; - int ret; - u16 val; - - val = cpu_to_be16(data); - msg.addr = VCM_ADDR; - msg.flags = 0; - msg.len = OV5693_16BIT; - msg.buf = (u8 *)&val; - - ret = i2c_transfer(client->adapter, &msg, 1); - - return ret == num_msg ? 0 : -EIO; -} - -/* Theory: per datasheet, the two VCMs both allow for a 2-byte read. - * The DW9714 doesn't actually specify what this does (it has a - * two-byte write-only protocol, but specifies the read sequence as - * legal), but it returns the same data (zeroes) always, after an - * undocumented initial NAK. The AD5823 has a one-byte address - * register to which all writes go, and subsequent reads will cycle - * through the 8 bytes of registers. Notably, the default values (the - * device is always power-cycled affirmatively, so we can rely on - * these) in AD5823 are not pairwise repetitions of the same 16 bit - * word. So all we have to do is sequentially read two bytes at a - * time and see if we detect a difference in any of the first four - * pairs. */ -static int vcm_detect(struct i2c_client *client) -{ - int i, ret; - struct i2c_msg msg; - u16 data0 = 0, data; - for (i = 0; i < 4; i++) { - msg.addr = VCM_ADDR; - msg.flags = I2C_M_RD; - msg.len = sizeof(data); - msg.buf = (u8 *)&data; - ret = i2c_transfer(client->adapter, &msg, 1); - - /* DW9714 always fails the first read and returns - * zeroes for subsequent ones */ - if (i == 0 && ret == -EREMOTEIO) { - data0 = 0; - continue; - } - - if (i == 0) - data0 = data; - - if (data != data0) - return VCM_AD5823; - } - return ret == 1 ? VCM_DW9714 : ret; -} - -static int ov5693_write_reg(struct i2c_client *client, u16 data_length, - u16 reg, u16 val) -{ - int ret; - unsigned char data[4] = {0}; - u16 *wreg = (u16 *)data; - const u16 len = data_length + sizeof(u16); /* 16-bit address + data */ - - if (data_length != OV5693_8BIT && data_length != OV5693_16BIT) { - dev_err(&client->dev, - "%s error, invalid data_length\n", __func__); - return -EINVAL; - } - - /* high byte goes out first */ - *wreg = cpu_to_be16(reg); - - if (data_length == OV5693_8BIT) { - data[2] = (u8)(val); - } else { - /* OV5693_16BIT */ - u16 *wdata = (u16 *)&data[2]; - *wdata = cpu_to_be16(val); - } - - ret = ov5693_i2c_write(client, len, data); - if (ret) - dev_err(&client->dev, - "write error: wrote 0x%x to offset 0x%x error %d", - val, reg, ret); - - return ret; -} - -/* - * ov5693_write_reg_array - Initializes a list of OV5693 registers - * @client: i2c driver client structure - * @reglist: list of registers to be written - * - * This function initializes a list of registers. When consecutive addresses - * are found in a row on the list, this function creates a buffer and sends - * consecutive data in a single i2c_transfer(). - * - * __ov5693_flush_reg_array, __ov5693_buf_reg_array() and - * __ov5693_write_reg_is_consecutive() are internal functions to - * ov5693_write_reg_array_fast() and should be not used anywhere else. - * - */ - -static int __ov5693_flush_reg_array(struct i2c_client *client, - struct ov5693_write_ctrl *ctrl) -{ - u16 size; - - if (ctrl->index == 0) - return 0; - - size = sizeof(u16) + ctrl->index; /* 16-bit address + data */ - ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr); - ctrl->index = 0; - - return ov5693_i2c_write(client, size, (u8 *)&ctrl->buffer); -} - -static int __ov5693_buf_reg_array(struct i2c_client *client, - struct ov5693_write_ctrl *ctrl, - const struct ov5693_reg *next) -{ - int size; - u16 *data16; - - switch (next->type) { - case OV5693_8BIT: - size = 1; - ctrl->buffer.data[ctrl->index] = (u8)next->val; - break; - case OV5693_16BIT: - size = 2; - data16 = (u16 *)&ctrl->buffer.data[ctrl->index]; - *data16 = cpu_to_be16((u16)next->val); - break; - default: - return -EINVAL; - } - - /* When first item is added, we need to store its starting address */ - if (ctrl->index == 0) - ctrl->buffer.addr = next->reg; - - ctrl->index += size; - - /* - * Buffer cannot guarantee free space for u32? Better flush it to avoid - * possible lack of memory for next item. - */ - if (ctrl->index + sizeof(u16) >= OV5693_MAX_WRITE_BUF_SIZE) - return __ov5693_flush_reg_array(client, ctrl); - - return 0; -} - -static int __ov5693_write_reg_is_consecutive(struct i2c_client *client, - struct ov5693_write_ctrl *ctrl, - const struct ov5693_reg *next) -{ - if (ctrl->index == 0) - return 1; - - return ctrl->buffer.addr + ctrl->index == next->reg; -} - -static int ov5693_write_reg_array(struct i2c_client *client, - const struct ov5693_reg *reglist) -{ - const struct ov5693_reg *next = reglist; - struct ov5693_write_ctrl ctrl; - int err; - - ctrl.index = 0; - for (; next->type != OV5693_TOK_TERM; next++) { - switch (next->type & OV5693_TOK_MASK) { - case OV5693_TOK_DELAY: - err = __ov5693_flush_reg_array(client, &ctrl); - if (err) - return err; - msleep(next->val); - break; - default: - /* - * If next address is not consecutive, data needs to be - * flushed before proceed. - */ - if (!__ov5693_write_reg_is_consecutive(client, &ctrl, - next)) { - err = __ov5693_flush_reg_array(client, &ctrl); - if (err) - return err; - } - err = __ov5693_buf_reg_array(client, &ctrl, next); - if (err) { - dev_err(&client->dev, - "%s: write error, aborted\n", - __func__); - return err; - } - break; - } - } - - return __ov5693_flush_reg_array(client, &ctrl); -} -static int ov5693_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV5693_FOCAL_LENGTH_NUM << 16) | OV5693_FOCAL_LENGTH_DEM; - return 0; -} - -static int ov5693_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /*const f number for imx*/ - *val = (OV5693_F_NUMBER_DEFAULT_NUM << 16) | OV5693_F_NUMBER_DEM; - return 0; -} - -static int ov5693_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (OV5693_F_NUMBER_DEFAULT_NUM << 24) | - (OV5693_F_NUMBER_DEM << 16) | - (OV5693_F_NUMBER_DEFAULT_NUM << 8) | OV5693_F_NUMBER_DEM; - return 0; -} - -static int ov5693_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - - *val = ov5693_res[dev->fmt_idx].bin_factor_x; - - return 0; -} - -static int ov5693_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - - *val = ov5693_res[dev->fmt_idx].bin_factor_y; - - return 0; -} - -static int ov5693_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct ov5693_resolution *res) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct atomisp_sensor_mode_data *buf = &info->data; - unsigned int pix_clk_freq_hz; - u16 reg_val; - int ret; - - if (info == NULL) - return -EINVAL; - - /* pixel clock */ - pix_clk_freq_hz = res->pix_clk_freq * 1000000; - - dev->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - buf->vt_pix_clk_freq_mhz = pix_clk_freq_hz; - - /* get integration time */ - buf->coarse_integration_time_min = OV5693_COARSE_INTG_TIME_MIN; - buf->coarse_integration_time_max_margin = - OV5693_COARSE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_min = OV5693_FINE_INTG_TIME_MIN; - buf->fine_integration_time_max_margin = - OV5693_FINE_INTG_TIME_MAX_MARGIN; - - buf->fine_integration_time_def = OV5693_FINE_INTG_TIME_MIN; - buf->frame_length_lines = res->lines_per_frame; - buf->line_length_pck = res->pixels_per_line; - buf->read_mode = res->bin_mode; - - /* get the cropping and output resolution to ISP for this mode. */ - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_HORIZONTAL_START_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_start = reg_val; - - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_VERTICAL_START_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_start = reg_val; - - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_HORIZONTAL_END_H, ®_val); - if (ret) - return ret; - buf->crop_horizontal_end = reg_val; - - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_VERTICAL_END_H, ®_val); - if (ret) - return ret; - buf->crop_vertical_end = reg_val; - - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_HORIZONTAL_OUTPUT_SIZE_H, ®_val); - if (ret) - return ret; - buf->output_width = reg_val; - - ret = ov5693_read_reg(client, OV5693_16BIT, - OV5693_VERTICAL_OUTPUT_SIZE_H, ®_val); - if (ret) - return ret; - buf->output_height = reg_val; - - buf->binning_factor_x = res->bin_factor_x ? - res->bin_factor_x : 1; - buf->binning_factor_y = res->bin_factor_y ? - res->bin_factor_y : 1; - return 0; -} - -static long __ov5693_set_exposure(struct v4l2_subdev *sd, int coarse_itg, - int gain, int digitgain) - -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov5693_device *dev = to_ov5693_sensor(sd); - u16 vts, hts; - int ret, exp_val; - - hts = ov5693_res[dev->fmt_idx].pixels_per_line; - vts = ov5693_res[dev->fmt_idx].lines_per_frame; - /*If coarse_itg is larger than 1<<15, can not write to reg directly. - The way is to write coarse_itg/2 to the reg, meanwhile write 2*hts - to the reg. */ - if (coarse_itg > (1 << 15)) { - hts = hts * 2; - coarse_itg = (int)coarse_itg / 2; - } - /* group hold */ - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_GROUP_ACCESS, 0x00); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_GROUP_ACCESS); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_TIMING_HTS_H, (hts >> 8) & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_TIMING_HTS_H); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_TIMING_HTS_L, hts & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_TIMING_HTS_L); - return ret; - } - /* Increase the VTS to match exposure + MARGIN */ - if (coarse_itg > vts - OV5693_INTEGRATION_TIME_MARGIN) - vts = (u16) coarse_itg + OV5693_INTEGRATION_TIME_MARGIN; - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_TIMING_VTS_H, (vts >> 8) & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_TIMING_VTS_H); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_TIMING_VTS_L, vts & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_TIMING_VTS_L); - return ret; - } - - /* set exposure */ - - /* Lower four bit should be 0*/ - exp_val = coarse_itg << 4; - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_L, exp_val & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_EXPOSURE_L); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_M, (exp_val >> 8) & 0xFF); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_EXPOSURE_M); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_H, (exp_val >> 16) & 0x0F); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_EXPOSURE_H); - return ret; - } - - /* Analog gain */ - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_AGC_L, gain & 0xff); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_AGC_L); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_AGC_H, (gain >> 8) & 0xff); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_AGC_H); - return ret; - } - - /* Digital gain */ - if (digitgain) { - ret = ov5693_write_reg(client, OV5693_16BIT, - OV5693_MWB_RED_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_MWB_RED_GAIN_H); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_16BIT, - OV5693_MWB_GREEN_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_MWB_RED_GAIN_H); - return ret; - } - - ret = ov5693_write_reg(client, OV5693_16BIT, - OV5693_MWB_BLUE_GAIN_H, digitgain); - if (ret) { - dev_err(&client->dev, "%s: write %x error, aborted\n", - __func__, OV5693_MWB_RED_GAIN_H); - return ret; - } - } - - /* End group */ - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_GROUP_ACCESS, 0x10); - if (ret) - return ret; - - /* Delay launch group */ - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_GROUP_ACCESS, 0xa0); - if (ret) - return ret; - return ret; -} - -static int ov5693_set_exposure(struct v4l2_subdev *sd, int exposure, - int gain, int digitgain) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - int ret; - - mutex_lock(&dev->input_lock); - ret = __ov5693_set_exposure(sd, exposure, gain, digitgain); - mutex_unlock(&dev->input_lock); - - return ret; -} - -static long ov5693_s_exposure(struct v4l2_subdev *sd, - struct atomisp_exposure *exposure) -{ - u16 coarse_itg = exposure->integration_time[0]; - u16 analog_gain = exposure->gain[0]; - u16 digital_gain = exposure->gain[1]; - - /* we should not accept the invalid value below */ - if (analog_gain == 0) { - struct i2c_client *client = v4l2_get_subdevdata(sd); - v4l2_err(client, "%s: invalid value\n", __func__); - return -EINVAL; - } - return ov5693_set_exposure(sd, coarse_itg, analog_gain, digital_gain); -} - -static int ov5693_read_otp_reg_array(struct i2c_client *client, u16 size, - u16 addr, u8 *buf) -{ - u16 index; - int ret; - u16 *pVal = NULL; - - for (index = 0; index <= size; index++) { - pVal = (u16 *) (buf + index); - ret = - ov5693_read_reg(client, OV5693_8BIT, addr + index, - pVal); - if (ret) - return ret; - } - - return 0; -} - -static int __ov5693_otp_read(struct v4l2_subdev *sd, u8 *buf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov5693_device *dev = to_ov5693_sensor(sd); - int ret; - int i; - u8 *b = buf; - dev->otp_size = 0; - for (i = 1; i < OV5693_OTP_BANK_MAX; i++) { - /*set bank NO and OTP read mode. */ - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_BANK_REG, (i | 0xc0)); //[7:6] 2'b11 [5:0] bank no - if (ret) { - dev_err(&client->dev, "failed to prepare OTP page\n"); - return ret; - } - //pr_debug("write 0x%x->0x%x\n",OV5693_OTP_BANK_REG,(i|0xc0)); - - /*enable read */ - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_OTP_READ_REG, OV5693_OTP_MODE_READ); // enable :1 - if (ret) { - dev_err(&client->dev, - "failed to set OTP reading mode page"); - return ret; - } - //pr_debug("write 0x%x->0x%x\n",OV5693_OTP_READ_REG,OV5693_OTP_MODE_READ); - - /* Reading the OTP data array */ - ret = ov5693_read_otp_reg_array(client, OV5693_OTP_BANK_SIZE, - OV5693_OTP_START_ADDR, - b); - if (ret) { - dev_err(&client->dev, "failed to read OTP data\n"); - return ret; - } - - //pr_debug("BANK[%2d] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", i, *b, *(b+1), *(b+2), *(b+3), *(b+4), *(b+5), *(b+6), *(b+7), *(b+8), *(b+9), *(b+10), *(b+11), *(b+12), *(b+13), *(b+14), *(b+15)); - - //Intel OTP map, try to read 320byts first. - if (21 == i) { - if ((*b) == 0) { - dev->otp_size = 320; - break; - } else { - b = buf; - continue; - } - } else if (24 == i) { //if the first 320bytes data doesn't not exist, try to read the next 32bytes data. - if ((*b) == 0) { - dev->otp_size = 32; - break; - } else { - b = buf; - continue; - } - } else if (27 == i) { //if the prvious 32bytes data doesn't exist, try to read the next 32bytes data again. - if ((*b) == 0) { - dev->otp_size = 32; - break; - } else { - dev->otp_size = 0; // no OTP data. - break; - } - } - - b = b + OV5693_OTP_BANK_SIZE; - } - return 0; -} - -/* - * Read otp data and store it into a kmalloced buffer. - * The caller must kfree the buffer when no more needed. - * @size: set to the size of the returned otp data. - */ -static void *ov5693_otp_read(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 *buf; - int ret; - - buf = devm_kzalloc(&client->dev, (OV5693_OTP_DATA_SIZE + 16), GFP_KERNEL); - if (!buf) - return ERR_PTR(-ENOMEM); - - //otp valid after mipi on and sw stream on - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_FRAME_OFF_NUM, 0x00); - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_SW_STREAM, OV5693_START_STREAMING); - - ret = __ov5693_otp_read(sd, buf); - - //mipi off and sw stream off after otp read - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_FRAME_OFF_NUM, 0x0f); - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_SW_STREAM, OV5693_STOP_STREAMING); - - /* Driver has failed to find valid data */ - if (ret) { - dev_err(&client->dev, "sensor found no valid OTP data\n"); - return ERR_PTR(ret); - } - - return buf; -} - -static int ov5693_g_priv_int_data(struct v4l2_subdev *sd, - struct v4l2_private_int_data *priv) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov5693_device *dev = to_ov5693_sensor(sd); - u8 __user *to = priv->data; - u32 read_size = priv->size; - int ret; - - /* No need to copy data if size is 0 */ - if (!read_size) - goto out; - - if (IS_ERR(dev->otp_data)) { - dev_err(&client->dev, "OTP data not available"); - return PTR_ERR(dev->otp_data); - } - - /* Correct read_size value only if bigger than maximum */ - if (read_size > OV5693_OTP_DATA_SIZE) - read_size = OV5693_OTP_DATA_SIZE; - - ret = copy_to_user(to, dev->otp_data, read_size); - if (ret) { - dev_err(&client->dev, "%s: failed to copy OTP data to user\n", - __func__); - return -EFAULT; - } - - pr_debug("%s read_size:%d\n", __func__, read_size); - -out: - /* Return correct size */ - priv->size = dev->otp_size; - - return 0; - -} - -static long ov5693_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - - switch (cmd) { - case ATOMISP_IOC_S_EXPOSURE: - return ov5693_s_exposure(sd, arg); - case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA: - return ov5693_g_priv_int_data(sd, arg); - default: - return -EINVAL; - } - return 0; -} - -/* This returns the exposure time being used. This should only be used - for filling in EXIF data, not for actual image processing. */ -static int ov5693_q_exposure(struct v4l2_subdev *sd, s32 *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 reg_v, reg_v2; - int ret; - - /* get exposure */ - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_L, - ®_v); - if (ret) - goto err; - - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_M, - ®_v2); - if (ret) - goto err; - - reg_v += reg_v2 << 8; - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_EXPOSURE_H, - ®_v2); - if (ret) - goto err; - - *value = reg_v + (((u32)reg_v2 << 16)); -err: - return ret; -} - -static int ad5823_t_focus_vcm(struct v4l2_subdev *sd, u16 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = -EINVAL; - u8 vcm_code; - - ret = ad5823_i2c_read(client, AD5823_REG_VCM_CODE_MSB, &vcm_code); - if (ret) - return ret; - - /* set reg VCM_CODE_MSB Bit[1:0] */ - vcm_code = (vcm_code & VCM_CODE_MSB_MASK) | - ((val >> 8) & ~VCM_CODE_MSB_MASK); - ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB, vcm_code); - if (ret) - return ret; - - /* set reg VCM_CODE_LSB Bit[7:0] */ - ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_LSB, (val & 0xff)); - if (ret) - return ret; - - /* set required vcm move time */ - vcm_code = AD5823_RESONANCE_PERIOD / AD5823_RESONANCE_COEF - - AD5823_HIGH_FREQ_RANGE; - ret = ad5823_i2c_write(client, AD5823_REG_VCM_MOVE_TIME, vcm_code); - - return ret; -} - -int ad5823_t_focus_abs(struct v4l2_subdev *sd, s32 value) -{ - value = min(value, AD5823_MAX_FOCUS_POS); - return ad5823_t_focus_vcm(sd, value); -} - -static int ov5693_t_focus_abs(struct v4l2_subdev *sd, s32 value) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - dev_dbg(&client->dev, "%s: FOCUS_POS: 0x%x\n", __func__, value); - value = clamp(value, 0, OV5693_VCM_MAX_FOCUS_POS); - if (dev->vcm == VCM_DW9714) { - if (dev->vcm_update) { - ret = vcm_dw_i2c_write(client, VCM_PROTECTION_OFF); - if (ret) - return ret; - ret = vcm_dw_i2c_write(client, DIRECT_VCM); - if (ret) - return ret; - ret = vcm_dw_i2c_write(client, VCM_PROTECTION_ON); - if (ret) - return ret; - dev->vcm_update = false; - } - ret = vcm_dw_i2c_write(client, - vcm_val(value, VCM_DEFAULT_S)); - } else if (dev->vcm == VCM_AD5823) { - ad5823_t_focus_abs(sd, value); - } - if (ret == 0) { - dev->number_of_steps = value - dev->focus; - dev->focus = value; - getnstimeofday(&(dev->timestamp_t_focus_abs)); - } else - dev_err(&client->dev, - "%s: i2c failed. ret %d\n", __func__, ret); - - return ret; -} - -static int ov5693_t_focus_rel(struct v4l2_subdev *sd, s32 value) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - return ov5693_t_focus_abs(sd, dev->focus + value); -} - -#define DELAY_PER_STEP_NS 1000000 -#define DELAY_MAX_PER_STEP_NS (1000000 * 1023) -static int ov5693_q_focus_status(struct v4l2_subdev *sd, s32 *value) -{ - u32 status = 0; - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct timespec temptime; - const struct timespec timedelay = { - 0, - min((u32)abs(dev->number_of_steps) * DELAY_PER_STEP_NS, - (u32)DELAY_MAX_PER_STEP_NS), - }; - - getnstimeofday(&temptime); - temptime = timespec_sub(temptime, (dev->timestamp_t_focus_abs)); - if (timespec_compare(&temptime, &timedelay) <= 0) { - status |= ATOMISP_FOCUS_STATUS_MOVING; - status |= ATOMISP_FOCUS_HP_IN_PROGRESS; - } else { - status |= ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE; - status |= ATOMISP_FOCUS_HP_COMPLETE; - } - - *value = status; - - return 0; -} - -static int ov5693_q_focus_abs(struct v4l2_subdev *sd, s32 *value) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - s32 val; - - ov5693_q_focus_status(sd, &val); - - if (val & ATOMISP_FOCUS_STATUS_MOVING) - *value = dev->focus - dev->number_of_steps; - else - *value = dev->focus; - - return 0; -} - -static int ov5693_t_vcm_slew(struct v4l2_subdev *sd, s32 value) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - dev->number_of_steps = value; - dev->vcm_update = true; - return 0; -} - -static int ov5693_t_vcm_timing(struct v4l2_subdev *sd, s32 value) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - dev->number_of_steps = value; - dev->vcm_update = true; - return 0; -} - -static int ov5693_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov5693_device *dev = - container_of(ctrl->handler, struct ov5693_device, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_FOCUS_ABSOLUTE: - dev_dbg(&client->dev, "%s: CID_FOCUS_ABSOLUTE:%d.\n", - __func__, ctrl->val); - ret = ov5693_t_focus_abs(&dev->sd, ctrl->val); - break; - case V4L2_CID_FOCUS_RELATIVE: - dev_dbg(&client->dev, "%s: CID_FOCUS_RELATIVE:%d.\n", - __func__, ctrl->val); - ret = ov5693_t_focus_rel(&dev->sd, ctrl->val); - break; - case V4L2_CID_VCM_SLEW: - ret = ov5693_t_vcm_slew(&dev->sd, ctrl->val); - break; - case V4L2_CID_VCM_TIMEING: - ret = ov5693_t_vcm_timing(&dev->sd, ctrl->val); - break; - default: - ret = -EINVAL; - } - return ret; -} - -static int ov5693_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov5693_device *dev = - container_of(ctrl->handler, struct ov5693_device, ctrl_handler); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE_ABSOLUTE: - ret = ov5693_q_exposure(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = ov5693_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = ov5693_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = ov5693_g_fnumber_range(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCUS_ABSOLUTE: - ret = ov5693_q_focus_abs(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCUS_STATUS: - ret = ov5693_q_focus_status(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_HORZ: - ret = ov5693_g_bin_factor_x(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_VERT: - ret = ov5693_g_bin_factor_y(&dev->sd, &ctrl->val); - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .s_ctrl = ov5693_s_ctrl, - .g_volatile_ctrl = ov5693_g_volatile_ctrl -}; - -struct v4l2_ctrl_config ov5693_controls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .min = 0x0, - .max = 0xffff, - .step = 0x01, - .def = 0x00, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = OV5693_FOCAL_LENGTH_DEFAULT, - .max = OV5693_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = OV5693_FOCAL_LENGTH_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = OV5693_F_NUMBER_DEFAULT, - .max = OV5693_F_NUMBER_DEFAULT, - .step = 0x01, - .def = OV5693_F_NUMBER_DEFAULT, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = OV5693_F_NUMBER_RANGE, - .max = OV5693_F_NUMBER_RANGE, - .step = 0x01, - .def = OV5693_F_NUMBER_RANGE, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCUS_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focus move absolute", - .min = 0, - .max = OV5693_VCM_MAX_FOCUS_POS, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCUS_RELATIVE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focus move relative", - .min = OV5693_VCM_MAX_FOCUS_NEG, - .max = OV5693_VCM_MAX_FOCUS_POS, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCUS_STATUS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focus status", - .min = 0, - .max = 100, /* allow enum to grow in the future */ - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_VCM_SLEW, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vcm slew", - .min = 0, - .max = OV5693_VCM_SLEW_STEP_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_VCM_TIMEING, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vcm step time", - .min = 0, - .max = OV5693_VCM_SLEW_TIME_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_HORZ, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "horizontal binning factor", - .min = 0, - .max = OV5693_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_VERT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vertical binning factor", - .min = 0, - .max = OV5693_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, -}; - -static int ov5693_init(struct v4l2_subdev *sd) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - pr_info("%s\n", __func__); - mutex_lock(&dev->input_lock); - dev->vcm_update = false; - - if (dev->vcm == VCM_AD5823) { - ret = vcm_ad_i2c_wr8(client, 0x01, 0x01); /* vcm init test */ - if (ret) - dev_err(&client->dev, - "vcm reset failed\n"); - /*change the mode*/ - ret = ad5823_i2c_write(client, AD5823_REG_VCM_CODE_MSB, - AD5823_RING_CTRL_ENABLE); - if (ret) - dev_err(&client->dev, - "vcm enable ringing failed\n"); - ret = ad5823_i2c_write(client, AD5823_REG_MODE, - AD5823_ARC_RES1); - if (ret) - dev_err(&client->dev, - "vcm change mode failed\n"); - } - - /*change initial focus value for ad5823*/ - if (dev->vcm == VCM_AD5823) { - dev->focus = AD5823_INIT_FOCUS_POS; - ov5693_t_focus_abs(sd, AD5823_INIT_FOCUS_POS); - } else { - dev->focus = 0; - ov5693_t_focus_abs(sd, 0); - } - - mutex_unlock(&dev->input_lock); - - return 0; -} - -static int power_ctrl(struct v4l2_subdev *sd, bool flag) -{ - int ret; - struct ov5693_device *dev = to_ov5693_sensor(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->power_ctrl) - return dev->platform_data->power_ctrl(sd, flag); - - /* This driver assumes "internal DVDD, PWDNB tied to DOVDD". - * In this set up only gpio0 (XSHUTDN) should be available - * but in some products (for example ECS) gpio1 (PWDNB) is - * also available. If gpio1 is available we emulate it being - * tied to DOVDD here. */ - if (flag) { - ret = dev->platform_data->v2p8_ctrl(sd, 1); - dev->platform_data->gpio1_ctrl(sd, 1); - if (ret == 0) { - ret = dev->platform_data->v1p8_ctrl(sd, 1); - if (ret) { - dev->platform_data->gpio1_ctrl(sd, 0); - ret = dev->platform_data->v2p8_ctrl(sd, 0); - } - } - } else { - dev->platform_data->gpio1_ctrl(sd, 0); - ret = dev->platform_data->v1p8_ctrl(sd, 0); - ret |= dev->platform_data->v2p8_ctrl(sd, 0); - } - - return ret; -} - -static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - - if (!dev || !dev->platform_data) - return -ENODEV; - - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->gpio_ctrl) - return dev->platform_data->gpio_ctrl(sd, flag); - - return dev->platform_data->gpio0_ctrl(sd, flag); -} - -static int __power_up(struct v4l2_subdev *sd) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (NULL == dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - - /* power control */ - ret = power_ctrl(sd, 1); - if (ret) - goto fail_power; - - /* according to DS, at least 5ms is needed between DOVDD and PWDN */ - /* add this delay time to 10~11ms*/ - usleep_range(10000, 11000); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 1); - if (ret) { - ret = gpio_ctrl(sd, 1); - if (ret) - goto fail_power; - } - - /* flis clock control */ - ret = dev->platform_data->flisclk_ctrl(sd, 1); - if (ret) - goto fail_clk; - - __cci_delay(up_delay); - - return 0; - -fail_clk: - gpio_ctrl(sd, 0); -fail_power: - power_ctrl(sd, 0); - dev_err(&client->dev, "sensor power-up failed\n"); - - return ret; -} - -static int power_down(struct v4l2_subdev *sd) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - dev->focus = OV5693_INVALID_CONFIG; - if (NULL == dev->platform_data) { - dev_err(&client->dev, - "no camera_sensor_platform_data"); - return -ENODEV; - } - - ret = dev->platform_data->flisclk_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "flisclk failed\n"); - - /* gpio ctrl */ - ret = gpio_ctrl(sd, 0); - if (ret) { - ret = gpio_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "gpio failed 2\n"); - } - - /* power control */ - ret = power_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "vprog failed.\n"); - - return ret; -} - -static int power_up(struct v4l2_subdev *sd) -{ - static const int retry_count = 4; - int i, ret; - - for (i = 0; i < retry_count; i++) { - ret = __power_up(sd); - if (!ret) - return 0; - - power_down(sd); - } - return ret; -} - -static int ov5693_s_power(struct v4l2_subdev *sd, int on) -{ - int ret; - - pr_info("%s: on %d\n", __func__, on); - if (on == 0) - return power_down(sd); - else { - ret = power_up(sd); - if (!ret) { - ret = ov5693_init(sd); - /* restore settings */ - ov5693_res = ov5693_res_preview; - N_RES = N_RES_PREVIEW; - } - } - return ret; -} - -/* - * distance - calculate the distance - * @res: resolution - * @w: width - * @h: height - * - * Get the gap between res_w/res_h and w/h. - * distance = (res_w/res_h - w/h) / (w/h) * 8192 - * res->width/height smaller than w/h wouldn't be considered. - * The gap of ratio larger than 1/8 wouldn't be considered. - * Returns the value of gap or -1 if fail. - */ -#define LARGEST_ALLOWED_RATIO_MISMATCH 1024 -static int distance(struct ov5693_resolution *res, u32 w, u32 h) -{ - int ratio; - int distance; - - if (w == 0 || h == 0 || - res->width < w || res->height < h) - return -1; - - ratio = res->width << 13; - ratio /= w; - ratio *= h; - ratio /= res->height; - - distance = abs(ratio - 8192); - - if (distance > LARGEST_ALLOWED_RATIO_MISMATCH) - return -1; - - return distance; -} - -/* Return the nearest higher resolution index - * Firstly try to find the approximate aspect ratio resolution - * If we find multiple same AR resolutions, choose the - * minimal size. - */ -static int nearest_resolution_index(int w, int h) -{ - int i; - int idx = -1; - int dist; - int min_dist = INT_MAX; - int min_res_w = INT_MAX; - struct ov5693_resolution *tmp_res = NULL; - - for (i = 0; i < N_RES; i++) { - tmp_res = &ov5693_res[i]; - dist = distance(tmp_res, w, h); - if (dist == -1) - continue; - if (dist < min_dist) { - min_dist = dist; - idx = i; - min_res_w = ov5693_res[i].width; - continue; - } - if (dist == min_dist && ov5693_res[i].width < min_res_w) - idx = i; - } - - return idx; -} - -static int get_resolution_index(int w, int h) -{ - int i; - - for (i = 0; i < N_RES; i++) { - if (w != ov5693_res[i].width) - continue; - if (h != ov5693_res[i].height) - continue; - - return i; - } - - return -1; -} - -/* TODO: remove it. */ -static int startup(struct v4l2_subdev *sd) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - ret = ov5693_write_reg(client, OV5693_8BIT, - OV5693_SW_RESET, 0x01); - if (ret) { - dev_err(&client->dev, "ov5693 reset err.\n"); - return ret; - } - - ret = ov5693_write_reg_array(client, ov5693_global_setting); - if (ret) { - dev_err(&client->dev, "ov5693 write register err.\n"); - return ret; - } - - ret = ov5693_write_reg_array(client, ov5693_res[dev->fmt_idx].regs); - if (ret) { - dev_err(&client->dev, "ov5693 write register err.\n"); - return ret; - } - - return ret; -} - -static int ov5693_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_mipi_info *ov5693_info = NULL; - int ret = 0; - int idx; - if (format->pad) - return -EINVAL; - if (!fmt) - return -EINVAL; - ov5693_info = v4l2_get_subdev_hostdata(sd); - if (ov5693_info == NULL) - return -EINVAL; - - mutex_lock(&dev->input_lock); - idx = nearest_resolution_index(fmt->width, fmt->height); - if (idx == -1) { - /* return the largest resolution */ - fmt->width = ov5693_res[N_RES - 1].width; - fmt->height = ov5693_res[N_RES - 1].height; - } else { - fmt->width = ov5693_res[idx].width; - fmt->height = ov5693_res[idx].height; - } - - fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; - mutex_unlock(&dev->input_lock); - return 0; - } - - dev->fmt_idx = get_resolution_index(fmt->width, fmt->height); - if (dev->fmt_idx == -1) { - dev_err(&client->dev, "get resolution fail\n"); - mutex_unlock(&dev->input_lock); - return -EINVAL; - } - - ret = startup(sd); - if (ret) { - int i = 0; - dev_err(&client->dev, "ov5693 startup err, retry to power up\n"); - for (i = 0; i < OV5693_POWER_UP_RETRY_NUM; i++) { - dev_err(&client->dev, - "ov5693 retry to power up %d/%d times, result: ", - i+1, OV5693_POWER_UP_RETRY_NUM); - power_down(sd); - ret = power_up(sd); - if (!ret) { - mutex_unlock(&dev->input_lock); - ov5693_init(sd); - mutex_lock(&dev->input_lock); - } else { - dev_err(&client->dev, "power up failed, continue\n"); - continue; - } - ret = startup(sd); - if (ret) { - dev_err(&client->dev, " startup FAILED!\n"); - } else { - dev_err(&client->dev, " startup SUCCESS!\n"); - break; - } - } - } - - /* - * After sensor settings are set to HW, sometimes stream is started. - * This would cause ISP timeout because ISP is not ready to receive - * data yet. So add stop streaming here. - */ - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM, - OV5693_STOP_STREAMING); - if (ret) - dev_warn(&client->dev, "ov5693 stream off err\n"); - - ret = ov5693_get_intg_factor(client, ov5693_info, - &ov5693_res[dev->fmt_idx]); - if (ret) { - dev_err(&client->dev, "failed to get integration_factor\n"); - goto err; - } - - ov5693_info->metadata_width = fmt->width * 10 / 8; - ov5693_info->metadata_height = 1; - ov5693_info->metadata_effective_width = &ov5693_embedded_effective_size; - -err: - mutex_unlock(&dev->input_lock); - return ret; -} -static int ov5693_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct ov5693_device *dev = to_ov5693_sensor(sd); - if (format->pad) - return -EINVAL; - - if (!fmt) - return -EINVAL; - - fmt->width = ov5693_res[dev->fmt_idx].width; - fmt->height = ov5693_res[dev->fmt_idx].height; - fmt->code = MEDIA_BUS_FMT_SBGGR10_1X10; - - return 0; -} - -static int ov5693_detect(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - u16 high, low; - int ret; - u16 id; - u8 revision; - - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) - return -ENODEV; - - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_SC_CMMN_CHIP_ID_H, &high); - if (ret) { - dev_err(&client->dev, "sensor_id_high = 0x%x\n", high); - return -ENODEV; - } - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_SC_CMMN_CHIP_ID_L, &low); - id = ((((u16) high) << 8) | (u16) low); - - if (id != OV5693_ID) { - dev_err(&client->dev, "sensor ID error 0x%x\n", id); - return -ENODEV; - } - - ret = ov5693_read_reg(client, OV5693_8BIT, - OV5693_SC_CMMN_SUB_ID, &high); - revision = (u8) high & 0x0f; - - dev_dbg(&client->dev, "sensor_revision = 0x%x\n", revision); - dev_dbg(&client->dev, "detect ov5693 success\n"); - return 0; -} - -static int ov5693_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - mutex_lock(&dev->input_lock); - - ret = ov5693_write_reg(client, OV5693_8BIT, OV5693_SW_STREAM, - enable ? OV5693_START_STREAMING : - OV5693_STOP_STREAMING); - - mutex_unlock(&dev->input_lock); - - return ret; -} - - -static int ov5693_s_config(struct v4l2_subdev *sd, - int irq, void *platform_data) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = 0; - - if (platform_data == NULL) - return -ENODEV; - - dev->platform_data = - (struct camera_sensor_platform_data *)platform_data; - - mutex_lock(&dev->input_lock); - /* power off the module, then power on it in future - * as first power on by board may not fulfill the - * power on sequqence needed by the module - */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "ov5693 power-off err.\n"); - goto fail_power_off; - } - - ret = power_up(sd); - if (ret) { - dev_err(&client->dev, "ov5693 power-up err.\n"); - goto fail_power_on; - } - - if (!dev->vcm) - dev->vcm = vcm_detect(client); - - ret = dev->platform_data->csi_cfg(sd, 1); - if (ret) - goto fail_csi_cfg; - - /* config & detect sensor */ - ret = ov5693_detect(client); - if (ret) { - dev_err(&client->dev, "ov5693_detect err s_config.\n"); - goto fail_csi_cfg; - } - - dev->otp_data = ov5693_otp_read(sd); - - /* turn off sensor, after probed */ - ret = power_down(sd); - if (ret) { - dev_err(&client->dev, "ov5693 power-off err.\n"); - goto fail_csi_cfg; - } - mutex_unlock(&dev->input_lock); - - return ret; - -fail_csi_cfg: - dev->platform_data->csi_cfg(sd, 0); -fail_power_on: - power_down(sd); - dev_err(&client->dev, "sensor power-gating failed\n"); -fail_power_off: - mutex_unlock(&dev->input_lock); - return ret; -} - -static int ov5693_g_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (!param) - return -EINVAL; - - if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dev_err(&client->dev, "unsupported buffer type.\n"); - return -EINVAL; - } - - memset(param, 0, sizeof(*param)); - param->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (dev->fmt_idx >= 0 && dev->fmt_idx < N_RES) { - param->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - param->parm.capture.timeperframe.numerator = 1; - param->parm.capture.capturemode = dev->run_mode; - param->parm.capture.timeperframe.denominator = - ov5693_res[dev->fmt_idx].fps; - } - return 0; -} - -static int ov5693_s_parm(struct v4l2_subdev *sd, - struct v4l2_streamparm *param) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - dev->run_mode = param->parm.capture.capturemode; - - mutex_lock(&dev->input_lock); - switch (dev->run_mode) { - case CI_MODE_VIDEO: - ov5693_res = ov5693_res_video; - N_RES = N_RES_VIDEO; - break; - case CI_MODE_STILL_CAPTURE: - ov5693_res = ov5693_res_still; - N_RES = N_RES_STILL; - break; - default: - ov5693_res = ov5693_res_preview; - N_RES = N_RES_PREVIEW; - } - mutex_unlock(&dev->input_lock); - return 0; -} - -static int ov5693_g_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct ov5693_device *dev = to_ov5693_sensor(sd); - - interval->interval.numerator = 1; - interval->interval.denominator = ov5693_res[dev->fmt_idx].fps; - - return 0; -} - -static int ov5693_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->index >= MAX_FMTS) - return -EINVAL; - - code->code = MEDIA_BUS_FMT_SBGGR10_1X10; - return 0; -} - -static int ov5693_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - int index = fse->index; - - if (index >= N_RES) - return -EINVAL; - - fse->min_width = ov5693_res[index].width; - fse->min_height = ov5693_res[index].height; - fse->max_width = ov5693_res[index].width; - fse->max_height = ov5693_res[index].height; - - return 0; - -} - -static const struct v4l2_subdev_video_ops ov5693_video_ops = { - .s_stream = ov5693_s_stream, - .g_parm = ov5693_g_parm, - .s_parm = ov5693_s_parm, - .g_frame_interval = ov5693_g_frame_interval, -}; - -static const struct v4l2_subdev_core_ops ov5693_core_ops = { - .s_power = ov5693_s_power, - .ioctl = ov5693_ioctl, -}; - -static const struct v4l2_subdev_pad_ops ov5693_pad_ops = { - .enum_mbus_code = ov5693_enum_mbus_code, - .enum_frame_size = ov5693_enum_frame_size, - .get_fmt = ov5693_get_fmt, - .set_fmt = ov5693_set_fmt, -}; - -static const struct v4l2_subdev_ops ov5693_ops = { - .core = &ov5693_core_ops, - .video = &ov5693_video_ops, - .pad = &ov5693_pad_ops, -}; - -static int ov5693_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ov5693_device *dev = to_ov5693_sensor(sd); - dev_dbg(&client->dev, "ov5693_remove...\n"); - - dev->platform_data->csi_cfg(sd, 0); - - v4l2_device_unregister_subdev(sd); - - atomisp_gmin_remove_subdev(sd); - - media_entity_cleanup(&dev->sd.entity); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - kfree(dev); - - return 0; -} - -static int ov5693_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct ov5693_device *dev; - int i2c; - int ret = 0; - void *pdata = client->dev.platform_data; - struct acpi_device *adev; - unsigned int i; - - /* Firmware workaround: Some modules use a "secondary default" - * address of 0x10 which doesn't appear on schematics, and - * some BIOS versions haven't gotten the memo. Work around - * via config. */ - i2c = gmin_get_var_int(&client->dev, "I2CAddr", -1); - if (i2c != -1) { - dev_info(&client->dev, - "Overriding firmware-provided I2C address (0x%x) with 0x%x\n", - client->addr, i2c); - client->addr = i2c; - } - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "out of memory\n"); - return -ENOMEM; - } - - mutex_init(&dev->input_lock); - - dev->fmt_idx = 0; - v4l2_i2c_subdev_init(&(dev->sd), client, &ov5693_ops); - - adev = ACPI_COMPANION(&client->dev); - if (adev) { - adev->power.flags.power_resources = 0; - pdata = gmin_camera_platform_data(&dev->sd, - ATOMISP_INPUT_FORMAT_RAW_10, - atomisp_bayer_order_bggr); - } - - if (!pdata) - goto out_free; - - ret = ov5693_s_config(&dev->sd, client->irq, pdata); - if (ret) - goto out_free; - - ret = atomisp_register_i2c_module(&dev->sd, pdata, RAW_CAMERA); - if (ret) - goto out_free; - - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->format.code = MEDIA_BUS_FMT_SBGGR10_1X10; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - ret = - v4l2_ctrl_handler_init(&dev->ctrl_handler, - ARRAY_SIZE(ov5693_controls)); - if (ret) { - ov5693_remove(client); - return ret; - } - - for (i = 0; i < ARRAY_SIZE(ov5693_controls); i++) - v4l2_ctrl_new_custom(&dev->ctrl_handler, &ov5693_controls[i], - NULL); - - if (dev->ctrl_handler.error) { - ov5693_remove(client); - return dev->ctrl_handler.error; - } - - /* Use same lock for controls as for everything else. */ - dev->ctrl_handler.lock = &dev->input_lock; - dev->sd.ctrl_handler = &dev->ctrl_handler; - - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); - if (ret) - ov5693_remove(client); - - return ret; -out_free: - v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); - return ret; -} - -MODULE_DEVICE_TABLE(i2c, ov5693_id); - -static const struct acpi_device_id ov5693_acpi_match[] = { - {"INT33BE"}, - {}, -}; -MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match); - -static struct i2c_driver ov5693_driver = { - .driver = { - .name = OV5693_NAME, - .acpi_match_table = ACPI_PTR(ov5693_acpi_match), - }, - .probe = ov5693_probe, - .remove = ov5693_remove, - .id_table = ov5693_id, -}; - -static int init_ov5693(void) -{ - return i2c_add_driver(&ov5693_driver); -} - -static void exit_ov5693(void) -{ - - i2c_del_driver(&ov5693_driver); -} - -module_init(init_ov5693); -module_exit(exit_ov5693); - -MODULE_DESCRIPTION("A low-level driver for OmniVision 5693 sensors"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From af7db4e90e47cc9e2220fb827e9c11235370c603 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 25 Sep 2017 13:17:31 +0200 Subject: media: staging: atomisp: Update TODO regarding sensors There was no specific item regarding what should be done to sensor, lens and flash drivers. Add one, to replace the vague item denoting support only to particular sensor, lens and flash devices. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/TODO | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/staging/media/atomisp/TODO b/drivers/staging/media/atomisp/TODO index 737452cbf8a0..447cb59c215a 100644 --- a/drivers/staging/media/atomisp/TODO +++ b/drivers/staging/media/atomisp/TODO @@ -36,13 +36,21 @@ there are any specific things that can be done to fold in support for multiple firmware versions. +8. Switch to V4L2 async API to set up sensor, lens and flash devices. + Control those devices using V4L2 sub-device API without custom + extensions. -Limitations: +9. Switch to standard V4L2 sub-device API for sensor and lens. In + particular, the user space API needs to support V4L2 controls as + defined in the V4L2 spec and references to atomisp must be removed from + these drivers. + +10. Use LED flash API for flash LED drivers such as LM3554 (which already + has a LED class driver). -1. Currently the patch only support some camera sensors - gc2235/gc0310/0v2680/ov2722/ov5693/mt9m114... +Limitations: -2. To test the patches, you also need the ISP firmware +1. To test the patches, you also need the ISP firmware for BYT:/lib/firmware/shisp_2400b0_v21.bin for CHT:/lib/firmware/shisp_2401a0_v21.bin @@ -51,14 +59,14 @@ Limitations: device but can also be extracted from the upgrade kit if you've managed to lose them somehow. -3. Without a 3A libary the capture behaviour is not very good. To take a good +2. Without a 3A libary the capture behaviour is not very good. To take a good picture, you need tune ISP parameters by IOCTL functions or use a 3A libary such as libxcam. -4. The driver is intended to drive the PCI exposed versions of the device. +3. The driver is intended to drive the PCI exposed versions of the device. It will not detect those devices enumerated via ACPI as a field of the i915 GPU driver. -5. The driver supports only v2 of the IPU/Camera. It will not work with the +4. The driver supports only v2 of the IPU/Camera. It will not work with the versions of the hardware in other SoCs. -- cgit v1.2.3 From 79bd3daaa86e9734289bfd0c994633fee381973e Mon Sep 17 00:00:00 2001 From: Muhammad Falak R Wani Date: Sat, 23 Sep 2017 21:45:34 +0200 Subject: media: staging/atomisp: make six local functions static to appease sparse The functions __bo_alloc, __bo_search_and_remove_from_free_rbtree, __bo_search_by_addr, __bo_search_by_addr_in_range, __bo_break_up and __bo_merge are local to the source and do not need to be in the global scope, so make them static. Cleans up sparse warnings: warning: symbol '__bo_alloc' was not declared. Should it be static? warning: symbol '__bo_search_and_remove_from_free_rbtree' was not declared. Should it be static? warning: symbol '__bo_search_by_addr' was not declared. Should it be static? warning: symbol '__bo_search_by_addr_in_range' was not declared. Should it be static? warning: symbol '__bo_break_up' was not declared. Should it be static? warning: symbol '__bo_merge' was not declared. Should it be static? Signed-off-by: Muhammad Falak R Wani Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_bo.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_bo.c b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_bo.c index e6ddfbf0c4e2..8007b6f50179 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_bo.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_bo.c @@ -58,7 +58,7 @@ static unsigned int nr_to_order_bottom(unsigned int nr) return fls(nr) - 1; } -struct hmm_buffer_object *__bo_alloc(struct kmem_cache *bo_cache) +static struct hmm_buffer_object *__bo_alloc(struct kmem_cache *bo_cache) { struct hmm_buffer_object *bo; @@ -99,7 +99,7 @@ static int __bo_init(struct hmm_bo_device *bdev, struct hmm_buffer_object *bo, return 0; } -struct hmm_buffer_object *__bo_search_and_remove_from_free_rbtree( +static struct hmm_buffer_object *__bo_search_and_remove_from_free_rbtree( struct rb_node *node, unsigned int pgnr) { struct hmm_buffer_object *this, *ret_bo, *temp_bo; @@ -150,7 +150,7 @@ remove_bo_and_return: return temp_bo; } -struct hmm_buffer_object *__bo_search_by_addr(struct rb_root *root, +static struct hmm_buffer_object *__bo_search_by_addr(struct rb_root *root, ia_css_ptr start) { struct rb_node *n = root->rb_node; @@ -175,8 +175,8 @@ struct hmm_buffer_object *__bo_search_by_addr(struct rb_root *root, return NULL; } -struct hmm_buffer_object *__bo_search_by_addr_in_range(struct rb_root *root, - unsigned int start) +static struct hmm_buffer_object *__bo_search_by_addr_in_range( + struct rb_root *root, unsigned int start) { struct rb_node *n = root->rb_node; struct hmm_buffer_object *bo; @@ -258,7 +258,7 @@ static void __bo_insert_to_alloc_rbtree(struct rb_root *root, rb_insert_color(&bo->node, root); } -struct hmm_buffer_object *__bo_break_up(struct hmm_bo_device *bdev, +static struct hmm_buffer_object *__bo_break_up(struct hmm_bo_device *bdev, struct hmm_buffer_object *bo, unsigned int pgnr) { @@ -331,7 +331,7 @@ static void __bo_take_off_handling(struct hmm_buffer_object *bo) } } -struct hmm_buffer_object *__bo_merge(struct hmm_buffer_object *bo, +static struct hmm_buffer_object *__bo_merge(struct hmm_buffer_object *bo, struct hmm_buffer_object *next_bo) { struct hmm_bo_device *bdev; -- cgit v1.2.3 From bc64ce98d6493337b61b958da454ecc9b35237a5 Mon Sep 17 00:00:00 2001 From: Jérémy Lefaure Date: Sun, 1 Oct 2017 21:30:54 +0200 Subject: media: staging: atomisp: use ARRAY_SIZE Using the ARRAY_SIZE macro improves the readability of the code. Also, it is useless to use a variable to store this constant calculated at compile time. Found with Coccinelle with the following semantic patch: @r depends on (org || report)@ type T; T[] E; position p; @@ ( (sizeof(E)@p /sizeof(*E)) | (sizeof(E)@p /sizeof(E[...])) | (sizeof(E)@p /sizeof(T)) ) Signed-off-by: Jérémy Lefaure Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../pci/atomisp2/css2400/camera/pipe/src/pipe_binarydesc.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/camera/pipe/src/pipe_binarydesc.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/camera/pipe/src/pipe_binarydesc.c index 17d3b7de93ba..98a2a3e9b3e6 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/camera/pipe/src/pipe_binarydesc.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/camera/pipe/src/pipe_binarydesc.c @@ -22,6 +22,7 @@ #include /* HRT_GDC_N */ #include "gdc_device.h" +#include /* This module provides a binary descriptions to used to find a binary. Since, * every stage is associated with a binary, it implicity helps stage @@ -147,11 +148,9 @@ enum ia_css_err sh_css_bds_factor_get_numerator_denominator( unsigned int *bds_factor_denominator) { unsigned int i; - unsigned int bds_list_size = sizeof(bds_factors_list) / - sizeof(struct sh_css_bds_factor); /* Loop over all bds factors until a match is found */ - for (i = 0; i < bds_list_size; i++) { + for (i = 0; i < ARRAY_SIZE(bds_factors_list); i++) { if (bds_factors_list[i].bds_factor == bds_factor) { *bds_factor_numerator = bds_factors_list[i].numerator; *bds_factor_denominator = bds_factors_list[i].denominator; @@ -170,8 +169,6 @@ enum ia_css_err binarydesc_calculate_bds_factor( unsigned int *bds_factor) { unsigned int i; - unsigned int bds_list_size = sizeof(bds_factors_list) / - sizeof(struct sh_css_bds_factor); unsigned int in_w = input_res.width, in_h = input_res.height, out_w = output_res.width, out_h = output_res.height; @@ -186,7 +183,7 @@ enum ia_css_err binarydesc_calculate_bds_factor( assert(out_w != 0 && out_h != 0); /* Loop over all bds factors until a match is found */ - for (i = 0; i < bds_list_size; i++) { + for (i = 0; i < ARRAY_SIZE(bds_factors_list); i++) { unsigned num = bds_factors_list[i].numerator; unsigned den = bds_factors_list[i].denominator; -- cgit v1.2.3 From d524b8fc75f1ad8132b6661b48a8cbfba37ecc2b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 15 Jul 2017 10:51:24 +0200 Subject: media: dt-bindings: document the tegra CEC bindings This documents the binding for the Tegra CEC module. Signed-off-by: Hans Verkuil Acked-by: Rob Herring Acked-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/tegra-cec.txt | 27 ++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/tegra-cec.txt diff --git a/Documentation/devicetree/bindings/media/tegra-cec.txt b/Documentation/devicetree/bindings/media/tegra-cec.txt new file mode 100644 index 000000000000..c503f06f3b84 --- /dev/null +++ b/Documentation/devicetree/bindings/media/tegra-cec.txt @@ -0,0 +1,27 @@ +* Tegra HDMI CEC hardware + +The HDMI CEC module is present in Tegra SoCs and its purpose is to +handle communication between HDMI connected devices over the CEC bus. + +Required properties: + - compatible : value should be one of the following: + "nvidia,tegra114-cec" + "nvidia,tegra124-cec" + "nvidia,tegra210-cec" + - reg : Physical base address of the IP registers and length of memory + mapped region. + - interrupts : HDMI CEC interrupt number to the CPU. + - clocks : from common clock binding: handle to HDMI CEC clock. + - clock-names : from common clock binding: must contain "cec", + corresponding to the entry in the clocks property. + - hdmi-phandle : phandle to the HDMI controller, see also cec.txt. + +Example: + +cec@70015000 { + compatible = "nvidia,tegra124-cec"; + reg = <0x0 0x70015000 0x0 0x00001000>; + interrupts = ; + clocks = <&tegra_car TEGRA124_CLK_CEC>; + clock-names = "cec"; +}; -- cgit v1.2.3 From 9d2d60687c9a0621e0da40338be4cbd7e3783be2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 15 Jul 2017 10:51:00 +0200 Subject: media: tegra-cec: add Tegra HDMI CEC driver This driver adds support for the Tegra CEC IP. It is based on the NVIDIA drivers/misc/tegra-cec driver in their 3.10 kernel. This has been converted to the CEC framework and cleaned up. Tested with my Jetson TK1 board. It has also been tested with the Tegra X1 in an embedded product. Note of warning for the Tegra X2: this SoC supports two HDMI outputs, but only one CEC adapter and the CEC bus is shared between the two outputs. This is a design mistake and the CEC adapter can control only one HDMI output. Never hook up both HDMI outputs to the CEC bus in a hardware design: this is illegal as per the CEC specification. The CEC bus can be shared between multiple inputs and zero or one outputs, but not between multiple outputs. Signed-off-by: Hans Verkuil Acked-by: Thierry Reding Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 8 + drivers/media/platform/Kconfig | 11 + drivers/media/platform/Makefile | 2 + drivers/media/platform/tegra-cec/Makefile | 1 + drivers/media/platform/tegra-cec/tegra_cec.c | 501 +++++++++++++++++++++++++++ drivers/media/platform/tegra-cec/tegra_cec.h | 127 +++++++ 6 files changed, 650 insertions(+) create mode 100644 drivers/media/platform/tegra-cec/Makefile create mode 100644 drivers/media/platform/tegra-cec/tegra_cec.c create mode 100644 drivers/media/platform/tegra-cec/tegra_cec.h diff --git a/MAINTAINERS b/MAINTAINERS index dbeaa2c44dcd..adbf69306e9e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1961,6 +1961,14 @@ M: Lennert Buytenhek L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained +ARM/TEGRA HDMI CEC SUBSYSTEM SUPPORT +M: Hans Verkuil +L: linux-tegra@vger.kernel.org +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/platform/tegra-cec/ +F: Documentation/devicetree/bindings/media/tegra-cec.txt + ARM/TETON BGA MACHINE SUPPORT M: "Mark F. Brown" L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 2dc1d8fe4f5f..fd0c99859d6f 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -614,6 +614,17 @@ config VIDEO_STM32_HDMI_CEC CEC bus is present in the HDMI connector and enables communication between compatible devices. +config VIDEO_TEGRA_HDMI_CEC + tristate "Tegra HDMI CEC driver" + depends on ARCH_TEGRA || COMPILE_TEST + select CEC_CORE + select CEC_NOTIFIER + ---help--- + This is a driver for the Tegra HDMI CEC interface. It uses the + generic CEC framework interface. + The CEC bus is present in the HDMI connector and enables communication + between compatible devices. + endif #CEC_PLATFORM_DRIVERS menuconfig SDR_PLATFORM_DRIVERS diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 1530b096db10..012eb4782156 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -48,6 +48,8 @@ obj-$(CONFIG_VIDEO_STI_HDMI_CEC) += sti/cec/ obj-$(CONFIG_VIDEO_STI_DELTA) += sti/delta/ +obj-$(CONFIG_VIDEO_TEGRA_HDMI_CEC) += tegra-cec/ + obj-y += stm32/ obj-y += blackfin/ diff --git a/drivers/media/platform/tegra-cec/Makefile b/drivers/media/platform/tegra-cec/Makefile new file mode 100644 index 000000000000..f3d81127589f --- /dev/null +++ b/drivers/media/platform/tegra-cec/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_VIDEO_TEGRA_HDMI_CEC) += tegra_cec.o diff --git a/drivers/media/platform/tegra-cec/tegra_cec.c b/drivers/media/platform/tegra-cec/tegra_cec.c new file mode 100644 index 000000000000..b53743f555e8 --- /dev/null +++ b/drivers/media/platform/tegra-cec/tegra_cec.c @@ -0,0 +1,501 @@ +/* + * Tegra CEC implementation + * + * The original 3.10 CEC driver using a custom API: + * + * Copyright (c) 2012-2015, NVIDIA CORPORATION. All rights reserved. + * + * Conversion to the CEC framework and to the mainline kernel: + * + * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "tegra_cec.h" + +#define TEGRA_CEC_NAME "tegra-cec" + +struct tegra_cec { + struct cec_adapter *adap; + struct device *dev; + struct clk *clk; + void __iomem *cec_base; + struct cec_notifier *notifier; + int tegra_cec_irq; + bool rx_done; + bool tx_done; + int tx_status; + u8 rx_buf[CEC_MAX_MSG_SIZE]; + u8 rx_buf_cnt; + u32 tx_buf[CEC_MAX_MSG_SIZE]; + u8 tx_buf_cur; + u8 tx_buf_cnt; +}; + +static inline u32 cec_read(struct tegra_cec *cec, u32 reg) +{ + return readl(cec->cec_base + reg); +} + +static inline void cec_write(struct tegra_cec *cec, u32 reg, u32 val) +{ + writel(val, cec->cec_base + reg); +} + +static void tegra_cec_error_recovery(struct tegra_cec *cec) +{ + u32 hw_ctrl; + + hw_ctrl = cec_read(cec, TEGRA_CEC_HW_CONTROL); + cec_write(cec, TEGRA_CEC_HW_CONTROL, 0); + cec_write(cec, TEGRA_CEC_INT_STAT, 0xffffffff); + cec_write(cec, TEGRA_CEC_HW_CONTROL, hw_ctrl); +} + +static irqreturn_t tegra_cec_irq_thread_handler(int irq, void *data) +{ + struct device *dev = data; + struct tegra_cec *cec = dev_get_drvdata(dev); + + if (cec->tx_done) { + cec_transmit_attempt_done(cec->adap, cec->tx_status); + cec->tx_done = false; + } + if (cec->rx_done) { + struct cec_msg msg = {}; + + msg.len = cec->rx_buf_cnt; + memcpy(msg.msg, cec->rx_buf, msg.len); + cec_received_msg(cec->adap, &msg); + cec->rx_done = false; + cec->rx_buf_cnt = 0; + } + return IRQ_HANDLED; +} + +static irqreturn_t tegra_cec_irq_handler(int irq, void *data) +{ + struct device *dev = data; + struct tegra_cec *cec = dev_get_drvdata(dev); + u32 status, mask; + + status = cec_read(cec, TEGRA_CEC_INT_STAT); + mask = cec_read(cec, TEGRA_CEC_INT_MASK); + + status &= mask; + + if (!status) + return IRQ_HANDLED; + + if (status & TEGRA_CEC_INT_STAT_TX_REGISTER_UNDERRUN) { + dev_err(dev, "TX underrun, interrupt timing issue!\n"); + + tegra_cec_error_recovery(cec); + cec_write(cec, TEGRA_CEC_INT_MASK, + mask & ~TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY); + + cec->tx_done = true; + cec->tx_status = CEC_TX_STATUS_ERROR; + return IRQ_WAKE_THREAD; + } + + if ((status & TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED) || + (status & TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED)) { + tegra_cec_error_recovery(cec); + cec_write(cec, TEGRA_CEC_INT_MASK, + mask & ~TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY); + + cec->tx_done = true; + if (status & TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED) + cec->tx_status = CEC_TX_STATUS_LOW_DRIVE; + else + cec->tx_status = CEC_TX_STATUS_ARB_LOST; + return IRQ_WAKE_THREAD; + } + + if (status & TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED) { + cec_write(cec, TEGRA_CEC_INT_STAT, + TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED); + + if (status & TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD) { + tegra_cec_error_recovery(cec); + + cec->tx_done = true; + cec->tx_status = CEC_TX_STATUS_NACK; + } else { + cec->tx_done = true; + cec->tx_status = CEC_TX_STATUS_OK; + } + return IRQ_WAKE_THREAD; + } + + if (status & TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD) + dev_warn(dev, "TX NAKed on the fly!\n"); + + if (status & TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY) { + if (cec->tx_buf_cur == cec->tx_buf_cnt) { + cec_write(cec, TEGRA_CEC_INT_MASK, + mask & ~TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY); + } else { + cec_write(cec, TEGRA_CEC_TX_REGISTER, + cec->tx_buf[cec->tx_buf_cur++]); + cec_write(cec, TEGRA_CEC_INT_STAT, + TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY); + } + } + + if (status & (TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN | + TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED | + TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED | + TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED)) { + cec_write(cec, TEGRA_CEC_INT_STAT, + (TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN | + TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED | + TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED | + TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED)); + } else if (status & TEGRA_CEC_INT_STAT_RX_REGISTER_FULL) { + u32 v; + + cec_write(cec, TEGRA_CEC_INT_STAT, + TEGRA_CEC_INT_STAT_RX_REGISTER_FULL); + v = cec_read(cec, TEGRA_CEC_RX_REGISTER); + if (cec->rx_buf_cnt < CEC_MAX_MSG_SIZE) + cec->rx_buf[cec->rx_buf_cnt++] = v & 0xff; + if (v & TEGRA_CEC_RX_REGISTER_EOM) { + cec->rx_done = true; + return IRQ_WAKE_THREAD; + } + } + + return IRQ_HANDLED; +} + +static int tegra_cec_adap_enable(struct cec_adapter *adap, bool enable) +{ + struct tegra_cec *cec = adap->priv; + + cec->rx_buf_cnt = 0; + cec->tx_buf_cnt = 0; + cec->tx_buf_cur = 0; + + cec_write(cec, TEGRA_CEC_HW_CONTROL, 0); + cec_write(cec, TEGRA_CEC_INT_MASK, 0); + cec_write(cec, TEGRA_CEC_INT_STAT, 0xffffffff); + cec_write(cec, TEGRA_CEC_SW_CONTROL, 0); + + if (!enable) + return 0; + + cec_write(cec, TEGRA_CEC_INPUT_FILTER, (1U << 31) | 0x20); + + cec_write(cec, TEGRA_CEC_RX_TIMING_0, + (0x7a << TEGRA_CEC_RX_TIM0_START_BIT_MAX_LO_TIME_SHIFT) | + (0x6d << TEGRA_CEC_RX_TIM0_START_BIT_MIN_LO_TIME_SHIFT) | + (0x93 << TEGRA_CEC_RX_TIM0_START_BIT_MAX_DURATION_SHIFT) | + (0x86 << TEGRA_CEC_RX_TIM0_START_BIT_MIN_DURATION_SHIFT)); + + cec_write(cec, TEGRA_CEC_RX_TIMING_1, + (0x35 << TEGRA_CEC_RX_TIM1_DATA_BIT_MAX_LO_TIME_SHIFT) | + (0x21 << TEGRA_CEC_RX_TIM1_DATA_BIT_SAMPLE_TIME_SHIFT) | + (0x56 << TEGRA_CEC_RX_TIM1_DATA_BIT_MAX_DURATION_SHIFT) | + (0x40 << TEGRA_CEC_RX_TIM1_DATA_BIT_MIN_DURATION_SHIFT)); + + cec_write(cec, TEGRA_CEC_RX_TIMING_2, + (0x50 << TEGRA_CEC_RX_TIM2_END_OF_BLOCK_TIME_SHIFT)); + + cec_write(cec, TEGRA_CEC_TX_TIMING_0, + (0x74 << TEGRA_CEC_TX_TIM0_START_BIT_LO_TIME_SHIFT) | + (0x8d << TEGRA_CEC_TX_TIM0_START_BIT_DURATION_SHIFT) | + (0x08 << TEGRA_CEC_TX_TIM0_BUS_XITION_TIME_SHIFT) | + (0x71 << TEGRA_CEC_TX_TIM0_BUS_ERROR_LO_TIME_SHIFT)); + + cec_write(cec, TEGRA_CEC_TX_TIMING_1, + (0x2f << TEGRA_CEC_TX_TIM1_LO_DATA_BIT_LO_TIME_SHIFT) | + (0x13 << TEGRA_CEC_TX_TIM1_HI_DATA_BIT_LO_TIME_SHIFT) | + (0x4b << TEGRA_CEC_TX_TIM1_DATA_BIT_DURATION_SHIFT) | + (0x21 << TEGRA_CEC_TX_TIM1_ACK_NAK_BIT_SAMPLE_TIME_SHIFT)); + + cec_write(cec, TEGRA_CEC_TX_TIMING_2, + (0x07 << TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_ADDITIONAL_FRAME_SHIFT) | + (0x05 << TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_NEW_FRAME_SHIFT) | + (0x03 << TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_RETRY_FRAME_SHIFT)); + + cec_write(cec, TEGRA_CEC_INT_MASK, + TEGRA_CEC_INT_MASK_TX_REGISTER_UNDERRUN | + TEGRA_CEC_INT_MASK_TX_FRAME_OR_BLOCK_NAKD | + TEGRA_CEC_INT_MASK_TX_ARBITRATION_FAILED | + TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED | + TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED | + TEGRA_CEC_INT_MASK_RX_REGISTER_FULL | + TEGRA_CEC_INT_MASK_RX_REGISTER_OVERRUN); + + cec_write(cec, TEGRA_CEC_HW_CONTROL, TEGRA_CEC_HWCTRL_TX_RX_MODE); + return 0; +} + +static int tegra_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr) +{ + struct tegra_cec *cec = adap->priv; + u32 state = cec_read(cec, TEGRA_CEC_HW_CONTROL); + + if (logical_addr == CEC_LOG_ADDR_INVALID) + state &= ~TEGRA_CEC_HWCTRL_RX_LADDR_MASK; + else + state |= TEGRA_CEC_HWCTRL_RX_LADDR((1 << logical_addr)); + + cec_write(cec, TEGRA_CEC_HW_CONTROL, state); + return 0; +} + +static int tegra_cec_adap_monitor_all_enable(struct cec_adapter *adap, + bool enable) +{ + struct tegra_cec *cec = adap->priv; + u32 reg = cec_read(cec, TEGRA_CEC_HW_CONTROL); + + if (enable) + reg |= TEGRA_CEC_HWCTRL_RX_SNOOP; + else + reg &= ~TEGRA_CEC_HWCTRL_RX_SNOOP; + cec_write(cec, TEGRA_CEC_HW_CONTROL, reg); + return 0; +} + +static int tegra_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time_ms, struct cec_msg *msg) +{ + bool retry_xfer = signal_free_time_ms == CEC_SIGNAL_FREE_TIME_RETRY; + struct tegra_cec *cec = adap->priv; + unsigned int i; + u32 mode = 0; + u32 mask; + + if (cec_msg_is_broadcast(msg)) + mode = TEGRA_CEC_TX_REG_BCAST; + + cec->tx_buf_cur = 0; + cec->tx_buf_cnt = msg->len; + + for (i = 0; i < msg->len; i++) { + cec->tx_buf[i] = mode | msg->msg[i]; + if (i == 0) + cec->tx_buf[i] |= TEGRA_CEC_TX_REG_START_BIT; + if (i == msg->len - 1) + cec->tx_buf[i] |= TEGRA_CEC_TX_REG_EOM; + if (i == 0 && retry_xfer) + cec->tx_buf[i] |= TEGRA_CEC_TX_REG_RETRY; + } + + mask = cec_read(cec, TEGRA_CEC_INT_MASK); + cec_write(cec, TEGRA_CEC_INT_MASK, + mask | TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY); + + return 0; +} + +static const struct cec_adap_ops tegra_cec_ops = { + .adap_enable = tegra_cec_adap_enable, + .adap_log_addr = tegra_cec_adap_log_addr, + .adap_transmit = tegra_cec_adap_transmit, + .adap_monitor_all_enable = tegra_cec_adap_monitor_all_enable, +}; + +static int tegra_cec_probe(struct platform_device *pdev) +{ + struct platform_device *hdmi_dev; + struct device_node *np; + struct tegra_cec *cec; + struct resource *res; + int ret = 0; + + np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0); + + if (!np) { + dev_err(&pdev->dev, "Failed to find hdmi node in device tree\n"); + return -ENODEV; + } + hdmi_dev = of_find_device_by_node(np); + if (hdmi_dev == NULL) + return -EPROBE_DEFER; + + cec = devm_kzalloc(&pdev->dev, sizeof(struct tegra_cec), GFP_KERNEL); + + if (!cec) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + if (!res) { + dev_err(&pdev->dev, + "Unable to allocate resources for device\n"); + ret = -EBUSY; + goto cec_error; + } + + if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), + pdev->name)) { + dev_err(&pdev->dev, + "Unable to request mem region for device\n"); + ret = -EBUSY; + goto cec_error; + } + + cec->tegra_cec_irq = platform_get_irq(pdev, 0); + + if (cec->tegra_cec_irq <= 0) { + ret = -EBUSY; + goto cec_error; + } + + cec->cec_base = devm_ioremap_nocache(&pdev->dev, res->start, + resource_size(res)); + + if (!cec->cec_base) { + dev_err(&pdev->dev, "Unable to grab IOs for device\n"); + ret = -EBUSY; + goto cec_error; + } + + cec->clk = devm_clk_get(&pdev->dev, "cec"); + + if (IS_ERR_OR_NULL(cec->clk)) { + dev_err(&pdev->dev, "Can't get clock for CEC\n"); + ret = -ENOENT; + goto clk_error; + } + + clk_prepare_enable(cec->clk); + + /* set context info. */ + cec->dev = &pdev->dev; + + platform_set_drvdata(pdev, cec); + + ret = devm_request_threaded_irq(&pdev->dev, cec->tegra_cec_irq, + tegra_cec_irq_handler, tegra_cec_irq_thread_handler, + 0, "cec_irq", &pdev->dev); + + if (ret) { + dev_err(&pdev->dev, + "Unable to request interrupt for device\n"); + goto cec_error; + } + + cec->notifier = cec_notifier_get(&hdmi_dev->dev); + if (!cec->notifier) { + ret = -ENOMEM; + goto cec_error; + } + + cec->adap = cec_allocate_adapter(&tegra_cec_ops, cec, TEGRA_CEC_NAME, + CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL, + CEC_MAX_LOG_ADDRS); + if (IS_ERR(cec->adap)) { + ret = -ENOMEM; + dev_err(&pdev->dev, "Couldn't create cec adapter\n"); + goto cec_error; + } + ret = cec_register_adapter(cec->adap, &pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Couldn't register device\n"); + goto cec_error; + } + + cec_register_cec_notifier(cec->adap, cec->notifier); + + return 0; + +cec_error: + if (cec->notifier) + cec_notifier_put(cec->notifier); + cec_delete_adapter(cec->adap); + clk_disable_unprepare(cec->clk); +clk_error: + return ret; +} + +static int tegra_cec_remove(struct platform_device *pdev) +{ + struct tegra_cec *cec = platform_get_drvdata(pdev); + + clk_disable_unprepare(cec->clk); + + cec_unregister_adapter(cec->adap); + cec_notifier_put(cec->notifier); + + return 0; +} + +#ifdef CONFIG_PM +static int tegra_cec_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct tegra_cec *cec = platform_get_drvdata(pdev); + + clk_disable_unprepare(cec->clk); + + dev_notice(&pdev->dev, "suspended\n"); + return 0; +} + +static int tegra_cec_resume(struct platform_device *pdev) +{ + struct tegra_cec *cec = platform_get_drvdata(pdev); + + dev_notice(&pdev->dev, "Resuming\n"); + + clk_prepare_enable(cec->clk); + + return 0; +} +#endif + +static const struct of_device_id tegra_cec_of_match[] = { + { .compatible = "nvidia,tegra114-cec", }, + { .compatible = "nvidia,tegra124-cec", }, + { .compatible = "nvidia,tegra210-cec", }, + {}, +}; + +static struct platform_driver tegra_cec_driver = { + .driver = { + .name = TEGRA_CEC_NAME, + .of_match_table = of_match_ptr(tegra_cec_of_match), + }, + .probe = tegra_cec_probe, + .remove = tegra_cec_remove, + +#ifdef CONFIG_PM + .suspend = tegra_cec_suspend, + .resume = tegra_cec_resume, +#endif +}; + +module_platform_driver(tegra_cec_driver); diff --git a/drivers/media/platform/tegra-cec/tegra_cec.h b/drivers/media/platform/tegra-cec/tegra_cec.h new file mode 100644 index 000000000000..e301513daa87 --- /dev/null +++ b/drivers/media/platform/tegra-cec/tegra_cec.h @@ -0,0 +1,127 @@ +/* + * Tegra CEC register definitions + * + * The original 3.10 CEC driver using a custom API: + * + * Copyright (c) 2012-2015, NVIDIA CORPORATION. All rights reserved. + * + * Conversion to the CEC framework and to the mainline kernel: + * + * Copyright 2016-2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TEGRA_CEC_H +#define TEGRA_CEC_H + +/* CEC registers */ +#define TEGRA_CEC_SW_CONTROL 0x000 +#define TEGRA_CEC_HW_CONTROL 0x004 +#define TEGRA_CEC_INPUT_FILTER 0x008 +#define TEGRA_CEC_TX_REGISTER 0x010 +#define TEGRA_CEC_RX_REGISTER 0x014 +#define TEGRA_CEC_RX_TIMING_0 0x018 +#define TEGRA_CEC_RX_TIMING_1 0x01c +#define TEGRA_CEC_RX_TIMING_2 0x020 +#define TEGRA_CEC_TX_TIMING_0 0x024 +#define TEGRA_CEC_TX_TIMING_1 0x028 +#define TEGRA_CEC_TX_TIMING_2 0x02c +#define TEGRA_CEC_INT_STAT 0x030 +#define TEGRA_CEC_INT_MASK 0x034 +#define TEGRA_CEC_HW_DEBUG_RX 0x038 +#define TEGRA_CEC_HW_DEBUG_TX 0x03c + +#define TEGRA_CEC_HWCTRL_RX_LADDR_MASK 0x7fff +#define TEGRA_CEC_HWCTRL_RX_LADDR(x) \ + ((x) & TEGRA_CEC_HWCTRL_RX_LADDR_MASK) +#define TEGRA_CEC_HWCTRL_RX_SNOOP (1 << 15) +#define TEGRA_CEC_HWCTRL_RX_NAK_MODE (1 << 16) +#define TEGRA_CEC_HWCTRL_TX_NAK_MODE (1 << 24) +#define TEGRA_CEC_HWCTRL_FAST_SIM_MODE (1 << 30) +#define TEGRA_CEC_HWCTRL_TX_RX_MODE (1 << 31) + +#define TEGRA_CEC_INPUT_FILTER_MODE (1 << 31) +#define TEGRA_CEC_INPUT_FILTER_FIFO_LENGTH_SHIFT 0 + +#define TEGRA_CEC_TX_REG_DATA_SHIFT 0 +#define TEGRA_CEC_TX_REG_EOM (1 << 8) +#define TEGRA_CEC_TX_REG_BCAST (1 << 12) +#define TEGRA_CEC_TX_REG_START_BIT (1 << 16) +#define TEGRA_CEC_TX_REG_RETRY (1 << 17) + +#define TEGRA_CEC_RX_REGISTER_SHIFT 0 +#define TEGRA_CEC_RX_REGISTER_EOM (1 << 8) +#define TEGRA_CEC_RX_REGISTER_ACK (1 << 9) + +#define TEGRA_CEC_RX_TIM0_START_BIT_MAX_LO_TIME_SHIFT 0 +#define TEGRA_CEC_RX_TIM0_START_BIT_MIN_LO_TIME_SHIFT 8 +#define TEGRA_CEC_RX_TIM0_START_BIT_MAX_DURATION_SHIFT 16 +#define TEGRA_CEC_RX_TIM0_START_BIT_MIN_DURATION_SHIFT 24 + +#define TEGRA_CEC_RX_TIM1_DATA_BIT_MAX_LO_TIME_SHIFT 0 +#define TEGRA_CEC_RX_TIM1_DATA_BIT_SAMPLE_TIME_SHIFT 8 +#define TEGRA_CEC_RX_TIM1_DATA_BIT_MAX_DURATION_SHIFT 16 +#define TEGRA_CEC_RX_TIM1_DATA_BIT_MIN_DURATION_SHIFT 24 + +#define TEGRA_CEC_RX_TIM2_END_OF_BLOCK_TIME_SHIFT 0 + +#define TEGRA_CEC_TX_TIM0_START_BIT_LO_TIME_SHIFT 0 +#define TEGRA_CEC_TX_TIM0_START_BIT_DURATION_SHIFT 8 +#define TEGRA_CEC_TX_TIM0_BUS_XITION_TIME_SHIFT 16 +#define TEGRA_CEC_TX_TIM0_BUS_ERROR_LO_TIME_SHIFT 24 + +#define TEGRA_CEC_TX_TIM1_LO_DATA_BIT_LO_TIME_SHIFT 0 +#define TEGRA_CEC_TX_TIM1_HI_DATA_BIT_LO_TIME_SHIFT 8 +#define TEGRA_CEC_TX_TIM1_DATA_BIT_DURATION_SHIFT 16 +#define TEGRA_CEC_TX_TIM1_ACK_NAK_BIT_SAMPLE_TIME_SHIFT 24 + +#define TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_ADDITIONAL_FRAME_SHIFT 0 +#define TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_NEW_FRAME_SHIFT 4 +#define TEGRA_CEC_TX_TIM2_BUS_IDLE_TIME_RETRY_FRAME_SHIFT 8 + +#define TEGRA_CEC_INT_STAT_TX_REGISTER_EMPTY (1 << 0) +#define TEGRA_CEC_INT_STAT_TX_REGISTER_UNDERRUN (1 << 1) +#define TEGRA_CEC_INT_STAT_TX_FRAME_OR_BLOCK_NAKD (1 << 2) +#define TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED (1 << 3) +#define TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED (1 << 4) +#define TEGRA_CEC_INT_STAT_TX_FRAME_TRANSMITTED (1 << 5) +#define TEGRA_CEC_INT_STAT_RX_REGISTER_FULL (1 << 8) +#define TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN (1 << 9) +#define TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED (1 << 10) +#define TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED (1 << 11) +#define TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED (1 << 12) +#define TEGRA_CEC_INT_STAT_FILTERED_RX_DATA_PIN_TRANSITION_H2L (1 << 13) +#define TEGRA_CEC_INT_STAT_FILTERED_RX_DATA_PIN_TRANSITION_L2H (1 << 14) + +#define TEGRA_CEC_INT_MASK_TX_REGISTER_EMPTY (1 << 0) +#define TEGRA_CEC_INT_MASK_TX_REGISTER_UNDERRUN (1 << 1) +#define TEGRA_CEC_INT_MASK_TX_FRAME_OR_BLOCK_NAKD (1 << 2) +#define TEGRA_CEC_INT_MASK_TX_ARBITRATION_FAILED (1 << 3) +#define TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED (1 << 4) +#define TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED (1 << 5) +#define TEGRA_CEC_INT_MASK_RX_REGISTER_FULL (1 << 8) +#define TEGRA_CEC_INT_MASK_RX_REGISTER_OVERRUN (1 << 9) +#define TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED (1 << 10) +#define TEGRA_CEC_INT_MASK_RX_BUS_ANOMALY_DETECTED (1 << 11) +#define TEGRA_CEC_INT_MASK_RX_BUS_ERROR_DETECTED (1 << 12) +#define TEGRA_CEC_INT_MASK_FILTERED_RX_DATA_PIN_TRANSITION_H2L (1 << 13) +#define TEGRA_CEC_INT_MASK_FILTERED_RX_DATA_PIN_TRANSITION_L2H (1 << 14) + +#define TEGRA_CEC_HW_DEBUG_TX_DURATION_COUNT_SHIFT 0 +#define TEGRA_CEC_HW_DEBUG_TX_TXBIT_COUNT_SHIFT 17 +#define TEGRA_CEC_HW_DEBUG_TX_STATE_SHIFT 21 +#define TEGRA_CEC_HW_DEBUG_TX_FORCELOOUT (1 << 25) +#define TEGRA_CEC_HW_DEBUG_TX_TXDATABIT_SAMPLE_TIMER (1 << 26) + +#endif /* TEGRA_CEC_H */ -- cgit v1.2.3 From d94a26f05b017d93513d176959c49996768f446f Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Mon, 16 Oct 2017 05:14:25 +0200 Subject: media: ov7670: Add entity pads initialization Add the media entity pads initialization. Signed-off-by: Wenyou Yang Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov7670.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index e88549f0e704..553945d4ca28 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -213,6 +213,9 @@ struct ov7670_devtype { struct ov7670_format_struct; /* coming later */ struct ov7670_info { struct v4l2_subdev sd; +#if defined(CONFIG_MEDIA_CONTROLLER) + struct media_pad pad; +#endif struct v4l2_ctrl_handler hdl; struct { /* gain cluster */ @@ -1688,14 +1691,27 @@ static int ov7670_probe(struct i2c_client *client, v4l2_ctrl_auto_cluster(2, &info->auto_exposure, V4L2_EXPOSURE_MANUAL, false); v4l2_ctrl_cluster(2, &info->saturation); + +#if defined(CONFIG_MEDIA_CONTROLLER) + info->pad.flags = MEDIA_PAD_FL_SOURCE; + info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad); + if (ret < 0) + goto hdl_free; +#endif + v4l2_ctrl_handler_setup(&info->hdl); ret = v4l2_async_register_subdev(&info->sd); if (ret < 0) - goto hdl_free; + goto entity_cleanup; return 0; +entity_cleanup: +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&info->sd.entity); +#endif hdl_free: v4l2_ctrl_handler_free(&info->hdl); clk_disable: @@ -1712,6 +1728,9 @@ static int ov7670_remove(struct i2c_client *client) v4l2_device_unregister_subdev(sd); v4l2_ctrl_handler_free(&info->hdl); clk_disable_unprepare(info->clk); +#if defined(CONFIG_MEDIA_CONTROLLER) + media_entity_cleanup(&info->sd.entity); +#endif return 0; } -- cgit v1.2.3 From c0662dd4e7a407a5ac79cc6ca4d1116bf03d3731 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Mon, 16 Oct 2017 05:14:26 +0200 Subject: media: ov7670: Add the get_fmt callback Add the get_fmt callback, also enable V4L2_SUBDEV_FL_HAS_DEVNODE flag to make this subdev has device node. Signed-off-by: Wenyou Yang Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov7670.c | 77 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 553945d4ca28..73ceec63a8ca 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -232,6 +232,7 @@ struct ov7670_info { struct v4l2_ctrl *saturation; struct v4l2_ctrl *hue; }; + struct v4l2_mbus_framefmt format; struct ov7670_format_struct *fmt; /* Current format */ struct clk *clk; struct gpio_desc *resetb_gpio; @@ -975,6 +976,9 @@ static int ov7670_try_fmt_internal(struct v4l2_subdev *sd, fmt->width = wsize->width; fmt->height = wsize->height; fmt->colorspace = ov7670_formats[index].colorspace; + + info->format = *fmt; + return 0; } @@ -988,6 +992,9 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, struct ov7670_format_struct *ovfmt; struct ov7670_win_size *wsize; struct ov7670_info *info = to_state(sd); +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + struct v4l2_mbus_framefmt *mbus_fmt; +#endif unsigned char com7; int ret; @@ -998,8 +1005,13 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, ret = ov7670_try_fmt_internal(sd, &format->format, NULL, NULL); if (ret) return ret; - cfg->try_fmt = format->format; +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); + *mbus_fmt = format->format; return 0; +#else + return -ENOTTY; +#endif } ret = ov7670_try_fmt_internal(sd, &format->format, &ovfmt, &wsize); @@ -1041,6 +1053,30 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, return 0; } +static int ov7670_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct ov7670_info *info = to_state(sd); +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + struct v4l2_mbus_framefmt *mbus_fmt; +#endif + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, 0); + format->format = *mbus_fmt; + return 0; +#else + return -ENOTTY; +#endif + } else { + format->format = info->format; + } + + return 0; +} + /* * Implement G/S_PARM. There is a "high quality" mode we could try * to do someday; for now, we just do the frame rate tweak. @@ -1508,6 +1544,30 @@ static int ov7670_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_regis } #endif +static void ov7670_get_default_format(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *format) +{ + struct ov7670_info *info = to_state(sd); + + format->width = info->devtype->win_sizes[0].width; + format->height = info->devtype->win_sizes[0].height; + format->colorspace = info->fmt->colorspace; + format->code = info->fmt->mbus_code; + format->field = V4L2_FIELD_NONE; +} + +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API +static int ov7670_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct v4l2_mbus_framefmt *format = + v4l2_subdev_get_try_format(sd, fh->pad, 0); + + ov7670_get_default_format(sd, format); + + return 0; +} +#endif + /* ----------------------------------------------------------------------- */ static const struct v4l2_subdev_core_ops ov7670_core_ops = { @@ -1528,6 +1588,7 @@ static const struct v4l2_subdev_pad_ops ov7670_pad_ops = { .enum_frame_interval = ov7670_enum_frame_interval, .enum_frame_size = ov7670_enum_frame_size, .enum_mbus_code = ov7670_enum_mbus_code, + .get_fmt = ov7670_get_fmt, .set_fmt = ov7670_set_fmt, }; @@ -1537,6 +1598,12 @@ static const struct v4l2_subdev_ops ov7670_ops = { .pad = &ov7670_pad_ops, }; +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API +static const struct v4l2_subdev_internal_ops ov7670_subdev_internal_ops = { + .open = ov7670_open, +}; +#endif + /* ----------------------------------------------------------------------- */ static const struct ov7670_devtype ov7670_devdata[] = { @@ -1589,6 +1656,11 @@ static int ov7670_probe(struct i2c_client *client, sd = &info->sd; v4l2_i2c_subdev_init(sd, client, &ov7670_ops); +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API + sd->internal_ops = &ov7670_subdev_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; +#endif + info->clock_speed = 30; /* default: a guess */ if (client->dev.platform_data) { struct ov7670_config *config = client->dev.platform_data; @@ -1645,6 +1717,9 @@ static int ov7670_probe(struct i2c_client *client, info->devtype = &ov7670_devdata[id->driver_data]; info->fmt = &ov7670_formats[0]; + + ov7670_get_default_format(sd, &info->format); + info->clkrc = 0; /* Set default frame rate to 30 fps */ -- cgit v1.2.3 From 71862f63f351078560a7ce35c6c2e2ca16750374 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Mon, 16 Oct 2017 05:14:27 +0200 Subject: media: ov7670: Add the ov7670_s_power function Add the ov7670_s_power function which is responsible for manipulating the power dowm mode through the PWDN pin and the reset operation through the RESET pin, and keep it powered at all times. [sakari.ailus@linux.intel.com: set pwdn_gpio direction only once] Signed-off-by: Wenyou Yang Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov7670.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 73ceec63a8ca..950a0acf85fb 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -1544,6 +1544,22 @@ static int ov7670_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_regis } #endif +static int ov7670_s_power(struct v4l2_subdev *sd, int on) +{ + struct ov7670_info *info = to_state(sd); + + if (info->pwdn_gpio) + gpiod_set_value(info->pwdn_gpio, !on); + if (on && info->resetb_gpio) { + gpiod_set_value(info->resetb_gpio, 1); + usleep_range(500, 1000); + gpiod_set_value(info->resetb_gpio, 0); + usleep_range(3000, 5000); + } + + return 0; +} + static void ov7670_get_default_format(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *format) { @@ -1694,23 +1710,25 @@ static int ov7670_probe(struct i2c_client *client, if (ret) return ret; - ret = ov7670_init_gpio(client, info); - if (ret) - goto clk_disable; - info->clock_speed = clk_get_rate(info->clk) / 1000000; if (info->clock_speed < 10 || info->clock_speed > 48) { ret = -EINVAL; goto clk_disable; } + ret = ov7670_init_gpio(client, info); + if (ret) + goto clk_disable; + + ov7670_s_power(sd, 1); + /* Make sure it's an ov7670 */ ret = ov7670_detect(sd); if (ret) { v4l_dbg(1, debug, client, "chip found @ 0x%x (%s) is not an ov7670 chip.\n", client->addr << 1, client->adapter->name); - goto clk_disable; + goto power_off; } v4l_info(client, "chip found @ 0x%02x (%s)\n", client->addr << 1, client->adapter->name); @@ -1789,6 +1807,8 @@ entity_cleanup: #endif hdl_free: v4l2_ctrl_handler_free(&info->hdl); +power_off: + ov7670_s_power(sd, 0); clk_disable: clk_disable_unprepare(info->clk); return ret; @@ -1806,6 +1826,7 @@ static int ov7670_remove(struct i2c_client *client) #if defined(CONFIG_MEDIA_CONTROLLER) media_entity_cleanup(&info->sd.entity); #endif + ov7670_s_power(sd, 0); return 0; } -- cgit v1.2.3 From 7bc9f038d02c2fc14e53e4aaca651deaf6d0de3f Mon Sep 17 00:00:00 2001 From: Jacob Chen Date: Sun, 1 Oct 2017 12:22:37 +0200 Subject: media: i2c: OV5647: ensure clock lane in LP-11 state before streaming on When I was supporting Rpi Camera Module on the ASUS Tinker board, I found this driver have some issues with rockchip's mipi-csi driver. It didn't place clock lane in LP-11 state before performing D-PHY initialisation. >From our experience, on some OV sensors, LP-11 state is not achieved while BIT(5)-0x4800 is cleared. So let's set BIT(5) and BIT(0) both while not streaming, in order to coax the clock lane into LP-11 state. 0x4800 : MIPI CTRL 00 BIT(5) : clock lane gate enable 0: continuous 1: none-continuous BIT(0) : manually set clock lane 0: Not used 1: used Signed-off-by: Jacob Chen Reviewed-by: Luis Oliveira Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5647.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c index 95ce90fdb876..247302d01f53 100644 --- a/drivers/media/i2c/ov5647.c +++ b/drivers/media/i2c/ov5647.c @@ -253,6 +253,10 @@ static int ov5647_stream_on(struct v4l2_subdev *sd) { int ret; + ret = ov5647_write(sd, 0x4800, 0x04); + if (ret < 0) + return ret; + ret = ov5647_write(sd, 0x4202, 0x00); if (ret < 0) return ret; @@ -264,6 +268,10 @@ static int ov5647_stream_off(struct v4l2_subdev *sd) { int ret; + ret = ov5647_write(sd, 0x4800, 0x25); + if (ret < 0) + return ret; + ret = ov5647_write(sd, 0x4202, 0x0f); if (ret < 0) return ret; @@ -320,7 +328,10 @@ static int __sensor_init(struct v4l2_subdev *sd) return ret; } - return ov5647_write(sd, 0x4800, 0x04); + /* + * stream off to make the clock lane into LP-11 state. + */ + return ov5647_stream_off(sd); } static int ov5647_sensor_power(struct v4l2_subdev *sd, int on) -- cgit v1.2.3 From cef6673440a29a9a2fd39a57d5ba28e6c68c7a76 Mon Sep 17 00:00:00 2001 From: Jacob Chen Date: Sun, 1 Oct 2017 12:22:38 +0200 Subject: media: i2c: OV5647: change to use macro for the registers ref docuemnt: ov5647-datasheet-v1.00-2009 Signed-off-by: Jacob Chen Reviewed-by: Luis Oliveira Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5647.c | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c index 247302d01f53..34179d232a35 100644 --- a/drivers/media/i2c/ov5647.c +++ b/drivers/media/i2c/ov5647.c @@ -35,9 +35,18 @@ #define SENSOR_NAME "ov5647" -#define OV5647_SW_RESET 0x0103 -#define OV5647_REG_CHIPID_H 0x300A -#define OV5647_REG_CHIPID_L 0x300B +#define MIPI_CTRL00_CLOCK_LANE_GATE BIT(5) +#define MIPI_CTRL00_BUS_IDLE BIT(2) +#define MIPI_CTRL00_CLOCK_LANE_DISABLE BIT(0) + +#define OV5647_SW_STANDBY 0x0100 +#define OV5647_SW_RESET 0x0103 +#define OV5647_REG_CHIPID_H 0x300A +#define OV5647_REG_CHIPID_L 0x300B +#define OV5640_REG_PAD_OUT 0x300D +#define OV5647_REG_FRAME_OFF_NUMBER 0x4202 +#define OV5647_REG_MIPI_CTRL00 0x4800 +#define OV5647_REG_MIPI_CTRL14 0x4814 #define REG_TERM 0xfffe #define VAL_TERM 0xfe @@ -241,42 +250,43 @@ static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel) u8 channel_id; int ret; - ret = ov5647_read(sd, 0x4814, &channel_id); + ret = ov5647_read(sd, OV5647_REG_MIPI_CTRL14, &channel_id); if (ret < 0) return ret; channel_id &= ~(3 << 6); - return ov5647_write(sd, 0x4814, channel_id | (channel << 6)); + return ov5647_write(sd, OV5647_REG_MIPI_CTRL14, channel_id | (channel << 6)); } static int ov5647_stream_on(struct v4l2_subdev *sd) { int ret; - ret = ov5647_write(sd, 0x4800, 0x04); + ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_BUS_IDLE); if (ret < 0) return ret; - ret = ov5647_write(sd, 0x4202, 0x00); + ret = ov5647_write(sd, OV5647_REG_FRAME_OFF_NUMBER, 0x00); if (ret < 0) return ret; - return ov5647_write(sd, 0x300D, 0x00); + return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x00); } static int ov5647_stream_off(struct v4l2_subdev *sd) { int ret; - ret = ov5647_write(sd, 0x4800, 0x25); + ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_CLOCK_LANE_GATE + | MIPI_CTRL00_BUS_IDLE | MIPI_CTRL00_CLOCK_LANE_DISABLE); if (ret < 0) return ret; - ret = ov5647_write(sd, 0x4202, 0x0f); + ret = ov5647_write(sd, OV5647_REG_FRAME_OFF_NUMBER, 0x0f); if (ret < 0) return ret; - return ov5647_write(sd, 0x300D, 0x01); + return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01); } static int set_sw_standby(struct v4l2_subdev *sd, bool standby) @@ -284,7 +294,7 @@ static int set_sw_standby(struct v4l2_subdev *sd, bool standby) int ret; u8 rdval; - ret = ov5647_read(sd, 0x0100, &rdval); + ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval); if (ret < 0) return ret; @@ -293,7 +303,7 @@ static int set_sw_standby(struct v4l2_subdev *sd, bool standby) else rdval |= 0x01; - return ov5647_write(sd, 0x0100, rdval); + return ov5647_write(sd, OV5647_SW_STANDBY, rdval); } static int __sensor_init(struct v4l2_subdev *sd) @@ -302,7 +312,7 @@ static int __sensor_init(struct v4l2_subdev *sd) u8 resetval, rdval; struct i2c_client *client = v4l2_get_subdevdata(sd); - ret = ov5647_read(sd, 0x0100, &rdval); + ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval); if (ret < 0) return ret; @@ -317,13 +327,13 @@ static int __sensor_init(struct v4l2_subdev *sd) if (ret < 0) return ret; - ret = ov5647_read(sd, 0x0100, &resetval); + ret = ov5647_read(sd, OV5647_SW_STANDBY, &resetval); if (ret < 0) return ret; if (!(resetval & 0x01)) { dev_err(&client->dev, "Device was in SW standby"); - ret = ov5647_write(sd, 0x0100, 0x01); + ret = ov5647_write(sd, OV5647_SW_STANDBY, 0x01); if (ret < 0) return ret; } -- cgit v1.2.3 From 9d39e46bdd9df945669a9039660a3194bdc8d0ac Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 17 Oct 2017 13:05:11 +0200 Subject: media: tc358743: validate lane count The TC358743 does not support more than 4 data lanes. Check that the lane count is valid. Signed-off-by: Philipp Zabel Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358743.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 0b65096613d9..d3cf016ad0a0 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -1941,6 +1941,11 @@ static int tc358743_probe_of(struct tc358743_state *state) goto free_endpoint; } + if (endpoint->bus.mipi_csi2.num_data_lanes > 4) { + dev_err(dev, "invalid number of lanes\n"); + goto free_endpoint; + } + state->bus = endpoint->bus.mipi_csi2; ret = clk_prepare_enable(refclk); -- cgit v1.2.3 From 1f709713cbd70efe85e76d9e9453606c6cc4bf82 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 16 Oct 2017 14:34:48 +0200 Subject: media: staging: media: atomisp: Fix oops by unbalanced clk enable/disable call The common-clk core expects clk consumers to always call enable/disable in a balanced manner. The atomisp driver does not call gmin_flisclk_ctrl() in a balanced manner, so add a clock_on bool and skip redundant calls. This fixes kernel oops like this one: [ 19.811613] gc0310_s_config S [ 19.811655] ------------[ cut here ]------------ [ 19.811664] WARNING: CPU: 1 PID: 720 at drivers/clk/clk.c:594 clk_core_disabl [ 19.811666] Modules linked in: tpm_crb(+) snd_soc_sst_atom_hifi2_platform tpm [ 19.811744] CPU: 1 PID: 720 Comm: systemd-udevd Tainted: G C OE 4.1 [ 19.811746] Hardware name: Insyde T701/T701, BIOS BYT70A.YNCHENG.WIN.007 08/2 [ 19.811749] task: ffff988df7ab2500 task.stack: ffffac1400474000 [ 19.811752] RIP: 0010:clk_core_disable+0xc0/0x130 ... [ 19.811775] Call Trace: [ 19.811783] clk_core_disable_lock+0x1f/0x30 [ 19.811788] clk_disable+0x1f/0x30 [ 19.811794] gmin_flisclk_ctrl+0x87/0xf0 [ 19.811801] 0xffffffffc0528512 [ 19.811805] 0xffffffffc05295e2 [ 19.811811] ? acpi_device_wakeup_disable+0x50/0x60 [ 19.811815] ? acpi_dev_pm_attach+0x8e/0xd0 [ 19.811818] ? 0xffffffffc05294d0 [ 19.811823] i2c_device_probe+0x1cd/0x280 [ 19.811828] driver_probe_device+0x2ff/0x450 Fixes: "staging: atomisp: use clock framework for camera clocks" Signed-off-by: Hans de Goede Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/platform/intel-mid/atomisp_gmin_platform.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c index 17b4cfae5abf..8a20a28d37f1 100644 --- a/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c @@ -29,6 +29,7 @@ struct gmin_subdev { struct v4l2_subdev *subdev; int clock_num; int clock_src; + bool clock_on; struct clk *pmc_clk; struct gpio_desc *gpio0; struct gpio_desc *gpio1; @@ -572,6 +573,9 @@ static int gmin_flisclk_ctrl(struct v4l2_subdev *subdev, int on) struct gmin_subdev *gs = find_gmin_subdev(subdev); struct i2c_client *client = v4l2_get_subdevdata(subdev); + if (gs->clock_on == !!on) + return 0; + if (on) { ret = clk_set_rate(gs->pmc_clk, gs->clock_src); @@ -580,8 +584,11 @@ static int gmin_flisclk_ctrl(struct v4l2_subdev *subdev, int on) gs->clock_src); ret = clk_prepare_enable(gs->pmc_clk); + if (ret == 0) + gs->clock_on = true; } else { clk_disable_unprepare(gs->pmc_clk); + gs->clock_on = false; } return ret; -- cgit v1.2.3 From bbae615636155fa43a9b0fe0ea31c678984be864 Mon Sep 17 00:00:00 2001 From: Aishwarya Pant Date: Tue, 17 Oct 2017 15:14:09 +0200 Subject: media: staging: atomisp2: cleanup null check on memory allocation For memory allocation functions that fail with a NULL return value, it is preferred to use the (!x) test in place of (x == NULL). Changes in atomisp2/css2400/sh_css.c were done by hand. Done with the help of the following cocci script: @@ type T; T* p; statement s,s1; @@ p = \(devm_kzalloc\|devm_ioremap\|usb_alloc_urb\|alloc_netdev\|dev_alloc_skb\| kmalloc\|kmalloc_array\|kzalloc\|kcalloc\|kmem_cache_alloc\|kmem_cache_zalloc\| kmem_cache_alloc_node\|kmalloc_node\|kzalloc_node\|devm_kzalloc\)(...) ...when != p if ( - p == NULL + !p ) s else s1 -- Changes in v3: Rebase changes over atomisp-next branch of the media tree Changes in atomisp2/css2400/sh_css.c were done by hand, the above script was not able to match the pattern if (a->b != null). Signed-off-by: Aishwarya Pant Acked-by: Julia Lawall Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/pci/atomisp2/css2400/sh_css.c | 36 +++++++++++----------- .../atomisp/pci/atomisp2/css2400/sh_css_firmware.c | 7 ++--- .../pci/atomisp2/css2400/sh_css_param_shading.c | 2 +- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c index bee30438e6fd..e61009faff27 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c @@ -5605,13 +5605,13 @@ static enum ia_css_err load_video_binaries(struct ia_css_pipe *pipe) mycs->num_yuv_scaler = cas_scaler_descr.num_stage; mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage * sizeof(struct ia_css_binary), GFP_KERNEL); - if (mycs->yuv_scaler_binary == NULL) { + if (!mycs->yuv_scaler_binary) { err = IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; return err; } mycs->is_output_stage = kzalloc(cas_scaler_descr.num_stage * sizeof(bool), GFP_KERNEL); - if (mycs->is_output_stage == NULL) { + if (!mycs->is_output_stage) { err = IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; return err; } @@ -6256,14 +6256,14 @@ static enum ia_css_err load_primary_binaries( mycs->num_yuv_scaler = cas_scaler_descr.num_stage; mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage * sizeof(struct ia_css_binary), GFP_KERNEL); - if (mycs->yuv_scaler_binary == NULL) { + if (!mycs->yuv_scaler_binary) { err = IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } mycs->is_output_stage = kzalloc(cas_scaler_descr.num_stage * sizeof(bool), GFP_KERNEL); - if (mycs->is_output_stage == NULL) { + if (!mycs->is_output_stage) { err = IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; IA_CSS_LEAVE_ERR_PRIVATE(err); return err; @@ -6980,27 +6980,27 @@ static enum ia_css_err ia_css_pipe_create_cas_scaler_desc_single_output( } descr->in_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info), GFP_KERNEL); - if (descr->in_info == NULL) { + if (!descr->in_info) { err = IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; goto ERR; } descr->internal_out_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info), GFP_KERNEL); - if (descr->internal_out_info == NULL) { + if (!descr->internal_out_info) { err = IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; goto ERR; } descr->out_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info), GFP_KERNEL); - if (descr->out_info == NULL) { + if (!descr->out_info) { err = IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; goto ERR; } descr->vf_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info), GFP_KERNEL); - if (descr->vf_info == NULL) { + if (!descr->vf_info) { err = IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; goto ERR; } descr->is_output_stage = kmalloc(descr->num_stage * sizeof(bool), GFP_KERNEL); - if (descr->is_output_stage == NULL) { + if (!descr->is_output_stage) { err = IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; goto ERR; } @@ -7116,22 +7116,22 @@ static enum ia_css_err ia_css_pipe_create_cas_scaler_desc(struct ia_css_pipe *pi descr->num_stage = num_stages; descr->in_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info), GFP_KERNEL); - if (descr->in_info == NULL) { + if (!descr->in_info) { err = IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; goto ERR; } descr->internal_out_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info), GFP_KERNEL); - if (descr->internal_out_info == NULL) { + if (!descr->internal_out_info) { err = IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; goto ERR; } descr->out_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info), GFP_KERNEL); - if (descr->out_info == NULL) { + if (!descr->out_info) { err = IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; goto ERR; } descr->vf_info = kmalloc(descr->num_stage * sizeof(struct ia_css_frame_info), GFP_KERNEL); - if (descr->vf_info == NULL) { + if (!descr->vf_info) { err = IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; goto ERR; } @@ -7274,13 +7274,13 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) mycs->num_yuv_scaler = cas_scaler_descr.num_stage; mycs->yuv_scaler_binary = kzalloc(cas_scaler_descr.num_stage * sizeof(struct ia_css_binary), GFP_KERNEL); - if (mycs->yuv_scaler_binary == NULL) { + if (!mycs->yuv_scaler_binary) { err = IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; goto ERR; } mycs->is_output_stage = kzalloc(cas_scaler_descr.num_stage * sizeof(bool), GFP_KERNEL); - if (mycs->is_output_stage == NULL) { + if (!mycs->is_output_stage) { err = IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; goto ERR; } @@ -7381,7 +7381,7 @@ load_yuvpp_binaries(struct ia_css_pipe *pipe) } mycs->vf_pp_binary = kzalloc(mycs->num_vf_pp * sizeof(struct ia_css_binary), GFP_KERNEL); - if (mycs->vf_pp_binary == NULL) { + if (!mycs->vf_pp_binary) { err = IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; goto ERR; } @@ -9443,7 +9443,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, /* allocate the stream instance */ curr_stream = kmalloc(sizeof(struct ia_css_stream), GFP_KERNEL); - if (curr_stream == NULL) { + if (!curr_stream) { err = IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; IA_CSS_LEAVE_ERR(err); return err; @@ -9455,7 +9455,7 @@ ia_css_stream_create(const struct ia_css_stream_config *stream_config, /* allocate pipes */ curr_stream->num_pipes = num_pipes; curr_stream->pipes = kzalloc(num_pipes * sizeof(struct ia_css_pipe *), GFP_KERNEL); - if (curr_stream->pipes == NULL) { + if (!curr_stream->pipes) { curr_stream->num_pipes = 0; kfree(curr_stream); curr_stream = NULL; diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c index 5e45d5fe0b2a..383d236c010c 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_firmware.c @@ -147,7 +147,7 @@ sh_css_load_blob_info(const char *fw, const struct ia_css_fw_info *bi, struct ia char *parambuf = kmalloc(paramstruct_size + configstruct_size + statestruct_size, GFP_KERNEL); - if (parambuf == NULL) + if (!parambuf) return IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; bd->mem_offsets.array[IA_CSS_PARAM_CLASS_PARAM].ptr = NULL; @@ -229,7 +229,7 @@ sh_css_load_firmware(const char *fw_data, sh_css_blob_info = kmalloc( (sh_css_num_binaries - NUM_OF_SPS) * sizeof(*sh_css_blob_info), GFP_KERNEL); - if (sh_css_blob_info == NULL) + if (!sh_css_blob_info) return IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; } else { sh_css_blob_info = NULL; @@ -237,8 +237,7 @@ sh_css_load_firmware(const char *fw_data, fw_minibuffer = kcalloc(sh_css_num_binaries, sizeof(struct fw_param), GFP_KERNEL); - - if (fw_minibuffer == NULL) + if (!fw_minibuffer) return IA_CSS_ERR_CANNOT_ALLOCATE_MEMORY; for (i = 0; i < sh_css_num_binaries; i++) { diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_param_shading.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_param_shading.c index eaf60e7b2dac..48e2e63c2336 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_param_shading.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_param_shading.c @@ -365,7 +365,7 @@ ia_css_shading_table_alloc( IA_CSS_ENTER(""); me = kmalloc(sizeof(*me), GFP_KERNEL); - if (me == NULL) { + if (!me) { IA_CSS_ERROR("out of memory"); return me; } -- cgit v1.2.3 From 58fd55e838276a0c13d1dc7c387f90f25063cbf3 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Mon, 9 Oct 2017 20:14:48 +0200 Subject: media: imon: Fix null-ptr-deref in imon_probe It seems that the return value of usb_ifnum_to_if() can be NULL and needs to be checked. Signed-off-by: Arvind Yadav Tested-by: Andrey Konovalov Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 9724fe8110e3..9fef8cc17114 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -2515,6 +2515,11 @@ static int imon_probe(struct usb_interface *interface, mutex_lock(&driver_lock); first_if = usb_ifnum_to_if(usbdev, 0); + if (!first_if) { + ret = -ENODEV; + goto fail; + } + first_if_ctx = usb_get_intfdata(first_if); if (ifnum == 0) { -- cgit v1.2.3 From 7dc31b82dd5da5eb596f9091b67326742135732c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 17 Oct 2017 01:10:36 +0200 Subject: media: serial_ir: Convert timers to use timer_setup() In preparation for unconditionally passing the struct timer_list pointer to all timer callbacks, switch to using the new timer_setup() and from_timer() to pass the timer pointer explicitly. Cc: Mauro Carvalho Chehab Signed-off-by: Kees Cook Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/serial_ir.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/media/rc/serial_ir.c b/drivers/media/rc/serial_ir.c index 8b66926bc16a..8bf5637b3a69 100644 --- a/drivers/media/rc/serial_ir.c +++ b/drivers/media/rc/serial_ir.c @@ -470,7 +470,7 @@ static int hardware_init_port(void) return 0; } -static void serial_ir_timeout(unsigned long arg) +static void serial_ir_timeout(struct timer_list *unused) { DEFINE_IR_RAW_EVENT(ev); @@ -540,8 +540,7 @@ static int serial_ir_probe(struct platform_device *dev) serial_ir.rcdev = rcdev; - setup_timer(&serial_ir.timeout_timer, serial_ir_timeout, - (unsigned long)&serial_ir); + timer_setup(&serial_ir.timeout_timer, serial_ir_timeout, 0); result = devm_request_irq(&dev->dev, irq, serial_ir_irq_handler, share_irq ? IRQF_SHARED : 0, -- cgit v1.2.3 From ce5aa6d205576904552b98e4e6ca88d8d285849f Mon Sep 17 00:00:00 2001 From: Younian Wang Date: Thu, 19 Oct 2017 21:43:29 +0200 Subject: media: rc/keymaps: add support for RC of hisilicon TV demo boards This is a NEC protocol type remote controller distributed with hisilicon TV demo boards. Signed-off-by: Younian Wang Signed-off-by: Jiancheng Xue Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/Makefile | 1 + drivers/media/rc/keymaps/rc-hisi-tv-demo.c | 81 ++++++++++++++++++++++++++++++ include/media/rc-map.h | 1 + 3 files changed, 83 insertions(+) create mode 100644 drivers/media/rc/keymaps/rc-hisi-tv-demo.c diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 3c1e31321e21..ba471f09102a 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-geekbox.o \ rc-genius-tvgo-a11mce.o \ rc-gotview7135.o \ + rc-hisi-tv-demo.o \ rc-imon-mce.o \ rc-imon-pad.o \ rc-iodata-bctv7e.o \ diff --git a/drivers/media/rc/keymaps/rc-hisi-tv-demo.c b/drivers/media/rc/keymaps/rc-hisi-tv-demo.c new file mode 100644 index 000000000000..4816e3a4a18d --- /dev/null +++ b/drivers/media/rc/keymaps/rc-hisi-tv-demo.c @@ -0,0 +1,81 @@ +/* + * Keytable for remote controller of HiSilicon tv demo board. + * + * Copyright (c) 2017 HiSilicon Technologies Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include + +static struct rc_map_table hisi_tv_demo_keymap[] = { + { 0x00000092, KEY_1}, + { 0x00000093, KEY_2}, + { 0x000000cc, KEY_3}, + { 0x0000009f, KEY_4}, + { 0x0000008e, KEY_5}, + { 0x0000008f, KEY_6}, + { 0x000000c8, KEY_7}, + { 0x00000094, KEY_8}, + { 0x0000008a, KEY_9}, + { 0x0000008b, KEY_0}, + { 0x000000ce, KEY_ENTER}, + { 0x000000ca, KEY_UP}, + { 0x00000099, KEY_LEFT}, + { 0x00000084, KEY_PAGEUP}, + { 0x000000c1, KEY_RIGHT}, + { 0x000000d2, KEY_DOWN}, + { 0x00000089, KEY_PAGEDOWN}, + { 0x000000d1, KEY_MUTE}, + { 0x00000098, KEY_VOLUMEDOWN}, + { 0x00000090, KEY_VOLUMEUP}, + { 0x0000009c, KEY_POWER}, + { 0x000000d6, KEY_STOP}, + { 0x00000097, KEY_MENU}, + { 0x000000cb, KEY_BACK}, + { 0x000000da, KEY_PLAYPAUSE}, + { 0x00000080, KEY_INFO}, + { 0x000000c3, KEY_REWIND}, + { 0x00000087, KEY_HOMEPAGE}, + { 0x000000d0, KEY_FASTFORWARD}, + { 0x000000c4, KEY_SOUND}, + { 0x00000082, BTN_1}, + { 0x000000c7, BTN_2}, + { 0x00000086, KEY_PROGRAM}, + { 0x000000d9, KEY_SUBTITLE}, + { 0x00000085, KEY_ZOOM}, + { 0x0000009b, KEY_RED}, + { 0x0000009a, KEY_GREEN}, + { 0x000000c0, KEY_YELLOW}, + { 0x000000c2, KEY_BLUE}, + { 0x0000009d, KEY_CHANNELDOWN}, + { 0x000000cf, KEY_CHANNELUP}, +}; + +static struct rc_map_list hisi_tv_demo_map = { + .map = { + .scan = hisi_tv_demo_keymap, + .size = ARRAY_SIZE(hisi_tv_demo_keymap), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_HISI_TV_DEMO, + } +}; + +static int __init init_rc_map_hisi_tv_demo(void) +{ + return rc_map_register(&hisi_tv_demo_map); +} + +static void __exit exit_rc_map_hisi_tv_demo(void) +{ + rc_map_unregister(&hisi_tv_demo_map); +} + +module_init(init_rc_map_hisi_tv_demo) +module_exit(exit_rc_map_hisi_tv_demo) + +MODULE_LICENSE("GPL v2"); diff --git a/include/media/rc-map.h b/include/media/rc-map.h index b4ddcb62c993..6d2172b6a0ed 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -258,6 +258,7 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_GENIUS_TVGO_A11MCE "rc-genius-tvgo-a11mce" #define RC_MAP_GOTVIEW7135 "rc-gotview7135" #define RC_MAP_HAUPPAUGE_NEW "rc-hauppauge" +#define RC_MAP_HISI_TV_DEMO "rc-hisi-tv-demo" #define RC_MAP_IMON_MCE "rc-imon-mce" #define RC_MAP_IMON_PAD "rc-imon-pad" #define RC_MAP_IODATA_BCTV7E "rc-iodata-bctv7e" -- cgit v1.2.3 From c62cf662a2cbaa1f5ad2a5e1998b4662ed15a316 Mon Sep 17 00:00:00 2001 From: Younian Wang Date: Thu, 19 Oct 2017 21:43:30 +0200 Subject: media: rc/keymaps: add support for RC of hisilicon poplar board This is a NEC protocol type remote controller distributed with 96boards poplar@tocoding board. Signed-off-by: Younian Wang Signed-off-by: Jiancheng Xue Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/Makefile | 1 + drivers/media/rc/keymaps/rc-hisi-poplar.c | 69 +++++++++++++++++++++++++++++++ include/media/rc-map.h | 1 + 3 files changed, 71 insertions(+) create mode 100644 drivers/media/rc/keymaps/rc-hisi-poplar.c diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index ba471f09102a..3f196232904f 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-geekbox.o \ rc-genius-tvgo-a11mce.o \ rc-gotview7135.o \ + rc-hisi-poplar.o \ rc-hisi-tv-demo.o \ rc-imon-mce.o \ rc-imon-pad.o \ diff --git a/drivers/media/rc/keymaps/rc-hisi-poplar.c b/drivers/media/rc/keymaps/rc-hisi-poplar.c new file mode 100644 index 000000000000..78728bc7f63a --- /dev/null +++ b/drivers/media/rc/keymaps/rc-hisi-poplar.c @@ -0,0 +1,69 @@ +/* + * Keytable for remote controller of HiSilicon poplar board. + * + * Copyright (c) 2017 HiSilicon Technologies Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include + +static struct rc_map_table hisi_poplar_keymap[] = { + { 0x0000b292, KEY_1}, + { 0x0000b293, KEY_2}, + { 0x0000b2cc, KEY_3}, + { 0x0000b28e, KEY_4}, + { 0x0000b28f, KEY_5}, + { 0x0000b2c8, KEY_6}, + { 0x0000b28a, KEY_7}, + { 0x0000b28b, KEY_8}, + { 0x0000b2c4, KEY_9}, + { 0x0000b287, KEY_0}, + { 0x0000b282, KEY_HOMEPAGE}, + { 0x0000b2ca, KEY_UP}, + { 0x0000b299, KEY_LEFT}, + { 0x0000b2c1, KEY_RIGHT}, + { 0x0000b2d2, KEY_DOWN}, + { 0x0000b2c5, KEY_DELETE}, + { 0x0000b29c, KEY_MUTE}, + { 0x0000b281, KEY_VOLUMEDOWN}, + { 0x0000b280, KEY_VOLUMEUP}, + { 0x0000b2dc, KEY_POWER}, + { 0x0000b29a, KEY_MENU}, + { 0x0000b28d, KEY_SETUP}, + { 0x0000b2c5, KEY_BACK}, + { 0x0000b295, KEY_PLAYPAUSE}, + { 0x0000b2ce, KEY_ENTER}, + { 0x0000b285, KEY_CHANNELUP}, + { 0x0000b286, KEY_CHANNELDOWN}, + { 0x0000b2da, KEY_NUMERIC_STAR}, + { 0x0000b2d0, KEY_NUMERIC_POUND}, +}; + +static struct rc_map_list hisi_poplar_map = { + .map = { + .scan = hisi_poplar_keymap, + .size = ARRAY_SIZE(hisi_poplar_keymap), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_HISI_POPLAR, + } +}; + +static int __init init_rc_map_hisi_poplar(void) +{ + return rc_map_register(&hisi_poplar_map); +} + +static void __exit exit_rc_map_hisi_poplar(void) +{ + rc_map_unregister(&hisi_poplar_map); +} + +module_init(init_rc_map_hisi_poplar) +module_exit(exit_rc_map_hisi_poplar) + +MODULE_LICENSE("GPL v2"); diff --git a/include/media/rc-map.h b/include/media/rc-map.h index 6d2172b6a0ed..cc59c72ac282 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -258,6 +258,7 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_GENIUS_TVGO_A11MCE "rc-genius-tvgo-a11mce" #define RC_MAP_GOTVIEW7135 "rc-gotview7135" #define RC_MAP_HAUPPAUGE_NEW "rc-hauppauge" +#define RC_MAP_HISI_POPLAR "rc-hisi-poplar" #define RC_MAP_HISI_TV_DEMO "rc-hisi-tv-demo" #define RC_MAP_IMON_MCE "rc-imon-mce" #define RC_MAP_IMON_PAD "rc-imon-pad" -- cgit v1.2.3 From ec62464e83beacd8b8856e8313a4cae4a91ea90b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 31 Oct 2017 05:32:02 -0400 Subject: media: atmel-isc: get rid of an unused var drivers/media/platform/atmel/atmel-isc.c: In function 'isc_async_complete': drivers/media/platform/atmel/atmel-isc.c:1900:28: warning: variable 'sd_entity' set but not used [-Wunused-but-set-variable] struct isc_subdev_entity *sd_entity; ^~~~~~~~~ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 2c40a7886542..8b37656f035d 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -1897,7 +1897,6 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) { struct isc_device *isc = container_of(notifier->v4l2_dev, struct isc_device, v4l2_dev); - struct isc_subdev_entity *sd_entity; struct video_device *vdev = &isc->video_dev; struct vb2_queue *q = &isc->vb2_vidq; int ret; @@ -1910,8 +1909,6 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) isc->current_subdev = container_of(notifier, struct isc_subdev_entity, notifier); - sd_entity = isc->current_subdev; - mutex_init(&isc->lock); init_completion(&isc->comp); -- cgit v1.2.3 From eab638a8ae6e874a226e61b57e35032ee461e0bf Mon Sep 17 00:00:00 2001 From: Srishti Sharma Date: Sat, 7 Oct 2017 09:52:02 -0400 Subject: media: Staging: media: atomisp: pci: Eliminate use of typedefs for struct The use of typedefs for struct is discouraged, and hence can be eliminated. Done using the following semantic patch by coccinelle. @r1@ type T; @@ typedef struct {...} T; @script: python p@ T << r1.T; T1; @@ if T[-2:] == "_t" or T[-2:] == "_T": coccinelle.T1 = T[:-2] else: coccinelle.T1 = T print T, T1 @r2@ type r1.T; identifier p.T1; @@ - typedef struct + T1 { ... } - T Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/pci/atomisp2/css2400/runtime/spctrl/src/spctrl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/spctrl/src/spctrl.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/spctrl/src/spctrl.c index d9178e80dab2..6d9bceb60196 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/spctrl/src/spctrl.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/spctrl/src/spctrl.c @@ -37,7 +37,7 @@ more details. #include "ia_css_spctrl.h" #include "ia_css_debug.h" -typedef struct { +struct spctrl_context_info { struct ia_css_sp_init_dmem_cfg dmem_config; uint32_t spctrl_config_dmem_addr; /** location of dmem_cfg in SP dmem */ uint32_t spctrl_state_dmem_addr; @@ -45,9 +45,9 @@ typedef struct { hrt_vaddress code_addr; /* sp firmware location in host mem-DDR*/ uint32_t code_size; char *program_name; /* used in case of PLATFORM_SIM */ -} spctrl_context_info; +}; -static spctrl_context_info spctrl_cofig_info[N_SP_ID]; +static struct spctrl_context_info spctrl_cofig_info[N_SP_ID]; static bool spctrl_loaded[N_SP_ID] = {0}; /* Load firmware */ -- cgit v1.2.3 From 309167b966b61c2aef2c268c4a0c25334d6310bd Mon Sep 17 00:00:00 2001 From: Aishwarya Pant Date: Tue, 17 Oct 2017 09:14:47 -0400 Subject: media: staging: atomisp: cleanup out of memory messages Logging of explicit out of memory messages is redundant since memory allocation failures produce a backtrace. Done with the help of the following cocci script: @@ expression ex, ret; statement s; constant char[] c; constant err; identifier f, l; @@ ex = \(kmalloc\|kmalloc_array\|kzalloc\|kcalloc\|kmem_cache_alloc\|kmem_cache_zalloc\| kmem_cache_alloc_node\|kmalloc_node\|kzalloc_node\|devm_kzalloc\)(...) ... when != ex if ( ( !ex | unlikely(!ex) ) ) - { - f(..., c, ...); ( return ex; | return; | return err; | goto l; ) - } else s Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-ap1302.c | 4 +--- drivers/staging/media/atomisp/i2c/atomisp-gc0310.c | 4 +--- drivers/staging/media/atomisp/i2c/atomisp-gc2235.c | 4 +--- drivers/staging/media/atomisp/i2c/atomisp-lm3554.c | 4 +--- drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c | 4 +--- drivers/staging/media/atomisp/i2c/atomisp-ov2680.c | 4 +--- drivers/staging/media/atomisp/i2c/atomisp-ov2722.c | 4 +--- drivers/staging/media/atomisp/i2c/imx/imx.c | 4 +--- drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c | 4 +--- drivers/staging/media/atomisp/i2c/ov8858.c | 6 +----- drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c | 4 +--- drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c | 9 ++------- .../media/atomisp/pci/atomisp2/css2400/sh_css_param_shading.c | 4 +--- drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_bo.c | 10 ++-------- .../staging/media/atomisp/pci/atomisp2/hmm/hmm_dynamic_pool.c | 6 +----- .../staging/media/atomisp/pci/atomisp2/hmm/hmm_reserved_pool.c | 5 +---- drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_vm.c | 4 +--- .../media/atomisp/platform/intel-mid/atomisp_gmin_platform.c | 4 +--- 18 files changed, 20 insertions(+), 68 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ap1302.c b/drivers/staging/media/atomisp/i2c/atomisp-ap1302.c index 2f772a020c8b..bfbf85122c3b 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ap1302.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ap1302.c @@ -1153,10 +1153,8 @@ static int ap1302_probe(struct i2c_client *client, /* allocate device & init sub device */ dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "%s: out of memory\n", __func__); + if (!dev) return -ENOMEM; - } mutex_init(&dev->input_lock); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c index 35ed51ffe944..291565451bfe 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c @@ -1385,10 +1385,8 @@ static int gc0310_probe(struct i2c_client *client, pr_info("%s S\n", __func__); dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "out of memory\n"); + if (!dev) return -ENOMEM; - } mutex_init(&dev->input_lock); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c index e43d31ea9676..f51535eee091 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -1123,10 +1123,8 @@ static int gc2235_probe(struct i2c_client *client, unsigned int i; dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "out of memory\n"); + if (!dev) return -ENOMEM; - } mutex_init(&dev->input_lock); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c index 679176f7c542..37876d245a02 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c @@ -871,10 +871,8 @@ static int lm3554_probe(struct i2c_client *client, int ret; flash = kzalloc(sizeof(*flash), GFP_KERNEL); - if (!flash) { - dev_err(&client->dev, "out of memory\n"); + if (!flash) return -ENOMEM; - } flash->pdata = client->dev.platform_data; diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index 3c837cb8859c..e204238ae06b 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -1863,10 +1863,8 @@ static int mt9m114_probe(struct i2c_client *client, /* Setup sensor configuration structure */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "out of memory\n"); + if (!dev) return -ENOMEM; - } v4l2_i2c_subdev_init(&dev->sd, client, &mt9m114_ops); pdata = client->dev.platform_data; diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 51b7d61df0f5..c81e80e7bdea 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -1447,10 +1447,8 @@ static int ov2680_probe(struct i2c_client *client, unsigned int i; dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "out of memory\n"); + if (!dev) return -ENOMEM; - } mutex_init(&dev->input_lock); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c index 10094ac56561..5f2e8a2798ef 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -1285,10 +1285,8 @@ static int ov2722_probe(struct i2c_client *client, struct acpi_device *adev; dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "out of memory\n"); + if (!dev) return -ENOMEM; - } mutex_init(&dev->input_lock); diff --git a/drivers/staging/media/atomisp/i2c/imx/imx.c b/drivers/staging/media/atomisp/i2c/imx/imx.c index 71b688970822..885a26cc158e 100644 --- a/drivers/staging/media/atomisp/i2c/imx/imx.c +++ b/drivers/staging/media/atomisp/i2c/imx/imx.c @@ -2364,10 +2364,8 @@ static int imx_probe(struct i2c_client *client, /* allocate sensor device & init sub device */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - v4l2_err(client, "%s: out of memory\n", __func__); + if (!dev) return -ENOMEM; - } mutex_init(&dev->input_lock); diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c index 219501167584..cfdb03fbb9e6 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c +++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c @@ -1958,10 +1958,8 @@ static int ov5693_probe(struct i2c_client *client, } dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "out of memory\n"); + if (!dev) return -ENOMEM; - } mutex_init(&dev->input_lock); diff --git a/drivers/staging/media/atomisp/i2c/ov8858.c b/drivers/staging/media/atomisp/i2c/ov8858.c index 43e1638fd674..918139d3d3c0 100644 --- a/drivers/staging/media/atomisp/i2c/ov8858.c +++ b/drivers/staging/media/atomisp/i2c/ov8858.c @@ -480,8 +480,6 @@ static int ov8858_priv_int_data_init(struct v4l2_subdev *sd) if (!dev->otp_data) { dev->otp_data = devm_kzalloc(&client->dev, size, GFP_KERNEL); if (!dev->otp_data) { - dev_err(&client->dev, "%s: can't allocate memory", - __func__); r = -ENOMEM; goto error3; } @@ -2094,10 +2092,8 @@ static int ov8858_probe(struct i2c_client *client, /* allocate sensor device & init sub device */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&client->dev, "%s: out of memory\n", __func__); + if (!dev) return -ENOMEM; - } mutex_init(&dev->input_lock); diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c index d8cfed358d55..d64c98944d49 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c @@ -1137,10 +1137,8 @@ static int remove_pad_from_frame(struct atomisp_device *isp, ia_css_ptr store = load; buffer = kmalloc(width*sizeof(load), GFP_KERNEL); - if (!buffer) { - dev_err(isp->dev, "out of memory.\n"); + if (!buffer) return -ENOMEM; - } load += ISP_LEFT_PAD; for (i = 0; i < height; i++) { diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c index dd59167237c1..ccb78f0bc7a2 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c @@ -942,10 +942,8 @@ int atomisp_alloc_css_stat_bufs(struct atomisp_sub_device *asd, dev_dbg(isp->dev, "allocating %d 3a buffers\n", count); while (count--) { s3a_buf = kzalloc(sizeof(struct atomisp_s3a_buf), GFP_KERNEL); - if (!s3a_buf) { - dev_err(isp->dev, "s3a stat buf alloc failed\n"); + if (!s3a_buf) goto error; - } if (atomisp_css_allocate_stat_buffers( asd, stream_id, s3a_buf, NULL, NULL)) { @@ -964,7 +962,6 @@ int atomisp_alloc_css_stat_bufs(struct atomisp_sub_device *asd, while (count--) { dis_buf = kzalloc(sizeof(struct atomisp_dis_buf), GFP_KERNEL); if (!dis_buf) { - dev_err(isp->dev, "dis stat buf alloc failed\n"); kfree(s3a_buf); goto error; } @@ -989,10 +986,8 @@ int atomisp_alloc_css_stat_bufs(struct atomisp_sub_device *asd, while (count--) { md_buf = kzalloc(sizeof(struct atomisp_metadata_buf), GFP_KERNEL); - if (!md_buf) { - dev_err(isp->dev, "metadata buf alloc failed\n"); + if (!md_buf) goto error; - } if (atomisp_css_allocate_stat_buffers( asd, stream_id, NULL, NULL, md_buf)) { diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_param_shading.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_param_shading.c index 48e2e63c2336..e6ebd1b08f0d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_param_shading.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_param_shading.c @@ -365,10 +365,8 @@ ia_css_shading_table_alloc( IA_CSS_ENTER(""); me = kmalloc(sizeof(*me), GFP_KERNEL); - if (!me) { - IA_CSS_ERROR("out of memory"); + if (!me) return me; - } me->width = width; me->height = height; diff --git a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_bo.c b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_bo.c index 8007b6f50179..12c96c4f284d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_bo.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_bo.c @@ -727,10 +727,8 @@ static int alloc_private_pages(struct hmm_buffer_object *bo, bo->page_obj = kmalloc(sizeof(struct hmm_page_object) * pgnr, GFP_KERNEL); - if (unlikely(!bo->page_obj)) { - dev_err(atomisp_dev, "out of memory for bo->page_obj\n"); + if (unlikely(!bo->page_obj)) return -ENOMEM; - } i = 0; alloc_pgnr = 0; @@ -991,15 +989,12 @@ static int alloc_user_pages(struct hmm_buffer_object *bo, struct page **pages; pages = kmalloc(sizeof(struct page *) * bo->pgnr, GFP_KERNEL); - if (unlikely(!pages)) { - dev_err(atomisp_dev, "out of memory for pages...\n"); + if (unlikely(!pages)) return -ENOMEM; - } bo->page_obj = kmalloc(sizeof(struct hmm_page_object) * bo->pgnr, GFP_KERNEL); if (unlikely(!bo->page_obj)) { - dev_err(atomisp_dev, "out of memory for bo->page_obj...\n"); kfree(pages); return -ENOMEM; } @@ -1362,7 +1357,6 @@ void *hmm_bo_vmap(struct hmm_buffer_object *bo, bool cached) pages = kmalloc(sizeof(*pages) * bo->pgnr, GFP_KERNEL); if (unlikely(!pages)) { mutex_unlock(&bo->mutex); - dev_err(atomisp_dev, "out of memory for pages...\n"); return NULL; } diff --git a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_dynamic_pool.c b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_dynamic_pool.c index 19e0e9ee37de..eb82c3e4c776 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_dynamic_pool.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_dynamic_pool.c @@ -116,8 +116,6 @@ static void free_pages_to_dynamic_pool(void *pool, hmm_page = kmem_cache_zalloc(dypool_info->pgptr_cache, GFP_KERNEL); if (!hmm_page) { - dev_err(atomisp_dev, "out of memory for hmm_page.\n"); - /* free page directly */ ret = set_pages_wb(page_obj->page, 1); if (ret) @@ -151,10 +149,8 @@ static int hmm_dynamic_pool_init(void **pool, unsigned int pool_size) dypool_info = kmalloc(sizeof(struct hmm_dynamic_pool_info), GFP_KERNEL); - if (unlikely(!dypool_info)) { - dev_err(atomisp_dev, "out of memory for repool_info.\n"); + if (unlikely(!dypool_info)) return -ENOMEM; - } dypool_info->pgptr_cache = kmem_cache_create("pgptr_cache", sizeof(struct hmm_page), 0, diff --git a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_reserved_pool.c b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_reserved_pool.c index bf6586805f7f..177bc354f1d7 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_reserved_pool.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_reserved_pool.c @@ -92,15 +92,12 @@ static int hmm_reserved_pool_setup(struct hmm_reserved_pool_info **repool_info, pool_info = kmalloc(sizeof(struct hmm_reserved_pool_info), GFP_KERNEL); - if (unlikely(!pool_info)) { - dev_err(atomisp_dev, "out of memory for repool_info.\n"); + if (unlikely(!pool_info)) return -ENOMEM; - } pool_info->pages = kmalloc(sizeof(struct page *) * pool_size, GFP_KERNEL); if (unlikely(!pool_info->pages)) { - dev_err(atomisp_dev, "out of memory for repool_info->pages.\n"); kfree(pool_info); return -ENOMEM; } diff --git a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_vm.c b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_vm.c index 0722a68a49e7..402ffd9cb480 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_vm.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_vm.c @@ -89,10 +89,8 @@ static struct hmm_vm_node *alloc_hmm_vm_node(unsigned int pgnr, struct hmm_vm_node *node; node = kmem_cache_alloc(vm->cache, GFP_KERNEL); - if (!node) { - dev_err(atomisp_dev, "out of memory.\n"); + if (!node) return NULL; - } INIT_LIST_HEAD(&node->list); node->pgnr = pgnr; diff --git a/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c index 8a20a28d37f1..8c6a26eea095 100644 --- a/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c @@ -785,10 +785,8 @@ int camera_sensor_csi(struct v4l2_subdev *sd, u32 port, if (flag) { csi = kzalloc(sizeof(*csi), GFP_KERNEL); - if (!csi) { - dev_err(&client->dev, "out of memory\n"); + if (!csi) return -ENOMEM; - } csi->port = port; csi->num_lanes = lanes; csi->input_format = format; -- cgit v1.2.3 From ef674997e49760137ca9a90aac41a9922ac399b2 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 4 Oct 2017 20:47:38 -0400 Subject: media: staging: atomisp: Convert timers to use timer_setup() In preparation for unconditionally passing the struct timer_list pointer to all timer callbacks, switch to using the new timer_setup() and from_timer() to pass the timer pointer explicitly. Cc: Mauro Carvalho Chehab Cc: Greg Kroah-Hartman Cc: Alan Cox Cc: Daeseok Youn Cc: Arnd Bergmann Cc: devel@driverdev.osuosl.org Cc: Thomas Gleixner Signed-off-by: Kees Cook Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c | 13 ++++--------- drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.h | 6 +----- .../media/atomisp/pci/atomisp2/atomisp_compat_css20.c | 2 +- drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c | 15 +++++---------- 4 files changed, 11 insertions(+), 25 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c index b0c647f4d250..f3cf4ecba630 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c @@ -1661,20 +1661,15 @@ void atomisp_css_flush(struct atomisp_device *isp) dev_dbg(isp->dev, "atomisp css flush done\n"); } -#ifndef ISP2401 -void atomisp_wdt(unsigned long isp_addr) -#else -void atomisp_wdt(unsigned long pipe_addr) -#endif +void atomisp_wdt(struct timer_list *t) { #ifndef ISP2401 - struct atomisp_device *isp = (struct atomisp_device *)isp_addr; + struct atomisp_sub_device *asd = from_timer(asd, t, wdt); #else - struct atomisp_video_pipe *pipe = - (struct atomisp_video_pipe *)pipe_addr; + struct atomisp_video_pipe *pipe = from_timer(pipe, t, wdt); struct atomisp_sub_device *asd = pipe->asd; - struct atomisp_device *isp = asd->isp; #endif + struct atomisp_device *isp = asd->isp; #ifdef ISP2401 atomic_inc(&pipe->wdt_count); diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.h index 31ba4e613d13..4bb83864da2e 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.h @@ -85,11 +85,7 @@ static inline void __iomem *atomisp_get_io_virt_addr(unsigned int address) void atomisp_msi_irq_init(struct atomisp_device *isp, struct pci_dev *dev); void atomisp_msi_irq_uninit(struct atomisp_device *isp, struct pci_dev *dev); void atomisp_wdt_work(struct work_struct *work); -#ifndef ISP2401 -void atomisp_wdt(unsigned long isp_addr); -#else -void atomisp_wdt(unsigned long pipe_addr); -#endif +void atomisp_wdt(struct timer_list *t); void atomisp_setup_flash(struct atomisp_sub_device *asd); irqreturn_t atomisp_isr(int irq, void *dev); irqreturn_t atomisp_isr_thread(int irq, void *isp_ptr); diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c index 05897b747349..0b907474e024 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c @@ -4515,7 +4515,7 @@ int atomisp_css_isr_thread(struct atomisp_device *isp, for (i = 0; i < isp->num_of_streams; i++) atomisp_wdt_stop(&isp->asd[i], 0); #ifndef ISP2401 - atomisp_wdt((unsigned long)isp); + atomisp_wdt(&isp->asd[0].wdt); #else queue_work(isp->wdt_work_queue, &isp->wdt_work); #endif diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c index e85b3819bffa..20aff7faf44a 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c @@ -1150,17 +1150,12 @@ static int init_atomisp_wdts(struct atomisp_device *isp) struct atomisp_sub_device *asd = &isp->asd[i]; asd = &isp->asd[i]; #ifndef ISP2401 - setup_timer(&asd->wdt, atomisp_wdt, (unsigned long)isp); + timer_setup(&asd->wdt, atomisp_wdt, 0); #else - setup_timer(&asd->video_out_capture.wdt, - atomisp_wdt, (unsigned long)&asd->video_out_capture); - setup_timer(&asd->video_out_preview.wdt, - atomisp_wdt, (unsigned long)&asd->video_out_preview); - setup_timer(&asd->video_out_vf.wdt, - atomisp_wdt, (unsigned long)&asd->video_out_vf); - setup_timer(&asd->video_out_video_capture.wdt, - atomisp_wdt, - (unsigned long)&asd->video_out_video_capture); + timer_setup(&asd->video_out_capture.wdt, atomisp_wdt, 0); + timer_setup(&asd->video_out_preview.wdt, atomisp_wdt, 0); + timer_setup(&asd->video_out_vf.wdt, atomisp_wdt, 0); + timer_setup(&asd->video_out_video_capture.wdt, atomisp_wdt, 0); #endif } return 0; -- cgit v1.2.3 From 3a81c7660f8021967dccd52624fa1a6fcf117000 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 27 Sep 2017 14:24:56 -0400 Subject: media: staging: atomisp: Remove IMX sensor support This sensor is not used by any known ACPI-enabled platform (and no kernel users for it so far). Just remove it for good until we get a platform which actually uses it. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/Kconfig | 1 - drivers/staging/media/atomisp/i2c/Makefile | 1 - drivers/staging/media/atomisp/i2c/imx/Kconfig | 9 - drivers/staging/media/atomisp/i2c/imx/Makefile | 13 - drivers/staging/media/atomisp/i2c/imx/ad5816g.c | 216 -- drivers/staging/media/atomisp/i2c/imx/ad5816g.h | 49 - drivers/staging/media/atomisp/i2c/imx/common.h | 65 - drivers/staging/media/atomisp/i2c/imx/drv201.c | 208 -- drivers/staging/media/atomisp/i2c/imx/drv201.h | 38 - drivers/staging/media/atomisp/i2c/imx/dw9714.c | 222 -- drivers/staging/media/atomisp/i2c/imx/dw9714.h | 63 - drivers/staging/media/atomisp/i2c/imx/dw9718.c | 233 -- drivers/staging/media/atomisp/i2c/imx/dw9718.h | 64 - drivers/staging/media/atomisp/i2c/imx/dw9719.c | 198 -- drivers/staging/media/atomisp/i2c/imx/dw9719.h | 58 - drivers/staging/media/atomisp/i2c/imx/imx.c | 2477 -------------- drivers/staging/media/atomisp/i2c/imx/imx.h | 737 ----- drivers/staging/media/atomisp/i2c/imx/imx132.h | 566 ---- drivers/staging/media/atomisp/i2c/imx/imx134.h | 2464 -------------- drivers/staging/media/atomisp/i2c/imx/imx135.h | 3374 -------------------- drivers/staging/media/atomisp/i2c/imx/imx175.h | 1959 ------------ drivers/staging/media/atomisp/i2c/imx/imx208.h | 550 ---- drivers/staging/media/atomisp/i2c/imx/imx219.h | 227 -- drivers/staging/media/atomisp/i2c/imx/imx227.h | 726 ----- drivers/staging/media/atomisp/i2c/imx/otp.c | 39 - .../media/atomisp/i2c/imx/otp_brcc064_e2prom.c | 80 - drivers/staging/media/atomisp/i2c/imx/otp_e2prom.c | 89 - drivers/staging/media/atomisp/i2c/imx/otp_imx.c | 190 -- drivers/staging/media/atomisp/i2c/imx/vcm.c | 45 - 29 files changed, 14961 deletions(-) delete mode 100644 drivers/staging/media/atomisp/i2c/imx/Kconfig delete mode 100644 drivers/staging/media/atomisp/i2c/imx/Makefile delete mode 100644 drivers/staging/media/atomisp/i2c/imx/ad5816g.c delete mode 100644 drivers/staging/media/atomisp/i2c/imx/ad5816g.h delete mode 100644 drivers/staging/media/atomisp/i2c/imx/common.h delete mode 100644 drivers/staging/media/atomisp/i2c/imx/drv201.c delete mode 100644 drivers/staging/media/atomisp/i2c/imx/drv201.h delete mode 100644 drivers/staging/media/atomisp/i2c/imx/dw9714.c delete mode 100644 drivers/staging/media/atomisp/i2c/imx/dw9714.h delete mode 100644 drivers/staging/media/atomisp/i2c/imx/dw9718.c delete mode 100644 drivers/staging/media/atomisp/i2c/imx/dw9718.h delete mode 100644 drivers/staging/media/atomisp/i2c/imx/dw9719.c delete mode 100644 drivers/staging/media/atomisp/i2c/imx/dw9719.h delete mode 100644 drivers/staging/media/atomisp/i2c/imx/imx.c delete mode 100644 drivers/staging/media/atomisp/i2c/imx/imx.h delete mode 100644 drivers/staging/media/atomisp/i2c/imx/imx132.h delete mode 100644 drivers/staging/media/atomisp/i2c/imx/imx134.h delete mode 100644 drivers/staging/media/atomisp/i2c/imx/imx135.h delete mode 100644 drivers/staging/media/atomisp/i2c/imx/imx175.h delete mode 100644 drivers/staging/media/atomisp/i2c/imx/imx208.h delete mode 100644 drivers/staging/media/atomisp/i2c/imx/imx219.h delete mode 100644 drivers/staging/media/atomisp/i2c/imx/imx227.h delete mode 100644 drivers/staging/media/atomisp/i2c/imx/otp.c delete mode 100644 drivers/staging/media/atomisp/i2c/imx/otp_brcc064_e2prom.c delete mode 100644 drivers/staging/media/atomisp/i2c/imx/otp_e2prom.c delete mode 100644 drivers/staging/media/atomisp/i2c/imx/otp_imx.c delete mode 100644 drivers/staging/media/atomisp/i2c/imx/vcm.c diff --git a/drivers/staging/media/atomisp/i2c/Kconfig b/drivers/staging/media/atomisp/i2c/Kconfig index 09b1a97ce560..1273c3beb1ec 100644 --- a/drivers/staging/media/atomisp/i2c/Kconfig +++ b/drivers/staging/media/atomisp/i2c/Kconfig @@ -3,7 +3,6 @@ # source "drivers/staging/media/atomisp/i2c/ov5693/Kconfig" -source "drivers/staging/media/atomisp/i2c/imx/Kconfig" config VIDEO_ATOMISP_OV2722 tristate "OVT ov2722 sensor support" diff --git a/drivers/staging/media/atomisp/i2c/Makefile b/drivers/staging/media/atomisp/i2c/Makefile index 3d27c75f5fc5..ae19c691a73f 100644 --- a/drivers/staging/media/atomisp/i2c/Makefile +++ b/drivers/staging/media/atomisp/i2c/Makefile @@ -2,7 +2,6 @@ # Makefile for sensor drivers # -obj-$(CONFIG_VIDEO_ATOMISP_IMX) += imx/ obj-$(CONFIG_VIDEO_ATOMISP_OV5693) += ov5693/ obj-$(CONFIG_VIDEO_ATOMISP_MT9M114) += atomisp-mt9m114.o obj-$(CONFIG_VIDEO_ATOMISP_GC2235) += atomisp-gc2235.o diff --git a/drivers/staging/media/atomisp/i2c/imx/Kconfig b/drivers/staging/media/atomisp/i2c/imx/Kconfig deleted file mode 100644 index c4356c1a8aca..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config VIDEO_ATOMISP_IMX - tristate "sony imx sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_ATOMISP_MSRLIST_HELPER && m - ---help--- - This is a Video4Linux2 sensor-level driver for the Sony - IMX RAW sensor. - - It currently depends on internal V4L2 extensions defined in - atomisp driver. diff --git a/drivers/staging/media/atomisp/i2c/imx/Makefile b/drivers/staging/media/atomisp/i2c/imx/Makefile deleted file mode 100644 index f3e2891cdfec..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -obj-$(CONFIG_VIDEO_ATOMISP_IMX) += atomisp-imx1x5.o - -atomisp-imx1x5-objs := imx.o drv201.o ad5816g.o dw9714.o dw9719.o dw9718.o vcm.o otp.o otp_imx.o otp_brcc064_e2prom.o otp_e2prom.o - -atomisp-ov8858-objs := ../ov8858.o dw9718.o vcm.o -obj-$(CONFIG_VIDEO_ATOMISP_OV8858) += atomisp-ov8858.o - -# HACK! While this driver is in bad shape, don't enable several warnings -# that would be otherwise enabled with W=1 -ccflags-y += $(call cc-disable-warning, unused-but-set-variable) -ccflags-y += $(call cc-disable-warning, unused-const-variable) -ccflags-y += $(call cc-disable-warning, missing-prototypes) -ccflags-y += $(call cc-disable-warning, missing-declarations) diff --git a/drivers/staging/media/atomisp/i2c/imx/ad5816g.c b/drivers/staging/media/atomisp/i2c/imx/ad5816g.c deleted file mode 100644 index 558dcdf135d9..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/ad5816g.c +++ /dev/null @@ -1,216 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ad5816g.h" - -struct ad5816g_device ad5816g_dev; - -static int ad5816g_i2c_rd8(struct i2c_client *client, u8 reg, u8 *val) -{ - struct i2c_msg msg[2]; - u8 buf[2]; - buf[0] = reg; - buf[1] = 0; - - msg[0].addr = AD5816G_VCM_ADDR; - msg[0].flags = 0; - msg[0].len = 1; - msg[0].buf = &buf[0]; - - msg[1].addr = AD5816G_VCM_ADDR; - msg[1].flags = I2C_M_RD; - msg[1].len = 1; - msg[1].buf = &buf[1]; - *val = 0; - if (i2c_transfer(client->adapter, msg, 2) != 2) - return -EIO; - *val = buf[1]; - return 0; -} - -static int ad5816g_i2c_wr8(struct i2c_client *client, u8 reg, u8 val) -{ - struct i2c_msg msg; - u8 buf[2]; - buf[0] = reg; - buf[1] = val; - msg.addr = AD5816G_VCM_ADDR; - msg.flags = 0; - msg.len = 2; - msg.buf = &buf[0]; - if (i2c_transfer(client->adapter, &msg, 1) != 1) - return -EIO; - return 0; -} - -static int ad5816g_i2c_wr16(struct i2c_client *client, u8 reg, u16 val) -{ - struct i2c_msg msg; - u8 buf[3]; - buf[0] = reg; - buf[1] = (u8)(val >> 8); - buf[2] = (u8)(val & 0xff); - msg.addr = AD5816G_VCM_ADDR; - msg.flags = 0; - msg.len = 3; - msg.buf = &buf[0]; - if (i2c_transfer(client->adapter, &msg, 1) != 1) - return -EIO; - return 0; -} - -static int ad5816g_set_arc_mode(struct i2c_client *client) -{ - int ret; - - ret = ad5816g_i2c_wr8(client, AD5816G_CONTROL, AD5816G_ARC_EN); - if (ret) - return ret; - - ret = ad5816g_i2c_wr8(client, AD5816G_MODE, - AD5816G_MODE_2_5M_SWITCH_CLOCK); - if (ret) - return ret; - - ret = ad5816g_i2c_wr8(client, AD5816G_VCM_FREQ, AD5816G_DEF_FREQ); - return ret; -} - -int ad5816g_vcm_power_up(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u8 ad5816g_id; - - /* Enable power */ - ret = ad5816g_dev.platform_data->power_ctrl(sd, 1); - if (ret) - return ret; - /* waiting time AD5816G(vcm) - t1 + t2 - * t1(1ms) -Time from VDD high to first i2c cmd - * t2(100us) - exit power-down mode time - */ - usleep_range(1100, 2200); - /* Detect device */ - ret = ad5816g_i2c_rd8(client, AD5816G_IC_INFO, &ad5816g_id); - if (ret < 0) - goto fail_powerdown; - if (ad5816g_id != AD5816G_ID) { - ret = -ENXIO; - goto fail_powerdown; - } - ret = ad5816g_set_arc_mode(client); - if (ret) - return ret; - - /* set the VCM_THRESHOLD */ - ret = ad5816g_i2c_wr8(client, AD5816G_VCM_THRESHOLD, - AD5816G_DEF_THRESHOLD); - - return ret; - -fail_powerdown: - ad5816g_dev.platform_data->power_ctrl(sd, 0); - return ret; -} - -int ad5816g_vcm_power_down(struct v4l2_subdev *sd) -{ - return ad5816g_dev.platform_data->power_ctrl(sd, 0); -} - - -static int ad5816g_t_focus_vcm(struct v4l2_subdev *sd, u16 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 data = val & VCM_CODE_MASK; - - return ad5816g_i2c_wr16(client, AD5816G_VCM_CODE_MSB, data); -} - -int ad5816g_t_focus_abs(struct v4l2_subdev *sd, s32 value) -{ - int ret; - - value = clamp(value, 0, AD5816G_MAX_FOCUS_POS); - ret = ad5816g_t_focus_vcm(sd, value); - if (ret == 0) { - ad5816g_dev.number_of_steps = value - ad5816g_dev.focus; - ad5816g_dev.focus = value; - getnstimeofday(&(ad5816g_dev.timestamp_t_focus_abs)); - } - - return ret; -} - -int ad5816g_t_focus_rel(struct v4l2_subdev *sd, s32 value) -{ - - return ad5816g_t_focus_abs(sd, ad5816g_dev.focus + value); -} - -int ad5816g_q_focus_status(struct v4l2_subdev *sd, s32 *value) -{ - u32 status = 0; - struct timespec temptime; - const struct timespec timedelay = { - 0, - min_t(u32, abs(ad5816g_dev.number_of_steps) * DELAY_PER_STEP_NS, - DELAY_MAX_PER_STEP_NS), - }; - - ktime_get_ts(&temptime); - - temptime = timespec_sub(temptime, (ad5816g_dev.timestamp_t_focus_abs)); - - if (timespec_compare(&temptime, &timedelay) <= 0) { - status |= ATOMISP_FOCUS_STATUS_MOVING; - status |= ATOMISP_FOCUS_HP_IN_PROGRESS; - } else { - status |= ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE; - status |= ATOMISP_FOCUS_HP_COMPLETE; - } - *value = status; - - return 0; -} - -int ad5816g_q_focus_abs(struct v4l2_subdev *sd, s32 *value) -{ - s32 val; - - ad5816g_q_focus_status(sd, &val); - - if (val & ATOMISP_FOCUS_STATUS_MOVING) - *value = ad5816g_dev.focus - ad5816g_dev.number_of_steps; - else - *value = ad5816g_dev.focus; - - return 0; -} - -int ad5816g_t_vcm_slew(struct v4l2_subdev *sd, s32 value) -{ - return 0; -} - -int ad5816g_t_vcm_timing(struct v4l2_subdev *sd, s32 value) -{ - return 0; -} diff --git a/drivers/staging/media/atomisp/i2c/imx/ad5816g.h b/drivers/staging/media/atomisp/i2c/imx/ad5816g.h deleted file mode 100644 index f995c2eeada4..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/ad5816g.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef __AD5816G_H__ -#define __AD5816G_H__ - -#include "../../include/linux/atomisp_platform.h" -#include -#include - -#define AD5816G_VCM_ADDR 0x0e - -/* ad5816g device structure */ -struct ad5816g_device { - const struct camera_af_platform_data *platform_data; - struct timespec timestamp_t_focus_abs; - struct timespec focus_time; /* Time when focus was last time set */ - s32 focus; /* Current focus value */ - s16 number_of_steps; -}; - -#define AD5816G_INVALID_CONFIG 0xffffffff -#define AD5816G_MAX_FOCUS_POS 1023 -#define DELAY_PER_STEP_NS 1000000 -#define DELAY_MAX_PER_STEP_NS (1000000 * 1023) - -/* Register Definitions */ -#define AD5816G_IC_INFO 0x00 -#define AD5816G_IC_VERSION 0x01 -#define AD5816G_CONTROL 0x02 -#define AD5816G_VCM_CODE_MSB 0x03 -#define AD5816G_VCM_CODE_LSB 0x04 -#define AD5816G_STATUS 0x05 -#define AD5816G_MODE 0x06 -#define AD5816G_VCM_FREQ 0x07 -#define AD5816G_VCM_THRESHOLD 0x08 - -/* ARC MODE ENABLE */ -#define AD5816G_ARC_EN 0x02 -/* ARC RES2 MODE */ -#define AD5816G_ARC_RES2 0x01 -/* ARC VCM FREQ - 78.1Hz */ -#define AD5816G_DEF_FREQ 0x7a -/* ARC VCM THRESHOLD - 0x08 << 1 */ -#define AD5816G_DEF_THRESHOLD 0x64 -#define AD5816G_ID 0x24 -#define VCM_CODE_MASK 0x03ff - -#define AD5816G_MODE_2_5M_SWITCH_CLOCK 0x14 - -#endif - diff --git a/drivers/staging/media/atomisp/i2c/imx/common.h b/drivers/staging/media/atomisp/i2c/imx/common.h deleted file mode 100644 index 7e525cef56ef..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/common.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef __COMMON_H__ -#define __COMMON_H__ - -#define MAX_FPS_OPTIONS_SUPPORTED 3 -#define I2C_MSG_LENGTH 0x2 -#define E2PROM_2ADDR 0x80000000 -#define E2PROM_ADDR_MASK 0x7fffffff - -/* Defines for register writes and register array processing */ -#define IMX_BYTE_MAX 32 -#define IMX_SHORT_MAX 16 -#define I2C_RETRY_COUNT 5 -#define IMX_TOK_MASK 0xfff0 - -enum imx_tok_type { - IMX_8BIT = 0x0001, - IMX_16BIT = 0x0002, - IMX_TOK_TERM = 0xf000, /* terminating token for reg list */ - IMX_TOK_DELAY = 0xfe00 /* delay token for reg list */ -}; - -/** - * struct imx_reg - MI sensor register format - * @type: type of the register - * @reg: 16-bit offset to register - * @val: 8/16/32-bit register value - * - * Define a structure for sensor register initialization values - */ -struct imx_reg { - enum imx_tok_type type; - u16 sreg; - u32 val; /* @set value for read/mod/write, @mask */ -}; - -struct imx_fps_setting { - int fps; - unsigned short pixels_per_line; - unsigned short lines_per_frame; - int mipi_freq; /* MIPI lane frequency in kHz */ - const struct imx_reg *regs; /* regs that the fps setting needs */ -}; - -struct imx_resolution { - const struct imx_fps_setting fps_options[MAX_FPS_OPTIONS_SUPPORTED]; - u8 *desc; - const struct imx_reg *regs; - int res; - int width; - int height; - int fps; - unsigned short pixels_per_line; - unsigned short lines_per_frame; - int mipi_freq; /* MIPI lane frequency in kHz */ - unsigned short skip_frames; - u8 bin_factor_x; - u8 bin_factor_y; - bool used; -}; - -#define GROUPED_PARAMETER_HOLD_ENABLE {IMX_8BIT, 0x0104, 0x1} -#define GROUPED_PARAMETER_HOLD_DISABLE {IMX_8BIT, 0x0104, 0x0} - -int imx_write_reg(struct i2c_client *client, u16 data_length, u16 reg, u16 val); -#endif diff --git a/drivers/staging/media/atomisp/i2c/imx/drv201.c b/drivers/staging/media/atomisp/i2c/imx/drv201.c deleted file mode 100644 index 532af7da3158..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/drv201.c +++ /dev/null @@ -1,208 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "drv201.h" - -static struct drv201_device drv201_dev; - -static int drv201_i2c_rd8(struct i2c_client *client, u8 reg, u8 *val) -{ - struct i2c_msg msg[2]; - u8 buf[2]; - buf[0] = reg; - buf[1] = 0; - - msg[0].addr = DRV201_VCM_ADDR; - msg[0].flags = 0; - msg[0].len = 1; - msg[0].buf = &buf[0]; - - msg[1].addr = DRV201_VCM_ADDR; - msg[1].flags = I2C_M_RD; - msg[1].len = 1; - msg[1].buf = &buf[1]; - *val = 0; - if (i2c_transfer(client->adapter, msg, 2) != 2) - return -EIO; - *val = buf[1]; - return 0; -} - -static int drv201_i2c_wr8(struct i2c_client *client, u8 reg, u8 val) -{ - struct i2c_msg msg; - u8 buf[2]; - buf[0] = reg; - buf[1] = val; - msg.addr = DRV201_VCM_ADDR; - msg.flags = 0; - msg.len = 2; - msg.buf = &buf[0]; - if (i2c_transfer(client->adapter, &msg, 1) != 1) - return -EIO; - return 0; -} - -static int drv201_i2c_wr16(struct i2c_client *client, u8 reg, u16 val) -{ - struct i2c_msg msg; - u8 buf[3]; - buf[0] = reg; - buf[1] = (u8)(val >> 8); - buf[2] = (u8)(val & 0xff); - msg.addr = DRV201_VCM_ADDR; - msg.flags = 0; - msg.len = 3; - msg.buf = &buf[0]; - if (i2c_transfer(client->adapter, &msg, 1) != 1) - return -EIO; - return 0; -} - -int drv201_vcm_power_up(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u8 value; - - /* Enable power */ - ret = drv201_dev.platform_data->power_ctrl(sd, 1); - if (ret) - return ret; - /* Wait for VBAT to stabilize */ - udelay(1); - /* - * Jiggle SCL pin to wake up device. - * Drv201 expect SCL from low to high to wake device up. - * So the 1st access to i2c would fail. - * Using following function to wake device up. - */ - drv201_i2c_wr8(client, DRV201_CONTROL, DRV201_RESET); - - /* Need 100us to transit from SHUTDOWN to STANDBY*/ - usleep_range(WAKEUP_DELAY_US, WAKEUP_DELAY_US * 10); - - /* Reset device */ - ret = drv201_i2c_wr8(client, DRV201_CONTROL, DRV201_RESET); - if (ret < 0) - goto fail_powerdown; - - /* Detect device */ - ret = drv201_i2c_rd8(client, DRV201_CONTROL, &value); - if (ret < 0) - goto fail_powerdown; - if (value != DEFAULT_CONTROL_VAL) { - ret = -ENXIO; - goto fail_powerdown; - } - - drv201_dev.focus = DRV201_MAX_FOCUS_POS; - drv201_dev.initialized = true; - - return 0; -fail_powerdown: - drv201_dev.platform_data->power_ctrl(sd, 0); - return ret; -} - -int drv201_vcm_power_down(struct v4l2_subdev *sd) -{ - return drv201_dev.platform_data->power_ctrl(sd, 0); -} - - -static int drv201_t_focus_vcm(struct v4l2_subdev *sd, u16 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 data = val & VCM_CODE_MASK; - - if (!drv201_dev.initialized) - return -ENODEV; - return drv201_i2c_wr16(client, DRV201_VCM_CURRENT, data); -} - -int drv201_t_focus_abs(struct v4l2_subdev *sd, s32 value) -{ - int ret; - - value = clamp(value, 0, DRV201_MAX_FOCUS_POS); - ret = drv201_t_focus_vcm(sd, value); - if (ret == 0) { - drv201_dev.number_of_steps = value - drv201_dev.focus; - drv201_dev.focus = value; - getnstimeofday(&(drv201_dev.timestamp_t_focus_abs)); - } - - return ret; -} - -int drv201_t_focus_rel(struct v4l2_subdev *sd, s32 value) -{ - return drv201_t_focus_abs(sd, drv201_dev.focus + value); -} - -int drv201_q_focus_status(struct v4l2_subdev *sd, s32 *value) -{ - u32 status = 0; - struct timespec temptime; - const struct timespec timedelay = { - 0, - min_t(u32, abs(drv201_dev.number_of_steps)*DELAY_PER_STEP_NS, - DELAY_MAX_PER_STEP_NS), - }; - - ktime_get_ts(&temptime); - - temptime = timespec_sub(temptime, (drv201_dev.timestamp_t_focus_abs)); - - if (timespec_compare(&temptime, &timedelay) <= 0) { - status |= ATOMISP_FOCUS_STATUS_MOVING; - status |= ATOMISP_FOCUS_HP_IN_PROGRESS; - } else { - status |= ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE; - status |= ATOMISP_FOCUS_HP_COMPLETE; - } - *value = status; - - return 0; -} - -int drv201_q_focus_abs(struct v4l2_subdev *sd, s32 *value) -{ - s32 val; - - drv201_q_focus_status(sd, &val); - - if (val & ATOMISP_FOCUS_STATUS_MOVING) - *value = drv201_dev.focus - drv201_dev.number_of_steps; - else - *value = drv201_dev.focus; - - return 0; -} - -int drv201_t_vcm_slew(struct v4l2_subdev *sd, s32 value) -{ - return 0; -} - -int drv201_t_vcm_timing(struct v4l2_subdev *sd, s32 value) -{ - return 0; -} diff --git a/drivers/staging/media/atomisp/i2c/imx/drv201.h b/drivers/staging/media/atomisp/i2c/imx/drv201.h deleted file mode 100644 index 8fc0ad116630..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/drv201.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef __DRV201_H__ -#define __DRV201_H__ - -#include "../../include/linux/atomisp_platform.h" -#include -#include - -#define DRV201_VCM_ADDR 0x0e - -/* drv201 device structure */ -struct drv201_device { - const struct camera_af_platform_data *platform_data; - struct timespec timestamp_t_focus_abs; - struct timespec focus_time; /* Time when focus was last time set */ - s32 focus; /* Current focus value */ - s16 number_of_steps; - bool initialized; /* true if drv201 is detected */ -}; - -#define DRV201_INVALID_CONFIG 0xffffffff -#define DRV201_MAX_FOCUS_POS 1023 -#define DELAY_PER_STEP_NS 1000000 -#define DELAY_MAX_PER_STEP_NS (1000000 * 1023) - -#define DRV201_CONTROL 2 -#define DRV201_VCM_CURRENT 3 -#define DRV201_STATUS 5 -#define DRV201_MODE 6 -#define DRV201_VCM_FREQ 7 - -#define DEFAULT_CONTROL_VAL 2 -#define DRV201_RESET 1 -#define WAKEUP_DELAY_US 100 -#define VCM_CODE_MASK 0x03ff - -#endif - - diff --git a/drivers/staging/media/atomisp/i2c/imx/dw9714.c b/drivers/staging/media/atomisp/i2c/imx/dw9714.c deleted file mode 100644 index 7e58fb3589cc..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/dw9714.c +++ /dev/null @@ -1,222 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dw9714.h" - -static struct dw9714_device dw9714_dev; -static int dw9714_i2c_write(struct i2c_client *client, u16 data) -{ - struct i2c_msg msg; - const int num_msg = 1; - int ret; - u16 val; - - val = cpu_to_be16(data); - msg.addr = DW9714_VCM_ADDR; - msg.flags = 0; - msg.len = DW9714_16BIT; - msg.buf = (u8 *)&val; - - ret = i2c_transfer(client->adapter, &msg, 1); - - return ret == num_msg ? 0 : -EIO; -} - -int dw9714_vcm_power_up(struct v4l2_subdev *sd) -{ - int ret; - - /* Enable power */ - ret = dw9714_dev.platform_data->power_ctrl(sd, 1); - /* waiting time requested by DW9714A(vcm) */ - usleep_range(12000, 12500); - return ret; -} - -int dw9714_vcm_power_down(struct v4l2_subdev *sd) -{ - return dw9714_dev.platform_data->power_ctrl(sd, 0); -} - - -static int dw9714_t_focus_vcm(struct v4l2_subdev *sd, u16 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret = -EINVAL; - u8 mclk = vcm_step_mclk(dw9714_dev.vcm_settings.step_setting); - u8 s = vcm_step_s(dw9714_dev.vcm_settings.step_setting); - - /* - * For different mode, VCM_PROTECTION_OFF/ON required by the - * control procedure. For DW9714_DIRECT/DLC mode, slew value is - * VCM_DEFAULT_S(0). - */ - switch (dw9714_dev.vcm_mode) { - case DW9714_DIRECT: - if (dw9714_dev.vcm_settings.update) { - ret = dw9714_i2c_write(client, VCM_PROTECTION_OFF); - if (ret) - return ret; - ret = dw9714_i2c_write(client, DIRECT_VCM); - if (ret) - return ret; - ret = dw9714_i2c_write(client, VCM_PROTECTION_ON); - if (ret) - return ret; - dw9714_dev.vcm_settings.update = false; - } - ret = dw9714_i2c_write(client, - vcm_val(val, VCM_DEFAULT_S)); - break; - case DW9714_LSC: - if (dw9714_dev.vcm_settings.update) { - ret = dw9714_i2c_write(client, VCM_PROTECTION_OFF); - if (ret) - return ret; - ret = dw9714_i2c_write(client, - vcm_dlc_mclk(DLC_DISABLE, mclk)); - if (ret) - return ret; - ret = dw9714_i2c_write(client, - vcm_tsrc(dw9714_dev.vcm_settings.t_src)); - if (ret) - return ret; - ret = dw9714_i2c_write(client, VCM_PROTECTION_ON); - if (ret) - return ret; - dw9714_dev.vcm_settings.update = false; - } - ret = dw9714_i2c_write(client, vcm_val(val, s)); - break; - case DW9714_DLC: - if (dw9714_dev.vcm_settings.update) { - ret = dw9714_i2c_write(client, VCM_PROTECTION_OFF); - if (ret) - return ret; - ret = dw9714_i2c_write(client, - vcm_dlc_mclk(DLC_ENABLE, mclk)); - if (ret) - return ret; - ret = dw9714_i2c_write(client, - vcm_tsrc(dw9714_dev.vcm_settings.t_src)); - if (ret) - return ret; - ret = dw9714_i2c_write(client, VCM_PROTECTION_ON); - if (ret) - return ret; - dw9714_dev.vcm_settings.update = false; - } - ret = dw9714_i2c_write(client, - vcm_val(val, VCM_DEFAULT_S)); - break; - } - return ret; -} - -int dw9714_t_focus_abs(struct v4l2_subdev *sd, s32 value) -{ - int ret; - - value = clamp(value, 0, DW9714_MAX_FOCUS_POS); - ret = dw9714_t_focus_vcm(sd, value); - if (ret == 0) { - dw9714_dev.number_of_steps = value - dw9714_dev.focus; - dw9714_dev.focus = value; - getnstimeofday(&(dw9714_dev.timestamp_t_focus_abs)); - } - - return ret; -} - -int dw9714_t_focus_abs_init(struct v4l2_subdev *sd) -{ - int ret; - - ret = dw9714_t_focus_vcm(sd, DW9714_DEFAULT_FOCUS_POS); - if (ret == 0) { - dw9714_dev.number_of_steps = - DW9714_DEFAULT_FOCUS_POS - dw9714_dev.focus; - dw9714_dev.focus = DW9714_DEFAULT_FOCUS_POS; - getnstimeofday(&(dw9714_dev.timestamp_t_focus_abs)); - } - - return ret; -} - -int dw9714_t_focus_rel(struct v4l2_subdev *sd, s32 value) -{ - - return dw9714_t_focus_abs(sd, dw9714_dev.focus + value); -} - -int dw9714_q_focus_status(struct v4l2_subdev *sd, s32 *value) -{ - u32 status = 0; - struct timespec temptime; - const struct timespec timedelay = { - 0, - min_t(u32, abs(dw9714_dev.number_of_steps)*DELAY_PER_STEP_NS, - DELAY_MAX_PER_STEP_NS), - }; - - ktime_get_ts(&temptime); - - temptime = timespec_sub(temptime, (dw9714_dev.timestamp_t_focus_abs)); - - if (timespec_compare(&temptime, &timedelay) <= 0) { - status |= ATOMISP_FOCUS_STATUS_MOVING; - status |= ATOMISP_FOCUS_HP_IN_PROGRESS; - } else { - status |= ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE; - status |= ATOMISP_FOCUS_HP_COMPLETE; - } - *value = status; - - return 0; -} - -int dw9714_q_focus_abs(struct v4l2_subdev *sd, s32 *value) -{ - s32 val; - - dw9714_q_focus_status(sd, &val); - - if (val & ATOMISP_FOCUS_STATUS_MOVING) - *value = dw9714_dev.focus - dw9714_dev.number_of_steps; - else - *value = dw9714_dev.focus; - - return 0; -} - -int dw9714_t_vcm_slew(struct v4l2_subdev *sd, s32 value) -{ - dw9714_dev.vcm_settings.step_setting = value; - dw9714_dev.vcm_settings.update = true; - - return 0; -} - -int dw9714_t_vcm_timing(struct v4l2_subdev *sd, s32 value) -{ - dw9714_dev.vcm_settings.t_src = value; - dw9714_dev.vcm_settings.update = true; - - return 0; -} diff --git a/drivers/staging/media/atomisp/i2c/imx/dw9714.h b/drivers/staging/media/atomisp/i2c/imx/dw9714.h deleted file mode 100644 index 5a98a9c97182..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/dw9714.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef __DW9714_H__ -#define __DW9714_H__ - -#include "../../include/linux/atomisp_platform.h" -#include - - -#define DW9714_VCM_ADDR 0x0c - -enum dw9714_tok_type { - DW9714_8BIT = 0x0001, - DW9714_16BIT = 0x0002, -}; - -struct dw9714_vcm_settings { - u16 code; /* bit[9:0]: Data[9:0] */ - u8 t_src; /* bit[4:0]: T_SRC[4:0] */ - u8 step_setting; /* bit[3:0]: S[3:0]/bit[5:4]: MCLK[1:0] */ - bool update; -}; - -enum dw9714_vcm_mode { - DW9714_DIRECT = 0x1, /* direct control */ - DW9714_LSC = 0x2, /* linear slope control */ - DW9714_DLC = 0x3, /* dual level control */ -}; - -/* dw9714 device structure */ -struct dw9714_device { - struct dw9714_vcm_settings vcm_settings; - struct timespec timestamp_t_focus_abs; - enum dw9714_vcm_mode vcm_mode; - s16 number_of_steps; - bool initialized; /* true if dw9714 is detected */ - s32 focus; /* Current focus value */ - struct timespec focus_time; /* Time when focus was last time set */ - __u8 buffer[4]; /* Used for i2c transactions */ - const struct camera_af_platform_data *platform_data; -}; - -#define DW9714_INVALID_CONFIG 0xffffffff -#define DW9714_MAX_FOCUS_POS 1023 -#define DW9714_DEFAULT_FOCUS_POS 290 - - -/* MCLK[1:0] = 01 T_SRC[4:0] = 00001 S[3:0] = 0111 */ -#define DELAY_PER_STEP_NS 1000000 -#define DELAY_MAX_PER_STEP_NS (1000000 * 1023) - -#define DLC_ENABLE 1 -#define DLC_DISABLE 0 -#define VCM_PROTECTION_OFF 0xeca3 -#define VCM_PROTECTION_ON 0xdc51 -#define VCM_DEFAULT_S 0x0 - -#define vcm_step_s(a) (u8)(a & 0xf) -#define vcm_step_mclk(a) (u8)((a >> 4) & 0x3) -#define vcm_dlc_mclk(dlc, mclk) (u16)((dlc << 3) | mclk | 0xa104) -#define vcm_tsrc(tsrc) (u16)(tsrc << 3 | 0xf200) -#define vcm_val(data, s) (u16)(data << 4 | s) -#define DIRECT_VCM vcm_dlc_mclk(0, 0) - -#endif diff --git a/drivers/staging/media/atomisp/i2c/imx/dw9718.c b/drivers/staging/media/atomisp/i2c/imx/dw9718.c deleted file mode 100644 index c02b9f0a2440..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/dw9718.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Support for dw9718 vcm driver. - * - * Copyright (c) 2014 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#include -#include "dw9718.h" - -static struct dw9718_device dw9718_dev; - -static int dw9718_i2c_rd8(struct i2c_client *client, u8 reg, u8 *val) -{ - struct i2c_msg msg[2]; - u8 buf[2] = { reg }; - - msg[0].addr = DW9718_VCM_ADDR; - msg[0].flags = 0; - msg[0].len = 1; - msg[0].buf = buf; - - msg[1].addr = DW9718_VCM_ADDR; - msg[1].flags = I2C_M_RD; - msg[1].len = 1; - msg[1].buf = &buf[1]; - *val = 0; - - if (i2c_transfer(client->adapter, msg, 2) != 2) - return -EIO; - *val = buf[1]; - - return 0; -} - -static int dw9718_i2c_wr8(struct i2c_client *client, u8 reg, u8 val) -{ - struct i2c_msg msg; - u8 buf[2] = { reg, val}; - - msg.addr = DW9718_VCM_ADDR; - msg.flags = 0; - msg.len = sizeof(buf); - msg.buf = buf; - - if (i2c_transfer(client->adapter, &msg, 1) != 1) - return -EIO; - - return 0; -} - -static int dw9718_i2c_wr16(struct i2c_client *client, u8 reg, u16 val) -{ - struct i2c_msg msg; - u8 buf[3] = { reg, (u8)(val >> 8), (u8)(val & 0xff)}; - - msg.addr = DW9718_VCM_ADDR; - msg.flags = 0; - msg.len = sizeof(buf); - msg.buf = buf; - - if (i2c_transfer(client->adapter, &msg, 1) != 1) - return -EIO; - - return 0; -} - -int dw9718_t_focus_abs(struct v4l2_subdev *sd, s32 value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - value = clamp(value, 0, DW9718_MAX_FOCUS_POS); - ret = dw9718_i2c_wr16(client, DW9718_DATA_M, value); - /*pr_info("%s: value = %d\n", __func__, value);*/ - if (ret < 0) - return ret; - - getnstimeofday(&dw9718_dev.focus_time); - dw9718_dev.focus = value; - - return 0; -} - -int dw9718_vcm_power_up(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u8 value; - - if (dw9718_dev.power_on) - return 0; - - /* Enable power */ - ret = dw9718_dev.platform_data->power_ctrl(sd, 1); - if (ret) { - dev_err(&client->dev, "DW9718_PD power_ctrl failed %d\n", ret); - return ret; - } - /* Wait for VBAT to stabilize */ - udelay(100); - - /* Detect device */ - ret = dw9718_i2c_rd8(client, DW9718_SACT, &value); - if (ret < 0) { - dev_err(&client->dev, "read DW9718_SACT failed %d\n", ret); - goto fail_powerdown; - } - /* - * WORKAROUND: for module P8V12F-203 which are used on - * Cherrytrail Refresh Davis Reef AoB, register SACT is not - * returning default value as spec. But VCM works as expected and - * root cause is still under discussion with vendor. - * workaround here to avoid aborting the power up sequence and just - * give a warning about this error. - */ - if (value != DW9718_SACT_DEFAULT_VAL) - dev_warn(&client->dev, "%s error, incorrect ID\n", __func__); - - /* Initialize according to recommended settings */ - ret = dw9718_i2c_wr8(client, DW9718_CONTROL, - DW9718_CONTROL_SW_LINEAR | - DW9718_CONTROL_S_SAC4 | - DW9718_CONTROL_OCP_DISABLE | - DW9718_CONTROL_UVLO_DISABLE); - if (ret < 0) { - dev_err(&client->dev, "write DW9718_CONTROL failed %d\n", ret); - goto fail_powerdown; - } - ret = dw9718_i2c_wr8(client, DW9718_SACT, - DW9718_SACT_MULT_TWO | - DW9718_SACT_PERIOD_8_8MS); - if (ret < 0) { - dev_err(&client->dev, "write DW9718_SACT failed %d\n", ret); - goto fail_powerdown; - } - - ret = dw9718_t_focus_abs(sd, dw9718_dev.focus); - if (ret) - return ret; - dw9718_dev.initialized = true; - dw9718_dev.power_on = 1; - - return 0; - -fail_powerdown: - dev_err(&client->dev, "%s error, powerup failed\n", __func__); - dw9718_dev.platform_data->power_ctrl(sd, 0); - return ret; -} - -int dw9718_vcm_power_down(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (!dw9718_dev.power_on) - return 0; - - ret = dw9718_dev.platform_data->power_ctrl(sd, 0); - if (ret) { - dev_err(&client->dev, "%s power_ctrl failed\n", - __func__); - return ret; - } - dw9718_dev.power_on = 0; - - return 0; -} - -int dw9718_q_focus_status(struct v4l2_subdev *sd, s32 *value) -{ - static const struct timespec move_time = { - .tv_sec = 0, - .tv_nsec = 60000000 - }; - struct timespec current_time, finish_time, delta_time; - - getnstimeofday(¤t_time); - finish_time = timespec_add(dw9718_dev.focus_time, move_time); - delta_time = timespec_sub(current_time, finish_time); - if (delta_time.tv_sec >= 0 && delta_time.tv_nsec >= 0) { - *value = ATOMISP_FOCUS_HP_COMPLETE | - ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE; - } else { - *value = ATOMISP_FOCUS_STATUS_MOVING | - ATOMISP_FOCUS_HP_IN_PROGRESS; - } - - return 0; -} - -int dw9718_t_focus_rel(struct v4l2_subdev *sd, s32 value) -{ - return dw9718_t_focus_abs(sd, dw9718_dev.focus + value); -} - -int dw9718_q_focus_abs(struct v4l2_subdev *sd, s32 *value) -{ - *value = dw9718_dev.focus; - return 0; -} -int dw9718_t_vcm_slew(struct v4l2_subdev *sd, s32 value) -{ - return 0; -} - -int dw9718_t_vcm_timing(struct v4l2_subdev *sd, s32 value) -{ - return 0; -} - -int dw9718_vcm_init(struct v4l2_subdev *sd) -{ - dw9718_dev.platform_data = camera_get_af_platform_data(); - dw9718_dev.focus = DW9718_DEFAULT_FOCUS_POSITION; - dw9718_dev.power_on = 0; - return (NULL == dw9718_dev.platform_data) ? -ENODEV : 0; -} diff --git a/drivers/staging/media/atomisp/i2c/imx/dw9718.h b/drivers/staging/media/atomisp/i2c/imx/dw9718.h deleted file mode 100644 index 4a1040c3149f..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/dw9718.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Support for dw9719 vcm driver. - * - * Copyright (c) 2014 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#ifndef __DW9718_H__ -#define __DW9718_H__ - -#include "../../include/linux/atomisp_platform.h" -#include - -#define DW9718_VCM_ADDR (0x18 >> 1) - -/* dw9718 device structure */ -struct dw9718_device { - struct timespec timestamp_t_focus_abs; - s16 number_of_steps; - bool initialized; /* true if dw9718 is detected */ - s32 focus; /* Current focus value */ - struct timespec focus_time; /* Time when focus was last time set */ - __u8 buffer[4]; /* Used for i2c transactions */ - const struct camera_af_platform_data *platform_data; - __u8 power_on; -}; - -#define DW9718_MAX_FOCUS_POS 1023 - -/* Register addresses */ -#define DW9718_PD 0x00 -#define DW9718_CONTROL 0x01 -#define DW9718_DATA_M 0x02 -#define DW9718_DATA_L 0x03 -#define DW9718_SW 0x04 -#define DW9718_SACT 0x05 -#define DW9718_FLAG 0x10 - -#define DW9718_CONTROL_SW_LINEAR BIT(0) -#define DW9718_CONTROL_S_SAC4 (BIT(1) | BIT(3)) -#define DW9718_CONTROL_OCP_DISABLE BIT(4) -#define DW9718_CONTROL_UVLO_DISABLE BIT(5) - -#define DW9718_SACT_MULT_TWO 0x00 -#define DW9718_SACT_PERIOD_8_8MS 0x19 -#define DW9718_SACT_DEFAULT_VAL 0x60 - -#define DW9718_DEFAULT_FOCUS_POSITION 300 - -#endif /* __DW9718_H__ */ diff --git a/drivers/staging/media/atomisp/i2c/imx/dw9719.c b/drivers/staging/media/atomisp/i2c/imx/dw9719.c deleted file mode 100644 index 565237796bb4..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/dw9719.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Support for dw9719 vcm driver. - * - * Copyright (c) 2012 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#include -#include "dw9719.h" - -static struct dw9719_device dw9719_dev; - -static int dw9719_i2c_rd8(struct i2c_client *client, u8 reg, u8 *val) -{ - struct i2c_msg msg[2]; - u8 buf[2] = { reg }; - - msg[0].addr = DW9719_VCM_ADDR; - msg[0].flags = 0; - msg[0].len = 1; - msg[0].buf = buf; - - msg[1].addr = DW9719_VCM_ADDR; - msg[1].flags = I2C_M_RD; - msg[1].len = 1; - msg[1].buf = &buf[1]; - *val = 0; - - if (i2c_transfer(client->adapter, msg, 2) != 2) - return -EIO; - *val = buf[1]; - - return 0; -} - -static int dw9719_i2c_wr8(struct i2c_client *client, u8 reg, u8 val) -{ - struct i2c_msg msg; - u8 buf[2] = { reg, val }; - - msg.addr = DW9719_VCM_ADDR; - msg.flags = 0; - msg.len = sizeof(buf); - msg.buf = buf; - - if (i2c_transfer(client->adapter, &msg, 1) != 1) - return -EIO; - - return 0; -} - -static int dw9719_i2c_wr16(struct i2c_client *client, u8 reg, u16 val) -{ - struct i2c_msg msg; - u8 buf[3] = { reg, (u8)(val >> 8), (u8)(val & 0xff)}; - - msg.addr = DW9719_VCM_ADDR; - msg.flags = 0; - msg.len = sizeof(buf); - msg.buf = buf; - - if (i2c_transfer(client->adapter, &msg, 1) != 1) - return -EIO; - - return 0; -} - -int dw9719_vcm_power_up(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u8 value; - - /* Enable power */ - ret = dw9719_dev.platform_data->power_ctrl(sd, 1); - /* waiting time requested by DW9714A(vcm) */ - if (ret) - return ret; - /* Wait for VBAT to stabilize */ - udelay(1); - - /* - * Jiggle SCL pin to wake up device. - */ - ret = dw9719_i2c_wr8(client, DW9719_CONTROL, 1); - /* Need 100us to transit from SHUTDOWN to STANDBY*/ - usleep_range(100, 1000); - - /* Enable the ringing compensation */ - ret = dw9719_i2c_wr8(client, DW9719_CONTROL, DW9719_ENABLE_RINGING); - if (ret < 0) - goto fail_powerdown; - - /* Use SAC3 mode */ - ret = dw9719_i2c_wr8(client, DW9719_MODE, DW9719_MODE_SAC3); - if (ret < 0) - goto fail_powerdown; - - /* Set the resonance frequency */ - ret = dw9719_i2c_wr8(client, DW9719_VCM_FREQ, DW9719_DEFAULT_VCM_FREQ); - if (ret < 0) - goto fail_powerdown; - - /* Detect device */ - ret = dw9719_i2c_rd8(client, DW9719_INFO, &value); - if (ret < 0) - goto fail_powerdown; - if (value != DW9719_ID) { - ret = -ENXIO; - goto fail_powerdown; - } - dw9719_dev.focus = 0; - dw9719_dev.initialized = true; - - return 0; - -fail_powerdown: - dw9719_dev.platform_data->power_ctrl(sd, 0); - return ret; -} - -int dw9719_vcm_power_down(struct v4l2_subdev *sd) -{ - return dw9719_dev.platform_data->power_ctrl(sd, 0); -} - -int dw9719_q_focus_status(struct v4l2_subdev *sd, s32 *value) -{ - static const struct timespec move_time = { - - .tv_sec = 0, - .tv_nsec = 60000000 - }; - struct timespec current_time, finish_time, delta_time; - - getnstimeofday(¤t_time); - finish_time = timespec_add(dw9719_dev.focus_time, move_time); - delta_time = timespec_sub(current_time, finish_time); - if (delta_time.tv_sec >= 0 && delta_time.tv_nsec >= 0) { - *value = ATOMISP_FOCUS_HP_COMPLETE | - ATOMISP_FOCUS_STATUS_ACCEPTS_NEW_MOVE; - } else { - *value = ATOMISP_FOCUS_STATUS_MOVING | - ATOMISP_FOCUS_HP_IN_PROGRESS; - } - - return 0; -} - -int dw9719_t_focus_abs(struct v4l2_subdev *sd, s32 value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - value = clamp(value, 0, DW9719_MAX_FOCUS_POS); - ret = dw9719_i2c_wr16(client, DW9719_VCM_CURRENT, value); - if (ret < 0) - return ret; - - getnstimeofday(&dw9719_dev.focus_time); - dw9719_dev.focus = value; - - return 0; -} - -int dw9719_t_focus_rel(struct v4l2_subdev *sd, s32 value) -{ - return dw9719_t_focus_abs(sd, dw9719_dev.focus + value); -} - -int dw9719_q_focus_abs(struct v4l2_subdev *sd, s32 *value) -{ - *value = dw9719_dev.focus; - return 0; -} -int dw9719_t_vcm_slew(struct v4l2_subdev *sd, s32 value) -{ - return 0; -} - -int dw9719_t_vcm_timing(struct v4l2_subdev *sd, s32 value) -{ - return 0; -} diff --git a/drivers/staging/media/atomisp/i2c/imx/dw9719.h b/drivers/staging/media/atomisp/i2c/imx/dw9719.h deleted file mode 100644 index 711f412aef2a..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/dw9719.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Support for dw9719 vcm driver. - * - * Copyright (c) 2012 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#ifndef __DW9719_H__ -#define __DW9719_H__ - -#include "../../include/linux/atomisp_platform.h" -#include - -#define DW9719_VCM_ADDR (0x18 >> 1) - -/* dw9719 device structure */ -struct dw9719_device { - struct timespec timestamp_t_focus_abs; - s16 number_of_steps; - bool initialized; /* true if dw9719 is detected */ - s32 focus; /* Current focus value */ - struct timespec focus_time; /* Time when focus was last time set */ - __u8 buffer[4]; /* Used for i2c transactions */ - const struct camera_af_platform_data *platform_data; -}; - -#define DW9719_INVALID_CONFIG 0xffffffff -#define DW9719_MAX_FOCUS_POS 1023 -#define DELAY_PER_STEP_NS 1000000 -#define DELAY_MAX_PER_STEP_NS (1000000 * 1023) - -#define DW9719_INFO 0 -#define DW9719_ID 0xF1 -#define DW9719_CONTROL 2 -#define DW9719_VCM_CURRENT 3 - -#define DW9719_MODE 6 -#define DW9719_VCM_FREQ 7 - -#define DW9719_MODE_SAC3 0x40 -#define DW9719_DEFAULT_VCM_FREQ 0x04 -#define DW9719_ENABLE_RINGING 0x02 - -#endif diff --git a/drivers/staging/media/atomisp/i2c/imx/imx.c b/drivers/staging/media/atomisp/i2c/imx/imx.c deleted file mode 100644 index 885a26cc158e..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/imx.c +++ /dev/null @@ -1,2477 +0,0 @@ -/* - * Support for Sony imx 8MP camera sensor. - * - * Copyright (c) 2012 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ -#include "../../include/linux/atomisp_platform.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../../include/linux/libmsrlisthelper.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "imx.h" - -/* - * The imx135 embedded data info: - * embedded data line num: 2 - * line 0 effective data size(byte): 76 - * line 1 effective data size(byte): 113 - */ -static const uint32_t - imx135_embedded_effective_size[IMX135_EMBEDDED_DATA_LINE_NUM] - = {76, 113}; - -static enum atomisp_bayer_order imx_bayer_order_mapping[] = { - atomisp_bayer_order_rggb, - atomisp_bayer_order_grbg, - atomisp_bayer_order_gbrg, - atomisp_bayer_order_bggr -}; - -static const unsigned int -IMX227_BRACKETING_LUT_FRAME_ENTRY[IMX_MAX_AE_LUT_LENGTH] = { - 0x0E10, 0x0E1E, 0x0E2C, 0x0E3A, 0x0E48}; - -static int -imx_read_reg(struct i2c_client *client, u16 len, u16 reg, u16 *val) -{ - struct i2c_msg msg[2]; - u16 data[IMX_SHORT_MAX]; - int ret, i; - int retry = 0; - - if (len > IMX_BYTE_MAX) { - dev_err(&client->dev, "%s error, invalid data length\n", - __func__); - return -EINVAL; - } - - do { - memset(msg, 0 , sizeof(msg)); - memset(data, 0 , sizeof(data)); - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = I2C_MSG_LENGTH; - msg[0].buf = (u8 *)data; - /* high byte goes first */ - data[0] = cpu_to_be16(reg); - - msg[1].addr = client->addr; - msg[1].len = len; - msg[1].flags = I2C_M_RD; - msg[1].buf = (u8 *)data; - - ret = i2c_transfer(client->adapter, msg, 2); - if (ret != 2) { - dev_err(&client->dev, - "retrying i2c read from offset 0x%x error %d... %d\n", - reg, ret, retry); - msleep(20); - } - } while (ret != 2 && retry++ < I2C_RETRY_COUNT); - - if (ret != 2) - return -EIO; - - /* high byte comes first */ - if (len == IMX_8BIT) { - *val = (u8)data[0]; - } else { - /* 16-bit access is default when len > 1 */ - for (i = 0; i < (len >> 1); i++) - val[i] = be16_to_cpu(data[i]); - } - - return 0; -} - -static int imx_i2c_write(struct i2c_client *client, u16 len, u8 *data) -{ - struct i2c_msg msg; - int ret; - int retry = 0; - - do { - msg.addr = client->addr; - msg.flags = 0; - msg.len = len; - msg.buf = data; - - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret != 1) { - dev_err(&client->dev, - "retrying i2c write transfer... %d\n", retry); - msleep(20); - } - } while (ret != 1 && retry++ < I2C_RETRY_COUNT); - - return ret == 1 ? 0 : -EIO; -} - -int -imx_write_reg(struct i2c_client *client, u16 data_length, u16 reg, u16 val) -{ - int ret; - unsigned char data[4] = {0}; - u16 *wreg = (u16 *)data; - const u16 len = data_length + sizeof(u16); /* 16-bit address + data */ - - if (data_length != IMX_8BIT && data_length != IMX_16BIT) { - v4l2_err(client, "%s error, invalid data_length\n", __func__); - return -EINVAL; - } - - /* high byte goes out first */ - *wreg = cpu_to_be16(reg); - - if (data_length == IMX_8BIT) - data[2] = (u8)(val); - else { - /* IMX_16BIT */ - u16 *wdata = (u16 *)&data[2]; - *wdata = cpu_to_be16(val); - } - - ret = imx_i2c_write(client, len, data); - if (ret) - dev_err(&client->dev, - "write error: wrote 0x%x to offset 0x%x error %d", - val, reg, ret); - - return ret; -} - -/* - * imx_write_reg_array - Initializes a list of imx registers - * @client: i2c driver client structure - * @reglist: list of registers to be written - * - * This function initializes a list of registers. When consecutive addresses - * are found in a row on the list, this function creates a buffer and sends - * consecutive data in a single i2c_transfer(). - * - * __imx_flush_reg_array, __imx_buf_reg_array() and - * __imx_write_reg_is_consecutive() are internal functions to - * imx_write_reg_array_fast() and should be not used anywhere else. - * - */ - -static int __imx_flush_reg_array(struct i2c_client *client, - struct imx_write_ctrl *ctrl) -{ - u16 size; - - if (ctrl->index == 0) - return 0; - - size = sizeof(u16) + ctrl->index; /* 16-bit address + data */ - ctrl->buffer.addr = cpu_to_be16(ctrl->buffer.addr); - ctrl->index = 0; - - return imx_i2c_write(client, size, (u8 *)&ctrl->buffer); -} - -static int __imx_buf_reg_array(struct i2c_client *client, - struct imx_write_ctrl *ctrl, - const struct imx_reg *next) -{ - int size; - u16 *data16; - - switch (next->type) { - case IMX_8BIT: - size = 1; - ctrl->buffer.data[ctrl->index] = (u8)next->val; - break; - case IMX_16BIT: - size = 2; - data16 = (u16 *)&ctrl->buffer.data[ctrl->index]; - *data16 = cpu_to_be16((u16)next->val); - break; - default: - return -EINVAL; - } - - /* When first item is added, we need to store its starting address */ - if (ctrl->index == 0) - ctrl->buffer.addr = next->sreg; - - ctrl->index += size; - - /* - * Buffer cannot guarantee free space for u32? Better flush it to avoid - * possible lack of memory for next item. - */ - if (ctrl->index + sizeof(u16) >= IMX_MAX_WRITE_BUF_SIZE) - return __imx_flush_reg_array(client, ctrl); - - return 0; -} - -static int -__imx_write_reg_is_consecutive(struct i2c_client *client, - struct imx_write_ctrl *ctrl, - const struct imx_reg *next) -{ - if (ctrl->index == 0) - return 1; - - return ctrl->buffer.addr + ctrl->index == next->sreg; -} - -static int imx_write_reg_array(struct i2c_client *client, - const struct imx_reg *reglist) -{ - const struct imx_reg *next = reglist; - struct imx_write_ctrl ctrl; - int err; - - ctrl.index = 0; - for (; next->type != IMX_TOK_TERM; next++) { - switch (next->type & IMX_TOK_MASK) { - case IMX_TOK_DELAY: - err = __imx_flush_reg_array(client, &ctrl); - if (err) - return err; - msleep(next->val); - break; - - default: - /* - * If next address is not consecutive, data needs to be - * flushed before proceed. - */ - if (!__imx_write_reg_is_consecutive(client, &ctrl, - next)) { - err = __imx_flush_reg_array(client, &ctrl); - if (err) - return err; - } - err = __imx_buf_reg_array(client, &ctrl, next); - if (err) { - v4l2_err(client, "%s: write error, aborted\n", - __func__); - return err; - } - break; - } - } - - return __imx_flush_reg_array(client, &ctrl); -} - -static int __imx_min_fps_diff(int fps, const struct imx_fps_setting *fps_list) -{ - int diff = INT_MAX; - int i; - - if (fps == 0) - return 0; - - for (i = 0; i < MAX_FPS_OPTIONS_SUPPORTED; i++) { - if (!fps_list[i].fps) - break; - if (abs(fps_list[i].fps - fps) < diff) - diff = abs(fps_list[i].fps - fps); - } - - return diff; -} - -static int __imx_nearest_fps_index(int fps, - const struct imx_fps_setting *fps_list) -{ - int fps_index = 0; - int i; - - for (i = 0; i < MAX_FPS_OPTIONS_SUPPORTED; i++) { - if (!fps_list[i].fps) - break; - if (abs(fps_list[i].fps - fps) - < abs(fps_list[fps_index].fps - fps)) - fps_index = i; - } - return fps_index; -} - -/* - * This is to choose the nearest fps setting above the requested fps - * fps_list should be in ascendant order. - */ -static int __imx_above_nearest_fps_index(int fps, - const struct imx_fps_setting *fps_list) -{ - int fps_index = 0; - int i; - - for (i = 0; i < MAX_FPS_OPTIONS_SUPPORTED; i++) { - if (!fps_list[i].fps) - break; - if (fps <= fps_list[i].fps) { - fps_index = i; - break; - } - } - - return fps_index; -} - -static int imx_get_lanes(struct v4l2_subdev *sd) -{ - struct camera_mipi_info *imx_info = v4l2_get_subdev_hostdata(sd); - - if (!imx_info) - return -ENOSYS; - if (imx_info->num_lanes < 1 || imx_info->num_lanes > 4 || - imx_info->num_lanes == 3) - return -EINVAL; - - return imx_info->num_lanes; -} - -static int __imx_update_exposure_timing(struct i2c_client *client, u16 exposure, - u16 llp, u16 fll) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct imx_device *dev = to_imx_sensor(sd); - int ret = 0; - - if (dev->sensor_id != IMX227_ID) { - /* Increase the VTS to match exposure + margin */ - if (exposure > fll - IMX_INTEGRATION_TIME_MARGIN) - fll = exposure + IMX_INTEGRATION_TIME_MARGIN; - } - - ret = imx_write_reg(client, IMX_16BIT, - dev->reg_addr->line_length_pixels, llp); - if (ret) - return ret; - - ret = imx_write_reg(client, IMX_16BIT, - dev->reg_addr->frame_length_lines, fll); - if (ret) - return ret; - - if (exposure) - ret = imx_write_reg(client, IMX_16BIT, - dev->reg_addr->coarse_integration_time, exposure); - - return ret; -} - -static int __imx_update_gain(struct v4l2_subdev *sd, u16 gain) -{ - struct imx_device *dev = to_imx_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - /* set global gain */ - ret = imx_write_reg(client, IMX_8BIT, dev->reg_addr->global_gain, gain); - if (ret) - return ret; - - /* set short analog gain */ - if (dev->sensor_id == IMX135_ID) - ret = imx_write_reg(client, IMX_8BIT, IMX_SHORT_AGC_GAIN, gain); - - return ret; -} - -static int __imx_update_digital_gain(struct i2c_client *client, u16 digitgain) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct imx_device *dev = to_imx_sensor(sd); - struct imx_write_buffer digit_gain; - - digit_gain.addr = cpu_to_be16(dev->reg_addr->dgc_adj); - digit_gain.data[0] = (digitgain >> 8) & 0xFF; - digit_gain.data[1] = digitgain & 0xFF; - - if (dev->sensor_id == IMX219_ID) { - return imx_i2c_write(client, IMX219_DGC_LEN, (u8 *)&digit_gain); - } else if (dev->sensor_id == IMX227_ID) { - return imx_i2c_write(client, IMX227_DGC_LEN, (u8 *)&digit_gain); - } else { - digit_gain.data[2] = (digitgain >> 8) & 0xFF; - digit_gain.data[3] = digitgain & 0xFF; - digit_gain.data[4] = (digitgain >> 8) & 0xFF; - digit_gain.data[5] = digitgain & 0xFF; - digit_gain.data[6] = (digitgain >> 8) & 0xFF; - digit_gain.data[7] = digitgain & 0xFF; - return imx_i2c_write(client, IMX_DGC_LEN, (u8 *)&digit_gain); - } - return 0; -} - -static int imx_set_exposure_gain(struct v4l2_subdev *sd, u16 coarse_itg, - u16 gain, u16 digitgain) -{ - struct imx_device *dev = to_imx_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int lanes = imx_get_lanes(sd); - unsigned int digitgain_scaled; - int ret = 0; - - /* Validate exposure: cannot exceed VTS-4 where VTS is 16bit */ - coarse_itg = clamp_t(u16, coarse_itg, 0, IMX_MAX_EXPOSURE_SUPPORTED); - - /* Validate gain: must not exceed maximum 8bit value */ - gain = clamp_t(u16, gain, 0, IMX_MAX_GLOBAL_GAIN_SUPPORTED); - - mutex_lock(&dev->input_lock); - - if (dev->sensor_id == IMX227_ID) { - ret = imx_write_reg_array(client, imx_param_hold); - if (ret) { - mutex_unlock(&dev->input_lock); - return ret; - } - } - - /* For imx175, setting gain must be delayed by one */ - if ((dev->sensor_id == IMX175_ID) && dev->digital_gain) - digitgain_scaled = dev->digital_gain; - else - digitgain_scaled = digitgain; - /* imx132 with two lanes needs more gain to saturate at max */ - if (dev->sensor_id == IMX132_ID && lanes > 1) { - digitgain_scaled *= IMX132_2LANES_GAINFACT; - digitgain_scaled >>= IMX132_2LANES_GAINFACT_SHIFT; - } - /* Validate digital gain: must not exceed 12 bit value*/ - digitgain_scaled = clamp_t(unsigned int, digitgain_scaled, - 0, IMX_MAX_DIGITAL_GAIN_SUPPORTED); - - ret = __imx_update_exposure_timing(client, coarse_itg, - dev->pixels_per_line, dev->lines_per_frame); - if (ret) - goto out; - dev->coarse_itg = coarse_itg; - - if (dev->sensor_id == IMX175_ID) - ret = __imx_update_gain(sd, dev->gain); - else - ret = __imx_update_gain(sd, gain); - if (ret) - goto out; - dev->gain = gain; - - ret = __imx_update_digital_gain(client, digitgain_scaled); - if (ret) - goto out; - dev->digital_gain = digitgain; - -out: - if (dev->sensor_id == IMX227_ID) - ret = imx_write_reg_array(client, imx_param_update); - mutex_unlock(&dev->input_lock); - return ret; -} - -static long imx_s_exposure(struct v4l2_subdev *sd, - struct atomisp_exposure *exposure) -{ - return imx_set_exposure_gain(sd, exposure->integration_time[0], - exposure->gain[0], exposure->gain[1]); -} - -/* FIXME -To be updated with real OTP reading */ -static int imx_g_priv_int_data(struct v4l2_subdev *sd, - struct v4l2_private_int_data *priv) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct imx_device *dev = to_imx_sensor(sd); - u8 __user *to = priv->data; - u32 read_size = priv->size; - int ret; - - /* No need to copy data if size is 0 */ - if (!read_size) - goto out; - - if (IS_ERR(dev->otp_data)) { - dev_err(&client->dev, "OTP data not available"); - return PTR_ERR(dev->otp_data); - } - /* Correct read_size value only if bigger than maximum */ - if (read_size > dev->otp_driver->size) - read_size = dev->otp_driver->size; - - ret = copy_to_user(to, dev->otp_data, read_size); - if (ret) { - dev_err(&client->dev, "%s: failed to copy OTP data to user\n", - __func__); - return -EFAULT; - } -out: - /* Return correct size */ - priv->size = dev->otp_driver->size; - - return 0; -} - -static int __imx_init(struct v4l2_subdev *sd, u32 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct imx_device *dev = to_imx_sensor(sd); - int lanes = imx_get_lanes(sd); - int ret; - - if (dev->sensor_id == IMX_ID_DEFAULT) - return 0; - - /* The default is no flip at sensor initialization */ - dev->h_flip->cur.val = 0; - dev->v_flip->cur.val = 0; - /* Sets the default FPS */ - dev->fps_index = 0; - dev->curr_res_table = dev->mode_tables->res_preview; - dev->entries_curr_table = dev->mode_tables->n_res_preview; - - ret = imx_write_reg_array(client, dev->mode_tables->init_settings); - if (ret) - return ret; - - if (dev->sensor_id == IMX132_ID && lanes > 0) { - static const u8 imx132_rglanesel[] = { - IMX132_RGLANESEL_1LANE, /* 1 lane */ - IMX132_RGLANESEL_2LANES, /* 2 lanes */ - IMX132_RGLANESEL_1LANE, /* undefined */ - IMX132_RGLANESEL_4LANES, /* 4 lanes */ - }; - ret = imx_write_reg(client, IMX_8BIT, - IMX132_RGLANESEL, imx132_rglanesel[lanes - 1]); - } - - return ret; -} - -static int imx_init(struct v4l2_subdev *sd, u32 val) -{ - struct imx_device *dev = to_imx_sensor(sd); - int ret = 0; - - mutex_lock(&dev->input_lock); - ret = __imx_init(sd, val); - mutex_unlock(&dev->input_lock); - - return ret; -} - -static long imx_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - - switch (cmd) { - case ATOMISP_IOC_S_EXPOSURE: - return imx_s_exposure(sd, arg); - case ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA: - return imx_g_priv_int_data(sd, arg); - default: - return -EINVAL; - } - return 0; -} - -static int power_up(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct imx_device *dev = to_imx_sensor(sd); - int ret; - - /* power control */ - ret = dev->platform_data->power_ctrl(sd, 1); - if (ret) - goto fail_power; - - /* flis clock control */ - ret = dev->platform_data->flisclk_ctrl(sd, 1); - if (ret) - goto fail_clk; - - /* gpio ctrl */ - ret = dev->platform_data->gpio_ctrl(sd, 1); - if (ret) { - dev_err(&client->dev, "gpio failed\n"); - goto fail_gpio; - } - - return 0; -fail_gpio: - dev->platform_data->gpio_ctrl(sd, 0); -fail_clk: - dev->platform_data->flisclk_ctrl(sd, 0); -fail_power: - dev->platform_data->power_ctrl(sd, 0); - dev_err(&client->dev, "sensor power-up failed\n"); - - return ret; -} - -static int power_down(struct v4l2_subdev *sd) -{ - struct imx_device *dev = to_imx_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - ret = dev->platform_data->flisclk_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "flisclk failed\n"); - - /* gpio ctrl */ - ret = dev->platform_data->gpio_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "gpio failed\n"); - - /* power control */ - ret = dev->platform_data->power_ctrl(sd, 0); - if (ret) - dev_err(&client->dev, "vprog failed.\n"); - - return ret; -} - -static int __imx_s_power(struct v4l2_subdev *sd, int on) -{ - struct imx_device *dev = to_imx_sensor(sd); - int ret = 0; - int r = 0; - - if (on == 0) { - ret = power_down(sd); - if (dev->vcm_driver && dev->vcm_driver->power_down) - r = dev->vcm_driver->power_down(sd); - if (ret == 0) - ret = r; - dev->power = 0; - } else { - if (dev->vcm_driver && dev->vcm_driver->power_up) - ret = dev->vcm_driver->power_up(sd); - if (ret) - return ret; - ret = power_up(sd); - if (!ret) { - dev->power = 1; - return __imx_init(sd, 0); - } - } - - return ret; -} - -static int imx_s_power(struct v4l2_subdev *sd, int on) -{ - int ret; - struct imx_device *dev = to_imx_sensor(sd); - - mutex_lock(&dev->input_lock); - ret = __imx_s_power(sd, on); - mutex_unlock(&dev->input_lock); - - return ret; -} - -static int imx_get_intg_factor(struct i2c_client *client, - struct camera_mipi_info *info, - const struct imx_reg *reglist) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct imx_device *dev = to_imx_sensor(sd); - int lanes = imx_get_lanes(sd); - u32 vt_pix_clk_div; - u32 vt_sys_clk_div; - u32 pre_pll_clk_div; - u32 pll_multiplier; - - const int ext_clk_freq_hz = 19200000; - struct atomisp_sensor_mode_data *buf = &info->data; - int ret; - u16 data[IMX_INTG_BUF_COUNT]; - - u32 vt_pix_clk_freq_mhz; - u32 coarse_integration_time_min; - u32 coarse_integration_time_max_margin; - u32 read_mode; - u32 div; - - if (info == NULL) - return -EINVAL; - - memset(data, 0, IMX_INTG_BUF_COUNT * sizeof(u16)); - ret = imx_read_reg(client, 1, IMX_VT_PIX_CLK_DIV, data); - if (ret) - return ret; - vt_pix_clk_div = data[0] & IMX_MASK_5BIT; - - if (dev->sensor_id == IMX132_ID || dev->sensor_id == IMX208_ID) { - static const int rgpltd[] = { 2, 4, 1, 1 }; - ret = imx_read_reg(client, 1, IMX132_208_VT_RGPLTD, data); - if (ret) - return ret; - vt_sys_clk_div = rgpltd[data[0] & IMX_MASK_2BIT]; - } else { - ret = imx_read_reg(client, 1, IMX_VT_SYS_CLK_DIV, data); - if (ret) - return ret; - vt_sys_clk_div = data[0] & IMX_MASK_2BIT; - } - ret = imx_read_reg(client, 1, IMX_PRE_PLL_CLK_DIV, data); - if (ret) - return ret; - pre_pll_clk_div = data[0] & IMX_MASK_4BIT; - - ret = imx_read_reg(client, 2, - (dev->sensor_id == IMX132_ID || - dev->sensor_id == IMX219_ID || - dev->sensor_id == IMX208_ID) ? - IMX132_208_219_PLL_MULTIPLIER : IMX_PLL_MULTIPLIER, data); - if (ret) - return ret; - pll_multiplier = data[0] & IMX_MASK_11BIT; - - memset(data, 0, IMX_INTG_BUF_COUNT * sizeof(u16)); - ret = imx_read_reg(client, 4, IMX_COARSE_INTG_TIME_MIN, data); - if (ret) - return ret; - coarse_integration_time_min = data[0]; - coarse_integration_time_max_margin = data[1]; - - /* Get the cropping and output resolution to ISP for this mode. */ - ret = imx_read_reg(client, 2, dev->reg_addr->horizontal_start_h, data); - if (ret) - return ret; - buf->crop_horizontal_start = data[0]; - - ret = imx_read_reg(client, 2, dev->reg_addr->vertical_start_h, data); - if (ret) - return ret; - buf->crop_vertical_start = data[0]; - - ret = imx_read_reg(client, 2, dev->reg_addr->horizontal_end_h, data); - if (ret) - return ret; - buf->crop_horizontal_end = data[0]; - - ret = imx_read_reg(client, 2, dev->reg_addr->vertical_end_h, data); - if (ret) - return ret; - buf->crop_vertical_end = data[0]; - - ret = imx_read_reg(client, 2, - dev->reg_addr->horizontal_output_size_h, data); - if (ret) - return ret; - buf->output_width = data[0]; - - ret = imx_read_reg(client, 2, - dev->reg_addr->vertical_output_size_h, data); - if (ret) - return ret; - buf->output_height = data[0]; - - memset(data, 0, IMX_INTG_BUF_COUNT * sizeof(u16)); - if (dev->sensor_id == IMX132_ID || dev->sensor_id == IMX208_ID || - dev->sensor_id == IMX219_ID) - read_mode = 0; - else { - if (dev->sensor_id == IMX227_ID) - ret = imx_read_reg(client, 1, IMX227_READ_MODE, data); - else - ret = imx_read_reg(client, 1, IMX_READ_MODE, data); - - if (ret) - return ret; - read_mode = data[0] & IMX_MASK_2BIT; - } - - div = pre_pll_clk_div*vt_sys_clk_div*vt_pix_clk_div; - if (div == 0) - return -EINVAL; - - if (dev->sensor_id == IMX132_ID || dev->sensor_id == IMX208_ID) - vt_pix_clk_freq_mhz = ext_clk_freq_hz / div; - else if (dev->sensor_id == IMX227_ID) { - /* according to IMX227 datasheet: - * vt_pix_freq_mhz = * num_of_vt_lanes(4) * ivt_pix_clk_freq_mhz - */ - vt_pix_clk_freq_mhz = - (u64)4 * ext_clk_freq_hz * pll_multiplier; - do_div(vt_pix_clk_freq_mhz, div); - } else - vt_pix_clk_freq_mhz = 2 * ext_clk_freq_hz / div; - - vt_pix_clk_freq_mhz *= pll_multiplier; - if (dev->sensor_id == IMX132_ID && lanes > 0) - vt_pix_clk_freq_mhz *= lanes; - - dev->vt_pix_clk_freq_mhz = vt_pix_clk_freq_mhz; - - buf->vt_pix_clk_freq_mhz = vt_pix_clk_freq_mhz; - buf->coarse_integration_time_min = coarse_integration_time_min; - buf->coarse_integration_time_max_margin = - coarse_integration_time_max_margin; - - buf->fine_integration_time_min = IMX_FINE_INTG_TIME; - buf->fine_integration_time_max_margin = IMX_FINE_INTG_TIME; - buf->fine_integration_time_def = IMX_FINE_INTG_TIME; - buf->frame_length_lines = dev->lines_per_frame; - buf->line_length_pck = dev->pixels_per_line; - buf->read_mode = read_mode; - - if (dev->sensor_id == IMX132_ID || dev->sensor_id == IMX208_ID || - dev->sensor_id == IMX219_ID) { - buf->binning_factor_x = 1; - buf->binning_factor_y = 1; - } else { - if (dev->sensor_id == IMX227_ID) - ret = imx_read_reg(client, 1, IMX227_BINNING_ENABLE, - data); - else - ret = imx_read_reg(client, 1, IMX_BINNING_ENABLE, data); - - if (ret) - return ret; - /* 1:binning enabled, 0:disabled */ - if (data[0] == 1) { - if (dev->sensor_id == IMX227_ID) - ret = imx_read_reg(client, 1, - IMX227_BINNING_TYPE, data); - else - ret = imx_read_reg(client, 1, - IMX_BINNING_TYPE, data); - - if (ret) - return ret; - buf->binning_factor_x = data[0] >> 4 & 0x0f; - if (!buf->binning_factor_x) - buf->binning_factor_x = 1; - buf->binning_factor_y = data[0] & 0xf; - if (!buf->binning_factor_y) - buf->binning_factor_y = 1; - /* WOWRKAROUND, NHD setting for IMX227 should have 4x4 - * binning but the register setting does not reflect - * this, I am asking vendor why this happens. this is - * workaround for INTEL BZ 216560. - */ - if (dev->sensor_id == IMX227_ID) { - if (dev->curr_res_table[dev->fmt_idx].width == - 376 && - dev->curr_res_table[dev->fmt_idx].height == - 656) { - buf->binning_factor_x = 4; - buf->binning_factor_y = 4; - } - } - } else { - buf->binning_factor_x = 1; - buf->binning_factor_y = 1; - } - } - - return 0; -} - -/* This returns the exposure time being used. This should only be used - for filling in EXIF data, not for actual image processing. */ -static int imx_q_exposure(struct v4l2_subdev *sd, s32 *value) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct imx_device *dev = to_imx_sensor(sd); - u16 coarse; - int ret; - - /* the fine integration time is currently not calculated */ - ret = imx_read_reg(client, IMX_16BIT, - dev->reg_addr->coarse_integration_time, &coarse); - *value = coarse; - - return ret; -} - -static int imx_test_pattern(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct imx_device *dev = to_imx_sensor(sd); - int ret; - - if (dev->power == 0) - return 0; - - ret = imx_write_reg(client, IMX_16BIT, IMX_TEST_PATTERN_COLOR_R, - (u16)(dev->tp_r->val >> 22)); - if (ret) - return ret; - - ret = imx_write_reg(client, IMX_16BIT, IMX_TEST_PATTERN_COLOR_GR, - (u16)(dev->tp_gr->val >> 22)); - if (ret) - return ret; - - ret = imx_write_reg(client, IMX_16BIT, IMX_TEST_PATTERN_COLOR_GB, - (u16)(dev->tp_gb->val >> 22)); - if (ret) - return ret; - - ret = imx_write_reg(client, IMX_16BIT, IMX_TEST_PATTERN_COLOR_B, - (u16)(dev->tp_b->val >> 22)); - if (ret) - return ret; - - return imx_write_reg(client, IMX_16BIT, IMX_TEST_PATTERN_MODE, - (u16)(dev->tp_mode->val)); -} - -static u32 imx_translate_bayer_order(enum atomisp_bayer_order code) -{ - switch (code) { - case atomisp_bayer_order_rggb: - return MEDIA_BUS_FMT_SRGGB10_1X10; - case atomisp_bayer_order_grbg: - return MEDIA_BUS_FMT_SGRBG10_1X10; - case atomisp_bayer_order_bggr: - return MEDIA_BUS_FMT_SBGGR10_1X10; - case atomisp_bayer_order_gbrg: - return MEDIA_BUS_FMT_SGBRG10_1X10; - } - return 0; -} - -static int imx_v_flip(struct v4l2_subdev *sd, s32 value) -{ - struct imx_device *dev = to_imx_sensor(sd); - struct camera_mipi_info *imx_info = NULL; - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u16 val; - - if (dev->power == 0) - return -EIO; - - ret = imx_write_reg_array(client, dev->param_hold); - if (ret) - return ret; - - ret = imx_read_reg(client, IMX_8BIT, - dev->reg_addr->img_orientation, &val); - if (ret) - return ret; - if (value) - val |= IMX_VFLIP_BIT; - else - val &= ~IMX_VFLIP_BIT; - - ret = imx_write_reg(client, IMX_8BIT, - dev->reg_addr->img_orientation, val); - if (ret) - return ret; - - imx_info = v4l2_get_subdev_hostdata(sd); - if (imx_info) { - val &= (IMX_VFLIP_BIT|IMX_HFLIP_BIT); - imx_info->raw_bayer_order = imx_bayer_order_mapping[val]; - dev->format.code = imx_translate_bayer_order( - imx_info->raw_bayer_order); - } - - return imx_write_reg_array(client, dev->param_update); -} - -static int imx_h_flip(struct v4l2_subdev *sd, s32 value) -{ - struct imx_device *dev = to_imx_sensor(sd); - struct camera_mipi_info *imx_info = NULL; - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u16 val; - - if (dev->power == 0) - return -EIO; - - ret = imx_write_reg_array(client, dev->param_hold); - if (ret) - return ret; - ret = imx_read_reg(client, IMX_8BIT, - dev->reg_addr->img_orientation, &val); - if (ret) - return ret; - if (value) - val |= IMX_HFLIP_BIT; - else - val &= ~IMX_HFLIP_BIT; - ret = imx_write_reg(client, IMX_8BIT, - dev->reg_addr->img_orientation, val); - if (ret) - return ret; - - imx_info = v4l2_get_subdev_hostdata(sd); - if (imx_info) { - val &= (IMX_VFLIP_BIT|IMX_HFLIP_BIT); - imx_info->raw_bayer_order = imx_bayer_order_mapping[val]; - dev->format.code = imx_translate_bayer_order( - imx_info->raw_bayer_order); - } - - return imx_write_reg_array(client, dev->param_update); -} - -static int imx_g_focal(struct v4l2_subdev *sd, s32 *val) -{ - *val = (IMX_FOCAL_LENGTH_NUM << 16) | IMX_FOCAL_LENGTH_DEM; - return 0; -} - -static int imx_g_fnumber(struct v4l2_subdev *sd, s32 *val) -{ - /*const f number for imx*/ - *val = (IMX_F_NUMBER_DEFAULT_NUM << 16) | IMX_F_NUMBER_DEM; - return 0; -} - -static int imx_g_fnumber_range(struct v4l2_subdev *sd, s32 *val) -{ - *val = (IMX_F_NUMBER_DEFAULT_NUM << 24) | - (IMX_F_NUMBER_DEM << 16) | - (IMX_F_NUMBER_DEFAULT_NUM << 8) | IMX_F_NUMBER_DEM; - return 0; -} - -static int imx_g_bin_factor_x(struct v4l2_subdev *sd, s32 *val) -{ - struct imx_device *dev = to_imx_sensor(sd); - - *val = dev->curr_res_table[dev->fmt_idx].bin_factor_x; - - return 0; -} - -static int imx_g_bin_factor_y(struct v4l2_subdev *sd, s32 *val) -{ - struct imx_device *dev = to_imx_sensor(sd); - - *val = dev->curr_res_table[dev->fmt_idx].bin_factor_y; - - return 0; -} - -static int imx_t_focus_abs(struct v4l2_subdev *sd, s32 value) -{ - struct imx_device *dev = to_imx_sensor(sd); - if (dev->vcm_driver && dev->vcm_driver->t_focus_abs) - return dev->vcm_driver->t_focus_abs(sd, value); - return 0; -} - -static int imx_t_focus_rel(struct v4l2_subdev *sd, s32 value) -{ - struct imx_device *dev = to_imx_sensor(sd); - if (dev->vcm_driver && dev->vcm_driver->t_focus_rel) - return dev->vcm_driver->t_focus_rel(sd, value); - return 0; -} - -static int imx_q_focus_status(struct v4l2_subdev *sd, s32 *value) -{ - struct imx_device *dev = to_imx_sensor(sd); - if (dev->vcm_driver && dev->vcm_driver->q_focus_status) - return dev->vcm_driver->q_focus_status(sd, value); - return 0; -} - -static int imx_q_focus_abs(struct v4l2_subdev *sd, s32 *value) -{ - struct imx_device *dev = to_imx_sensor(sd); - if (dev->vcm_driver && dev->vcm_driver->q_focus_abs) - return dev->vcm_driver->q_focus_abs(sd, value); - return 0; -} - -static int imx_t_vcm_slew(struct v4l2_subdev *sd, s32 value) -{ - struct imx_device *dev = to_imx_sensor(sd); - if (dev->vcm_driver && dev->vcm_driver->t_vcm_slew) - return dev->vcm_driver->t_vcm_slew(sd, value); - return 0; -} - -static int imx_t_vcm_timing(struct v4l2_subdev *sd, s32 value) -{ - struct imx_device *dev = to_imx_sensor(sd); - if (dev->vcm_driver && dev->vcm_driver->t_vcm_timing) - return dev->vcm_driver->t_vcm_timing(sd, value); - return 0; -} - -static int imx_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct imx_device *dev = container_of( - ctrl->handler, struct imx_device, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); - int ret = 0; - - switch (ctrl->id) { - case V4L2_CID_TEST_PATTERN: - ret = imx_test_pattern(&dev->sd); - break; - case V4L2_CID_VFLIP: - dev_dbg(&client->dev, "%s: CID_VFLIP:%d.\n", - __func__, ctrl->val); - ret = imx_v_flip(&dev->sd, ctrl->val); - break; - case V4L2_CID_HFLIP: - dev_dbg(&client->dev, "%s: CID_HFLIP:%d.\n", - __func__, ctrl->val); - ret = imx_h_flip(&dev->sd, ctrl->val); - break; - case V4L2_CID_FOCUS_ABSOLUTE: - ret = imx_t_focus_abs(&dev->sd, ctrl->val); - break; - case V4L2_CID_FOCUS_RELATIVE: - ret = imx_t_focus_rel(&dev->sd, ctrl->val); - break; - case V4L2_CID_VCM_SLEW: - ret = imx_t_vcm_slew(&dev->sd, ctrl->val); - break; - case V4L2_CID_VCM_TIMEING: - ret = imx_t_vcm_timing(&dev->sd, ctrl->val); - break; - } - - return ret; -} - -static int imx_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct imx_device *dev = container_of( - ctrl->handler, struct imx_device, ctrl_handler); - int ret = 0; - unsigned int val; - - switch (ctrl->id) { - case V4L2_CID_EXPOSURE_ABSOLUTE: - ret = imx_q_exposure(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCUS_ABSOLUTE: - ret = imx_q_focus_abs(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCUS_STATUS: - ret = imx_q_focus_status(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FOCAL_ABSOLUTE: - ret = imx_g_focal(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_ABSOLUTE: - ret = imx_g_fnumber(&dev->sd, &ctrl->val); - break; - case V4L2_CID_FNUMBER_RANGE: - ret = imx_g_fnumber_range(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_HORZ: - ret = imx_g_bin_factor_x(&dev->sd, &ctrl->val); - break; - case V4L2_CID_BIN_FACTOR_VERT: - ret = imx_g_bin_factor_y(&dev->sd, &ctrl->val); - break; - case V4L2_CID_VBLANK: - ctrl->val = dev->lines_per_frame - - dev->curr_res_table[dev->fmt_idx].height; - break; - case V4L2_CID_HBLANK: - ctrl->val = dev->pixels_per_line - - dev->curr_res_table[dev->fmt_idx].width; - break; - case V4L2_CID_PIXEL_RATE: - ctrl->val = dev->vt_pix_clk_freq_mhz; - break; - case V4L2_CID_LINK_FREQ: - val = dev->curr_res_table[dev->fmt_idx]. - fps_options[dev->fps_index].mipi_freq; - if (val == 0) - val = dev->curr_res_table[dev->fmt_idx].mipi_freq; - if (val == 0) - return -EINVAL; - ctrl->val = val * 1000; /* To Hz */ - break; - default: - return -EINVAL; - } - - return ret; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .s_ctrl = imx_s_ctrl, - .g_volatile_ctrl = imx_g_volatile_ctrl -}; - -static const struct v4l2_ctrl_config imx_controls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .min = 0x0, - .max = 0xffff, - .step = 0x01, - .def = 0x00, - .flags = V4L2_CTRL_FLAG_VOLATILE, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_TEST_PATTERN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Test pattern", - .min = 0, - .max = 0xffff, - .step = 1, - .def = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_TEST_PATTERN_COLOR_R, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Test pattern solid color R", - .min = INT_MIN, - .max = INT_MAX, - .step = 1, - .def = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_TEST_PATTERN_COLOR_GR, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Test pattern solid color GR", - .min = INT_MIN, - .max = INT_MAX, - .step = 1, - .def = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_TEST_PATTERN_COLOR_GB, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Test pattern solid color GB", - .min = INT_MIN, - .max = INT_MAX, - .step = 1, - .def = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_TEST_PATTERN_COLOR_B, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Test pattern solid color B", - .min = INT_MIN, - .max = INT_MAX, - .step = 1, - .def = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Flip", - .min = 0, - .max = 1, - .step = 1, - .def = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror", - .min = 0, - .max = 1, - .step = 1, - .def = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCUS_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focus move absolute", - .min = 0, - .max = IMX_MAX_FOCUS_POS, - .step = 1, - .def = 0, - .flags = V4L2_CTRL_FLAG_VOLATILE, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCUS_RELATIVE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focus move relative", - .min = IMX_MAX_FOCUS_NEG, - .max = IMX_MAX_FOCUS_POS, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCUS_STATUS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focus status", - .min = 0, - .max = 100, /* allow enum to grow in the future */ - .step = 1, - .def = 0, - .flags = V4L2_CTRL_FLAG_VOLATILE, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_VCM_SLEW, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vcm slew", - .min = 0, - .max = IMX_VCM_SLEW_STEP_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_VCM_TIMEING, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vcm step time", - .min = 0, - .max = IMX_VCM_SLEW_TIME_MAX, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FOCAL_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "focal length", - .min = IMX_FOCAL_LENGTH_DEFAULT, - .max = IMX_FOCAL_LENGTH_DEFAULT, - .step = 0x01, - .def = IMX_FOCAL_LENGTH_DEFAULT, - .flags = V4L2_CTRL_FLAG_VOLATILE, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_ABSOLUTE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number", - .min = IMX_F_NUMBER_DEFAULT, - .max = IMX_F_NUMBER_DEFAULT, - .step = 0x01, - .def = IMX_F_NUMBER_DEFAULT, - .flags = V4L2_CTRL_FLAG_VOLATILE, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_FNUMBER_RANGE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "f-number range", - .min = IMX_F_NUMBER_RANGE, - .max = IMX_F_NUMBER_RANGE, - .step = 0x01, - .def = IMX_F_NUMBER_RANGE, - .flags = V4L2_CTRL_FLAG_VOLATILE, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_HORZ, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "horizontal binning factor", - .min = 0, - .max = IMX_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = V4L2_CTRL_FLAG_VOLATILE, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_BIN_FACTOR_VERT, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "vertical binning factor", - .min = 0, - .max = IMX_BIN_FACTOR_MAX, - .step = 1, - .def = 0, - .flags = V4L2_CTRL_FLAG_VOLATILE, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_LINK_FREQ, - .name = "Link Frequency", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 1, - .max = 1500000 * 1000, - .step = 1, - .def = 1, - .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_PIXEL_RATE, - .name = "Pixel Rate", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = INT_MAX, - .step = 1, - .def = 0, - .flags = V4L2_CTRL_FLAG_VOLATILE, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_HBLANK, - .name = "Horizontal Blanking", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = SHRT_MAX, - .step = 1, - .def = 0, - .flags = V4L2_CTRL_FLAG_VOLATILE, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_VBLANK, - .name = "Vertical Blanking", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = SHRT_MAX, - .step = 1, - .def = 0, - .flags = V4L2_CTRL_FLAG_VOLATILE, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_HFLIP, - .name = "Horizontal Flip", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = 1, - .step = 1, - .def = 0, - .flags = 0, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_VFLIP, - .name = "Vertical Flip", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = 1, - .step = 1, - .def = 0, - .flags = 0, - }, -}; - -/* - * distance - calculate the distance - * @res: resolution - * @w: width - * @h: height - * - * Get the gap between resolution and w/h. - * res->width/height smaller than w/h wouldn't be considered. - * Returns the value of gap or -1 if fail. - */ -#define LARGEST_ALLOWED_RATIO_MISMATCH 600 -static int distance(struct imx_resolution const *res, u32 w, u32 h, - bool keep_ratio) -{ - unsigned int w_ratio; - unsigned int h_ratio; - int match; - unsigned int allowed_ratio_mismatch = LARGEST_ALLOWED_RATIO_MISMATCH; - - if (!keep_ratio) - allowed_ratio_mismatch = ~0; - - if (w == 0) - return -1; - w_ratio = (res->width << 13) / w; - if (h == 0) - return -1; - h_ratio = (res->height << 13) / h; - if (h_ratio == 0) - return -1; - match = abs(((w_ratio << 13) / h_ratio) - ((int)8192)); - - if ((w_ratio < (int)8192) || (h_ratio < (int)8192) || - (match > allowed_ratio_mismatch)) - return -1; - - return w_ratio + h_ratio; -} - -/* Return the nearest higher resolution index */ -static int nearest_resolution_index(struct v4l2_subdev *sd, int w, int h) -{ - int i; - int idx = -1; - int dist; - int fps_diff; - int min_fps_diff = INT_MAX; - int min_dist = INT_MAX; - const struct imx_resolution *tmp_res = NULL; - struct imx_device *dev = to_imx_sensor(sd); - bool again = 1; -retry: - for (i = 0; i < dev->entries_curr_table; i++) { - tmp_res = &dev->curr_res_table[i]; - dist = distance(tmp_res, w, h, again); - if (dist == -1) - continue; - if (dist < min_dist) { - min_dist = dist; - idx = i; - } - if (dist == min_dist) { - fps_diff = __imx_min_fps_diff(dev->targetfps, - tmp_res->fps_options); - if (fps_diff < min_fps_diff) { - min_fps_diff = fps_diff; - idx = i; - } - } - } - - /* - * FIXME! - * only IMX135 for Saltbay and IMX227 use this algorithm - */ - if (idx == -1 && again == true && dev->new_res_sel_method) { - again = false; - goto retry; - } - return idx; -} - -/* Call with ctrl_handler.lock hold */ -static int __adjust_hvblank(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct imx_device *dev = to_imx_sensor(sd); - u16 new_frame_length_lines, new_line_length_pck; - int ret; - - /* - * No need to adjust h/v blank if not set dbg value - * Note that there is no other checking on the h/v blank value, - * as h/v blank can be set to any value above zero for debug purpose - */ - if (!dev->v_blank->val || !dev->h_blank->val) - return 0; - - new_frame_length_lines = dev->curr_res_table[dev->fmt_idx].height + - dev->v_blank->val; - new_line_length_pck = dev->curr_res_table[dev->fmt_idx].width + - dev->h_blank->val; - - ret = imx_write_reg(client, IMX_16BIT, - dev->reg_addr->line_length_pixels, new_line_length_pck); - if (ret) - return ret; - ret = imx_write_reg(client, IMX_16BIT, - dev->reg_addr->frame_length_lines, new_frame_length_lines); - if (ret) - return ret; - - dev->lines_per_frame = new_frame_length_lines; - dev->pixels_per_line = new_line_length_pck; - - return 0; -} - -static int imx_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct imx_device *dev = to_imx_sensor(sd); - struct camera_mipi_info *imx_info = NULL; - struct i2c_client *client = v4l2_get_subdevdata(sd); - const struct imx_resolution *res; - int lanes = imx_get_lanes(sd); - int ret; - u16 data, val; - int idx; - if (format->pad) - return -EINVAL; - if (!fmt) - return -EINVAL; - - imx_info = v4l2_get_subdev_hostdata(sd); - if (imx_info == NULL) - return -EINVAL; - if ((fmt->width > imx_max_res[dev->sensor_id].res_max_width) - || (fmt->height > imx_max_res[dev->sensor_id].res_max_height)) { - fmt->width = imx_max_res[dev->sensor_id].res_max_width; - fmt->height = imx_max_res[dev->sensor_id].res_max_height; - } else { - idx = nearest_resolution_index(sd, fmt->width, fmt->height); - - /* - * nearest_resolution_index() doesn't return smaller - * resolutions. If it fails, it means the requested - * resolution is higher than wecan support. Fallback - * to highest possible resolution in this case. - */ - if (idx == -1) - idx = dev->entries_curr_table - 1; - - fmt->width = dev->curr_res_table[idx].width; - fmt->height = dev->curr_res_table[idx].height; - } - - fmt->code = dev->format.code; - if(format->which == V4L2_SUBDEV_FORMAT_TRY) { - cfg->try_fmt = *fmt; - return 0; - } - mutex_lock(&dev->input_lock); - - dev->fmt_idx = nearest_resolution_index(sd, fmt->width, fmt->height); - if (dev->fmt_idx == -1) { - ret = -EINVAL; - goto out; - } - res = &dev->curr_res_table[dev->fmt_idx]; - - /* Adjust the FPS selection based on the resolution selected */ - dev->fps_index = __imx_nearest_fps_index(dev->targetfps, - res->fps_options); - dev->fps = res->fps_options[dev->fps_index].fps; - dev->regs = res->fps_options[dev->fps_index].regs; - if (!dev->regs) - dev->regs = res->regs; - - ret = imx_write_reg_array(client, dev->regs); - if (ret) - goto out; - - if (dev->sensor_id == IMX132_ID && lanes > 0) { - static const u8 imx132_rgpltd[] = { - 2, /* 1 lane: /1 */ - 0, /* 2 lanes: /2 */ - 0, /* undefined */ - 1, /* 4 lanes: /4 */ - }; - ret = imx_write_reg(client, IMX_8BIT, IMX132_208_VT_RGPLTD, - imx132_rgpltd[lanes - 1]); - if (ret) - goto out; - } - - dev->pixels_per_line = res->fps_options[dev->fps_index].pixels_per_line; - dev->lines_per_frame = res->fps_options[dev->fps_index].lines_per_frame; - - /* dbg h/v blank time */ - __adjust_hvblank(sd); - - ret = __imx_update_exposure_timing(client, dev->coarse_itg, - dev->pixels_per_line, dev->lines_per_frame); - if (ret) - goto out; - - ret = __imx_update_gain(sd, dev->gain); - if (ret) - goto out; - - ret = __imx_update_digital_gain(client, dev->digital_gain); - if (ret) - goto out; - - ret = imx_write_reg_array(client, dev->param_update); - if (ret) - goto out; - - ret = imx_get_intg_factor(client, imx_info, dev->regs); - if (ret) - goto out; - - ret = imx_read_reg(client, IMX_8BIT, - dev->reg_addr->img_orientation, &val); - if (ret) - goto out; - val &= (IMX_VFLIP_BIT|IMX_HFLIP_BIT); - imx_info->raw_bayer_order = imx_bayer_order_mapping[val]; - dev->format.code = imx_translate_bayer_order( - imx_info->raw_bayer_order); - - /* - * Fill meta data info. add imx135 metadata setting for RAW10 format - */ - switch (dev->sensor_id) { - case IMX135_ID: - ret = imx_read_reg(client, 2, - IMX135_OUTPUT_DATA_FORMAT_REG, &data); - if (ret) - goto out; - /* - * The IMX135 can support various resolutions like - * RAW6/8/10/12/14. - * 1.The data format is RAW10: - * matadata width = current resolution width(pixel) * 10 / 8 - * 2.The data format is RAW6 or RAW8: - * matadata width = current resolution width(pixel); - * 3.other data format(RAW12/14 etc): - * TBD. - */ - if (data == IMX135_OUTPUT_FORMAT_RAW10) - /* the data format is RAW10. */ - imx_info->metadata_width = res->width * 10 / 8; - else - /* The data format is RAW6/8/12/14/ etc. */ - imx_info->metadata_width = res->width; - - imx_info->metadata_height = IMX135_EMBEDDED_DATA_LINE_NUM; - - if (imx_info->metadata_effective_width == NULL) - imx_info->metadata_effective_width = - imx135_embedded_effective_size; - - break; - case IMX227_ID: - ret = imx_read_reg(client, 2, IMX227_OUTPUT_DATA_FORMAT_REG, - &data); - if (ret) - goto out; - if (data == IMX227_OUTPUT_FORMAT_RAW10) - /* the data format is RAW10. */ - imx_info->metadata_width = res->width * 10 / 8; - else - /* The data format is RAW6/8/12/14/ etc. */ - imx_info->metadata_width = res->width; - - imx_info->metadata_height = IMX227_EMBEDDED_DATA_LINE_NUM; - - if (imx_info->metadata_effective_width == NULL) - imx_info->metadata_effective_width = - imx227_embedded_effective_size; - - break; - default: - imx_info->metadata_width = 0; - imx_info->metadata_height = 0; - imx_info->metadata_effective_width = NULL; - break; - } - -out: - mutex_unlock(&dev->input_lock); - return ret; -} - - -static int imx_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct imx_device *dev = to_imx_sensor(sd); - - if (format->pad) - return -EINVAL; - if (!fmt) - return -EINVAL; - - mutex_lock(&dev->input_lock); - fmt->width = dev->curr_res_table[dev->fmt_idx].width; - fmt->height = dev->curr_res_table[dev->fmt_idx].height; - fmt->code = dev->format.code; - mutex_unlock(&dev->input_lock); - return 0; -} - -static int imx_detect(struct i2c_client *client, u16 *id, u8 *revision) -{ - struct i2c_adapter *adapter = client->adapter; - - /* i2c check */ - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) - return -ENODEV; - - /* check sensor chip ID */ - if (imx_read_reg(client, IMX_16BIT, IMX132_175_208_219_CHIP_ID, id)) { - v4l2_err(client, "sensor_id = 0x%x\n", *id); - return -ENODEV; - } - - if (*id == IMX132_ID || *id == IMX175_ID || - *id == IMX208_ID || *id == IMX219_ID) - goto found; - - if (imx_read_reg(client, IMX_16BIT, IMX134_135_227_CHIP_ID, id)) { - v4l2_err(client, "sensor_id = 0x%x\n", *id); - return -ENODEV; - } - if (*id != IMX134_ID && *id != IMX135_ID && *id != IMX227_ID) { - v4l2_err(client, "no imx sensor found\n"); - return -ENODEV; - } -found: - v4l2_info(client, "sensor_id = 0x%x\n", *id); - - /* TODO - need to be updated */ - *revision = 0; - - return 0; -} - -static void __imx_print_timing(struct v4l2_subdev *sd) -{ - struct imx_device *dev = to_imx_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - u16 width = dev->curr_res_table[dev->fmt_idx].width; - u16 height = dev->curr_res_table[dev->fmt_idx].height; - - dev_dbg(&client->dev, "Dump imx timing in stream on:\n"); - dev_dbg(&client->dev, "width: %d:\n", width); - dev_dbg(&client->dev, "height: %d:\n", height); - dev_dbg(&client->dev, "pixels_per_line: %d:\n", dev->pixels_per_line); - dev_dbg(&client->dev, "line per frame: %d:\n", dev->lines_per_frame); - dev_dbg(&client->dev, "pix freq: %d:\n", dev->vt_pix_clk_freq_mhz); - dev_dbg(&client->dev, "init fps: %d:\n", dev->vt_pix_clk_freq_mhz / - dev->pixels_per_line / dev->lines_per_frame); - dev_dbg(&client->dev, "HBlank: %d nS:\n", - 1000 * (dev->pixels_per_line - width) / - (dev->vt_pix_clk_freq_mhz / 1000000)); - dev_dbg(&client->dev, "VBlank: %d uS:\n", - (dev->lines_per_frame - height) * dev->pixels_per_line / - (dev->vt_pix_clk_freq_mhz / 1000000)); -} - -/* - * imx stream on/off - */ -static int imx_s_stream(struct v4l2_subdev *sd, int enable) -{ - int ret; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct imx_device *dev = to_imx_sensor(sd); - - mutex_lock(&dev->input_lock); - if (enable) { - /* Noise reduction & dead pixel applied before streaming */ - if (dev->fw == NULL) { - dev_warn(&client->dev, "No MSR loaded from library"); - } else { - ret = apply_msr_data(client, dev->fw); - if (ret) { - mutex_unlock(&dev->input_lock); - return ret; - } - } - ret = imx_test_pattern(sd); - if (ret) { - v4l2_err(client, "Configure test pattern failed.\n"); - mutex_unlock(&dev->input_lock); - return ret; - } - __imx_print_timing(sd); - ret = imx_write_reg_array(client, imx_streaming); - if (ret != 0) { - v4l2_err(client, "write_reg_array err\n"); - mutex_unlock(&dev->input_lock); - return ret; - } - dev->streaming = 1; - if (dev->vcm_driver && dev->vcm_driver->t_focus_abs_init) - dev->vcm_driver->t_focus_abs_init(sd); - } else { - ret = imx_write_reg_array(client, imx_soft_standby); - if (ret != 0) { - v4l2_err(client, "write_reg_array err\n"); - mutex_unlock(&dev->input_lock); - return ret; - } - dev->streaming = 0; - dev->targetfps = 0; - } - mutex_unlock(&dev->input_lock); - - return 0; -} - -static int __update_imx_device_settings(struct imx_device *dev, u16 sensor_id) -{ - /* IMX on other platform is not supported yet */ - return -EINVAL; -} - -static int imx_s_config(struct v4l2_subdev *sd, - int irq, void *pdata) -{ - struct imx_device *dev = to_imx_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 sensor_revision; - u16 sensor_id; - int ret; - if (pdata == NULL) - return -ENODEV; - - dev->platform_data = pdata; - - mutex_lock(&dev->input_lock); - - if (dev->platform_data->platform_init) { - ret = dev->platform_data->platform_init(client); - if (ret) { - mutex_unlock(&dev->input_lock); - dev_err(&client->dev, "imx platform init err\n"); - return ret; - } - } - /* - * power off the module first. - * - * As first power on by board have undecided state of power/gpio pins. - */ - ret = __imx_s_power(sd, 0); - if (ret) { - v4l2_err(client, "imx power-down err.\n"); - mutex_unlock(&dev->input_lock); - return ret; - } - - ret = __imx_s_power(sd, 1); - if (ret) { - v4l2_err(client, "imx power-up err.\n"); - mutex_unlock(&dev->input_lock); - return ret; - } - - ret = dev->platform_data->csi_cfg(sd, 1); - if (ret) - goto fail_csi_cfg; - - /* config & detect sensor */ - ret = imx_detect(client, &sensor_id, &sensor_revision); - if (ret) { - v4l2_err(client, "imx_detect err s_config.\n"); - goto fail_detect; - } - - dev->sensor_id = sensor_id; - dev->sensor_revision = sensor_revision; - - /* Resolution settings depend on sensor type and platform */ - ret = __update_imx_device_settings(dev, dev->sensor_id); - if (ret) - goto fail_detect; - /* Read sensor's OTP data */ - dev->otp_data = dev->otp_driver->otp_read(sd, - dev->otp_driver->dev_addr, dev->otp_driver->start_addr, - dev->otp_driver->size); - - /* power off sensor */ - ret = __imx_s_power(sd, 0); - - mutex_unlock(&dev->input_lock); - if (ret) - v4l2_err(client, "imx power-down err.\n"); - - return ret; - -fail_detect: - dev->platform_data->csi_cfg(sd, 0); -fail_csi_cfg: - __imx_s_power(sd, 0); - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); - mutex_unlock(&dev->input_lock); - dev_err(&client->dev, "sensor power-gating failed\n"); - return ret; -} - -static int -imx_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - struct imx_device *dev = to_imx_sensor(sd); - if (code->index >= MAX_FMTS) - return -EINVAL; - - mutex_lock(&dev->input_lock); - code->code = dev->format.code; - mutex_unlock(&dev->input_lock); - return 0; -} - -static int -imx_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - int index = fse->index; - struct imx_device *dev = to_imx_sensor(sd); - - mutex_lock(&dev->input_lock); - if (index >= dev->entries_curr_table) { - mutex_unlock(&dev->input_lock); - return -EINVAL; - } - - fse->min_width = dev->curr_res_table[index].width; - fse->min_height = dev->curr_res_table[index].height; - fse->max_width = dev->curr_res_table[index].width; - fse->max_height = dev->curr_res_table[index].height; - mutex_unlock(&dev->input_lock); - return 0; -} - -static int -imx_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *param) -{ - struct imx_device *dev = to_imx_sensor(sd); - - mutex_lock(&dev->input_lock); - dev->run_mode = param->parm.capture.capturemode; - - switch (dev->run_mode) { - case CI_MODE_VIDEO: - dev->curr_res_table = dev->mode_tables->res_video; - dev->entries_curr_table = dev->mode_tables->n_res_video; - break; - case CI_MODE_STILL_CAPTURE: - dev->curr_res_table = dev->mode_tables->res_still; - dev->entries_curr_table = dev->mode_tables->n_res_still; - break; - default: - dev->curr_res_table = dev->mode_tables->res_preview; - dev->entries_curr_table = dev->mode_tables->n_res_preview; - } - mutex_unlock(&dev->input_lock); - return 0; -} - -static int imx_g_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct imx_device *dev = to_imx_sensor(sd); - - mutex_lock(&dev->input_lock); - interval->interval.denominator = dev->fps; - interval->interval.numerator = 1; - mutex_unlock(&dev->input_lock); - return 0; -} - -static int __imx_s_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct imx_device *dev = to_imx_sensor(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - const struct imx_resolution *res = - &dev->curr_res_table[dev->fmt_idx]; - struct camera_mipi_info *imx_info = NULL; - unsigned short pixels_per_line; - unsigned short lines_per_frame; - unsigned int fps_index; - int fps; - int ret = 0; - - - imx_info = v4l2_get_subdev_hostdata(sd); - if (imx_info == NULL) - return -EINVAL; - - if (!interval->interval.numerator) - interval->interval.numerator = 1; - - fps = interval->interval.denominator / interval->interval.numerator; - - if (!fps) - return -EINVAL; - - dev->targetfps = fps; - /* No need to proceed further if we are not streaming */ - if (!dev->streaming) - return 0; - - /* Ignore if we are already using the required FPS. */ - if (fps == dev->fps) - return 0; - - /* - * Start here, sensor is already streaming, so adjust fps dynamically - */ - fps_index = __imx_above_nearest_fps_index(fps, res->fps_options); - if (fps > res->fps_options[fps_index].fps) { - /* - * if does not have high fps setting, not support increase fps - * by adjust lines per frame. - */ - dev_err(&client->dev, "Could not support fps: %d.\n", fps); - return -EINVAL; - } - - if (res->fps_options[fps_index].regs && - res->fps_options[fps_index].regs != dev->regs) { - /* - * if need a new setting, but the new setting has difference - * with current setting, not use this one, as may have - * unexpected result, e.g. PLL, IQ. - */ - dev_dbg(&client->dev, - "Sensor is streaming, not apply new sensor setting\n"); - if (fps > res->fps_options[dev->fps_index].fps) { - /* - * Does not support increase fps based on low fps - * setting, as the high fps setting could not be used, - * and fps requested is above current setting fps. - */ - dev_warn(&client->dev, - "Could not support fps: %d, keep current: %d.\n", - fps, dev->fps); - return 0; - } - } else { - dev->fps_index = fps_index; - dev->fps = res->fps_options[dev->fps_index].fps; - } - - /* Update the new frametimings based on FPS */ - pixels_per_line = res->fps_options[dev->fps_index].pixels_per_line; - lines_per_frame = res->fps_options[dev->fps_index].lines_per_frame; - - if (fps > res->fps_options[fps_index].fps) { - /* - * if does not have high fps setting, not support increase fps - * by adjust lines per frame. - */ - dev_warn(&client->dev, "Could not support fps: %d. Use:%d.\n", - fps, res->fps_options[fps_index].fps); - goto done; - } - - /* if the new setting does not match exactly */ - if (dev->fps != fps) { -#define MAX_LINES_PER_FRAME 0xffff - dev_dbg(&client->dev, "adjusting fps using lines_per_frame\n"); - /* - * FIXME! - * 1: check DS on max value of lines_per_frame - * 2: consider use pixel per line for more range? - */ - if (dev->lines_per_frame * dev->fps / fps > - MAX_LINES_PER_FRAME) { - dev_warn(&client->dev, - "adjust lines_per_frame out of range, try to use max value.\n"); - lines_per_frame = MAX_LINES_PER_FRAME; - } else { - lines_per_frame = lines_per_frame * dev->fps / fps; - } - } -done: - /* Update the new frametimings based on FPS */ - dev->pixels_per_line = pixels_per_line; - dev->lines_per_frame = lines_per_frame; - - /* Update the new values so that user side knows the current settings */ - ret = __imx_update_exposure_timing(client, - dev->coarse_itg, dev->pixels_per_line, dev->lines_per_frame); - if (ret) - return ret; - - dev->fps = fps; - - ret = imx_get_intg_factor(client, imx_info, dev->regs); - if (ret) - return ret; - - interval->interval.denominator = res->fps_options[dev->fps_index].fps; - interval->interval.numerator = 1; - __imx_print_timing(sd); - - return ret; -} - -static int imx_s_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct imx_device *dev = to_imx_sensor(sd); - int ret; - - mutex_lock(&dev->input_lock); - ret = __imx_s_frame_interval(sd, interval); - mutex_unlock(&dev->input_lock); - - return ret; -} -static int imx_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) -{ - struct imx_device *dev = to_imx_sensor(sd); - - mutex_lock(&dev->input_lock); - *frames = dev->curr_res_table[dev->fmt_idx].skip_frames; - mutex_unlock(&dev->input_lock); - - return 0; -} - -static const struct v4l2_subdev_sensor_ops imx_sensor_ops = { - .g_skip_frames = imx_g_skip_frames, -}; - -static const struct v4l2_subdev_video_ops imx_video_ops = { - .s_stream = imx_s_stream, - .s_parm = imx_s_parm, - .g_frame_interval = imx_g_frame_interval, - .s_frame_interval = imx_s_frame_interval, -}; - -static const struct v4l2_subdev_core_ops imx_core_ops = { - .s_power = imx_s_power, - .ioctl = imx_ioctl, - .init = imx_init, -}; - -static const struct v4l2_subdev_pad_ops imx_pad_ops = { - .enum_mbus_code = imx_enum_mbus_code, - .enum_frame_size = imx_enum_frame_size, - .get_fmt = imx_get_fmt, - .set_fmt = imx_set_fmt, -}; - -static const struct v4l2_subdev_ops imx_ops = { - .core = &imx_core_ops, - .video = &imx_video_ops, - .pad = &imx_pad_ops, - .sensor = &imx_sensor_ops, -}; - -static const struct media_entity_operations imx_entity_ops = { - .link_setup = NULL, -}; - -static int imx_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct imx_device *dev = to_imx_sensor(sd); - - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); - - media_entity_cleanup(&dev->sd.entity); - v4l2_ctrl_handler_free(&dev->ctrl_handler); - dev->platform_data->csi_cfg(sd, 0); - v4l2_device_unregister_subdev(sd); - release_msr_list(client, dev->fw); - kfree(dev); - - return 0; -} - -static int __imx_init_ctrl_handler(struct imx_device *dev) -{ - struct v4l2_ctrl_handler *hdl; - int i; - - hdl = &dev->ctrl_handler; - - v4l2_ctrl_handler_init(&dev->ctrl_handler, ARRAY_SIZE(imx_controls)); - - for (i = 0; i < ARRAY_SIZE(imx_controls); i++) - v4l2_ctrl_new_custom(&dev->ctrl_handler, - &imx_controls[i], NULL); - - dev->pixel_rate = v4l2_ctrl_find(&dev->ctrl_handler, - V4L2_CID_PIXEL_RATE); - dev->h_blank = v4l2_ctrl_find(&dev->ctrl_handler, - V4L2_CID_HBLANK); - dev->v_blank = v4l2_ctrl_find(&dev->ctrl_handler, - V4L2_CID_VBLANK); - dev->link_freq = v4l2_ctrl_find(&dev->ctrl_handler, - V4L2_CID_LINK_FREQ); - dev->h_flip = v4l2_ctrl_find(&dev->ctrl_handler, - V4L2_CID_HFLIP); - dev->v_flip = v4l2_ctrl_find(&dev->ctrl_handler, - V4L2_CID_VFLIP); - dev->tp_mode = v4l2_ctrl_find(&dev->ctrl_handler, - V4L2_CID_TEST_PATTERN); - dev->tp_r = v4l2_ctrl_find(&dev->ctrl_handler, - V4L2_CID_TEST_PATTERN_COLOR_R); - dev->tp_gr = v4l2_ctrl_find(&dev->ctrl_handler, - V4L2_CID_TEST_PATTERN_COLOR_GR); - dev->tp_gb = v4l2_ctrl_find(&dev->ctrl_handler, - V4L2_CID_TEST_PATTERN_COLOR_GB); - dev->tp_b = v4l2_ctrl_find(&dev->ctrl_handler, - V4L2_CID_TEST_PATTERN_COLOR_B); - - if (dev->ctrl_handler.error || dev->pixel_rate == NULL - || dev->h_blank == NULL || dev->v_blank == NULL - || dev->h_flip == NULL || dev->v_flip == NULL - || dev->link_freq == NULL) { - return dev->ctrl_handler.error; - } - - dev->ctrl_handler.lock = &dev->input_lock; - dev->sd.ctrl_handler = hdl; - v4l2_ctrl_handler_setup(&dev->ctrl_handler); - - return 0; -} - -static void imx_update_reg_info(struct imx_device *dev) -{ - if (dev->sensor_id == IMX219_ID) { - dev->reg_addr = &imx219_addr; - dev->param_hold = imx219_param_hold; - dev->param_update = imx219_param_update; - } else { - dev->reg_addr = &imx_addr; - dev->param_hold = imx_param_hold; - dev->param_update = imx_param_update; - } -} - -static int imx_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct imx_device *dev; - struct camera_mipi_info *imx_info = NULL; - int ret; - char *msr_file_name = NULL; - - /* allocate sensor device & init sub device */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - mutex_init(&dev->input_lock); - - dev->i2c_id = id->driver_data; - dev->fmt_idx = 0; - dev->sensor_id = IMX_ID_DEFAULT; - dev->vcm_driver = &imx_vcms[IMX_ID_DEFAULT]; - dev->digital_gain = 256; - - v4l2_i2c_subdev_init(&(dev->sd), client, &imx_ops); - - if (client->dev.platform_data) { - ret = imx_s_config(&dev->sd, client->irq, - client->dev.platform_data); - if (ret) - goto out_free; - } - imx_info = v4l2_get_subdev_hostdata(&dev->sd); - - /* - * sd->name is updated with sensor driver name by the v4l2. - * change it to sensor name in this case. - */ - imx_update_reg_info(dev); - snprintf(dev->sd.name, sizeof(dev->sd.name), "%s%x %d-%04x", - IMX_SUBDEV_PREFIX, dev->sensor_id, - i2c_adapter_id(client->adapter), client->addr); - - ret = __imx_init_ctrl_handler(dev); - if (ret) - goto out_ctrl_handler_free; - - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->format.code = imx_translate_bayer_order( - imx_info->raw_bayer_order); - dev->sd.entity.ops = &imx_entity_ops; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); - if (ret) { - imx_remove(client); - return ret; - } - - /* Load the Noise reduction, Dead pixel registers from cpf file*/ - if (dev->platform_data->msr_file_name != NULL) - msr_file_name = dev->platform_data->msr_file_name(); - if (msr_file_name) { - ret = load_msr_list(client, msr_file_name, &dev->fw); - if (ret) { - imx_remove(client); - return ret; - } - } else { - dev_warn(&client->dev, "Drvb file not present"); - } - - return ret; - -out_ctrl_handler_free: - v4l2_ctrl_handler_free(&dev->ctrl_handler); - -out_free: - v4l2_device_unregister_subdev(&dev->sd); - kfree(dev); - return ret; -} - -static const struct i2c_device_id imx_ids[] = { - {IMX_NAME_175, IMX175_ID}, - {IMX_NAME_135, IMX135_ID}, - {IMX_NAME_135_FUJI, IMX135_FUJI_ID}, - {IMX_NAME_134, IMX134_ID}, - {IMX_NAME_132, IMX132_ID}, - {IMX_NAME_208, IMX208_ID}, - {IMX_NAME_219, IMX219_ID}, - {IMX_NAME_227, IMX227_ID}, - {} -}; - -MODULE_DEVICE_TABLE(i2c, imx_ids); - -static struct i2c_driver imx_driver = { - .driver = { - .name = IMX_DRIVER, - }, - .probe = imx_probe, - .remove = imx_remove, - .id_table = imx_ids, -}; - -static __init int init_imx(void) -{ - return i2c_add_driver(&imx_driver); -} - -static __exit void exit_imx(void) -{ - i2c_del_driver(&imx_driver); -} - -module_init(init_imx); -module_exit(exit_imx); - -MODULE_DESCRIPTION("A low-level driver for Sony IMX sensors"); -MODULE_AUTHOR("Shenbo Huang "); -MODULE_LICENSE("GPL"); - diff --git a/drivers/staging/media/atomisp/i2c/imx/imx.h b/drivers/staging/media/atomisp/i2c/imx/imx.h deleted file mode 100644 index 30beb2a0ed93..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/imx.h +++ /dev/null @@ -1,737 +0,0 @@ -/* - * Support for Sony IMX camera sensor. - * - * Copyright (c) 2010 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#ifndef __IMX_H__ -#define __IMX_H__ -#include "../../include/linux/atomisp_platform.h" -#include "../../include/linux/atomisp.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "imx175.h" -#include "imx135.h" -#include "imx134.h" -#include "imx132.h" -#include "imx208.h" -#include "imx219.h" -#include "imx227.h" - -#define IMX_MCLK 192 - -/* TODO - This should be added into include/linux/videodev2.h */ -#ifndef V4L2_IDENT_IMX -#define V4L2_IDENT_IMX 8245 -#endif - -#define IMX_MAX_AE_LUT_LENGTH 5 -/* - * imx System control registers - */ -#define IMX_MASK_5BIT 0x1F -#define IMX_MASK_4BIT 0xF -#define IMX_MASK_3BIT 0x7 -#define IMX_MASK_2BIT 0x3 -#define IMX_MASK_8BIT 0xFF -#define IMX_MASK_11BIT 0x7FF -#define IMX_INTG_BUF_COUNT 2 - -#define IMX_FINE_INTG_TIME 0x1E8 - -#define IMX_VT_PIX_CLK_DIV 0x0301 -#define IMX_VT_SYS_CLK_DIV 0x0303 -#define IMX_PRE_PLL_CLK_DIV 0x0305 -#define IMX227_IOP_PRE_PLL_CLK_DIV 0x030D -#define IMX227_PLL_MULTIPLIER 0x0306 -#define IMX227_IOP_PLL_MULTIPLIER 0x030E -#define IMX227_PLL_MULTI_DRIVE 0x0310 -#define IMX227_OP_PIX_CLK_DIV 0x0309 -#define IMX227_OP_SYS_CLK_DIV 0x030B -#define IMX_PLL_MULTIPLIER 0x030C -#define IMX_OP_PIX_DIV 0x0309 -#define IMX_OP_SYS_DIV 0x030B -#define IMX_FRAME_LENGTH_LINES 0x0340 -#define IMX_LINE_LENGTH_PIXELS 0x0342 -#define IMX_COARSE_INTG_TIME_MIN 0x1004 -#define IMX_COARSE_INTG_TIME_MAX 0x1006 -#define IMX_BINNING_ENABLE 0x0390 -#define IMX227_BINNING_ENABLE 0x0900 -#define IMX_BINNING_TYPE 0x0391 -#define IMX227_BINNING_TYPE 0x0901 -#define IMX_READ_MODE 0x0390 -#define IMX227_READ_MODE 0x0900 - -#define IMX_HORIZONTAL_START_H 0x0344 -#define IMX_VERTICAL_START_H 0x0346 -#define IMX_HORIZONTAL_END_H 0x0348 -#define IMX_VERTICAL_END_H 0x034a -#define IMX_HORIZONTAL_OUTPUT_SIZE_H 0x034c -#define IMX_VERTICAL_OUTPUT_SIZE_H 0x034e - -/* Post Divider setting register for imx132 and imx208 */ -#define IMX132_208_VT_RGPLTD 0x30A4 - -/* Multiplier setting register for imx132, imx208, and imx219 */ -#define IMX132_208_219_PLL_MULTIPLIER 0x0306 - -#define IMX_COARSE_INTEGRATION_TIME 0x0202 -#define IMX_TEST_PATTERN_MODE 0x0600 -#define IMX_TEST_PATTERN_COLOR_R 0x0602 -#define IMX_TEST_PATTERN_COLOR_GR 0x0604 -#define IMX_TEST_PATTERN_COLOR_B 0x0606 -#define IMX_TEST_PATTERN_COLOR_GB 0x0608 -#define IMX_IMG_ORIENTATION 0x0101 -#define IMX_VFLIP_BIT 2 -#define IMX_HFLIP_BIT 1 -#define IMX_GLOBAL_GAIN 0x0205 -#define IMX_SHORT_AGC_GAIN 0x0233 -#define IMX_DGC_ADJ 0x020E -#define IMX_DGC_LEN 10 -#define IMX227_DGC_LEN 4 -#define IMX_MAX_EXPOSURE_SUPPORTED 0xfffb -#define IMX_MAX_GLOBAL_GAIN_SUPPORTED 0x00ff -#define IMX_MAX_DIGITAL_GAIN_SUPPORTED 0x0fff - -#define MAX_FMTS 1 -#define IMX_OTP_DATA_SIZE 1280 - -#define IMX_SUBDEV_PREFIX "imx" -#define IMX_DRIVER "imx1x5" - -/* Sensor ids from identification register */ -#define IMX_NAME_134 "imx134" -#define IMX_NAME_135 "imx135" -#define IMX_NAME_175 "imx175" -#define IMX_NAME_132 "imx132" -#define IMX_NAME_208 "imx208" -#define IMX_NAME_219 "imx219" -#define IMX_NAME_227 "imx227" -#define IMX175_ID 0x0175 -#define IMX135_ID 0x0135 -#define IMX134_ID 0x0134 -#define IMX132_ID 0x0132 -#define IMX208_ID 0x0208 -#define IMX219_ID 0x0219 -#define IMX227_ID 0x0227 - -/* Sensor id based on i2c_device_id table - * (Fuji module can not be detected based on sensor registers) */ -#define IMX135_FUJI_ID 0x0136 -#define IMX_NAME_135_FUJI "imx135fuji" - -/* imx175 - use dw9714 vcm */ -#define IMX175_MERRFLD 0x175 -#define IMX175_VALLEYVIEW 0x176 -#define IMX135_SALTBAY 0x135 -#define IMX135_VICTORIABAY 0x136 -#define IMX132_SALTBAY 0x132 -#define IMX134_VALLEYVIEW 0x134 -#define IMX208_MOFD_PD2 0x208 -#define IMX219_MFV0_PRH 0x219 -#define IMX227_SAND 0x227 - -/* otp - specific settings */ -#define E2PROM_ADDR 0xa0 -#define E2PROM_LITEON_12P1BA869D_ADDR 0xa0 -#define E2PROM_ABICO_SS89A839_ADDR 0xa8 -#define DEFAULT_OTP_SIZE 1280 -#define IMX135_OTP_SIZE 1280 -#define IMX219_OTP_SIZE 2048 -#define IMX227_OTP_SIZE 2560 -#define E2PROM_LITEON_12P1BA869D_SIZE 544 - -#define IMX_ID_DEFAULT 0x0000 -#define IMX132_175_208_219_CHIP_ID 0x0000 -#define IMX134_135_CHIP_ID 0x0016 -#define IMX134_135_227_CHIP_ID 0x0016 - -#define IMX175_RES_WIDTH_MAX 3280 -#define IMX175_RES_HEIGHT_MAX 2464 -#define IMX135_RES_WIDTH_MAX 4208 -#define IMX135_RES_HEIGHT_MAX 3120 -#define IMX132_RES_WIDTH_MAX 1936 -#define IMX132_RES_HEIGHT_MAX 1096 -#define IMX134_RES_WIDTH_MAX 3280 -#define IMX134_RES_HEIGHT_MAX 2464 -#define IMX208_RES_WIDTH_MAX 1936 -#define IMX208_RES_HEIGHT_MAX 1096 -#define IMX219_RES_WIDTH_MAX 3280 -#define IMX219_RES_HEIGHT_MAX 2464 -#define IMX227_RES_WIDTH_MAX 2400 -#define IMX227_RES_HEIGHT_MAX 2720 - -/* Defines for lens/VCM */ -#define IMX_FOCAL_LENGTH_NUM 369 /*3.69mm*/ -#define IMX_FOCAL_LENGTH_DEM 100 -#define IMX_F_NUMBER_DEFAULT_NUM 22 -#define IMX_F_NUMBER_DEM 10 -#define IMX_INVALID_CONFIG 0xffffffff -#define IMX_MAX_FOCUS_POS 1023 -#define IMX_MAX_FOCUS_NEG (-1023) -#define IMX_VCM_SLEW_STEP_MAX 0x3f -#define IMX_VCM_SLEW_TIME_MAX 0x1f - -#define IMX_BIN_FACTOR_MAX 4 -#define IMX_INTEGRATION_TIME_MARGIN 4 -/* - * focal length bits definition: - * bits 31-16: numerator, bits 15-0: denominator - */ -#define IMX_FOCAL_LENGTH_DEFAULT 0x1710064 - -/* - * current f-number bits definition: - * bits 31-16: numerator, bits 15-0: denominator - */ -#define IMX_F_NUMBER_DEFAULT 0x16000a - -/* - * f-number range bits definition: - * bits 31-24: max f-number numerator - * bits 23-16: max f-number denominator - * bits 15-8: min f-number numerator - * bits 7-0: min f-number denominator - */ -#define IMX_F_NUMBER_RANGE 0x160a160a - -struct imx_vcm { - int (*power_up)(struct v4l2_subdev *sd); - int (*power_down)(struct v4l2_subdev *sd); - int (*t_focus_abs)(struct v4l2_subdev *sd, s32 value); - int (*t_focus_abs_init)(struct v4l2_subdev *sd); - int (*t_focus_rel)(struct v4l2_subdev *sd, s32 value); - int (*q_focus_status)(struct v4l2_subdev *sd, s32 *value); - int (*q_focus_abs)(struct v4l2_subdev *sd, s32 *value); - int (*t_vcm_slew)(struct v4l2_subdev *sd, s32 value); - int (*t_vcm_timing)(struct v4l2_subdev *sd, s32 value); -}; - -struct imx_otp { - void * (*otp_read)(struct v4l2_subdev *sd, u8 dev_addr, - u32 start_addr, u32 size); - u32 start_addr; - u32 size; - u8 dev_addr; -}; - -struct max_res { - int res_max_width; - int res_max_height; -}; - -struct max_res imx_max_res[] = { - [IMX175_ID] = { - .res_max_width = IMX175_RES_WIDTH_MAX, - .res_max_height = IMX175_RES_HEIGHT_MAX, - }, - [IMX135_ID] = { - .res_max_width = IMX135_RES_WIDTH_MAX, - .res_max_height = IMX135_RES_HEIGHT_MAX, - }, - [IMX132_ID] = { - .res_max_width = IMX132_RES_WIDTH_MAX, - .res_max_height = IMX132_RES_HEIGHT_MAX, - }, - [IMX134_ID] = { - .res_max_width = IMX134_RES_WIDTH_MAX, - .res_max_height = IMX134_RES_HEIGHT_MAX, - }, - [IMX208_ID] = { - .res_max_width = IMX208_RES_WIDTH_MAX, - .res_max_height = IMX208_RES_HEIGHT_MAX, - }, - [IMX219_ID] = { - .res_max_width = IMX219_RES_WIDTH_MAX, - .res_max_height = IMX219_RES_HEIGHT_MAX, - }, - [IMX227_ID] = { - .res_max_width = IMX227_RES_WIDTH_MAX, - .res_max_height = IMX227_RES_HEIGHT_MAX, - }, -}; - -struct imx_settings { - struct imx_reg const *init_settings; - struct imx_resolution *res_preview; - struct imx_resolution *res_still; - struct imx_resolution *res_video; - int n_res_preview; - int n_res_still; - int n_res_video; -}; - -struct imx_settings imx_sets[] = { - [IMX175_MERRFLD] = { - .init_settings = imx175_init_settings, - .res_preview = imx175_res_preview, - .res_still = imx175_res_still, - .res_video = imx175_res_video, - .n_res_preview = ARRAY_SIZE(imx175_res_preview), - .n_res_still = ARRAY_SIZE(imx175_res_still), - .n_res_video = ARRAY_SIZE(imx175_res_video), - }, - [IMX175_VALLEYVIEW] = { - .init_settings = imx175_init_settings, - .res_preview = imx175_res_preview, - .res_still = imx175_res_still, - .res_video = imx175_res_video, - .n_res_preview = ARRAY_SIZE(imx175_res_preview), - .n_res_still = ARRAY_SIZE(imx175_res_still), - .n_res_video = ARRAY_SIZE(imx175_res_video), - }, - [IMX135_SALTBAY] = { - .init_settings = imx135_init_settings, - .res_preview = imx135_res_preview, - .res_still = imx135_res_still, - .res_video = imx135_res_video, - .n_res_preview = ARRAY_SIZE(imx135_res_preview), - .n_res_still = ARRAY_SIZE(imx135_res_still), - .n_res_video = ARRAY_SIZE(imx135_res_video), - }, - [IMX135_VICTORIABAY] = { - .init_settings = imx135_init_settings, - .res_preview = imx135_res_preview_mofd, - .res_still = imx135_res_still_mofd, - .res_video = imx135_res_video, - .n_res_preview = ARRAY_SIZE(imx135_res_preview_mofd), - .n_res_still = ARRAY_SIZE(imx135_res_still_mofd), - .n_res_video = ARRAY_SIZE(imx135_res_video), - }, - [IMX132_SALTBAY] = { - .init_settings = imx132_init_settings, - .res_preview = imx132_res_preview, - .res_still = imx132_res_still, - .res_video = imx132_res_video, - .n_res_preview = ARRAY_SIZE(imx132_res_preview), - .n_res_still = ARRAY_SIZE(imx132_res_still), - .n_res_video = ARRAY_SIZE(imx132_res_video), - }, - [IMX134_VALLEYVIEW] = { - .init_settings = imx134_init_settings, - .res_preview = imx134_res_preview, - .res_still = imx134_res_still, - .res_video = imx134_res_video, - .n_res_preview = ARRAY_SIZE(imx134_res_preview), - .n_res_still = ARRAY_SIZE(imx134_res_still), - .n_res_video = ARRAY_SIZE(imx134_res_video), - }, - [IMX208_MOFD_PD2] = { - .init_settings = imx208_init_settings, - .res_preview = imx208_res_preview, - .res_still = imx208_res_still, - .res_video = imx208_res_video, - .n_res_preview = ARRAY_SIZE(imx208_res_preview), - .n_res_still = ARRAY_SIZE(imx208_res_still), - .n_res_video = ARRAY_SIZE(imx208_res_video), - }, - [IMX219_MFV0_PRH] = { - .init_settings = imx219_init_settings, - .res_preview = imx219_res_preview, - .res_still = imx219_res_still, - .res_video = imx219_res_video, - .n_res_preview = ARRAY_SIZE(imx219_res_preview), - .n_res_still = ARRAY_SIZE(imx219_res_still), - .n_res_video = ARRAY_SIZE(imx219_res_video), - }, - [IMX227_SAND] = { - .init_settings = imx227_init_settings, - .res_preview = imx227_res_preview, - .res_still = imx227_res_still, - .res_video = imx227_res_video, - .n_res_preview = ARRAY_SIZE(imx227_res_preview), - .n_res_still = ARRAY_SIZE(imx227_res_still), - .n_res_video = ARRAY_SIZE(imx227_res_video), - }, -}; - -struct imx_reg_addr { - u16 frame_length_lines; - u16 line_length_pixels; - u16 horizontal_start_h; - u16 vertical_start_h; - u16 horizontal_end_h; - u16 vertical_end_h; - u16 horizontal_output_size_h; - u16 vertical_output_size_h; - u16 coarse_integration_time; - u16 img_orientation; - u16 global_gain; - u16 dgc_adj; -}; - -struct imx_reg_addr imx_addr = { - IMX_FRAME_LENGTH_LINES, - IMX_LINE_LENGTH_PIXELS, - IMX_HORIZONTAL_START_H, - IMX_VERTICAL_START_H, - IMX_HORIZONTAL_END_H, - IMX_VERTICAL_END_H, - IMX_HORIZONTAL_OUTPUT_SIZE_H, - IMX_VERTICAL_OUTPUT_SIZE_H, - IMX_COARSE_INTEGRATION_TIME, - IMX_IMG_ORIENTATION, - IMX_GLOBAL_GAIN, - IMX_DGC_ADJ, -}; - -struct imx_reg_addr imx219_addr = { - IMX219_FRAME_LENGTH_LINES, - IMX219_LINE_LENGTH_PIXELS, - IMX219_HORIZONTAL_START_H, - IMX219_VERTICAL_START_H, - IMX219_HORIZONTAL_END_H, - IMX219_VERTICAL_END_H, - IMX219_HORIZONTAL_OUTPUT_SIZE_H, - IMX219_VERTICAL_OUTPUT_SIZE_H, - IMX219_COARSE_INTEGRATION_TIME, - IMX219_IMG_ORIENTATION, - IMX219_GLOBAL_GAIN, - IMX219_DGC_ADJ, -}; - -#define v4l2_format_capture_type_entry(_width, _height, \ - _pixelformat, _bytesperline, _colorspace) \ - {\ - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,\ - .fmt.pix.width = (_width),\ - .fmt.pix.height = (_height),\ - .fmt.pix.pixelformat = (_pixelformat),\ - .fmt.pix.bytesperline = (_bytesperline),\ - .fmt.pix.colorspace = (_colorspace),\ - .fmt.pix.sizeimage = (_height)*(_bytesperline),\ - } - -#define s_output_format_entry(_width, _height, _pixelformat, \ - _bytesperline, _colorspace, _fps) \ - {\ - .v4l2_fmt = v4l2_format_capture_type_entry(_width, \ - _height, _pixelformat, _bytesperline, \ - _colorspace),\ - .fps = (_fps),\ - } - -#define s_output_format_reg_entry(_width, _height, _pixelformat, \ - _bytesperline, _colorspace, _fps, _reg_setting) \ - {\ - .s_fmt = s_output_format_entry(_width, _height,\ - _pixelformat, _bytesperline, \ - _colorspace, _fps),\ - .reg_setting = (_reg_setting),\ - } - -/* imx device structure */ -struct imx_device { - struct v4l2_subdev sd; - struct media_pad pad; - struct v4l2_mbus_framefmt format; - struct camera_sensor_platform_data *platform_data; - struct mutex input_lock; /* serialize sensor's ioctl */ - int fmt_idx; - int status; - int streaming; - int power; - int run_mode; - int vt_pix_clk_freq_mhz; - int fps_index; - u32 focus; - u16 sensor_id; /* Sensor id from registers */ - u16 i2c_id; /* Sensor id from i2c_device_id */ - u16 coarse_itg; - u16 fine_itg; - u16 digital_gain; - u16 gain; - u16 pixels_per_line; - u16 lines_per_frame; - u8 targetfps; - u8 fps; - const struct imx_reg *regs; - u8 res; - u8 type; - u8 sensor_revision; - u8 *otp_data; - struct imx_settings *mode_tables; - struct imx_vcm *vcm_driver; - struct imx_otp *otp_driver; - const struct imx_resolution *curr_res_table; - unsigned long entries_curr_table; - const struct firmware *fw; - struct imx_reg_addr *reg_addr; - const struct imx_reg *param_hold; - const struct imx_reg *param_update; - - /* used for h/b blank tuning */ - struct v4l2_ctrl_handler ctrl_handler; - struct v4l2_ctrl *pixel_rate; - struct v4l2_ctrl *h_blank; - struct v4l2_ctrl *v_blank; - struct v4l2_ctrl *link_freq; - struct v4l2_ctrl *h_flip; - struct v4l2_ctrl *v_flip; - - /* Test pattern control */ - struct v4l2_ctrl *tp_mode; - struct v4l2_ctrl *tp_r; - struct v4l2_ctrl *tp_gr; - struct v4l2_ctrl *tp_gb; - struct v4l2_ctrl *tp_b; - - /* FIXME! */ - bool new_res_sel_method; -}; - -#define to_imx_sensor(x) container_of(x, struct imx_device, sd) - -#define IMX_MAX_WRITE_BUF_SIZE 32 -struct imx_write_buffer { - u16 addr; - u8 data[IMX_MAX_WRITE_BUF_SIZE]; -}; - -struct imx_write_ctrl { - int index; - struct imx_write_buffer buffer; -}; - -static const struct imx_reg imx_soft_standby[] = { - {IMX_8BIT, 0x0100, 0x00}, - {IMX_TOK_TERM, 0, 0} -}; - -static const struct imx_reg imx_streaming[] = { - {IMX_8BIT, 0x0100, 0x01}, - {IMX_TOK_TERM, 0, 0} -}; - -static const struct imx_reg imx_param_hold[] = { - {IMX_8BIT, 0x0104, 0x01}, /* GROUPED_PARAMETER_HOLD */ - {IMX_TOK_TERM, 0, 0} -}; - -static const struct imx_reg imx_param_update[] = { - {IMX_8BIT, 0x0104, 0x00}, /* GROUPED_PARAMETER_HOLD */ - {IMX_TOK_TERM, 0, 0} -}; - -static const struct imx_reg imx219_param_hold[] = { - {IMX_TOK_TERM, 0, 0} -}; - -static const struct imx_reg imx219_param_update[] = { - {IMX_TOK_TERM, 0, 0} -}; - -extern int ad5816g_vcm_power_up(struct v4l2_subdev *sd); -extern int ad5816g_vcm_power_down(struct v4l2_subdev *sd); -extern int ad5816g_t_focus_abs(struct v4l2_subdev *sd, s32 value); -extern int ad5816g_t_focus_rel(struct v4l2_subdev *sd, s32 value); -extern int ad5816g_q_focus_status(struct v4l2_subdev *sd, s32 *value); -extern int ad5816g_q_focus_abs(struct v4l2_subdev *sd, s32 *value); -extern int ad5816g_t_vcm_slew(struct v4l2_subdev *sd, s32 value); -extern int ad5816g_t_vcm_timing(struct v4l2_subdev *sd, s32 value); - -extern int drv201_vcm_power_up(struct v4l2_subdev *sd); -extern int drv201_vcm_power_down(struct v4l2_subdev *sd); -extern int drv201_t_focus_abs(struct v4l2_subdev *sd, s32 value); -extern int drv201_t_focus_rel(struct v4l2_subdev *sd, s32 value); -extern int drv201_q_focus_status(struct v4l2_subdev *sd, s32 *value); -extern int drv201_q_focus_abs(struct v4l2_subdev *sd, s32 *value); -extern int drv201_t_vcm_slew(struct v4l2_subdev *sd, s32 value); -extern int drv201_t_vcm_timing(struct v4l2_subdev *sd, s32 value); - -extern int dw9714_vcm_power_up(struct v4l2_subdev *sd); -extern int dw9714_vcm_power_down(struct v4l2_subdev *sd); -extern int dw9714_t_focus_abs(struct v4l2_subdev *sd, s32 value); -extern int dw9714_t_focus_abs_init(struct v4l2_subdev *sd); -extern int dw9714_t_focus_rel(struct v4l2_subdev *sd, s32 value); -extern int dw9714_q_focus_status(struct v4l2_subdev *sd, s32 *value); -extern int dw9714_q_focus_abs(struct v4l2_subdev *sd, s32 *value); -extern int dw9714_t_vcm_slew(struct v4l2_subdev *sd, s32 value); -extern int dw9714_t_vcm_timing(struct v4l2_subdev *sd, s32 value); - -extern int dw9719_vcm_power_up(struct v4l2_subdev *sd); -extern int dw9719_vcm_power_down(struct v4l2_subdev *sd); -extern int dw9719_t_focus_abs(struct v4l2_subdev *sd, s32 value); -extern int dw9719_t_focus_rel(struct v4l2_subdev *sd, s32 value); -extern int dw9719_q_focus_status(struct v4l2_subdev *sd, s32 *value); -extern int dw9719_q_focus_abs(struct v4l2_subdev *sd, s32 *value); -extern int dw9719_t_vcm_slew(struct v4l2_subdev *sd, s32 value); -extern int dw9719_t_vcm_timing(struct v4l2_subdev *sd, s32 value); - -extern int dw9718_vcm_power_up(struct v4l2_subdev *sd); -extern int dw9718_vcm_power_down(struct v4l2_subdev *sd); -extern int dw9718_t_focus_abs(struct v4l2_subdev *sd, s32 value); -extern int dw9718_t_focus_rel(struct v4l2_subdev *sd, s32 value); -extern int dw9718_q_focus_status(struct v4l2_subdev *sd, s32 *value); -extern int dw9718_q_focus_abs(struct v4l2_subdev *sd, s32 *value); -extern int dw9718_t_vcm_slew(struct v4l2_subdev *sd, s32 value); -extern int dw9718_t_vcm_timing(struct v4l2_subdev *sd, s32 value); - -extern int vcm_power_up(struct v4l2_subdev *sd); -extern int vcm_power_down(struct v4l2_subdev *sd); - -struct imx_vcm imx_vcms[] = { - [IMX175_MERRFLD] = { - .power_up = drv201_vcm_power_up, - .power_down = drv201_vcm_power_down, - .t_focus_abs = drv201_t_focus_abs, - .t_focus_abs_init = NULL, - .t_focus_rel = drv201_t_focus_rel, - .q_focus_status = drv201_q_focus_status, - .q_focus_abs = drv201_q_focus_abs, - .t_vcm_slew = drv201_t_vcm_slew, - .t_vcm_timing = drv201_t_vcm_timing, - }, - [IMX175_VALLEYVIEW] = { - .power_up = dw9714_vcm_power_up, - .power_down = dw9714_vcm_power_down, - .t_focus_abs = dw9714_t_focus_abs, - .t_focus_abs_init = NULL, - .t_focus_rel = dw9714_t_focus_rel, - .q_focus_status = dw9714_q_focus_status, - .q_focus_abs = dw9714_q_focus_abs, - .t_vcm_slew = dw9714_t_vcm_slew, - .t_vcm_timing = dw9714_t_vcm_timing, - }, - [IMX135_SALTBAY] = { - .power_up = ad5816g_vcm_power_up, - .power_down = ad5816g_vcm_power_down, - .t_focus_abs = ad5816g_t_focus_abs, - .t_focus_abs_init = NULL, - .t_focus_rel = ad5816g_t_focus_rel, - .q_focus_status = ad5816g_q_focus_status, - .q_focus_abs = ad5816g_q_focus_abs, - .t_vcm_slew = ad5816g_t_vcm_slew, - .t_vcm_timing = ad5816g_t_vcm_timing, - }, - [IMX135_VICTORIABAY] = { - .power_up = dw9719_vcm_power_up, - .power_down = dw9719_vcm_power_down, - .t_focus_abs = dw9719_t_focus_abs, - .t_focus_abs_init = NULL, - .t_focus_rel = dw9719_t_focus_rel, - .q_focus_status = dw9719_q_focus_status, - .q_focus_abs = dw9719_q_focus_abs, - .t_vcm_slew = dw9719_t_vcm_slew, - .t_vcm_timing = dw9719_t_vcm_timing, - }, - [IMX134_VALLEYVIEW] = { - .power_up = dw9714_vcm_power_up, - .power_down = dw9714_vcm_power_down, - .t_focus_abs = dw9714_t_focus_abs, - .t_focus_abs_init = dw9714_t_focus_abs_init, - .t_focus_rel = dw9714_t_focus_rel, - .q_focus_status = dw9714_q_focus_status, - .q_focus_abs = dw9714_q_focus_abs, - .t_vcm_slew = dw9714_t_vcm_slew, - .t_vcm_timing = dw9714_t_vcm_timing, - }, - [IMX219_MFV0_PRH] = { - .power_up = dw9718_vcm_power_up, - .power_down = dw9718_vcm_power_down, - .t_focus_abs = dw9718_t_focus_abs, - .t_focus_abs_init = NULL, - .t_focus_rel = dw9718_t_focus_rel, - .q_focus_status = dw9718_q_focus_status, - .q_focus_abs = dw9718_q_focus_abs, - .t_vcm_slew = dw9718_t_vcm_slew, - .t_vcm_timing = dw9718_t_vcm_timing, - }, - [IMX_ID_DEFAULT] = { - .power_up = NULL, - .power_down = NULL, - .t_focus_abs_init = NULL, - }, -}; - -extern void *dummy_otp_read(struct v4l2_subdev *sd, u8 dev_addr, - u32 start_addr, u32 size); -extern void *imx_otp_read(struct v4l2_subdev *sd, u8 dev_addr, - u32 start_addr, u32 size); -extern void *e2prom_otp_read(struct v4l2_subdev *sd, u8 dev_addr, - u32 start_addr, u32 size); -extern void *brcc064_otp_read(struct v4l2_subdev *sd, u8 dev_addr, - u32 start_addr, u32 size); -extern void *imx227_otp_read(struct v4l2_subdev *sd, u8 dev_addr, - u32 start_addr, u32 size); -extern void *e2prom_otp_read(struct v4l2_subdev *sd, u8 dev_addr, - u32 start_addr, u32 size); -struct imx_otp imx_otps[] = { - [IMX175_MERRFLD] = { - .otp_read = imx_otp_read, - .dev_addr = E2PROM_ADDR, - .start_addr = 0, - .size = DEFAULT_OTP_SIZE, - }, - [IMX175_VALLEYVIEW] = { - .otp_read = e2prom_otp_read, - .dev_addr = E2PROM_ABICO_SS89A839_ADDR, - .start_addr = E2PROM_2ADDR, - .size = DEFAULT_OTP_SIZE, - }, - [IMX135_SALTBAY] = { - .otp_read = e2prom_otp_read, - .dev_addr = E2PROM_ADDR, - .start_addr = 0, - .size = DEFAULT_OTP_SIZE, - }, - [IMX135_VICTORIABAY] = { - .otp_read = imx_otp_read, - .size = DEFAULT_OTP_SIZE, - }, - [IMX134_VALLEYVIEW] = { - .otp_read = e2prom_otp_read, - .dev_addr = E2PROM_LITEON_12P1BA869D_ADDR, - .start_addr = 0, - .size = E2PROM_LITEON_12P1BA869D_SIZE, - }, - [IMX132_SALTBAY] = { - .otp_read = dummy_otp_read, - .size = DEFAULT_OTP_SIZE, - }, - [IMX208_MOFD_PD2] = { - .otp_read = dummy_otp_read, - .size = DEFAULT_OTP_SIZE, - }, - [IMX219_MFV0_PRH] = { - .otp_read = brcc064_otp_read, - .dev_addr = E2PROM_ADDR, - .start_addr = 0, - .size = IMX219_OTP_SIZE, - }, - [IMX227_SAND] = { - .otp_read = imx227_otp_read, - .size = IMX227_OTP_SIZE, - }, - [IMX_ID_DEFAULT] = { - .otp_read = dummy_otp_read, - .size = DEFAULT_OTP_SIZE, - }, -}; - -#endif - diff --git a/drivers/staging/media/atomisp/i2c/imx/imx132.h b/drivers/staging/media/atomisp/i2c/imx/imx132.h deleted file mode 100644 index 98f047b8a1ba..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/imx132.h +++ /dev/null @@ -1,566 +0,0 @@ -/* - * Support for Sony IMX camera sensor. - * - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#ifndef __IMX132_H__ -#define __IMX132_H__ -#include "common.h" - -/********************** registers define ********************************/ -#define IMX132_RGLANESEL 0x3301 /* Number of lanes */ -#define IMX132_RGLANESEL_1LANE 0x01 -#define IMX132_RGLANESEL_2LANES 0x00 -#define IMX132_RGLANESEL_4LANES 0x03 - -#define IMX132_2LANES_GAINFACT 2096 /* 524/256 * 2^10 */ -#define IMX132_2LANES_GAINFACT_SHIFT 10 - -/********************** settings for imx from vendor*********************/ -static struct imx_reg imx132_1080p_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* Global Settings */ - {IMX_8BIT, 0x3087, 0x53}, - {IMX_8BIT, 0x308B, 0x5A}, - {IMX_8BIT, 0x3094, 0x11}, - {IMX_8BIT, 0x309D, 0xA4}, - {IMX_8BIT, 0x30AA, 0x01}, - {IMX_8BIT, 0x30C6, 0x00}, - {IMX_8BIT, 0x30C7, 0x00}, - {IMX_8BIT, 0x3118, 0x2F}, - {IMX_8BIT, 0x312A, 0x00}, - {IMX_8BIT, 0x312B, 0x0B}, - {IMX_8BIT, 0x312C, 0x0B}, - {IMX_8BIT, 0x312D, 0x13}, - /* PLL setting */ - {IMX_8BIT, 0x0305, 0x02}, - {IMX_8BIT, 0x0307, 0x50}, - {IMX_8BIT, 0x30A4, 0x02}, - {IMX_8BIT, 0x303C, 0x3C}, - /* Mode setting */ - {IMX_8BIT, 0x0344, 0x00}, - {IMX_8BIT, 0x0345, 0x14}, - {IMX_8BIT, 0x0346, 0x00}, - {IMX_8BIT, 0x0347, 0x32}, - {IMX_8BIT, 0x0348, 0x07}, - {IMX_8BIT, 0x0349, 0xA3}, - {IMX_8BIT, 0x034A, 0x04}, - {IMX_8BIT, 0x034B, 0x79}, - {IMX_8BIT, 0x034C, 0x07}, - {IMX_8BIT, 0x034D, 0x90}, - {IMX_8BIT, 0x034E, 0x04}, - {IMX_8BIT, 0x034F, 0x48}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x303D, 0x10}, - {IMX_8BIT, 0x303E, 0x5A}, - {IMX_8BIT, 0x3040, 0x00}, - {IMX_8BIT, 0x3041, 0x00}, - {IMX_8BIT, 0x3048, 0x00}, - {IMX_8BIT, 0x304C, 0x2F}, - {IMX_8BIT, 0x304D, 0x02}, - {IMX_8BIT, 0x3064, 0x92}, - {IMX_8BIT, 0x306A, 0x10}, - {IMX_8BIT, 0x309B, 0x00}, - {IMX_8BIT, 0x309E, 0x41}, - {IMX_8BIT, 0x30A0, 0x10}, - {IMX_8BIT, 0x30A1, 0x0B}, - {IMX_8BIT, 0x30B2, 0x00}, - {IMX_8BIT, 0x30D5, 0x00}, - {IMX_8BIT, 0x30D6, 0x00}, - {IMX_8BIT, 0x30D7, 0x00}, - {IMX_8BIT, 0x30D8, 0x00}, - {IMX_8BIT, 0x30D9, 0x00}, - {IMX_8BIT, 0x30DA, 0x00}, - {IMX_8BIT, 0x30DB, 0x00}, - {IMX_8BIT, 0x30DC, 0x00}, - {IMX_8BIT, 0x30DD, 0x00}, - {IMX_8BIT, 0x30DE, 0x00}, - {IMX_8BIT, 0x3102, 0x0C}, - {IMX_8BIT, 0x3103, 0x33}, - {IMX_8BIT, 0x3104, 0x18}, - {IMX_8BIT, 0x3105, 0x00}, - {IMX_8BIT, 0x3106, 0x65}, - {IMX_8BIT, 0x3107, 0x00}, - {IMX_8BIT, 0x3108, 0x06}, - {IMX_8BIT, 0x3109, 0x04}, - {IMX_8BIT, 0x310A, 0x04}, - {IMX_8BIT, 0x315C, 0x3D}, - {IMX_8BIT, 0x315D, 0x3C}, - {IMX_8BIT, 0x316E, 0x3E}, - {IMX_8BIT, 0x316F, 0x3D}, - /* Global timing */ - {IMX_8BIT, 0x3304, 0x07}, /* RGTLPX[5:0] TLPX */ - {IMX_8BIT, 0x3305, 0x06}, /* RGTCLKPREPARE[3:0] TCLK-PREPARE */ - {IMX_8BIT, 0x3306, 0x19}, /* RGTCLKZERO[5:0] TCLK-ZERO */ - {IMX_8BIT, 0x3307, 0x03}, /* RGTCLKPRE[5:0] TCLK-PRE */ - {IMX_8BIT, 0x3308, 0x0F}, /* RGTCLKPOST[5:0] TCLK-POST */ - {IMX_8BIT, 0x3309, 0x07}, /* RGTCLKTRAIL[3:0] TCLK-TRAIL */ - {IMX_8BIT, 0x330A, 0x0C}, /* RGTHSEXIT[5:0] THS-EXIT */ - {IMX_8BIT, 0x330B, 0x06}, /* RGTHSPREPARE[3:0] THS-PREPARE */ - {IMX_8BIT, 0x330C, 0x0B}, /* RGTHSZERO[5:0] THS-ZERO */ - {IMX_8BIT, 0x330D, 0x07}, /* RGTHSTRAIL[3:0] THS-TRAIL */ - {IMX_8BIT, 0x330E, 0x03}, - {IMX_8BIT, 0x3318, 0x62}, - {IMX_8BIT, 0x3322, 0x09}, - {IMX_8BIT, 0x3342, 0x00}, - {IMX_8BIT, 0x3348, 0xE0}, - - {IMX_TOK_TERM, 0, 0}, -}; - -static struct imx_reg imx132_1456x1096_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* Global Settings */ - {IMX_8BIT, 0x3087, 0x53}, - {IMX_8BIT, 0x308B, 0x5A}, - {IMX_8BIT, 0x3094, 0x11}, - {IMX_8BIT, 0x309D, 0xA4}, - {IMX_8BIT, 0x30AA, 0x01}, - {IMX_8BIT, 0x30C6, 0x00}, - {IMX_8BIT, 0x30C7, 0x00}, - {IMX_8BIT, 0x3118, 0x2F}, - {IMX_8BIT, 0x312A, 0x00}, - {IMX_8BIT, 0x312B, 0x0B}, - {IMX_8BIT, 0x312C, 0x0B}, - {IMX_8BIT, 0x312D, 0x13}, - /* PLL setting */ - {IMX_8BIT, 0x0305, 0x02}, - {IMX_8BIT, 0x0307, 0x50}, - {IMX_8BIT, 0x30A4, 0x02}, - {IMX_8BIT, 0x303C, 0x3C}, - /* Mode setting */ - {IMX_8BIT, 0x0344, 0x01}, - {IMX_8BIT, 0x0345, 0x04}, - {IMX_8BIT, 0x0346, 0x00}, - {IMX_8BIT, 0x0347, 0x32}, - {IMX_8BIT, 0x0348, 0x06}, - {IMX_8BIT, 0x0349, 0xB3}, - {IMX_8BIT, 0x034A, 0x04}, - {IMX_8BIT, 0x034B, 0x79}, - {IMX_8BIT, 0x034C, 0x05}, - {IMX_8BIT, 0x034D, 0xB0}, - {IMX_8BIT, 0x034E, 0x04}, - {IMX_8BIT, 0x034F, 0x48}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x303D, 0x10}, - {IMX_8BIT, 0x303E, 0x5A}, - {IMX_8BIT, 0x3040, 0x00}, - {IMX_8BIT, 0x3041, 0x00}, - {IMX_8BIT, 0x3048, 0x00}, - {IMX_8BIT, 0x304C, 0x2F}, - {IMX_8BIT, 0x304D, 0x02}, - {IMX_8BIT, 0x3064, 0x92}, - {IMX_8BIT, 0x306A, 0x10}, - {IMX_8BIT, 0x309B, 0x00}, - {IMX_8BIT, 0x309E, 0x41}, - {IMX_8BIT, 0x30A0, 0x10}, - {IMX_8BIT, 0x30A1, 0x0B}, - {IMX_8BIT, 0x30B2, 0x00}, - {IMX_8BIT, 0x30D5, 0x00}, - {IMX_8BIT, 0x30D6, 0x00}, - {IMX_8BIT, 0x30D7, 0x00}, - {IMX_8BIT, 0x30D8, 0x00}, - {IMX_8BIT, 0x30D9, 0x00}, - {IMX_8BIT, 0x30DA, 0x00}, - {IMX_8BIT, 0x30DB, 0x00}, - {IMX_8BIT, 0x30DC, 0x00}, - {IMX_8BIT, 0x30DD, 0x00}, - {IMX_8BIT, 0x30DE, 0x00}, - {IMX_8BIT, 0x3102, 0x0C}, - {IMX_8BIT, 0x3103, 0x33}, - {IMX_8BIT, 0x3104, 0x18}, - {IMX_8BIT, 0x3105, 0x00}, - {IMX_8BIT, 0x3106, 0x65}, - {IMX_8BIT, 0x3107, 0x00}, - {IMX_8BIT, 0x3108, 0x06}, - {IMX_8BIT, 0x3109, 0x04}, - {IMX_8BIT, 0x310A, 0x04}, - {IMX_8BIT, 0x315C, 0x3D}, - {IMX_8BIT, 0x315D, 0x3C}, - {IMX_8BIT, 0x316E, 0x3E}, - {IMX_8BIT, 0x316F, 0x3D}, - /* Global timing */ - {IMX_8BIT, 0x3304, 0x07}, /* RGTLPX[5:0] TLPX */ - {IMX_8BIT, 0x3305, 0x06}, /* RGTCLKPREPARE[3:0] TCLK-PREPARE */ - {IMX_8BIT, 0x3306, 0x19}, /* RGTCLKZERO[5:0] TCLK-ZERO */ - {IMX_8BIT, 0x3307, 0x03}, /* RGTCLKPRE[5:0] TCLK-PRE */ - {IMX_8BIT, 0x3308, 0x0F}, /* RGTCLKPOST[5:0] TCLK-POST */ - {IMX_8BIT, 0x3309, 0x07}, /* RGTCLKTRAIL[3:0] TCLK-TRAIL */ - {IMX_8BIT, 0x330A, 0x0C}, /* RGTHSEXIT[5:0] THS-EXIT */ - {IMX_8BIT, 0x330B, 0x06}, /* RGTHSPREPARE[3:0] THS-PREPARE */ - {IMX_8BIT, 0x330C, 0x0B}, /* RGTHSZERO[5:0] THS-ZERO */ - {IMX_8BIT, 0x330D, 0x07}, /* RGTHSTRAIL[3:0] THS-TRAIL */ - {IMX_8BIT, 0x330E, 0x03}, - {IMX_8BIT, 0x3318, 0x62}, - {IMX_8BIT, 0x3322, 0x09}, - {IMX_8BIT, 0x3342, 0x00}, - {IMX_8BIT, 0x3348, 0xE0}, - - {IMX_TOK_TERM, 0, 0}, -}; - -static struct imx_reg imx132_1636x1096_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* Global Settings */ - {IMX_8BIT, 0x3087, 0x53}, - {IMX_8BIT, 0x308B, 0x5A}, - {IMX_8BIT, 0x3094, 0x11}, - {IMX_8BIT, 0x309D, 0xA4}, - {IMX_8BIT, 0x30AA, 0x01}, - {IMX_8BIT, 0x30C6, 0x00}, - {IMX_8BIT, 0x30C7, 0x00}, - {IMX_8BIT, 0x3118, 0x2F}, - {IMX_8BIT, 0x312A, 0x00}, - {IMX_8BIT, 0x312B, 0x0B}, - {IMX_8BIT, 0x312C, 0x0B}, - {IMX_8BIT, 0x312D, 0x13}, - /* PLL setting */ - {IMX_8BIT, 0x0305, 0x02}, - {IMX_8BIT, 0x0307, 0x50}, - {IMX_8BIT, 0x30A4, 0x02}, - {IMX_8BIT, 0x303C, 0x3C}, - /* Mode setting */ - {IMX_8BIT, 0x0344, 0x00}, - {IMX_8BIT, 0x0345, 0xAA}, - {IMX_8BIT, 0x0346, 0x00}, - {IMX_8BIT, 0x0347, 0x32}, - {IMX_8BIT, 0x0348, 0x07}, - {IMX_8BIT, 0x0349, 0x0D}, - {IMX_8BIT, 0x034A, 0x04}, - {IMX_8BIT, 0x034B, 0x79}, - {IMX_8BIT, 0x034C, 0x06}, - {IMX_8BIT, 0x034D, 0x64}, - {IMX_8BIT, 0x034E, 0x04}, - {IMX_8BIT, 0x034F, 0x48}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x303D, 0x10}, - {IMX_8BIT, 0x303E, 0x5A}, - {IMX_8BIT, 0x3040, 0x00}, - {IMX_8BIT, 0x3041, 0x00}, - {IMX_8BIT, 0x3048, 0x00}, - {IMX_8BIT, 0x304C, 0x2F}, - {IMX_8BIT, 0x304D, 0x02}, - {IMX_8BIT, 0x3064, 0x92}, - {IMX_8BIT, 0x306A, 0x10}, - {IMX_8BIT, 0x309B, 0x00}, - {IMX_8BIT, 0x309E, 0x41}, - {IMX_8BIT, 0x30A0, 0x10}, - {IMX_8BIT, 0x30A1, 0x0B}, - {IMX_8BIT, 0x30B2, 0x00}, - {IMX_8BIT, 0x30D5, 0x00}, - {IMX_8BIT, 0x30D6, 0x00}, - {IMX_8BIT, 0x30D7, 0x00}, - {IMX_8BIT, 0x30D8, 0x00}, - {IMX_8BIT, 0x30D9, 0x00}, - {IMX_8BIT, 0x30DA, 0x00}, - {IMX_8BIT, 0x30DB, 0x00}, - {IMX_8BIT, 0x30DC, 0x00}, - {IMX_8BIT, 0x30DD, 0x00}, - {IMX_8BIT, 0x30DE, 0x00}, - {IMX_8BIT, 0x3102, 0x0C}, - {IMX_8BIT, 0x3103, 0x33}, - {IMX_8BIT, 0x3104, 0x18}, - {IMX_8BIT, 0x3105, 0x00}, - {IMX_8BIT, 0x3106, 0x65}, - {IMX_8BIT, 0x3107, 0x00}, - {IMX_8BIT, 0x3108, 0x06}, - {IMX_8BIT, 0x3109, 0x04}, - {IMX_8BIT, 0x310A, 0x04}, - {IMX_8BIT, 0x315C, 0x3D}, - {IMX_8BIT, 0x315D, 0x3C}, - {IMX_8BIT, 0x316E, 0x3E}, - {IMX_8BIT, 0x316F, 0x3D}, - /* Global timing */ - {IMX_8BIT, 0x3304, 0x07}, /* RGTLPX[5:0] TLPX */ - {IMX_8BIT, 0x3305, 0x06}, /* RGTCLKPREPARE[3:0] TCLK-PREPARE */ - {IMX_8BIT, 0x3306, 0x19}, /* RGTCLKZERO[5:0] TCLK-ZERO */ - {IMX_8BIT, 0x3307, 0x03}, /* RGTCLKPRE[5:0] TCLK-PRE */ - {IMX_8BIT, 0x3308, 0x0F}, /* RGTCLKPOST[5:0] TCLK-POST */ - {IMX_8BIT, 0x3309, 0x07}, /* RGTCLKTRAIL[3:0] TCLK-TRAIL */ - {IMX_8BIT, 0x330A, 0x0C}, /* RGTHSEXIT[5:0] THS-EXIT */ - {IMX_8BIT, 0x330B, 0x06}, /* RGTHSPREPARE[3:0] THS-PREPARE */ - {IMX_8BIT, 0x330C, 0x0B}, /* RGTHSZERO[5:0] THS-ZERO */ - {IMX_8BIT, 0x330D, 0x07}, /* RGTHSTRAIL[3:0] THS-TRAIL */ - {IMX_8BIT, 0x330E, 0x03}, - {IMX_8BIT, 0x3318, 0x62}, - {IMX_8BIT, 0x3322, 0x09}, - {IMX_8BIT, 0x3342, 0x00}, - {IMX_8BIT, 0x3348, 0xE0}, - - {IMX_TOK_TERM, 0, 0}, -}; - -static struct imx_reg imx132_1336x1096_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* Global Settings */ - {IMX_8BIT, 0x3087, 0x53}, - {IMX_8BIT, 0x308B, 0x5A}, - {IMX_8BIT, 0x3094, 0x11}, - {IMX_8BIT, 0x309D, 0xA4}, - {IMX_8BIT, 0x30AA, 0x01}, - {IMX_8BIT, 0x30C6, 0x00}, - {IMX_8BIT, 0x30C7, 0x00}, - {IMX_8BIT, 0x3118, 0x2F}, - {IMX_8BIT, 0x312A, 0x00}, - {IMX_8BIT, 0x312B, 0x0B}, - {IMX_8BIT, 0x312C, 0x0B}, - {IMX_8BIT, 0x312D, 0x13}, - /* PLL setting */ - {IMX_8BIT, 0x0305, 0x02}, - {IMX_8BIT, 0x0307, 0x50}, - {IMX_8BIT, 0x30A4, 0x02}, - {IMX_8BIT, 0x303C, 0x3C}, - /* Mode setting */ - {IMX_8BIT, 0x0344, 0x01}, - {IMX_8BIT, 0x0345, 0x2C}, - {IMX_8BIT, 0x0346, 0x00}, - {IMX_8BIT, 0x0347, 0x32}, - {IMX_8BIT, 0x0348, 0x06}, - {IMX_8BIT, 0x0349, 0x77}, - {IMX_8BIT, 0x034A, 0x04}, - {IMX_8BIT, 0x034B, 0x79}, - {IMX_8BIT, 0x034C, 0x05}, - {IMX_8BIT, 0x034D, 0x38}, - {IMX_8BIT, 0x034E, 0x04}, - {IMX_8BIT, 0x034F, 0x48}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x303D, 0x10}, - {IMX_8BIT, 0x303E, 0x5A}, - {IMX_8BIT, 0x3040, 0x00}, - {IMX_8BIT, 0x3041, 0x00}, - {IMX_8BIT, 0x3048, 0x00}, - {IMX_8BIT, 0x304C, 0x2F}, - {IMX_8BIT, 0x304D, 0x02}, - {IMX_8BIT, 0x3064, 0x92}, - {IMX_8BIT, 0x306A, 0x10}, - {IMX_8BIT, 0x309B, 0x00}, - {IMX_8BIT, 0x309E, 0x41}, - {IMX_8BIT, 0x30A0, 0x10}, - {IMX_8BIT, 0x30A1, 0x0B}, - {IMX_8BIT, 0x30B2, 0x00}, - {IMX_8BIT, 0x30D5, 0x00}, - {IMX_8BIT, 0x30D6, 0x00}, - {IMX_8BIT, 0x30D7, 0x00}, - {IMX_8BIT, 0x30D8, 0x00}, - {IMX_8BIT, 0x30D9, 0x00}, - {IMX_8BIT, 0x30DA, 0x00}, - {IMX_8BIT, 0x30DB, 0x00}, - {IMX_8BIT, 0x30DC, 0x00}, - {IMX_8BIT, 0x30DD, 0x00}, - {IMX_8BIT, 0x30DE, 0x00}, - {IMX_8BIT, 0x3102, 0x0C}, - {IMX_8BIT, 0x3103, 0x33}, - {IMX_8BIT, 0x3104, 0x18}, - {IMX_8BIT, 0x3105, 0x00}, - {IMX_8BIT, 0x3106, 0x65}, - {IMX_8BIT, 0x3107, 0x00}, - {IMX_8BIT, 0x3108, 0x06}, - {IMX_8BIT, 0x3109, 0x04}, - {IMX_8BIT, 0x310A, 0x04}, - {IMX_8BIT, 0x315C, 0x3D}, - {IMX_8BIT, 0x315D, 0x3C}, - {IMX_8BIT, 0x316E, 0x3E}, - {IMX_8BIT, 0x316F, 0x3D}, - /* Global timing */ - {IMX_8BIT, 0x3304, 0x07}, /* RGTLPX[5:0] TLPX */ - {IMX_8BIT, 0x3305, 0x06}, /* RGTCLKPREPARE[3:0] TCLK-PREPARE */ - {IMX_8BIT, 0x3306, 0x19}, /* RGTCLKZERO[5:0] TCLK-ZERO */ - {IMX_8BIT, 0x3307, 0x03}, /* RGTCLKPRE[5:0] TCLK-PRE */ - {IMX_8BIT, 0x3308, 0x0F}, /* RGTCLKPOST[5:0] TCLK-POST */ - {IMX_8BIT, 0x3309, 0x07}, /* RGTCLKTRAIL[3:0] TCLK-TRAIL */ - {IMX_8BIT, 0x330A, 0x0C}, /* RGTHSEXIT[5:0] THS-EXIT */ - {IMX_8BIT, 0x330B, 0x06}, /* RGTHSPREPARE[3:0] THS-PREPARE */ - {IMX_8BIT, 0x330C, 0x0B}, /* RGTHSZERO[5:0] THS-ZERO */ - {IMX_8BIT, 0x330D, 0x07}, /* RGTHSTRAIL[3:0] THS-TRAIL */ - {IMX_8BIT, 0x330E, 0x03}, - {IMX_8BIT, 0x3318, 0x62}, - {IMX_8BIT, 0x3322, 0x09}, - {IMX_8BIT, 0x3342, 0x00}, - {IMX_8BIT, 0x3348, 0xE0}, - - {IMX_TOK_TERM, 0, 0}, -}; - -/********************** settings for imx - reference *********************/ -static struct imx_reg const imx132_init_settings[] = { - /* sw reset */ - { IMX_8BIT, 0x0100, 0x00 }, - { IMX_8BIT, 0x0103, 0x01 }, - { IMX_TOK_DELAY, 0, 5}, - { IMX_8BIT, 0x0103, 0x00 }, - GROUPED_PARAMETER_HOLD_ENABLE, - /* Global Settings */ - {IMX_8BIT, 0x3087, 0x53}, - {IMX_8BIT, 0x308B, 0x5A}, - {IMX_8BIT, 0x3094, 0x11}, - {IMX_8BIT, 0x309D, 0xA4}, - {IMX_8BIT, 0x30AA, 0x01}, - {IMX_8BIT, 0x30C6, 0x00}, - {IMX_8BIT, 0x30C7, 0x00}, - {IMX_8BIT, 0x3118, 0x2F}, - {IMX_8BIT, 0x312A, 0x00}, - {IMX_8BIT, 0x312B, 0x0B}, - {IMX_8BIT, 0x312C, 0x0B}, - {IMX_8BIT, 0x312D, 0x13}, - GROUPED_PARAMETER_HOLD_DISABLE, - { IMX_TOK_TERM, 0, 0} -}; - -struct imx_resolution imx132_res_preview[] = { - { - .desc = "imx132_1080p_30fps", - .regs = imx132_1080p_30fps, - .width = 1936, - .height = 1096, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08F2, - .lines_per_frame = 0x045C, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .skip_frames = 2, - .mipi_freq = 384000, - }, -}; - -struct imx_resolution imx132_res_still[] = { - { - .desc = "imx132_1080p_30fps", - .regs = imx132_1080p_30fps, - .width = 1936, - .height = 1096, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08F2, - .lines_per_frame = 0x045C, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .skip_frames = 2, - .mipi_freq = 384000, - }, -}; - -struct imx_resolution imx132_res_video[] = { - { - .desc = "imx132_1336x1096_30fps", - .regs = imx132_1336x1096_30fps, - .width = 1336, - .height = 1096, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08F2, - .lines_per_frame = 0x045C, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .skip_frames = 2, - .mipi_freq = 384000, - }, - { - .desc = "imx132_1456x1096_30fps", - .regs = imx132_1456x1096_30fps, - .width = 1456, - .height = 1096, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08F2, - .lines_per_frame = 0x045C, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .skip_frames = 2, - .mipi_freq = 384000, - }, - { - .desc = "imx132_1636x1096_30fps", - .regs = imx132_1636x1096_30fps, - .width = 1636, - .height = 1096, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08F2, - .lines_per_frame = 0x045C, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .skip_frames = 2, - .mipi_freq = 384000, - }, - { - .desc = "imx132_1080p_30fps", - .regs = imx132_1080p_30fps, - .width = 1936, - .height = 1096, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08F2, - .lines_per_frame = 0x045C, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .skip_frames = 2, - .mipi_freq = 384000, - }, -}; -#endif - diff --git a/drivers/staging/media/atomisp/i2c/imx/imx134.h b/drivers/staging/media/atomisp/i2c/imx/imx134.h deleted file mode 100644 index cf35197ed77f..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/imx134.h +++ /dev/null @@ -1,2464 +0,0 @@ -#ifndef __IMX134_H__ -#define __IMX134_H__ - -/********************** imx134 setting - version 1 *********************/ -static struct imx_reg const imx134_init_settings[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* Basic settings */ - { IMX_8BIT, 0x0105, 0x01 }, - { IMX_8BIT, 0x0220, 0x01 }, - { IMX_8BIT, 0x3302, 0x11 }, - { IMX_8BIT, 0x3833, 0x20 }, - { IMX_8BIT, 0x3893, 0x00 }, - { IMX_8BIT, 0x3906, 0x08 }, - { IMX_8BIT, 0x3907, 0x01 }, - { IMX_8BIT, 0x391B, 0x01 }, - { IMX_8BIT, 0x3C09, 0x01 }, - { IMX_8BIT, 0x600A, 0x00 }, - - /* Analog settings */ - { IMX_8BIT, 0x3008, 0xB0 }, - { IMX_8BIT, 0x320A, 0x01 }, - { IMX_8BIT, 0x320D, 0x10 }, - { IMX_8BIT, 0x3216, 0x2E }, - { IMX_8BIT, 0x322C, 0x02 }, - { IMX_8BIT, 0x3409, 0x0C }, - { IMX_8BIT, 0x340C, 0x2D }, - { IMX_8BIT, 0x3411, 0x39 }, - { IMX_8BIT, 0x3414, 0x1E }, - { IMX_8BIT, 0x3427, 0x04 }, - { IMX_8BIT, 0x3480, 0x1E }, - { IMX_8BIT, 0x3484, 0x1E }, - { IMX_8BIT, 0x3488, 0x1E }, - { IMX_8BIT, 0x348C, 0x1E }, - { IMX_8BIT, 0x3490, 0x1E }, - { IMX_8BIT, 0x3494, 0x1E }, - { IMX_8BIT, 0x3511, 0x8F }, - { IMX_8BIT, 0x3617, 0x2D }, - - GROUPED_PARAMETER_HOLD_DISABLE, - { IMX_TOK_TERM, 0, 0 } -}; - -/* 4 lane 3280x2464 8M 30fps, vendor provide */ -static struct imx_reg const imx134_8M_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* mode set clear */ - { IMX_8BIT, 0x3A43, 0x01 }, - /* clock setting */ - { IMX_8BIT, 0x011E, 0x13 }, - { IMX_8BIT, 0x011F, 0x33 }, - { IMX_8BIT, 0x0301, 0x05 }, - { IMX_8BIT, 0x0303, 0x01 }, - { IMX_8BIT, 0x0305, 0x0C }, - { IMX_8BIT, 0x0309, 0x05 }, - { IMX_8BIT, 0x030B, 0x01 }, - { IMX_8BIT, 0x030C, 0x01 }, - { IMX_8BIT, 0x030D, 0xA9 }, - { IMX_8BIT, 0x030E, 0x01 }, - { IMX_8BIT, 0x3A06, 0x11 }, - - /* Mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x00 }, - { IMX_8BIT, 0x0391, 0x11 }, - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x00 }, - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x10 }, /* down scaling 16/16 = 1 */ - { IMX_8BIT, 0x4082, 0x01 }, - { IMX_8BIT, 0x4083, 0x01 }, - { IMX_8BIT, 0x7006, 0x04 }, - - /* optionnal Function setting */ - { IMX_8BIT, 0x0700, 0x00 }, - { IMX_8BIT, 0x3A63, 0x00 }, - { IMX_8BIT, 0x4100, 0xF8 }, - { IMX_8BIT, 0x4203, 0xFF }, - { IMX_8BIT, 0x4344, 0x00 }, - { IMX_8BIT, 0x441C, 0x01 }, - - /* Size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* x_addr_start[15:8]:0 */ - { IMX_8BIT, 0x0345, 0x00 }, /* x_addr_start[7:0] */ - { IMX_8BIT, 0x0346, 0x00 }, /* y_addr_start[15:8]:0 */ - { IMX_8BIT, 0x0347, 0x00 }, /* y_addr_start[7:0] */ - { IMX_8BIT, 0x0348, 0x0C }, /* x_addr_end[15:8]:3279 */ - { IMX_8BIT, 0x0349, 0xCF }, /* x_addr_end[7:0] */ - { IMX_8BIT, 0x034A, 0x09 }, /* y_addr_end[15:8]:2463 */ - { IMX_8BIT, 0x034B, 0x9F }, /* y_addr_end[7:0] */ - { IMX_8BIT, 0x034C, 0x0C }, /* x_output_size[15:8]: 3280*/ - { IMX_8BIT, 0x034D, 0xD0 }, /* x_output_size[7:0] */ - { IMX_8BIT, 0x034E, 0x09 }, /* y_output_size[15:8]:2464 */ - { IMX_8BIT, 0x034F, 0xA0 }, /* y_output_size[7:0] */ - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x0C }, - { IMX_8BIT, 0x0355, 0xD0 }, - { IMX_8BIT, 0x0356, 0x09 }, - { IMX_8BIT, 0x0357, 0xA0 }, - { IMX_8BIT, 0x301D, 0x30 }, - { IMX_8BIT, 0x3310, 0x0C }, - { IMX_8BIT, 0x3311, 0xD0 }, - { IMX_8BIT, 0x3312, 0x09 }, - { IMX_8BIT, 0x3313, 0xA0 }, - { IMX_8BIT, 0x331C, 0x01 }, - { IMX_8BIT, 0x331D, 0xAE }, - { IMX_8BIT, 0x4084, 0x00 }, - { IMX_8BIT, 0x4085, 0x00 }, - { IMX_8BIT, 0x4086, 0x00 }, - { IMX_8BIT, 0x4087, 0x00 }, - { IMX_8BIT, 0x4400, 0x00 }, - - /* Global timing setting */ - { IMX_8BIT, 0x0830, 0x77 }, - { IMX_8BIT, 0x0831, 0x2F }, - { IMX_8BIT, 0x0832, 0x4F }, - { IMX_8BIT, 0x0833, 0x37 }, - { IMX_8BIT, 0x0834, 0x2F }, - { IMX_8BIT, 0x0835, 0x37 }, - { IMX_8BIT, 0x0836, 0xAF }, - { IMX_8BIT, 0x0837, 0x37 }, - { IMX_8BIT, 0x0839, 0x1F }, - { IMX_8BIT, 0x083A, 0x17 }, - { IMX_8BIT, 0x083B, 0x02 }, - - /* Integration time setting */ - { IMX_8BIT, 0x0202, 0x09 }, - { IMX_8BIT, 0x0203, 0xD2 }, - - /* HDR setting */ - { IMX_8BIT, 0x0230, 0x00 }, - { IMX_8BIT, 0x0231, 0x00 }, - { IMX_8BIT, 0x0233, 0x00 }, - { IMX_8BIT, 0x0234, 0x00 }, - { IMX_8BIT, 0x0235, 0x40 }, - { IMX_8BIT, 0x0238, 0x00 }, - { IMX_8BIT, 0x0239, 0x04 }, - { IMX_8BIT, 0x023B, 0x00 }, - { IMX_8BIT, 0x023C, 0x01 }, - { IMX_8BIT, 0x33B0, 0x04 }, - { IMX_8BIT, 0x33B1, 0x00 }, - { IMX_8BIT, 0x33B3, 0x00 }, - { IMX_8BIT, 0x33B4, 0x01 }, - { IMX_8BIT, 0x3800, 0x00 }, - { IMX_TOK_TERM, 0, 0 } -}; - -/* 4 lane, 1/2 binning 30fps 1640x1232, vendor provide */ -static struct imx_reg const imx134_1640_1232_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* mode set clear */ - { IMX_8BIT, 0x3A43, 0x01 }, - /* Clock Setting */ - { IMX_8BIT, 0x011E, 0x13 }, - { IMX_8BIT, 0x011F, 0x33 }, - { IMX_8BIT, 0x0301, 0x05 }, - { IMX_8BIT, 0x0303, 0x01 }, - { IMX_8BIT, 0x0305, 0x0C }, - { IMX_8BIT, 0x0309, 0x05 }, - { IMX_8BIT, 0x030B, 0x01 }, - { IMX_8BIT, 0x030C, 0x01 }, - { IMX_8BIT, 0x030D, 0xA9 }, - { IMX_8BIT, 0x030E, 0x01 }, - { IMX_8BIT, 0x3A06, 0x11 }, - - /* Mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x01 }, /* binning */ - { IMX_8BIT, 0x0391, 0x22 }, /* 2x2 binning */ - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x00 }, /* no resize */ - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x10 }, - { IMX_8BIT, 0x4082, 0x01 }, - { IMX_8BIT, 0x4083, 0x01 }, - { IMX_8BIT, 0x7006, 0x04 }, - - /* Optionnal Function setting */ - { IMX_8BIT, 0x0700, 0x00 }, - { IMX_8BIT, 0x3A63, 0x00 }, - { IMX_8BIT, 0x4100, 0xF8 }, - { IMX_8BIT, 0x4203, 0xFF }, - { IMX_8BIT, 0x4344, 0x00 }, - { IMX_8BIT, 0x441C, 0x01 }, - - /* Size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* x_addr_start[15:8]:0 */ - { IMX_8BIT, 0x0345, 0x00 }, /* x_addr_start[7:0] */ - { IMX_8BIT, 0x0346, 0x00 }, /* y_addr_start[15:8]:0 */ - { IMX_8BIT, 0x0347, 0x00 }, /* y_addr_start[7:0] */ - { IMX_8BIT, 0x0348, 0x0C }, /* x_addr_end[15:8]:3279 */ - { IMX_8BIT, 0x0349, 0xCF }, /* x_addr_end[7:0] */ - { IMX_8BIT, 0x034A, 0x09 }, /* y_addr_end[15:8]:2463 */ - { IMX_8BIT, 0x034B, 0x9F }, /* y_addr_end[7:0] */ - { IMX_8BIT, 0x034C, 0x06 }, /* x_output_size[15:8]:1640 */ - { IMX_8BIT, 0x034D, 0x68 }, /* x_output_size[7:0] */ - { IMX_8BIT, 0x034E, 0x04 }, /* y_output_size[15:8]:1232 */ - { IMX_8BIT, 0x034F, 0xD0 }, /* y_output_size[7:0] */ - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x06 }, - { IMX_8BIT, 0x0355, 0x68 }, - { IMX_8BIT, 0x0356, 0x04 }, - { IMX_8BIT, 0x0357, 0xD0 }, - - { IMX_8BIT, 0x301D, 0x30 }, - - { IMX_8BIT, 0x3310, 0x06 }, - { IMX_8BIT, 0x3311, 0x68 }, - { IMX_8BIT, 0x3312, 0x04 }, - { IMX_8BIT, 0x3313, 0xD0 }, - - { IMX_8BIT, 0x331C, 0x04 }, - { IMX_8BIT, 0x331D, 0x06 }, - { IMX_8BIT, 0x4084, 0x00 }, - { IMX_8BIT, 0x4085, 0x00 }, - { IMX_8BIT, 0x4086, 0x00 }, - { IMX_8BIT, 0x4087, 0x00 }, - { IMX_8BIT, 0x4400, 0x00 }, - - /* Global Timing Setting */ - { IMX_8BIT, 0x0830, 0x77 }, - { IMX_8BIT, 0x0831, 0x2F }, - { IMX_8BIT, 0x0832, 0x4F }, - { IMX_8BIT, 0x0833, 0x37 }, - { IMX_8BIT, 0x0834, 0x2F }, - { IMX_8BIT, 0x0835, 0x37 }, - { IMX_8BIT, 0x0836, 0xAF }, - { IMX_8BIT, 0x0837, 0x37 }, - { IMX_8BIT, 0x0839, 0x1F }, - { IMX_8BIT, 0x083A, 0x17 }, - { IMX_8BIT, 0x083B, 0x02 }, - - /* Integration Time Setting */ - { IMX_8BIT, 0x0202, 0x09 }, - { IMX_8BIT, 0x0203, 0xD2 }, - - /* HDR Setting */ - { IMX_8BIT, 0x0230, 0x00 }, - { IMX_8BIT, 0x0231, 0x00 }, - { IMX_8BIT, 0x0233, 0x00 }, - { IMX_8BIT, 0x0234, 0x00 }, - { IMX_8BIT, 0x0235, 0x40 }, - { IMX_8BIT, 0x0238, 0x00 }, - { IMX_8BIT, 0x0239, 0x04 }, - { IMX_8BIT, 0x023B, 0x00 }, - { IMX_8BIT, 0x023C, 0x01 }, - { IMX_8BIT, 0x33B0, 0x04 }, - { IMX_8BIT, 0x33B1, 0x00 }, - { IMX_8BIT, 0x33B3, 0x00 }, - { IMX_8BIT, 0x33B4, 0x01 }, - { IMX_8BIT, 0x3800, 0x00 }, - { IMX_TOK_TERM, 0, 0 } -}; - -/* 4 lane, 1/4 binning 30fps 820x616, vendor provide */ -static struct imx_reg const imx134_820_616_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* mode set clear */ - { IMX_8BIT, 0x3A43, 0x01 }, - /* Clock Setting */ - { IMX_8BIT, 0x011E, 0x13 }, - { IMX_8BIT, 0x011F, 0x33 }, - { IMX_8BIT, 0x0301, 0x05 }, - { IMX_8BIT, 0x0303, 0x01 }, - { IMX_8BIT, 0x0305, 0x0C }, - { IMX_8BIT, 0x0309, 0x05 }, - { IMX_8BIT, 0x030B, 0x01 }, - { IMX_8BIT, 0x030C, 0x01 }, - { IMX_8BIT, 0x030D, 0xA9 }, - { IMX_8BIT, 0x030E, 0x01 }, - { IMX_8BIT, 0x3A06, 0x11 }, - - /* Mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x01 }, /* binning */ - { IMX_8BIT, 0x0391, 0x44 }, /* 4x4 binning */ - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x00 }, /* no resize */ - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x10 }, - { IMX_8BIT, 0x4082, 0x01 }, - { IMX_8BIT, 0x4083, 0x01 }, - { IMX_8BIT, 0x7006, 0x04 }, - - /* Optionnal Function setting */ - { IMX_8BIT, 0x0700, 0x00 }, - { IMX_8BIT, 0x3A63, 0x00 }, - { IMX_8BIT, 0x4100, 0xF8 }, - { IMX_8BIT, 0x4203, 0xFF }, - { IMX_8BIT, 0x4344, 0x00 }, - { IMX_8BIT, 0x441C, 0x01 }, - - /* Size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* x_addr_start[15:8]:0 */ - { IMX_8BIT, 0x0345, 0x00 }, /* x_addr_start[7:0] */ - { IMX_8BIT, 0x0346, 0x00 }, /* y_addr_start[15:8]:0 */ - { IMX_8BIT, 0x0347, 0x00 }, /* y_addr_start[7:0] */ - { IMX_8BIT, 0x0348, 0x0C }, /* x_addr_end[15:8]:3279 */ - { IMX_8BIT, 0x0349, 0xCF }, /* x_addr_end[7:0] */ - { IMX_8BIT, 0x034A, 0x09 }, /* y_addr_end[15:8]:2463 */ - { IMX_8BIT, 0x034B, 0x9F }, /* y_addr_end[7:0] */ - { IMX_8BIT, 0x034C, 0x03 }, /* x_output_size[15:8]:820 */ - { IMX_8BIT, 0x034D, 0x34 }, /* x_output_size[7:0] */ - { IMX_8BIT, 0x034E, 0x02 }, /* y_output_size[15:8]:616 */ - { IMX_8BIT, 0x034F, 0x68 }, /* y_output_size[7:0] */ - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x03 }, - { IMX_8BIT, 0x0355, 0x34 }, - { IMX_8BIT, 0x0356, 0x02 }, - { IMX_8BIT, 0x0357, 0x68 }, - { IMX_8BIT, 0x301D, 0x30 }, - { IMX_8BIT, 0x3310, 0x03 }, - { IMX_8BIT, 0x3311, 0x34 }, - { IMX_8BIT, 0x3312, 0x02 }, - { IMX_8BIT, 0x3313, 0x68 }, - { IMX_8BIT, 0x331C, 0x02 }, - { IMX_8BIT, 0x331D, 0xD0 }, - { IMX_8BIT, 0x4084, 0x00 }, - { IMX_8BIT, 0x4085, 0x00 }, - { IMX_8BIT, 0x4086, 0x00 }, - { IMX_8BIT, 0x4087, 0x00 }, - { IMX_8BIT, 0x4400, 0x00 }, - - /* Global Timing Setting */ - { IMX_8BIT, 0x0830, 0x77 }, - { IMX_8BIT, 0x0831, 0x2F }, - { IMX_8BIT, 0x0832, 0x4F }, - { IMX_8BIT, 0x0833, 0x37 }, - { IMX_8BIT, 0x0834, 0x2F }, - { IMX_8BIT, 0x0835, 0x37 }, - { IMX_8BIT, 0x0836, 0xAF }, - { IMX_8BIT, 0x0837, 0x37 }, - { IMX_8BIT, 0x0839, 0x1F }, - { IMX_8BIT, 0x083A, 0x17 }, - { IMX_8BIT, 0x083B, 0x02 }, - - /* Integration Time Setting */ - { IMX_8BIT, 0x0202, 0x09 }, - { IMX_8BIT, 0x0203, 0xD2 }, - - /* HDR Setting */ - { IMX_8BIT, 0x0230, 0x00 }, - { IMX_8BIT, 0x0231, 0x00 }, - { IMX_8BIT, 0x0233, 0x00 }, - { IMX_8BIT, 0x0234, 0x00 }, - { IMX_8BIT, 0x0235, 0x40 }, - { IMX_8BIT, 0x0238, 0x00 }, - { IMX_8BIT, 0x0239, 0x04 }, - { IMX_8BIT, 0x023B, 0x00 }, - { IMX_8BIT, 0x023C, 0x01 }, - { IMX_8BIT, 0x33B0, 0x04 }, - { IMX_8BIT, 0x33B1, 0x00 }, - { IMX_8BIT, 0x33B3, 0x00 }, - { IMX_8BIT, 0x33B4, 0x01 }, - { IMX_8BIT, 0x3800, 0x00 }, - { IMX_TOK_TERM, 0, 0 } -}; - -/* 4 lane, 1/4 binning 30fps 820x552 */ -static struct imx_reg const imx134_820_552_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* mode set clear */ - { IMX_8BIT, 0x3A43, 0x01 }, - /* Clock Setting */ - { IMX_8BIT, 0x011E, 0x13 }, - { IMX_8BIT, 0x011F, 0x33 }, - { IMX_8BIT, 0x0301, 0x05 }, - { IMX_8BIT, 0x0303, 0x01 }, - { IMX_8BIT, 0x0305, 0x0C }, - { IMX_8BIT, 0x0309, 0x05 }, - { IMX_8BIT, 0x030B, 0x01 }, - { IMX_8BIT, 0x030C, 0x01 }, - { IMX_8BIT, 0x030D, 0xA9 }, - { IMX_8BIT, 0x030E, 0x01 }, - { IMX_8BIT, 0x3A06, 0x11 }, - - /* Mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x01 }, /* binning */ - { IMX_8BIT, 0x0391, 0x44 }, /* 4x4 binning */ - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x00 }, /* no resize */ - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x10 }, - { IMX_8BIT, 0x4082, 0x01 }, - { IMX_8BIT, 0x4083, 0x01 }, - { IMX_8BIT, 0x7006, 0x04 }, - - /* Optionnal Function setting */ - { IMX_8BIT, 0x0700, 0x00 }, - { IMX_8BIT, 0x3A63, 0x00 }, - { IMX_8BIT, 0x4100, 0xF8 }, - { IMX_8BIT, 0x4203, 0xFF }, - { IMX_8BIT, 0x4344, 0x00 }, - { IMX_8BIT, 0x441C, 0x01 }, - - /* Size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* x_addr_start[15:8]:0 */ - { IMX_8BIT, 0x0345, 0x00 }, /* x_addr_start[7:0] */ - { IMX_8BIT, 0x0346, 0x00 }, /* y_addr_start[15:8]:128 */ - { IMX_8BIT, 0x0347, 0x80 }, /* y_addr_start[7:0] */ - { IMX_8BIT, 0x0348, 0x0C }, /* x_addr_end[15:8]:3280-1 */ - { IMX_8BIT, 0x0349, 0xCF }, /* x_addr_end[7:0] */ - { IMX_8BIT, 0x034A, 0x09 }, /* y_addr_end[15:8]:2208+128-1 */ - { IMX_8BIT, 0x034B, 0x1F }, /* y_addr_end[7:0] */ - { IMX_8BIT, 0x034C, 0x03 }, /* x_output_size[15:8]: */ - { IMX_8BIT, 0x034D, 0x34 }, /* x_output_size[7:0] */ - { IMX_8BIT, 0x034E, 0x02 }, /* y_output_size[15:8]:616 */ - { IMX_8BIT, 0x034F, 0x28 }, /* y_output_size[7:0] */ - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x03 }, - { IMX_8BIT, 0x0355, 0x34 }, - { IMX_8BIT, 0x0356, 0x02 }, - { IMX_8BIT, 0x0357, 0x28 }, - { IMX_8BIT, 0x301D, 0x30 }, - { IMX_8BIT, 0x3310, 0x03 }, - { IMX_8BIT, 0x3311, 0x34 }, - { IMX_8BIT, 0x3312, 0x02 }, - { IMX_8BIT, 0x3313, 0x28 }, - { IMX_8BIT, 0x331C, 0x02 }, - { IMX_8BIT, 0x331D, 0xD0 }, - { IMX_8BIT, 0x4084, 0x00 }, - { IMX_8BIT, 0x4085, 0x00 }, - { IMX_8BIT, 0x4086, 0x00 }, - { IMX_8BIT, 0x4087, 0x00 }, - { IMX_8BIT, 0x4400, 0x00 }, - - /* Global Timing Setting */ - { IMX_8BIT, 0x0830, 0x77 }, - { IMX_8BIT, 0x0831, 0x2F }, - { IMX_8BIT, 0x0832, 0x4F }, - { IMX_8BIT, 0x0833, 0x37 }, - { IMX_8BIT, 0x0834, 0x2F }, - { IMX_8BIT, 0x0835, 0x37 }, - { IMX_8BIT, 0x0836, 0xAF }, - { IMX_8BIT, 0x0837, 0x37 }, - { IMX_8BIT, 0x0839, 0x1F }, - { IMX_8BIT, 0x083A, 0x17 }, - { IMX_8BIT, 0x083B, 0x02 }, - - /* Integration Time Setting */ - { IMX_8BIT, 0x0202, 0x09 }, - { IMX_8BIT, 0x0203, 0xD2 }, - - /* HDR Setting */ - { IMX_8BIT, 0x0230, 0x00 }, - { IMX_8BIT, 0x0231, 0x00 }, - { IMX_8BIT, 0x0233, 0x00 }, - { IMX_8BIT, 0x0234, 0x00 }, - { IMX_8BIT, 0x0235, 0x40 }, - { IMX_8BIT, 0x0238, 0x00 }, - { IMX_8BIT, 0x0239, 0x04 }, - { IMX_8BIT, 0x023B, 0x00 }, - { IMX_8BIT, 0x023C, 0x01 }, - { IMX_8BIT, 0x33B0, 0x04 }, - { IMX_8BIT, 0x33B1, 0x00 }, - { IMX_8BIT, 0x33B3, 0x00 }, - { IMX_8BIT, 0x33B4, 0x01 }, - { IMX_8BIT, 0x3800, 0x00 }, - { IMX_TOK_TERM, 0, 0 } -}; - -/* 4 lane, 1/4 binning 30fps 720x592 */ -static struct imx_reg const imx134_720_592_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* mode set clear */ - { IMX_8BIT, 0x3A43, 0x01 }, - /* Clock Setting */ - { IMX_8BIT, 0x011E, 0x13 }, - { IMX_8BIT, 0x011F, 0x33 }, - { IMX_8BIT, 0x0301, 0x05 }, - { IMX_8BIT, 0x0303, 0x01 }, - { IMX_8BIT, 0x0305, 0x0C }, - { IMX_8BIT, 0x0309, 0x05 }, - { IMX_8BIT, 0x030B, 0x01 }, - { IMX_8BIT, 0x030C, 0x01 }, - { IMX_8BIT, 0x030D, 0xA9 }, - { IMX_8BIT, 0x030E, 0x01 }, - { IMX_8BIT, 0x3A06, 0x11 }, - - /* Mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x01 }, /* binning */ - { IMX_8BIT, 0x0391, 0x44 }, /* 4x4 binning */ - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x00 }, /* no resize */ - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x10 }, - { IMX_8BIT, 0x4082, 0x01 }, - { IMX_8BIT, 0x4083, 0x01 }, - { IMX_8BIT, 0x7006, 0x04 }, - - /* Optionnal Function setting */ - { IMX_8BIT, 0x0700, 0x00 }, - { IMX_8BIT, 0x3A63, 0x00 }, - { IMX_8BIT, 0x4100, 0xF8 }, - { IMX_8BIT, 0x4203, 0xFF }, - { IMX_8BIT, 0x4344, 0x00 }, - { IMX_8BIT, 0x441C, 0x01 }, - - /* Size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* x_addr_start[15:8]:200 */ - { IMX_8BIT, 0x0345, 0xC8 }, /* x_addr_start[7:0] */ - { IMX_8BIT, 0x0346, 0x00 }, /* y_addr_start[15:8]:40 */ - { IMX_8BIT, 0x0347, 0x28 }, /* y_addr_start[7:0] */ - { IMX_8BIT, 0x0348, 0x0C }, /* x_addr_end[15:8]:2880+200-1 */ - { IMX_8BIT, 0x0349, 0x07 }, /* x_addr_end[7:0] */ - { IMX_8BIT, 0x034A, 0x09 }, /* y_addr_end[15:8]:2368+40-1 */ - { IMX_8BIT, 0x034B, 0x67 }, /* y_addr_end[7:0] */ - { IMX_8BIT, 0x034C, 0x02 }, /* x_output_size[15:8]: */ - { IMX_8BIT, 0x034D, 0xD0 }, /* x_output_size[7:0] */ - { IMX_8BIT, 0x034E, 0x02 }, /* y_output_size[15:8]:616 */ - { IMX_8BIT, 0x034F, 0x50 }, /* y_output_size[7:0] */ - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x02 }, - { IMX_8BIT, 0x0355, 0xD0 }, - { IMX_8BIT, 0x0356, 0x02 }, - { IMX_8BIT, 0x0357, 0x50 }, - { IMX_8BIT, 0x301D, 0x30 }, - { IMX_8BIT, 0x3310, 0x02 }, - { IMX_8BIT, 0x3311, 0xD0 }, - { IMX_8BIT, 0x3312, 0x02 }, - { IMX_8BIT, 0x3313, 0x50 }, - { IMX_8BIT, 0x331C, 0x02 }, - { IMX_8BIT, 0x331D, 0xD0 }, - { IMX_8BIT, 0x4084, 0x00 }, - { IMX_8BIT, 0x4085, 0x00 }, - { IMX_8BIT, 0x4086, 0x00 }, - { IMX_8BIT, 0x4087, 0x00 }, - { IMX_8BIT, 0x4400, 0x00 }, - - /* Global Timing Setting */ - { IMX_8BIT, 0x0830, 0x77 }, - { IMX_8BIT, 0x0831, 0x2F }, - { IMX_8BIT, 0x0832, 0x4F }, - { IMX_8BIT, 0x0833, 0x37 }, - { IMX_8BIT, 0x0834, 0x2F }, - { IMX_8BIT, 0x0835, 0x37 }, - { IMX_8BIT, 0x0836, 0xAF }, - { IMX_8BIT, 0x0837, 0x37 }, - { IMX_8BIT, 0x0839, 0x1F }, - { IMX_8BIT, 0x083A, 0x17 }, - { IMX_8BIT, 0x083B, 0x02 }, - - /* Integration Time Setting */ - { IMX_8BIT, 0x0202, 0x09 }, - { IMX_8BIT, 0x0203, 0xD2 }, - - /* HDR Setting */ - { IMX_8BIT, 0x0230, 0x00 }, - { IMX_8BIT, 0x0231, 0x00 }, - { IMX_8BIT, 0x0233, 0x00 }, - { IMX_8BIT, 0x0234, 0x00 }, - { IMX_8BIT, 0x0235, 0x40 }, - { IMX_8BIT, 0x0238, 0x00 }, - { IMX_8BIT, 0x0239, 0x04 }, - { IMX_8BIT, 0x023B, 0x00 }, - { IMX_8BIT, 0x023C, 0x01 }, - { IMX_8BIT, 0x33B0, 0x04 }, - { IMX_8BIT, 0x33B1, 0x00 }, - { IMX_8BIT, 0x33B3, 0x00 }, - { IMX_8BIT, 0x33B4, 0x01 }, - { IMX_8BIT, 0x3800, 0x00 }, - { IMX_TOK_TERM, 0, 0 } -}; - -static struct imx_reg const imx134_752_616_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* mode set clear */ - { IMX_8BIT, 0x3A43, 0x01 }, - /* Clock Setting */ - { IMX_8BIT, 0x011E, 0x13 }, - { IMX_8BIT, 0x011F, 0x33 }, - { IMX_8BIT, 0x0301, 0x05 }, - { IMX_8BIT, 0x0303, 0x01 }, - { IMX_8BIT, 0x0305, 0x0C }, - { IMX_8BIT, 0x0309, 0x05 }, - { IMX_8BIT, 0x030B, 0x01 }, - { IMX_8BIT, 0x030C, 0x01 }, - { IMX_8BIT, 0x030D, 0xA9 }, - { IMX_8BIT, 0x030E, 0x01 }, - { IMX_8BIT, 0x3A06, 0x11 }, - - /* Mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x01 }, /* binning */ - { IMX_8BIT, 0x0391, 0x44 }, /* 4x4 binning */ - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x00 }, /* no resize */ - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x10 }, - { IMX_8BIT, 0x4082, 0x01 }, - { IMX_8BIT, 0x4083, 0x01 }, - { IMX_8BIT, 0x7006, 0x04 }, - - /* Optionnal Function setting */ - { IMX_8BIT, 0x0700, 0x00 }, - { IMX_8BIT, 0x3A63, 0x00 }, - { IMX_8BIT, 0x4100, 0xF8 }, - { IMX_8BIT, 0x4203, 0xFF }, - { IMX_8BIT, 0x4344, 0x00 }, - { IMX_8BIT, 0x441C, 0x01 }, - - /* Size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* x_addr_start[15:8]:136 */ - { IMX_8BIT, 0x0345, 0x88 }, /* x_addr_start[7:0] */ - { IMX_8BIT, 0x0346, 0x00 }, /* y_addr_start[15:8]:0 */ - { IMX_8BIT, 0x0347, 0x00 }, /* y_addr_start[7:0] */ - { IMX_8BIT, 0x0348, 0x0C }, /* x_addr_end[15:8]:3145+134-1 */ - { IMX_8BIT, 0x0349, 0x47 }, /* x_addr_end[7:0] */ - { IMX_8BIT, 0x034A, 0x09 }, /* y_addr_end[15:8]:2463 */ - { IMX_8BIT, 0x034B, 0x9F }, /* y_addr_end[7:0] */ - { IMX_8BIT, 0x034C, 0x02 }, /* x_output_size[15:8]: 752*/ - { IMX_8BIT, 0x034D, 0xF0 }, /* x_output_size[7:0] */ - { IMX_8BIT, 0x034E, 0x02 }, /* y_output_size[15:8]:616 */ - { IMX_8BIT, 0x034F, 0x68 }, /* y_output_size[7:0] */ - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - - { IMX_8BIT, 0x0354, 0x02 }, - { IMX_8BIT, 0x0355, 0xF0 }, - { IMX_8BIT, 0x0356, 0x02 }, - { IMX_8BIT, 0x0357, 0x68 }, - - { IMX_8BIT, 0x301D, 0x30 }, - - { IMX_8BIT, 0x3310, 0x02 }, - { IMX_8BIT, 0x3311, 0xF0 }, - { IMX_8BIT, 0x3312, 0x02 }, - { IMX_8BIT, 0x3313, 0x68 }, - - { IMX_8BIT, 0x331C, 0x02 }, - { IMX_8BIT, 0x331D, 0xD0 }, - { IMX_8BIT, 0x4084, 0x00 }, - { IMX_8BIT, 0x4085, 0x00 }, - { IMX_8BIT, 0x4086, 0x00 }, - { IMX_8BIT, 0x4087, 0x00 }, - { IMX_8BIT, 0x4400, 0x00 }, - - /* Global Timing Setting */ - { IMX_8BIT, 0x0830, 0x77 }, - { IMX_8BIT, 0x0831, 0x2F }, - { IMX_8BIT, 0x0832, 0x4F }, - { IMX_8BIT, 0x0833, 0x37 }, - { IMX_8BIT, 0x0834, 0x2F }, - { IMX_8BIT, 0x0835, 0x37 }, - { IMX_8BIT, 0x0836, 0xAF }, - { IMX_8BIT, 0x0837, 0x37 }, - { IMX_8BIT, 0x0839, 0x1F }, - { IMX_8BIT, 0x083A, 0x17 }, - { IMX_8BIT, 0x083B, 0x02 }, - - /* Integration Time Setting */ - { IMX_8BIT, 0x0202, 0x09 }, - { IMX_8BIT, 0x0203, 0xD2 }, - - /* HDR Setting */ - { IMX_8BIT, 0x0230, 0x00 }, - { IMX_8BIT, 0x0231, 0x00 }, - { IMX_8BIT, 0x0233, 0x00 }, - { IMX_8BIT, 0x0234, 0x00 }, - { IMX_8BIT, 0x0235, 0x40 }, - { IMX_8BIT, 0x0238, 0x00 }, - { IMX_8BIT, 0x0239, 0x04 }, - { IMX_8BIT, 0x023B, 0x00 }, - { IMX_8BIT, 0x023C, 0x01 }, - { IMX_8BIT, 0x33B0, 0x04 }, - { IMX_8BIT, 0x33B1, 0x00 }, - { IMX_8BIT, 0x33B3, 0x00 }, - { IMX_8BIT, 0x33B4, 0x01 }, - { IMX_8BIT, 0x3800, 0x00 }, - { IMX_TOK_TERM, 0, 0 } -}; - -/* 1424x1168 */ -static struct imx_reg const imx134_1424_1168_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* mode set clear */ - { IMX_8BIT, 0x3A43, 0x01 }, - /* Clock Setting */ - { IMX_8BIT, 0x011E, 0x13 }, - { IMX_8BIT, 0x011F, 0x33 }, - { IMX_8BIT, 0x0301, 0x05 }, - { IMX_8BIT, 0x0303, 0x01 }, - { IMX_8BIT, 0x0305, 0x0C }, - { IMX_8BIT, 0x0309, 0x05 }, - { IMX_8BIT, 0x030B, 0x01 }, - { IMX_8BIT, 0x030C, 0x01 }, - { IMX_8BIT, 0x030D, 0xA9 }, - { IMX_8BIT, 0x030E, 0x01 }, - { IMX_8BIT, 0x3A06, 0x11 }, - - /* Mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x00 }, /* binning */ - { IMX_8BIT, 0x0391, 0x11 }, /* no binning */ - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x02 }, /* resize */ - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x22 }, /* 34/16=2.125 */ - { IMX_8BIT, 0x4082, 0x00 }, /* ?? */ - { IMX_8BIT, 0x4083, 0x00 }, /* ?? */ - { IMX_8BIT, 0x7006, 0x04 }, - - /* Optionnal Function setting */ - { IMX_8BIT, 0x0700, 0x00 }, - { IMX_8BIT, 0x3A63, 0x00 }, - { IMX_8BIT, 0x4100, 0xF8 }, - { IMX_8BIT, 0x4203, 0xFF }, - { IMX_8BIT, 0x4344, 0x00 }, - { IMX_8BIT, 0x441C, 0x01 }, - - /* Size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* x_addr_start[15:8]:136 */ - { IMX_8BIT, 0x0345, 0x80 }, /* x_addr_start[7:0] */ - { IMX_8BIT, 0x0346, 0x00 }, /* y_addr_start[15:8]:0 */ - { IMX_8BIT, 0x0347, 0x00 }, /* y_addr_start[7:0] */ - { IMX_8BIT, 0x0348, 0x0C }, /* x_addr_end[15:8]:3145+134-1 */ - { IMX_8BIT, 0x0349, 0x51 }, /* x_addr_end[7:0] */ - { IMX_8BIT, 0x034A, 0x09 }, /* y_addr_end[15:8]:2463 */ - { IMX_8BIT, 0x034B, 0xB1 }, /* y_addr_end[7:0] */ - { IMX_8BIT, 0x034C, 0x05 }, /* x_output_size[15:8]: 1424*/ - { IMX_8BIT, 0x034D, 0x90 }, /* x_output_size[7:0] */ - { IMX_8BIT, 0x034E, 0x04 }, /* y_output_size[15:8]:1168 */ - { IMX_8BIT, 0x034F, 0x90 }, /* y_output_size[7:0] */ - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - - { IMX_8BIT, 0x0354, 0x0B }, - { IMX_8BIT, 0x0355, 0xD2 }, - { IMX_8BIT, 0x0356, 0x09 }, - { IMX_8BIT, 0x0357, 0xB2 }, - - { IMX_8BIT, 0x301D, 0x30 }, - - { IMX_8BIT, 0x3310, 0x05 }, - { IMX_8BIT, 0x3311, 0x90 }, - { IMX_8BIT, 0x3312, 0x04 }, - { IMX_8BIT, 0x3313, 0x90 }, - - { IMX_8BIT, 0x331C, 0x02 }, - { IMX_8BIT, 0x331D, 0xD0 }, - { IMX_8BIT, 0x4084, 0x05 }, - { IMX_8BIT, 0x4085, 0x90 }, - { IMX_8BIT, 0x4086, 0x04 }, - { IMX_8BIT, 0x4087, 0x90 }, - { IMX_8BIT, 0x4400, 0x00 }, - - /* Global Timing Setting */ - { IMX_8BIT, 0x0830, 0x77 }, - { IMX_8BIT, 0x0831, 0x2F }, - { IMX_8BIT, 0x0832, 0x4F }, - { IMX_8BIT, 0x0833, 0x37 }, - { IMX_8BIT, 0x0834, 0x2F }, - { IMX_8BIT, 0x0835, 0x37 }, - { IMX_8BIT, 0x0836, 0xAF }, - { IMX_8BIT, 0x0837, 0x37 }, - { IMX_8BIT, 0x0839, 0x1F }, - { IMX_8BIT, 0x083A, 0x17 }, - { IMX_8BIT, 0x083B, 0x02 }, - - /* Integration Time Setting */ - { IMX_8BIT, 0x0202, 0x09 }, - { IMX_8BIT, 0x0203, 0xD2 }, - - /* HDR Setting */ - { IMX_8BIT, 0x0230, 0x00 }, - { IMX_8BIT, 0x0231, 0x00 }, - { IMX_8BIT, 0x0233, 0x00 }, - { IMX_8BIT, 0x0234, 0x00 }, - { IMX_8BIT, 0x0235, 0x40 }, - { IMX_8BIT, 0x0238, 0x00 }, - { IMX_8BIT, 0x0239, 0x04 }, - { IMX_8BIT, 0x023B, 0x00 }, - { IMX_8BIT, 0x023C, 0x01 }, - { IMX_8BIT, 0x33B0, 0x04 }, - { IMX_8BIT, 0x33B1, 0x00 }, - { IMX_8BIT, 0x33B3, 0x00 }, - { IMX_8BIT, 0x33B4, 0x01 }, - { IMX_8BIT, 0x3800, 0x00 }, - { IMX_TOK_TERM, 0, 0 } -}; - -/* 4 lane, 1/4 binning, 16/35 down scaling, 30fps, dvs */ -static struct imx_reg const imx134_240_196_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* mode set clear */ - { IMX_8BIT, 0x3A43, 0x01 }, - /* Clock Setting */ - { IMX_8BIT, 0x011E, 0x13 }, - { IMX_8BIT, 0x011F, 0x33 }, - { IMX_8BIT, 0x0301, 0x05 }, - { IMX_8BIT, 0x0303, 0x01 }, - { IMX_8BIT, 0x0305, 0x0C }, - { IMX_8BIT, 0x0309, 0x05 }, - { IMX_8BIT, 0x030B, 0x01 }, - { IMX_8BIT, 0x030C, 0x01 }, - { IMX_8BIT, 0x030D, 0xA9 }, - { IMX_8BIT, 0x030E, 0x01 }, - { IMX_8BIT, 0x3A06, 0x11 }, - - /* Mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x01 }, /*4x4 binning */ - { IMX_8BIT, 0x0391, 0x44 }, - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x02 }, /* resize */ - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x23 }, /* down scaling = 16/35 */ - { IMX_8BIT, 0x4082, 0x00 }, - { IMX_8BIT, 0x4083, 0x00 }, - { IMX_8BIT, 0x7006, 0x04 }, - - /* Optionnal Function setting */ - { IMX_8BIT, 0x0700, 0x00 }, - { IMX_8BIT, 0x3A63, 0x00 }, - { IMX_8BIT, 0x4100, 0xF8 }, - { IMX_8BIT, 0x4203, 0xFF }, - { IMX_8BIT, 0x4344, 0x00 }, - { IMX_8BIT, 0x441C, 0x01 }, - - /* Size setting */ - { IMX_8BIT, 0x0344, 0x02 }, /* x_addr_start[15:8]:590 */ - { IMX_8BIT, 0x0345, 0x4E }, /* x_addr_start[7:0] */ - { IMX_8BIT, 0x0346, 0x01 }, /* y_addr_start[15:8]:366 */ - { IMX_8BIT, 0x0347, 0x6E }, /* y_addr_start[7:0] */ - { IMX_8BIT, 0x0348, 0x0A }, /* x_addr_end[15:8]:2104+590-1 */ - { IMX_8BIT, 0x0349, 0x85 }, /* x_addr_end[7:0] */ - { IMX_8BIT, 0x034A, 0x08 }, /* y_addr_end[15:8]:1720+366-1 */ - { IMX_8BIT, 0x034B, 0x25 }, /* y_addr_end[7:0] */ - { IMX_8BIT, 0x034C, 0x00 }, /* x_output_size[15:8]: 240*/ - { IMX_8BIT, 0x034D, 0xF0 }, /* x_output_size[7:0] */ - { IMX_8BIT, 0x034E, 0x00 }, /* y_output_size[15:8]:196 */ - { IMX_8BIT, 0x034F, 0xC4 }, /* y_output_size[7:0] */ - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x02 }, /* crop_x: 526 */ - { IMX_8BIT, 0x0355, 0x0E }, - { IMX_8BIT, 0x0356, 0x01 }, /* crop_y: 430 */ - { IMX_8BIT, 0x0357, 0xAE }, - - { IMX_8BIT, 0x301D, 0x30 }, - - { IMX_8BIT, 0x3310, 0x00 }, - { IMX_8BIT, 0x3311, 0xF0 }, - { IMX_8BIT, 0x3312, 0x00 }, - { IMX_8BIT, 0x3313, 0xC4 }, - - { IMX_8BIT, 0x331C, 0x04 }, - { IMX_8BIT, 0x331D, 0x4C }, - - { IMX_8BIT, 0x4084, 0x00 }, - { IMX_8BIT, 0x4085, 0xF0 }, - { IMX_8BIT, 0x4086, 0x00 }, - { IMX_8BIT, 0x4087, 0xC4 }, - - { IMX_8BIT, 0x4400, 0x00 }, - - /* Global Timing Setting */ - { IMX_8BIT, 0x0830, 0x77 }, - { IMX_8BIT, 0x0831, 0x2F }, - { IMX_8BIT, 0x0832, 0x4F }, - { IMX_8BIT, 0x0833, 0x37 }, - { IMX_8BIT, 0x0834, 0x2F }, - { IMX_8BIT, 0x0835, 0x37 }, - { IMX_8BIT, 0x0836, 0xAF }, - { IMX_8BIT, 0x0837, 0x37 }, - { IMX_8BIT, 0x0839, 0x1F }, - { IMX_8BIT, 0x083A, 0x17 }, - { IMX_8BIT, 0x083B, 0x02 }, - - /* Integration Time Setting */ - { IMX_8BIT, 0x0202, 0x0A }, - { IMX_8BIT, 0x0203, 0x88 }, - - /* HDR Setting */ - { IMX_8BIT, 0x0230, 0x00 }, - { IMX_8BIT, 0x0231, 0x00 }, - { IMX_8BIT, 0x0233, 0x00 }, - { IMX_8BIT, 0x0234, 0x00 }, - { IMX_8BIT, 0x0235, 0x40 }, - { IMX_8BIT, 0x0238, 0x00 }, - { IMX_8BIT, 0x0239, 0x04 }, - { IMX_8BIT, 0x023B, 0x00 }, - { IMX_8BIT, 0x023C, 0x01 }, - { IMX_8BIT, 0x33B0, 0x04 }, - { IMX_8BIT, 0x33B1, 0x00 }, - { IMX_8BIT, 0x33B3, 0x00 }, - { IMX_8BIT, 0x33B4, 0x01 }, - { IMX_8BIT, 0x3800, 0x00 }, - { IMX_TOK_TERM, 0, 0 } -}; - -/* 4 lane, 1/2 binning, 16/38 downscaling, 30fps, dvs */ -static struct imx_reg const imx134_448_366_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* mode set clear */ - { IMX_8BIT, 0x3A43, 0x01 }, - /* Clock Setting */ - { IMX_8BIT, 0x011E, 0x13 }, - { IMX_8BIT, 0x011F, 0x33 }, - { IMX_8BIT, 0x0301, 0x05 }, - { IMX_8BIT, 0x0303, 0x01 }, - { IMX_8BIT, 0x0305, 0x0C }, - { IMX_8BIT, 0x0309, 0x05 }, - { IMX_8BIT, 0x030B, 0x01 }, - { IMX_8BIT, 0x030C, 0x01 }, - { IMX_8BIT, 0x030D, 0xA9 }, - { IMX_8BIT, 0x030E, 0x01 }, - { IMX_8BIT, 0x3A06, 0x11 }, - - /* Mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x01 }, /* 2x2 binning */ - { IMX_8BIT, 0x0391, 0x22 }, - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x02 }, /* resize */ - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x26 }, /* down scaling = 16/38 */ - { IMX_8BIT, 0x4082, 0x00 }, - { IMX_8BIT, 0x4083, 0x00 }, - { IMX_8BIT, 0x7006, 0x04 }, - - /* Optionnal Function setting */ - { IMX_8BIT, 0x0700, 0x00 }, - { IMX_8BIT, 0x3A63, 0x00 }, - { IMX_8BIT, 0x4100, 0xF8 }, - { IMX_8BIT, 0x4203, 0xFF }, - { IMX_8BIT, 0x4344, 0x00 }, - { IMX_8BIT, 0x441C, 0x01 }, - - /* Size setting */ - { IMX_8BIT, 0x0344, 0x02 }, /* x_addr_start[15:8]:590 */ - { IMX_8BIT, 0x0345, 0x4E }, /* x_addr_start[7:0] */ - { IMX_8BIT, 0x0346, 0x01 }, /* y_addr_start[15:8]:366 */ - { IMX_8BIT, 0x0347, 0x6E }, /* y_addr_start[7:0] */ - { IMX_8BIT, 0x0348, 0x0A }, /* x_addr_end[15:8]:2128+590-1 */ - { IMX_8BIT, 0x0349, 0x9D }, /* x_addr_end[7:0] */ - { IMX_8BIT, 0x034A, 0x08 }, /* y_addr_end[15:8]:1740+366-1 */ - { IMX_8BIT, 0x034B, 0x39 }, /* y_addr_end[7:0] */ - { IMX_8BIT, 0x034C, 0x01 }, /* x_output_size[15:8]: 448*/ - { IMX_8BIT, 0x034D, 0xC0 }, /* x_output_size[7:0] */ - { IMX_8BIT, 0x034E, 0x01 }, /* y_output_size[15:8]:366 */ - { IMX_8BIT, 0x034F, 0x6E }, /* y_output_size[7:0] */ - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x04 }, /* crop_x: 1064 */ - { IMX_8BIT, 0x0355, 0x28 }, - { IMX_8BIT, 0x0356, 0x03 }, /* crop_y: 870 */ - { IMX_8BIT, 0x0357, 0x66 }, - - { IMX_8BIT, 0x301D, 0x30 }, - - { IMX_8BIT, 0x3310, 0x01 }, - { IMX_8BIT, 0x3311, 0xC0 }, - { IMX_8BIT, 0x3312, 0x01 }, - { IMX_8BIT, 0x3313, 0x6E }, - - { IMX_8BIT, 0x331C, 0x02 }, - { IMX_8BIT, 0x331D, 0xD0 }, - - { IMX_8BIT, 0x4084, 0x01 }, - { IMX_8BIT, 0x4085, 0xC0 }, - { IMX_8BIT, 0x4086, 0x01 }, - { IMX_8BIT, 0x4087, 0x6E }, - { IMX_8BIT, 0x4400, 0x00 }, - - /* Global Timing Setting */ - { IMX_8BIT, 0x0830, 0x77 }, - { IMX_8BIT, 0x0831, 0x2F }, - { IMX_8BIT, 0x0832, 0x4F }, - { IMX_8BIT, 0x0833, 0x37 }, - { IMX_8BIT, 0x0834, 0x2F }, - { IMX_8BIT, 0x0835, 0x37 }, - { IMX_8BIT, 0x0836, 0xAF }, - { IMX_8BIT, 0x0837, 0x37 }, - { IMX_8BIT, 0x0839, 0x1F }, - { IMX_8BIT, 0x083A, 0x17 }, - { IMX_8BIT, 0x083B, 0x02 }, - - /* Integration Time Setting */ - { IMX_8BIT, 0x0202, 0x09 }, - { IMX_8BIT, 0x0203, 0xD2 }, - - /* HDR Setting */ - { IMX_8BIT, 0x0230, 0x00 }, - { IMX_8BIT, 0x0231, 0x00 }, - { IMX_8BIT, 0x0233, 0x00 }, - { IMX_8BIT, 0x0234, 0x00 }, - { IMX_8BIT, 0x0235, 0x40 }, - { IMX_8BIT, 0x0238, 0x00 }, - { IMX_8BIT, 0x0239, 0x04 }, - { IMX_8BIT, 0x023B, 0x00 }, - { IMX_8BIT, 0x023C, 0x01 }, - { IMX_8BIT, 0x33B0, 0x04 }, - { IMX_8BIT, 0x33B1, 0x00 }, - { IMX_8BIT, 0x33B3, 0x00 }, - { IMX_8BIT, 0x33B4, 0x01 }, - { IMX_8BIT, 0x3800, 0x00 }, - { IMX_TOK_TERM, 0, 0 } -}; - -/* 4 lane 2336x1312, 30fps, for 1080p dvs, vendor provide */ -static struct imx_reg const imx134_2336_1312_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* mode set clear */ - { IMX_8BIT, 0x3A43, 0x01 }, - /* Clock Setting */ - { IMX_8BIT, 0x011E, 0x13 }, - { IMX_8BIT, 0x011F, 0x33 }, - { IMX_8BIT, 0x0301, 0x05 }, - { IMX_8BIT, 0x0303, 0x01 }, - { IMX_8BIT, 0x0305, 0x0C }, - { IMX_8BIT, 0x0309, 0x05 }, - { IMX_8BIT, 0x030B, 0x01 }, - { IMX_8BIT, 0x030C, 0x01 }, - { IMX_8BIT, 0x030D, 0xA9 }, - { IMX_8BIT, 0x030E, 0x01 }, - { IMX_8BIT, 0x3A06, 0x11 }, - - /* Mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x00 }, /* disable binning */ - { IMX_8BIT, 0x0391, 0x11 }, - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x02 }, /* H/V resize */ - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x16 }, /* down scaling = 16/22 = 8/11 */ - { IMX_8BIT, 0x4082, 0x00 }, - { IMX_8BIT, 0x4083, 0x00 }, - { IMX_8BIT, 0x7006, 0x04 }, - - /* Optionnal Function setting */ - { IMX_8BIT, 0x0700, 0x00 }, - { IMX_8BIT, 0x3A63, 0x00 }, - { IMX_8BIT, 0x4100, 0xF8 }, - { IMX_8BIT, 0x4203, 0xFF }, - { IMX_8BIT, 0x4344, 0x00 }, - { IMX_8BIT, 0x441C, 0x01 }, - - /* Size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* x_addr_start[15:8]:34 */ - { IMX_8BIT, 0x0345, 0x22 }, /* x_addr_start[7:0] */ - { IMX_8BIT, 0x0346, 0x01 }, /* y_addr_start[15:8]:332 */ - { IMX_8BIT, 0x0347, 0x4C }, /* y_addr_start[7:0] */ - { IMX_8BIT, 0x0348, 0x0C }, /* x_addr_end[15:8]:3245 */ - { IMX_8BIT, 0x0349, 0xAD }, /* x_addr_end[7:0] */ - { IMX_8BIT, 0x034A, 0x08 }, /* y_addr_end[15:8]:2135 */ - { IMX_8BIT, 0x034B, 0x57 }, /* y_addr_end[7:0] */ - { IMX_8BIT, 0x034C, 0x09 }, /* x_output_size[15:8]:2336 */ - { IMX_8BIT, 0x034D, 0x20 }, /* x_output_size[7:0] */ - { IMX_8BIT, 0x034E, 0x05 }, /* y_output_size[15:8]:1312 */ - { IMX_8BIT, 0x034F, 0x20 }, /* y_output_size[7:0] */ - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x0C }, - { IMX_8BIT, 0x0355, 0x8C }, - { IMX_8BIT, 0x0356, 0x07 }, - { IMX_8BIT, 0x0357, 0x0C }, - { IMX_8BIT, 0x301D, 0x30 }, - { IMX_8BIT, 0x3310, 0x09 }, - { IMX_8BIT, 0x3311, 0x20 }, - { IMX_8BIT, 0x3312, 0x05 }, - { IMX_8BIT, 0x3313, 0x20 }, - { IMX_8BIT, 0x331C, 0x03 }, - { IMX_8BIT, 0x331D, 0xEB }, - { IMX_8BIT, 0x4084, 0x09 }, - { IMX_8BIT, 0x4085, 0x20 }, - { IMX_8BIT, 0x4086, 0x05 }, - { IMX_8BIT, 0x4087, 0x20 }, - { IMX_8BIT, 0x4400, 0x00 }, - - /* Global Timing Setting */ - { IMX_8BIT, 0x0830, 0x77 }, - { IMX_8BIT, 0x0831, 0x2F }, - { IMX_8BIT, 0x0832, 0x4F }, - { IMX_8BIT, 0x0833, 0x37 }, - { IMX_8BIT, 0x0834, 0x2F }, - { IMX_8BIT, 0x0835, 0x37 }, - { IMX_8BIT, 0x0836, 0xAF }, - { IMX_8BIT, 0x0837, 0x37 }, - { IMX_8BIT, 0x0839, 0x1F }, - { IMX_8BIT, 0x083A, 0x17 }, - { IMX_8BIT, 0x083B, 0x02 }, - - /* Integration Time Setting */ - { IMX_8BIT, 0x0202, 0x09 }, - { IMX_8BIT, 0x0203, 0xD2 }, - - /* HDR Setting */ - { IMX_8BIT, 0x0230, 0x00 }, - { IMX_8BIT, 0x0231, 0x00 }, - { IMX_8BIT, 0x0233, 0x00 }, - { IMX_8BIT, 0x0234, 0x00 }, - { IMX_8BIT, 0x0235, 0x40 }, - { IMX_8BIT, 0x0238, 0x00 }, - { IMX_8BIT, 0x0239, 0x04 }, - { IMX_8BIT, 0x023B, 0x00 }, - { IMX_8BIT, 0x023C, 0x01 }, - { IMX_8BIT, 0x33B0, 0x04 }, - { IMX_8BIT, 0x33B1, 0x00 }, - { IMX_8BIT, 0x33B3, 0x00 }, - { IMX_8BIT, 0x33B4, 0x01 }, - { IMX_8BIT, 0x3800, 0x00 }, - { IMX_TOK_TERM, 0, 0 } -}; - -/* 4 lane 1920x1080, 30fps, for 720p still capture */ -static struct imx_reg const imx134_1936_1096_30fps_v1[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* mode set clear */ - { IMX_8BIT, 0x3A43, 0x01 }, - /* Clock Setting */ - { IMX_8BIT, 0x011E, 0x13 }, - { IMX_8BIT, 0x011F, 0x33 }, - { IMX_8BIT, 0x0301, 0x05 }, - { IMX_8BIT, 0x0303, 0x01 }, - { IMX_8BIT, 0x0305, 0x0C }, - { IMX_8BIT, 0x0309, 0x05 }, - { IMX_8BIT, 0x030B, 0x01 }, - { IMX_8BIT, 0x030C, 0x01 }, - { IMX_8BIT, 0x030D, 0xA9 }, - { IMX_8BIT, 0x030E, 0x01 }, - { IMX_8BIT, 0x3A06, 0x11 }, - - /* Mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x00 }, /* disable binning */ - { IMX_8BIT, 0x0391, 0x11 }, /* 2x2 binning */ - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x02 }, /* H/V resize */ - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x1A }, /* downscaling 16/26*/ - { IMX_8BIT, 0x4082, 0x00 }, - { IMX_8BIT, 0x4083, 0x00 }, - { IMX_8BIT, 0x7006, 0x04 }, - - /* Optionnal Function setting */ - { IMX_8BIT, 0x0700, 0x00 }, - { IMX_8BIT, 0x3A63, 0x00 }, - { IMX_8BIT, 0x4100, 0xF8 }, - { IMX_8BIT, 0x4203, 0xFF }, - { IMX_8BIT, 0x4344, 0x00 }, - { IMX_8BIT, 0x441C, 0x01 }, - - /* Size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* x_addr_start[15:8]:64 */ - { IMX_8BIT, 0x0345, 0x40 }, /* x_addr_start[7:0] */ - { IMX_8BIT, 0x0346, 0x01 }, /* y_addr_start[15:8]:340 */ - { IMX_8BIT, 0x0347, 0x54 }, /* y_addr_start[7:0] */ - { IMX_8BIT, 0x0348, 0x0C }, /* x_addr_end[15:8]:3209 */ - { IMX_8BIT, 0x0349, 0x89 }, /* x_addr_end[7:0] */ - { IMX_8BIT, 0x034A, 0x08 }, /* y_addr_end[15:8]:2121 */ - { IMX_8BIT, 0x034B, 0x49 }, /* y_addr_end[7:0] */ - { IMX_8BIT, 0x034C, 0x07 }, /* x_output_size[15:8]:1936 */ - { IMX_8BIT, 0x034D, 0x90 }, /* x_output_size[7:0] */ - { IMX_8BIT, 0x034E, 0x04 }, /* y_output_size[15:8]:1096 */ - { IMX_8BIT, 0x034F, 0x48 }, /* y_output_size[7:0] */ - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x0C }, /* crop x:3146 */ - { IMX_8BIT, 0x0355, 0x4A }, - { IMX_8BIT, 0x0356, 0x06 }, /* xrop y:1782 */ - { IMX_8BIT, 0x0357, 0xF6 }, - { IMX_8BIT, 0x301D, 0x30 }, - { IMX_8BIT, 0x3310, 0x07 }, - { IMX_8BIT, 0x3311, 0x80 }, - { IMX_8BIT, 0x3312, 0x04 }, - { IMX_8BIT, 0x3313, 0x38 }, - { IMX_8BIT, 0x331C, 0x04 }, - { IMX_8BIT, 0x331D, 0x1E }, - { IMX_8BIT, 0x4084, 0x07 }, - { IMX_8BIT, 0x4085, 0x80 }, - { IMX_8BIT, 0x4086, 0x04 }, - { IMX_8BIT, 0x4087, 0x38 }, - { IMX_8BIT, 0x4400, 0x00 }, - - /* Global Timing Setting */ - { IMX_8BIT, 0x0830, 0x77 }, - { IMX_8BIT, 0x0831, 0x2F }, - { IMX_8BIT, 0x0832, 0x4F }, - { IMX_8BIT, 0x0833, 0x37 }, - { IMX_8BIT, 0x0834, 0x2F }, - { IMX_8BIT, 0x0835, 0x37 }, - { IMX_8BIT, 0x0836, 0xAF }, - { IMX_8BIT, 0x0837, 0x37 }, - { IMX_8BIT, 0x0839, 0x1F }, - { IMX_8BIT, 0x083A, 0x17 }, - { IMX_8BIT, 0x083B, 0x02 }, - - /* Integration Time Setting */ - { IMX_8BIT, 0x0202, 0x09 }, - { IMX_8BIT, 0x0203, 0xD2 }, - - /* HDR Setting */ - { IMX_8BIT, 0x0230, 0x00 }, - { IMX_8BIT, 0x0231, 0x00 }, - { IMX_8BIT, 0x0233, 0x00 }, - { IMX_8BIT, 0x0234, 0x00 }, - { IMX_8BIT, 0x0235, 0x40 }, - { IMX_8BIT, 0x0238, 0x00 }, - { IMX_8BIT, 0x0239, 0x04 }, - { IMX_8BIT, 0x023B, 0x00 }, - { IMX_8BIT, 0x023C, 0x01 }, - { IMX_8BIT, 0x33B0, 0x04 }, - { IMX_8BIT, 0x33B1, 0x00 }, - { IMX_8BIT, 0x33B3, 0x00 }, - { IMX_8BIT, 0x33B4, 0x01 }, - { IMX_8BIT, 0x3800, 0x00 }, - { IMX_TOK_TERM, 0, 0 } -}; - -/* 4 lane 1920x1080, 30fps, for 720p still capture, vendor provide */ -static struct imx_reg const imx134_1936_1096_30fps_v2[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* mode set clear */ - { IMX_8BIT, 0x3A43, 0x01 }, - /* Clock Setting */ - { IMX_8BIT, 0x011E, 0x13 }, - { IMX_8BIT, 0x011F, 0x33 }, - { IMX_8BIT, 0x0301, 0x05 }, - { IMX_8BIT, 0x0303, 0x01 }, - { IMX_8BIT, 0x0305, 0x0C }, - { IMX_8BIT, 0x0309, 0x05 }, - { IMX_8BIT, 0x030B, 0x01 }, - { IMX_8BIT, 0x030C, 0x01 }, - { IMX_8BIT, 0x030D, 0xA9 }, - { IMX_8BIT, 0x030E, 0x01 }, - { IMX_8BIT, 0x3A06, 0x11 }, - - /* Mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x00 }, /* disable binning */ - { IMX_8BIT, 0x0391, 0x11 }, - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x02 }, /* H/V resize */ - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x1B }, /* downscaling 16/27*/ - { IMX_8BIT, 0x4082, 0x00 }, - { IMX_8BIT, 0x4083, 0x00 }, - { IMX_8BIT, 0x7006, 0x04 }, - - /* Optionnal Function setting */ - { IMX_8BIT, 0x0700, 0x00 }, - { IMX_8BIT, 0x3A63, 0x00 }, - { IMX_8BIT, 0x4100, 0xF8 }, - { IMX_8BIT, 0x4203, 0xFF }, - { IMX_8BIT, 0x4344, 0x00 }, - { IMX_8BIT, 0x441C, 0x01 }, - - /* Size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* x_addr_start[15:8]:64 */ - { IMX_8BIT, 0x0345, 0x06 }, /* x_addr_start[7:0] */ - { IMX_8BIT, 0x0346, 0x01 }, /* y_addr_start[15:8]:340 */ - { IMX_8BIT, 0x0347, 0x34 }, /* y_addr_start[7:0] */ - { IMX_8BIT, 0x0348, 0x0C }, /* x_addr_end[15:8]:3209 */ - { IMX_8BIT, 0x0349, 0xC9 }, /* x_addr_end[7:0] */ - { IMX_8BIT, 0x034A, 0x08 }, /* y_addr_end[15:8]:2121 */ - { IMX_8BIT, 0x034B, 0x6F }, /* y_addr_end[7:0] */ - { IMX_8BIT, 0x034C, 0x07 }, /* x_output_size[15:8]:1936 */ - { IMX_8BIT, 0x034D, 0x90 }, /* x_output_size[7:0] */ - { IMX_8BIT, 0x034E, 0x04 }, /* y_output_size[15:8]:1096 */ - { IMX_8BIT, 0x034F, 0x48 }, /* y_output_size[7:0] */ - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x0C }, /* crop x:3146 */ - { IMX_8BIT, 0x0355, 0xC4 }, - { IMX_8BIT, 0x0356, 0x07 }, /* xrop y:1782 */ - { IMX_8BIT, 0x0357, 0x3A }, - { IMX_8BIT, 0x301D, 0x30 }, - { IMX_8BIT, 0x3310, 0x07 }, /* decide by mode and output size */ - { IMX_8BIT, 0x3311, 0x90 }, - { IMX_8BIT, 0x3312, 0x04 }, - { IMX_8BIT, 0x3313, 0x48 }, - { IMX_8BIT, 0x331C, 0x04 }, - { IMX_8BIT, 0x331D, 0x1E }, - { IMX_8BIT, 0x4084, 0x07 }, - { IMX_8BIT, 0x4085, 0x90 }, - { IMX_8BIT, 0x4086, 0x04 }, - { IMX_8BIT, 0x4087, 0x48 }, - { IMX_8BIT, 0x4400, 0x00 }, - - /* Global Timing Setting */ - { IMX_8BIT, 0x0830, 0x77 }, - { IMX_8BIT, 0x0831, 0x2F }, - { IMX_8BIT, 0x0832, 0x4F }, - { IMX_8BIT, 0x0833, 0x37 }, - { IMX_8BIT, 0x0834, 0x2F }, - { IMX_8BIT, 0x0835, 0x37 }, - { IMX_8BIT, 0x0836, 0xAF }, - { IMX_8BIT, 0x0837, 0x37 }, - { IMX_8BIT, 0x0839, 0x1F }, - { IMX_8BIT, 0x083A, 0x17 }, - { IMX_8BIT, 0x083B, 0x02 }, - - /* Integration Time Setting */ - { IMX_8BIT, 0x0202, 0x09 }, - { IMX_8BIT, 0x0203, 0xD2 }, - - /* HDR Setting */ - { IMX_8BIT, 0x0230, 0x00 }, - { IMX_8BIT, 0x0231, 0x00 }, - { IMX_8BIT, 0x0233, 0x00 }, - { IMX_8BIT, 0x0234, 0x00 }, - { IMX_8BIT, 0x0235, 0x40 }, - { IMX_8BIT, 0x0238, 0x00 }, - { IMX_8BIT, 0x0239, 0x04 }, - { IMX_8BIT, 0x023B, 0x00 }, - { IMX_8BIT, 0x023C, 0x01 }, - { IMX_8BIT, 0x33B0, 0x04 }, - { IMX_8BIT, 0x33B1, 0x00 }, - { IMX_8BIT, 0x33B3, 0x00 }, - { IMX_8BIT, 0x33B4, 0x01 }, - { IMX_8BIT, 0x3800, 0x00 }, - { IMX_TOK_TERM, 0, 0 } -}; - -/* 4 lane 1296x736, 30fps, for 720p still capture, vendor provide */ -static struct imx_reg const imx134_1296_736_30fps_v2[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* mode set clear */ - { IMX_8BIT, 0x3A43, 0x01 }, - /* Clock Setting */ - { IMX_8BIT, 0x011E, 0x13 }, - { IMX_8BIT, 0x011F, 0x33 }, - { IMX_8BIT, 0x0301, 0x05 }, - { IMX_8BIT, 0x0303, 0x01 }, - { IMX_8BIT, 0x0305, 0x0C }, - { IMX_8BIT, 0x0309, 0x05 }, - { IMX_8BIT, 0x030B, 0x01 }, - { IMX_8BIT, 0x030C, 0x01 }, - { IMX_8BIT, 0x030D, 0xA9 }, - { IMX_8BIT, 0x030E, 0x01 }, - { IMX_8BIT, 0x3A06, 0x11 }, - - /* Mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x01 }, /* binning */ - { IMX_8BIT, 0x0391, 0x22 }, /* 2x2 binning */ - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x02 }, /* H/V resize */ - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x14 }, - { IMX_8BIT, 0x4082, 0x00 }, - { IMX_8BIT, 0x4083, 0x00 }, - { IMX_8BIT, 0x7006, 0x04 }, - - /* OptionnalFunction settig */ - { IMX_8BIT, 0x0700, 0x00 }, - { IMX_8BIT, 0x3A63, 0x00 }, - { IMX_8BIT, 0x4100, 0xF8 }, - { IMX_8BIT, 0x4203, 0xFF }, - { IMX_8BIT, 0x4344, 0x00 }, - { IMX_8BIT, 0x441C, 0x01 }, - - /* Size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* x_addr_start[15:8]:40 */ - { IMX_8BIT, 0x0345, 0x14 }, /* x_addr_start[7:0] */ - { IMX_8BIT, 0x0346, 0x01 }, /* y_addr_start[15:8]:332 */ - { IMX_8BIT, 0x0347, 0x38 }, /* y_addr_start[7:0] */ - { IMX_8BIT, 0x0348, 0x0C }, /* x_addr_end[15:8]:3239 */ - { IMX_8BIT, 0x0349, 0xBB }, /* x_addr_end[7:0] */ - { IMX_8BIT, 0x034A, 0x08 }, /* y_addr_end[15:8]:2131 */ - { IMX_8BIT, 0x034B, 0x67 }, /* y_addr_end[7:0] */ - { IMX_8BIT, 0x034C, 0x05 }, /* x_output_size[15:8]:1280 */ - { IMX_8BIT, 0x034D, 0x10 }, /* x_output_size[7:0] */ - { IMX_8BIT, 0x034E, 0x02 }, /* y_output_size[15:8]:720 */ - { IMX_8BIT, 0x034F, 0xE0 }, /* y_output_size[7:0] */ - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x06 }, - { IMX_8BIT, 0x0355, 0x54 }, - { IMX_8BIT, 0x0356, 0x03 }, - { IMX_8BIT, 0x0357, 0x98 }, - { IMX_8BIT, 0x301D, 0x30 }, - { IMX_8BIT, 0x3310, 0x05 }, - { IMX_8BIT, 0x3311, 0x10 }, - { IMX_8BIT, 0x3312, 0x02 }, - { IMX_8BIT, 0x3313, 0xE0 }, - { IMX_8BIT, 0x331C, 0x01 }, - { IMX_8BIT, 0x331D, 0x10 }, - { IMX_8BIT, 0x4084, 0x05 }, - { IMX_8BIT, 0x4085, 0x10 }, - { IMX_8BIT, 0x4086, 0x02 }, - { IMX_8BIT, 0x4087, 0xE0 }, - { IMX_8BIT, 0x4400, 0x00 }, - - /* Global Timing Setting */ - { IMX_8BIT, 0x0830, 0x77 }, - { IMX_8BIT, 0x0831, 0x2F }, - { IMX_8BIT, 0x0832, 0x4F }, - { IMX_8BIT, 0x0833, 0x37 }, - { IMX_8BIT, 0x0834, 0x2F }, - { IMX_8BIT, 0x0835, 0x37 }, - { IMX_8BIT, 0x0836, 0xAF }, - { IMX_8BIT, 0x0837, 0x37 }, - { IMX_8BIT, 0x0839, 0x1F }, - { IMX_8BIT, 0x083A, 0x17 }, - { IMX_8BIT, 0x083B, 0x02 }, - - /* Integration Time Settin */ - { IMX_8BIT, 0x0202, 0x09 }, - { IMX_8BIT, 0x0203, 0xD2 }, - - /* HDR Setting */ - { IMX_8BIT, 0x0230, 0x00 }, - { IMX_8BIT, 0x0231, 0x00 }, - { IMX_8BIT, 0x0233, 0x00 }, - { IMX_8BIT, 0x0234, 0x00 }, - { IMX_8BIT, 0x0235, 0x40 }, - { IMX_8BIT, 0x0238, 0x00 }, - { IMX_8BIT, 0x0239, 0x04 }, - { IMX_8BIT, 0x023B, 0x00 }, - { IMX_8BIT, 0x023C, 0x01 }, - { IMX_8BIT, 0x33B0, 0x04 }, - { IMX_8BIT, 0x33B1, 0x00 }, - { IMX_8BIT, 0x33B3, 0x00 }, - { IMX_8BIT, 0x33B4, 0x01 }, - { IMX_8BIT, 0x3800, 0x00 }, - { IMX_TOK_TERM, 0, 0 } -}; - -/* 4 lane 1280x720, 30fps, for 720p dvs, vendor provide */ -static struct imx_reg const imx134_1568_880_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* mode set clear */ - { IMX_8BIT, 0x3A43, 0x01 }, - /* Clock Setting */ - { IMX_8BIT, 0x011E, 0x13 }, - { IMX_8BIT, 0x011F, 0x33 }, - { IMX_8BIT, 0x0301, 0x05 }, - { IMX_8BIT, 0x0303, 0x01 }, - { IMX_8BIT, 0x0305, 0x0C }, - { IMX_8BIT, 0x0309, 0x05 }, - { IMX_8BIT, 0x030B, 0x01 }, - { IMX_8BIT, 0x030C, 0x01 }, - { IMX_8BIT, 0x030D, 0xA9 }, - { IMX_8BIT, 0x030E, 0x01 }, - { IMX_8BIT, 0x3A06, 0x11 }, - - /* Mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x01 }, /* binning*/ - { IMX_8BIT, 0x0391, 0x22 }, /* 2x2 binning */ - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x02 }, /* H/V resize */ - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x10 }, /* down scaling 16/16 = 1 */ - { IMX_8BIT, 0x4082, 0x01 }, - { IMX_8BIT, 0x4083, 0x01 }, - { IMX_8BIT, 0x7006, 0x04 }, - - /* OptionnalFunction settig */ - { IMX_8BIT, 0x0700, 0x00 }, - { IMX_8BIT, 0x3A63, 0x00 }, - { IMX_8BIT, 0x4100, 0xF8 }, - { IMX_8BIT, 0x4203, 0xFF }, - { IMX_8BIT, 0x4344, 0x00 }, - { IMX_8BIT, 0x441C, 0x01 }, - - /* Size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* x_addr_start[15:8]:72 */ - { IMX_8BIT, 0x0345, 0x48 }, /* x_addr_start[7:0] */ - { IMX_8BIT, 0x0346, 0x01 }, /* y_addr_start[15:8]:356 */ - { IMX_8BIT, 0x0347, 0x64 }, /* y_addr_start[7:0] */ - { IMX_8BIT, 0x0348, 0x0C }, /* x_addr_end[15:8]:3207 */ - { IMX_8BIT, 0x0349, 0x87 }, /* x_addr_end[7:0] */ - { IMX_8BIT, 0x034A, 0x08 }, /* y_addr_end[15:8]:2115 */ - { IMX_8BIT, 0x034B, 0x43 }, /* y_addr_end[7:0] */ - { IMX_8BIT, 0x034C, 0x06 }, /* x_output_size[15:8]:1568 */ - { IMX_8BIT, 0x034D, 0x20 }, /* x_output_size[7:0] */ - { IMX_8BIT, 0x034E, 0x03 }, /* y_output_size[15:8]:880 */ - { IMX_8BIT, 0x034F, 0x70 }, /* y_output_size[7:0] */ - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x06 }, - { IMX_8BIT, 0x0355, 0x20 }, - { IMX_8BIT, 0x0356, 0x03 }, - { IMX_8BIT, 0x0357, 0x70 }, - { IMX_8BIT, 0x301D, 0x30 }, - { IMX_8BIT, 0x3310, 0x06 }, - { IMX_8BIT, 0x3311, 0x20 }, - { IMX_8BIT, 0x3312, 0x03 }, - { IMX_8BIT, 0x3313, 0x70 }, - { IMX_8BIT, 0x331C, 0x03 }, - { IMX_8BIT, 0x331D, 0xF2 }, - { IMX_8BIT, 0x4084, 0x00 }, - { IMX_8BIT, 0x4085, 0x00 }, - { IMX_8BIT, 0x4086, 0x00 }, - { IMX_8BIT, 0x4087, 0x00 }, - { IMX_8BIT, 0x4400, 0x00 }, - - /* Global Timing Setting */ - { IMX_8BIT, 0x0830, 0x77 }, - { IMX_8BIT, 0x0831, 0x2F }, - { IMX_8BIT, 0x0832, 0x4F }, - { IMX_8BIT, 0x0833, 0x37 }, - { IMX_8BIT, 0x0834, 0x2F }, - { IMX_8BIT, 0x0835, 0x37 }, - { IMX_8BIT, 0x0836, 0xAF }, - { IMX_8BIT, 0x0837, 0x37 }, - { IMX_8BIT, 0x0839, 0x1F }, - { IMX_8BIT, 0x083A, 0x17 }, - { IMX_8BIT, 0x083B, 0x02 }, - - /* Integration Time Settin */ - { IMX_8BIT, 0x0202, 0x09 }, - { IMX_8BIT, 0x0203, 0xD2 }, - - /* HDR Setting */ - { IMX_8BIT, 0x0230, 0x00 }, - { IMX_8BIT, 0x0231, 0x00 }, - { IMX_8BIT, 0x0233, 0x00 }, - { IMX_8BIT, 0x0234, 0x00 }, - { IMX_8BIT, 0x0235, 0x40 }, - { IMX_8BIT, 0x0238, 0x00 }, - { IMX_8BIT, 0x0239, 0x04 }, - { IMX_8BIT, 0x023B, 0x00 }, - { IMX_8BIT, 0x023C, 0x01 }, - { IMX_8BIT, 0x33B0, 0x04 }, - { IMX_8BIT, 0x33B1, 0x00 }, - { IMX_8BIT, 0x33B3, 0x00 }, - { IMX_8BIT, 0x33B4, 0x01 }, - { IMX_8BIT, 0x3800, 0x00 }, - { IMX_TOK_TERM, 0, 0 } -}; - -static struct imx_reg const imx134_1568_876_60fps_0625[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* mode set clear */ - { IMX_8BIT, 0x3A43, 0x01 }, - /* Clock Setting */ - { IMX_8BIT, 0x011E, 0x13 }, - { IMX_8BIT, 0x011F, 0x33 }, - { IMX_8BIT, 0x0301, 0x05 }, - { IMX_8BIT, 0x0303, 0x01 }, - { IMX_8BIT, 0x0305, 0x0C }, - { IMX_8BIT, 0x0309, 0x05 }, - { IMX_8BIT, 0x030B, 0x01 }, - { IMX_8BIT, 0x030C, 0x01 }, - { IMX_8BIT, 0x030D, 0x8F }, - { IMX_8BIT, 0x030E, 0x01 }, - { IMX_8BIT, 0x3A06, 0x11 }, - - /* Mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x01 }, /* binning*/ - { IMX_8BIT, 0x0391, 0x22 }, /* 2x2 binning */ - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x00 }, /* H/V resize */ - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x10 }, /* down scaling 16/16 = 1 */ - { IMX_8BIT, 0x4082, 0x01 }, - { IMX_8BIT, 0x4083, 0x01 }, - { IMX_8BIT, 0x7006, 0x04 }, - - /* OptionnalFunction settig */ - { IMX_8BIT, 0x0700, 0x00 }, - { IMX_8BIT, 0x3A63, 0x00 }, - { IMX_8BIT, 0x4100, 0xF8 }, - { IMX_8BIT, 0x4203, 0xFF }, - { IMX_8BIT, 0x4344, 0x00 }, - { IMX_8BIT, 0x441C, 0x01 }, - - /* Size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* x_addr_start[15:8]:72 */ - { IMX_8BIT, 0x0345, 0x48 }, /* x_addr_start[7:0] */ - { IMX_8BIT, 0x0346, 0x01 }, /* y_addr_start[15:8]:356 */ - { IMX_8BIT, 0x0347, 0x64 }, /* y_addr_start[7:0] */ - { IMX_8BIT, 0x0348, 0x0C }, /* x_addr_end[15:8]:3207 */ - { IMX_8BIT, 0x0349, 0x87 }, /* x_addr_end[7:0] */ - { IMX_8BIT, 0x034A, 0x08 }, /* y_addr_end[15:8]:2115 */ - { IMX_8BIT, 0x034B, 0x3B }, /* y_addr_end[7:0] */ - { IMX_8BIT, 0x034C, 0x06 }, /* x_output_size[15:8]:1568 */ - { IMX_8BIT, 0x034D, 0x20 }, /* x_output_size[7:0] */ - { IMX_8BIT, 0x034E, 0x03 }, /* y_output_size[15:8]:880 */ - { IMX_8BIT, 0x034F, 0x6C }, /* y_output_size[7:0] */ - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x06 }, - { IMX_8BIT, 0x0355, 0x20 }, - { IMX_8BIT, 0x0356, 0x03 }, - { IMX_8BIT, 0x0357, 0x6C }, - { IMX_8BIT, 0x301D, 0x30 }, - { IMX_8BIT, 0x3310, 0x06 }, - { IMX_8BIT, 0x3311, 0x20 }, - { IMX_8BIT, 0x3312, 0x03 }, - { IMX_8BIT, 0x3313, 0x6C }, - { IMX_8BIT, 0x331C, 0x03 }, - { IMX_8BIT, 0x331D, 0xF2 }, - { IMX_8BIT, 0x4084, 0x00 }, - { IMX_8BIT, 0x4085, 0x00 }, - { IMX_8BIT, 0x4086, 0x00 }, - { IMX_8BIT, 0x4087, 0x00 }, - { IMX_8BIT, 0x4400, 0x00 }, - - /* Global Timing Setting */ - { IMX_8BIT, 0x0830, 0x6F }, - { IMX_8BIT, 0x0831, 0x27 }, - { IMX_8BIT, 0x0832, 0x4F }, - { IMX_8BIT, 0x0833, 0x2F }, - { IMX_8BIT, 0x0834, 0x2F }, - { IMX_8BIT, 0x0835, 0x2F }, - { IMX_8BIT, 0x0836, 0x9F }, - { IMX_8BIT, 0x0837, 0x37 }, - { IMX_8BIT, 0x0839, 0x1F }, - { IMX_8BIT, 0x083A, 0x17 }, - { IMX_8BIT, 0x083B, 0x02 }, - - /* Integration Time Settin */ - { IMX_8BIT, 0x0202, 0x09 }, - { IMX_8BIT, 0x0203, 0xD2 }, - - /* HDR Setting */ - { IMX_8BIT, 0x0230, 0x00 }, - { IMX_8BIT, 0x0231, 0x00 }, - { IMX_8BIT, 0x0233, 0x00 }, - { IMX_8BIT, 0x0234, 0x00 }, - { IMX_8BIT, 0x0235, 0x40 }, - { IMX_8BIT, 0x0238, 0x00 }, - { IMX_8BIT, 0x0239, 0x04 }, - { IMX_8BIT, 0x023B, 0x00 }, - { IMX_8BIT, 0x023C, 0x01 }, - { IMX_8BIT, 0x33B0, 0x04 }, - { IMX_8BIT, 0x33B1, 0x00 }, - { IMX_8BIT, 0x33B3, 0x00 }, - { IMX_8BIT, 0x33B4, 0x01 }, - { IMX_8BIT, 0x3800, 0x00 }, - { IMX_TOK_TERM, 0, 0 } -}; - - -/* 4 lane for 720p dvs, vendor provide */ -static struct imx_reg const imx134_1568_880[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* mode set clear */ - { IMX_8BIT, 0x3A43, 0x01 }, - /* Clock Setting */ - { IMX_8BIT, 0x011E, 0x13 }, - { IMX_8BIT, 0x011F, 0x33 }, - { IMX_8BIT, 0x0301, 0x05 }, - { IMX_8BIT, 0x0303, 0x01 }, - { IMX_8BIT, 0x0305, 0x0C }, - { IMX_8BIT, 0x0309, 0x05 }, - { IMX_8BIT, 0x030B, 0x01 }, - { IMX_8BIT, 0x030C, 0x01 }, - { IMX_8BIT, 0x030D, 0xC8 }, - { IMX_8BIT, 0x030E, 0x01 }, - { IMX_8BIT, 0x3A06, 0x11 }, - - /* Mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x01 }, /* binning*/ - { IMX_8BIT, 0x0391, 0x22 }, /* 2x2 binning */ - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x00 }, /* H/V resize */ - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x10 }, /* down scaling 16/16 = 1 */ - { IMX_8BIT, 0x4082, 0x01 }, - { IMX_8BIT, 0x4083, 0x01 }, - { IMX_8BIT, 0x7006, 0x04 }, - - /* OptionnalFunction settig */ - { IMX_8BIT, 0x0700, 0x00 }, - { IMX_8BIT, 0x3A63, 0x00 }, - { IMX_8BIT, 0x4100, 0xF8 }, - { IMX_8BIT, 0x4203, 0xFF }, - { IMX_8BIT, 0x4344, 0x00 }, - { IMX_8BIT, 0x441C, 0x01 }, - - /* Size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* x_addr_start[15:8]:72 */ - { IMX_8BIT, 0x0345, 0x48 }, /* x_addr_start[7:0] */ - { IMX_8BIT, 0x0346, 0x01 }, /* y_addr_start[15:8]:356 */ - { IMX_8BIT, 0x0347, 0x64 }, /* y_addr_start[7:0] */ - { IMX_8BIT, 0x0348, 0x0C }, /* x_addr_end[15:8]:3207 */ - { IMX_8BIT, 0x0349, 0x87 }, /* x_addr_end[7:0] */ - { IMX_8BIT, 0x034A, 0x08 }, /* y_addr_end[15:8]:2115 */ - { IMX_8BIT, 0x034B, 0x43 }, /* y_addr_end[7:0] */ - { IMX_8BIT, 0x034C, 0x06 }, /* x_output_size[15:8]:1568 */ - { IMX_8BIT, 0x034D, 0x20 }, /* x_output_size[7:0] */ - { IMX_8BIT, 0x034E, 0x03 }, /* y_output_size[15:8]:880 */ - { IMX_8BIT, 0x034F, 0x70 }, /* y_output_size[7:0] */ - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x06 }, - { IMX_8BIT, 0x0355, 0x20 }, - { IMX_8BIT, 0x0356, 0x03 }, - { IMX_8BIT, 0x0357, 0x70 }, - { IMX_8BIT, 0x301D, 0x30 }, - { IMX_8BIT, 0x3310, 0x06 }, - { IMX_8BIT, 0x3311, 0x20 }, - { IMX_8BIT, 0x3312, 0x03 }, - { IMX_8BIT, 0x3313, 0x70 }, - { IMX_8BIT, 0x331C, 0x03 }, - { IMX_8BIT, 0x331D, 0xF2 }, - { IMX_8BIT, 0x4084, 0x00 }, - { IMX_8BIT, 0x4085, 0x00 }, - { IMX_8BIT, 0x4086, 0x00 }, - { IMX_8BIT, 0x4087, 0x00 }, - { IMX_8BIT, 0x4400, 0x00 }, - - /* Global Timing Setting */ - { IMX_8BIT, 0x0830, 0x77 }, - { IMX_8BIT, 0x0831, 0x2F }, - { IMX_8BIT, 0x0832, 0x5F }, - { IMX_8BIT, 0x0833, 0x37 }, - { IMX_8BIT, 0x0834, 0x37 }, - { IMX_8BIT, 0x0835, 0x37 }, - { IMX_8BIT, 0x0836, 0xBF }, - { IMX_8BIT, 0x0837, 0x3F }, - { IMX_8BIT, 0x0839, 0x1F }, - { IMX_8BIT, 0x083A, 0x17 }, - { IMX_8BIT, 0x083B, 0x02 }, - - - /* Integration Time Settin */ - { IMX_8BIT, 0x0202, 0x09 }, - { IMX_8BIT, 0x0203, 0xD2 }, - - /* HDR Setting */ - { IMX_8BIT, 0x0230, 0x00 }, - { IMX_8BIT, 0x0231, 0x00 }, - { IMX_8BIT, 0x0233, 0x00 }, - { IMX_8BIT, 0x0234, 0x00 }, - { IMX_8BIT, 0x0235, 0x40 }, - { IMX_8BIT, 0x0238, 0x00 }, - { IMX_8BIT, 0x0239, 0x04 }, - { IMX_8BIT, 0x023B, 0x00 }, - { IMX_8BIT, 0x023C, 0x01 }, - { IMX_8BIT, 0x33B0, 0x04 }, - { IMX_8BIT, 0x33B1, 0x00 }, - { IMX_8BIT, 0x33B3, 0x00 }, - { IMX_8BIT, 0x33B4, 0x01 }, - { IMX_8BIT, 0x3800, 0x00 }, - { IMX_TOK_TERM, 0, 0 } -}; -/* 4 lane for 480p dvs, default 60fps, vendor provide */ -static struct imx_reg const imx134_880_592[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* mode set clear */ - { IMX_8BIT, 0x3A43, 0x01 }, - /* Clock Setting */ - { IMX_8BIT, 0x011E, 0x13 }, - { IMX_8BIT, 0x011F, 0x33 }, - { IMX_8BIT, 0x0301, 0x05 }, - { IMX_8BIT, 0x0303, 0x01 }, - { IMX_8BIT, 0x0305, 0x0C }, - { IMX_8BIT, 0x0309, 0x05 }, - { IMX_8BIT, 0x030B, 0x01 }, - { IMX_8BIT, 0x030C, 0x01 }, - { IMX_8BIT, 0x030D, 0xC8 }, - { IMX_8BIT, 0x030E, 0x01 }, - { IMX_8BIT, 0x3A06, 0x11 }, - - /* Mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x01 }, /* binning*/ - { IMX_8BIT, 0x0391, 0x22 }, /* 2x2 binning */ - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x02 }, /* H/V resize */ - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x1D }, /* downscaling ratio = 16/29 */ - { IMX_8BIT, 0x4082, 0x00 }, - { IMX_8BIT, 0x4083, 0x00 }, - { IMX_8BIT, 0x7006, 0x04 }, - - /* OptionnalFunction settig */ - { IMX_8BIT, 0x0700, 0x00 }, - { IMX_8BIT, 0x3A63, 0x00 }, - { IMX_8BIT, 0x4100, 0xF8 }, - { IMX_8BIT, 0x4203, 0xFF }, - { IMX_8BIT, 0x4344, 0x00 }, - { IMX_8BIT, 0x441C, 0x01 }, - - /* Size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* x_addr_start[15:8]:44 */ - { IMX_8BIT, 0x0345, 0x2C }, /* x_addr_start[7:0] */ - { IMX_8BIT, 0x0346, 0x00 }, /* y_addr_start[15:8]:160 */ - { IMX_8BIT, 0x0347, 0xA0 }, /* y_addr_start[7:0] */ - { IMX_8BIT, 0x0348, 0x0C }, /* x_addr_end[15:8]:3235 */ - { IMX_8BIT, 0x0349, 0xA3 }, /* x_addr_end[7:0] */ - { IMX_8BIT, 0x034A, 0x09 }, /* y_addr_end[15:8]:2307 */ - { IMX_8BIT, 0x034B, 0x03 }, /* y_addr_end[7:0] */ - { IMX_8BIT, 0x034C, 0x03 }, /* x_output_size[15:8]:880 */ - { IMX_8BIT, 0x034D, 0x70 }, /* x_output_size[7:0] */ - { IMX_8BIT, 0x034E, 0x02 }, /* y_output_size[15:8]:592 */ - { IMX_8BIT, 0x034F, 0x50 }, /* y_output_size[7:0] */ - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x06 }, - { IMX_8BIT, 0x0355, 0x3C }, - { IMX_8BIT, 0x0356, 0x04 }, - { IMX_8BIT, 0x0357, 0x32 }, - { IMX_8BIT, 0x301D, 0x30 }, - { IMX_8BIT, 0x3310, 0x03 }, - { IMX_8BIT, 0x3311, 0x70 }, - { IMX_8BIT, 0x3312, 0x02 }, - { IMX_8BIT, 0x3313, 0x50 }, - { IMX_8BIT, 0x331C, 0x04 }, - { IMX_8BIT, 0x331D, 0x4C }, - { IMX_8BIT, 0x4084, 0x03 }, - { IMX_8BIT, 0x4085, 0x70 }, - { IMX_8BIT, 0x4086, 0x02 }, - { IMX_8BIT, 0x4087, 0x50 }, - { IMX_8BIT, 0x4400, 0x00 }, - - /* Global Timing Setting */ - { IMX_8BIT, 0x0830, 0x77 }, - { IMX_8BIT, 0x0831, 0x2F }, - { IMX_8BIT, 0x0832, 0x5F }, - { IMX_8BIT, 0x0833, 0x37 }, - { IMX_8BIT, 0x0834, 0x37 }, - { IMX_8BIT, 0x0835, 0x37 }, - { IMX_8BIT, 0x0836, 0xBF }, - { IMX_8BIT, 0x0837, 0x3F }, - { IMX_8BIT, 0x0839, 0x1F }, - { IMX_8BIT, 0x083A, 0x17 }, - { IMX_8BIT, 0x083B, 0x02 }, - - - /* Integration Time Settin */ - { IMX_8BIT, 0x0202, 0x05 }, - { IMX_8BIT, 0x0203, 0x42 }, - - /* HDR Setting */ - { IMX_8BIT, 0x0230, 0x00 }, - { IMX_8BIT, 0x0231, 0x00 }, - { IMX_8BIT, 0x0233, 0x00 }, - { IMX_8BIT, 0x0234, 0x00 }, - { IMX_8BIT, 0x0235, 0x40 }, - { IMX_8BIT, 0x0238, 0x00 }, - { IMX_8BIT, 0x0239, 0x04 }, - { IMX_8BIT, 0x023B, 0x00 }, - { IMX_8BIT, 0x023C, 0x01 }, - { IMX_8BIT, 0x33B0, 0x04 }, - { IMX_8BIT, 0x33B1, 0x00 }, - { IMX_8BIT, 0x33B3, 0x00 }, - { IMX_8BIT, 0x33B4, 0x01 }, - { IMX_8BIT, 0x3800, 0x00 }, - { IMX_TOK_TERM, 0, 0 } -}; -static struct imx_reg const imx134_2336_1308_60fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - /* mode set clear */ - { IMX_8BIT, 0x3A43, 0x01 }, - /* Clock Setting */ - { IMX_8BIT, 0x011E, 0x13 }, - { IMX_8BIT, 0x011F, 0x33 }, - { IMX_8BIT, 0x0301, 0x05 }, - { IMX_8BIT, 0x0303, 0x01 }, - { IMX_8BIT, 0x0305, 0x0C }, - { IMX_8BIT, 0x0309, 0x05 }, - { IMX_8BIT, 0x030B, 0x01 }, - { IMX_8BIT, 0x030C, 0x01 }, - { IMX_8BIT, 0x030D, 0xC8 }, - { IMX_8BIT, 0x030E, 0x01 }, - { IMX_8BIT, 0x3A06, 0x11 }, - - /* Mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x00 }, /* binning*/ - { IMX_8BIT, 0x0391, 0x11 }, /* 2x2 binning */ - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x00 }, /* H/V resize */ - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x10 }, /* down scaling 16/16 = 1 */ - { IMX_8BIT, 0x4082, 0x01 }, - { IMX_8BIT, 0x4083, 0x01 }, - { IMX_8BIT, 0x7006, 0x04 }, - - /* OptionnalFunction settig */ - { IMX_8BIT, 0x0700, 0x00 }, - { IMX_8BIT, 0x3A63, 0x00 }, - { IMX_8BIT, 0x4100, 0xF8 }, - { IMX_8BIT, 0x4203, 0xFF }, - { IMX_8BIT, 0x4344, 0x00 }, - { IMX_8BIT, 0x441C, 0x01 }, - - /* Size setting */ - { IMX_8BIT, 0x0344, 0x01 }, /* x_addr_start[15:8]:72 */ - { IMX_8BIT, 0x0345, 0xD8 }, /* x_addr_start[7:0] */ - { IMX_8BIT, 0x0346, 0x02 }, /* y_addr_start[15:8]:356 */ - { IMX_8BIT, 0x0347, 0x44 }, /* y_addr_start[7:0] */ - { IMX_8BIT, 0x0348, 0x0A }, /* x_addr_end[15:8]:3207 */ - { IMX_8BIT, 0x0349, 0xF7 }, /* x_addr_end[7:0] */ - { IMX_8BIT, 0x034A, 0x07 }, /* y_addr_end[15:8]:2107 */ - { IMX_8BIT, 0x034B, 0x5F+4 }, /* y_addr_end[7:0] */ - { IMX_8BIT, 0x034C, 0x09 }, /* x_output_size[15:8]:1568 */ - { IMX_8BIT, 0x034D, 0x20 }, /* x_output_size[7:0] */ - { IMX_8BIT, 0x034E, 0x05 }, /* y_output_size[15:8]:876 */ - { IMX_8BIT, 0x034F, 0x1C+4 }, /* y_output_size[7:0] */ - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x09 }, - { IMX_8BIT, 0x0355, 0x20 }, - { IMX_8BIT, 0x0356, 0x05 }, - { IMX_8BIT, 0x0357, 0x1C+4 }, - { IMX_8BIT, 0x301D, 0x30 }, - { IMX_8BIT, 0x3310, 0x09 }, - { IMX_8BIT, 0x3311, 0x20 }, - { IMX_8BIT, 0x3312, 0x05 }, - { IMX_8BIT, 0x3313, 0x1C+4 }, - { IMX_8BIT, 0x331C, 0x03 }, - { IMX_8BIT, 0x331D, 0xE8 }, - { IMX_8BIT, 0x4084, 0x00 }, - { IMX_8BIT, 0x4085, 0x00 }, - { IMX_8BIT, 0x4086, 0x00 }, - { IMX_8BIT, 0x4087, 0x00 }, - { IMX_8BIT, 0x4400, 0x00 }, - - /* Global Timing Setting */ - { IMX_8BIT, 0x0830, 0x77 }, - { IMX_8BIT, 0x0831, 0x2F }, - { IMX_8BIT, 0x0832, 0x5F }, - { IMX_8BIT, 0x0833, 0x37 }, - { IMX_8BIT, 0x0834, 0x37 }, - { IMX_8BIT, 0x0835, 0x37 }, - { IMX_8BIT, 0x0836, 0xBF }, - { IMX_8BIT, 0x0837, 0x3F }, - { IMX_8BIT, 0x0839, 0x1F }, - { IMX_8BIT, 0x083A, 0x17 }, - { IMX_8BIT, 0x083B, 0x02 }, - - /* Integration Time Settin */ - { IMX_8BIT, 0x0202, 0x05 }, - { IMX_8BIT, 0x0203, 0x42 }, - - /* HDR Setting */ - { IMX_8BIT, 0x0230, 0x00 }, - { IMX_8BIT, 0x0231, 0x00 }, - { IMX_8BIT, 0x0233, 0x00 }, - { IMX_8BIT, 0x0234, 0x00 }, - { IMX_8BIT, 0x0235, 0x40 }, - { IMX_8BIT, 0x0238, 0x00 }, - { IMX_8BIT, 0x0239, 0x04 }, - { IMX_8BIT, 0x023B, 0x00 }, - { IMX_8BIT, 0x023C, 0x01 }, - { IMX_8BIT, 0x33B0, 0x04 }, - { IMX_8BIT, 0x33B1, 0x00 }, - { IMX_8BIT, 0x33B3, 0x00 }, - { IMX_8BIT, 0x33B4, 0x01 }, - { IMX_8BIT, 0x3800, 0x00 }, - { IMX_TOK_TERM, 0, 0 } -}; - -struct imx_resolution imx134_res_preview[] = { - { - .desc = "imx134_CIF_30fps", - .regs = imx134_720_592_30fps, - .width = 720, - .height = 592, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3600, - .lines_per_frame = 2518, - }, - { - } - }, - .bin_factor_x = 2, - .bin_factor_y = 2, - .used = 0, - }, - { - .desc = "imx134_820_552_30fps_preview", - .regs = imx134_820_552_30fps, - .width = 820, - .height = 552, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3600, - .lines_per_frame = 2518, - }, - { - } - }, - .bin_factor_x = 2, - .bin_factor_y = 2, - .used = 0, - }, - { - .desc = "imx134_820_616_preview_30fps", - .regs = imx134_820_616_30fps, - .width = 820, - .height = 616, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3600, - .lines_per_frame = 2518, - }, - { - } - }, - .bin_factor_x = 2, - .bin_factor_y = 2, - .used = 0, - }, - { - .desc = "imx134_1080p_preview_30fps", - .regs = imx134_1936_1096_30fps_v2, - .width = 1936, - .height = 1096, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3600, - .lines_per_frame = 2518, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - }, - { - .desc = "imx134_1640_1232_preview_30fps", - .regs = imx134_1640_1232_30fps, - .width = 1640, - .height = 1232, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3600, - .lines_per_frame = 2518, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - }, - { - .desc = "imx134_8M_preview_30fps", - .regs = imx134_8M_30fps, - .width = 3280, - .height = 2464, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3600, - .lines_per_frame = 2518, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - }, -}; - -struct imx_resolution imx134_res_still[] = { - { - .desc = "imx134_CIF_30fps", - .regs = imx134_1424_1168_30fps, - .width = 1424, - .height = 1168, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3600, - .lines_per_frame = 2518, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - }, - { - .desc = "imx134_VGA_still_30fps", - .regs = imx134_1640_1232_30fps, - .width = 1640, - .height = 1232, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3600, - .lines_per_frame = 2518, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - }, - { - .desc = "imx134_1080p_still_30fps", - .regs = imx134_1936_1096_30fps_v2, - .width = 1936, - .height = 1096, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3600, - .lines_per_frame = 2518, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - }, - { - .desc = "imx134_1640_1232_still_30fps", - .regs = imx134_1640_1232_30fps, - .width = 1640, - .height = 1232, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3600, - .lines_per_frame = 2518, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - }, - { - .desc = "imx134_8M_still_30fps", - .regs = imx134_8M_30fps, - .width = 3280, - .height = 2464, - .fps_options = { - { - /* WORKAROUND for FW performance limitation */ - .fps = 8, - .pixels_per_line = 6400, - .lines_per_frame = 5312, - }, - { - .fps = 30, - .pixels_per_line = 3600, - .lines_per_frame = 2518, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - }, -}; - -struct imx_resolution imx134_res_video[] = { - { - .desc = "imx134_QCIF_DVS_30fps", - .regs = imx134_240_196_30fps, - .width = 240, - .height = 196, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3600, - .lines_per_frame = 2518, - }, - { - } - }, - .bin_factor_x = 2, - .bin_factor_y = 2, - .used = 0, - }, - { - .desc = "imx134_CIF_DVS_30fps", - .regs = imx134_448_366_30fps, - .width = 448, - .height = 366, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3600, - .lines_per_frame = 2518, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - }, - { - .desc = "imx134_VGA_30fps", - .regs = imx134_820_616_30fps, - .width = 820, - .height = 616, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3600, - .lines_per_frame = 2518, - }, - { - } - }, - .bin_factor_x = 2, - .bin_factor_y = 2, - .used = 0, - }, - { - .desc = "imx134_480p", - .regs = imx134_880_592, - .width = 880, - .height = 592, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3600, - .lines_per_frame = 2700, - }, - { - .fps = 60, - .pixels_per_line = 3600, - .lines_per_frame = 1350, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - }, - { - .desc = "imx134_1568_880", - .regs = imx134_1568_880, - .width = 1568, - .height = 880, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3600, - .lines_per_frame = 2700, - }, - { - .fps = 60, - .pixels_per_line = 3600, - .lines_per_frame = 1350, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - }, - { - .desc = "imx134_1080p_dvs_30fps", - .regs = imx134_2336_1312_30fps, - .width = 2336, - .height = 1312, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3600, - .lines_per_frame = 2518, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - }, - { - .desc = "imx134_1080p_dvs_60fps", - .regs = imx134_2336_1308_60fps, - .width = 2336, - .height = 1312, - .fps_options = { - { - .fps = 60, - .pixels_per_line = 3600, - .lines_per_frame = 1350, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - }, - { - /*This setting only be used for SDV mode*/ - .desc = "imx134_8M_sdv_30fps", - .regs = imx134_8M_30fps, - .width = 3280, - .height = 2464, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 3600, - .lines_per_frame = 2518, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - }, -}; - -#endif - diff --git a/drivers/staging/media/atomisp/i2c/imx/imx135.h b/drivers/staging/media/atomisp/i2c/imx/imx135.h deleted file mode 100644 index 58b43af909f2..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/imx135.h +++ /dev/null @@ -1,3374 +0,0 @@ -/* - * Support for Sony IMX camera sensor. - * - * Copyright (c) 2010 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#ifndef __IMX135_H__ -#define __IMX135_H__ - -#include "common.h" - -#define IMX_SC_CMMN_CHIP_ID_H 0x0016 -#define IMX_SC_CMMN_CHIP_ID_L 0x0017 - -/* - * focal length bits definition: - * bits 31-16: numerator, bits 15-0: denominator - */ -#define IMX_FOCAL_LENGTH_DEFAULT 0x1710064 - -/* - * current f-number bits definition: - * bits 31-16: numerator, bits 15-0: denominator - */ -#define IMX_F_NUMBER_DEFAULT 0x16000a - -/* - * f-number range bits definition: - * bits 31-24: max f-number numerator - * bits 23-16: max f-number denominator - * bits 15-8: min f-number numerator - * bits 7-0: min f-number denominator - */ -#define IMX_F_NUMBER_RANGE 0x160a160a - -#define GROUPED_PARAMETER_HOLD_ENABLE {IMX_8BIT, 0x0104, 0x1} -#define GROUPED_PARAMETER_HOLD_DISABLE {IMX_8BIT, 0x0104, 0x0} - -#define IMX135_EMBEDDED_DATA_LINE_NUM 2 -#define IMX135_OUTPUT_DATA_FORMAT_REG 0x0112 -#define IMX135_OUTPUT_FORMAT_RAW10 0x0a0a -/* - * We use three different MIPI rates for our modes based on the resolution and - * FPS requirements. So we have three PLL configurationa and these are based - * on the EMC friendly MIPI values. - * - * Maximum clock: Pix clock @ 360.96MHz MIPI @ 451.2MHz 902.4mbps - * Reduced clock: Pix clock @ 273.00MHz MIPI @ 342.0MHz 684.0mbps - * Binning modes: Pix clock @ 335.36MHz MIPI @ 209.6MHz 419.2mbps - * Global Timing registers are based on the data rates and these are part of - * the below clock definitions. - */ -/* MIPI 499.2MHz 998.4mbps PIXCLK: 399.36MHz */ -#define PLL_SETTINGS_FOR_MIPI_499_2MHZ_SALTBAY \ - {IMX_8BIT, 0x011e, 0x13}, \ - {IMX_8BIT, 0x011f, 0x33}, \ - {IMX_8BIT, 0x0301, 0x05}, \ - {IMX_8BIT, 0x0303, 0x01}, \ - {IMX_8BIT, 0x0305, 0x0c}, \ - {IMX_8BIT, 0x0309, 0x05}, \ - {IMX_8BIT, 0x030b, 0x01}, \ - {IMX_8BIT, 0x030c, 0x02}, \ - {IMX_8BIT, 0x030d, 0x70}, \ - {IMX_8BIT, 0x030e, 0x01}, \ - {IMX_8BIT, 0x3a06, 0x11}, \ - {IMX_8BIT, 0x0830, 0x7f}, \ - {IMX_8BIT, 0x0831, 0x37}, \ - {IMX_8BIT, 0x0832, 0x67}, \ - {IMX_8BIT, 0x0833, 0x3f}, \ - {IMX_8BIT, 0x0834, 0x3f}, \ - {IMX_8BIT, 0x0835, 0x47}, \ - {IMX_8BIT, 0x0836, 0xdf}, \ - {IMX_8BIT, 0x0837, 0x47}, \ - {IMX_8BIT, 0x0839, 0x1f}, \ - {IMX_8BIT, 0x083a, 0x17}, \ - {IMX_8BIT, 0x083b, 0x02} - -/* MIPI 451.2MHz 902.4mbps PIXCLK: 360.96MHz */ -#define PLL_SETTINGS_FOR_MIPI_451_2MHZ_SALTBAY \ - {IMX_8BIT, 0x011e, 0x13}, \ - {IMX_8BIT, 0x011f, 0x33}, \ - {IMX_8BIT, 0x0301, 0x05}, \ - {IMX_8BIT, 0x0303, 0x01}, \ - {IMX_8BIT, 0x0305, 0x0c}, \ - {IMX_8BIT, 0x0309, 0x05}, \ - {IMX_8BIT, 0x030b, 0x01}, \ - {IMX_8BIT, 0x030c, 0x02}, \ - {IMX_8BIT, 0x030d, 0x34}, \ - {IMX_8BIT, 0x030e, 0x01}, \ - {IMX_8BIT, 0x3a06, 0x11}, \ - {IMX_8BIT, 0x0830, 0x7f}, \ - {IMX_8BIT, 0x0831, 0x37}, \ - {IMX_8BIT, 0x0832, 0x67}, \ - {IMX_8BIT, 0x0833, 0x3f}, \ - {IMX_8BIT, 0x0834, 0x3f}, \ - {IMX_8BIT, 0x0835, 0x47}, \ - {IMX_8BIT, 0x0836, 0xdf}, \ - {IMX_8BIT, 0x0837, 0x47}, \ - {IMX_8BIT, 0x0839, 0x1f}, \ - {IMX_8BIT, 0x083a, 0x17}, \ - {IMX_8BIT, 0x083b, 0x02} - -/* MIPI 209.6MHz, 419.2mbps PIXCLK: 335.36 MHz */ -#define PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY \ - {IMX_8BIT, 0x011e, 0x13}, \ - {IMX_8BIT, 0x011f, 0x33}, \ - {IMX_8BIT, 0x0301, 0x05}, \ - {IMX_8BIT, 0x0303, 0x01}, \ - {IMX_8BIT, 0x0305, 0x06}, \ - {IMX_8BIT, 0x0309, 0x05}, \ - {IMX_8BIT, 0x030b, 0x02}, \ - {IMX_8BIT, 0x030c, 0x01}, \ - {IMX_8BIT, 0x030d, 0x06}, \ - {IMX_8BIT, 0x030e, 0x01}, \ - {IMX_8BIT, 0x3a06, 0x12}, \ - {IMX_8BIT, 0x0830, 0x5f}, \ - {IMX_8BIT, 0x0831, 0x1f}, \ - {IMX_8BIT, 0x0832, 0x3f}, \ - {IMX_8BIT, 0x0833, 0x1f}, \ - {IMX_8BIT, 0x0834, 0x1f}, \ - {IMX_8BIT, 0x0835, 0x17}, \ - {IMX_8BIT, 0x0836, 0x67}, \ - {IMX_8BIT, 0x0837, 0x27}, \ - {IMX_8BIT, 0x0839, 0x1f}, \ - {IMX_8BIT, 0x083a, 0x17}, \ - {IMX_8BIT, 0x083b, 0x02} - -/* MIPI 342MHz 684mbps PIXCLK: 273.6MHz */ -#define PLL_SETTINGS_FOR_MIPI_342MHZ_SALTBAY \ - {IMX_8BIT, 0x011e, 0x13}, \ - {IMX_8BIT, 0x011f, 0x33}, \ - {IMX_8BIT, 0x0301, 0x05}, \ - {IMX_8BIT, 0x0303, 0x01}, \ - {IMX_8BIT, 0x0305, 0x08}, \ - {IMX_8BIT, 0x0309, 0x05}, \ - {IMX_8BIT, 0x030b, 0x01}, \ - {IMX_8BIT, 0x030c, 0x01}, \ - {IMX_8BIT, 0x030d, 0x1d}, \ - {IMX_8BIT, 0x030e, 0x01}, \ - {IMX_8BIT, 0x3a06, 0x11}, \ - {IMX_8BIT, 0x0830, 0x77}, \ - {IMX_8BIT, 0x0831, 0x2f}, \ - {IMX_8BIT, 0x0832, 0x4f}, \ - {IMX_8BIT, 0x0833, 0x37}, \ - {IMX_8BIT, 0x0834, 0x2f}, \ - {IMX_8BIT, 0x0835, 0x37}, \ - {IMX_8BIT, 0x0836, 0xa7}, \ - {IMX_8BIT, 0x0837, 0x37}, \ - {IMX_8BIT, 0x0839, 0x1f}, \ - {IMX_8BIT, 0x083a, 0x17}, \ - {IMX_8BIT, 0x083b, 0x02} - -/* Basic settings: Applied only once after the sensor power up */ -static struct imx_reg const imx135_init_settings[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - { IMX_8BIT, 0x0220, 0x01}, - { IMX_8BIT, 0x3008, 0xB0}, - { IMX_8BIT, 0x320A, 0x01}, - { IMX_8BIT, 0x320D, 0x10}, - { IMX_8BIT, 0x3216, 0x2E}, - { IMX_8BIT, 0x3230, 0x0A}, - { IMX_8BIT, 0x3228, 0x05}, - { IMX_8BIT, 0x3229, 0x02}, - { IMX_8BIT, 0x322C, 0x02}, - { IMX_8BIT, 0x3302, 0x10}, - { IMX_8BIT, 0x3390, 0x45}, - { IMX_8BIT, 0x3409, 0x0C}, - { IMX_8BIT, 0x340B, 0xF5}, - { IMX_8BIT, 0x340C, 0x2D}, - { IMX_8BIT, 0x3412, 0x41}, - { IMX_8BIT, 0x3413, 0xAD}, - { IMX_8BIT, 0x3414, 0x1E}, - { IMX_8BIT, 0x3427, 0x04}, - { IMX_8BIT, 0x3480, 0x1E}, - { IMX_8BIT, 0x3484, 0x1E}, - { IMX_8BIT, 0x3488, 0x1E}, - { IMX_8BIT, 0x348C, 0x1E}, - { IMX_8BIT, 0x3490, 0x1E}, - { IMX_8BIT, 0x3494, 0x1E}, - { IMX_8BIT, 0x349C, 0x38}, - { IMX_8BIT, 0x34A3, 0x38}, - { IMX_8BIT, 0x3511, 0x8F}, - { IMX_8BIT, 0x3518, 0x00}, - { IMX_8BIT, 0x3519, 0x94}, - { IMX_8BIT, 0x3833, 0x20}, - { IMX_8BIT, 0x3893, 0x01}, - { IMX_8BIT, 0x38C2, 0x08}, - { IMX_8BIT, 0x38C3, 0x08}, - { IMX_8BIT, 0x3C09, 0x01}, - { IMX_8BIT, 0x4000, 0x0E}, - { IMX_8BIT, 0x4300, 0x00}, - { IMX_8BIT, 0x4316, 0x12}, - { IMX_8BIT, 0x4317, 0x22}, - { IMX_8BIT, 0x4318, 0x00}, - { IMX_8BIT, 0x4319, 0x00}, - { IMX_8BIT, 0x431A, 0x00}, - { IMX_8BIT, 0x4324, 0x03}, - { IMX_8BIT, 0x4325, 0x20}, - { IMX_8BIT, 0x4326, 0x03}, - { IMX_8BIT, 0x4327, 0x84}, - { IMX_8BIT, 0x4328, 0x03}, - { IMX_8BIT, 0x4329, 0x20}, - { IMX_8BIT, 0x432A, 0x03}, - { IMX_8BIT, 0x432B, 0x84}, - { IMX_8BIT, 0x432C, 0x01}, - { IMX_8BIT, 0x4401, 0x3F}, - { IMX_8BIT, 0x4402, 0xFF}, - { IMX_8BIT, 0x4412, 0x3F}, - { IMX_8BIT, 0x4413, 0xFF}, - { IMX_8BIT, 0x441D, 0x28}, - { IMX_8BIT, 0x4444, 0x00}, - { IMX_8BIT, 0x4445, 0x00}, - { IMX_8BIT, 0x4446, 0x3F}, - { IMX_8BIT, 0x4447, 0xFF}, - { IMX_8BIT, 0x4452, 0x00}, - { IMX_8BIT, 0x4453, 0xA0}, - { IMX_8BIT, 0x4454, 0x08}, - { IMX_8BIT, 0x4455, 0x00}, - { IMX_8BIT, 0x4458, 0x18}, - { IMX_8BIT, 0x4459, 0x18}, - { IMX_8BIT, 0x445A, 0x3F}, - { IMX_8BIT, 0x445B, 0x3A}, - { IMX_8BIT, 0x4462, 0x00}, - { IMX_8BIT, 0x4463, 0x00}, - { IMX_8BIT, 0x4464, 0x00}, - { IMX_8BIT, 0x4465, 0x00}, - { IMX_8BIT, 0x446E, 0x01}, - { IMX_8BIT, 0x4500, 0x1F}, - { IMX_8BIT, 0x600a, 0x00}, - { IMX_8BIT, 0x380a, 0x00}, - { IMX_8BIT, 0x380b, 0x00}, - { IMX_8BIT, 0x4103, 0x00}, - { IMX_8BIT, 0x4243, 0x9a}, - { IMX_8BIT, 0x4330, 0x01}, - { IMX_8BIT, 0x4331, 0x90}, - { IMX_8BIT, 0x4332, 0x02}, - { IMX_8BIT, 0x4333, 0x58}, - { IMX_8BIT, 0x4334, 0x03}, - { IMX_8BIT, 0x4335, 0x20}, - { IMX_8BIT, 0x4336, 0x03}, - { IMX_8BIT, 0x4337, 0x84}, - { IMX_8BIT, 0x433C, 0x01}, - { IMX_8BIT, 0x4340, 0x02}, - { IMX_8BIT, 0x4341, 0x58}, - { IMX_8BIT, 0x4342, 0x03}, - { IMX_8BIT, 0x4343, 0x52}, - { IMX_8BIT, 0x4364, 0x0b}, - { IMX_8BIT, 0x4368, 0x00}, - { IMX_8BIT, 0x4369, 0x0f}, - { IMX_8BIT, 0x436a, 0x03}, - { IMX_8BIT, 0x436b, 0xa8}, - { IMX_8BIT, 0x436c, 0x00}, - { IMX_8BIT, 0x436d, 0x00}, - { IMX_8BIT, 0x436e, 0x00}, - { IMX_8BIT, 0x436f, 0x06}, - { IMX_8BIT, 0x4281, 0x21}, - { IMX_8BIT, 0x4282, 0x18}, - { IMX_8BIT, 0x4283, 0x04}, - { IMX_8BIT, 0x4284, 0x08}, - { IMX_8BIT, 0x4287, 0x7f}, - { IMX_8BIT, 0x4288, 0x08}, - { IMX_8BIT, 0x428c, 0x08}, - { IMX_8BIT, 0x4297, 0x00}, - { IMX_8BIT, 0x4299, 0x7E}, - { IMX_8BIT, 0x42A4, 0xFB}, - { IMX_8BIT, 0x42A5, 0x7E}, - { IMX_8BIT, 0x42A6, 0xDF}, - { IMX_8BIT, 0x42A7, 0xB7}, - { IMX_8BIT, 0x42AF, 0x03}, - { IMX_8BIT, 0x4207, 0x03}, - { IMX_8BIT, 0x4218, 0x00}, - { IMX_8BIT, 0x421B, 0x20}, - { IMX_8BIT, 0x421F, 0x04}, - { IMX_8BIT, 0x4222, 0x02}, - { IMX_8BIT, 0x4223, 0x22}, - { IMX_8BIT, 0x422E, 0x54}, - { IMX_8BIT, 0x422F, 0xFB}, - { IMX_8BIT, 0x4230, 0xFF}, - { IMX_8BIT, 0x4231, 0xFE}, - { IMX_8BIT, 0x4232, 0xFF}, - { IMX_8BIT, 0x4235, 0x58}, - { IMX_8BIT, 0x4236, 0xF7}, - { IMX_8BIT, 0x4237, 0xFD}, - { IMX_8BIT, 0x4239, 0x4E}, - { IMX_8BIT, 0x423A, 0xFC}, - { IMX_8BIT, 0x423B, 0xFD}, - { IMX_8BIT, 0x4300, 0x00}, - { IMX_8BIT, 0x4316, 0x12}, - { IMX_8BIT, 0x4317, 0x22}, - { IMX_8BIT, 0x4318, 0x00}, - { IMX_8BIT, 0x4319, 0x00}, - { IMX_8BIT, 0x431A, 0x00}, - { IMX_8BIT, 0x4324, 0x03}, - { IMX_8BIT, 0x4325, 0x20}, - { IMX_8BIT, 0x4326, 0x03}, - { IMX_8BIT, 0x4327, 0x84}, - { IMX_8BIT, 0x4328, 0x03}, - { IMX_8BIT, 0x4329, 0x20}, - { IMX_8BIT, 0x432A, 0x03}, - { IMX_8BIT, 0x432B, 0x20}, - { IMX_8BIT, 0x432C, 0x01}, - { IMX_8BIT, 0x432D, 0x01}, - { IMX_8BIT, 0x4338, 0x02}, - { IMX_8BIT, 0x4339, 0x00}, - { IMX_8BIT, 0x433A, 0x00}, - { IMX_8BIT, 0x433B, 0x02}, - { IMX_8BIT, 0x435A, 0x03}, - { IMX_8BIT, 0x435B, 0x84}, - { IMX_8BIT, 0x435E, 0x01}, - { IMX_8BIT, 0x435F, 0xFF}, - { IMX_8BIT, 0x4360, 0x01}, - { IMX_8BIT, 0x4361, 0xF4}, - { IMX_8BIT, 0x4362, 0x03}, - { IMX_8BIT, 0x4363, 0x84}, - { IMX_8BIT, 0x437B, 0x01}, - { IMX_8BIT, 0x4400, 0x00}, /* STATS off ISP do not support STATS*/ - { IMX_8BIT, 0x4401, 0x3F}, - { IMX_8BIT, 0x4402, 0xFF}, - { IMX_8BIT, 0x4404, 0x13}, - { IMX_8BIT, 0x4405, 0x26}, - { IMX_8BIT, 0x4406, 0x07}, - { IMX_8BIT, 0x4408, 0x20}, - { IMX_8BIT, 0x4409, 0xE5}, - { IMX_8BIT, 0x440A, 0xFB}, - { IMX_8BIT, 0x440C, 0xF6}, - { IMX_8BIT, 0x440D, 0xEA}, - { IMX_8BIT, 0x440E, 0x20}, - { IMX_8BIT, 0x4410, 0x00}, - { IMX_8BIT, 0x4411, 0x00}, - { IMX_8BIT, 0x4412, 0x3F}, - { IMX_8BIT, 0x4413, 0xFF}, - { IMX_8BIT, 0x4414, 0x1F}, - { IMX_8BIT, 0x4415, 0xFF}, - { IMX_8BIT, 0x4416, 0x20}, - { IMX_8BIT, 0x4417, 0x00}, - { IMX_8BIT, 0x4418, 0x1F}, - { IMX_8BIT, 0x4419, 0xFF}, - { IMX_8BIT, 0x441A, 0x20}, - { IMX_8BIT, 0x441B, 0x00}, - { IMX_8BIT, 0x441D, 0x40}, - { IMX_8BIT, 0x441E, 0x1E}, - { IMX_8BIT, 0x441F, 0x38}, - { IMX_8BIT, 0x4420, 0x01}, - { IMX_8BIT, 0x4444, 0x00}, - { IMX_8BIT, 0x4445, 0x00}, - { IMX_8BIT, 0x4446, 0x1D}, - { IMX_8BIT, 0x4447, 0xF9}, - { IMX_8BIT, 0x4452, 0x00}, - { IMX_8BIT, 0x4453, 0xA0}, - { IMX_8BIT, 0x4454, 0x08}, - { IMX_8BIT, 0x4455, 0x00}, - { IMX_8BIT, 0x4456, 0x0F}, - { IMX_8BIT, 0x4457, 0xFF}, - { IMX_8BIT, 0x4458, 0x18}, - { IMX_8BIT, 0x4459, 0x18}, - { IMX_8BIT, 0x445A, 0x3F}, - { IMX_8BIT, 0x445B, 0x3A}, - { IMX_8BIT, 0x445C, 0x00}, - { IMX_8BIT, 0x445D, 0x28}, - { IMX_8BIT, 0x445E, 0x01}, - { IMX_8BIT, 0x445F, 0x90}, - { IMX_8BIT, 0x4460, 0x00}, - { IMX_8BIT, 0x4461, 0x60}, - { IMX_8BIT, 0x4462, 0x00}, - { IMX_8BIT, 0x4463, 0x00}, - { IMX_8BIT, 0x4464, 0x00}, - { IMX_8BIT, 0x4465, 0x00}, - { IMX_8BIT, 0x446C, 0x00}, - { IMX_8BIT, 0x446D, 0x00}, - { IMX_8BIT, 0x446E, 0x00}, - { IMX_8BIT, 0x452A, 0x02}, - { IMX_8BIT, 0x0712, 0x01}, - { IMX_8BIT, 0x0713, 0x00}, - { IMX_8BIT, 0x0714, 0x01}, - { IMX_8BIT, 0x0715, 0x00}, - { IMX_8BIT, 0x0716, 0x01}, - { IMX_8BIT, 0x0717, 0x00}, - { IMX_8BIT, 0x0718, 0x01}, - { IMX_8BIT, 0x0719, 0x00}, - { IMX_8BIT, 0x4500, 0x1F }, - PLL_SETTINGS_FOR_MIPI_451_2MHZ_SALTBAY, - { IMX_8BIT, 0x0205, 0x00}, - { IMX_8BIT, 0x020E, 0x01}, - { IMX_8BIT, 0x020F, 0x00}, - { IMX_8BIT, 0x0210, 0x02}, - { IMX_8BIT, 0x0211, 0x00}, - { IMX_8BIT, 0x0212, 0x02}, - { IMX_8BIT, 0x0213, 0x00}, - { IMX_8BIT, 0x0214, 0x01}, - { IMX_8BIT, 0x0215, 0x00}, - /* HDR Setting */ - { IMX_8BIT, 0x0230, 0x00}, - { IMX_8BIT, 0x0231, 0x00}, - { IMX_8BIT, 0x0233, 0x00}, - { IMX_8BIT, 0x0234, 0x00}, - { IMX_8BIT, 0x0235, 0x40}, - { IMX_8BIT, 0x0238, 0x00}, - { IMX_8BIT, 0x0239, 0x04}, - { IMX_8BIT, 0x023B, 0x00}, - { IMX_8BIT, 0x023C, 0x01}, - { IMX_8BIT, 0x33B0, 0x04}, - { IMX_8BIT, 0x33B1, 0x00}, - { IMX_8BIT, 0x33B3, 0x00}, - { IMX_8BIT, 0x33B4, 0x01}, - { IMX_8BIT, 0x3800, 0x00}, - GROUPED_PARAMETER_HOLD_DISABLE, - { IMX_TOK_TERM, 0, 0} -}; - -/********* Preview, continuous capture and still modes *****************/ - -static struct imx_reg const imx135_13m[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_451_2MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03}, - {IMX_8BIT, 0x0112, 0x0A}, - {IMX_8BIT, 0x0113, 0x0A}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x0390, 0x00}, - {IMX_8BIT, 0x0391, 0x11}, - {IMX_8BIT, 0x0392, 0x00}, - {IMX_8BIT, 0x0401, 0x00}, - {IMX_8BIT, 0x0404, 0x00}, - {IMX_8BIT, 0x0405, 0x10}, - {IMX_8BIT, 0x4082, 0x01}, - {IMX_8BIT, 0x4083, 0x01}, - {IMX_8BIT, 0x4203, 0xFF}, - {IMX_8BIT, 0x7006, 0x04}, - /* Size Setting */ - {IMX_8BIT, 0x0344, 0x00}, /* 0, 0, 4207,3119 4208x3120 */ - {IMX_8BIT, 0x0345, 0x00}, - {IMX_8BIT, 0x0346, 0x00}, - {IMX_8BIT, 0x0347, 0x00}, - {IMX_8BIT, 0x0348, 0x10}, - {IMX_8BIT, 0x0349, 0x6F}, - {IMX_8BIT, 0x034A, 0x0C}, - {IMX_8BIT, 0x034B, 0x2F}, - {IMX_8BIT, 0x034C, 0x10}, - {IMX_8BIT, 0x034D, 0x70}, - {IMX_8BIT, 0x034E, 0x0C}, - {IMX_8BIT, 0x034F, 0x30}, - {IMX_8BIT, 0x0350, 0x00}, - {IMX_8BIT, 0x0351, 0x00}, - {IMX_8BIT, 0x0352, 0x00}, - {IMX_8BIT, 0x0353, 0x00}, - {IMX_8BIT, 0x0354, 0x10}, /* 4208x3120 */ - {IMX_8BIT, 0x0355, 0x70}, - {IMX_8BIT, 0x0356, 0x0C}, - {IMX_8BIT, 0x0357, 0x30}, - {IMX_8BIT, 0x301D, 0x30}, - {IMX_8BIT, 0x3310, 0x10}, - {IMX_8BIT, 0x3311, 0x70}, - {IMX_8BIT, 0x3312, 0x0C}, - {IMX_8BIT, 0x3313, 0x30}, - {IMX_8BIT, 0x331C, 0x00}, - {IMX_8BIT, 0x331D, 0x10}, - {IMX_8BIT, 0x4084, 0x00}, /* If scaling, Fill this */ - {IMX_8BIT, 0x4085, 0x00}, - {IMX_8BIT, 0x4086, 0x00}, - {IMX_8BIT, 0x4087, 0x00}, - {IMX_8BIT, 0x4400, 0x00}, - {IMX_TOK_TERM, 0, 0}, -}; - -/* 13MP reduced pixel clock MIPI 342MHz is EMC friendly*/ -static struct imx_reg const imx135_13m_for_mipi_342[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_342MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03}, - {IMX_8BIT, 0x0112, 0x0A}, - {IMX_8BIT, 0x0113, 0x0A}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x0390, 0x00}, - {IMX_8BIT, 0x0391, 0x11}, - {IMX_8BIT, 0x0392, 0x00}, - {IMX_8BIT, 0x0401, 0x00}, - {IMX_8BIT, 0x0404, 0x00}, - {IMX_8BIT, 0x0405, 0x10}, - {IMX_8BIT, 0x4082, 0x01}, - {IMX_8BIT, 0x4083, 0x01}, - {IMX_8BIT, 0x4203, 0xFF}, - {IMX_8BIT, 0x7006, 0x04}, - /* Size Setting */ - {IMX_8BIT, 0x0344, 0x00}, - {IMX_8BIT, 0x0345, 0x00}, - {IMX_8BIT, 0x0346, 0x00}, - {IMX_8BIT, 0x0347, 0x00}, - {IMX_8BIT, 0x0348, 0x10}, - {IMX_8BIT, 0x0349, 0x6F}, - {IMX_8BIT, 0x034A, 0x0C}, - {IMX_8BIT, 0x034B, 0x2F}, - {IMX_8BIT, 0x034C, 0x10}, - {IMX_8BIT, 0x034D, 0x70}, - {IMX_8BIT, 0x034E, 0x0C}, - {IMX_8BIT, 0x034F, 0x30}, - {IMX_8BIT, 0x0350, 0x00}, - {IMX_8BIT, 0x0351, 0x00}, - {IMX_8BIT, 0x0352, 0x00}, - {IMX_8BIT, 0x0353, 0x00}, - {IMX_8BIT, 0x0354, 0x10}, - {IMX_8BIT, 0x0355, 0x70}, - {IMX_8BIT, 0x0356, 0x0C}, - {IMX_8BIT, 0x0357, 0x30}, - {IMX_8BIT, 0x301D, 0x30}, - {IMX_8BIT, 0x3310, 0x10}, - {IMX_8BIT, 0x3311, 0x70}, - {IMX_8BIT, 0x3312, 0x0C}, - {IMX_8BIT, 0x3313, 0x30}, - {IMX_8BIT, 0x331C, 0x00}, - {IMX_8BIT, 0x331D, 0x10}, - {IMX_8BIT, 0x4084, 0x00}, /* If scaling, Fill this */ - {IMX_8BIT, 0x4085, 0x00}, - {IMX_8BIT, 0x4086, 0x00}, - {IMX_8BIT, 0x4087, 0x00}, - {IMX_8BIT, 0x4400, 0x00}, - {IMX_TOK_TERM, 0, 0}, -}; - -static struct imx_reg const imx135_10m[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_451_2MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03}, - {IMX_8BIT, 0x0112, 0x0A}, - {IMX_8BIT, 0x0113, 0x0A}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x0390, 0x00}, - {IMX_8BIT, 0x0391, 0x11}, - {IMX_8BIT, 0x0392, 0x00}, - {IMX_8BIT, 0x0401, 0x00}, - {IMX_8BIT, 0x0404, 0x00}, - {IMX_8BIT, 0x0405, 0x10}, - {IMX_8BIT, 0x4082, 0x01}, - {IMX_8BIT, 0x4083, 0x01}, - {IMX_8BIT, 0x4203, 0xFF}, - {IMX_8BIT, 0x7006, 0x04}, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x00}, /* 0, 376, 4207, 2743 */ - {IMX_8BIT, 0x0345, 0x00}, - {IMX_8BIT, 0x0346, 0x01}, - {IMX_8BIT, 0x0347, 0x78}, - {IMX_8BIT, 0x0348, 0x10}, - {IMX_8BIT, 0x0349, 0x6f}, - {IMX_8BIT, 0x034A, 0x0a}, - {IMX_8BIT, 0x034B, 0xb7}, - {IMX_8BIT, 0x034C, 0x10}, /* 4208x2368 */ - {IMX_8BIT, 0x034D, 0x70}, - {IMX_8BIT, 0x034E, 0x09}, - {IMX_8BIT, 0x034F, 0x40}, - {IMX_8BIT, 0x0350, 0x00}, - {IMX_8BIT, 0x0351, 0x00}, - {IMX_8BIT, 0x0352, 0x00}, - {IMX_8BIT, 0x0353, 0x00}, - {IMX_8BIT, 0x0354, 0x10}, - {IMX_8BIT, 0x0355, 0x70}, - {IMX_8BIT, 0x0356, 0x09}, - {IMX_8BIT, 0x0357, 0x40}, - {IMX_8BIT, 0x301D, 0x30}, - {IMX_8BIT, 0x3310, 0x10}, - {IMX_8BIT, 0x3311, 0x70}, - {IMX_8BIT, 0x3312, 0x09}, - {IMX_8BIT, 0x3313, 0x40}, - {IMX_8BIT, 0x331C, 0x01}, - {IMX_8BIT, 0x331D, 0x68}, - {IMX_8BIT, 0x4084, 0x00}, - {IMX_8BIT, 0x4085, 0x00}, - {IMX_8BIT, 0x4086, 0x00}, - {IMX_8BIT, 0x4087, 0x00}, - {IMX_8BIT, 0x4400, 0x00}, - {IMX_TOK_TERM, 0, 0}, -}; - -static struct imx_reg const imx135_10m_for_mipi_342[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_342MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03}, - {IMX_8BIT, 0x0112, 0x0A}, - {IMX_8BIT, 0x0113, 0x0A}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x0390, 0x00}, - {IMX_8BIT, 0x0391, 0x11}, - {IMX_8BIT, 0x0392, 0x00}, - {IMX_8BIT, 0x0401, 0x00}, - {IMX_8BIT, 0x0404, 0x00}, - {IMX_8BIT, 0x0405, 0x10}, - {IMX_8BIT, 0x4082, 0x01}, - {IMX_8BIT, 0x4083, 0x01}, - {IMX_8BIT, 0x4203, 0xFF}, - {IMX_8BIT, 0x7006, 0x04}, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x00}, /* 0, 376, 4207, 2743 */ - {IMX_8BIT, 0x0345, 0x00}, - {IMX_8BIT, 0x0346, 0x01}, - {IMX_8BIT, 0x0347, 0x78}, - {IMX_8BIT, 0x0348, 0x10}, - {IMX_8BIT, 0x0349, 0x6f}, - {IMX_8BIT, 0x034A, 0x0a}, - {IMX_8BIT, 0x034B, 0xb7}, - {IMX_8BIT, 0x034C, 0x10}, /* 4208x2368 */ - {IMX_8BIT, 0x034D, 0x70}, - {IMX_8BIT, 0x034E, 0x09}, - {IMX_8BIT, 0x034F, 0x40}, - {IMX_8BIT, 0x0350, 0x00}, - {IMX_8BIT, 0x0351, 0x00}, - {IMX_8BIT, 0x0352, 0x00}, - {IMX_8BIT, 0x0353, 0x00}, - {IMX_8BIT, 0x0354, 0x10}, - {IMX_8BIT, 0x0355, 0x70}, - {IMX_8BIT, 0x0356, 0x09}, - {IMX_8BIT, 0x0357, 0x40}, - {IMX_8BIT, 0x301D, 0x30}, - {IMX_8BIT, 0x3310, 0x10}, - {IMX_8BIT, 0x3311, 0x70}, - {IMX_8BIT, 0x3312, 0x09}, - {IMX_8BIT, 0x3313, 0x40}, - {IMX_8BIT, 0x331C, 0x01}, - {IMX_8BIT, 0x331D, 0x68}, - {IMX_8BIT, 0x4084, 0x00}, - {IMX_8BIT, 0x4085, 0x00}, - {IMX_8BIT, 0x4086, 0x00}, - {IMX_8BIT, 0x4087, 0x00}, - {IMX_8BIT, 0x4400, 0x00}, - {IMX_TOK_TERM, 0, 0}, -}; - -/* - * It is 8.5 DS from (3:2)8m cropped setting. - * - * The 8m(3:2) cropped setting is 2992x2448 effective res. - * The ISP effect cropped setting should be 1408x1152 effect res. - * - * Consider ISP 16x16 padding: - * sensor outputs 368x304 - * cropped region is 3128x2584 - */ -static struct imx_reg const imx135_368x304_cropped[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03}, - {IMX_8BIT, 0x0112, 0x0A}, - {IMX_8BIT, 0x0113, 0x0A}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x0390, 0x00}, - {IMX_8BIT, 0x0391, 0x11}, /* no binning */ - {IMX_8BIT, 0x0392, 0x00}, - {IMX_8BIT, 0x0401, 0x02}, /* resize */ - {IMX_8BIT, 0x0404, 0x00}, - {IMX_8BIT, 0x0405, 0x88}, /* 136/16=8.5 */ - {IMX_8BIT, 0x4082, 0x00}, - {IMX_8BIT, 0x4083, 0x00}, - {IMX_8BIT, 0x4203, 0xFF}, - {IMX_8BIT, 0x7006, 0x04}, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x02}, /* X_ADD_STA */ - {IMX_8BIT, 0x0345, 0x1C}, /* 540 */ - {IMX_8BIT, 0x0346, 0x01}, /* Y_ADD_STA */ - {IMX_8BIT, 0x0347, 0x0C}, /* 268 */ - {IMX_8BIT, 0x0348, 0x0E}, /* X_ADD_END */ - {IMX_8BIT, 0x0349, 0x53}, /* 3667 */ - {IMX_8BIT, 0x034A, 0x0B}, /* Y_ADD_END */ - {IMX_8BIT, 0x034B, 0x23}, /* 2851 */ - {IMX_8BIT, 0x034C, 0x01}, /* X_OUT_SIZE */ - {IMX_8BIT, 0x034D, 0x70}, /* 368 */ - {IMX_8BIT, 0x034E, 0x01}, /* Y_OUT_SIZE */ - {IMX_8BIT, 0x034F, 0x30}, /* 304 */ - {IMX_8BIT, 0x0350, 0x00}, /* No Dig crop */ - {IMX_8BIT, 0x0351, 0x00}, - {IMX_8BIT, 0x0352, 0x00}, - {IMX_8BIT, 0x0353, 0x00}, - {IMX_8BIT, 0x0354, 0x0C}, /* Cut out siz same as the size after crop */ - {IMX_8BIT, 0x0355, 0x38}, - {IMX_8BIT, 0x0356, 0x0A}, - {IMX_8BIT, 0x0357, 0x18}, - {IMX_8BIT, 0x301D, 0x30}, /* ?? */ - {IMX_8BIT, 0x3310, 0x01}, /* Write H and V size same as output size? */ - {IMX_8BIT, 0x3311, 0x70}, - {IMX_8BIT, 0x3312, 0x01}, - {IMX_8BIT, 0x3313, 0x30}, - {IMX_8BIT, 0x331C, 0x02}, /* ?? */ - {IMX_8BIT, 0x331D, 0xD0}, - {IMX_8BIT, 0x4084, 0x01}, /* Scaling related? */ - {IMX_8BIT, 0x4085, 0x70}, - {IMX_8BIT, 0x4086, 0x01}, - {IMX_8BIT, 0x4087, 0x30}, - {IMX_8BIT, 0x4400, 0x00}, /* STATS off */ - {IMX_TOK_TERM, 0, 0}, -}; - -/* - * It is 1/4 binning from 8m cropped setting. - * - * The 8m cropped setting is 3264x2448 effective res. - * The xga cropped setting should be 816x612 effect res. - * - * Consider ISP 16x16 padding: - * sensor outputs 832x628 - * cropped region is 3328x2512 - */ -static struct imx_reg const imx135_xga_cropped[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03}, - {IMX_8BIT, 0x0112, 0x0A}, - {IMX_8BIT, 0x0113, 0x0A}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x0390, 0x01}, - {IMX_8BIT, 0x0391, 0x44}, - {IMX_8BIT, 0x0392, 0x00}, - {IMX_8BIT, 0x0401, 0x00}, - {IMX_8BIT, 0x0404, 0x00}, - {IMX_8BIT, 0x0405, 0x10}, - {IMX_8BIT, 0x4082, 0x00}, - {IMX_8BIT, 0x4083, 0x00}, -/* {IMX_8BIT, 0x4203, 0xFF}, */ - {IMX_8BIT, 0x7006, 0x04}, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x01}, /* X_ADD_STA */ - {IMX_8BIT, 0x0345, 0xB8}, /* 440 */ - {IMX_8BIT, 0x0346, 0x01}, /* Y_ADD_STA */ - {IMX_8BIT, 0x0347, 0x30}, /* 304 */ - {IMX_8BIT, 0x0348, 0x0E}, /* X_ADD_END */ - {IMX_8BIT, 0x0349, 0xB7}, /* 4207-440=3767 */ - {IMX_8BIT, 0x034A, 0x0A}, /* Y_ADD_END */ - {IMX_8BIT, 0x034B, 0xFF}, /* 3119-304=2815 */ - {IMX_8BIT, 0x034C, 0x03}, /* X_OUT_SIZE */ - {IMX_8BIT, 0x034D, 0x40}, /* 832 */ - {IMX_8BIT, 0x034E, 0x02}, /* Y_OUT_SIZE */ - {IMX_8BIT, 0x034F, 0x74}, /* 628 */ - {IMX_8BIT, 0x0350, 0x00}, /* No Dig crop */ - {IMX_8BIT, 0x0351, 0x00}, - {IMX_8BIT, 0x0352, 0x00}, - {IMX_8BIT, 0x0353, 0x00}, - {IMX_8BIT, 0x0354, 0x03}, /* Cut out size same as the size after crop */ - {IMX_8BIT, 0x0355, 0x40}, - {IMX_8BIT, 0x0356, 0x02}, - {IMX_8BIT, 0x0357, 0x74}, - {IMX_8BIT, 0x301D, 0x30}, /* ?? */ - {IMX_8BIT, 0x3310, 0x03}, /* Write H and V size same as output size? */ - {IMX_8BIT, 0x3311, 0x40}, - {IMX_8BIT, 0x3312, 0x02}, - {IMX_8BIT, 0x3313, 0x74}, - {IMX_8BIT, 0x331C, 0x02}, /* ?? */ - {IMX_8BIT, 0x331D, 0x21}, - {IMX_8BIT, 0x4084, 0x03}, /* Scaling related? */ - {IMX_8BIT, 0x4085, 0x40}, - {IMX_8BIT, 0x4086, 0x02}, - {IMX_8BIT, 0x4087, 0x74}, - {IMX_8BIT, 0x4400, 0x00}, /* STATS off */ - {IMX_TOK_TERM, 0, 0}, -}; - -/* - * It is 28/16 DS from (16:9)8m cropped setting. - * - * The 8m(16:9) cropped setting is 3360x1890 effective res. - * - this is larger then the expected 3264x1836 FOV - * - * Consider ISP 16x16 padding: - * sensor outputs 1936x1096 - * cropped region is 3388x1918 - */ -static struct imx_reg const imx135_1936x1096_cropped[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03}, - {IMX_8BIT, 0x0112, 0x0A}, - {IMX_8BIT, 0x0113, 0x0A}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x0390, 0x00}, - {IMX_8BIT, 0x0391, 0x11}, /* no binning */ - {IMX_8BIT, 0x0392, 0x00}, - {IMX_8BIT, 0x0401, 0x02}, /* resize */ - {IMX_8BIT, 0x0404, 0x00}, - {IMX_8BIT, 0x0405, 0x1C}, /* 28/16 */ - {IMX_8BIT, 0x4082, 0x00}, - {IMX_8BIT, 0x4083, 0x00}, - {IMX_8BIT, 0x4203, 0xFF}, - {IMX_8BIT, 0x7006, 0x04}, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x01}, /* X_ADD_STA */ - {IMX_8BIT, 0x0345, 0x9A}, /* 410 */ - {IMX_8BIT, 0x0346, 0x02}, /* Y_ADD_STA */ - {IMX_8BIT, 0x0347, 0x58}, /* 600 */ - {IMX_8BIT, 0x0348, 0x0E}, /* X_ADD_END */ - {IMX_8BIT, 0x0349, 0xD5}, /* 3797 */ - {IMX_8BIT, 0x034A, 0x09}, /* Y_ADD_END */ - {IMX_8BIT, 0x034B, 0xD5}, /* 2517 */ - {IMX_8BIT, 0x034C, 0x07}, /* X_OUT_SIZE */ - {IMX_8BIT, 0x034D, 0x90}, /* 1936 */ - {IMX_8BIT, 0x034E, 0x04}, /* Y_OUT_SIZE */ - {IMX_8BIT, 0x034F, 0x48}, /* 1096 */ - {IMX_8BIT, 0x0350, 0x00}, /* No Dig crop */ - {IMX_8BIT, 0x0351, 0x00}, - {IMX_8BIT, 0x0352, 0x00}, - {IMX_8BIT, 0x0353, 0x00}, - {IMX_8BIT, 0x0354, 0x0D}, /* Cut out siz same as the size after crop */ - {IMX_8BIT, 0x0355, 0x3C}, - {IMX_8BIT, 0x0356, 0x07}, - {IMX_8BIT, 0x0357, 0x7E}, - {IMX_8BIT, 0x301D, 0x30}, /* ?? */ - {IMX_8BIT, 0x3310, 0x07}, /* Write H and V size same as output size? */ - {IMX_8BIT, 0x3311, 0x90}, - {IMX_8BIT, 0x3312, 0x04}, - {IMX_8BIT, 0x3313, 0x48}, - {IMX_8BIT, 0x331C, 0x00}, /* ?? */ - {IMX_8BIT, 0x331D, 0xAA}, - {IMX_8BIT, 0x4084, 0x07}, /* Scaling related? */ - {IMX_8BIT, 0x4085, 0x90}, - {IMX_8BIT, 0x4086, 0x04}, - {IMX_8BIT, 0x4087, 0x48}, - {IMX_8BIT, 0x4400, 0x00}, /* STATS off */ - {IMX_TOK_TERM, 0, 0}, -}; - -/* - * It is 2.125 DS from (3:2)8m cropped setting. - * - * The 8m(3:2) cropped setting is 2992x2448 effective res. - * The ISP effect cropped setting should be 1408x1152 effect res. - * - * Consider ISP 16x16 padding: - * sensor outputs 1424x1168 - * cropped region is 3026x2482 - */ -static struct imx_reg const imx135_1424x1168_cropped[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03}, - {IMX_8BIT, 0x0112, 0x0A}, - {IMX_8BIT, 0x0113, 0x0A}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x0390, 0x00}, - {IMX_8BIT, 0x0391, 0x11}, /* no binning */ - {IMX_8BIT, 0x0392, 0x00}, - {IMX_8BIT, 0x0401, 0x02}, /* resize */ - {IMX_8BIT, 0x0404, 0x00}, - {IMX_8BIT, 0x0405, 0x22}, /* 34/16=2.125 */ - {IMX_8BIT, 0x4082, 0x00}, - {IMX_8BIT, 0x4083, 0x00}, - {IMX_8BIT, 0x4203, 0xFF}, - {IMX_8BIT, 0x7006, 0x04}, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x02}, /* X_ADD_STA */ - {IMX_8BIT, 0x0345, 0x4E}, /* 590 */ - {IMX_8BIT, 0x0346, 0x01}, /* Y_ADD_STA */ - {IMX_8BIT, 0x0347, 0x3E}, /* 318 */ - {IMX_8BIT, 0x0348, 0x0E}, /* X_ADD_END */ - {IMX_8BIT, 0x0349, 0x1F}, /* 3615 */ - {IMX_8BIT, 0x034A, 0x0A}, /* Y_ADD_END */ - {IMX_8BIT, 0x034B, 0xEF}, /* 2799 */ - {IMX_8BIT, 0x034C, 0x05}, /* X_OUT_SIZE */ - {IMX_8BIT, 0x034D, 0x90}, /* 1424 */ - {IMX_8BIT, 0x034E, 0x04}, /* Y_OUT_SIZE */ - {IMX_8BIT, 0x034F, 0x90}, /* 1168 */ - {IMX_8BIT, 0x0350, 0x00}, /* No Dig crop */ - {IMX_8BIT, 0x0351, 0x00}, - {IMX_8BIT, 0x0352, 0x00}, - {IMX_8BIT, 0x0353, 0x00}, - {IMX_8BIT, 0x0354, 0x0B}, /* Cut out siz same as the size after crop */ - {IMX_8BIT, 0x0355, 0xD2}, - {IMX_8BIT, 0x0356, 0x09}, - {IMX_8BIT, 0x0357, 0xB2}, - {IMX_8BIT, 0x301D, 0x30}, /* ?? */ - {IMX_8BIT, 0x3310, 0x05}, /* Write H and V size same as output size? */ - {IMX_8BIT, 0x3311, 0x90}, - {IMX_8BIT, 0x3312, 0x04}, - {IMX_8BIT, 0x3313, 0x90}, - {IMX_8BIT, 0x331C, 0x00}, /* ?? */ - {IMX_8BIT, 0x331D, 0xAA}, - {IMX_8BIT, 0x4084, 0x05}, /* Scaling related? */ - {IMX_8BIT, 0x4085, 0x90}, - {IMX_8BIT, 0x4086, 0x04}, - {IMX_8BIT, 0x4087, 0x90}, - {IMX_8BIT, 0x4400, 0x00}, /* STATS off */ - {IMX_TOK_TERM, 0, 0}, -}; - -/* - * It is 1/2 binning from 8m cropped setting. - * - * The 8m cropped setting is 3264x2448 effective res. - * The 2m cropped setting should be 1632x1224 effect res. - * - * Consider ISP 16x16 padding: - * sensor outputs 1648x1240 - * cropped region is 3296x2480 - */ -static struct imx_reg const imx135_2m_cropped[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03}, - {IMX_8BIT, 0x0112, 0x0A}, - {IMX_8BIT, 0x0113, 0x0A}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x0390, 0x01}, - {IMX_8BIT, 0x0391, 0x22}, - {IMX_8BIT, 0x0392, 0x00}, - {IMX_8BIT, 0x0401, 0x00}, - {IMX_8BIT, 0x0404, 0x00}, - {IMX_8BIT, 0x0405, 0x10}, - {IMX_8BIT, 0x4082, 0x01}, - {IMX_8BIT, 0x4083, 0x01}, - {IMX_8BIT, 0x4203, 0xFF}, - {IMX_8BIT, 0x7006, 0x04}, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x01}, /* X_ADD_STA */ - {IMX_8BIT, 0x0345, 0xC8}, /* 464(1D0) -> 456(1C8)*/ - {IMX_8BIT, 0x0346, 0x01}, /* Y_ADD_STA */ - {IMX_8BIT, 0x0347, 0x40}, /* 320 */ - {IMX_8BIT, 0x0348, 0x0E}, /* X_ADD_END */ - {IMX_8BIT, 0x0349, 0xA7}, /* 4207-456=3751 */ - {IMX_8BIT, 0x034A, 0x0A}, /* Y_ADD_END */ - {IMX_8BIT, 0x034B, 0xEF}, /* 3119-320=2799 */ - {IMX_8BIT, 0x034C, 0x06}, /* X_OUT_SIZE */ - {IMX_8BIT, 0x034D, 0x70}, /* 1648 */ - {IMX_8BIT, 0x034E, 0x04}, /* Y_OUT_SIZE */ - {IMX_8BIT, 0x034F, 0xD8}, /* 1240 */ - {IMX_8BIT, 0x0350, 0x00}, /* No Dig crop */ - {IMX_8BIT, 0x0351, 0x00}, - {IMX_8BIT, 0x0352, 0x00}, - {IMX_8BIT, 0x0353, 0x00}, - {IMX_8BIT, 0x0354, 0x06}, /* Cut out size same as the size after crop */ - {IMX_8BIT, 0x0355, 0x70}, - {IMX_8BIT, 0x0356, 0x04}, - {IMX_8BIT, 0x0357, 0xD8}, - {IMX_8BIT, 0x301D, 0x30}, /* ?? */ - {IMX_8BIT, 0x3310, 0x06}, /* Write H and V size same as output size? */ - {IMX_8BIT, 0x3311, 0x70}, - {IMX_8BIT, 0x3312, 0x04}, - {IMX_8BIT, 0x3313, 0xD8}, - {IMX_8BIT, 0x331C, 0x00}, /* ?? */ - {IMX_8BIT, 0x331D, 0xAA}, - {IMX_8BIT, 0x4084, 0x00}, /* Scaling related? */ - {IMX_8BIT, 0x4085, 0x00}, - {IMX_8BIT, 0x4086, 0x00}, - {IMX_8BIT, 0x4087, 0x00}, - {IMX_8BIT, 0x4400, 0x00}, /* STATS off */ - {IMX_TOK_TERM, 0, 0}, -}; - -/* - * 8M Cropped 16:9 setting - * - * Effect res: 3264x1836 - * Sensor out: 3280x1852 - */ -static struct imx_reg const imx135_6m_cropped[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_451_2MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03}, - {IMX_8BIT, 0x0112, 0x0A}, - {IMX_8BIT, 0x0113, 0x0A}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x0390, 0x00}, - {IMX_8BIT, 0x0391, 0x11}, - {IMX_8BIT, 0x0392, 0x00}, - {IMX_8BIT, 0x0401, 0x00}, - {IMX_8BIT, 0x0404, 0x00}, - {IMX_8BIT, 0x0405, 0x10}, - {IMX_8BIT, 0x4082, 0x01}, - {IMX_8BIT, 0x4083, 0x01}, - {IMX_8BIT, 0x4203, 0xFF}, - {IMX_8BIT, 0x7006, 0x04}, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x01}, - {IMX_8BIT, 0x0345, 0xD0}, - {IMX_8BIT, 0x0346, 0x02}, /* 634 */ - {IMX_8BIT, 0x0347, 0x7A}, - {IMX_8BIT, 0x0348, 0x0E}, - {IMX_8BIT, 0x0349, 0x9F}, - {IMX_8BIT, 0x034A, 0x09}, /* 2485 */ - {IMX_8BIT, 0x034B, 0xB5}, - {IMX_8BIT, 0x034C, 0x0C}, /* 3280 */ - {IMX_8BIT, 0x034D, 0xD0}, - {IMX_8BIT, 0x034E, 0x07}, /* 1852 */ - {IMX_8BIT, 0x034F, 0x3C}, - {IMX_8BIT, 0x0350, 0x00}, /* No Dig crop */ - {IMX_8BIT, 0x0351, 0x00}, - {IMX_8BIT, 0x0352, 0x00}, - {IMX_8BIT, 0x0353, 0x00}, - {IMX_8BIT, 0x0354, 0x0C}, /* Cut out size same as the size after crop */ - {IMX_8BIT, 0x0355, 0xD0}, - {IMX_8BIT, 0x0356, 0x07}, - {IMX_8BIT, 0x0357, 0x3C}, - {IMX_8BIT, 0x301D, 0x30}, /* ?? */ - {IMX_8BIT, 0x3310, 0x0C}, /* Write H and V size same as output size? */ - {IMX_8BIT, 0x3311, 0xD0}, - {IMX_8BIT, 0x3312, 0x07}, - {IMX_8BIT, 0x3313, 0x3C}, - {IMX_8BIT, 0x331C, 0x00}, /* ?? */ - {IMX_8BIT, 0x331D, 0x10}, - {IMX_8BIT, 0x4084, 0x00}, /* Scaling related? */ - {IMX_8BIT, 0x4085, 0x00}, - {IMX_8BIT, 0x4086, 0x00}, - {IMX_8BIT, 0x4087, 0x00}, - {IMX_8BIT, 0x4400, 0x00}, /* STATS off */ - {IMX_TOK_TERM, 0, 0}, -}; - -static struct imx_reg const imx135_8m_cropped[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_451_2MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03}, - {IMX_8BIT, 0x0112, 0x0A}, - {IMX_8BIT, 0x0113, 0x0A}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x0390, 0x00}, - {IMX_8BIT, 0x0391, 0x11}, - {IMX_8BIT, 0x0392, 0x00}, - {IMX_8BIT, 0x0401, 0x00}, - {IMX_8BIT, 0x0404, 0x00}, - {IMX_8BIT, 0x0405, 0x10}, - {IMX_8BIT, 0x4082, 0x01}, - {IMX_8BIT, 0x4083, 0x01}, - {IMX_8BIT, 0x4203, 0xFF}, - {IMX_8BIT, 0x7006, 0x04}, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x01}, - {IMX_8BIT, 0x0345, 0xD0}, - {IMX_8BIT, 0x0346, 0x01}, - {IMX_8BIT, 0x0347, 0x48}, - {IMX_8BIT, 0x0348, 0x0E}, - {IMX_8BIT, 0x0349, 0x9F}, - {IMX_8BIT, 0x034A, 0x0A}, - {IMX_8BIT, 0x034B, 0xE7}, - {IMX_8BIT, 0x034C, 0x0C}, /* 3280 */ - {IMX_8BIT, 0x034D, 0xD0}, - {IMX_8BIT, 0x034E, 0x09}, /* 2464 */ - {IMX_8BIT, 0x034F, 0xA0}, - {IMX_8BIT, 0x0350, 0x00}, /* No Dig crop */ - {IMX_8BIT, 0x0351, 0x00}, - {IMX_8BIT, 0x0352, 0x00}, - {IMX_8BIT, 0x0353, 0x00}, - {IMX_8BIT, 0x0354, 0x0C}, /* Cut out size same as the size after crop */ - {IMX_8BIT, 0x0355, 0xD0}, - {IMX_8BIT, 0x0356, 0x09}, - {IMX_8BIT, 0x0357, 0xA0}, - {IMX_8BIT, 0x301D, 0x30}, /* ?? */ - {IMX_8BIT, 0x3310, 0x0C}, /* Write H and V size same as output size? */ - {IMX_8BIT, 0x3311, 0xD0}, - {IMX_8BIT, 0x3312, 0x09}, - {IMX_8BIT, 0x3313, 0xA0}, - {IMX_8BIT, 0x331C, 0x00}, /* ?? */ - {IMX_8BIT, 0x331D, 0x10}, - {IMX_8BIT, 0x4084, 0x00}, /* Scaling related? */ - {IMX_8BIT, 0x4085, 0x00}, - {IMX_8BIT, 0x4086, 0x00}, - {IMX_8BIT, 0x4087, 0x00}, - {IMX_8BIT, 0x4400, 0x00}, /* STATS off */ - {IMX_TOK_TERM, 0, 0}, -}; - -static struct imx_reg const imx135_8m_scaled_from_12m[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_451_2MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03}, - {IMX_8BIT, 0x0112, 0x0A}, - {IMX_8BIT, 0x0113, 0x0A}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x0390, 0x00}, - {IMX_8BIT, 0x0391, 0x11}, - {IMX_8BIT, 0x0392, 0x00}, - {IMX_8BIT, 0x0401, 0x02}, /* Scaling */ - {IMX_8BIT, 0x0404, 0x00}, - {IMX_8BIT, 0x0405, 0x14}, - {IMX_8BIT, 0x4082, 0x00}, - {IMX_8BIT, 0x4083, 0x00}, - {IMX_8BIT, 0x4203, 0xFF}, - {IMX_8BIT, 0x7006, 0x04}, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x00}, - {IMX_8BIT, 0x0345, 0x36}, - {IMX_8BIT, 0x0346, 0x00}, - {IMX_8BIT, 0x0347, 0x14}, - {IMX_8BIT, 0x0348, 0x10}, - {IMX_8BIT, 0x0349, 0x39}, - {IMX_8BIT, 0x034A, 0x0C}, - {IMX_8BIT, 0x034B, 0x1B}, - {IMX_8BIT, 0x034C, 0x0C}, /* 3280x2464 */ - {IMX_8BIT, 0x034D, 0xD0}, - {IMX_8BIT, 0x034E, 0x09}, - {IMX_8BIT, 0x034F, 0xA0}, - {IMX_8BIT, 0x0350, 0x00}, /* No Dig crop */ - {IMX_8BIT, 0x0351, 0x00}, - {IMX_8BIT, 0x0352, 0x00}, - {IMX_8BIT, 0x0353, 0x00}, - {IMX_8BIT, 0x0354, 0x10}, /* Cut out size same as the size after crop */ - {IMX_8BIT, 0x0355, 0x04}, - {IMX_8BIT, 0x0356, 0x0C}, - {IMX_8BIT, 0x0357, 0x08}, - {IMX_8BIT, 0x301D, 0x30}, /* ?? */ - {IMX_8BIT, 0x3310, 0x0C}, /* Write H and V size same as output size? */ - {IMX_8BIT, 0x3311, 0xD0}, - {IMX_8BIT, 0x3312, 0x09}, - {IMX_8BIT, 0x3313, 0xA0}, - {IMX_8BIT, 0x331C, 0x02}, /* ?? */ - {IMX_8BIT, 0x331D, 0xA0}, - {IMX_8BIT, 0x4084, 0x0C}, /* Scaling related? */ - {IMX_8BIT, 0x4085, 0xD0}, - {IMX_8BIT, 0x4086, 0x09}, - {IMX_8BIT, 0x4087, 0xA0}, - {IMX_8BIT, 0x4400, 0x00}, /* STATS off */ - {IMX_TOK_TERM, 0, 0}, -}; - -static struct imx_reg const imx135_8m_scaled_from_12m_for_mipi342[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_342MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03}, - {IMX_8BIT, 0x0112, 0x0A}, - {IMX_8BIT, 0x0113, 0x0A}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x0390, 0x00}, - {IMX_8BIT, 0x0391, 0x11}, - {IMX_8BIT, 0x0392, 0x00}, - {IMX_8BIT, 0x0401, 0x02}, /* Scaling */ - {IMX_8BIT, 0x0404, 0x00}, - {IMX_8BIT, 0x0405, 0x14}, - {IMX_8BIT, 0x4082, 0x00}, - {IMX_8BIT, 0x4083, 0x00}, - {IMX_8BIT, 0x4203, 0xFF}, - {IMX_8BIT, 0x7006, 0x04}, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x00}, - {IMX_8BIT, 0x0345, 0x36}, - {IMX_8BIT, 0x0346, 0x00}, - {IMX_8BIT, 0x0347, 0x14}, - {IMX_8BIT, 0x0348, 0x10}, - {IMX_8BIT, 0x0349, 0x39}, - {IMX_8BIT, 0x034A, 0x0C}, - {IMX_8BIT, 0x034B, 0x1B}, - {IMX_8BIT, 0x034C, 0x0C}, /* 3280x2464 */ - {IMX_8BIT, 0x034D, 0xD0}, - {IMX_8BIT, 0x034E, 0x09}, - {IMX_8BIT, 0x034F, 0xA0}, - {IMX_8BIT, 0x0350, 0x00}, /* No Dig crop */ - {IMX_8BIT, 0x0351, 0x00}, - {IMX_8BIT, 0x0352, 0x00}, - {IMX_8BIT, 0x0353, 0x00}, - {IMX_8BIT, 0x0354, 0x10}, /* Cut out size same as the size after crop */ - {IMX_8BIT, 0x0355, 0x04}, - {IMX_8BIT, 0x0356, 0x0C}, - {IMX_8BIT, 0x0357, 0x08}, - {IMX_8BIT, 0x301D, 0x30}, /* ?? */ - {IMX_8BIT, 0x3310, 0x0C}, /* Write H and V size same as output size? */ - {IMX_8BIT, 0x3311, 0xD0}, - {IMX_8BIT, 0x3312, 0x09}, - {IMX_8BIT, 0x3313, 0xA0}, - {IMX_8BIT, 0x331C, 0x02}, /* ?? */ - {IMX_8BIT, 0x331D, 0xA0}, - {IMX_8BIT, 0x4084, 0x0C}, /* Resize IMG Hand V size-> Scaling related?*/ - {IMX_8BIT, 0x4085, 0xD0}, - {IMX_8BIT, 0x4086, 0x09}, - {IMX_8BIT, 0x4087, 0xA0}, - {IMX_8BIT, 0x4400, 0x00}, /* STATS off */ - {IMX_TOK_TERM, 0, 0}, -}; - -static struct imx_reg const imx135_6m[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_451_2MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03}, - {IMX_8BIT, 0x0112, 0x0A}, - {IMX_8BIT, 0x0113, 0x0A}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x0390, 0x00}, - {IMX_8BIT, 0x0391, 0x11}, - {IMX_8BIT, 0x0392, 0x00}, - {IMX_8BIT, 0x0401, 0x02}, - {IMX_8BIT, 0x0404, 0x00}, - {IMX_8BIT, 0x0405, 0x14}, - {IMX_8BIT, 0x4082, 0x00}, - {IMX_8BIT, 0x4083, 0x00}, - {IMX_8BIT, 0x4203, 0xFF}, - {IMX_8BIT, 0x7006, 0x04}, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x00}, /* 36, 194, 1039, a9f 4100x2316 */ - {IMX_8BIT, 0x0345, 0x36}, - {IMX_8BIT, 0x0346, 0x01}, - {IMX_8BIT, 0x0347, 0x94}, - {IMX_8BIT, 0x0348, 0x10}, - {IMX_8BIT, 0x0349, 0x39}, - {IMX_8BIT, 0x034A, 0x0A}, - {IMX_8BIT, 0x034B, 0x9F}, - {IMX_8BIT, 0x034C, 0x0C}, /* 3280x1852 */ - {IMX_8BIT, 0x034D, 0xD0}, - {IMX_8BIT, 0x034E, 0x07}, - {IMX_8BIT, 0x034F, 0x3C}, - {IMX_8BIT, 0x0350, 0x00}, - {IMX_8BIT, 0x0351, 0x00}, - {IMX_8BIT, 0x0352, 0x00}, - {IMX_8BIT, 0x0353, 0x00}, - {IMX_8BIT, 0x0354, 0x10}, /* 4100x2316 */ - {IMX_8BIT, 0x0355, 0x04}, - {IMX_8BIT, 0x0356, 0x09}, - {IMX_8BIT, 0x0357, 0x0C}, - {IMX_8BIT, 0x301D, 0x30}, - {IMX_8BIT, 0x3310, 0x0C}, - {IMX_8BIT, 0x3311, 0xD0}, - {IMX_8BIT, 0x3312, 0x07}, - {IMX_8BIT, 0x3313, 0x3C}, - {IMX_8BIT, 0x331C, 0x02}, - {IMX_8BIT, 0x331D, 0xA0}, - {IMX_8BIT, 0x4084, 0x0C}, - {IMX_8BIT, 0x4085, 0xD0}, - {IMX_8BIT, 0x4086, 0x07}, - {IMX_8BIT, 0x4087, 0x3C}, - {IMX_8BIT, 0x4400, 0x00}, - {IMX_TOK_TERM, 0, 0}, -}; - -static struct imx_reg const imx135_6m_for_mipi_342[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_342MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03}, - {IMX_8BIT, 0x0112, 0x0A}, - {IMX_8BIT, 0x0113, 0x0A}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x0390, 0x00}, - {IMX_8BIT, 0x0391, 0x11}, - {IMX_8BIT, 0x0392, 0x00}, - {IMX_8BIT, 0x0401, 0x02}, - {IMX_8BIT, 0x0404, 0x00}, - {IMX_8BIT, 0x0405, 0x14}, - {IMX_8BIT, 0x4082, 0x00}, - {IMX_8BIT, 0x4083, 0x00}, - {IMX_8BIT, 0x4203, 0xFF}, - {IMX_8BIT, 0x7006, 0x04}, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x00}, /* 36, 194, 1039, a9f 4100x2316 */ - {IMX_8BIT, 0x0345, 0x36}, - {IMX_8BIT, 0x0346, 0x01}, - {IMX_8BIT, 0x0347, 0x94}, - {IMX_8BIT, 0x0348, 0x10}, - {IMX_8BIT, 0x0349, 0x39}, - {IMX_8BIT, 0x034A, 0x0A}, - {IMX_8BIT, 0x034B, 0x9F}, - {IMX_8BIT, 0x034C, 0x0C}, /* 3280x1852 */ - {IMX_8BIT, 0x034D, 0xD0}, - {IMX_8BIT, 0x034E, 0x07}, - {IMX_8BIT, 0x034F, 0x3C}, - {IMX_8BIT, 0x0350, 0x00}, - {IMX_8BIT, 0x0351, 0x00}, - {IMX_8BIT, 0x0352, 0x00}, - {IMX_8BIT, 0x0353, 0x00}, - {IMX_8BIT, 0x0354, 0x10}, /* 4100x2316 */ - {IMX_8BIT, 0x0355, 0x04}, - {IMX_8BIT, 0x0356, 0x09}, - {IMX_8BIT, 0x0357, 0x0C}, - {IMX_8BIT, 0x301D, 0x30}, - {IMX_8BIT, 0x3310, 0x0C}, - {IMX_8BIT, 0x3311, 0xD0}, - {IMX_8BIT, 0x3312, 0x07}, - {IMX_8BIT, 0x3313, 0x3C}, - {IMX_8BIT, 0x331C, 0x02}, - {IMX_8BIT, 0x331D, 0xA0}, - {IMX_8BIT, 0x4084, 0x0C}, - {IMX_8BIT, 0x4085, 0xD0}, - {IMX_8BIT, 0x4086, 0x07}, - {IMX_8BIT, 0x4087, 0x3C}, - {IMX_8BIT, 0x4400, 0x00}, - {IMX_TOK_TERM, 0, 0}, -}; - -/* - * FOV is: 3280x2464, larger then 3264x2448. - * Sensor output: 336x256 - * Cropping region: 3444x2624 - */ -static struct imx_reg const imx135_336x256[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY, - /* mode setting */ - {IMX_8BIT, 0x0108, 0x03}, - {IMX_8BIT, 0x0112, 0x0A}, - {IMX_8BIT, 0x0113, 0x0A}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x0390, 0x01}, - {IMX_8BIT, 0x0391, 0x22}, - {IMX_8BIT, 0x0392, 0x00}, - {IMX_8BIT, 0x0401, 0x02}, /* 2x binning */ - {IMX_8BIT, 0x0404, 0x00}, - {IMX_8BIT, 0x0405, 0x52}, /* scaling: 82/16 */ - {IMX_8BIT, 0x4082, 0x00}, - {IMX_8BIT, 0x4083, 0x00}, - {IMX_8BIT, 0x4203, 0xFF}, - {IMX_8BIT, 0x7006, 0x04}, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x01}, /* x_start: 374 */ - {IMX_8BIT, 0x0345, 0x76}, - {IMX_8BIT, 0x0346, 0x00}, /* y_start: 248 */ - {IMX_8BIT, 0x0347, 0xF8}, - {IMX_8BIT, 0x0348, 0x0E}, /* x_end: 3817 */ - {IMX_8BIT, 0x0349, 0xE9}, - {IMX_8BIT, 0x034A, 0x0B}, /* y_end: 2871 */ - {IMX_8BIT, 0x034B, 0x37}, - {IMX_8BIT, 0x034C, 0x01}, /* x_out: 336 */ - {IMX_8BIT, 0x034D, 0x50}, - {IMX_8BIT, 0x034E, 0x01}, /* y_out: 256 */ - {IMX_8BIT, 0x034F, 0x00}, - {IMX_8BIT, 0x0350, 0x00}, - {IMX_8BIT, 0x0351, 0x00}, - {IMX_8BIT, 0x0352, 0x00}, - {IMX_8BIT, 0x0353, 0x00}, - {IMX_8BIT, 0x0354, 0x06}, /* dig x_out: 1722 */ - {IMX_8BIT, 0x0355, 0xBA}, - {IMX_8BIT, 0x0356, 0x05}, /* dig y_out: 1312 */ - {IMX_8BIT, 0x0357, 0x20}, - {IMX_8BIT, 0x301D, 0x30}, - {IMX_8BIT, 0x3310, 0x01}, /* ?: x_out */ - {IMX_8BIT, 0x3311, 0x50}, - {IMX_8BIT, 0x3312, 0x01}, /* ?: y_out */ - {IMX_8BIT, 0x3313, 0x00}, - {IMX_8BIT, 0x331C, 0x02}, - {IMX_8BIT, 0x331D, 0x4E}, - {IMX_8BIT, 0x4084, 0x01}, /* ?: x_out */ - {IMX_8BIT, 0x4085, 0x50}, - {IMX_8BIT, 0x4086, 0x01}, /* ?: y_out */ - {IMX_8BIT, 0x4087, 0x00}, - {IMX_8BIT, 0x4400, 0x00}, - {IMX_TOK_TERM, 0, 0}, -}; - -static struct imx_reg const imx135_1m[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY, - /* mode setting */ - {IMX_8BIT, 0x0108, 0x03}, - {IMX_8BIT, 0x0112, 0x0A}, - {IMX_8BIT, 0x0113, 0x0A}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x0390, 0x01}, - {IMX_8BIT, 0x0391, 0x22}, - {IMX_8BIT, 0x0392, 0x00}, - {IMX_8BIT, 0x0401, 0x02}, - {IMX_8BIT, 0x0404, 0x00}, - {IMX_8BIT, 0x0405, 0x1F}, - {IMX_8BIT, 0x4082, 0x00}, - {IMX_8BIT, 0x4083, 0x00}, - {IMX_8BIT, 0x4203, 0xFF}, - {IMX_8BIT, 0x7006, 0x04}, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x00}, - {IMX_8BIT, 0x0345, 0x58}, - {IMX_8BIT, 0x0346, 0x00}, - {IMX_8BIT, 0x0347, 0x28}, - {IMX_8BIT, 0x0348, 0x10}, - {IMX_8BIT, 0x0349, 0x17}, - {IMX_8BIT, 0x034A, 0x0C}, - {IMX_8BIT, 0x034B, 0x07}, - {IMX_8BIT, 0x034C, 0x04}, - {IMX_8BIT, 0x034D, 0x10}, - {IMX_8BIT, 0x034E, 0x03}, - {IMX_8BIT, 0x034F, 0x10}, - {IMX_8BIT, 0x0350, 0x00}, - {IMX_8BIT, 0x0351, 0x00}, - {IMX_8BIT, 0x0352, 0x00}, - {IMX_8BIT, 0x0353, 0x00}, - {IMX_8BIT, 0x0354, 0x07}, - {IMX_8BIT, 0x0355, 0xE0}, - {IMX_8BIT, 0x0356, 0x05}, - {IMX_8BIT, 0x0357, 0xF0}, - {IMX_8BIT, 0x301D, 0x30}, - {IMX_8BIT, 0x3310, 0x04}, - {IMX_8BIT, 0x3311, 0x10}, - {IMX_8BIT, 0x3312, 0x03}, - {IMX_8BIT, 0x3313, 0x10}, - {IMX_8BIT, 0x331C, 0x02}, - {IMX_8BIT, 0x331D, 0x4E}, - {IMX_8BIT, 0x4084, 0x04}, - {IMX_8BIT, 0x4085, 0x10}, - {IMX_8BIT, 0x4086, 0x03}, - {IMX_8BIT, 0x4087, 0x10}, - {IMX_8BIT, 0x4400, 0x00}, - {IMX_TOK_TERM, 0, 0}, -}; - -static struct imx_reg const imx135_3m_binning[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03}, - {IMX_8BIT, 0x0112, 0x0A}, - {IMX_8BIT, 0x0113, 0x0A}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x0390, 0x01}, /* Binning */ - {IMX_8BIT, 0x0391, 0x22}, /* 2x2 binning */ - {IMX_8BIT, 0x0392, 0x00}, /* average */ - {IMX_8BIT, 0x0401, 0x00}, - {IMX_8BIT, 0x0404, 0x00}, - {IMX_8BIT, 0x0405, 0x10}, - {IMX_8BIT, 0x4082, 0x01}, - {IMX_8BIT, 0x4083, 0x01}, - {IMX_8BIT, 0x4203, 0xFF}, - {IMX_8BIT, 0x7006, 0x04}, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x00}, - {IMX_8BIT, 0x0345, 0x28}, - {IMX_8BIT, 0x0346, 0x00}, - {IMX_8BIT, 0x0347, 0x08}, - {IMX_8BIT, 0x0348, 0x10}, - {IMX_8BIT, 0x0349, 0x47}, - {IMX_8BIT, 0x034A, 0x0C}, - {IMX_8BIT, 0x034B, 0x27}, - {IMX_8BIT, 0x034C, 0x08}, - {IMX_8BIT, 0x034D, 0x10}, - {IMX_8BIT, 0x034E, 0x06}, - {IMX_8BIT, 0x034F, 0x10}, - {IMX_8BIT, 0x0350, 0x00}, - {IMX_8BIT, 0x0351, 0x00}, - {IMX_8BIT, 0x0352, 0x00}, - {IMX_8BIT, 0x0353, 0x00}, - {IMX_8BIT, 0x0354, 0x08}, - {IMX_8BIT, 0x0355, 0x10}, - {IMX_8BIT, 0x0356, 0x06}, - {IMX_8BIT, 0x0357, 0x10}, - {IMX_8BIT, 0x301D, 0x30}, - {IMX_8BIT, 0x3310, 0x08}, - {IMX_8BIT, 0x3311, 0x10}, - {IMX_8BIT, 0x3312, 0x06}, - {IMX_8BIT, 0x3313, 0x10}, - {IMX_8BIT, 0x331C, 0x00}, - {IMX_8BIT, 0x331D, 0xAA}, - {IMX_8BIT, 0x4084, 0x00}, - {IMX_8BIT, 0x4085, 0x00}, - {IMX_8BIT, 0x4086, 0x00}, - {IMX_8BIT, 0x4087, 0x00}, - {IMX_8BIT, 0x4400, 0x00}, - {IMX_TOK_TERM, 0, 0}, -}; - -/* 1080P 1936x1104 */ -static struct imx_reg const imx135_1080p_binning[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03}, - {IMX_8BIT, 0x0112, 0x0A}, - {IMX_8BIT, 0x0113, 0x0A}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0387, 0x01}, - {IMX_8BIT, 0x0390, 0x01}, - {IMX_8BIT, 0x0391, 0x22}, - {IMX_8BIT, 0x0392, 0x00}, - {IMX_8BIT, 0x0401, 0x02}, - {IMX_8BIT, 0x0404, 0x00}, - {IMX_8BIT, 0x0405, 0x11}, - {IMX_8BIT, 0x4082, 0x00}, - {IMX_8BIT, 0x4083, 0x00}, - {IMX_8BIT, 0x7006, 0x04}, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x00}, - {IMX_8BIT, 0x0345, 0x2E}, - {IMX_8BIT, 0x0346, 0x01}, - {IMX_8BIT, 0x0347, 0x84}, - {IMX_8BIT, 0x0348, 0x10}, - {IMX_8BIT, 0x0349, 0x41}, - {IMX_8BIT, 0x034A, 0x0A}, - {IMX_8BIT, 0x034B, 0xAF}, - {IMX_8BIT, 0x034C, 0x07}, - {IMX_8BIT, 0x034D, 0x90}, - {IMX_8BIT, 0x034E, 0x04}, - {IMX_8BIT, 0x034F, 0x50}, - {IMX_8BIT, 0x0350, 0x00}, - {IMX_8BIT, 0x0351, 0x00}, - {IMX_8BIT, 0x0352, 0x00}, - {IMX_8BIT, 0x0353, 0x00}, - {IMX_8BIT, 0x0354, 0x08}, - {IMX_8BIT, 0x0355, 0x0A}, - {IMX_8BIT, 0x0356, 0x04}, - {IMX_8BIT, 0x0357, 0x96}, - {IMX_8BIT, 0x301D, 0x30}, - {IMX_8BIT, 0x3310, 0x07}, - {IMX_8BIT, 0x3311, 0x90}, - {IMX_8BIT, 0x3312, 0x04}, - {IMX_8BIT, 0x3313, 0x50}, - {IMX_8BIT, 0x331C, 0x01}, - {IMX_8BIT, 0x331D, 0x00}, - {IMX_8BIT, 0x4084, 0x07}, - {IMX_8BIT, 0x4085, 0x90}, - {IMX_8BIT, 0x4086, 0x04}, - {IMX_8BIT, 0x4087, 0x50}, - {IMX_8BIT, 0x4400, 0x00}, - {IMX_TOK_TERM, 0, 0}, -}; - -static const struct imx_reg imx135_1080p_nodvs_fullfov_max_clock[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_451_2MHZ_SALTBAY, - /* mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x01 }, - { IMX_8BIT, 0x0391, 0x22 }, - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x00 }, - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x10 }, - { IMX_8BIT, 0x4082, 0x01 }, - { IMX_8BIT, 0x4083, 0x01 }, - { IMX_8BIT, 0x7006, 0x04 }, - /* size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* 168,464,4039,2655: 3872x2192 */ - { IMX_8BIT, 0x0345, 0xA8 }, - { IMX_8BIT, 0x0346, 0x01 }, - { IMX_8BIT, 0x0347, 0xD0 }, - { IMX_8BIT, 0x0348, 0x0F }, - { IMX_8BIT, 0x0349, 0xC7 }, - { IMX_8BIT, 0x034A, 0x0A }, - { IMX_8BIT, 0x034B, 0x5F }, - { IMX_8BIT, 0x034C, 0x07 }, /*1936 x 1096 */ - { IMX_8BIT, 0x034D, 0x90 }, - { IMX_8BIT, 0x034E, 0x04 }, - { IMX_8BIT, 0x034F, 0x48 }, - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x07 }, /*1936 x 1096 */ - { IMX_8BIT, 0x0355, 0x90 }, - { IMX_8BIT, 0x0356, 0x04 }, - { IMX_8BIT, 0x0357, 0x48 }, - { IMX_8BIT, 0x301D, 0x30 }, - { IMX_8BIT, 0x3310, 0x07 }, - { IMX_8BIT, 0x3311, 0x90 }, - { IMX_8BIT, 0x3312, 0x04 }, - { IMX_8BIT, 0x3313, 0x48 }, - { IMX_8BIT, 0x331C, 0x04 }, - { IMX_8BIT, 0x331D, 0xB0 }, - { IMX_8BIT, 0x4084, 0x07 }, - { IMX_8BIT, 0x4085, 0x90 }, - { IMX_8BIT, 0x4086, 0x04 }, - { IMX_8BIT, 0x4087, 0x48 }, - { IMX_8BIT, 0x4400, 0x00 }, - { IMX_TOK_TERM, 0, 0} -}; - -/* 1080P NODVS 1936x1096 */ -static const struct imx_reg imx135_1080p_nodvs_max_clock[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_451_2MHZ_SALTBAY, - /* mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x01 }, - { IMX_8BIT, 0x0391, 0x22 }, - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x02 }, - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x11 }, - { IMX_8BIT, 0x4082, 0x00 }, - { IMX_8BIT, 0x4083, 0x00 }, - { IMX_8BIT, 0x7006, 0x04 }, - /* size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* 46,396,4161,2727: 4116x2332 */ - { IMX_8BIT, 0x0345, 0x2E }, - { IMX_8BIT, 0x0346, 0x01 }, - { IMX_8BIT, 0x0347, 0x8C }, - { IMX_8BIT, 0x0348, 0x10 }, - { IMX_8BIT, 0x0349, 0x41 }, - { IMX_8BIT, 0x034A, 0x0A }, - { IMX_8BIT, 0x034B, 0xA7 }, - { IMX_8BIT, 0x034C, 0x07 }, /*1936 x 1096 */ - { IMX_8BIT, 0x034D, 0x90 }, - { IMX_8BIT, 0x034E, 0x04 }, - { IMX_8BIT, 0x034F, 0x48 }, - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x08 }, /* 2058x1166 */ - { IMX_8BIT, 0x0355, 0x0A }, - { IMX_8BIT, 0x0356, 0x04 }, - { IMX_8BIT, 0x0357, 0x8E }, - { IMX_8BIT, 0x301D, 0x30 }, - { IMX_8BIT, 0x3310, 0x07 }, - { IMX_8BIT, 0x3311, 0x90 }, - { IMX_8BIT, 0x3312, 0x04 }, - { IMX_8BIT, 0x3313, 0x48 }, - { IMX_8BIT, 0x331C, 0x04 }, - { IMX_8BIT, 0x331D, 0xB0 }, - { IMX_8BIT, 0x4084, 0x07 }, - { IMX_8BIT, 0x4085, 0x90 }, - { IMX_8BIT, 0x4086, 0x04 }, - { IMX_8BIT, 0x4087, 0x48 }, - { IMX_8BIT, 0x4400, 0x00 }, - { IMX_TOK_TERM, 0, 0} -}; - -/* 1080P 10%DVS 2104x1184 */ -static const struct imx_reg imx135_1080p_10_dvs_max_clock[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_451_2MHZ_SALTBAY, - /* mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x01 }, - { IMX_8BIT, 0x0391, 0x22 }, - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x00 }, - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x10 }, - { IMX_8BIT, 0x4082, 0x01 }, - { IMX_8BIT, 0x4083, 0x01 }, - { IMX_8BIT, 0x7006, 0x04 }, - /* size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* 0,376,4207,2743: 4208x2368 */ - { IMX_8BIT, 0x0345, 0x00 }, - { IMX_8BIT, 0x0346, 0x01 }, - { IMX_8BIT, 0x0347, 0x78 }, - { IMX_8BIT, 0x0348, 0x10 }, - { IMX_8BIT, 0x0349, 0x6F }, - { IMX_8BIT, 0x034A, 0x0A }, - { IMX_8BIT, 0x034B, 0xB7 }, - { IMX_8BIT, 0x034C, 0x08 }, /* 2104 x 1184 */ - { IMX_8BIT, 0x034D, 0x38 }, - { IMX_8BIT, 0x034E, 0x04 }, - { IMX_8BIT, 0x034F, 0xA0 }, - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x08 }, /* 2104 x 1184 */ - { IMX_8BIT, 0x0355, 0x38 }, - { IMX_8BIT, 0x0356, 0x04 }, - { IMX_8BIT, 0x0357, 0xA0 }, - { IMX_8BIT, 0x301D, 0x30 }, - { IMX_8BIT, 0x3310, 0x08 }, - { IMX_8BIT, 0x3311, 0x38 }, - { IMX_8BIT, 0x3312, 0x04 }, - { IMX_8BIT, 0x3313, 0xA0 }, - { IMX_8BIT, 0x331C, 0x04 }, - { IMX_8BIT, 0x331D, 0xB0 }, - { IMX_8BIT, 0x4084, 0x00 }, - { IMX_8BIT, 0x4085, 0x00 }, - { IMX_8BIT, 0x4086, 0x00 }, - { IMX_8BIT, 0x4087, 0x00 }, - { IMX_8BIT, 0x4400, 0x00 }, - { IMX_TOK_TERM, 0, 0} -}; - -static const struct imx_reg imx135_720pdvs_max_clock[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_451_2MHZ_SALTBAY, - /* mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x01 }, - { IMX_8BIT, 0x0391, 0x22 }, - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x02 }, - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x15 }, - { IMX_8BIT, 0x4082, 0x00 }, - { IMX_8BIT, 0x4083, 0x00 }, - { IMX_8BIT, 0x7006, 0x04 }, - /* size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* 46,404,4161,2715: 4116x2312 */ - { IMX_8BIT, 0x0345, 0x2E }, - { IMX_8BIT, 0x0346, 0x01 }, - { IMX_8BIT, 0x0347, 0x94 }, - { IMX_8BIT, 0x0348, 0x10 }, - { IMX_8BIT, 0x0349, 0x41 }, - { IMX_8BIT, 0x034A, 0x0A }, - { IMX_8BIT, 0x034B, 0x9B }, - { IMX_8BIT, 0x034C, 0x06 }, /*1568 x 880 */ - { IMX_8BIT, 0x034D, 0x20 }, - { IMX_8BIT, 0x034E, 0x03 }, - { IMX_8BIT, 0x034F, 0x70 }, - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x08 }, /*2058 x 1156 */ - { IMX_8BIT, 0x0355, 0x0A }, - { IMX_8BIT, 0x0356, 0x04 }, - { IMX_8BIT, 0x0357, 0x84 }, - { IMX_8BIT, 0x301D, 0x30 }, - { IMX_8BIT, 0x3310, 0x06 }, - { IMX_8BIT, 0x3311, 0x20 }, - { IMX_8BIT, 0x3312, 0x03 }, - { IMX_8BIT, 0x3313, 0x70 }, - { IMX_8BIT, 0x331C, 0x04 }, - { IMX_8BIT, 0x331D, 0x4C }, - { IMX_8BIT, 0x4084, 0x06 }, - { IMX_8BIT, 0x4085, 0x20 }, - { IMX_8BIT, 0x4086, 0x03 }, - { IMX_8BIT, 0x4087, 0x70 }, - { IMX_8BIT, 0x4400, 0x00 }, - { IMX_TOK_TERM, 0, 0} -}; - -/******************* Video Modes ******************/ - -/* 1080P DVS 2336x1320 */ -static const struct imx_reg imx135_2336x1320_max_clock[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_451_2MHZ_SALTBAY, - /* mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x00 }, - { IMX_8BIT, 0x0391, 0x11 }, - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x02 }, - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x1C }, - { IMX_8BIT, 0x4082, 0x00 }, - { IMX_8BIT, 0x4083, 0x00 }, - { IMX_8BIT, 0x7006, 0x04 }, - /* size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* 60,404,4147,2715: 4088x2312 */ - { IMX_8BIT, 0x0345, 0x3C }, - { IMX_8BIT, 0x0346, 0x01 }, - { IMX_8BIT, 0x0347, 0x94 }, - { IMX_8BIT, 0x0348, 0x10 }, - { IMX_8BIT, 0x0349, 0x33 }, - { IMX_8BIT, 0x034A, 0x0A }, - { IMX_8BIT, 0x034B, 0x9B }, - { IMX_8BIT, 0x034C, 0x09 }, /*2336 x 1320 */ - { IMX_8BIT, 0x034D, 0x20 }, - { IMX_8BIT, 0x034E, 0x05 }, - { IMX_8BIT, 0x034F, 0x28 }, - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x0F }, /* 4088x2312 */ - { IMX_8BIT, 0x0355, 0xF8 }, - { IMX_8BIT, 0x0356, 0x09 }, - { IMX_8BIT, 0x0357, 0x08 }, - { IMX_8BIT, 0x301D, 0x30 }, - { IMX_8BIT, 0x3310, 0x09 }, - { IMX_8BIT, 0x3311, 0x20 }, - { IMX_8BIT, 0x3312, 0x05 }, - { IMX_8BIT, 0x3313, 0x28 }, - { IMX_8BIT, 0x331C, 0x04 }, - { IMX_8BIT, 0x331D, 0xE2 }, - { IMX_8BIT, 0x4084, 0x09 }, - { IMX_8BIT, 0x4085, 0x20 }, - { IMX_8BIT, 0x4086, 0x05 }, - { IMX_8BIT, 0x4087, 0x28 }, - { IMX_8BIT, 0x4400, 0x00 }, - { IMX_TOK_TERM, 0, 0} -}; - -/* 1080P DVS 2336x1320 Cropped */ -static const struct imx_reg imx135_2336x1320_cropped_mipi499[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_499_2MHZ_SALTBAY, - /* mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x00 }, - { IMX_8BIT, 0x0391, 0x11 }, - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x02 }, - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x1C }, - { IMX_8BIT, 0x4082, 0x01 }, - { IMX_8BIT, 0x4083, 0x01 }, - { IMX_8BIT, 0x7006, 0x04 }, - /* size setting */ - { IMX_8BIT, 0x0344, 0x03 }, /* 936,900,3271,2219: 2336x1320 */ - { IMX_8BIT, 0x0345, 0xA8 }, - { IMX_8BIT, 0x0346, 0x03 }, - { IMX_8BIT, 0x0347, 0x84 }, - { IMX_8BIT, 0x0348, 0x0C }, - { IMX_8BIT, 0x0349, 0xC7 }, - { IMX_8BIT, 0x034A, 0x08 }, - { IMX_8BIT, 0x034B, 0xAB }, - { IMX_8BIT, 0x034C, 0x09 }, /* 2336 x 1320 */ - { IMX_8BIT, 0x034D, 0x20 }, - { IMX_8BIT, 0x034E, 0x05 }, - { IMX_8BIT, 0x034F, 0x28 }, - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x09 }, /* 2336 x 1320 */ - { IMX_8BIT, 0x0355, 0x20 }, - { IMX_8BIT, 0x0356, 0x05 }, - { IMX_8BIT, 0x0357, 0x28 }, - { IMX_8BIT, 0x301D, 0x30 }, - { IMX_8BIT, 0x3310, 0x09 }, - { IMX_8BIT, 0x3311, 0x20 }, - { IMX_8BIT, 0x3312, 0x05 }, - { IMX_8BIT, 0x3313, 0x28 }, - { IMX_8BIT, 0x331C, 0x00 }, - { IMX_8BIT, 0x331D, 0xB4 }, - { IMX_8BIT, 0x4084, 0x09 }, - { IMX_8BIT, 0x4085, 0x20 }, - { IMX_8BIT, 0x4086, 0x05 }, - { IMX_8BIT, 0x4087, 0x28 }, - { IMX_8BIT, 0x4400, 0x00 }, - { IMX_TOK_TERM, 0, 0} -}; - -/* 720P DVS 1568 x 880 */ -static const struct imx_reg imx135_720p_dvs_binning[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY, - /* mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x01 }, - { IMX_8BIT, 0x0391, 0x22 }, - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x02 }, - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x15 }, - { IMX_8BIT, 0x4082, 0x00 }, - { IMX_8BIT, 0x4083, 0x00 }, - { IMX_8BIT, 0x7006, 0x04 }, - /* size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* 46,404,4161,2715: 4116x2312 */ - { IMX_8BIT, 0x0345, 0x2e }, - { IMX_8BIT, 0x0346, 0x01 }, - { IMX_8BIT, 0x0347, 0x94 }, - { IMX_8BIT, 0x0348, 0x10 }, - { IMX_8BIT, 0x0349, 0x41 }, - { IMX_8BIT, 0x034A, 0x0A }, - { IMX_8BIT, 0x034B, 0x9B }, - { IMX_8BIT, 0x034C, 0x06 }, /*1568 x 880 */ - { IMX_8BIT, 0x034D, 0x20 }, - { IMX_8BIT, 0x034E, 0x03 }, - { IMX_8BIT, 0x034F, 0x70 }, - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x08 }, /* 2058x1156 */ - { IMX_8BIT, 0x0355, 0x0a }, - { IMX_8BIT, 0x0356, 0x04 }, - { IMX_8BIT, 0x0357, 0x84 }, - { IMX_8BIT, 0x301D, 0x30 }, /* TODO! */ - { IMX_8BIT, 0x3310, 0x06 }, - { IMX_8BIT, 0x3311, 0x20 }, - { IMX_8BIT, 0x3312, 0x03 }, - { IMX_8BIT, 0x3313, 0x70 }, - { IMX_8BIT, 0x331C, 0x01 }, /* TODO! */ - { IMX_8BIT, 0x331D, 0xd6 }, /* TODO! */ - { IMX_8BIT, 0x4084, 0x06 }, - { IMX_8BIT, 0x4085, 0x20 }, - { IMX_8BIT, 0x4086, 0x03 }, - { IMX_8BIT, 0x4087, 0x70 }, - { IMX_8BIT, 0x4400, 0x00 }, - { IMX_TOK_TERM, 0, 0} -}; - -/* wvga: H : 1640 V : 1024 */ -static const struct imx_reg imx135_wvga_dvs_binning[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03 }, - {IMX_8BIT, 0x0112, 0x0A }, - {IMX_8BIT, 0x0113, 0x0A }, - {IMX_8BIT, 0x0381, 0x01 }, - {IMX_8BIT, 0x0383, 0x01 }, - {IMX_8BIT, 0x0385, 0x01 }, - {IMX_8BIT, 0x0387, 0x01 }, - {IMX_8BIT, 0x0390, 0x01 }, - {IMX_8BIT, 0x0391, 0x22 }, - {IMX_8BIT, 0x0392, 0x00 }, - {IMX_8BIT, 0x0401, 0x02 }, - {IMX_8BIT, 0x0404, 0x00 }, - {IMX_8BIT, 0x0405, 0x14 }, - {IMX_8BIT, 0x4082, 0x00 }, - {IMX_8BIT, 0x4083, 0x00 }, - {IMX_8BIT, 0x7006, 0x04 }, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x00 }, - {IMX_8BIT, 0x0345, 0x36 }, - {IMX_8BIT, 0x0346, 0x01 }, - {IMX_8BIT, 0x0347, 0x18 }, - {IMX_8BIT, 0x0348, 0x10 }, - {IMX_8BIT, 0x0349, 0x39 }, - {IMX_8BIT, 0x034A, 0x0B }, - {IMX_8BIT, 0x034B, 0x17 }, - {IMX_8BIT, 0x034C, 0x06 }, - {IMX_8BIT, 0x034D, 0x68 }, - {IMX_8BIT, 0x034E, 0x04 }, - {IMX_8BIT, 0x034F, 0x00 }, - {IMX_8BIT, 0x0350, 0x00 }, - {IMX_8BIT, 0x0351, 0x00 }, - {IMX_8BIT, 0x0352, 0x00 }, - {IMX_8BIT, 0x0353, 0x00 }, - {IMX_8BIT, 0x0354, 0x08 }, - {IMX_8BIT, 0x0355, 0x02 }, - {IMX_8BIT, 0x0356, 0x05 }, - {IMX_8BIT, 0x0357, 0x00 }, - {IMX_8BIT, 0x301D, 0x30 }, - {IMX_8BIT, 0x3310, 0x06 }, - {IMX_8BIT, 0x3311, 0x68 }, - {IMX_8BIT, 0x3312, 0x04 }, - {IMX_8BIT, 0x3313, 0x00 }, - {IMX_8BIT, 0x331C, 0x01 }, - {IMX_8BIT, 0x331D, 0xBD }, - {IMX_8BIT, 0x4084, 0x06 }, - {IMX_8BIT, 0x4085, 0x68 }, - {IMX_8BIT, 0x4086, 0x04 }, - {IMX_8BIT, 0x4087, 0x00 }, - {IMX_8BIT, 0x4400, 0x00 }, - {IMX_TOK_TERM, 0, 0} -}; - -/* 480P 1036 x 696 */ -static const struct imx_reg imx135_480p_binning[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03 }, - {IMX_8BIT, 0x0112, 0x0A }, - {IMX_8BIT, 0x0113, 0x0A }, - {IMX_8BIT, 0x0381, 0x01 }, - {IMX_8BIT, 0x0383, 0x01 }, - {IMX_8BIT, 0x0385, 0x01 }, - {IMX_8BIT, 0x0387, 0x01 }, - {IMX_8BIT, 0x0390, 0x01 }, - {IMX_8BIT, 0x0391, 0x44 }, - {IMX_8BIT, 0x0392, 0x00 }, - {IMX_8BIT, 0x0401, 0x00 }, - {IMX_8BIT, 0x0404, 0x00 }, - {IMX_8BIT, 0x0405, 0x10 },/* No scal */ - {IMX_8BIT, 0x4082, 0x00 }, - {IMX_8BIT, 0x4083, 0x00 }, - {IMX_8BIT, 0x7006, 0x04 }, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x00 }, /* 52,20,4155, 3099 4144x2784*/ - {IMX_8BIT, 0x0345, 0x20 }, - {IMX_8BIT, 0x0346, 0x00 }, - {IMX_8BIT, 0x0347, 0xA8 }, - {IMX_8BIT, 0x0348, 0x10 }, - {IMX_8BIT, 0x0349, 0x4F }, - {IMX_8BIT, 0x034A, 0x0B }, - {IMX_8BIT, 0x034B, 0x88 }, - {IMX_8BIT, 0x034C, 0x04 }, /* 1036 * 696 */ - {IMX_8BIT, 0x034D, 0x0C }, - {IMX_8BIT, 0x034E, 0x02 }, - {IMX_8BIT, 0x034F, 0xB8 }, - {IMX_8BIT, 0x0350, 0x00 }, - {IMX_8BIT, 0x0351, 0x00 }, - {IMX_8BIT, 0x0352, 0x00 }, - {IMX_8BIT, 0x0353, 0x00 }, - {IMX_8BIT, 0x0354, 0x04 }, /* 1036x696 */ - {IMX_8BIT, 0x0355, 0x0C }, - {IMX_8BIT, 0x0356, 0x02 }, - {IMX_8BIT, 0x0357, 0xB8 }, - {IMX_8BIT, 0x301D, 0x30 }, - {IMX_8BIT, 0x3310, 0x04 }, - {IMX_8BIT, 0x3311, 0x0C }, - {IMX_8BIT, 0x3312, 0x02 }, - {IMX_8BIT, 0x3313, 0xB8 }, - {IMX_8BIT, 0x331C, 0x02 }, - {IMX_8BIT, 0x331D, 0x21 }, - {IMX_8BIT, 0x4084, 0x04 }, - {IMX_8BIT, 0x4085, 0x0C }, - {IMX_8BIT, 0x4086, 0x02 }, - {IMX_8BIT, 0x4087, 0xB8 }, - {IMX_8BIT, 0x4400, 0x00 }, - {IMX_TOK_TERM, 0, 0} -}; - -/* 480P DVS 936 x 602 */ -static const struct imx_reg imx135_480p_dvs_binning[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY, - /* mode setting */ - { IMX_8BIT, 0x0108, 0x03 }, - { IMX_8BIT, 0x0112, 0x0A }, - { IMX_8BIT, 0x0113, 0x0A }, - { IMX_8BIT, 0x0381, 0x01 }, - { IMX_8BIT, 0x0383, 0x01 }, - { IMX_8BIT, 0x0385, 0x01 }, - { IMX_8BIT, 0x0387, 0x01 }, - { IMX_8BIT, 0x0390, 0x01 }, - { IMX_8BIT, 0x0391, 0x22 }, - { IMX_8BIT, 0x0392, 0x00 }, - { IMX_8BIT, 0x0401, 0x02 }, - { IMX_8BIT, 0x0404, 0x00 }, - { IMX_8BIT, 0x0405, 0x23 }, - { IMX_8BIT, 0x4082, 0x00 }, - { IMX_8BIT, 0x4083, 0x00 }, - { IMX_8BIT, 0x7006, 0x04 }, - /* size setting */ - { IMX_8BIT, 0x0344, 0x00 }, /* 56,244,4151,2877: 4096x2634 */ - { IMX_8BIT, 0x0345, 0x38 }, - { IMX_8BIT, 0x0346, 0x00 }, - { IMX_8BIT, 0x0347, 0xf4 }, - { IMX_8BIT, 0x0348, 0x10 }, - { IMX_8BIT, 0x0349, 0x37 }, - { IMX_8BIT, 0x034A, 0x0b }, - { IMX_8BIT, 0x034B, 0x3d }, - { IMX_8BIT, 0x034C, 0x03 }, /* 936 x 602 */ - { IMX_8BIT, 0x034D, 0xa8 }, - { IMX_8BIT, 0x034E, 0x02 }, - { IMX_8BIT, 0x034F, 0x5a }, - { IMX_8BIT, 0x0350, 0x00 }, - { IMX_8BIT, 0x0351, 0x00 }, - { IMX_8BIT, 0x0352, 0x00 }, - { IMX_8BIT, 0x0353, 0x00 }, - { IMX_8BIT, 0x0354, 0x08 }, /* 2058x1156 */ - { IMX_8BIT, 0x0355, 0x00 }, - { IMX_8BIT, 0x0356, 0x05 }, - { IMX_8BIT, 0x0357, 0x25 }, - { IMX_8BIT, 0x301D, 0x30 }, /* TODO! */ - { IMX_8BIT, 0x3310, 0x03 }, - { IMX_8BIT, 0x3311, 0xa8 }, - { IMX_8BIT, 0x3312, 0x02 }, - { IMX_8BIT, 0x3313, 0x5a }, - { IMX_8BIT, 0x331C, 0x01 }, /* TODO! */ - { IMX_8BIT, 0x331D, 0xd6 }, - { IMX_8BIT, 0x4084, 0x03 }, - { IMX_8BIT, 0x4085, 0xa8 }, - { IMX_8BIT, 0x4086, 0x02 }, - { IMX_8BIT, 0x4087, 0x5a }, - { IMX_8BIT, 0x4400, 0x00 }, - { IMX_TOK_TERM, 0, 0} -}; - -/* VGA: H : 1036 V : 780 */ -static const struct imx_reg imx135_vga_binning[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03 }, - {IMX_8BIT, 0x0112, 0x0A }, - {IMX_8BIT, 0x0113, 0x0A }, - {IMX_8BIT, 0x0381, 0x01 }, - {IMX_8BIT, 0x0383, 0x01 }, - {IMX_8BIT, 0x0385, 0x01 }, - {IMX_8BIT, 0x0387, 0x01 }, - {IMX_8BIT, 0x0390, 0x01 }, - {IMX_8BIT, 0x0391, 0x44 }, - {IMX_8BIT, 0x0392, 0x00 }, - {IMX_8BIT, 0x0401, 0x00 }, - {IMX_8BIT, 0x0404, 0x00 }, - {IMX_8BIT, 0x0405, 0x10 }, - {IMX_8BIT, 0x4082, 0x00 }, - {IMX_8BIT, 0x4083, 0x00 }, - {IMX_8BIT, 0x7006, 0x04 }, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x00 }, /* 52,20,4155, 3099 4144x3120*/ - {IMX_8BIT, 0x0345, 0x20 }, - {IMX_8BIT, 0x0346, 0x00 }, - {IMX_8BIT, 0x0347, 0x00 }, - {IMX_8BIT, 0x0348, 0x10 }, - {IMX_8BIT, 0x0349, 0x4F }, - {IMX_8BIT, 0x034A, 0x0C }, - {IMX_8BIT, 0x034B, 0x2F }, - {IMX_8BIT, 0x034C, 0x04 }, /* 1036x780 */ - {IMX_8BIT, 0x034D, 0x0C }, - {IMX_8BIT, 0x034E, 0x03 }, - {IMX_8BIT, 0x034F, 0x0C }, - {IMX_8BIT, 0x0350, 0x00 }, - {IMX_8BIT, 0x0351, 0x00 }, - {IMX_8BIT, 0x0352, 0x00 }, - {IMX_8BIT, 0x0353, 0x00 }, - {IMX_8BIT, 0x0354, 0x04 }, /* 1036x780 */ - {IMX_8BIT, 0x0355, 0x0C }, - {IMX_8BIT, 0x0356, 0x03 }, - {IMX_8BIT, 0x0357, 0x0C }, - {IMX_8BIT, 0x301D, 0x30 }, - {IMX_8BIT, 0x3310, 0x04 }, - {IMX_8BIT, 0x3311, 0x0C }, - {IMX_8BIT, 0x3312, 0x03 }, - {IMX_8BIT, 0x3313, 0x0C }, - {IMX_8BIT, 0x331C, 0x02 }, - {IMX_8BIT, 0x331D, 0x21 }, - {IMX_8BIT, 0x4084, 0x04 }, - {IMX_8BIT, 0x4085, 0x0C }, - {IMX_8BIT, 0x4086, 0x03 }, - {IMX_8BIT, 0x4087, 0x0C }, - {IMX_8BIT, 0x4400, 0x00 }, - {IMX_TOK_TERM, 0, 0} -}; - -/* VGA: H : 820 V : 616 */ -static const struct imx_reg imx135_vga_dvs_binning[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03 }, - {IMX_8BIT, 0x0112, 0x0A }, - {IMX_8BIT, 0x0113, 0x0A }, - {IMX_8BIT, 0x0381, 0x01 }, - {IMX_8BIT, 0x0383, 0x01 }, - {IMX_8BIT, 0x0385, 0x01 }, - {IMX_8BIT, 0x0387, 0x01 }, - {IMX_8BIT, 0x0390, 0x01 }, - {IMX_8BIT, 0x0391, 0x44 }, - {IMX_8BIT, 0x0392, 0x00 }, - {IMX_8BIT, 0x0401, 0x02 }, - {IMX_8BIT, 0x0404, 0x00 }, - {IMX_8BIT, 0x0405, 0x14 }, - {IMX_8BIT, 0x4082, 0x00 }, - {IMX_8BIT, 0x4083, 0x00 }, - {IMX_8BIT, 0x7006, 0x04 }, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x00 }, /* 52,20,4155, 3099 4104x3080*/ - {IMX_8BIT, 0x0345, 0x34 }, - {IMX_8BIT, 0x0346, 0x00 }, - {IMX_8BIT, 0x0347, 0x14 }, - {IMX_8BIT, 0x0348, 0x10 }, - {IMX_8BIT, 0x0349, 0x3B }, - {IMX_8BIT, 0x034A, 0x0C }, - {IMX_8BIT, 0x034B, 0x1B }, - {IMX_8BIT, 0x034C, 0x03 }, /* 820x616 */ - {IMX_8BIT, 0x034D, 0x34 }, - {IMX_8BIT, 0x034E, 0x02 }, - {IMX_8BIT, 0x034F, 0x68 }, - {IMX_8BIT, 0x0350, 0x00 }, - {IMX_8BIT, 0x0351, 0x00 }, - {IMX_8BIT, 0x0352, 0x00 }, - {IMX_8BIT, 0x0353, 0x00 }, - {IMX_8BIT, 0x0354, 0x04 }, /* 1026x770 */ - {IMX_8BIT, 0x0355, 0x02 }, - {IMX_8BIT, 0x0356, 0x03 }, - {IMX_8BIT, 0x0357, 0x02 }, - {IMX_8BIT, 0x301D, 0x30 }, - {IMX_8BIT, 0x3310, 0x03 }, - {IMX_8BIT, 0x3311, 0x34 }, - {IMX_8BIT, 0x3312, 0x02 }, - {IMX_8BIT, 0x3313, 0x68 }, - {IMX_8BIT, 0x331C, 0x02 }, - {IMX_8BIT, 0x331D, 0x21 }, - {IMX_8BIT, 0x4084, 0x03 }, - {IMX_8BIT, 0x4085, 0x34 }, - {IMX_8BIT, 0x4086, 0x02 }, - {IMX_8BIT, 0x4087, 0x68 }, - {IMX_8BIT, 0x4400, 0x00 }, - {IMX_TOK_TERM, 0, 0} -}; - -/* VGA: H : 436 V : 360 */ -static const struct imx_reg imx135_436x360_binning[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03 }, - {IMX_8BIT, 0x0112, 0x0A }, - {IMX_8BIT, 0x0113, 0x0A }, - {IMX_8BIT, 0x0381, 0x01 }, - {IMX_8BIT, 0x0383, 0x01 }, - {IMX_8BIT, 0x0385, 0x01 }, - {IMX_8BIT, 0x0387, 0x01 }, - {IMX_8BIT, 0x0390, 0x01 }, - {IMX_8BIT, 0x0391, 0x44 }, - {IMX_8BIT, 0x0392, 0x00 }, - {IMX_8BIT, 0x0401, 0x02 }, - {IMX_8BIT, 0x0404, 0x00 }, - {IMX_8BIT, 0x0405, 0x22 }, - {IMX_8BIT, 0x4082, 0x00 }, - {IMX_8BIT, 0x4083, 0x00 }, - {IMX_8BIT, 0x7006, 0x04 }, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x00 }, /* 212,0,3995,3119 3784x3120 */ - {IMX_8BIT, 0x0345, 0xD4 }, - {IMX_8BIT, 0x0346, 0x00 }, - {IMX_8BIT, 0x0347, 0x00 }, - {IMX_8BIT, 0x0348, 0x0F }, - {IMX_8BIT, 0x0349, 0x9B }, - {IMX_8BIT, 0x034A, 0x0C }, - {IMX_8BIT, 0x034B, 0x2F }, - - {IMX_8BIT, 0x034C, 0x01 }, /* 436x360 */ - {IMX_8BIT, 0x034D, 0xB4 }, - {IMX_8BIT, 0x034E, 0x01 }, - {IMX_8BIT, 0x034F, 0x68 }, - {IMX_8BIT, 0x0350, 0x00 }, - {IMX_8BIT, 0x0351, 0x12 }, - {IMX_8BIT, 0x0352, 0x00 }, - {IMX_8BIT, 0x0353, 0x0C }, - - {IMX_8BIT, 0x0354, 0x03 }, /* 928x768 crop from 946x780*/ - {IMX_8BIT, 0x0355, 0xA0 }, - {IMX_8BIT, 0x0356, 0x03 }, - {IMX_8BIT, 0x0357, 0x00 }, - - {IMX_8BIT, 0x301D, 0x30 }, - {IMX_8BIT, 0x3310, 0x01 }, - {IMX_8BIT, 0x3311, 0xB4 }, - {IMX_8BIT, 0x3312, 0x01 }, - {IMX_8BIT, 0x3313, 0x68 }, - {IMX_8BIT, 0x331C, 0x02 }, - {IMX_8BIT, 0x331D, 0x21 }, - {IMX_8BIT, 0x4084, 0x01 }, - {IMX_8BIT, 0x4085, 0xB4 }, - {IMX_8BIT, 0x4086, 0x01 }, - {IMX_8BIT, 0x4087, 0x68 }, - {IMX_8BIT, 0x4400, 0x00 }, - {IMX_TOK_TERM, 0, 0} -}; - -/* QVGA: H : 408 V : 308 */ -static const struct imx_reg imx135_qvga__dvs_binning[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03 }, - {IMX_8BIT, 0x0112, 0x0A }, - {IMX_8BIT, 0x0113, 0x0A }, - {IMX_8BIT, 0x0381, 0x01 }, - {IMX_8BIT, 0x0383, 0x01 }, - {IMX_8BIT, 0x0385, 0x01 }, - {IMX_8BIT, 0x0387, 0x01 }, - {IMX_8BIT, 0x0390, 0x01 }, - {IMX_8BIT, 0x0391, 0x44 }, - {IMX_8BIT, 0x0392, 0x00 }, - {IMX_8BIT, 0x0401, 0x02 }, - {IMX_8BIT, 0x0404, 0x00 }, - {IMX_8BIT, 0x0405, 0x28 }, - {IMX_8BIT, 0x4082, 0x00 }, - {IMX_8BIT, 0x4083, 0x00 }, - {IMX_8BIT, 0x7006, 0x04 }, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x00 }, /* 64,20,4143,3099 4080x3080 */ - {IMX_8BIT, 0x0345, 0x40 }, - {IMX_8BIT, 0x0346, 0x00 }, - {IMX_8BIT, 0x0347, 0x14 }, - {IMX_8BIT, 0x0348, 0x10 }, - {IMX_8BIT, 0x0349, 0x2F }, - {IMX_8BIT, 0x034A, 0x0C }, - {IMX_8BIT, 0x034B, 0x1B }, - {IMX_8BIT, 0x034C, 0x01 }, /* 408x308 */ - {IMX_8BIT, 0x034D, 0x98 }, - {IMX_8BIT, 0x034E, 0x01 }, - {IMX_8BIT, 0x034F, 0x34 }, - {IMX_8BIT, 0x0350, 0x00 }, - {IMX_8BIT, 0x0351, 0x00 }, - {IMX_8BIT, 0x0352, 0x00 }, - {IMX_8BIT, 0x0353, 0x00 }, - {IMX_8BIT, 0x0354, 0x03 }, /* 1020x770 */ - {IMX_8BIT, 0x0355, 0xFC }, - {IMX_8BIT, 0x0356, 0x03 }, - {IMX_8BIT, 0x0357, 0x02 }, - {IMX_8BIT, 0x301D, 0x30 }, - {IMX_8BIT, 0x3310, 0x01 }, - {IMX_8BIT, 0x3311, 0x98 }, - {IMX_8BIT, 0x3312, 0x01 }, - {IMX_8BIT, 0x3313, 0x34 }, - {IMX_8BIT, 0x331C, 0x01 }, - {IMX_8BIT, 0x331D, 0x68 }, - {IMX_8BIT, 0x4084, 0x01 }, - {IMX_8BIT, 0x4085, 0x98 }, - {IMX_8BIT, 0x4086, 0x01 }, - {IMX_8BIT, 0x4087, 0x34 }, - {IMX_8BIT, 0x4400, 0x00 }, - {IMX_TOK_TERM, 0, 0} -}; - -/* CIF H : 368 V : 304 */ -static const struct imx_reg imx135_cif_binning[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03 }, - {IMX_8BIT, 0x0112, 0x0A }, - {IMX_8BIT, 0x0113, 0x0A }, - {IMX_8BIT, 0x0381, 0x01 }, - {IMX_8BIT, 0x0383, 0x01 }, - {IMX_8BIT, 0x0385, 0x01 }, - {IMX_8BIT, 0x0387, 0x01 }, - {IMX_8BIT, 0x0390, 0x01 }, - {IMX_8BIT, 0x0391, 0x44 }, - {IMX_8BIT, 0x0392, 0x00 }, - {IMX_8BIT, 0x0401, 0x02 }, - {IMX_8BIT, 0x0404, 0x00 }, - {IMX_8BIT, 0x0405, 0x28 }, - {IMX_8BIT, 0x4082, 0x00 }, - {IMX_8BIT, 0x4083, 0x00 }, - {IMX_8BIT, 0x7006, 0x04 }, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x01 }, /* 264,42,3943,3081 3680x3040 */ - {IMX_8BIT, 0x0345, 0x08 }, - {IMX_8BIT, 0x0346, 0x00 }, - {IMX_8BIT, 0x0347, 0x2a }, - {IMX_8BIT, 0x0348, 0x0F }, - {IMX_8BIT, 0x0349, 0x67 }, - {IMX_8BIT, 0x034A, 0x0c }, - {IMX_8BIT, 0x034B, 0x09 }, - {IMX_8BIT, 0x034C, 0x01 }, /* 368x304 */ - {IMX_8BIT, 0x034D, 0x70 }, - {IMX_8BIT, 0x034E, 0x01 }, - {IMX_8BIT, 0x034F, 0x30 }, - {IMX_8BIT, 0x0350, 0x00 }, - {IMX_8BIT, 0x0351, 0x00 }, - {IMX_8BIT, 0x0352, 0x00 }, - {IMX_8BIT, 0x0353, 0x00 }, - {IMX_8BIT, 0x0354, 0x03 }, /* 920x760 */ - {IMX_8BIT, 0x0355, 0x98 }, - {IMX_8BIT, 0x0356, 0x02 }, - {IMX_8BIT, 0x0357, 0xf8 }, - {IMX_8BIT, 0x301D, 0x30 }, - {IMX_8BIT, 0x3310, 0x01 }, - {IMX_8BIT, 0x3311, 0x70 }, - {IMX_8BIT, 0x3312, 0x01 }, - {IMX_8BIT, 0x3313, 0x30 }, - {IMX_8BIT, 0x331C, 0x02 }, /* TODO! binning 4x4 must be 021c? */ - {IMX_8BIT, 0x331D, 0x1C }, - {IMX_8BIT, 0x4084, 0x01 }, - {IMX_8BIT, 0x4085, 0x70 }, - {IMX_8BIT, 0x4086, 0x01 }, - {IMX_8BIT, 0x4087, 0x30 }, - {IMX_8BIT, 0x4400, 0x00 }, - {IMX_TOK_TERM, 0, 0} -}; - -/* CIF H : 1888 V : 1548 */ -static const struct imx_reg imx135_cif_binning_1888x1548[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03 }, - {IMX_8BIT, 0x0112, 0x0A }, - {IMX_8BIT, 0x0113, 0x0A }, - {IMX_8BIT, 0x0381, 0x01 }, - {IMX_8BIT, 0x0383, 0x01 }, - {IMX_8BIT, 0x0385, 0x01 }, - {IMX_8BIT, 0x0387, 0x01 }, - {IMX_8BIT, 0x0390, 0x01 }, - {IMX_8BIT, 0x0391, 0x22 }, - {IMX_8BIT, 0x0392, 0x00 }, - {IMX_8BIT, 0x0401, 0x00 }, - {IMX_8BIT, 0x0404, 0x00 }, - {IMX_8BIT, 0x0405, 0x10 }, - {IMX_8BIT, 0x4082, 0x00 }, - {IMX_8BIT, 0x4083, 0x00 }, - {IMX_8BIT, 0x7006, 0x04 }, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x00 }, /* 264,42, 3776x3096 */ - {IMX_8BIT, 0x0345, 0xD8 }, - {IMX_8BIT, 0x0346, 0x00 }, - {IMX_8BIT, 0x0347, 0x0C }, - {IMX_8BIT, 0x0348, 0x0F }, - {IMX_8BIT, 0x0349, 0x97 }, - {IMX_8BIT, 0x034A, 0x0C }, - {IMX_8BIT, 0x034B, 0x23 }, - {IMX_8BIT, 0x034C, 0x07 }, /* 1888x1548 */ - {IMX_8BIT, 0x034D, 0x60 }, - {IMX_8BIT, 0x034E, 0x06 }, - {IMX_8BIT, 0x034F, 0x0C }, - {IMX_8BIT, 0x0350, 0x00 }, - {IMX_8BIT, 0x0351, 0x00 }, - {IMX_8BIT, 0x0352, 0x00 }, - {IMX_8BIT, 0x0353, 0x00 }, - {IMX_8BIT, 0x0354, 0x07 }, /* 1888x1548 */ - {IMX_8BIT, 0x0355, 0x60 }, - {IMX_8BIT, 0x0356, 0x06 }, - {IMX_8BIT, 0x0357, 0x0C }, - {IMX_8BIT, 0x301D, 0x30 }, - {IMX_8BIT, 0x3310, 0x07 }, - {IMX_8BIT, 0x3311, 0x60 }, - {IMX_8BIT, 0x3312, 0x06 }, - {IMX_8BIT, 0x3313, 0x0C }, - {IMX_8BIT, 0x331C, 0x02 }, /* TODO! binning 4x4 must be 021c? */ - {IMX_8BIT, 0x331D, 0x1C }, - {IMX_8BIT, 0x4084, 0x07 }, - {IMX_8BIT, 0x4085, 0x60 }, - {IMX_8BIT, 0x4086, 0x06 }, - {IMX_8BIT, 0x4087, 0x0C }, - {IMX_8BIT, 0x4400, 0x00 }, - {IMX_TOK_TERM, 0, 0} -}; - -/* QCIF H : 216 V : 176 */ -static const struct imx_reg imx135_qcif_dvs_binning[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - PLL_SETTINGS_FOR_MIPI_209_6MHZ_SALTBAY, - /* Mode setting */ - {IMX_8BIT, 0x0108, 0x03 }, - {IMX_8BIT, 0x0112, 0x0A }, - {IMX_8BIT, 0x0113, 0x0A }, - {IMX_8BIT, 0x0381, 0x01 }, - {IMX_8BIT, 0x0383, 0x01 }, - {IMX_8BIT, 0x0385, 0x01 }, - {IMX_8BIT, 0x0387, 0x01 }, - {IMX_8BIT, 0x0390, 0x01 }, - {IMX_8BIT, 0x0391, 0x44 }, - {IMX_8BIT, 0x0392, 0x00 }, - {IMX_8BIT, 0x0401, 0x02 }, - {IMX_8BIT, 0x0404, 0x00 }, - {IMX_8BIT, 0x0405, 0x46 }, - {IMX_8BIT, 0x4082, 0x00 }, - {IMX_8BIT, 0x4083, 0x00 }, - {IMX_8BIT, 0x7006, 0x04 }, - /* Size setting */ - {IMX_8BIT, 0x0344, 0x00 }, /* 212,20,3995,3099 3784x3080 */ - {IMX_8BIT, 0x0345, 0xD4 }, - {IMX_8BIT, 0x0346, 0x00 }, - {IMX_8BIT, 0x0347, 0x14 }, - {IMX_8BIT, 0x0348, 0x0F }, - {IMX_8BIT, 0x0349, 0x9B }, - {IMX_8BIT, 0x034A, 0x0C }, - {IMX_8BIT, 0x034B, 0x1B }, - {IMX_8BIT, 0x034C, 0x00 }, /* 216x176 */ - {IMX_8BIT, 0x034D, 0xD8 }, - {IMX_8BIT, 0x034E, 0x00 }, - {IMX_8BIT, 0x034F, 0xB0 }, - {IMX_8BIT, 0x0350, 0x00 }, - {IMX_8BIT, 0x0351, 0x00 }, - {IMX_8BIT, 0x0352, 0x00 }, - {IMX_8BIT, 0x0353, 0x00 }, - {IMX_8BIT, 0x0354, 0x03 }, /* 946x770 */ - {IMX_8BIT, 0x0355, 0xB2 }, - {IMX_8BIT, 0x0356, 0x03 }, - {IMX_8BIT, 0x0357, 0x02 }, - {IMX_8BIT, 0x301D, 0x30 }, - {IMX_8BIT, 0x3310, 0x00 }, - {IMX_8BIT, 0x3311, 0xD8 }, - {IMX_8BIT, 0x3312, 0x00 }, - {IMX_8BIT, 0x3313, 0xB0 }, - {IMX_8BIT, 0x331C, 0x02 }, /* TODO! binning 4x4 must be 021c */ - {IMX_8BIT, 0x331D, 0x1C }, - {IMX_8BIT, 0x4084, 0x00 }, - {IMX_8BIT, 0x4085, 0xD8 }, - {IMX_8BIT, 0x4086, 0x00 }, - {IMX_8BIT, 0x4087, 0xB0 }, - {IMX_8BIT, 0x4400, 0x00 }, - {IMX_TOK_TERM, 0, 0} -}; - -/* - * ISP Scaling is now supported in offine capture use cases. Because of that - * we need only few modes to cover the different aspect ratios from the - * sensor and the ISP will scale it based on the requested resolution from HAL. - * - * There is a performance impact when continuous view finder option is chose - * for resolutions above 8MP. So 8MP and 6MP resolution are kept, so that lower - * than these take 8MP or 6MP espectively for down scaling based on the - * aspect ratio. - */ -struct imx_resolution imx135_res_preview_mofd[] = { - { - .desc = "imx135_cif_binning_preview", - .regs = imx135_cif_binning, - .width = 368, - .height = 304, - .fps_options = { - { /* Binning Pixel clock: 335.36MHz */ - .fps = 30, - .pixels_per_line = 9114, - .lines_per_frame = 1226, - }, - { - } - }, - .bin_factor_x = 2, - .bin_factor_y = 2, - .mipi_freq = 209600, - }, - { - .desc = "imx135_vga_binning_preview", - .regs = imx135_vga_binning, - .width = 1036, - .height = 780, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 9144, - .lines_per_frame = 1226, - }, - { - } - }, - .bin_factor_x = 2, - .bin_factor_y = 2, - .mipi_freq = 209600, - }, - { - .desc = "imx135_480p_preview", - .regs = imx135_480p_binning, - .width = 1036, - .height = 696, - .fps_options = { - { /* Binning Pixel clock: 335.36MHz */ - .fps = 30, - .pixels_per_line = 9144, - .lines_per_frame = 1226, - }, - { - } - }, - .bin_factor_x = 2, - .bin_factor_y = 2, - .mipi_freq = 209600, - }, - { - .desc = "imx135_1080p_binning_preview", - .regs = imx135_1080p_binning, - .width = 1936, - .height = 1104, - .fps_options = { - { /* Binning Pixel clock: 335.36MHz */ - .fps = 30, - .pixels_per_line = 5464, - .lines_per_frame = 2046, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - .mipi_freq = 209600, - }, - { - .desc = "imx135_3m__cont_cap", - .regs = imx135_3m_binning, - .width = 2064, - .height = 1552, - .fps_options = { - { /* Binning Pixel clock: 335.36MHz */ - .fps = 30, - .pixels_per_line = 5464, - .lines_per_frame = 2046, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - .mipi_freq = 209600, - }, - { - .desc = "imx135_6m_cont_cap", - .regs = imx135_6m, - .width = 3280, - .height = 1852, - .fps_options = { - { /* Binning Pixel clock: 360.96MHz */ - .fps = 30, - .pixels_per_line = 4572, - .lines_per_frame = 2624, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .mipi_freq = 451200, - }, - { - .desc = "imx135_8m_scaled_from_12m__cont_cap", - .regs = imx135_8m_scaled_from_12m, - .width = 3280, - .height = 2464, - .fps_options = { - { /* Pixel clock: 360.96MHz */ - .fps = 24, - .pixels_per_line = 4572, - .lines_per_frame = 3280, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .mipi_freq = 451200, - }, - { - .desc = "imx135_10m__cont_cap", - .regs = imx135_10m, - .width = 4208, - .height = 2368, - .fps_options = { - { /* Pixel clock: 360.96MHz */ - .fps = 30, - .pixels_per_line = 4572, - .lines_per_frame = 2632, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .mipi_freq = 451200, - }, - { - .desc = "imx135_13m__cont_cap", - .regs = imx135_13m, - .width = 4208, - .height = 3120, - .fps_options = { - { /* Pixel clock: 360.96MHz */ - .fps = 24, - .pixels_per_line = 4572, - .lines_per_frame = 3290, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .mipi_freq = 451200, - }, -}; - -struct imx_resolution imx135_res_preview[] = { - { - .desc = "imx135_xga_cropped_video", - .regs = imx135_xga_cropped, - .width = 832, - .height = 628, - .fps_options = { - { /* Binning Pixel clock: 335.36MHz */ - .fps = 30, - .pixels_per_line = 5464, - .lines_per_frame = 2046, - - }, - { - } - }, - .bin_factor_x = 2, - .bin_factor_y = 2, - .used = 0, - .mipi_freq = 209600, - }, - { - .desc = "imx135_2m_cropped_video", - .regs = imx135_2m_cropped, - .width = 1648, - .height = 1240, - .fps_options = { - { /* Pixel clock: 335.36MHz */ - .fps = 30, - .pixels_per_line = 5464, - .lines_per_frame = 2046, - - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - .mipi_freq = 209600, - }, - { - .desc = "imx135_1936x1096_cropped", - .regs = imx135_1936x1096_cropped, - .width = 1936, - .height = 1096, - .fps_options = { - { /* Pixel clock: 335.36MHz */ - .fps = 30, - .pixels_per_line = 5464, - .lines_per_frame = 2046, - - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .mipi_freq = 209600, - }, - { - .desc = "imx135_8m_cropped_video", - .regs = imx135_8m_cropped, - .width = 3280, - .height = 2464, - .fps_options = { - { /* Pixel clock: 360.96MHz */ - .fps = 30, - .pixels_per_line = 4572, - .lines_per_frame = 2624, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .mipi_freq = 451200, - }, -}; - -/* - * ISP Scaling is now supported in online capture use cases. Because of that - * we need only few modes to cover the different aspect ratios from the - * sensor and the ISP will scale it based on the requested resolution from HAL. - * - * There is a performance impact when continuous view finder option is chose - * for resolutions above 8MP. So 8MP and 6MP resolution are kept, so that lower - * than these take 8MP or 6MP espectively for down scaling based on the - * aspect ratio. - */ -struct imx_resolution imx135_res_still_mofd[] = { - { - .desc = "imx135_cif_binning_still", - .regs = imx135_cif_binning_1888x1548, - .width = 1888, - .height = 1548, - .fps_options = { - { /* Binning Pixel clock: 335.36MHz */ - .fps = 30, - .pixels_per_line = 5464, - .lines_per_frame = 2046, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .mipi_freq = 209600, - }, - { - .desc = "imx135_vga_binning_preview", - .regs = imx135_vga_binning, - .width = 1036, - .height = 780, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 9144, - .lines_per_frame = 1226, - }, - { - } - }, - .bin_factor_x = 2, - .bin_factor_y = 2, - .mipi_freq = 209600, - }, - { - .desc = "imx135_480p_preview", - .regs = imx135_480p_binning, - .width = 1036, - .height = 696, - .fps_options = { - { /* Binning Pixel clock: 335.36MHz */ - .fps = 30, - .pixels_per_line = 9144, - .lines_per_frame = 1226, - }, - { - } - }, - .bin_factor_x = 2, - .bin_factor_y = 2, - .mipi_freq = 209600, - }, - { - .desc = "imx135_1080p_binning_still", - .regs = imx135_1080p_binning, - .width = 1936, - .height = 1104, - .fps_options = { - { /* Binning Pixel clock: 335.36MHz */ - .fps = 15, - .pixels_per_line = 9114, - .lines_per_frame = 2453, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - .mipi_freq = 209600, - }, - { - .desc = "imx135_3m__still", - .regs = imx135_3m_binning, - .width = 2064, - .height = 1552, - .fps_options = { - { /* Binning Pixel clock: 335.36MHz */ - .fps = 15, - .pixels_per_line = 9114, - .lines_per_frame = 2453, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - .mipi_freq = 209600, - }, - { - .desc = "imx135_6m_for_mipi_342_still", - .regs = imx135_6m_for_mipi_342, - .width = 3280, - .height = 1852, - .fps_options = { - { /* Pixel clock: 273.6MHz */ - .fps = 11, - .pixels_per_line = 9114, - .lines_per_frame = 2664, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .mipi_freq = 342000, - }, - { - .desc = "imx135_8m_scaled_from_12m_for_mipi342_still", - .regs = imx135_8m_scaled_from_12m_for_mipi342, - .width = 3280, - .height = 2464, - .fps_options = { - { /* Pixel clock: 273.6MHz */ - .fps = 8, - .pixels_per_line = 7672, - .lines_per_frame = 4458, - }, - { /* Pixel clock: 273.6MHz */ - .fps = 15, - .pixels_per_line = 5500, - .lines_per_frame = 3314, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .mipi_freq = 342000, - }, - { - .desc = "imx135_10m_for_mipi_342_still", - .regs = imx135_10m_for_mipi_342, - .width = 4208, - .height = 2368, - .fps_options = { - { /* Pixel clock: 273.6MHz */ - .fps = 11, - .pixels_per_line = 9144, - .lines_per_frame = 2664, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .mipi_freq = 342000, - }, - { - .desc = "imx135_13m_still", - .regs = imx135_13m_for_mipi_342, - .width = 4208, - .height = 3120, - .fps_options = { - { /* Pixel clock: 273.6MHz */ - .fps = 5, - .pixels_per_line = 9144, - .lines_per_frame = 5990, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .mipi_freq = 342000, - }, -}; - -struct imx_resolution imx135_res_still[] = { - { - .desc = "imx135_qvga", - .regs = imx135_336x256, - .width = 336, - .height = 256, - .fps_options = { - { /* Pixel clock: 360.96MHz */ - .fps = 30, - .pixels_per_line = 4572, - .lines_per_frame = 2624, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - .mipi_freq = 451200, - }, - { - .desc = "imx135_cif", - .regs = imx135_368x304_cropped, - .width = 368, - .height = 304, - .fps_options = { - { /* Pixel clock: 360.96MHz */ - .fps = 30, - .pixels_per_line = 4572, - .lines_per_frame = 2624, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - .mipi_freq = 451200, - }, - { - .desc = "imx135_xga_cropped_video", - .regs = imx135_xga_cropped, - .width = 832, - .height = 628, - .fps_options = { - { /* Pixel clock: 360.96MHz */ - .fps = 30, - .pixels_per_line = 4572, - .lines_per_frame = 2624, - }, - { - } - }, - .bin_factor_x = 2, - .bin_factor_y = 2, - .used = 0, - .mipi_freq = 451200, - }, - { - .desc = "imx135_2M_for_11:9", - .regs = imx135_1424x1168_cropped, - .width = 1424, - .height = 1168, - .fps_options = { - { /* Pixel clock: 360.96MHz */ - .fps = 30, - .pixels_per_line = 4572, - .lines_per_frame = 2624, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - .mipi_freq = 451200, - }, - { - .desc = "imx135_2m_cropped_video", - .regs = imx135_2m_cropped, - .width = 1648, - .height = 1240, - .fps_options = { - { /* Pixel clock: 360.96MHz */ - .fps = 15, - .pixels_per_line = 6466, - .lines_per_frame = 3710, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - .mipi_freq = 451200, - }, - { - .desc = "imx135_6m_cropped_video", - .regs = imx135_6m_cropped, - .width = 3280, - .height = 1852, - .fps_options = { - { /* Pixel clock: 360.96MHz */ - .fps = 8, - .pixels_per_line = 8850, - .lines_per_frame = 5080, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .mipi_freq = 451200, - }, - { - .desc = "imx135_8m_cropped_video", - .regs = imx135_8m_cropped, - .width = 3280, - .height = 2464, - .fps_options = { - { /* Pixel clock: 360.96MHz */ - .fps = 8, - .pixels_per_line = 8850, - .lines_per_frame = 5080, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .mipi_freq = 451200, - }, -}; - -/* - * ISP scaling is not supported in case of video modes. So we need to have - * separate sensor mode for video use cases - */ -struct imx_resolution imx135_res_video[] = { - /* For binning modes pix clock is 335.36 MHz. */ - { - .desc = "imx135_qcif_dvs_binning_video", - .regs = imx135_qcif_dvs_binning, - .width = 216, - .height = 176, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 9144, - .lines_per_frame = 1226, - }, - { - } - }, - .bin_factor_x = 2, - .bin_factor_y = 2, - .mipi_freq = 209600, - }, - { - .desc = "imx135_cif_binning_video", - .regs = imx135_cif_binning, - .width = 368, - .height = 304, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 9144, - .lines_per_frame = 1226, - }, - { - } - }, - .bin_factor_x = 2, - .bin_factor_y = 2, - .mipi_freq = 209600, - }, - { - .desc = "imx135_qvga__dvs_binning_video", - .regs = imx135_qvga__dvs_binning, - .width = 408, - .height = 308, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 9144, - .lines_per_frame = 1226, - }, - { - } - }, - .bin_factor_x = 2, - .bin_factor_y = 2, - .mipi_freq = 209600, - }, - { - .desc = "imx135_436x360_binning_video", - .regs = imx135_436x360_binning, - .width = 436, - .height = 360, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 9144, - .lines_per_frame = 1226, - }, - { - } - }, - .bin_factor_x = 2, - .bin_factor_y = 2, - .mipi_freq = 209600, - }, - { - .desc = "imx135_vga_dvs_binning_video", - .regs = imx135_vga_dvs_binning, - .width = 820, - .height = 616, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 9144, - .lines_per_frame = 1226, - }, - { - } - }, - .bin_factor_x = 2, - .bin_factor_y = 2, - .mipi_freq = 209600, - }, - { - .desc = "imx135_480p_dvs_binning_video", - .regs = imx135_480p_dvs_binning, - .width = 936, - .height = 602, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 5464, - .lines_per_frame = 2046, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .mipi_freq = 209600, - }, - { - .desc = "imx135_720P_dvs_video", - .regs = imx135_720pdvs_max_clock, - .width = 1568, - .height = 880, - .fps_options = { - {/* Pixel Clock : 360.96 MHz */ - .fps = 30, - .pixels_per_line = 5850, - .lines_per_frame = 2000, - }, - {/* Pixel Clock : 360.96 MHz */ - .fps = 60, - .pixels_per_line = 4572, - .lines_per_frame = 1310, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .mipi_freq = 451200, - }, - { - .desc = "imx135_wvga_dvs_binning_video", - .regs = imx135_wvga_dvs_binning, - .width = 1640, - .height = 1024, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 5464, - .lines_per_frame = 2046, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .mipi_freq = 209600, - }, - { - .desc = "imx135_1936_1096_fullfov_max_clock", - .regs = imx135_1080p_nodvs_max_clock, - .width = 1936, - .height = 1096, - .fps_options = { - {/* Pixel Clock : 360.96 MHz */ - .fps = 30, - .pixels_per_line = 5850, - .lines_per_frame = 2000, - }, - {/* Pixel Clock : 360.96 MHz */ - .fps = 60, - .pixels_per_line = 4572, - .lines_per_frame = 1310, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .mipi_freq = 451200, - }, - { - .desc = "imx135_1080P_dvs_video", - .regs = imx135_2336x1320_max_clock, - .width = 2336, - .height = 1320, - .fps_options = { - {/* Pixel Clock : 360.96 MHz */ - .fps = 30, - .pixels_per_line = 4572, - .lines_per_frame = 2632, - .regs = imx135_2336x1320_max_clock, - .mipi_freq = 451200, - }, - {/* Pixel Clock : 399.36MHz */ - .fps = 60, - .pixels_per_line = 4754, - .lines_per_frame = 1400, - .regs = imx135_2336x1320_cropped_mipi499, - .mipi_freq = 499200, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .mipi_freq = 451200, - }, - { - .desc = "imx135_6m_cont_cap", - .regs = imx135_6m, - .width = 3280, - .height = 1852, - .fps_options = { - { /* Binning Pixel clock: 360.96MHz */ - .fps = 30, - .pixels_per_line = 4572, - .lines_per_frame = 2624, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .mipi_freq = 451200, - }, - { - .desc = "imx135_8m_cropped_video", - .regs = imx135_8m_cropped, - .width = 3280, - .height = 2464, - .fps_options = { - { /* Pixel clock: 360.96MHz */ - .fps = 30, - .pixels_per_line = 4572, - .lines_per_frame = 2624, - }, - { - } - }, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .mipi_freq = 451200, - }, -}; - -#endif diff --git a/drivers/staging/media/atomisp/i2c/imx/imx175.h b/drivers/staging/media/atomisp/i2c/imx/imx175.h deleted file mode 100644 index 5f409ccedc85..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/imx175.h +++ /dev/null @@ -1,1959 +0,0 @@ -#ifndef __IMX175_H__ -#define __IMX175_H__ -#include "common.h" - -/************************** settings for imx *************************/ -static struct imx_reg const imx_STILL_8M_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x0A}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0xFC}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x09}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x01}, - {IMX_8BIT, 0x030D, 0x2c}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x09}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0xC4}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x0D}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x66}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x00}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x00}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x00}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0C}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xCF}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x09}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x9F}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x0C}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0xD0}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x09}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0xA0}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x00}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x00}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x10}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x57}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x77}, - {IMX_8BIT, 0x3371, 0x2F}, - {IMX_8BIT, 0x3372, 0x4F}, - {IMX_8BIT, 0x3373, 0x2F}, - {IMX_8BIT, 0x3374, 0x2F}, - {IMX_8BIT, 0x3375, 0x37}, - {IMX_8BIT, 0x3376, 0x9F}, - {IMX_8BIT, 0x3377, 0x37}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x0C}, - {IMX_8BIT, 0x33D5, 0xD0}, - {IMX_8BIT, 0x33D6, 0x09}, - {IMX_8BIT, 0x33D7, 0xA0}, - - {IMX_8BIT, 0x030e, 0x01}, - {IMX_8BIT, 0x41c0, 0x01}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_STILL_8M_15fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x0A}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0xFC}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x09}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x01}, - {IMX_8BIT, 0x030D, 0x2c}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x0B}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0xB8}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x16}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x44}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x00}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x00}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x00}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0C}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xCF}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x09}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x9F}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x0C}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0xD0}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x09}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0xA0}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x00}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x00}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x10}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x57}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x77}, - {IMX_8BIT, 0x3371, 0x2F}, - {IMX_8BIT, 0x3372, 0x4F}, - {IMX_8BIT, 0x3373, 0x2F}, - {IMX_8BIT, 0x3374, 0x2F}, - {IMX_8BIT, 0x3375, 0x37}, - {IMX_8BIT, 0x3376, 0x9F}, - {IMX_8BIT, 0x3377, 0x37}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x0C}, - {IMX_8BIT, 0x33D5, 0xD0}, - {IMX_8BIT, 0x33D6, 0x09}, - {IMX_8BIT, 0x33D7, 0xA0}, - - {IMX_8BIT, 0x030e, 0x01}, - {IMX_8BIT, 0x41c0, 0x01}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_STILL_3M_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x0A}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0xEF}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x09}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x01}, - {IMX_8BIT, 0x030D, 0x2c}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x09}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0xC4}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x0D}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x66}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x00}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x00}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x00}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0C}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xCF}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x09}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x9F}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x08}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0x10}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x06}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0x10}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x00}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x02}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x19}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x57}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x77}, - {IMX_8BIT, 0x3371, 0x2F}, - {IMX_8BIT, 0x3372, 0x4F}, - {IMX_8BIT, 0x3373, 0x2F}, - {IMX_8BIT, 0x3374, 0x2F}, - {IMX_8BIT, 0x3375, 0x37}, - {IMX_8BIT, 0x3376, 0x9F}, - {IMX_8BIT, 0x3377, 0x37}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x0C}, - {IMX_8BIT, 0x33D5, 0xD0}, - {IMX_8BIT, 0x33D6, 0x09}, - {IMX_8BIT, 0x33D7, 0xA0}, - - {IMX_8BIT, 0x030e, 0x01}, - {IMX_8BIT, 0x41c0, 0x01}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_STILL_3M_15fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x0A}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0xEF}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x09}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x01}, - {IMX_8BIT, 0x030D, 0x2c}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x0B}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0xB8}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x16}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x44}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x00}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x00}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x00}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0C}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xCF}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x09}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x9F}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x08}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0x10}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x06}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0x10}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x00}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x02}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x19}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x57}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x77}, - {IMX_8BIT, 0x3371, 0x2F}, - {IMX_8BIT, 0x3372, 0x4F}, - {IMX_8BIT, 0x3373, 0x2F}, - {IMX_8BIT, 0x3374, 0x2F}, - {IMX_8BIT, 0x3375, 0x37}, - {IMX_8BIT, 0x3376, 0x9F}, - {IMX_8BIT, 0x3377, 0x37}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x0C}, - {IMX_8BIT, 0x33D5, 0xD0}, - {IMX_8BIT, 0x33D6, 0x09}, - {IMX_8BIT, 0x33D7, 0xA0}, - - {IMX_8BIT, 0x030e, 0x01}, - {IMX_8BIT, 0x41c0, 0x01}, - {IMX_TOK_TERM, 0, 0} -}; - - -static struct imx_reg const imx_STILL_5M_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x0A}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0xEF}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x09}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x01}, - {IMX_8BIT, 0x030D, 0x2c}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x09}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0xC4}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x0D}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x66}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x00}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x00}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x00}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0C}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xCF}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x09}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x9F}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x0A}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0x10}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x07}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0x90}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x00}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x02}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x14}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x57}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x77}, - {IMX_8BIT, 0x3371, 0x2F}, - {IMX_8BIT, 0x3372, 0x4F}, - {IMX_8BIT, 0x3373, 0x2F}, - {IMX_8BIT, 0x3374, 0x2F}, - {IMX_8BIT, 0x3375, 0x37}, - {IMX_8BIT, 0x3376, 0x9F}, - {IMX_8BIT, 0x3377, 0x37}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x0C}, - {IMX_8BIT, 0x33D5, 0xD0}, - {IMX_8BIT, 0x33D6, 0x09}, - {IMX_8BIT, 0x33D7, 0xA0}, - - {IMX_8BIT, 0x030e, 0x01}, - {IMX_8BIT, 0x41c0, 0x01}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_STILL_5M_15fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x0A}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0xEF}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x09}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x01}, - {IMX_8BIT, 0x030D, 0x2c}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x0B}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0xB8}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x16}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x44}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x00}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x00}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x00}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0C}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xCF}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x09}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x9F}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x0A}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0x10}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x07}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0x90}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x00}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x00}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x14}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x57}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x77}, - {IMX_8BIT, 0x3371, 0x2F}, - {IMX_8BIT, 0x3372, 0x4F}, - {IMX_8BIT, 0x3373, 0x2F}, - {IMX_8BIT, 0x3374, 0x2F}, - {IMX_8BIT, 0x3375, 0x37}, - {IMX_8BIT, 0x3376, 0x9F}, - {IMX_8BIT, 0x3377, 0x37}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x0C}, - {IMX_8BIT, 0x33D5, 0xD0}, - {IMX_8BIT, 0x33D6, 0x09}, - {IMX_8BIT, 0x33D7, 0xA0}, - - {IMX_8BIT, 0x030e, 0x01}, - {IMX_8BIT, 0x41c0, 0x01}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_STILL_6M_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x0A}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0xEF}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x09}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x01}, - {IMX_8BIT, 0x030D, 0x2c}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x09}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0xC4}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x0D}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x66}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x00}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x01}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x32}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0C}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xCF}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x08}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x6D}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x0C}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0xD0}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x07}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0x3C}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x00}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x00}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x10}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x57}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x77}, - {IMX_8BIT, 0x3371, 0x2F}, - {IMX_8BIT, 0x3372, 0x4F}, - {IMX_8BIT, 0x3373, 0x2F}, - {IMX_8BIT, 0x3374, 0x2F}, - {IMX_8BIT, 0x3375, 0x37}, - {IMX_8BIT, 0x3376, 0x9F}, - {IMX_8BIT, 0x3377, 0x37}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x0C}, - {IMX_8BIT, 0x33D5, 0xD0}, - {IMX_8BIT, 0x33D6, 0x09}, - {IMX_8BIT, 0x33D7, 0xA0}, - - {IMX_8BIT, 0x030e, 0x01}, - {IMX_8BIT, 0x41c0, 0x01}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_STILL_6M_15fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x0A}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0xEF}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x09}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x01}, - {IMX_8BIT, 0x030D, 0x2c}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x0B}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0xB8}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x16}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x44}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x00}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x01}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x32}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0C}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xCF}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x08}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x6D}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x0C}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0xD0}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x07}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0x3C}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x00}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x00}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x10}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x57}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x77}, - {IMX_8BIT, 0x3371, 0x2F}, - {IMX_8BIT, 0x3372, 0x4F}, - {IMX_8BIT, 0x3373, 0x2F}, - {IMX_8BIT, 0x3374, 0x2F}, - {IMX_8BIT, 0x3375, 0x37}, - {IMX_8BIT, 0x3376, 0x9F}, - {IMX_8BIT, 0x3377, 0x37}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x0C}, - {IMX_8BIT, 0x33D5, 0xD0}, - {IMX_8BIT, 0x33D6, 0x09}, - {IMX_8BIT, 0x33D7, 0xA0}, - - {IMX_8BIT, 0x030e, 0x01}, - {IMX_8BIT, 0x41c0, 0x01}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_STILL_2M_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x0A}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0x8C}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x09}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x01}, - {IMX_8BIT, 0x030D, 0x2c}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x09}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0xC4}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x0D}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x66}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x00}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x00}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x00}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0C}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xCF}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x09}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x9F}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x06}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0x68}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x04}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0xD0}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x01}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x00}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x10}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x57}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x77}, - {IMX_8BIT, 0x3371, 0x2F}, - {IMX_8BIT, 0x3372, 0x4F}, - {IMX_8BIT, 0x3373, 0x2F}, - {IMX_8BIT, 0x3374, 0x2F}, - {IMX_8BIT, 0x3375, 0x37}, - {IMX_8BIT, 0x3376, 0x9F}, - {IMX_8BIT, 0x3377, 0x37}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x0C}, - {IMX_8BIT, 0x33D5, 0xD0}, - {IMX_8BIT, 0x33D6, 0x09}, - {IMX_8BIT, 0x33D7, 0xA0}, - - {IMX_8BIT, 0x030e, 0x01}, - {IMX_8BIT, 0x41c0, 0x01}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_STILL_2M_15fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x0A}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0x8C}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x09}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x01}, - {IMX_8BIT, 0x030D, 0x2c}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x0B}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0xB8}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x16}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x44}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x00}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x00}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x00}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0C}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xCF}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x09}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x9F}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x06}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0x68}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x04}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0xD0}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x01}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x00}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x10}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x57}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x77}, - {IMX_8BIT, 0x3371, 0x2F}, - {IMX_8BIT, 0x3372, 0x4F}, - {IMX_8BIT, 0x3373, 0x2F}, - {IMX_8BIT, 0x3374, 0x2F}, - {IMX_8BIT, 0x3375, 0x37}, - {IMX_8BIT, 0x3376, 0x9F}, - {IMX_8BIT, 0x3377, 0x37}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x0C}, - {IMX_8BIT, 0x33D5, 0xD0}, - {IMX_8BIT, 0x33D6, 0x09}, - {IMX_8BIT, 0x33D7, 0xA0}, - - {IMX_8BIT, 0x030e, 0x01}, - {IMX_8BIT, 0x41c0, 0x01}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_PREVIEW_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x05}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0x44}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x06}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x00}, - {IMX_8BIT, 0x030D, 0x6D}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x05}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0x48}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x0D}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x70}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x00}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x00}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x00}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0C}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xCF}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x09}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x9F}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x03}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0x34}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x02}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0x68}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x02}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x00}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x10}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x37}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x5F}, - {IMX_8BIT, 0x3371, 0x17}, - {IMX_8BIT, 0x3372, 0x37}, - {IMX_8BIT, 0x3373, 0x17}, - {IMX_8BIT, 0x3374, 0x17}, - {IMX_8BIT, 0x3375, 0x0F}, - {IMX_8BIT, 0x3376, 0x57}, - {IMX_8BIT, 0x3377, 0x27}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x03}, - {IMX_8BIT, 0x33D5, 0x34}, - {IMX_8BIT, 0x33D6, 0x02}, - {IMX_8BIT, 0x33D7, 0x68}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_WIDE_PREVIEW_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x05}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0x44}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x06}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x00}, - {IMX_8BIT, 0x030D, 0x6D}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x0D}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0x70}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x10}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x00}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x00}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x00}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x14}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0C}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xCF}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x08}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x8C}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x06}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0x68}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x03}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0xBC}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x01}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x00}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x10}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x37}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x5F}, - {IMX_8BIT, 0x3371, 0x17}, - {IMX_8BIT, 0x3372, 0x37}, - {IMX_8BIT, 0x3373, 0x17}, - {IMX_8BIT, 0x3374, 0x17}, - {IMX_8BIT, 0x3375, 0x0F}, - {IMX_8BIT, 0x3376, 0x57}, - {IMX_8BIT, 0x3377, 0x27}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x06}, - {IMX_8BIT, 0x33D5, 0x68}, - {IMX_8BIT, 0x33D6, 0x03}, - {IMX_8BIT, 0x33D7, 0xBC}, - {IMX_TOK_TERM, 0, 0} -}; - -/*****************************video************************/ -static struct imx_reg const imx_1080p_strong_dvs_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x06}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0x4C}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x09}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x01}, - {IMX_8BIT, 0x030D, 0x12}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x06}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0xA4}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x11}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0xC6}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x01}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0xDB}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x02}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x42}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0A}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xEA}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x07}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x61}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x09}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0x10}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x05}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0x20}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x00}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x00}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x10}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x57}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x6F}, - {IMX_8BIT, 0x3371, 0x27}, - {IMX_8BIT, 0x3372, 0x4F}, - {IMX_8BIT, 0x3373, 0x2F}, - {IMX_8BIT, 0x3374, 0x27}, - {IMX_8BIT, 0x3375, 0x2F}, - {IMX_8BIT, 0x3376, 0x97}, - {IMX_8BIT, 0x3377, 0x37}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x0C}, - {IMX_8BIT, 0x33D5, 0xD0}, - {IMX_8BIT, 0x33D6, 0x07}, - {IMX_8BIT, 0x33D7, 0x38}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_1080p_no_dvs_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x08}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0xD5}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x09}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x01}, - {IMX_8BIT, 0x030D, 0x12}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x07}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0xD0}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x0F}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x3C}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x00}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x01}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x34}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0C}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xCF}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x08}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x6B}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x07}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0x94}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x04}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0x44}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x00}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x02}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x1B}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x57}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x6F}, - {IMX_8BIT, 0x3371, 0x27}, - {IMX_8BIT, 0x3372, 0x4F}, - {IMX_8BIT, 0x3373, 0x2F}, - {IMX_8BIT, 0x3374, 0x27}, - {IMX_8BIT, 0x3375, 0x2F}, - {IMX_8BIT, 0x3376, 0x97}, - {IMX_8BIT, 0x3377, 0x37}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x0C}, - {IMX_8BIT, 0x33D5, 0xD0}, - {IMX_8BIT, 0x33D6, 0x07}, - {IMX_8BIT, 0x33D7, 0x38}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_1080p_no_dvs_15fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x08}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0xD5}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x09}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x01}, - {IMX_8BIT, 0x030D, 0x12}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x09}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0xA6}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x18}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x9C}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x00}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x01}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x34}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0C}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xCF}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x08}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x6B}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x07}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0x94}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x04}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0x44}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x00}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x02}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x1B}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x57}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x6F}, - {IMX_8BIT, 0x3371, 0x27}, - {IMX_8BIT, 0x3372, 0x4F}, - {IMX_8BIT, 0x3373, 0x2F}, - {IMX_8BIT, 0x3374, 0x27}, - {IMX_8BIT, 0x3375, 0x2F}, - {IMX_8BIT, 0x3376, 0x97}, - {IMX_8BIT, 0x3377, 0x37}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x0C}, - {IMX_8BIT, 0x33D5, 0xD0}, - {IMX_8BIT, 0x33D6, 0x07}, - {IMX_8BIT, 0x33D7, 0x38}, - {IMX_TOK_TERM, 0, 0} -}; -/*****************************video************************/ -static struct imx_reg const imx_720p_strong_dvs_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x05}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0xFC}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x09}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x01}, - {IMX_8BIT, 0x030D, 0x12}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x06}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0x00}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x13}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x9C}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x01}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0xD7}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x02}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x3E}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0A}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xEE}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x07}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x65}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x06}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0x10}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x03}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0x70}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x00}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x02}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x18}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x57}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x6F}, - {IMX_8BIT, 0x3371, 0x27}, - {IMX_8BIT, 0x3372, 0x4F}, - {IMX_8BIT, 0x3373, 0x2F}, - {IMX_8BIT, 0x3374, 0x27}, - {IMX_8BIT, 0x3375, 0x2F}, - {IMX_8BIT, 0x3376, 0x97}, - {IMX_8BIT, 0x3377, 0x37}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x0C}, - {IMX_8BIT, 0x33D5, 0xD0}, - {IMX_8BIT, 0x33D6, 0x07}, - {IMX_8BIT, 0x33D7, 0x38}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_480p_strong_dvs_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x05}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0xFC}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x09}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x01}, - {IMX_8BIT, 0x030D, 0x12}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x06}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0x00}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x13}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x9C}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x01}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0xD4}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x01}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0xC8}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0A}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xF1}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x07}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0xDB}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x03}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0x70}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x02}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0x50}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x01}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x02}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x15}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x57}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x6F}, - {IMX_8BIT, 0x3371, 0x27}, - {IMX_8BIT, 0x3372, 0x4F}, - {IMX_8BIT, 0x3373, 0x2F}, - {IMX_8BIT, 0x3374, 0x27}, - {IMX_8BIT, 0x3375, 0x2F}, - {IMX_8BIT, 0x3376, 0x97}, - {IMX_8BIT, 0x3377, 0x37}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x0C}, - {IMX_8BIT, 0x33D5, 0xD0}, - {IMX_8BIT, 0x33D6, 0x07}, - {IMX_8BIT, 0x33D7, 0x38}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_STILL_720p_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x05}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0x44}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x04}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x00}, - {IMX_8BIT, 0x030D, 0x6D}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x05}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0x48}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x14}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x28}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x48}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x01}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x64}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0C}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0x87}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x08}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x3B}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x06}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0x20}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x03}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0x6C}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x01}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x00}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x10}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x37}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x5F}, - {IMX_8BIT, 0x3371, 0x17}, - {IMX_8BIT, 0x3372, 0x37}, - {IMX_8BIT, 0x3373, 0x17}, - {IMX_8BIT, 0x3374, 0x17}, - {IMX_8BIT, 0x3375, 0x0F}, - {IMX_8BIT, 0x3376, 0x57}, - {IMX_8BIT, 0x3377, 0x27}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x06}, - {IMX_8BIT, 0x33D5, 0x20}, - {IMX_8BIT, 0x33D6, 0x03}, - {IMX_8BIT, 0x33D7, 0x6C}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_STILL_720p_15fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x05}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0x44}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x04}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x00}, - {IMX_8BIT, 0x030D, 0x6D}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x08}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0xCA}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x18}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x38}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x48}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x01}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x64}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0C}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0x87}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x08}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x3B}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x06}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0x20}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x03}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0x6C}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x01}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x00}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x10}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x37}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x5F}, - {IMX_8BIT, 0x3371, 0x17}, - {IMX_8BIT, 0x3372, 0x37}, - {IMX_8BIT, 0x3373, 0x17}, - {IMX_8BIT, 0x3374, 0x17}, - {IMX_8BIT, 0x3375, 0x0F}, - {IMX_8BIT, 0x3376, 0x57}, - {IMX_8BIT, 0x3377, 0x27}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x06}, - {IMX_8BIT, 0x33D5, 0x20}, - {IMX_8BIT, 0x33D6, 0x03}, - {IMX_8BIT, 0x33D7, 0x6C}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_WVGA_strong_dvs_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x05}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0xEC}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x09}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x01}, - {IMX_8BIT, 0x030D, 0x12}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x06}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0x00}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x13}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x9C}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x00}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x00}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0xD0}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0C}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xCF}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x08}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0xCF}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x06}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0x68}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x04}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0x00}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x01}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x00}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x10}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x57}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x6F}, - {IMX_8BIT, 0x3371, 0x27}, - {IMX_8BIT, 0x3372, 0x4F}, - {IMX_8BIT, 0x3373, 0x2F}, - {IMX_8BIT, 0x3374, 0x27}, - {IMX_8BIT, 0x3375, 0x2F}, - {IMX_8BIT, 0x3376, 0x97}, - {IMX_8BIT, 0x3377, 0x37}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x0C}, - {IMX_8BIT, 0x33D5, 0xD0}, - {IMX_8BIT, 0x33D6, 0x07}, - {IMX_8BIT, 0x33D7, 0x38}, - {IMX_TOK_TERM, 0, 0} -}; -static struct imx_reg const imx_CIF_strong_dvs_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x05}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0xFC}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x04}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x00}, - {IMX_8BIT, 0x030D, 0x6D}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x06}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0x00}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x11}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0xDB}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x00}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x00}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x00}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0C}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xCF}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x09}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x9F}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x01}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0x70}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x01}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0x30}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x02}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x00}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x10}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x37}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x5F}, - {IMX_8BIT, 0x3371, 0x17}, - {IMX_8BIT, 0x3372, 0x37}, - {IMX_8BIT, 0x3373, 0x17}, - {IMX_8BIT, 0x3374, 0x17}, - {IMX_8BIT, 0x3375, 0x0F}, - {IMX_8BIT, 0x3376, 0x57}, - {IMX_8BIT, 0x3377, 0x27}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x06}, - {IMX_8BIT, 0x33D5, 0x20}, - {IMX_8BIT, 0x33D6, 0x03}, - {IMX_8BIT, 0x33D7, 0x6C}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_VGA_strong_dvs_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x05}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0xFC}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x04}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x00}, - {IMX_8BIT, 0x030D, 0x6D}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x06}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0x00}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x11}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x94}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x00}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x00}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x00}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0C}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xCF}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x09}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x9F}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x03}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0x34}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x02}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0x68}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x02}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x00}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x10}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x37}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x5F}, - {IMX_8BIT, 0x3371, 0x17}, - {IMX_8BIT, 0x3372, 0x37}, - {IMX_8BIT, 0x3373, 0x17}, - {IMX_8BIT, 0x3374, 0x17}, - {IMX_8BIT, 0x3375, 0x0F}, - {IMX_8BIT, 0x3376, 0x57}, - {IMX_8BIT, 0x3377, 0x27}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x06}, - {IMX_8BIT, 0x33D5, 0x20}, - {IMX_8BIT, 0x33D6, 0x03}, - {IMX_8BIT, 0x33D7, 0x6C}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_VGA_strong_dvs_15fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x05}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0xFC}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x04}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x00}, - {IMX_8BIT, 0x030D, 0x6D}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x07}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0x9E}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x1C}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0xB6}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x00}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x00}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x00}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x0C}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0xCF}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x09}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x9F}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x03}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0x34}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x02}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0x68}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x02}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x00}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x10}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x37}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x5F}, - {IMX_8BIT, 0x3371, 0x17}, - {IMX_8BIT, 0x3372, 0x37}, - {IMX_8BIT, 0x3373, 0x17}, - {IMX_8BIT, 0x3374, 0x17}, - {IMX_8BIT, 0x3375, 0x0F}, - {IMX_8BIT, 0x3376, 0x57}, - {IMX_8BIT, 0x3377, 0x27}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x06}, - {IMX_8BIT, 0x33D5, 0x20}, - {IMX_8BIT, 0x33D6, 0x03}, - {IMX_8BIT, 0x33D7, 0x6C}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_QVGA_strong_dvs_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x05}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0x44}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x06}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x00}, - {IMX_8BIT, 0x030D, 0x6D}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x05}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0x48}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x0D}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x70}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x03}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0x38}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x02}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x68}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x09}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0x97}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x07}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x37}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x01}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0x98}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x01}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0x34}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x02}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x00}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x10}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x37}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x5F}, - {IMX_8BIT, 0x3371, 0x17}, - {IMX_8BIT, 0x3372, 0x37}, - {IMX_8BIT, 0x3373, 0x17}, - {IMX_8BIT, 0x3374, 0x17}, - {IMX_8BIT, 0x3375, 0x0F}, - {IMX_8BIT, 0x3376, 0x57}, - {IMX_8BIT, 0x3377, 0x27}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x01}, - {IMX_8BIT, 0x33D5, 0x98}, - {IMX_8BIT, 0x33D6, 0x01}, - {IMX_8BIT, 0x33D7, 0x34}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_QCIF_strong_dvs_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - /* shutter */ - {IMX_8BIT, 0x0202, 0x05}, /* coarse _integration_time[15:8] */ - {IMX_8BIT, 0x0203, 0x44}, /* coarse _integration_time[7:0] */ - /* pll */ - {IMX_8BIT, 0x0301, 0x05}, /* vt_pix_clk_div[7:0] */ - {IMX_8BIT, 0x0303, 0x01}, /* vt_sys_clk_div[7:0] */ - {IMX_8BIT, 0x0305, 0x06}, /* pre_pll_clk_div[7:0] */ - {IMX_8BIT, 0x0309, 0x05}, /* op_pix_clk_div[7:0] */ - {IMX_8BIT, 0x030B, 0x01}, /* op_sys_clk_div[7:0] */ - {IMX_8BIT, 0x030C, 0x00}, - {IMX_8BIT, 0x030D, 0x6D}, - /* image sizing */ - {IMX_8BIT, 0x0340, 0x05}, /* frame_length_lines[15:8] */ - {IMX_8BIT, 0x0341, 0x48}, /* frame_length_lines[7:0] */ - {IMX_8BIT, 0x0342, 0x0D}, /* line_length_pck[15:8] */ - {IMX_8BIT, 0x0343, 0x70}, /* line_length_pck[7:0] */ - {IMX_8BIT, 0x0344, 0x04}, /* x_addr_start[15:8] */ - {IMX_8BIT, 0x0345, 0xB8}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x03}, /* y_addr_start[15:8] */ - {IMX_8BIT, 0x0347, 0x70}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x08}, /* x_addr_end[15:8] */ - {IMX_8BIT, 0x0349, 0x17}, /* x_addr_end[7:0] */ - {IMX_8BIT, 0x034A, 0x06}, /* y_addr_end[15:8] */ - {IMX_8BIT, 0x034B, 0x2F}, /* y_addr_end[7:0] */ - {IMX_8BIT, 0x034C, 0x00}, /* x_output_size[15:8] */ - {IMX_8BIT, 0x034D, 0xD8}, /* x_output_size[7:0] */ - {IMX_8BIT, 0x034E, 0x00}, /* y_output_size[15:8] */ - {IMX_8BIT, 0x034F, 0xB0}, /* y_output_size[7:0] */ - /* binning & scaling */ - {IMX_8BIT, 0x0390, 0x02}, /* binning mode */ - {IMX_8BIT, 0x0401, 0x00}, /* scaling mode*/ - {IMX_8BIT, 0x0405, 0x10}, /* scale_m[7:0] */ - /* timer */ - {IMX_8BIT, 0x3344, 0x37}, - {IMX_8BIT, 0x3345, 0x1F}, - /* timing */ - {IMX_8BIT, 0x3370, 0x5F}, - {IMX_8BIT, 0x3371, 0x17}, - {IMX_8BIT, 0x3372, 0x37}, - {IMX_8BIT, 0x3373, 0x17}, - {IMX_8BIT, 0x3374, 0x17}, - {IMX_8BIT, 0x3375, 0x0F}, - {IMX_8BIT, 0x3376, 0x57}, - {IMX_8BIT, 0x3377, 0x27}, - {IMX_8BIT, 0x33C8, 0x01}, - {IMX_8BIT, 0x33D4, 0x00}, - {IMX_8BIT, 0x33D5, 0xD8}, - {IMX_8BIT, 0x33D6, 0x00}, - {IMX_8BIT, 0x33D7, 0xB0}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx175_init_settings[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0103, 0x01}, - /* misc control */ - {IMX_8BIT, 0x3020, 0x10}, - {IMX_8BIT, 0x302D, 0x02}, - {IMX_8BIT, 0x302F, 0x80}, - {IMX_8BIT, 0x3032, 0xA3}, - {IMX_8BIT, 0x3033, 0x20}, - {IMX_8BIT, 0x3034, 0x24}, - {IMX_8BIT, 0x3041, 0x15}, - {IMX_8BIT, 0x3042, 0x87}, - {IMX_8BIT, 0x3050, 0x35}, - {IMX_8BIT, 0x3056, 0x57}, - {IMX_8BIT, 0x305D, 0x41}, - {IMX_8BIT, 0x3097, 0x69}, - {IMX_8BIT, 0x3109, 0x41}, - {IMX_8BIT, 0x3148, 0x3F}, - {IMX_8BIT, 0x330F, 0x07}, - /* csi & inck */ - {IMX_8BIT, 0x3364, 0x00}, - {IMX_8BIT, 0x3368, 0x13}, - {IMX_8BIT, 0x3369, 0x33}, - /* znr */ - {IMX_8BIT, 0x4100, 0x0E}, - {IMX_8BIT, 0x4104, 0x32}, - {IMX_8BIT, 0x4105, 0x32}, - {IMX_8BIT, 0x4108, 0x01}, - {IMX_8BIT, 0x4109, 0x7C}, - {IMX_8BIT, 0x410A, 0x00}, - {IMX_8BIT, 0x410B, 0x00}, - GROUPED_PARAMETER_HOLD_DISABLE, - {IMX_TOK_TERM, 0, 0} -}; -/* TODO settings of preview/still/video will be updated with new use case */ -struct imx_resolution imx175_res_preview[] = { - { - .desc = "CIF_strong_dvs_30fps", - .regs = imx_CIF_strong_dvs_30fps, - .width = 368, - .height = 304, - .bin_factor_x = 4, - .bin_factor_y = 4, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x11DB, - .lines_per_frame = 0x0600, - }, - { - } - }, - .mipi_freq = 261500, - - }, - { - .desc = "VGA_strong_dvs_30fps", - .regs = imx_VGA_strong_dvs_30fps, - .width = 820, - .height = 616, - .bin_factor_x = 4, - .bin_factor_y = 4, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x11DB, - .lines_per_frame = 0x0600, - }, - { - } - }, - .mipi_freq = 261500, - }, - { - .desc = "WIDE_PREVIEW_30fps", - .regs = imx_WIDE_PREVIEW_30fps, - .width = 1640, - .height = 956, - .bin_factor_x = 2, - .bin_factor_y = 2, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x1000, - .lines_per_frame = 0x0D70, - }, - { - } - }, - .mipi_freq = 174500, - }, - { - .desc = "STILL_720p_30fps", - .regs = imx_STILL_720p_30fps, - .width = 1568, - .height = 876, - .bin_factor_x = 2, - .bin_factor_y = 2, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x1428, - .lines_per_frame = 0x0548, - }, - { - } - }, - .mipi_freq = 261500, - }, - { - .desc = "STILL_2M_30fps", - .regs = imx_STILL_2M_30fps, - .width = 1640, - .height = 1232, - .bin_factor_x = 2, - .bin_factor_y = 2, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x0D66, - .lines_per_frame = 0x09C4, - }, - { - } - }, - .mipi_freq = 320000, - }, - { - .desc = "1080p_strong_dvs_30fps", - .regs = imx_1080p_no_dvs_30fps, - .width = 1940, - .height = 1092, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x0F3C, - .lines_per_frame = 0x07D0, - }, - { - } - }, - .mipi_freq = 292500, - }, - { - .desc = "STILL_3M_30fps", - .regs = imx_STILL_3M_30fps, - .width = 2064, - .height = 1552, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x0D66, - .lines_per_frame = 0x09C4, - }, - { - } - }, - .mipi_freq = 320000, - }, - { - .desc = "STILL_5M_30fps", - .regs = imx_STILL_5M_30fps, - .width = 2576, - .height = 1936, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x0D66, - .lines_per_frame = 0x09C4, - }, - { - } - }, - .mipi_freq = 320000, - }, - { - .desc = "STILL_6M_30fps", - .regs = imx_STILL_6M_30fps, - .width = 3280, - .height = 1852, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x0D66, - .lines_per_frame = 0x09C4, - }, - { - } - }, - .mipi_freq = 320000, - }, - { - .desc = "STILL_8M_30fps", - .regs = imx_STILL_8M_30fps, - .width = 3280, - .height = 2464, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x0D66, - .lines_per_frame = 0x09C4, - }, - { - } - }, - .mipi_freq = 320000, - }, -}; - -struct imx_resolution imx175_res_still[] = { - { - .desc = "CIF_strong_dvs_30fps", - .regs = imx_CIF_strong_dvs_30fps, - .width = 368, - .height = 304, - .bin_factor_x = 4, - .bin_factor_y = 4, - .used = 0, - .fps_options = { - { - .fps = 15, - .pixels_per_line = 0x11DB, - .lines_per_frame = 0x0600, - }, - { - } - }, - .mipi_freq = 261000, - }, - { - .desc = "VGA_strong_dvs_15fps", - .regs = imx_VGA_strong_dvs_15fps, - .width = 820, - .height = 616, - .bin_factor_x = 4, - .bin_factor_y = 4, - .used = 0, - .fps_options = { - { - .fps = 15, - .pixels_per_line = 0x1C86, - .lines_per_frame = 0x079E, - }, - { - } - }, - .mipi_freq = 261500, - }, - { - .desc = "imx_STILL_720p_15fps", - .regs = imx_STILL_720p_15fps, - .width = 1568, - .height = 876, - .bin_factor_x = 2, - .bin_factor_y = 2, - .used = 0, - .fps_options = { - { - .fps = 15, - .pixels_per_line = 0x1838, - .lines_per_frame = 0x08CA, - }, - { - } - }, - .mipi_freq = 261500, - }, - { - .desc = "STILL_2M_15fps", - .regs = imx_STILL_2M_15fps, - .width = 1640, - .height = 1232, - .bin_factor_x = 2, - .bin_factor_y = 2, - .used = 0, - .fps_options = { - { - .fps = 15, - .pixels_per_line = 0x1646, - .lines_per_frame = 0x0BB8, - }, - { - } - }, - .mipi_freq = 320000, - }, - { - .desc = "1080p_strong_dvs_15fps", - .regs = imx_1080p_no_dvs_15fps, - .width = 1940, - .height = 1092, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .fps_options = { - { - .fps = 15, - .pixels_per_line = 0x189C, - .lines_per_frame = 0x09A6, - }, - { - } - }, - .mipi_freq = 292500, - }, - { - .desc = "STILL_3M_15fps", - .regs = imx_STILL_3M_15fps, - .width = 2064, - .height = 1552, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .fps_options = { - { - .fps = 15, - .pixels_per_line = 0x1646, - .lines_per_frame = 0x0BB8, - }, - { - } - }, - .mipi_freq = 320000, - }, - { - .desc = "STILL_5M_15fps", - .regs = imx_STILL_5M_15fps, - .width = 2576, - .height = 1936, - .fps = 15, - .pixels_per_line = 0x1646, /* consistent with regs arrays */ - .lines_per_frame = 0x0BB8, /* consistent with regs arrays */ - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .fps_options = { - { - .fps = 15, - .pixels_per_line = 0x1646, - .lines_per_frame = 0x0BB8, - }, - { - } - }, - .mipi_freq = 320000, - }, - { - .desc = "STILL_6M_15fps", - .regs = imx_STILL_6M_15fps, - .width = 3280, - .height = 1852, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .fps_options = { - { - .fps = 15, - .pixels_per_line = 0x1646, - .lines_per_frame = 0x0BB8, - }, - { - } - }, - .mipi_freq = 320000, - }, - { - .desc = "STILL_8M_15fps", - .regs = imx_STILL_8M_15fps, - .width = 3280, - .height = 2464, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .fps_options = { - { - .fps = 15, - .pixels_per_line = 0x1646, - .lines_per_frame = 0x0BB8, - }, - { - } - }, - .mipi_freq = 320000, - }, -}; - -struct imx_resolution imx175_res_video[] = { - { - .desc = "QCIF_strong_dvs_30fps", - .regs = imx_QCIF_strong_dvs_30fps, - .width = 216, - .height = 176, - .bin_factor_x = 4, - .bin_factor_y = 4, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x0D70, - .lines_per_frame = 0x0548, - }, - { - } - }, - .mipi_freq = 174500, - }, - { - .desc = "QVGA_strong_dvs_30fps", - .regs = imx_QVGA_strong_dvs_30fps, - .width = 408, - .height = 308, - .bin_factor_x = 4, - .bin_factor_y = 4, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x0D70, - .lines_per_frame = 0x0548, - }, - { - } - }, - .mipi_freq = 174500, - }, - { - .desc = "VGA_strong_dvs_30fps", - .regs = imx_VGA_strong_dvs_30fps, - .width = 820, - .height = 616, - .bin_factor_x = 4, - .bin_factor_y = 4, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x1194, - .lines_per_frame = 0x0600, - }, - { - } - }, - .mipi_freq = 261500, - }, - { - .desc = "720p_strong_dvs_30fps", - .regs = imx_720p_strong_dvs_30fps, - .width = 1552, - .height = 880, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x139C, - .lines_per_frame = 0x0600, - }, - { - .fps = 60, - .pixels_per_line = 0xD70, - .lines_per_frame = 0x444, - }, - { - } - }, - .mipi_freq = 292500, - }, - { - .desc = "480p_strong_dvs_30fps", - .regs = imx_480p_strong_dvs_30fps, - .width = 880, - .height = 592, - .bin_factor_x = 2, - .bin_factor_y = 2, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x139C, - .lines_per_frame = 0x0600, - }, - { - } - }, - .mipi_freq = 292500, - }, - { - .desc = "WVGA_strong_dvs_30fps", - .regs = imx_WVGA_strong_dvs_30fps, - .width = 1640, - .height = 1024, - .bin_factor_x = 2, - .bin_factor_y = 2, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x139C, - .lines_per_frame = 0x0600, - }, - { - } - }, - .mipi_freq = 292500, - }, - { - .desc = "1080p_strong_dvs_30fps", - .regs = imx_1080p_strong_dvs_30fps, - .width = 2320, - .height = 1312, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x11C6, - .lines_per_frame = 0x06A4, - }, - { - } - }, - .mipi_freq = 292500, - }, -}; - -#endif diff --git a/drivers/staging/media/atomisp/i2c/imx/imx208.h b/drivers/staging/media/atomisp/i2c/imx/imx208.h deleted file mode 100644 index fed387f42f99..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/imx208.h +++ /dev/null @@ -1,550 +0,0 @@ -/* - * Support for Sony IMX camera sensor. - * - * Copyright (c) 2014 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#ifndef __IMX208_H__ -#define __IMX208_H__ -#include "common.h" - -/********************** settings for imx from vendor*********************/ -static struct imx_reg imx208_1080p_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0305, 0x02}, /* PREPLLCK DIV */ - {IMX_8BIT, 0x0307, 0x54}, /* PLL MPY */ - {IMX_8BIT, 0x303C, 0x3C}, /* PLL oscillation stable wait time */ - {IMX_8BIT, 0x30A4, 0x02}, /* Default */ - {IMX_8BIT, 0x0112, 0x0A}, /* CCP_data_format : RAW 10bit */ - {IMX_8BIT, 0x0113, 0x0A}, /* CCP_data_format : RAW 10bit */ - {IMX_8BIT, 0x0340, 0x04}, /* frame length line [15:8] */ - {IMX_8BIT, 0x0341, 0xAA}, /* frame length line [7:0] */ - {IMX_8BIT, 0x0342, 0x08}, /* line length pck [15:8] */ - {IMX_8BIT, 0x0343, 0xC8}, /* line length pck [7:0] */ - {IMX_8BIT, 0x0344, 0x00}, /* x_addr_start[12:8] */ - {IMX_8BIT, 0x0345, 0x00}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x00}, /* y_addr_start[12:8] */ - {IMX_8BIT, 0x0347, 0x00}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x07}, /* x_addr_end [12:8] */ - {IMX_8BIT, 0x0349, 0x8F}, /* x_addr_end [7:0] */ - {IMX_8BIT, 0x034A, 0x04}, /* y_addr_end [12:8] */ - {IMX_8BIT, 0x034B, 0x47}, /* y_addr_end [7:0] */ - {IMX_8BIT, 0x034C, 0x07}, /* x_output_size [ 12:8] */ - {IMX_8BIT, 0x034D, 0x90}, /* x_output_size [7:0] */ - {IMX_8BIT, 0x034E, 0x04}, /* y_output_size [11:8] */ - {IMX_8BIT, 0x034F, 0x48}, /* y_output_size [7:0] */ - {IMX_8BIT, 0x0381, 0x01}, /* x_even_inc */ - {IMX_8BIT, 0x0383, 0x01}, /* x_odd_inc */ - {IMX_8BIT, 0x0385, 0x01}, /* y_even_inc */ - {IMX_8BIT, 0x0387, 0x01}, /* y_odd_inc */ - {IMX_8BIT, 0x3048, 0x00}, /* VMODEFDS binning operation */ - {IMX_8BIT, 0x304E, 0x0A}, /* VTPXCK_DIV */ - {IMX_8BIT, 0x3050, 0x02}, /* OPSYCK_DIV */ - {IMX_8BIT, 0x309B, 0x00}, /* RGDAFDSUMEN */ - {IMX_8BIT, 0x30D5, 0x00}, /* HADDEN ( binning ) */ - {IMX_8BIT, 0x3301, 0x01}, /* RGLANESEL */ - {IMX_8BIT, 0x3318, 0x61}, /* MIPI Global Timing */ - {IMX_8BIT, 0x0202, 0x01}, /* coarse integration time */ - {IMX_8BIT, 0x0203, 0x90}, /* coarse integration time */ - {IMX_8BIT, 0x0205, 0x00}, /* ana global gain */ - - {IMX_TOK_TERM, 0, 0}, -}; - -static struct imx_reg imx208_1296x736_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0305, 0x02}, /* PREPLLCK DIV */ - {IMX_8BIT, 0x0307, 0x54}, /* PLL MPY */ - {IMX_8BIT, 0x303C, 0x3C}, /* PLL oscillation stable wait time */ - {IMX_8BIT, 0x30A4, 0x02}, /* Default */ - {IMX_8BIT, 0x0112, 0x0A}, /* CCP_data_format : RAW 10bit */ - {IMX_8BIT, 0x0113, 0x0A}, /* CCP_data_format : RAW 10bit */ - {IMX_8BIT, 0x0340, 0x04}, /* frame length line [15:8] */ - {IMX_8BIT, 0x0341, 0xAA}, /* frame length line [7:0] */ - {IMX_8BIT, 0x0342, 0x08}, /* line length pck [15:8] */ - {IMX_8BIT, 0x0343, 0xC8}, /* line length pck [7:0] */ - {IMX_8BIT, 0x0344, 0x01}, /* x_addr_start[12:8] */ - {IMX_8BIT, 0x0345, 0x40}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x00}, /* y_addr_start[12:8] */ - {IMX_8BIT, 0x0347, 0xB4}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x06}, /* x_addr_end [12:8] */ - {IMX_8BIT, 0x0349, 0x4F}, /* x_addr_end [7:0] */ - {IMX_8BIT, 0x034A, 0x03}, /* y_addr_end [12:8] */ - {IMX_8BIT, 0x034B, 0x93}, /* y_addr_end [7:0] */ - {IMX_8BIT, 0x034C, 0x05}, /* x_output_size [ 12:8] */ - {IMX_8BIT, 0x034D, 0x10}, /* x_output_size [7:0] */ - {IMX_8BIT, 0x034E, 0x02}, /* y_output_size [11:8] */ - {IMX_8BIT, 0x034F, 0xE0}, /* y_output_size [7:0] */ - {IMX_8BIT, 0x0381, 0x01}, /* x_even_inc */ - {IMX_8BIT, 0x0383, 0x01}, /* x_odd_inc */ - {IMX_8BIT, 0x0385, 0x01}, /* y_even_inc */ - {IMX_8BIT, 0x0387, 0x01}, /* y_odd_inc */ - {IMX_8BIT, 0x3048, 0x00}, /* VMODEFDS binning operation */ - {IMX_8BIT, 0x304E, 0x0A}, /* VTPXCK_DIV */ - {IMX_8BIT, 0x3050, 0x02}, /* OPSYCK_DIV */ - {IMX_8BIT, 0x309B, 0x00}, /* RGDAFDSUMEN */ - {IMX_8BIT, 0x30D5, 0x00}, /* HADDEN ( binning ) */ - {IMX_8BIT, 0x3301, 0x01}, /* RGLANESEL */ - {IMX_8BIT, 0x3318, 0x61}, /* MIPI Global Timing */ - {IMX_8BIT, 0x0202, 0x01}, /* coarse integration time */ - {IMX_8BIT, 0x0203, 0x90}, /* coarse integration time */ - {IMX_8BIT, 0x0205, 0x00}, /* ana global gain */ - - {IMX_TOK_TERM, 0, 0}, -}; - -static struct imx_reg imx208_1296x976_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0305, 0x02}, /* PREPLLCK DIV */ - {IMX_8BIT, 0x0307, 0x54}, /* PLL MPY */ - {IMX_8BIT, 0x303C, 0x3C}, /* PLL oscillation stable wait time */ - {IMX_8BIT, 0x30A4, 0x02}, /* Default */ - {IMX_8BIT, 0x0112, 0x0A}, /* CCP_data_format : RAW 10bit */ - {IMX_8BIT, 0x0113, 0x0A}, /* CCP_data_format : RAW 10bit */ - {IMX_8BIT, 0x0340, 0x04}, /* frame length line [15:8] */ - {IMX_8BIT, 0x0341, 0xAA}, /* frame length line [7:0] */ - {IMX_8BIT, 0x0342, 0x08}, /* line length pck [15:8] */ - {IMX_8BIT, 0x0343, 0xC8}, /* line length pck [7:0] */ - {IMX_8BIT, 0x0344, 0x01}, /* x_addr_start[12:8] */ - {IMX_8BIT, 0x0345, 0x40}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x00}, /* y_addr_start[12:8] */ - {IMX_8BIT, 0x0347, 0x3C}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x06}, /* x_addr_end [12:8] */ - {IMX_8BIT, 0x0349, 0x4F}, /* x_addr_end [7:0] */ - {IMX_8BIT, 0x034A, 0x04}, /* y_addr_end [12:8] */ - {IMX_8BIT, 0x034B, 0x0B}, /* y_addr_end [7:0] */ - {IMX_8BIT, 0x034C, 0x05}, /* x_output_size [ 12:8] */ - {IMX_8BIT, 0x034D, 0x10}, /* x_output_size [7:0] */ - {IMX_8BIT, 0x034E, 0x03}, /* y_output_size [11:8] */ - {IMX_8BIT, 0x034F, 0xD0}, /* y_output_size [7:0] */ - {IMX_8BIT, 0x0381, 0x01}, /* x_even_inc */ - {IMX_8BIT, 0x0383, 0x01}, /* x_odd_inc */ - {IMX_8BIT, 0x0385, 0x01}, /* y_even_inc */ - {IMX_8BIT, 0x0387, 0x01}, /* y_odd_inc */ - {IMX_8BIT, 0x3048, 0x00}, /* VMODEFDS binning operation */ - {IMX_8BIT, 0x304E, 0x0A}, /* VTPXCK_DIV */ - {IMX_8BIT, 0x3050, 0x02}, /* OPSYCK_DIV */ - {IMX_8BIT, 0x309B, 0x00}, /* RGDAFDSUMEN */ - {IMX_8BIT, 0x30D5, 0x00}, /* HADDEN ( binning ) */ - {IMX_8BIT, 0x3301, 0x01}, /* RGLANESEL */ - {IMX_8BIT, 0x3318, 0x61}, /* MIPI Global Timing */ - {IMX_8BIT, 0x0202, 0x01}, /* coarse integration time */ - {IMX_8BIT, 0x0203, 0x90}, /* coarse integration time */ - {IMX_8BIT, 0x0205, 0x00}, /* ana global gain */ - - {IMX_TOK_TERM, 0, 0}, -}; - -static struct imx_reg imx208_336x256_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0305, 0x02}, /* PREPLLCK DIV */ - {IMX_8BIT, 0x0307, 0x54}, /* PLL MPY */ - {IMX_8BIT, 0x303C, 0x3C}, /* PLL oscillation stable wait time */ - {IMX_8BIT, 0x30A4, 0x02}, /* Default */ - {IMX_8BIT, 0x0112, 0x0A}, /* CCP_data_format : RAW 10bit */ - {IMX_8BIT, 0x0113, 0x0A}, /* CCP_data_format : RAW 10bit */ - {IMX_8BIT, 0x0340, 0x04}, /* frame length line [15:8] */ - {IMX_8BIT, 0x0341, 0xAA}, /* frame length line [7:0] */ - {IMX_8BIT, 0x0342, 0x08}, /* line length pck [15:8] */ - {IMX_8BIT, 0x0343, 0xC8}, /* line length pck [7:0] */ - {IMX_8BIT, 0x0344, 0x02}, /* x_addr_start[12:8] */ - {IMX_8BIT, 0x0345, 0x78}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x01}, /* y_addr_start[12:8] */ - {IMX_8BIT, 0x0347, 0x24}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x05}, /* x_addr_end [12:8] */ - {IMX_8BIT, 0x0349, 0x17}, /* x_addr_end [7:0] */ - {IMX_8BIT, 0x034A, 0x03}, /* y_addr_end [12:8] */ - {IMX_8BIT, 0x034B, 0x23}, /* y_addr_end [7:0] */ - {IMX_8BIT, 0x034C, 0x01}, /* x_output_size [ 12:8] */ - {IMX_8BIT, 0x034D, 0x50}, /* x_output_size [7:0] */ - {IMX_8BIT, 0x034E, 0x01}, /* y_output_size [11:8] */ - {IMX_8BIT, 0x034F, 0x00}, /* y_output_size [7:0] */ - {IMX_8BIT, 0x0381, 0x01}, /* x_even_inc */ - {IMX_8BIT, 0x0383, 0x03}, /* x_odd_inc */ - {IMX_8BIT, 0x0385, 0x01}, /* y_even_inc */ - {IMX_8BIT, 0x0387, 0x03}, /* y_odd_inc */ - {IMX_8BIT, 0x3048, 0x01}, /* VMODEFDS binning operation */ - {IMX_8BIT, 0x304E, 0x0A}, /* VTPXCK_DIV */ - {IMX_8BIT, 0x3050, 0x02}, /* OPSYCK_DIV */ - {IMX_8BIT, 0x309B, 0x00}, /* RGDAFDSUMEN */ - {IMX_8BIT, 0x30D5, 0x03}, /* HADDEN ( binning ) */ - {IMX_8BIT, 0x3301, 0x01}, /* RGLANESEL */ - {IMX_8BIT, 0x3318, 0x66}, /* MIPI Global Timing */ - {IMX_8BIT, 0x0202, 0x01}, /* coarse integration time */ - {IMX_8BIT, 0x0203, 0x90}, /* coarse integration time */ - {IMX_8BIT, 0x0205, 0x00}, /* ana global gain */ - - {IMX_TOK_TERM, 0, 0}, -}; - -static struct imx_reg imx208_192x160_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0305, 0x02}, /* PREPLLCK DIV */ - {IMX_8BIT, 0x0307, 0x54}, /* PLL MPY */ - {IMX_8BIT, 0x303C, 0x3C}, /* PLL oscillation stable wait time */ - {IMX_8BIT, 0x30A4, 0x02}, /* Default */ - {IMX_8BIT, 0x0112, 0x0A}, /* CCP_data_format : RAW 10bit */ - {IMX_8BIT, 0x0113, 0x0A}, /* CCP_data_format : RAW 10bit */ - {IMX_8BIT, 0x0340, 0x04}, /* frame length line [15:8] */ - {IMX_8BIT, 0x0341, 0xAA}, /* frame length line [7:0] */ - {IMX_8BIT, 0x0342, 0x08}, /* line length pck [15:8] */ - {IMX_8BIT, 0x0343, 0xC8}, /* line length pck [7:0] */ - {IMX_8BIT, 0x0344, 0x02}, /* x_addr_start[12:8] */ - {IMX_8BIT, 0x0345, 0x48}, /* x_addr_start[7:0] */ - {IMX_8BIT, 0x0346, 0x00}, /* y_addr_start[12:8] */ - {IMX_8BIT, 0x0347, 0xE4}, /* y_addr_start[7:0] */ - {IMX_8BIT, 0x0348, 0x05}, /* x_addr_end [12:8] */ - {IMX_8BIT, 0x0349, 0x47}, /* x_addr_end [7:0] */ - {IMX_8BIT, 0x034A, 0x03}, /* y_addr_end [12:8] */ - {IMX_8BIT, 0x034B, 0x63}, /* y_addr_end [7:0] */ - {IMX_8BIT, 0x034C, 0x00}, /* x_output_size [ 12:8] */ - {IMX_8BIT, 0x034D, 0xC0}, /* x_output_size [7:0] */ - {IMX_8BIT, 0x034E, 0x00}, /* y_output_size [11:8] */ - {IMX_8BIT, 0x034F, 0xA0}, /* y_output_size [7:0] */ - {IMX_8BIT, 0x0381, 0x03}, /* x_even_inc */ - {IMX_8BIT, 0x0383, 0x05}, /* x_odd_inc */ - {IMX_8BIT, 0x0385, 0x03}, /* y_even_inc */ - {IMX_8BIT, 0x0387, 0x05}, /* y_odd_inc */ - {IMX_8BIT, 0x3048, 0x01}, /* VMODEFDS binning operation */ - {IMX_8BIT, 0x304E, 0x0A}, /* VTPXCK_DIV */ - {IMX_8BIT, 0x3050, 0x02}, /* OPSYCK_DIV */ - {IMX_8BIT, 0x309B, 0x00}, /* RGDAFDSUMEN */ - {IMX_8BIT, 0x30D5, 0x03}, /* HADDEN ( binning ) */ - {IMX_8BIT, 0x3301, 0x11}, /* RGLANESEL */ - {IMX_8BIT, 0x3318, 0x74}, /* MIPI Global Timing */ - {IMX_8BIT, 0x0202, 0x01}, /* coarse integration time */ - {IMX_8BIT, 0x0203, 0x90}, /* coarse integration time */ - {IMX_8BIT, 0x0205, 0x00}, /* ana global gain */ - - {IMX_TOK_TERM, 0, 0}, -}; -/********************** settings for imx - reference *********************/ -static struct imx_reg const imx208_init_settings[] = { - { IMX_TOK_TERM, 0, 0} -}; - -struct imx_resolution imx208_res_preview[] = { - { - .desc = "imx208_1080p_30fps", - .regs = imx208_1080p_30fps, - .width = 1936, - .height = 1096, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08C8, - .lines_per_frame = 0x04AA, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - .skip_frames = 2, - .mipi_freq = 403200, - }, - { - .desc = "imx208_1296x976_30fps", - .regs = imx208_1296x976_30fps, - .width = 1296, - .height = 976, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08C8, - .lines_per_frame = 0x04AA, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - .skip_frames = 2, - .mipi_freq = 403200, - }, - { - .desc = "imx208_1296x736_30fps", - .regs = imx208_1296x736_30fps, - .width = 1296, - .height = 736, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08C8, - .lines_per_frame = 0x04AA, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - .skip_frames = 2, - .mipi_freq = 403200, - }, - { - .desc = "imx208_336x256_30fps", - .regs = imx208_336x256_30fps, - .width = 336, - .height = 256, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08C8, - .lines_per_frame = 0x04AA, - }, - { - } - }, - .bin_factor_x = 2, - .bin_factor_y = 2, - .used = 0, - .skip_frames = 2, - .mipi_freq = 201600, - }, - { - .desc = "imx208_192x160_30fps", - .regs = imx208_192x160_30fps, - .width = 192, - .height = 160, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08C8, - .lines_per_frame = 0x04AA, - }, - { - } - }, - .bin_factor_x = 4, - .bin_factor_y = 4, - .used = 0, - .skip_frames = 2, - .mipi_freq = 100800, - }, -}; - -struct imx_resolution imx208_res_still[] = { - { - .desc = "imx208_1080p_30fps", - .regs = imx208_1080p_30fps, - .width = 1936, - .height = 1096, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08C8, - .lines_per_frame = 0x04AA, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - .skip_frames = 2, - .mipi_freq = 403200, - }, - { - .desc = "imx208_1296x976_30fps", - .regs = imx208_1296x976_30fps, - .width = 1296, - .height = 976, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08C8, - .lines_per_frame = 0x04AA, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - .skip_frames = 2, - .mipi_freq = 403200, - }, - { - .desc = "imx208_1296x736_30fps", - .regs = imx208_1296x736_30fps, - .width = 1296, - .height = 736, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08C8, - .lines_per_frame = 0x04AA, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - .skip_frames = 2, - .mipi_freq = 403200, - }, - { - .desc = "imx208_336x256_30fps", - .regs = imx208_336x256_30fps, - .width = 336, - .height = 256, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08C8, - .lines_per_frame = 0x04AA, - }, - { - } - }, - .bin_factor_x = 2, - .bin_factor_y = 2, - .used = 0, - .skip_frames = 2, - .mipi_freq = 201600, - }, - { - .desc = "imx208_192x160_30fps", - .regs = imx208_192x160_30fps, - .width = 192, - .height = 160, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08C8, - .lines_per_frame = 0x04AA, - }, - { - } - }, - .bin_factor_x = 4, - .bin_factor_y = 4, - .used = 0, - .skip_frames = 2, - .mipi_freq = 100800, - }, -}; - -struct imx_resolution imx208_res_video[] = { - { - .desc = "imx208_1080p_30fps", - .regs = imx208_1080p_30fps, - .width = 1936, - .height = 1096, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08C8, - .lines_per_frame = 0x04AA, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - .skip_frames = 2, - .mipi_freq = 403200, - }, - { - .desc = "imx208_1296x976_30fps", - .regs = imx208_1296x976_30fps, - .width = 1296, - .height = 976, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08C8, - .lines_per_frame = 0x04AA, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - .skip_frames = 2, - .mipi_freq = 403200, - }, - { - .desc = "imx208_1296x736_30fps", - .regs = imx208_1296x736_30fps, - .width = 1296, - .height = 736, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08C8, - .lines_per_frame = 0x04AA, - }, - { - } - }, - .bin_factor_x = 1, - .bin_factor_y = 1, - .used = 0, - .skip_frames = 2, - .mipi_freq = 403200, - }, - { - .desc = "imx208_336x256_30fps", - .regs = imx208_336x256_30fps, - .width = 336, - .height = 256, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08C8, - .lines_per_frame = 0x04AA, - }, - { - } - }, - .bin_factor_x = 2, - .bin_factor_y = 2, - .used = 0, - .skip_frames = 2, - .mipi_freq = 201600, - }, - { - .desc = "imx208_192x160_30fps", - .regs = imx208_192x160_30fps, - .width = 192, - .height = 160, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x08C8, - .lines_per_frame = 0x04AA, - }, - { - } - }, - .bin_factor_x = 4, - .bin_factor_y = 4, - .used = 0, - .skip_frames = 2, - .mipi_freq = 100800, - }, -}; -#endif - diff --git a/drivers/staging/media/atomisp/i2c/imx/imx219.h b/drivers/staging/media/atomisp/i2c/imx/imx219.h deleted file mode 100644 index 52df582c56d8..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/imx219.h +++ /dev/null @@ -1,227 +0,0 @@ -#ifndef __IMX219_H__ -#define __IMX219_H__ -#include "common.h" - -#define IMX219_FRAME_LENGTH_LINES 0x0160 -#define IMX219_LINE_LENGTH_PIXELS 0x0162 -#define IMX219_HORIZONTAL_START_H 0x0164 -#define IMX219_VERTICAL_START_H 0x0168 -#define IMX219_HORIZONTAL_END_H 0x0166 -#define IMX219_VERTICAL_END_H 0x016A -#define IMX219_HORIZONTAL_OUTPUT_SIZE_H 0x016c -#define IMX219_VERTICAL_OUTPUT_SIZE_H 0x016E -#define IMX219_COARSE_INTEGRATION_TIME 0x015A -#define IMX219_IMG_ORIENTATION 0x0172 -#define IMX219_GLOBAL_GAIN 0x0157 -#define IMX219_DGC_ADJ 0x0158 - -#define IMX219_DGC_LEN 4 - -/************************** settings for imx *************************/ -static struct imx_reg const imx219_STILL_8M_30fps[] = { - {IMX_8BIT, 0x30EB, 0x05}, /*Access Code for address over 0x3000*/ - {IMX_8BIT, 0x30EB, 0x0C}, /*Access Code for address over 0x3000*/ - {IMX_8BIT, 0x300A, 0xFF}, /*Access Code for address over 0x3000*/ - {IMX_8BIT, 0x300B, 0xFF}, /*Access Code for address over 0x3000*/ - {IMX_8BIT, 0x30EB, 0x05}, /*Access Code for address over 0x3000*/ - {IMX_8BIT, 0x30EB, 0x09}, /*Access Code for address over 0x3000*/ - {IMX_8BIT, 0x0114, 0x03}, /*CSI_LANE_MODE[1:0}*/ - {IMX_8BIT, 0x0128, 0x00}, /*DPHY_CNTRL*/ - {IMX_8BIT, 0x012A, 0x13}, /*EXCK_FREQ[15:8]*/ - {IMX_8BIT, 0x012B, 0x34}, /*EXCK_FREQ[7:0]*/ - {IMX_8BIT, 0x0160, 0x0A}, /*FRM_LENGTH_A[15:8]*/ - {IMX_8BIT, 0x0161, 0x94}, /*FRM_LENGTH_A[7:0]*/ - {IMX_8BIT, 0x0162, 0x0D}, /*LINE_LENGTH_A[15:8]*/ - {IMX_8BIT, 0x0163, 0x78}, /*LINE_LENGTH_A[7:0]*/ - {IMX_8BIT, 0x0164, 0x00}, /*X_ADD_STA_A[11:8]*/ - {IMX_8BIT, 0x0165, 0x00}, /*X_ADD_STA_A[7:0]*/ - {IMX_8BIT, 0x0166, 0x0C}, /*X_ADD_END_A[11:8]*/ - {IMX_8BIT, 0x0167, 0xCF}, /*X_ADD_END_A[7:0]*/ - {IMX_8BIT, 0x0168, 0x00}, /*Y_ADD_STA_A[11:8]*/ - {IMX_8BIT, 0x0169, 0x00}, /*Y_ADD_STA_A[7:0]*/ - {IMX_8BIT, 0x016A, 0x09}, /*Y_ADD_END_A[11:8]*/ - {IMX_8BIT, 0x016B, 0x9F}, /*Y_ADD_END_A[7:0]*/ - {IMX_8BIT, 0x016C, 0x0C}, /*X_OUTPUT_SIZE_A[11:8]*/ - {IMX_8BIT, 0x016D, 0xD0}, /*X_OUTPUT_SIZE_A[7:0]*/ - {IMX_8BIT, 0x016E, 0x09}, /*Y_OUTPUT_SIZE_A[11:8]*/ - {IMX_8BIT, 0x016F, 0xA0}, /*Y_OUTPUT_SIZE_A[7:0]*/ - {IMX_8BIT, 0x0170, 0x01}, /*X_ODD_INC_A[2:0]*/ - {IMX_8BIT, 0x0171, 0x01}, /*Y_ODD_INC_A[2:0]*/ - {IMX_8BIT, 0x0174, 0x00}, /*BINNING_MODE_H_A*/ - {IMX_8BIT, 0x0175, 0x00}, /*BINNING_MODE_V_A*/ - {IMX_8BIT, 0x018C, 0x0A}, /*CSI_DATA_FORMAT_A[15:8]*/ - {IMX_8BIT, 0x018D, 0x0A}, /*CSI_DATA_FORMAT_A[7:0]*/ - {IMX_8BIT, 0x0301, 0x05}, /*VTPXCK_DIV*/ - {IMX_8BIT, 0x0303, 0x01}, /*VTSYCK_DIV*/ - {IMX_8BIT, 0x0304, 0x02}, /*PREPLLCK_VT_DIV[3:0]*/ - {IMX_8BIT, 0x0305, 0x02}, /*PREPLLCK_OP_DIV[3:0]*/ - {IMX_8BIT, 0x0306, 0x00}, /*PLL_VT_MPY[10:8]*/ - {IMX_8BIT, 0x0307, 0x49}, /*PLL_VT_MPY[7:0]*/ - {IMX_8BIT, 0x0309, 0x0A}, /*OPPXCK_DIV[4:0]*/ - {IMX_8BIT, 0x030B, 0x01}, /*OPSYCK_DIV*/ - {IMX_8BIT, 0x030C, 0x00}, /*PLL_OP_MPY[10:8]*/ - {IMX_8BIT, 0x030D, 0x4C}, /*PLL_OP_MPY[7:0]*/ - {IMX_8BIT, 0x4767, 0x0F}, /*CIS Tuning*/ - {IMX_8BIT, 0x4750, 0x14}, /*CIS Tuning*/ - {IMX_8BIT, 0x47B4, 0x14}, /*CIS Tuning*/ - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx219_STILL_6M_30fps[] = { - {IMX_8BIT, 0x30EB, 0x05}, /*Access Code for address over 0x3000*/ - {IMX_8BIT, 0x30EB, 0x0C}, /*Access Code for address over 0x3000*/ - {IMX_8BIT, 0x300A, 0xFF}, /*Access Code for address over 0x3000*/ - {IMX_8BIT, 0x300B, 0xFF}, /*Access Code for address over 0x3000*/ - {IMX_8BIT, 0x30EB, 0x05}, /*Access Code for address over 0x3000*/ - {IMX_8BIT, 0x30EB, 0x09}, /*Access Code for address over 0x3000*/ - {IMX_8BIT, 0x0114, 0x03}, /*CSI_LANE_MODE[1:0}*/ - {IMX_8BIT, 0x0128, 0x00}, /*DPHY_CNTRL*/ - {IMX_8BIT, 0x012A, 0x13}, /*EXCK_FREQ[15:8]*/ - {IMX_8BIT, 0x012B, 0x34}, /*EXCK_FREQ[7:0]*/ - {IMX_8BIT, 0x0160, 0x07}, /*FRM_LENGTH_A[15:8]*/ - {IMX_8BIT, 0x0161, 0x64}, /*FRM_LENGTH_A[7:0]*/ - {IMX_8BIT, 0x0162, 0x0D}, /*LINE_LENGTH_A[15:8]*/ - {IMX_8BIT, 0x0163, 0x78}, /*LINE_LENGTH_A[7:0]*/ - {IMX_8BIT, 0x0164, 0x00}, /*X_ADD_STA_A[11:8]*/ - {IMX_8BIT, 0x0165, 0x00}, /*X_ADD_STA_A[7:0]*/ - {IMX_8BIT, 0x0166, 0x0C}, /*X_ADD_END_A[11:8]*/ - {IMX_8BIT, 0x0167, 0xCF}, /*X_ADD_END_A[7:0]*/ - {IMX_8BIT, 0x0168, 0x01}, /*Y_ADD_STA_A[11:8]*/ - {IMX_8BIT, 0x0169, 0x32}, /*Y_ADD_STA_A[7:0]*/ - {IMX_8BIT, 0x016A, 0x08}, /*Y_ADD_END_A[11:8]*/ - {IMX_8BIT, 0x016B, 0x6D}, /*Y_ADD_END_A[7:0]*/ - {IMX_8BIT, 0x016C, 0x0C}, /*X_OUTPUT_SIZE_A[11:8]*/ - {IMX_8BIT, 0x016D, 0xD0}, /*X_OUTPUT_SIZE_A[7:0]*/ - {IMX_8BIT, 0x016E, 0x07}, /*Y_OUTPUT_SIZE_A[11:8]*/ - {IMX_8BIT, 0x016F, 0x3C}, /*Y_OUTPUT_SIZE_A[7:0]*/ - {IMX_8BIT, 0x0170, 0x01}, /*X_ODD_INC_A[2:0]*/ - {IMX_8BIT, 0x0171, 0x01}, /*Y_ODD_INC_A[2:0]*/ - {IMX_8BIT, 0x0174, 0x00}, /*BINNING_MODE_H_A*/ - {IMX_8BIT, 0x0175, 0x00}, /*BINNING_MODE_V_A*/ - {IMX_8BIT, 0x018C, 0x0A}, /*CSI_DATA_FORMAT_A[15:8]*/ - {IMX_8BIT, 0x018D, 0x0A}, /*CSI_DATA_FORMAT_A[7:0]*/ - {IMX_8BIT, 0x0301, 0x05}, /*VTPXCK_DIV*/ - {IMX_8BIT, 0x0303, 0x01}, /*VTSYCK_DIV*/ - {IMX_8BIT, 0x0304, 0x02}, /*PREPLLCK_VT_DIV[3:0]*/ - {IMX_8BIT, 0x0305, 0x02}, /*PREPLLCK_OP_DIV[3:0]*/ - {IMX_8BIT, 0x0306, 0x00}, /*PLL_VT_MPY[10:8]*/ - {IMX_8BIT, 0x0307, 0x33}, /*PLL_VT_MPY[7:0]*/ - {IMX_8BIT, 0x0309, 0x0A}, /*OPPXCK_DIV[4:0]*/ - {IMX_8BIT, 0x030B, 0x01}, /*OPSYCK_DIV*/ - {IMX_8BIT, 0x030C, 0x00}, /*PLL_OP_MPY[10:8]*/ - {IMX_8BIT, 0x030D, 0x36}, /*PLL_OP_MPY[7:0]*/ - {IMX_8BIT, 0x4767, 0x0F}, /*CIS Tuning*/ - {IMX_8BIT, 0x4750, 0x14}, /*CIS Tuning*/ - {IMX_8BIT, 0x47B4, 0x14}, /*CIS Tuning*/ - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx219_init_settings[] = { - {IMX_TOK_TERM, 0, 0} -}; - -struct imx_resolution imx219_res_preview[] = { - { - .desc = "STILL_6M_30fps", - .regs = imx219_STILL_6M_30fps, - .width = 3280, - .height = 1852, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x0D78, - .lines_per_frame = 0x0764, - }, - { - } - }, - .mipi_freq = 259000, - }, - { - .desc = "STILL_8M_30fps", - .regs = imx219_STILL_8M_30fps, - .width = 3280, - .height = 2464, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x0D78, - .lines_per_frame = 0x0A94, - }, - { - } - }, - .mipi_freq = 365000, - }, -}; - -struct imx_resolution imx219_res_still[] = { - { - .desc = "STILL_6M_30fps", - .regs = imx219_STILL_6M_30fps, - .width = 3280, - .height = 1852, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x0D78, - .lines_per_frame = 0x0764, - }, - { - } - }, - .mipi_freq = 259000, - }, - { - .desc = "STILL_8M_30fps", - .regs = imx219_STILL_8M_30fps, - .width = 3280, - .height = 2464, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x0D78, - .lines_per_frame = 0x0A94, - }, - { - } - }, - .mipi_freq = 365000, - }, -}; - -struct imx_resolution imx219_res_video[] = { - { - .desc = "STILL_6M_30fps", - .regs = imx219_STILL_6M_30fps, - .width = 3280, - .height = 1852, - .bin_factor_x = 0, - .bin_factor_y = 0, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x0D78, - .lines_per_frame = 0x0764, - }, - { - } - }, - .mipi_freq = 259000, - }, -}; - -#endif diff --git a/drivers/staging/media/atomisp/i2c/imx/imx227.h b/drivers/staging/media/atomisp/i2c/imx/imx227.h deleted file mode 100644 index 10e5b86f6687..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/imx227.h +++ /dev/null @@ -1,726 +0,0 @@ -#ifndef __IMX227_H__ -#define __IMX227_H__ - -#include "common.h" - -#define IMX227_EMBEDDED_DATA_LINE_NUM 2 -#define IMX227_OUTPUT_DATA_FORMAT_REG 0x0112 -#define IMX227_OUTPUT_FORMAT_RAW10 0x0a0a - -/* AE Bracketing Registers */ -#define IMX227_BRACKETING_LUT_MODE_BIT_CONTINUE_STREAMING 0x1 -#define IMX227_BRACKETING_LUT_MODE_BIT_LOOP_MODE 0x2 - -#define IMX227_BRACKETING_LUT_CONTROL 0x0E00 -#define IMX227_BRACKETING_LUT_MODE 0x0E01 -#define IMX227_BRACKETING_LUT_ENTRY_CONTROL 0x0E02 - -/* - * The imx135 embedded data info: - * embedded data line num: 2 - * line 0 effective data size(byte): 76 - * line 1 effective data size(byte): 113 - */ -static const uint32_t -imx227_embedded_effective_size[IMX227_EMBEDDED_DATA_LINE_NUM] = {160, 62}; - -/************************** settings for imx *************************/ -/* Full Output Mode */ -static struct imx_reg const imx_STILL_6_5M_25fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x6259, 0x06}, /* latency ctrl */ - {IMX_8BIT, 0x9004, 0xd0}, /* preset_sel */ - {IMX_8BIT, 0x9005, 0x3f}, /* preset_en */ - {IMX_8BIT, 0x0136, 0x13}, - {IMX_8BIT, 0x0137, 0x33}, - {IMX_TOK_TERM, 0, 0} -}; - -/* 4:3 Output Mode */ -static struct imx_reg const imx_STILL_5_5M_3X4_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0344, 0x00}, - {IMX_8BIT, 0x0345, 0xb0}, - {IMX_8BIT, 0x0346, 0x00}, - {IMX_8BIT, 0x0347, 0x00}, - {IMX_8BIT, 0x0348, 0x08}, - {IMX_8BIT, 0x0349, 0xaf}, - {IMX_8BIT, 0x034a, 0x0a}, - {IMX_8BIT, 0x034b, 0x9f}, - {IMX_8BIT, 0x034c, 0x08}, - {IMX_8BIT, 0x034d, 0x00}, - {IMX_8BIT, 0x034e, 0x0a}, - {IMX_8BIT, 0x034f, 0xa0}, - - {IMX_8BIT, 0x6259, 0x05}, /* latency ctrl */ - {IMX_8BIT, 0x9004, 0xd8}, /* preset_sel */ - {IMX_8BIT, 0x9005, 0x3f}, /* preset_en */ - {IMX_8BIT, 0x0136, 0x13}, - {IMX_8BIT, 0x0137, 0x33}, - {IMX_TOK_TERM, 0, 0} -}; - -/* Square Output Mode */ -static struct imx_reg const imx_STILL_5_7M_1X1_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0344, 0x00}, - {IMX_8BIT, 0x0345, 0x00}, - {IMX_8BIT, 0x0346, 0x00}, - {IMX_8BIT, 0x0347, 0xa0}, - {IMX_8BIT, 0x0348, 0x09}, - {IMX_8BIT, 0x0349, 0x5f}, - {IMX_8BIT, 0x034a, 0x09}, - {IMX_8BIT, 0x034b, 0xff}, - {IMX_8BIT, 0x034c, 0x09}, - {IMX_8BIT, 0x034d, 0x60}, - {IMX_8BIT, 0x034e, 0x09}, - {IMX_8BIT, 0x034f, 0x60}, - - {IMX_8BIT, 0x6259, 0x06}, /* latency ctrl */ - {IMX_8BIT, 0x9004, 0xd4}, /* preset_sel */ - {IMX_8BIT, 0x9005, 0x3f}, /* preset_en */ - {IMX_8BIT, 0x0136, 0x13}, - {IMX_8BIT, 0x0137, 0x33}, - {IMX_TOK_TERM, 0, 0} -}; - -/* Full Frame 1080P Mode (use ISP scaler)*/ -static struct imx_reg const imx_VIDEO_4M_9X16_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x6259, 0x05}, /* latency ctrl */ - {IMX_8BIT, 0x9004, 0xdc}, /* preset_sel */ - {IMX_8BIT, 0x9005, 0x3f}, /* preset_en */ - {IMX_8BIT, 0x0136, 0x13}, - {IMX_8BIT, 0x0137, 0x33}, - {IMX_TOK_TERM, 0, 0} -}; - -/* Cropped 1080P Mode */ -static struct imx_reg const imx_VIDEO_2M_9X16_45fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0112, 0x0a}, - {IMX_8BIT, 0x0113, 0x0a}, - {IMX_8BIT, 0x0344, 0x02}, - {IMX_8BIT, 0x0345, 0x8a}, - {IMX_8BIT, 0x0346, 0x01}, - {IMX_8BIT, 0x0347, 0x88}, - {IMX_8BIT, 0x0348, 0x06}, - {IMX_8BIT, 0x0349, 0xd1}, - {IMX_8BIT, 0x034a, 0x09}, - {IMX_8BIT, 0x034b, 0x17}, - {IMX_8BIT, 0x034c, 0x04}, - {IMX_8BIT, 0x034d, 0x48}, - {IMX_8BIT, 0x034e, 0x07}, - {IMX_8BIT, 0x034f, 0x90}, - - {IMX_8BIT, 0x0380, 0x00}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0382, 0x00}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0384, 0x00}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0386, 0x00}, - {IMX_8BIT, 0x0387, 0x01}, - - {IMX_8BIT, 0x0408, 0x00}, - {IMX_8BIT, 0x0409, 0x00}, - {IMX_8BIT, 0x040a, 0x00}, - {IMX_8BIT, 0x040b, 0x00}, - {IMX_8BIT, 0x040c, 0x04}, - {IMX_8BIT, 0x040d, 0x48}, - {IMX_8BIT, 0x040e, 0x07}, - {IMX_8BIT, 0x040f, 0x90}, - - {IMX_8BIT, 0x0900, 0x00}, - {IMX_8BIT, 0x0901, 0x00}, - - {IMX_8BIT, 0x6259, 0x05}, /* latency ctrl */ - {IMX_8BIT, 0x9004, 0xdc}, /* preset_sel */ - {IMX_8BIT, 0x9005, 0x3c}, /* preset_en */ - - {IMX_8BIT, 0x0136, 0x13}, - {IMX_8BIT, 0x0137, 0x33}, - {IMX_TOK_TERM, 0, 0} -}; - -/* Moment mode */ -static struct imx_reg const imx_VIDEO_1_3M_3X4_60fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x6259, 0x05}, /* latency ctrl */ - {IMX_8BIT, 0x9004, 0xd9}, /* preset_sel */ - {IMX_8BIT, 0x9005, 0x3f}, /* preset_en */ - {IMX_8BIT, 0x0136, 0x13}, - {IMX_8BIT, 0x0137, 0x33}, - {IMX_TOK_TERM, 0, 0} -}; - -/* High Speed 3:4 mode */ -static struct imx_reg const imx_VIDEO_VGA_3X4_120fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x9004, 0xca}, /* preset_sel */ - {IMX_8BIT, 0x9005, 0x3f}, /* preset_en */ - {IMX_8BIT, 0x0136, 0x13}, - {IMX_8BIT, 0x0137, 0x33}, - {IMX_TOK_TERM, 0, 0} -}; - - -/* Binned 720P mode */ -static struct imx_reg const imx_VIDEO_1M_9X16_60fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0112, 0x0a}, - {IMX_8BIT, 0x0113, 0x0a}, - {IMX_8BIT, 0x0344, 0x01}, - {IMX_8BIT, 0x0345, 0xd0}, - {IMX_8BIT, 0x0346, 0x00}, - {IMX_8BIT, 0x0347, 0x40}, - {IMX_8BIT, 0x0348, 0x07}, - {IMX_8BIT, 0x0349, 0x8f}, - {IMX_8BIT, 0x034a, 0x0a}, - {IMX_8BIT, 0x034b, 0x5f}, - {IMX_8BIT, 0x034c, 0x02}, - {IMX_8BIT, 0x034d, 0xe0}, - {IMX_8BIT, 0x034e, 0x05}, - {IMX_8BIT, 0x034f, 0x10}, - - {IMX_8BIT, 0x0380, 0x00}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0382, 0x00}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0384, 0x00}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0386, 0x00}, - {IMX_8BIT, 0x0387, 0x01}, - - {IMX_8BIT, 0x0408, 0x00}, - {IMX_8BIT, 0x0409, 0x00}, - {IMX_8BIT, 0x040a, 0x00}, - {IMX_8BIT, 0x040b, 0x00}, - {IMX_8BIT, 0x040c, 0x02}, - {IMX_8BIT, 0x040d, 0xe0}, - {IMX_8BIT, 0x040e, 0x05}, - {IMX_8BIT, 0x040f, 0x10}, - - {IMX_8BIT, 0x0900, 0x01}, - {IMX_8BIT, 0x0901, 0x22}, - - {IMX_8BIT, 0x6259, 0x05}, /* latency ctrl */ - {IMX_8BIT, 0x9004, 0xdd}, /* preset_sel */ - {IMX_8BIT, 0x9005, 0x3c}, /* preset_en */ - {IMX_8BIT, 0x0136, 0x13}, - {IMX_8BIT, 0x0137, 0x33}, - {IMX_TOK_TERM, 0, 0} -}; - -/* Binned 496x868 mode */ -static struct imx_reg const imx_VIDEO_496x868_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0112, 0x0a}, - {IMX_8BIT, 0x0113, 0x0a}, - {IMX_8BIT, 0x0344, 0x02}, - {IMX_8BIT, 0x0345, 0xc0}, - {IMX_8BIT, 0x0346, 0x01}, - {IMX_8BIT, 0x0347, 0xec}, - {IMX_8BIT, 0x0348, 0x06}, - {IMX_8BIT, 0x0349, 0x9f}, - {IMX_8BIT, 0x034a, 0x08}, - {IMX_8BIT, 0x034b, 0xb3}, - {IMX_8BIT, 0x034c, 0x01}, - {IMX_8BIT, 0x034d, 0xf0}, - {IMX_8BIT, 0x034e, 0x03}, - {IMX_8BIT, 0x034f, 0x64}, - - {IMX_8BIT, 0x0380, 0x00}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0382, 0x00}, - {IMX_8BIT, 0x0383, 0x01}, - {IMX_8BIT, 0x0384, 0x00}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0386, 0x00}, - {IMX_8BIT, 0x0387, 0x01}, - - {IMX_8BIT, 0x0408, 0x00}, - {IMX_8BIT, 0x0409, 0x00}, - {IMX_8BIT, 0x040a, 0x00}, - {IMX_8BIT, 0x040b, 0x00}, - {IMX_8BIT, 0x040c, 0x01}, - {IMX_8BIT, 0x040d, 0xf0}, - {IMX_8BIT, 0x040e, 0x03}, - {IMX_8BIT, 0x040f, 0x64}, - - {IMX_8BIT, 0x0900, 0x01}, - {IMX_8BIT, 0x0901, 0x22}, - - {IMX_8BIT, 0x6259, 0x05}, /* latency ctrl */ - {IMX_8BIT, 0x9004, 0xdd}, /* preset_sel */ - {IMX_8BIT, 0x9005, 0x3c}, /* preset_en */ - {IMX_8BIT, 0x0136, 0x13}, - {IMX_8BIT, 0x0137, 0x33}, - {IMX_TOK_TERM, 0, 0} -}; - - -/* Hangout mode */ -static struct imx_reg const imx_PREVIEW_374X652_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0112, 0x0a}, - {IMX_8BIT, 0x0113, 0x0a}, - {IMX_8BIT, 0x0344, 0x01}, - {IMX_8BIT, 0x0345, 0xc0}, - {IMX_8BIT, 0x0346, 0x00}, - {IMX_8BIT, 0x0347, 0x30}, - {IMX_8BIT, 0x0348, 0x07}, - {IMX_8BIT, 0x0349, 0x9f}, - {IMX_8BIT, 0x034a, 0x0a}, - {IMX_8BIT, 0x034b, 0x6f}, - {IMX_8BIT, 0x034c, 0x01}, - {IMX_8BIT, 0x034d, 0x78}, - {IMX_8BIT, 0x034e, 0x02}, - {IMX_8BIT, 0x034f, 0x90}, - - {IMX_8BIT, 0x0380, 0x00}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0382, 0x00}, - {IMX_8BIT, 0x0383, 0x03}, - {IMX_8BIT, 0x0384, 0x00}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0386, 0x00}, - {IMX_8BIT, 0x0387, 0x03}, - - {IMX_8BIT, 0x0408, 0x00}, - {IMX_8BIT, 0x0409, 0x00}, - {IMX_8BIT, 0x040a, 0x00}, - {IMX_8BIT, 0x040b, 0x02}, - {IMX_8BIT, 0x040c, 0x01}, - {IMX_8BIT, 0x040d, 0x76}, - {IMX_8BIT, 0x040e, 0x02}, - {IMX_8BIT, 0x040f, 0x8c}, - - {IMX_8BIT, 0x0900, 0x01}, - {IMX_8BIT, 0x0901, 0x22}, - - {IMX_8BIT, 0x6259, 0x05}, /* latency ctrl */ - {IMX_8BIT, 0x9004, 0xde}, /* preset_sel */ - {IMX_8BIT, 0x9005, 0x3c}, /* preset_en */ - {IMX_8BIT, 0x0136, 0x13}, - {IMX_8BIT, 0x0137, 0x33}, - {IMX_TOK_TERM, 0, 0} -}; - -static struct imx_reg const imx_VIDEO_NHD_9X16_30fps[] = { - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0112, 0x0a}, - {IMX_8BIT, 0x0113, 0x0a}, - {IMX_8BIT, 0x0344, 0x01}, - {IMX_8BIT, 0x0345, 0xc0}, - {IMX_8BIT, 0x0346, 0x00}, - {IMX_8BIT, 0x0347, 0x30}, - {IMX_8BIT, 0x0348, 0x07}, - {IMX_8BIT, 0x0349, 0x9f}, - {IMX_8BIT, 0x034a, 0x0a}, - {IMX_8BIT, 0x034b, 0x6f}, - {IMX_8BIT, 0x034c, 0x01}, - {IMX_8BIT, 0x034d, 0x78}, - {IMX_8BIT, 0x034e, 0x02}, - {IMX_8BIT, 0x034f, 0x90}, - - {IMX_8BIT, 0x0380, 0x00}, - {IMX_8BIT, 0x0381, 0x01}, - {IMX_8BIT, 0x0382, 0x00}, - {IMX_8BIT, 0x0383, 0x03}, - {IMX_8BIT, 0x0384, 0x00}, - {IMX_8BIT, 0x0385, 0x01}, - {IMX_8BIT, 0x0386, 0x00}, - {IMX_8BIT, 0x0387, 0x03}, - - {IMX_8BIT, 0x0408, 0x00}, - {IMX_8BIT, 0x0409, 0x00}, - {IMX_8BIT, 0x040a, 0x00}, - {IMX_8BIT, 0x040b, 0x00}, - {IMX_8BIT, 0x040c, 0x01}, - {IMX_8BIT, 0x040d, 0x78}, - {IMX_8BIT, 0x040e, 0x02}, - {IMX_8BIT, 0x040f, 0x90}, - - {IMX_8BIT, 0x0900, 0x01}, - {IMX_8BIT, 0x0901, 0x22}, - - {IMX_8BIT, 0x6259, 0x05}, /* latency ctrl */ - {IMX_8BIT, 0x9004, 0xde}, /* preset_sel */ - {IMX_8BIT, 0x9005, 0x3c}, /* preset_en */ - {IMX_8BIT, 0x0136, 0x13}, - {IMX_8BIT, 0x0137, 0x33}, - {IMX_TOK_TERM, 0, 0} -}; - - -static struct imx_reg const imx227_init_settings[] = { - {IMX_8BIT, 0x0100, 0x00}, /* mode_select */ - GROUPED_PARAMETER_HOLD_ENABLE, - {IMX_8BIT, 0x0306, 0x00}, - {IMX_8BIT, 0x0307, 0xBB}, - {IMX_8BIT, 0x030E, 0x03}, - {IMX_8BIT, 0x030F, 0x0D}, - {IMX_8BIT, 0x463b, 0x30}, - {IMX_8BIT, 0x463e, 0x05}, - {IMX_8BIT, 0x4612, 0x66}, - {IMX_8BIT, 0x4815, 0x65}, - {IMX_8BIT, 0x4991, 0x00}, - {IMX_8BIT, 0x4992, 0x01}, - {IMX_8BIT, 0x4993, 0xff}, - {IMX_8BIT, 0x458b, 0x00}, - {IMX_8BIT, 0x452a, 0x02}, - {IMX_8BIT, 0x4a7c, 0x00}, - {IMX_8BIT, 0x4a7d, 0x1c}, - {IMX_8BIT, 0x4a7e, 0x00}, - {IMX_8BIT, 0x4a7f, 0x17}, - {IMX_8BIT, 0x462C, 0x2E}, - {IMX_8BIT, 0x461B, 0x28}, - {IMX_8BIT, 0x4663, 0x29}, - {IMX_8BIT, 0x461A, 0x7C}, - {IMX_8BIT, 0x4619, 0x28}, - {IMX_8BIT, 0x4667, 0x22}, - {IMX_8BIT, 0x466B, 0x23}, - {IMX_8BIT, 0x40AD, 0xFF}, - {IMX_8BIT, 0x40BE, 0x00}, - {IMX_8BIT, 0x40BF, 0x6E}, - {IMX_8BIT, 0x40CE, 0x00}, - {IMX_8BIT, 0x40CF, 0x0A}, - {IMX_8BIT, 0x40CA, 0x00}, - {IMX_8BIT, 0x40CB, 0x1F}, - {IMX_8BIT, 0x4D16, 0x00}, - {IMX_8BIT, 0x6204, 0x01}, - {IMX_8BIT, 0x6209, 0x00}, - {IMX_8BIT, 0x621F, 0x01}, - {IMX_8BIT, 0x621E, 0x10}, - GROUPED_PARAMETER_HOLD_DISABLE, - {IMX_TOK_TERM, 0, 0} -}; - -/* TODO settings of preview/still/video will be updated with new use case */ -struct imx_resolution imx227_res_preview[] = { - { - .desc = "imx_PREVIEW_374X652_30fps", - .regs = imx_PREVIEW_374X652_30fps, - .width = 374, - .height = 652, - .bin_factor_x = 2, - .bin_factor_y = 2, - .mipi_freq = 499000, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x0E70, - .lines_per_frame = 0x0C0A, - }, - { - } - }, - }, - { - .desc = "imx_VIDEO_496x868_30fps", - .regs = imx_VIDEO_496x868_30fps, - .width = 496, - .height = 868, - .bin_factor_x = 1, - .bin_factor_y = 1, - .mipi_freq = 499000, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x0E70, - .lines_per_frame = 0x0C08, - }, - { - } - }, - }, - { - .desc = "imx_STILL_5_5M_3X4_30fps", - .regs = imx_STILL_5_5M_3X4_30fps, - .width = 2048, - .height = 2720, - .bin_factor_x = 0, - .bin_factor_y = 0, - .mipi_freq = 499000, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x0ED8, - .lines_per_frame = 0x0BB8, - }, - { - } - }, - - }, - { - .desc = "imx_STILL_5_7M_1X1_30fps", - .regs = imx_STILL_5_7M_1X1_30fps, - .width = 2400, - .height = 2400, - .bin_factor_x = 0, - .bin_factor_y = 0, - .mipi_freq = 499000, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x1130, - .lines_per_frame = 0x0A1E, - }, - { - } - }, - - }, - { - .desc = "imx_STILL_6_5M_25fps", - .regs = imx_STILL_6_5M_25fps, - .width = 2400, - .height = 2720, - .bin_factor_x = 0, - .bin_factor_y = 0, - .mipi_freq = 499000, - .used = 0, - .fps_options = { - { - .fps = 25, - .pixels_per_line = 0x1130, - .lines_per_frame = 0x0C24, - }, - { - } - }, - } -}; - -struct imx_resolution imx227_res_still[] = { - { - .desc = "imx_STILL_5_5M_3X4_30fps", - .regs = imx_STILL_5_5M_3X4_30fps, - .width = 2048, - .height = 2720, - .bin_factor_x = 0, - .bin_factor_y = 0, - .mipi_freq = 499000, - .used = 0, - .fps_options = { - { - .fps = 6, - .pixels_per_line = 0x2130, - .lines_per_frame = 0x1A22, - }, - { - .fps = 30, - .pixels_per_line = 0x0ED8, - .lines_per_frame = 0x0BB8, - }, - { - } - }, - - }, - { - .desc = "imx_STILL_5_7M_1X1_30fps", - .regs = imx_STILL_5_7M_1X1_30fps, - .width = 2400, - .height = 2400, - .bin_factor_x = 0, - .bin_factor_y = 0, - .mipi_freq = 499000, - .used = 0, - .fps_options = { - { - .fps = 6, - .pixels_per_line = 0x266E, - .lines_per_frame = 0x1704, - }, - { - .fps = 30, - .pixels_per_line = 0x1130, - .lines_per_frame = 0x0A1E, - }, - { - } - }, - - }, - { - .desc = "imx_STILL_6_5M_25fps", - .regs = imx_STILL_6_5M_25fps, - .width = 2400, - .height = 2720, - .bin_factor_x = 0, - .bin_factor_y = 0, - .mipi_freq = 499000, - .used = 0, - .fps_options = { - { - .fps = 25, - .pixels_per_line = 0x1130, - .lines_per_frame = 0x0C24, - }, - { - } - }, - }, -}; - -struct imx_resolution imx227_res_video[] = { - { - .desc = "imx_VIDEO_4M_9X16_30fps", - .regs = imx_VIDEO_4M_9X16_30fps, - .width = 1536, - .height = 2720, - .bin_factor_x = 0, - .bin_factor_y = 0, - .mipi_freq = 499000, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x0E70, - .lines_per_frame = 0x0C08, - }, - { - } - }, - - }, - { - .desc = "imx_VIDEO_2M_9X16_45fps", - .regs = imx_VIDEO_2M_9X16_45fps, - .width = 1096, - .height = 1936, - .bin_factor_x = 0, - .bin_factor_y = 0, - .mipi_freq = 499000, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x0E70, - .lines_per_frame = 0x0C08, - }, - { - .fps = 45, - .pixels_per_line = 0x0E70, - .lines_per_frame = 0x0800, - }, - { - } - }, - - }, - { - .desc = "imx_VIDEO_1_3M_3X4_60fps", - .regs = imx_VIDEO_1_3M_3X4_60fps, - .width = 1024, - .height = 1360, - .bin_factor_x = 1, - .bin_factor_y = 1, - .mipi_freq = 499000, - .used = 0, - .fps_options = { - { - .fps = 60, - .pixels_per_line = 0x0E70, - .lines_per_frame = 0x0604, - }, - { - } - }, - }, - { - .desc = "imx_VIDEO_496x868_30fps", - .regs = imx_VIDEO_496x868_30fps, - .width = 496, - .height = 868, - .bin_factor_x = 1, - .bin_factor_y = 1, - .mipi_freq = 499000, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x0E70, - .lines_per_frame = 0x0C08, - }, - { - } - }, - }, - { - .desc = "imx_VIDEO_1M_9X16_60fps", - .regs = imx_VIDEO_1M_9X16_60fps, - .width = 736, - .height = 1296, - .bin_factor_x = 1, - .bin_factor_y = 1, - .mipi_freq = 499000, - .used = 0, - .fps_options = { - { - .fps = 60, - .pixels_per_line = 0x0E70, - .lines_per_frame = 0x0604, - }, - { - .fps = 30, - .pixels_per_line = 0x0E70, - .lines_per_frame = 0x0C10, - }, - { - } - }, - }, - { - .desc = "imx_VIDEO_VGA_3X4_120fps", - .regs = imx_VIDEO_VGA_3X4_120fps, - .width = 512, - .height = 680, - .bin_factor_x = 2, - .bin_factor_y = 2, - .mipi_freq = 499000, - .used = 0, - .fps_options = { - { - .fps = 120, - .pixels_per_line = 0x0E70, - .lines_per_frame = 0x0302, - }, - { - .fps = 30, - .pixels_per_line = 0x0E70, - .lines_per_frame = 0x0C08, - }, - { - } - }, - }, - { - .desc = "imx_VIDEO_NHD_9X16_30fps", - .regs = imx_VIDEO_NHD_9X16_30fps, - .width = 376, - .height = 656, - .bin_factor_x = 2, - .bin_factor_y = 2, - .mipi_freq = 499000, - .used = 0, - .fps_options = { - { - .fps = 30, - .pixels_per_line = 0x0E70, - .lines_per_frame = 0x0C0A, - }, - { - } - }, - }, -}; - -#endif /* __IMX227_H__ */ diff --git a/drivers/staging/media/atomisp/i2c/imx/otp.c b/drivers/staging/media/atomisp/i2c/imx/otp.c deleted file mode 100644 index 462275038046..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/otp.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include - -void *dummy_otp_read(struct v4l2_subdev *sd, u8 dev_addr, - u32 start_addr, u32 size) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 *buf; - - buf = devm_kzalloc(&client->dev, size, GFP_KERNEL); - if (!buf) - return ERR_PTR(-ENOMEM); - - return buf; -} diff --git a/drivers/staging/media/atomisp/i2c/imx/otp_brcc064_e2prom.c b/drivers/staging/media/atomisp/i2c/imx/otp_brcc064_e2prom.c deleted file mode 100644 index b11f90c5960c..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/otp_brcc064_e2prom.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "common.h" - -/* - * Read EEPROM data from brcc064 and store - * it into a kmalloced buffer. On error return NULL. - * @size: set to the size of the returned EEPROM data. - */ -void *brcc064_otp_read(struct v4l2_subdev *sd, u8 dev_addr, - u32 start_addr, u32 size) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - unsigned int e2prom_i2c_addr = dev_addr >> 1; - static const unsigned int max_read_size = 30; - int addr; - u32 s_addr = start_addr & E2PROM_ADDR_MASK; - unsigned char *buffer; - - buffer = devm_kzalloc(&client->dev, size, GFP_KERNEL); - if (!buffer) - return NULL; - - for (addr = s_addr; addr < size; addr += max_read_size) { - struct i2c_msg msg[2]; - unsigned int i2c_addr = e2prom_i2c_addr; - u16 addr_buf; - int r; - - msg[0].flags = 0; - msg[0].addr = i2c_addr; - addr_buf = cpu_to_be16(addr & 0xFFFF); - msg[0].len = 2; - msg[0].buf = (u8 *)&addr_buf; - - msg[1].addr = i2c_addr; - msg[1].flags = I2C_M_RD; - msg[1].len = min(max_read_size, size - addr); - msg[1].buf = &buffer[addr]; - - r = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); - if (r != ARRAY_SIZE(msg)) { - dev_err(&client->dev, "read failed at 0x%03x\n", addr); - return NULL; - } - } - return buffer; - -} - - diff --git a/drivers/staging/media/atomisp/i2c/imx/otp_e2prom.c b/drivers/staging/media/atomisp/i2c/imx/otp_e2prom.c deleted file mode 100644 index 73d041f97811..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/otp_e2prom.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "common.h" - -/* - * Read EEPROM data from the gerneral e2prom chip(eg. - * CAT24C08, CAT24C128, le24l042cs, and store - * it into a kmalloced buffer. On error return NULL. - * @size: set to the size of the returned EEPROM data. - */ -void *e2prom_otp_read(struct v4l2_subdev *sd, u8 dev_addr, - u32 start_addr, u32 size) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - unsigned int e2prom_i2c_addr = dev_addr >> 1; - static const unsigned int max_read_size = 30; - int addr; - u32 s_addr = start_addr & E2PROM_ADDR_MASK; - bool two_addr = (start_addr & E2PROM_2ADDR) >> 31; - char *buffer; - - buffer = devm_kzalloc(&client->dev, size, GFP_KERNEL); - if (!buffer) - return NULL; - - for (addr = s_addr; addr < size; addr += max_read_size) { - struct i2c_msg msg[2]; - unsigned int i2c_addr = e2prom_i2c_addr; - u16 addr_buf; - int r; - - msg[0].flags = 0; - if (two_addr) { - msg[0].addr = i2c_addr; - addr_buf = cpu_to_be16(addr & 0xFFFF); - msg[0].len = 2; - msg[0].buf = (u8 *)&addr_buf; - } else { - i2c_addr |= (addr >> 8) & 0x7; - msg[0].addr = i2c_addr; - addr_buf = addr & 0xFF; - msg[0].len = 1; - msg[0].buf = (u8 *)&addr_buf; - } - - msg[1].addr = i2c_addr; - msg[1].flags = I2C_M_RD; - msg[1].len = min(max_read_size, size - addr); - msg[1].buf = &buffer[addr]; - - r = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); - if (r != ARRAY_SIZE(msg)) { - dev_err(&client->dev, "read failed at 0x%03x\n", addr); - return NULL; - } - } - return buffer; -} - - diff --git a/drivers/staging/media/atomisp/i2c/imx/otp_imx.c b/drivers/staging/media/atomisp/i2c/imx/otp_imx.c deleted file mode 100644 index 279784cab6c3..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/otp_imx.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "common.h" - -/* Defines for OTP Data Registers */ -#define IMX_OTP_START_ADDR 0x3B04 -#define IMX_OTP_PAGE_SIZE 64 -#define IMX_OTP_READY_REG 0x3B01 -#define IMX_OTP_PAGE_REG 0x3B02 -#define IMX_OTP_MODE_REG 0x3B00 -#define IMX_OTP_PAGE_MAX 20 -#define IMX_OTP_READY_REG_DONE 1 -#define IMX_OTP_READ_ONETIME 32 -#define IMX_OTP_MODE_READ 1 -#define IMX227_OTP_START_ADDR 0x0A04 -#define IMX227_OTP_ENABLE_REG 0x0A00 -#define IMX227_OTP_READY_REG 0x0A01 -#define IMX227_OTP_PAGE_REG 0x0A02 -#define IMX227_OTP_READY_REG_DONE 1 -#define IMX227_OTP_MODE_READ 1 - -static int -imx_read_otp_data(struct i2c_client *client, u16 len, u16 reg, void *val) -{ - struct i2c_msg msg[2]; - u16 data[IMX_SHORT_MAX] = { 0 }; - int err; - - if (len > IMX_BYTE_MAX) { - dev_err(&client->dev, "%s error, invalid data length\n", - __func__); - return -EINVAL; - } - - memset(msg, 0 , sizeof(msg)); - memset(data, 0 , sizeof(data)); - - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = I2C_MSG_LENGTH; - msg[0].buf = (u8 *)data; - /* high byte goes first */ - data[0] = cpu_to_be16(reg); - - msg[1].addr = client->addr; - msg[1].len = len; - msg[1].flags = I2C_M_RD; - msg[1].buf = (u8 *)data; - - err = i2c_transfer(client->adapter, msg, 2); - if (err != 2) { - if (err >= 0) - err = -EIO; - goto error; - } - - memcpy(val, data, len); - return 0; - -error: - dev_err(&client->dev, "read from offset 0x%x error %d", reg, err); - return err; -} - -static int imx_read_otp_reg_array(struct i2c_client *client, u16 size, u16 addr, - u8 *buf) -{ - u16 index; - int ret; - - for (index = 0; index + IMX_OTP_READ_ONETIME <= size; - index += IMX_OTP_READ_ONETIME) { - ret = imx_read_otp_data(client, IMX_OTP_READ_ONETIME, - addr + index, &buf[index]); - if (ret) - return ret; - } - return 0; -} - -void *imx_otp_read(struct v4l2_subdev *sd, u8 dev_addr, - u32 start_addr, u32 size) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 *buf; - int ret; - int i; - - buf = devm_kzalloc(&client->dev, size, GFP_KERNEL); - if (!buf) - return ERR_PTR(-ENOMEM); - - for (i = 0; i < IMX_OTP_PAGE_MAX; i++) { - - /*set page NO.*/ - ret = imx_write_reg(client, IMX_8BIT, - IMX_OTP_PAGE_REG, i & 0xff); - if (ret) - goto fail; - - /*set read mode*/ - ret = imx_write_reg(client, IMX_8BIT, - IMX_OTP_MODE_REG, IMX_OTP_MODE_READ); - if (ret) - goto fail; - - /* Reading the OTP data array */ - ret = imx_read_otp_reg_array(client, IMX_OTP_PAGE_SIZE, - IMX_OTP_START_ADDR, buf + i * IMX_OTP_PAGE_SIZE); - if (ret) - goto fail; - } - - return buf; -fail: - /* Driver has failed to find valid data */ - dev_err(&client->dev, "sensor found no valid OTP data\n"); - return ERR_PTR(ret); -} - -void *imx227_otp_read(struct v4l2_subdev *sd, u8 dev_addr, - u32 start_addr, u32 size) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 *buf; - int ret; - int i; - - buf = devm_kzalloc(&client->dev, size, GFP_KERNEL); - if (!buf) - return ERR_PTR(-ENOMEM); - - for (i = 0; i < IMX_OTP_PAGE_MAX; i++) { - - /*set page NO.*/ - ret = imx_write_reg(client, IMX_8BIT, - IMX227_OTP_PAGE_REG, i & 0xff); - if (ret) - goto fail; - - /*set read mode*/ - ret = imx_write_reg(client, IMX_8BIT, - IMX227_OTP_ENABLE_REG, IMX227_OTP_MODE_READ); - if (ret) - goto fail; - - /* Reading the OTP data array */ - ret = imx_read_otp_reg_array(client, IMX_OTP_PAGE_SIZE, - IMX227_OTP_START_ADDR, buf + i * IMX_OTP_PAGE_SIZE); - if (ret) - goto fail; - } - - return buf; -fail: - /* Driver has failed to find valid data */ - dev_err(&client->dev, "sensor found no valid OTP data\n"); - return ERR_PTR(ret); -} - diff --git a/drivers/staging/media/atomisp/i2c/imx/vcm.c b/drivers/staging/media/atomisp/i2c/imx/vcm.c deleted file mode 100644 index 2d2df04c800a..000000000000 --- a/drivers/staging/media/atomisp/i2c/imx/vcm.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2012 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ -#include -#include -#include -#include -#include "../../include/linux/atomisp_platform.h" - -int vcm_power_up(struct v4l2_subdev *sd) -{ - const struct camera_af_platform_data *vcm_platform_data; - - vcm_platform_data = camera_get_af_platform_data(); - if (NULL == vcm_platform_data) - return -ENODEV; - /* Enable power */ - return vcm_platform_data->power_ctrl(sd, 1); -} - -int vcm_power_down(struct v4l2_subdev *sd) -{ - const struct camera_af_platform_data *vcm_platform_data; - - vcm_platform_data = camera_get_af_platform_data(); - if (NULL == vcm_platform_data) - return -ENODEV; - return vcm_platform_data->power_ctrl(sd, 0); -} - -- cgit v1.2.3 From d4870725b99a622e6d05ef62b6a648a3e28adfc3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 27 Sep 2017 14:24:57 -0400 Subject: media: staging: atomisp: Remove AP1302 sensor support This sensor is not used by any known ACPI-enabled platform (and no kernel users for it so far). Just remove it for good until we get a platform which actually uses it. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/Kconfig | 12 - drivers/staging/media/atomisp/i2c/Makefile | 2 - drivers/staging/media/atomisp/i2c/ap1302.h | 198 ---- drivers/staging/media/atomisp/i2c/atomisp-ap1302.c | 1253 -------------------- 4 files changed, 1465 deletions(-) delete mode 100644 drivers/staging/media/atomisp/i2c/ap1302.h delete mode 100644 drivers/staging/media/atomisp/i2c/atomisp-ap1302.c diff --git a/drivers/staging/media/atomisp/i2c/Kconfig b/drivers/staging/media/atomisp/i2c/Kconfig index 1273c3beb1ec..7aa5d77b5def 100644 --- a/drivers/staging/media/atomisp/i2c/Kconfig +++ b/drivers/staging/media/atomisp/i2c/Kconfig @@ -58,18 +58,6 @@ config VIDEO_ATOMISP_MT9M114 It currently only works with the atomisp driver. -config VIDEO_ATOMISP_AP1302 - tristate "AP1302 external ISP support" - depends on I2C && VIDEO_V4L2 - select REGMAP_I2C - ---help--- - This is a Video4Linux2 sensor-level driver for the external - ISP AP1302. - - AP1302 is an exteral ISP. - - It currently only works with the atomisp driver. - config VIDEO_ATOMISP_GC0310 tristate "GC0310 sensor support" depends on I2C && VIDEO_V4L2 diff --git a/drivers/staging/media/atomisp/i2c/Makefile b/drivers/staging/media/atomisp/i2c/Makefile index ae19c691a73f..ae43dc84c229 100644 --- a/drivers/staging/media/atomisp/i2c/Makefile +++ b/drivers/staging/media/atomisp/i2c/Makefile @@ -11,8 +11,6 @@ obj-$(CONFIG_VIDEO_ATOMISP_GC0310) += atomisp-gc0310.o obj-$(CONFIG_VIDEO_ATOMISP_MSRLIST_HELPER) += atomisp-libmsrlisthelper.o -obj-$(CONFIG_VIDEO_ATOMISP_AP1302) += atomisp-ap1302.o - # Makefile for flash drivers # diff --git a/drivers/staging/media/atomisp/i2c/ap1302.h b/drivers/staging/media/atomisp/i2c/ap1302.h deleted file mode 100644 index 4d0b181a9671..000000000000 --- a/drivers/staging/media/atomisp/i2c/ap1302.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - * - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#ifndef __AP1302_H__ -#define __AP1302_H__ - -#include "../include/linux/atomisp_platform.h" -#include -#include -#include -#include - -#define AP1302_NAME "ap1302" -#define AP1302_CHIP_ID 0x265 -#define AP1302_I2C_MAX_LEN 65534 -#define AP1302_FW_WINDOW_OFFSET 0x8000 -#define AP1302_FW_WINDOW_SIZE 0x2000 - -#define AP1302_REG16 2 -#define AP1302_REG32 4 - -#define REG_CHIP_VERSION 0x0000 -#define REG_CHIP_REV 0x0050 -#define REG_MF_ID 0x0004 -#define REG_ERROR 0x0006 -#define REG_CTRL 0x1000 -#define REG_DZ_TGT_FCT 0x1010 -#define REG_SFX_MODE 0x1016 -#define REG_SS_HEAD_PT0 0x1174 -#define REG_AE_BV_OFF 0x5014 -#define REG_AE_BV_BIAS 0x5016 -#define REG_AWB_CTRL 0x5100 -#define REG_FLICK_CTRL 0x5440 -#define REG_SCENE_CTRL 0x5454 -#define REG_BOOTDATA_STAGE 0x6002 -#define REG_SENSOR_SELECT 0x600C -#define REG_SYS_START 0x601A -#define REG_SIP_CRC 0xF052 - -#define REG_PREVIEW_BASE 0x2000 -#define REG_SNAPSHOT_BASE 0x3000 -#define REG_VIDEO_BASE 0x4000 -#define CNTX_WIDTH 0x00 -#define CNTX_HEIGHT 0x02 -#define CNTX_ROI_X0 0x04 -#define CNTX_ROI_Y0 0x06 -#define CNTX_ROI_X1 0x08 -#define CNTX_ROI_Y1 0x0A -#define CNTX_ASPECT 0x0C -#define CNTX_LOCK 0x0E -#define CNTX_ENABLE 0x10 -#define CNTX_OUT_FMT 0x12 -#define CNTX_SENSOR_MODE 0x14 -#define CNTX_MIPI_CTRL 0x16 -#define CNTX_MIPI_II_CTRL 0x18 -#define CNTX_LINE_TIME 0x1C -#define CNTX_MAX_FPS 0x20 -#define CNTX_AE_USG 0x22 -#define CNTX_AE_UPPER_ET 0x24 -#define CNTX_AE_MAX_ET 0x28 -#define CNTX_SS 0x2C -#define CNTX_S1_SENSOR_MODE 0x2E -#define CNTX_HINF_CTRL 0x30 - -#define CTRL_CNTX_MASK 0x03 -#define CTRL_CNTX_OFFSET 0x00 -#define HINF_CTRL_LANE_MASK 0x07 -#define HINF_CTRL_LANE_OFFSET 0x00 -#define MIPI_CTRL_IMGVC_MASK 0xC0 -#define MIPI_CTRL_IMGVC_OFFSET 0x06 -#define MIPI_CTRL_IMGTYPE_AUTO 0x3F -#define MIPI_CTRL_SSVC_MASK 0xC000 -#define MIPI_CTRL_SSVC_OFFSET 0x0E -#define MIPI_CTRL_SSTYPE_MASK 0x3F00 -#define MIPI_CTRL_SSTYPE_OFFSET 0x08 -#define OUT_FMT_IIS_MASK 0x30 -#define OUT_FMT_IIS_OFFSET 0x08 -#define OUT_FMT_SS_MASK 0x1000 -#define OUT_FMT_SS_OFFSET 0x12 -#define OUT_FMT_TYPE_MASK 0xFF -#define SENSOR_SELECT_MASK 0x03 -#define SENSOR_SELECT_OFFSET 0x00 -#define AWB_CTRL_MODE_MASK 0x0F -#define AWB_CTRL_MODE_OFFSET 0x00 -#define AWB_CTRL_FLASH_MASK 0x100 - -#define AP1302_FMT_UYVY422 0x50 - -#define AP1302_SYS_ACTIVATE 0x8010 -#define AP1302_SYS_SWITCH 0x8140 -#define AP1302_SENSOR_PRI 0x01 -#define AP1302_SENSOR_SEC 0x02 -#define AP1302_SS_CTRL 0x31 - -#define AP1302_MAX_RATIO_MISMATCH 10 /* Unit in percentage */ -#define AP1302_MAX_EV 2 -#define AP1302_MIN_EV -2 - -enum ap1302_contexts { - CONTEXT_PREVIEW = 0, - CONTEXT_SNAPSHOT, - CONTEXT_VIDEO, - CONTEXT_NUM -}; - -/* The context registers are defined according to preview/video registers. - Preview and video context have the same register definition. - But snapshot context does not have register S1_SENSOR_MODE. - When setting snapshot registers, if the offset exceeds - S1_SENSOR_MODE, the actual offset needs to minus 2. */ -struct ap1302_context_config { - u16 width; - u16 height; - u16 roi_x0; - u16 roi_y0; - u16 roi_x1; - u16 roi_y1; - u16 aspect_factor; - u16 lock; - u16 enable; - u16 out_fmt; - u16 sensor_mode; - u16 mipi_ctrl; - u16 mipi_ii_ctrl; - u16 padding; - u32 line_time; - u16 max_fps; - u16 ae_usg; - u32 ae_upper_et; - u32 ae_max_et; - u16 ss; - u16 s1_sensor_mode; - u16 hinf_ctrl; - u32 reserved; -}; - -struct ap1302_res_struct { - u16 width; - u16 height; - u16 fps; -}; - -struct ap1302_context_res { - u32 res_num; - u32 cur_res; - struct ap1302_res_struct *res_table; -}; - -struct ap1302_device { - struct v4l2_subdev sd; - struct media_pad pad; - struct camera_sensor_platform_data *platform_data; - const struct firmware *fw; - struct mutex input_lock; /* serialize sensor's ioctl */ - struct v4l2_mbus_framefmt format; - struct v4l2_ctrl_handler ctrl_handler; - struct v4l2_ctrl *run_mode; - struct ap1302_context_config cntx_config[CONTEXT_NUM]; - struct ap1302_context_res cntx_res[CONTEXT_NUM]; - enum ap1302_contexts cur_context; - unsigned int num_lanes; - struct regmap *regmap16; - struct regmap *regmap32; - bool sys_activated; - bool power_on; -}; - -struct ap1302_firmware { - u32 crc; - u32 pll_init_size; - u32 total_size; - u32 reserved; -}; - -struct ap1302_context_info { - u16 offset; - u16 len; - char *name; -}; - -#endif diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ap1302.c b/drivers/staging/media/atomisp/i2c/atomisp-ap1302.c deleted file mode 100644 index bfbf85122c3b..000000000000 --- a/drivers/staging/media/atomisp/i2c/atomisp-ap1302.c +++ /dev/null @@ -1,1253 +0,0 @@ -/* - * - * Copyright (c) 2013 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include "../include/linux/atomisp.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ap1302.h" - -#define to_ap1302_device(sub_dev) \ - container_of(sub_dev, struct ap1302_device, sd) - -/* Static definitions */ -static struct regmap_config ap1302_reg16_config = { - .reg_bits = 16, - .val_bits = 16, - .reg_format_endian = REGMAP_ENDIAN_BIG, - .val_format_endian = REGMAP_ENDIAN_BIG, -}; - -static struct regmap_config ap1302_reg32_config = { - .reg_bits = 16, - .val_bits = 32, - .reg_format_endian = REGMAP_ENDIAN_BIG, - .val_format_endian = REGMAP_ENDIAN_BIG, -}; - -static enum ap1302_contexts ap1302_cntx_mapping[] = { - CONTEXT_PREVIEW, /* Invalid atomisp run mode */ - CONTEXT_VIDEO, /* ATOMISP_RUN_MODE_VIDEO */ - CONTEXT_SNAPSHOT, /* ATOMISP_RUN_MODE_STILL_CAPTURE */ - CONTEXT_SNAPSHOT, /* ATOMISP_RUN_MODE_CONTINUOUS_CAPTURE */ - CONTEXT_PREVIEW, /* ATOMISP_RUN_MODE_PREVIEW */ -}; - -static struct ap1302_res_struct ap1302_preview_res[] = { - { - .width = 640, - .height = 480, - .fps = 30, - }, - { - .width = 720, - .height = 480, - .fps = 30, - }, - { - .width = 1280, - .height = 720, - .fps = 30, - }, - { - .width = 1920, - .height = 1080, - .fps = 30, - } -}; - -static struct ap1302_res_struct ap1302_snapshot_res[] = { - { - .width = 640, - .height = 480, - .fps = 30, - }, - { - .width = 720, - .height = 480, - .fps = 30, - }, - { - .width = 1280, - .height = 720, - .fps = 30, - }, - { - .width = 1920, - .height = 1080, - .fps = 30, - } -}; - -static struct ap1302_res_struct ap1302_video_res[] = { - { - .width = 640, - .height = 480, - .fps = 30, - }, - { - .width = 720, - .height = 480, - .fps = 30, - }, - { - .width = 1280, - .height = 720, - .fps = 30, - }, - { - .width = 1920, - .height = 1080, - .fps = 30, - } -}; - -static enum ap1302_contexts stream_to_context[] = { - CONTEXT_SNAPSHOT, - CONTEXT_PREVIEW, - CONTEXT_PREVIEW, - CONTEXT_VIDEO -}; - -static u16 aux_stream_config[CONTEXT_NUM][CONTEXT_NUM] = { - {0, 0, 0}, /* Preview: No aux streams. */ - {1, 0, 2}, /* Snapshot: 1 for postview. 2 for video */ - {1, 0, 0}, /* Video: 1 for preview. */ -}; - -static struct ap1302_context_info context_info[] = { - {CNTX_WIDTH, AP1302_REG16, "width"}, - {CNTX_HEIGHT, AP1302_REG16, "height"}, - {CNTX_ROI_X0, AP1302_REG16, "roi_x0"}, - {CNTX_ROI_X1, AP1302_REG16, "roi_x1"}, - {CNTX_ROI_Y0, AP1302_REG16, "roi_y0"}, - {CNTX_ROI_Y1, AP1302_REG16, "roi_y1"}, - {CNTX_ASPECT, AP1302_REG16, "aspect"}, - {CNTX_LOCK, AP1302_REG16, "lock"}, - {CNTX_ENABLE, AP1302_REG16, "enable"}, - {CNTX_OUT_FMT, AP1302_REG16, "out_fmt"}, - {CNTX_SENSOR_MODE, AP1302_REG16, "sensor_mode"}, - {CNTX_MIPI_CTRL, AP1302_REG16, "mipi_ctrl"}, - {CNTX_MIPI_II_CTRL, AP1302_REG16, "mipi_ii_ctrl"}, - {CNTX_LINE_TIME, AP1302_REG32, "line_time"}, - {CNTX_MAX_FPS, AP1302_REG16, "max_fps"}, - {CNTX_AE_USG, AP1302_REG16, "ae_usg"}, - {CNTX_AE_UPPER_ET, AP1302_REG32, "ae_upper_et"}, - {CNTX_AE_MAX_ET, AP1302_REG32, "ae_max_et"}, - {CNTX_SS, AP1302_REG16, "ss"}, - {CNTX_S1_SENSOR_MODE, AP1302_REG16, "s1_sensor_mode"}, - {CNTX_HINF_CTRL, AP1302_REG16, "hinf_ctrl"}, -}; - -/* This array stores the description list for metadata. - The metadata contains exposure settings and face - detection results. */ -static u16 ap1302_ss_list[] = { - 0xb01c, /* From 0x0186 with size 0x1C are exposure settings. */ - 0x0186, - 0xb002, /* 0x71c0 is for F-number */ - 0x71c0, - 0xb010, /* From 0x03dc with size 0x10 are face general infos. */ - 0x03dc, - 0xb0a0, /* From 0x03e4 with size 0xa0 are face detail infos. */ - 0x03e4, - 0xb020, /* From 0x0604 with size 0x20 are smile rate infos. */ - 0x0604, - 0x0000 -}; - -/* End of static definitions */ - -static int ap1302_i2c_read_reg(struct v4l2_subdev *sd, - u16 reg, u16 len, void *val) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - if (len == AP1302_REG16) - ret = regmap_read(dev->regmap16, reg, val); - else if (len == AP1302_REG32) - ret = regmap_read(dev->regmap32, reg, val); - else - ret = -EINVAL; - if (ret) { - dev_dbg(&client->dev, "Read reg failed. reg=0x%04X\n", reg); - return ret; - } - if (len == AP1302_REG16) - dev_dbg(&client->dev, "read_reg[0x%04X] = 0x%04X\n", - reg, *(u16 *)val); - else - dev_dbg(&client->dev, "read_reg[0x%04X] = 0x%08X\n", - reg, *(u32 *)val); - return ret; -} - -static int ap1302_i2c_write_reg(struct v4l2_subdev *sd, - u16 reg, u16 len, u32 val) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - if (len == AP1302_REG16) - ret = regmap_write(dev->regmap16, reg, val); - else if (len == AP1302_REG32) - ret = regmap_write(dev->regmap32, reg, val); - else - ret = -EINVAL; - if (ret) { - dev_dbg(&client->dev, "Write reg failed. reg=0x%04X\n", reg); - return ret; - } - if (len == AP1302_REG16) - dev_dbg(&client->dev, "write_reg[0x%04X] = 0x%04X\n", - reg, (u16)val); - else - dev_dbg(&client->dev, "write_reg[0x%04X] = 0x%08X\n", - reg, (u32)val); - return ret; -} - -static u16 -ap1302_calculate_context_reg_addr(enum ap1302_contexts context, u16 offset) -{ - u16 reg_addr; - /* The register offset is defined according to preview/video registers. - Preview and video context have the same register definition. - But snapshot context does not have register S1_SENSOR_MODE. - When setting snapshot registers, if the offset exceeds - S1_SENSOR_MODE, the actual offset needs to minus 2. */ - if (context == CONTEXT_SNAPSHOT) { - if (offset == CNTX_S1_SENSOR_MODE) - return 0; - if (offset > CNTX_S1_SENSOR_MODE) - offset -= 2; - } - if (context == CONTEXT_PREVIEW) - reg_addr = REG_PREVIEW_BASE + offset; - else if (context == CONTEXT_VIDEO) - reg_addr = REG_VIDEO_BASE + offset; - else - reg_addr = REG_SNAPSHOT_BASE + offset; - return reg_addr; -} - -static int ap1302_read_context_reg(struct v4l2_subdev *sd, - enum ap1302_contexts context, u16 offset, u16 len) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - u16 reg_addr = ap1302_calculate_context_reg_addr(context, offset); - if (reg_addr == 0) - return -EINVAL; - return ap1302_i2c_read_reg(sd, reg_addr, len, - ((u8 *)&dev->cntx_config[context]) + offset); -} - -static int ap1302_write_context_reg(struct v4l2_subdev *sd, - enum ap1302_contexts context, u16 offset, u16 len) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - u16 reg_addr = ap1302_calculate_context_reg_addr(context, offset); - if (reg_addr == 0) - return -EINVAL; - return ap1302_i2c_write_reg(sd, reg_addr, len, - *(u32 *)(((u8 *)&dev->cntx_config[context]) + offset)); -} - -static int ap1302_dump_context_reg(struct v4l2_subdev *sd, - enum ap1302_contexts context) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ap1302_device *dev = to_ap1302_device(sd); - int i; - dev_dbg(&client->dev, "Dump registers for context[%d]:\n", context); - for (i = 0; i < ARRAY_SIZE(context_info); i++) { - struct ap1302_context_info *info = &context_info[i]; - u8 *var = (u8 *)&dev->cntx_config[context] + info->offset; - /* Snapshot context does not have s1_sensor_mode register. */ - if (context == CONTEXT_SNAPSHOT && - info->offset == CNTX_S1_SENSOR_MODE) - continue; - ap1302_read_context_reg(sd, context, info->offset, info->len); - if (info->len == AP1302_REG16) - dev_dbg(&client->dev, "context.%s = 0x%04X (%d)\n", - info->name, *(u16 *)var, *(u16 *)var); - else - dev_dbg(&client->dev, "context.%s = 0x%08X (%d)\n", - info->name, *(u32 *)var, *(u32 *)var); - } - return 0; -} - -static int ap1302_request_firmware(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ap1302_device *dev = to_ap1302_device(sd); - int ret; - ret = request_firmware(&dev->fw, "ap1302_fw.bin", &client->dev); - if (ret) - dev_err(&client->dev, - "ap1302_request_firmware failed. ret=%d\n", ret); - return ret; -} - -/* When loading firmware, host writes firmware data from address 0x8000. - When the address reaches 0x9FFF, the next address should return to 0x8000. - This function handles this address window and load firmware data to AP1302. - win_pos indicates the offset within this window. Firmware loading procedure - may call this function several times. win_pos records the current position - that has been written to.*/ -static int ap1302_write_fw_window(struct v4l2_subdev *sd, - u16 *win_pos, const u8 *buf, u32 len) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - int ret; - u32 pos; - u32 sub_len; - for (pos = 0; pos < len; pos += sub_len) { - if (len - pos < AP1302_FW_WINDOW_SIZE - *win_pos) - sub_len = len - pos; - else - sub_len = AP1302_FW_WINDOW_SIZE - *win_pos; - ret = regmap_raw_write(dev->regmap16, - *win_pos + AP1302_FW_WINDOW_OFFSET, - buf + pos, sub_len); - if (ret) - return ret; - *win_pos += sub_len; - if (*win_pos >= AP1302_FW_WINDOW_SIZE) - *win_pos = 0; - } - return 0; -} - -static int ap1302_load_firmware(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ap1302_device *dev = to_ap1302_device(sd); - const struct ap1302_firmware *fw; - const u8 *fw_data; - u16 reg_val = 0; - u16 win_pos = 0; - int ret; - - dev_info(&client->dev, "Start to load firmware.\n"); - if (!dev->fw) { - dev_err(&client->dev, "firmware not requested.\n"); - return -EINVAL; - } - fw = (const struct ap1302_firmware *) dev->fw->data; - if (dev->fw->size != (sizeof(*fw) + fw->total_size)) { - dev_err(&client->dev, "firmware size does not match.\n"); - return -EINVAL; - } - /* The fw binary contains a header of struct ap1302_firmware. - Following the header is the bootdata of AP1302. - The bootdata pointer can be referenced as &fw[1]. */ - fw_data = (u8 *)&fw[1]; - - /* Clear crc register. */ - ret = ap1302_i2c_write_reg(sd, REG_SIP_CRC, AP1302_REG16, 0xFFFF); - if (ret) - return ret; - - /* Load FW data for PLL init stage. */ - ret = ap1302_write_fw_window(sd, &win_pos, fw_data, fw->pll_init_size); - if (ret) - return ret; - - /* Write 2 to bootdata_stage register to apply basic_init_hp - settings and enable PLL. */ - ret = ap1302_i2c_write_reg(sd, REG_BOOTDATA_STAGE, - AP1302_REG16, 0x0002); - if (ret) - return ret; - - /* Wait 1ms for PLL to lock. */ - msleep(20); - - /* Load the rest of bootdata content. */ - ret = ap1302_write_fw_window(sd, &win_pos, fw_data + fw->pll_init_size, - fw->total_size - fw->pll_init_size); - if (ret) - return ret; - - /* Check crc. */ - ret = ap1302_i2c_read_reg(sd, REG_SIP_CRC, AP1302_REG16, ®_val); - if (ret) - return ret; - if (reg_val != fw->crc) { - dev_err(&client->dev, - "crc does not match. T:0x%04X F:0x%04X\n", - fw->crc, reg_val); - return -EAGAIN; - } - - /* Write 0xFFFF to bootdata_stage register to indicate AP1302 that - the whole bootdata content has been loaded. */ - ret = ap1302_i2c_write_reg(sd, REG_BOOTDATA_STAGE, - AP1302_REG16, 0xFFFF); - if (ret) - return ret; - dev_info(&client->dev, "Load firmware successfully.\n"); - - return 0; -} - -static int __ap1302_s_power(struct v4l2_subdev *sd, int on, int load_fw) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret, i; - u16 ss_ptr; - - dev_info(&client->dev, "ap1302_s_power is called.\n"); - ret = dev->platform_data->power_ctrl(sd, on); - if (ret) { - dev_err(&client->dev, - "ap1302_s_power error. on=%d ret=%d\n", on, ret); - return ret; - } - dev->power_on = on; - if (!on || !load_fw) - return 0; - /* Load firmware after power on. */ - ret = ap1302_load_firmware(sd); - if (ret) { - dev_err(&client->dev, - "ap1302_load_firmware failed. ret=%d\n", ret); - return ret; - } - ret = ap1302_i2c_read_reg(sd, REG_SS_HEAD_PT0, AP1302_REG16, &ss_ptr); - if (ret) - return ret; - for (i = 0; i < ARRAY_SIZE(ap1302_ss_list); i++) { - ret = ap1302_i2c_write_reg(sd, ss_ptr + i * 2, - AP1302_REG16, ap1302_ss_list[i]); - if (ret) - return ret; - } - return ret; -} - -static int ap1302_s_power(struct v4l2_subdev *sd, int on) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - int ret; - - mutex_lock(&dev->input_lock); - ret = __ap1302_s_power(sd, on, 1); - dev->sys_activated = 0; - mutex_unlock(&dev->input_lock); - - return ret; -} - -static int ap1302_s_config(struct v4l2_subdev *sd, void *pdata) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct camera_mipi_info *mipi_info; - u16 reg_val = 0; - int ret; - - dev_info(&client->dev, "ap1302_s_config is called.\n"); - if (pdata == NULL) - return -ENODEV; - - dev->platform_data = pdata; - - mutex_lock(&dev->input_lock); - - if (dev->platform_data->platform_init) { - ret = dev->platform_data->platform_init(client); - if (ret) - goto fail_power; - } - - ret = __ap1302_s_power(sd, 1, 0); - if (ret) - goto fail_power; - - /* Detect for AP1302 */ - ret = ap1302_i2c_read_reg(sd, REG_CHIP_VERSION, AP1302_REG16, ®_val); - if (ret || (reg_val != AP1302_CHIP_ID)) { - dev_err(&client->dev, - "Chip version does no match. ret=%d ver=0x%04x\n", - ret, reg_val); - goto fail_config; - } - dev_info(&client->dev, "AP1302 Chip ID is 0x%X\n", reg_val); - - /* Detect revision for AP1302 */ - ret = ap1302_i2c_read_reg(sd, REG_CHIP_REV, AP1302_REG16, ®_val); - if (ret) - goto fail_config; - dev_info(&client->dev, "AP1302 Chip Rev is 0x%X\n", reg_val); - ret = dev->platform_data->csi_cfg(sd, 1); - if (ret) - goto fail_config; - - mipi_info = v4l2_get_subdev_hostdata(sd); - if (!mipi_info) - goto fail_config; - dev->num_lanes = mipi_info->num_lanes; - - ret = __ap1302_s_power(sd, 0, 0); - if (ret) - goto fail_power; - - mutex_unlock(&dev->input_lock); - - return ret; - -fail_config: - __ap1302_s_power(sd, 0, 0); -fail_power: - mutex_unlock(&dev->input_lock); - dev_err(&client->dev, "ap1302_s_config failed\n"); - return ret; -} - -static enum ap1302_contexts ap1302_get_context(struct v4l2_subdev *sd) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - return dev->cur_context; -} - -static int ap1302_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->index) - return -EINVAL; - - code->code = MEDIA_BUS_FMT_UYVY8_1X16; - - return 0; -} - -static int ap1302_match_resolution(struct ap1302_context_res *res, - struct v4l2_mbus_framefmt *fmt) -{ - s32 w0, h0, mismatch, distance; - s32 w1 = fmt->width; - s32 h1 = fmt->height; - s32 min_distance = INT_MAX; - s32 i, idx = -1; - - if (w1 == 0 || h1 == 0) - return -1; - - for (i = 0; i < res->res_num; i++) { - w0 = res->res_table[i].width; - h0 = res->res_table[i].height; - if (w0 < w1 || h0 < h1) - continue; - mismatch = abs(w0 * h1 - w1 * h0) * 8192 / w1 / h0; - if (mismatch > 8192 * AP1302_MAX_RATIO_MISMATCH / 100) - continue; - distance = (w0 * h1 + w1 * h0) * 8192 / w1 / h1; - if (distance < min_distance) { - min_distance = distance; - idx = i; - } - } - - return idx; -} - -static s32 ap1302_try_mbus_fmt_locked(struct v4l2_subdev *sd, - enum ap1302_contexts context, - struct v4l2_mbus_framefmt *fmt) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - struct ap1302_res_struct *res_table; - s32 res_num, idx = -1; - - res_table = dev->cntx_res[context].res_table; - res_num = dev->cntx_res[context].res_num; - - if ((fmt->width <= res_table[res_num - 1].width) && - (fmt->height <= res_table[res_num - 1].height)) - idx = ap1302_match_resolution(&dev->cntx_res[context], fmt); - if (idx == -1) - idx = res_num - 1; - - fmt->width = res_table[idx].width; - fmt->height = res_table[idx].height; - fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; - return idx; -} - - -static int ap1302_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) - -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct ap1302_device *dev = to_ap1302_device(sd); - enum ap1302_contexts context; - struct ap1302_res_struct *res_table; - s32 cur_res; - if (format->pad) - return -EINVAL; - mutex_lock(&dev->input_lock); - context = ap1302_get_context(sd); - res_table = dev->cntx_res[context].res_table; - cur_res = dev->cntx_res[context].cur_res; - fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; - fmt->width = res_table[cur_res].width; - fmt->height = res_table[cur_res].height; - mutex_unlock(&dev->input_lock); - return 0; -} - -static int ap1302_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *fmt = &format->format; - struct ap1302_device *dev = to_ap1302_device(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct atomisp_input_stream_info *stream_info = - (struct atomisp_input_stream_info *)fmt->reserved; - enum ap1302_contexts context, main_context; - if (format->pad) - return -EINVAL; - if (!fmt) - return -EINVAL; - mutex_lock(&dev->input_lock); - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - context = ap1302_get_context(sd); - ap1302_try_mbus_fmt_locked(sd, context, fmt); - cfg->try_fmt = *fmt; - mutex_unlock(&dev->input_lock); - return 0; - } - context = stream_to_context[stream_info->stream]; - dev_dbg(&client->dev, "ap1302_set_mbus_fmt. stream=%d context=%d\n", - stream_info->stream, context); - dev->cntx_res[context].cur_res = - ap1302_try_mbus_fmt_locked(sd, context, fmt); - dev->cntx_config[context].width = fmt->width; - dev->cntx_config[context].height = fmt->height; - ap1302_write_context_reg(sd, context, CNTX_WIDTH, AP1302_REG16); - ap1302_write_context_reg(sd, context, CNTX_HEIGHT, AP1302_REG16); - ap1302_read_context_reg(sd, context, CNTX_OUT_FMT, AP1302_REG16); - dev->cntx_config[context].out_fmt &= ~OUT_FMT_TYPE_MASK; - dev->cntx_config[context].out_fmt |= AP1302_FMT_UYVY422; - ap1302_write_context_reg(sd, context, CNTX_OUT_FMT, AP1302_REG16); - - main_context = ap1302_get_context(sd); - if (context == main_context) { - ap1302_read_context_reg(sd, context, - CNTX_MIPI_CTRL, AP1302_REG16); - dev->cntx_config[context].mipi_ctrl &= ~MIPI_CTRL_IMGVC_MASK; - dev->cntx_config[context].mipi_ctrl |= - (context << MIPI_CTRL_IMGVC_OFFSET); - dev->cntx_config[context].mipi_ctrl &= ~MIPI_CTRL_SSVC_MASK; - dev->cntx_config[context].mipi_ctrl |= - (context << MIPI_CTRL_SSVC_OFFSET); - dev->cntx_config[context].mipi_ctrl &= ~MIPI_CTRL_SSTYPE_MASK; - dev->cntx_config[context].mipi_ctrl |= - (0x12 << MIPI_CTRL_SSTYPE_OFFSET); - ap1302_write_context_reg(sd, context, - CNTX_MIPI_CTRL, AP1302_REG16); - ap1302_read_context_reg(sd, context, - CNTX_SS, AP1302_REG16); - dev->cntx_config[context].ss = AP1302_SS_CTRL; - ap1302_write_context_reg(sd, context, - CNTX_SS, AP1302_REG16); - } else { - /* Configure aux stream */ - ap1302_read_context_reg(sd, context, - CNTX_MIPI_II_CTRL, AP1302_REG16); - dev->cntx_config[context].mipi_ii_ctrl &= ~MIPI_CTRL_IMGVC_MASK; - dev->cntx_config[context].mipi_ii_ctrl |= - (context << MIPI_CTRL_IMGVC_OFFSET); - ap1302_write_context_reg(sd, context, - CNTX_MIPI_II_CTRL, AP1302_REG16); - if (stream_info->enable) { - ap1302_read_context_reg(sd, main_context, - CNTX_OUT_FMT, AP1302_REG16); - dev->cntx_config[context].out_fmt |= - (aux_stream_config[main_context][context] - << OUT_FMT_IIS_OFFSET); - ap1302_write_context_reg(sd, main_context, - CNTX_OUT_FMT, AP1302_REG16); - } - } - stream_info->ch_id = context; - mutex_unlock(&dev->input_lock); - - return 0; -} - - -static int ap1302_g_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_frame_interval *interval) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - enum ap1302_contexts context; - struct ap1302_res_struct *res_table; - u32 cur_res; - - mutex_lock(&dev->input_lock); - context = ap1302_get_context(sd); - res_table = dev->cntx_res[context].res_table; - cur_res = dev->cntx_res[context].cur_res; - interval->interval.denominator = res_table[cur_res].fps; - interval->interval.numerator = 1; - mutex_unlock(&dev->input_lock); - return 0; -} - -static int ap1302_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - enum ap1302_contexts context; - struct ap1302_res_struct *res_table; - int index = fse->index; - - mutex_lock(&dev->input_lock); - context = ap1302_get_context(sd); - if (index >= dev->cntx_res[context].res_num) { - mutex_unlock(&dev->input_lock); - return -EINVAL; - } - - res_table = dev->cntx_res[context].res_table; - fse->min_width = res_table[index].width; - fse->min_height = res_table[index].height; - fse->max_width = res_table[index].width; - fse->max_height = res_table[index].height; - mutex_unlock(&dev->input_lock); - - return 0; -} - - -static int ap1302_g_skip_frames(struct v4l2_subdev *sd, u32 *frames) -{ - *frames = 0; - return 0; -} - -static int ap1302_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - enum ap1302_contexts context; - u32 reg_val; - int ret; - - mutex_lock(&dev->input_lock); - context = ap1302_get_context(sd); - dev_dbg(&client->dev, "ap1302_s_stream. context=%d enable=%d\n", - context, enable); - /* Switch context */ - ap1302_i2c_read_reg(sd, REG_CTRL, - AP1302_REG16, ®_val); - reg_val &= ~CTRL_CNTX_MASK; - reg_val |= (context<dev, "Start stream. context=%d\n", context); - ap1302_dump_context_reg(sd, context); - if (!dev->sys_activated) { - reg_val = AP1302_SYS_ACTIVATE; - dev->sys_activated = 1; - } else { - reg_val = AP1302_SYS_SWITCH; - } - } else { - dev_info(&client->dev, "Stop stream. context=%d\n", context); - reg_val = AP1302_SYS_SWITCH; - } - ret = ap1302_i2c_write_reg(sd, REG_SYS_START, AP1302_REG16, reg_val); - if (ret) - dev_err(&client->dev, - "AP1302 set stream failed. enable=%d\n", enable); - mutex_unlock(&dev->input_lock); - return ret; -} - -static u16 ap1302_ev_values[] = {0xfd00, 0xfe80, 0x0, 0x180, 0x300}; - -static int ap1302_set_exposure_off(struct v4l2_subdev *sd, s32 val) -{ - val -= AP1302_MIN_EV; - return ap1302_i2c_write_reg(sd, REG_AE_BV_OFF, AP1302_REG16, - ap1302_ev_values[val]); -} - -static u16 ap1302_wb_values[] = { - 0, /* V4L2_WHITE_BALANCE_MANUAL */ - 0xf, /* V4L2_WHITE_BALANCE_AUTO */ - 0x2, /* V4L2_WHITE_BALANCE_INCANDESCENT */ - 0x4, /* V4L2_WHITE_BALANCE_FLUORESCENT */ - 0x5, /* V4L2_WHITE_BALANCE_FLUORESCENT_H */ - 0x1, /* V4L2_WHITE_BALANCE_HORIZON */ - 0x5, /* V4L2_WHITE_BALANCE_DAYLIGHT */ - 0xf, /* V4L2_WHITE_BALANCE_FLASH */ - 0x6, /* V4L2_WHITE_BALANCE_CLOUDY */ - 0x6, /* V4L2_WHITE_BALANCE_SHADE */ -}; - -static int ap1302_set_wb_mode(struct v4l2_subdev *sd, s32 val) -{ - int ret = 0; - u16 reg_val; - - ret = ap1302_i2c_read_reg(sd, REG_AWB_CTRL, AP1302_REG16, ®_val); - if (ret) - return ret; - reg_val &= ~AWB_CTRL_MODE_MASK; - reg_val |= ap1302_wb_values[val] << AWB_CTRL_MODE_OFFSET; - if (val == V4L2_WHITE_BALANCE_FLASH) - reg_val |= AWB_CTRL_FLASH_MASK; - else - reg_val &= ~AWB_CTRL_FLASH_MASK; - ret = ap1302_i2c_write_reg(sd, REG_AWB_CTRL, AP1302_REG16, reg_val); - return ret; -} - -static int ap1302_set_zoom(struct v4l2_subdev *sd, s32 val) -{ - ap1302_i2c_write_reg(sd, REG_DZ_TGT_FCT, AP1302_REG16, - val * 4 + 0x100); - return 0; -} - -static u16 ap1302_sfx_values[] = { - 0x00, /* V4L2_COLORFX_NONE */ - 0x03, /* V4L2_COLORFX_BW */ - 0x0d, /* V4L2_COLORFX_SEPIA */ - 0x07, /* V4L2_COLORFX_NEGATIVE */ - 0x04, /* V4L2_COLORFX_EMBOSS */ - 0x0f, /* V4L2_COLORFX_SKETCH */ - 0x08, /* V4L2_COLORFX_SKY_BLUE */ - 0x09, /* V4L2_COLORFX_GRASS_GREEN */ - 0x0a, /* V4L2_COLORFX_SKIN_WHITEN */ - 0x00, /* V4L2_COLORFX_VIVID */ - 0x00, /* V4L2_COLORFX_AQUA */ - 0x00, /* V4L2_COLORFX_ART_FREEZE */ - 0x00, /* V4L2_COLORFX_SILHOUETTE */ - 0x10, /* V4L2_COLORFX_SOLARIZATION */ - 0x02, /* V4L2_COLORFX_ANTIQUE */ - 0x00, /* V4L2_COLORFX_SET_CBCR */ -}; - -static int ap1302_set_special_effect(struct v4l2_subdev *sd, s32 val) -{ - ap1302_i2c_write_reg(sd, REG_SFX_MODE, AP1302_REG16, - ap1302_sfx_values[val]); - return 0; -} - -static u16 ap1302_scene_mode_values[] = { - 0x00, /* V4L2_SCENE_MODE_NONE */ - 0x07, /* V4L2_SCENE_MODE_BACKLIGHT */ - 0x0a, /* V4L2_SCENE_MODE_BEACH_SNOW */ - 0x06, /* V4L2_SCENE_MODE_CANDLE_LIGHT */ - 0x00, /* V4L2_SCENE_MODE_DAWN_DUSK */ - 0x00, /* V4L2_SCENE_MODE_FALL_COLORS */ - 0x0d, /* V4L2_SCENE_MODE_FIREWORKS */ - 0x02, /* V4L2_SCENE_MODE_LANDSCAPE */ - 0x05, /* V4L2_SCENE_MODE_NIGHT */ - 0x0c, /* V4L2_SCENE_MODE_PARTY_INDOOR */ - 0x01, /* V4L2_SCENE_MODE_PORTRAIT */ - 0x03, /* V4L2_SCENE_MODE_SPORTS */ - 0x0e, /* V4L2_SCENE_MODE_SUNSET */ - 0x0b, /* V4L2_SCENE_MODE_TEXT */ -}; - -static int ap1302_set_scene_mode(struct v4l2_subdev *sd, s32 val) -{ - ap1302_i2c_write_reg(sd, REG_SCENE_CTRL, AP1302_REG16, - ap1302_scene_mode_values[val]); - return 0; -} - -static u16 ap1302_flicker_values[] = { - 0x0, /* OFF */ - 0x3201, /* 50HZ */ - 0x3c01, /* 60HZ */ - 0x2 /* AUTO */ -}; - -static int ap1302_set_flicker_freq(struct v4l2_subdev *sd, s32 val) -{ - ap1302_i2c_write_reg(sd, REG_FLICK_CTRL, AP1302_REG16, - ap1302_flicker_values[val]); - return 0; -} - -static int ap1302_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ap1302_device *dev = container_of( - ctrl->handler, struct ap1302_device, ctrl_handler); - - switch (ctrl->id) { - case V4L2_CID_RUN_MODE: - dev->cur_context = ap1302_cntx_mapping[ctrl->val]; - break; - case V4L2_CID_EXPOSURE: - ap1302_set_exposure_off(&dev->sd, ctrl->val); - break; - case V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: - ap1302_set_wb_mode(&dev->sd, ctrl->val); - break; - case V4L2_CID_ZOOM_ABSOLUTE: - ap1302_set_zoom(&dev->sd, ctrl->val); - break; - case V4L2_CID_COLORFX: - ap1302_set_special_effect(&dev->sd, ctrl->val); - break; - case V4L2_CID_SCENE_MODE: - ap1302_set_scene_mode(&dev->sd, ctrl->val); - break; - case V4L2_CID_POWER_LINE_FREQUENCY: - ap1302_set_flicker_freq(&dev->sd, ctrl->val); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int ap1302_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - int ret; - u32 reg_val; - - if (reg->size != AP1302_REG16 && - reg->size != AP1302_REG32) - return -EINVAL; - - mutex_lock(&dev->input_lock); - if (dev->power_on) - ret = ap1302_i2c_read_reg(sd, reg->reg, reg->size, ®_val); - else - ret = -EIO; - mutex_unlock(&dev->input_lock); - if (ret) - return ret; - - reg->val = reg_val; - - return 0; -} - -static int ap1302_s_register(struct v4l2_subdev *sd, - const struct v4l2_dbg_register *reg) -{ - struct ap1302_device *dev = to_ap1302_device(sd); - int ret; - - if (reg->size != AP1302_REG16 && - reg->size != AP1302_REG32) - return -EINVAL; - - mutex_lock(&dev->input_lock); - if (dev->power_on) - ret = ap1302_i2c_write_reg(sd, reg->reg, reg->size, reg->val); - else - ret = -EIO; - mutex_unlock(&dev->input_lock); - return ret; -} - -static long ap1302_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - long ret = 0; - switch (cmd) { - case VIDIOC_DBG_G_REGISTER: - ret = ap1302_g_register(sd, arg); - break; - case VIDIOC_DBG_S_REGISTER: - ret = ap1302_s_register(sd, arg); - break; - default: - ret = -EINVAL; - } - return ret; -} - -static const struct v4l2_ctrl_ops ctrl_ops = { - .s_ctrl = ap1302_s_ctrl, -}; - -static const char * const ctrl_run_mode_menu[] = { - NULL, - "Video", - "Still capture", - "Continuous capture", - "Preview", -}; - -static const struct v4l2_ctrl_config ctrls[] = { - { - .ops = &ctrl_ops, - .id = V4L2_CID_RUN_MODE, - .name = "Run Mode", - .type = V4L2_CTRL_TYPE_MENU, - .min = 1, - .def = 4, - .max = 4, - .qmenu = ctrl_run_mode_menu, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_EXPOSURE, - .name = "Exposure", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = AP1302_MIN_EV, - .def = 0, - .max = AP1302_MAX_EV, - .step = 1, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, - .name = "White Balance", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .def = 0, - .max = 9, - .step = 1, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_ZOOM_ABSOLUTE, - .name = "Zoom Absolute", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .def = 0, - .max = 1024, - .step = 1, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_COLORFX, - .name = "Color Special Effect", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .def = 0, - .max = 15, - .step = 1, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_SCENE_MODE, - .name = "Scene Mode", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .def = 0, - .max = 13, - .step = 1, - }, - { - .ops = &ctrl_ops, - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .name = "Light frequency filter", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .def = 3, - .max = 3, - .step = 1, - }, -}; - -static const struct v4l2_subdev_sensor_ops ap1302_sensor_ops = { - .g_skip_frames = ap1302_g_skip_frames, -}; - -static const struct v4l2_subdev_video_ops ap1302_video_ops = { - .s_stream = ap1302_s_stream, - .g_frame_interval = ap1302_g_frame_interval, -}; - -static const struct v4l2_subdev_core_ops ap1302_core_ops = { - .s_power = ap1302_s_power, - .ioctl = ap1302_ioctl, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = ap1302_g_register, - .s_register = ap1302_s_register, -#endif -}; - -static const struct v4l2_subdev_pad_ops ap1302_pad_ops = { - .enum_mbus_code = ap1302_enum_mbus_code, - .enum_frame_size = ap1302_enum_frame_size, - .get_fmt = ap1302_get_fmt, - .set_fmt = ap1302_set_fmt, -}; - -static const struct v4l2_subdev_ops ap1302_ops = { - .core = &ap1302_core_ops, - .pad = &ap1302_pad_ops, - .video = &ap1302_video_ops, - .sensor = &ap1302_sensor_ops -}; - -static int ap1302_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct ap1302_device *dev = to_ap1302_device(sd); - - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); - - release_firmware(dev->fw); - - media_entity_cleanup(&dev->sd.entity); - dev->platform_data->csi_cfg(sd, 0); - v4l2_device_unregister_subdev(sd); - - return 0; -} - -static int ap1302_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct ap1302_device *dev; - int ret; - unsigned int i; - - dev_info(&client->dev, "ap1302 probe called.\n"); - - /* allocate device & init sub device */ - dev = devm_kzalloc(&client->dev, sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - mutex_init(&dev->input_lock); - - v4l2_i2c_subdev_init(&(dev->sd), client, &ap1302_ops); - - ret = ap1302_request_firmware(&(dev->sd)); - if (ret) { - dev_err(&client->dev, "Cannot request ap1302 firmware.\n"); - goto out_free; - } - - dev->regmap16 = devm_regmap_init_i2c(client, &ap1302_reg16_config); - if (IS_ERR(dev->regmap16)) { - ret = PTR_ERR(dev->regmap16); - dev_err(&client->dev, - "Failed to allocate 16bit register map: %d\n", ret); - return ret; - } - - dev->regmap32 = devm_regmap_init_i2c(client, &ap1302_reg32_config); - if (IS_ERR(dev->regmap32)) { - ret = PTR_ERR(dev->regmap32); - dev_err(&client->dev, - "Failed to allocate 32bit register map: %d\n", ret); - return ret; - } - - if (client->dev.platform_data) { - ret = ap1302_s_config(&dev->sd, client->dev.platform_data); - if (ret) - goto out_free; - } - - dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - dev->pad.flags = MEDIA_PAD_FL_SOURCE; - dev->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - - dev->cntx_res[CONTEXT_PREVIEW].res_num = ARRAY_SIZE(ap1302_preview_res); - dev->cntx_res[CONTEXT_PREVIEW].res_table = ap1302_preview_res; - dev->cntx_res[CONTEXT_SNAPSHOT].res_num = - ARRAY_SIZE(ap1302_snapshot_res); - dev->cntx_res[CONTEXT_SNAPSHOT].res_table = ap1302_snapshot_res; - dev->cntx_res[CONTEXT_VIDEO].res_num = ARRAY_SIZE(ap1302_video_res); - dev->cntx_res[CONTEXT_VIDEO].res_table = ap1302_video_res; - - ret = v4l2_ctrl_handler_init(&dev->ctrl_handler, ARRAY_SIZE(ctrls)); - if (ret) { - ap1302_remove(client); - return ret; - } - - for (i = 0; i < ARRAY_SIZE(ctrls); i++) - v4l2_ctrl_new_custom(&dev->ctrl_handler, &ctrls[i], NULL); - - if (dev->ctrl_handler.error) { - ap1302_remove(client); - return dev->ctrl_handler.error; - } - - /* Use same lock for controls as for everything else. */ - dev->ctrl_handler.lock = &dev->input_lock; - dev->sd.ctrl_handler = &dev->ctrl_handler; - v4l2_ctrl_handler_setup(&dev->ctrl_handler); - - dev->run_mode = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_RUN_MODE); - v4l2_ctrl_s_ctrl(dev->run_mode, ATOMISP_RUN_MODE_PREVIEW); - - ret = media_entity_pads_init(&dev->sd.entity, 1, &dev->pad); - if (ret) - ap1302_remove(client); - return ret; -out_free: - v4l2_device_unregister_subdev(&dev->sd); - return ret; -} - -static const struct i2c_device_id ap1302_id[] = { - {AP1302_NAME, 0}, - {} -}; -MODULE_DEVICE_TABLE(i2c, ap1302_id); - -static struct i2c_driver ap1302_driver = { - .driver = { - .name = AP1302_NAME, - }, - .probe = ap1302_probe, - .remove = ap1302_remove, - .id_table = ap1302_id, -}; - -module_i2c_driver(ap1302_driver); - -MODULE_AUTHOR("Tianshu Qiu "); -MODULE_DESCRIPTION("AP1302 Driver"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 2cb63c4cf56fbe1a6dcc52595885eb2692a7df01 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 27 Sep 2017 14:24:58 -0400 Subject: media: staging: atomisp: Use module_i2c_driver() macro This is done using coccinelle semantic patch: // @a@ identifier f, x; @@ -static f(...) { return i2c_add_driver(&x); } @b depends on a@ identifier e, a.x; @@ -static e(...) { i2c_del_driver(&x); } @c depends on a && b@ identifier a.f; declarer name module_init; @@ -module_init(f); @d depends on a && b && c@ identifier b.e, a.x; declarer name module_exit; declarer name module_i2c_driver; @@ -module_exit(e); +module_i2c_driver(x); // Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-gc0310.c | 15 +-------------- drivers/staging/media/atomisp/i2c/atomisp-gc2235.c | 15 +-------------- drivers/staging/media/atomisp/i2c/atomisp-lm3554.c | 13 +------------ drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c | 14 +------------- drivers/staging/media/atomisp/i2c/atomisp-ov2680.c | 16 +--------------- drivers/staging/media/atomisp/i2c/atomisp-ov2722.c | 15 +-------------- .../staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c | 15 +-------------- drivers/staging/media/atomisp/i2c/ov8858.c | 14 +------------- 8 files changed, 8 insertions(+), 109 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c index 291565451bfe..5a7e20ae59a2 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c @@ -1468,20 +1468,7 @@ static struct i2c_driver gc0310_driver = { .remove = gc0310_remove, .id_table = gc0310_id, }; - -static int init_gc0310(void) -{ - return i2c_add_driver(&gc0310_driver); -} - -static void exit_gc0310(void) -{ - - i2c_del_driver(&gc0310_driver); -} - -module_init(init_gc0310); -module_exit(exit_gc0310); +module_i2c_driver(gc0310_driver); MODULE_AUTHOR("Lai, Angie "); MODULE_DESCRIPTION("A low-level driver for GalaxyCore GC0310 sensors"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c index f51535eee091..30f41d9853ea 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -1197,20 +1197,7 @@ static struct i2c_driver gc2235_driver = { .remove = gc2235_remove, .id_table = gc2235_id, }; - -static int init_gc2235(void) -{ - return i2c_add_driver(&gc2235_driver); -} - -static void exit_gc2235(void) -{ - - i2c_del_driver(&gc2235_driver); -} - -module_init(init_gc2235); -module_exit(exit_gc2235); +module_i2c_driver(gc2235_driver); MODULE_AUTHOR("Shuguang Gong "); MODULE_DESCRIPTION("A low-level driver for GC2235 sensors"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c index 37876d245a02..6abda48afe59 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c @@ -989,19 +989,8 @@ static struct i2c_driver lm3554_driver = { .remove = lm3554_remove, .id_table = lm3554_id, }; +module_i2c_driver(lm3554_driver); -static __init int init_lm3554(void) -{ - return i2c_add_driver(&lm3554_driver); -} - -static __exit void exit_lm3554(void) -{ - i2c_del_driver(&lm3554_driver); -} - -module_init(init_lm3554); -module_exit(exit_lm3554); MODULE_AUTHOR("Jing Tao "); MODULE_DESCRIPTION("LED flash driver for LM3554"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index e204238ae06b..e627522414aa 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -1943,19 +1943,7 @@ static struct i2c_driver mt9m114_driver = { .remove = mt9m114_remove, .id_table = mt9m114_id, }; - -static __init int init_mt9m114(void) -{ - return i2c_add_driver(&mt9m114_driver); -} - -static __exit void exit_mt9m114(void) -{ - i2c_del_driver(&mt9m114_driver); -} - -module_init(init_mt9m114); -module_exit(exit_mt9m114); +module_i2c_driver(mt9m114_driver); MODULE_AUTHOR("Shuguang Gong "); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index c81e80e7bdea..8a4147308eb8 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -1525,7 +1525,6 @@ MODULE_DEVICE_TABLE(acpi, ov2680_acpi_match); MODULE_DEVICE_TABLE(i2c, ov2680_id); static struct i2c_driver ov2680_driver = { .driver = { - .owner = THIS_MODULE, .name = OV2680_NAME, .acpi_match_table = ACPI_PTR(ov2680_acpi_match), @@ -1534,20 +1533,7 @@ static struct i2c_driver ov2680_driver = { .remove = ov2680_remove, .id_table = ov2680_id, }; - -static int init_ov2680(void) -{ - return i2c_add_driver(&ov2680_driver); -} - -static void exit_ov2680(void) -{ - - i2c_del_driver(&ov2680_driver); -} - -module_init(init_ov2680); -module_exit(exit_ov2680); +module_i2c_driver(ov2680_driver); MODULE_AUTHOR("Jacky Wang "); MODULE_DESCRIPTION("A low-level driver for OmniVision 2680 sensors"); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c index 5f2e8a2798ef..c031cbe00693 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -1351,20 +1351,7 @@ static struct i2c_driver ov2722_driver = { .remove = ov2722_remove, .id_table = ov2722_id, }; - -static int init_ov2722(void) -{ - return i2c_add_driver(&ov2722_driver); -} - -static void exit_ov2722(void) -{ - - i2c_del_driver(&ov2722_driver); -} - -module_init(init_ov2722); -module_exit(exit_ov2722); +module_i2c_driver(ov2722_driver); MODULE_AUTHOR("Wei Liu "); MODULE_DESCRIPTION("A low-level driver for OmniVision 2722 sensors"); diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c index cfdb03fbb9e6..0a2b9e64f2c8 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c +++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c @@ -2038,20 +2038,7 @@ static struct i2c_driver ov5693_driver = { .remove = ov5693_remove, .id_table = ov5693_id, }; - -static int init_ov5693(void) -{ - return i2c_add_driver(&ov5693_driver); -} - -static void exit_ov5693(void) -{ - - i2c_del_driver(&ov5693_driver); -} - -module_init(init_ov5693); -module_exit(exit_ov5693); +module_i2c_driver(ov5693_driver); MODULE_DESCRIPTION("A low-level driver for OmniVision 5693 sensors"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/atomisp/i2c/ov8858.c b/drivers/staging/media/atomisp/i2c/ov8858.c index 918139d3d3c0..3ea157c7ee03 100644 --- a/drivers/staging/media/atomisp/i2c/ov8858.c +++ b/drivers/staging/media/atomisp/i2c/ov8858.c @@ -2199,19 +2199,7 @@ static struct i2c_driver ov8858_driver = { .remove = ov8858_remove, .id_table = ov8858_id, }; - -static __init int ov8858_init_mod(void) -{ - return i2c_add_driver(&ov8858_driver); -} - -static __exit void ov8858_exit_mod(void) -{ - i2c_del_driver(&ov8858_driver); -} - -module_init(ov8858_init_mod); -module_exit(ov8858_exit_mod); +module_i2c_driver(ov8858_driver); MODULE_DESCRIPTION("A low-level driver for Omnivision OV8858 sensors"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From e19c92059a700453a304061ff4291dfc2de2902b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 27 Sep 2017 14:24:59 -0400 Subject: media: staging: atomisp: Switch i2c drivers to use ->probe_new() Since most of the drivers are being used on ACPI enabled platforms there is no need to keep legacy API support for them. Thus, switch to ->probe_new() callback and remove orphaned code. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/Kconfig | 9 +++++++-- drivers/staging/media/atomisp/i2c/atomisp-gc0310.c | 12 ++++-------- drivers/staging/media/atomisp/i2c/atomisp-gc2235.c | 13 +++++-------- drivers/staging/media/atomisp/i2c/atomisp-lm3554.c | 18 ++++-------------- drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c | 11 +++-------- drivers/staging/media/atomisp/i2c/atomisp-ov2680.c | 14 ++++---------- drivers/staging/media/atomisp/i2c/atomisp-ov2722.c | 13 ++++--------- drivers/staging/media/atomisp/i2c/gc0310.h | 7 ------- drivers/staging/media/atomisp/i2c/gc2235.h | 7 ------- drivers/staging/media/atomisp/i2c/mt9m114.h | 5 ----- drivers/staging/media/atomisp/i2c/ov2680.h | 10 ---------- drivers/staging/media/atomisp/i2c/ov2722.h | 7 ------- drivers/staging/media/atomisp/i2c/ov5693/Kconfig | 2 +- .../media/atomisp/i2c/ov5693/atomisp-ov5693.c | 12 ++++-------- drivers/staging/media/atomisp/i2c/ov5693/ov5693.h | 7 ------- drivers/staging/media/atomisp/i2c/ov8858.c | 20 +++++--------------- drivers/staging/media/atomisp/i2c/ov8858.h | 1 - drivers/staging/media/atomisp/i2c/ov8858_btns.h | 1 - drivers/staging/media/atomisp/include/media/lm3554.h | 1 - 19 files changed, 41 insertions(+), 129 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/Kconfig b/drivers/staging/media/atomisp/i2c/Kconfig index 7aa5d77b5def..db054d3c7ed6 100644 --- a/drivers/staging/media/atomisp/i2c/Kconfig +++ b/drivers/staging/media/atomisp/i2c/Kconfig @@ -6,6 +6,7 @@ source "drivers/staging/media/atomisp/i2c/ov5693/Kconfig" config VIDEO_ATOMISP_OV2722 tristate "OVT ov2722 sensor support" + depends on ACPI depends on I2C && VIDEO_V4L2 ---help--- This is a Video4Linux2 sensor-level driver for the OVT @@ -17,6 +18,7 @@ config VIDEO_ATOMISP_OV2722 config VIDEO_ATOMISP_GC2235 tristate "Galaxy gc2235 sensor support" + depends on ACPI depends on I2C && VIDEO_V4L2 ---help--- This is a Video4Linux2 sensor-level driver for the OVT @@ -28,6 +30,7 @@ config VIDEO_ATOMISP_GC2235 config VIDEO_ATOMISP_OV8858 tristate "Omnivision ov8858 sensor support" + depends on ACPI depends on I2C && VIDEO_V4L2 && VIDEO_ATOMISP ---help--- This is a Video4Linux2 sensor-level driver for the Omnivision @@ -49,6 +52,7 @@ config VIDEO_ATOMISP_MSRLIST_HELPER config VIDEO_ATOMISP_MT9M114 tristate "Aptina mt9m114 sensor support" + depends on ACPI depends on I2C && VIDEO_V4L2 ---help--- This is a Video4Linux2 sensor-level driver for the Micron @@ -60,6 +64,7 @@ config VIDEO_ATOMISP_MT9M114 config VIDEO_ATOMISP_GC0310 tristate "GC0310 sensor support" + depends on ACPI depends on I2C && VIDEO_V4L2 ---help--- This is a Video4Linux2 sensor-level driver for the Galaxycore @@ -67,6 +72,7 @@ config VIDEO_ATOMISP_GC0310 config VIDEO_ATOMISP_OV2680 tristate "Omnivision OV2680 sensor support" + depends on ACPI depends on I2C && VIDEO_V4L2 ---help--- This is a Video4Linux2 sensor-level driver for the Omnivision @@ -82,6 +88,7 @@ config VIDEO_ATOMISP_OV2680 config VIDEO_ATOMISP_LM3554 tristate "LM3554 flash light driver" + depends on ACPI depends on VIDEO_V4L2 && I2C ---help--- This is a Video4Linux2 sub-dev driver for the LM3554 @@ -89,5 +96,3 @@ config VIDEO_ATOMISP_LM3554 To compile this driver as a module, choose M here: the module will be called lm3554 - - diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c index 5a7e20ae59a2..aafa4db55a57 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c @@ -1375,8 +1375,7 @@ static int gc0310_remove(struct i2c_client *client) return 0; } -static int gc0310_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int gc0310_probe(struct i2c_client *client) { struct gc0310_device *dev; int ret; @@ -1455,18 +1454,15 @@ static const struct acpi_device_id gc0310_acpi_match[] = { {"INT0310"}, {}, }; - MODULE_DEVICE_TABLE(acpi, gc0310_acpi_match); -MODULE_DEVICE_TABLE(i2c, gc0310_id); static struct i2c_driver gc0310_driver = { .driver = { - .name = GC0310_NAME, - .acpi_match_table = ACPI_PTR(gc0310_acpi_match), + .name = "gc0310", + .acpi_match_table = gc0310_acpi_match, }, - .probe = gc0310_probe, + .probe_new = gc0310_probe, .remove = gc0310_remove, - .id_table = gc0310_id, }; module_i2c_driver(gc0310_driver); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c index 30f41d9853ea..ab64598c482f 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -1114,8 +1114,7 @@ static int gc2235_remove(struct i2c_client *client) return 0; } -static int gc2235_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int gc2235_probe(struct i2c_client *client) { struct gc2235_device *dev; void *gcpdev; @@ -1185,17 +1184,15 @@ static const struct acpi_device_id gc2235_acpi_match[] = { { "INT33F8" }, {}, }; - MODULE_DEVICE_TABLE(acpi, gc2235_acpi_match); -MODULE_DEVICE_TABLE(i2c, gc2235_id); + static struct i2c_driver gc2235_driver = { .driver = { - .name = GC2235_NAME, - .acpi_match_table = ACPI_PTR(gc2235_acpi_match), + .name = "gc2235", + .acpi_match_table = gc2235_acpi_match, }, - .probe = gc2235_probe, + .probe_new = gc2235_probe, .remove = gc2235_remove, - .id_table = gc2235_id, }; module_i2c_driver(gc2235_driver); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c index 6abda48afe59..a4e8a55db587 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c @@ -862,8 +862,7 @@ static void *lm3554_platform_data_func(struct i2c_client *client) return &platform_data; } -static int lm3554_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int lm3554_probe(struct i2c_client *client) { int err = 0; struct lm3554 *flash; @@ -960,13 +959,6 @@ fail: return ret; } -static const struct i2c_device_id lm3554_id[] = { - {LM3554_NAME, 0}, - {}, -}; - -MODULE_DEVICE_TABLE(i2c, lm3554_id); - static const struct dev_pm_ops lm3554_pm_ops = { .suspend = lm3554_suspend, .resume = lm3554_resume, @@ -976,18 +968,16 @@ static const struct acpi_device_id lm3554_acpi_match[] = { { "INTCF1C" }, {}, }; - MODULE_DEVICE_TABLE(acpi, lm3554_acpi_match); static struct i2c_driver lm3554_driver = { .driver = { - .name = LM3554_NAME, + .name = "lm3554", .pm = &lm3554_pm_ops, - .acpi_match_table = ACPI_PTR(lm3554_acpi_match), + .acpi_match_table = lm3554_acpi_match, }, - .probe = lm3554_probe, + .probe_new = lm3554_probe, .remove = lm3554_remove, - .id_table = lm3554_id, }; module_i2c_driver(lm3554_driver); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index e627522414aa..b80f86e6d91a 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -1853,8 +1853,7 @@ static int mt9m114_remove(struct i2c_client *client) return 0; } -static int mt9m114_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int mt9m114_probe(struct i2c_client *client) { struct mt9m114_device *dev; int ret = 0; @@ -1924,24 +1923,20 @@ static int mt9m114_probe(struct i2c_client *client, return 0; } -MODULE_DEVICE_TABLE(i2c, mt9m114_id); - static const struct acpi_device_id mt9m114_acpi_match[] = { { "INT33F0" }, { "CRMT1040" }, {}, }; - MODULE_DEVICE_TABLE(acpi, mt9m114_acpi_match); static struct i2c_driver mt9m114_driver = { .driver = { .name = "mt9m114", - .acpi_match_table = ACPI_PTR(mt9m114_acpi_match), + .acpi_match_table = mt9m114_acpi_match, }, - .probe = mt9m114_probe, + .probe_new = mt9m114_probe, .remove = mt9m114_remove, - .id_table = mt9m114_id, }; module_i2c_driver(mt9m114_driver); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 8a4147308eb8..219a856fc34e 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -1438,8 +1438,7 @@ static int ov2680_remove(struct i2c_client *client) return 0; } -static int ov2680_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ov2680_probe(struct i2c_client *client) { struct ov2680_device *dev; int ret; @@ -1521,21 +1520,16 @@ static const struct acpi_device_id ov2680_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, ov2680_acpi_match); - -MODULE_DEVICE_TABLE(i2c, ov2680_id); static struct i2c_driver ov2680_driver = { .driver = { - .name = OV2680_NAME, - .acpi_match_table = ACPI_PTR(ov2680_acpi_match), - + .name = "ov2680", + .acpi_match_table = ov2680_acpi_match, }, - .probe = ov2680_probe, + .probe_new = ov2680_probe, .remove = ov2680_remove, - .id_table = ov2680_id, }; module_i2c_driver(ov2680_driver); MODULE_AUTHOR("Jacky Wang "); MODULE_DESCRIPTION("A low-level driver for OmniVision 2680 sensors"); MODULE_LICENSE("GPL"); - diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c index c031cbe00693..ac827e302654 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -1276,8 +1276,7 @@ static int __ov2722_init_ctrl_handler(struct ov2722_device *dev) return 0; } -static int ov2722_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ov2722_probe(struct i2c_client *client) { struct ov2722_device *dev; void *ovpdev; @@ -1333,23 +1332,19 @@ out_free: return ret; } -MODULE_DEVICE_TABLE(i2c, ov2722_id); - static const struct acpi_device_id ov2722_acpi_match[] = { { "INT33FB" }, {}, }; - MODULE_DEVICE_TABLE(acpi, ov2722_acpi_match); static struct i2c_driver ov2722_driver = { .driver = { - .name = OV2722_NAME, - .acpi_match_table = ACPI_PTR(ov2722_acpi_match), + .name = "ov2722", + .acpi_match_table = ov2722_acpi_match, }, - .probe = ov2722_probe, + .probe_new = ov2722_probe, .remove = ov2722_remove, - .id_table = ov2722_id, }; module_i2c_driver(ov2722_driver); diff --git a/drivers/staging/media/atomisp/i2c/gc0310.h b/drivers/staging/media/atomisp/i2c/gc0310.h index 7d8a0aeecb6c..7e97e45b4f79 100644 --- a/drivers/staging/media/atomisp/i2c/gc0310.h +++ b/drivers/staging/media/atomisp/i2c/gc0310.h @@ -36,8 +36,6 @@ #include "../include/linux/atomisp_platform.h" -#define GC0310_NAME "gc0310" - /* Defines for register writes and register array processing */ #define I2C_MSG_LENGTH 1 #define I2C_RETRY_COUNT 5 @@ -196,11 +194,6 @@ struct gc0310_write_ctrl { struct gc0310_write_buffer buffer; }; -static const struct i2c_device_id gc0310_id[] = { - {GC0310_NAME, 0}, - {} -}; - /* * Register settings for various resolution */ diff --git a/drivers/staging/media/atomisp/i2c/gc2235.h b/drivers/staging/media/atomisp/i2c/gc2235.h index a8d6aa9c9a5d..3c30a05c3991 100644 --- a/drivers/staging/media/atomisp/i2c/gc2235.h +++ b/drivers/staging/media/atomisp/i2c/gc2235.h @@ -33,8 +33,6 @@ #include "../include/linux/atomisp_platform.h" -#define GC2235_NAME "gc2235" - /* Defines for register writes and register array processing */ #define I2C_MSG_LENGTH 0x2 #define I2C_RETRY_COUNT 5 @@ -200,11 +198,6 @@ struct gc2235_write_ctrl { struct gc2235_write_buffer buffer; }; -static const struct i2c_device_id gc2235_id[] = { - {GC2235_NAME, 0}, - {} -}; - static struct gc2235_reg const gc2235_stream_on[] = { { GC2235_8BIT, 0xfe, 0x03}, /* switch to P3 */ { GC2235_8BIT, 0x10, 0x91}, /* start mipi */ diff --git a/drivers/staging/media/atomisp/i2c/mt9m114.h b/drivers/staging/media/atomisp/i2c/mt9m114.h index 5e7d79d2e01b..1ad1b1ac55e7 100644 --- a/drivers/staging/media/atomisp/i2c/mt9m114.h +++ b/drivers/staging/media/atomisp/i2c/mt9m114.h @@ -394,11 +394,6 @@ static struct mt9m114_res_struct mt9m114_res[] = { }; #define N_RES (ARRAY_SIZE(mt9m114_res)) -static const struct i2c_device_id mt9m114_id[] = { - {"mt9m114", 0}, - {} -}; - static struct misensor_reg const mt9m114_exitstandby[] = { {MISENSOR_16BIT, 0x098E, 0xDC00}, /* exit-standby */ diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index ab8907e6c9ef..198c158de3f2 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -35,10 +35,6 @@ #include "../include/linux/atomisp_platform.h" -#define OV2680_NAME "ov2680" -#define OV2680B_NAME "ov2680b" -#define OV2680F_NAME "ov2680f" - /* Defines for register writes and register array processing */ #define I2C_MSG_LENGTH 0x2 #define I2C_RETRY_COUNT 5 @@ -227,12 +223,6 @@ struct ov2680_format { struct ov2680_write_buffer buffer; }; - static const struct i2c_device_id ov2680_id[] = { - {OV2680B_NAME, 0}, - {OV2680F_NAME, 0}, - {} - }; - static struct ov2680_reg const ov2680_global_setting[] = { {OV2680_8BIT, 0x0103, 0x01}, {OV2680_8BIT, 0x3002, 0x00}, diff --git a/drivers/staging/media/atomisp/i2c/ov2722.h b/drivers/staging/media/atomisp/i2c/ov2722.h index 73ecb1679718..3ee8eaadba49 100644 --- a/drivers/staging/media/atomisp/i2c/ov2722.h +++ b/drivers/staging/media/atomisp/i2c/ov2722.h @@ -35,8 +35,6 @@ #include "../include/linux/atomisp_platform.h" -#define OV2722_NAME "ov2722" - #define OV2722_POWER_UP_RETRY_NUM 5 /* Defines for register writes and register array processing */ @@ -257,11 +255,6 @@ struct ov2722_write_ctrl { struct ov2722_write_buffer buffer; }; -static const struct i2c_device_id ov2722_id[] = { - {OV2722_NAME, 0}, - {} -}; - /* * Register settings for various resolution */ diff --git a/drivers/staging/media/atomisp/i2c/ov5693/Kconfig b/drivers/staging/media/atomisp/i2c/ov5693/Kconfig index 5fe4113bbf08..3f527f2047a7 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/Kconfig +++ b/drivers/staging/media/atomisp/i2c/ov5693/Kconfig @@ -1,5 +1,6 @@ config VIDEO_ATOMISP_OV5693 tristate "Omnivision ov5693 sensor support" + depends on ACPI depends on I2C && VIDEO_V4L2 ---help--- This is a Video4Linux2 sensor-level driver for the Micron @@ -8,4 +9,3 @@ config VIDEO_ATOMISP_OV5693 ov5693 is video camera sensor. It currently only works with the atomisp driver. - diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c index 0a2b9e64f2c8..863cf2d9297f 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c +++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c @@ -1935,8 +1935,7 @@ static int ov5693_remove(struct i2c_client *client) return 0; } -static int ov5693_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ov5693_probe(struct i2c_client *client) { struct ov5693_device *dev; int i2c; @@ -2021,8 +2020,6 @@ out_free: return ret; } -MODULE_DEVICE_TABLE(i2c, ov5693_id); - static const struct acpi_device_id ov5693_acpi_match[] = { {"INT33BE"}, {}, @@ -2031,12 +2028,11 @@ MODULE_DEVICE_TABLE(acpi, ov5693_acpi_match); static struct i2c_driver ov5693_driver = { .driver = { - .name = OV5693_NAME, - .acpi_match_table = ACPI_PTR(ov5693_acpi_match), + .name = "ov5693", + .acpi_match_table = ov5693_acpi_match, }, - .probe = ov5693_probe, + .probe_new = ov5693_probe, .remove = ov5693_remove, - .id_table = ov5693_id, }; module_i2c_driver(ov5693_driver); diff --git a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h index 8c2e6794463b..b94a72a300d4 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h +++ b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h @@ -35,8 +35,6 @@ #include "../../include/linux/atomisp_platform.h" -#define OV5693_NAME "ov5693" - #define OV5693_POWER_UP_RETRY_NUM 5 /* Defines for register writes and register array processing */ @@ -278,11 +276,6 @@ struct ov5693_write_ctrl { struct ov5693_write_buffer buffer; }; -static const struct i2c_device_id ov5693_id[] = { - {OV5693_NAME, 0}, - {} -}; - static struct ov5693_reg const ov5693_global_setting[] = { {OV5693_8BIT, 0x0103, 0x01}, {OV5693_8BIT, 0x3001, 0x0a}, diff --git a/drivers/staging/media/atomisp/i2c/ov8858.c b/drivers/staging/media/atomisp/i2c/ov8858.c index 3ea157c7ee03..10383b8b6ecb 100644 --- a/drivers/staging/media/atomisp/i2c/ov8858.c +++ b/drivers/staging/media/atomisp/i2c/ov8858.c @@ -2080,8 +2080,7 @@ static const struct v4l2_ctrl_config ctrls[] = { } }; -static int ov8858_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ov8858_probe(struct i2c_client *client) { struct ov8858_device *dev; unsigned int i; @@ -2097,8 +2096,6 @@ static int ov8858_probe(struct i2c_client *client, mutex_init(&dev->input_lock); - if (id) - dev->i2c_id = id->driver_data; dev->fmt_idx = 0; dev->sensor_id = OV_ID_DEFAULT; dev->vcm_driver = &ov8858_vcms[OV8858_ID_DEFAULT]; @@ -2178,26 +2175,19 @@ out_free: return ret; } -static const struct i2c_device_id ov8858_id[] = { - {OV8858_NAME, 0}, - {} -}; - -MODULE_DEVICE_TABLE(i2c, ov8858_id); - static const struct acpi_device_id ov8858_acpi_match[] = { {"INT3477"}, {}, }; +MODULE_DEVICE_TABLE(acpi, ov8858_acpi_match); static struct i2c_driver ov8858_driver = { .driver = { - .name = OV8858_NAME, - .acpi_match_table = ACPI_PTR(ov8858_acpi_match), + .name = "ov8858", + .acpi_match_table = ov8858_acpi_match, }, - .probe = ov8858_probe, + .probe_new = ov8858_probe, .remove = ov8858_remove, - .id_table = ov8858_id, }; module_i2c_driver(ov8858_driver); diff --git a/drivers/staging/media/atomisp/i2c/ov8858.h b/drivers/staging/media/atomisp/i2c/ov8858.h index 638d1a803a2b..0f1b76e49a34 100644 --- a/drivers/staging/media/atomisp/i2c/ov8858.h +++ b/drivers/staging/media/atomisp/i2c/ov8858.h @@ -113,7 +113,6 @@ #define OV_SUBDEV_PREFIX "ov" #define OV_ID_DEFAULT 0x0000 -#define OV8858_NAME "ov8858" #define OV8858_CHIP_ID 0x8858 #define OV8858_LONG_EXPO 0x3500 diff --git a/drivers/staging/media/atomisp/i2c/ov8858_btns.h b/drivers/staging/media/atomisp/i2c/ov8858_btns.h index 7d74a8899fae..5cf03c220876 100644 --- a/drivers/staging/media/atomisp/i2c/ov8858_btns.h +++ b/drivers/staging/media/atomisp/i2c/ov8858_btns.h @@ -113,7 +113,6 @@ #define OV_SUBDEV_PREFIX "ov" #define OV_ID_DEFAULT 0x0000 -#define OV8858_NAME "ov8858" #define OV8858_CHIP_ID 0x8858 #define OV8858_LONG_EXPO 0x3500 diff --git a/drivers/staging/media/atomisp/include/media/lm3554.h b/drivers/staging/media/atomisp/include/media/lm3554.h index 7d6a8c05dd52..df17d546f661 100644 --- a/drivers/staging/media/atomisp/include/media/lm3554.h +++ b/drivers/staging/media/atomisp/include/media/lm3554.h @@ -24,7 +24,6 @@ #include #include -#define LM3554_NAME "lm3554" #define LM3554_ID 3554 #define v4l2_queryctrl_entry_integer(_id, _name,\ -- cgit v1.2.3 From 81050aff3093bd34c186e36ac4b6be2a7eb17d5d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 27 Sep 2017 14:25:00 -0400 Subject: media: staging: atomisp: Do not set GPIO twice gpiod_get() configures GPIO line at the time of successful request. Thus, no need to do this explicitly. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../atomisp/platform/intel-mid/atomisp_gmin_platform.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c index 8c6a26eea095..704d66b83106 100644 --- a/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c @@ -409,21 +409,11 @@ static struct gmin_subdev *gmin_subdev_add(struct v4l2_subdev *subdev) if (!ret) clk_disable_unprepare(gmin_subdevs[i].pmc_clk); - if (!IS_ERR(gmin_subdevs[i].gpio0)) { - ret = gpiod_direction_output(gmin_subdevs[i].gpio0, 0); - if (ret) - dev_err(dev, "gpio0 set output failed: %d\n", ret); - } else { + if (IS_ERR(gmin_subdevs[i].gpio0)) gmin_subdevs[i].gpio0 = NULL; - } - if (!IS_ERR(gmin_subdevs[i].gpio1)) { - ret = gpiod_direction_output(gmin_subdevs[i].gpio1, 0); - if (ret) - dev_err(dev, "gpio1 set output failed: %d\n", ret); - } else { + if (IS_ERR(gmin_subdevs[i].gpio1)) gmin_subdevs[i].gpio1 = NULL; - } if (pmic_id == PMIC_REGULATOR) { gmin_subdevs[i].v1p8_reg = regulator_get(dev, "V1P8SX"); -- cgit v1.2.3 From d2cde88348ec2d0cfaad5cd3f6339eeef69e5c7f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 27 Sep 2017 14:25:01 -0400 Subject: media: staging: atomisp: Remove unneeded gpio.h inclusion GPIO handling is done only in two modules, the rest do not need to include linux/gpio.h header. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-gc0310.c | 1 - drivers/staging/media/atomisp/i2c/atomisp-gc2235.c | 1 - drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c | 1 - drivers/staging/media/atomisp/i2c/atomisp-ov2680.c | 1 - drivers/staging/media/atomisp/i2c/atomisp-ov2722.c | 1 - drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c | 1 - 6 files changed, 6 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c index aafa4db55a57..5fd4e9486a99 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c index ab64598c482f..aa6bde6d4d01 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include "../include/linux/atomisp_gmin_platform.h" diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index b80f86e6d91a..cd4765e2cc23 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include "../include/linux/atomisp_gmin_platform.h" #include diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 219a856fc34e..d44d4d4d2dee 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c index ac827e302654..d1f149e7599a 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include "../include/linux/atomisp_gmin_platform.h" diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c index 863cf2d9297f..796d33de2f08 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c +++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 32471bdaa28291e18108d91f7b1c56b68e032c03 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 27 Sep 2017 14:25:02 -0400 Subject: media: staging: atomisp: Remove ->gpio_ctrl() callback There is redundant callback which does nothing in upstreamed version of the driver. Remove it along with user call places. Mostly done with help of coccinelle. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-gc0310.c | 4 ---- drivers/staging/media/atomisp/i2c/atomisp-gc2235.c | 4 ---- drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c | 4 ---- drivers/staging/media/atomisp/i2c/atomisp-ov2680.c | 4 ---- drivers/staging/media/atomisp/i2c/atomisp-ov2722.c | 4 ---- drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c | 4 ---- drivers/staging/media/atomisp/i2c/ov8858.c | 4 ---- drivers/staging/media/atomisp/include/linux/atomisp_platform.h | 2 -- 8 files changed, 30 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c index 5fd4e9486a99..70cc041f549c 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c @@ -771,10 +771,6 @@ static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) if (!dev || !dev->platform_data) return -ENODEV; - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->gpio_ctrl) - return dev->platform_data->gpio_ctrl(sd, flag); - /* GPIO0 == "reset" (active low), GPIO1 == "power down" */ if (flag) { /* Pulse reset, then release power down */ diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c index aa6bde6d4d01..9a97db696f55 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -571,10 +571,6 @@ static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) if (!dev || !dev->platform_data) return -ENODEV; - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->gpio_ctrl) - return dev->platform_data->gpio_ctrl(sd, flag); - ret |= dev->platform_data->gpio1_ctrl(sd, !flag); usleep_range(60, 90); return dev->platform_data->gpio0_ctrl(sd, flag); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index cd4765e2cc23..81f90bc3f4e2 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -480,10 +480,6 @@ static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) if (!dev || !dev->platform_data) return -ENODEV; - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->gpio_ctrl) - return dev->platform_data->gpio_ctrl(sd, flag); - /* Note: current modules wire only one GPIO signal (RESET#), * but the schematic wires up two to the connector. BIOS * versions have been unfortunately inconsistent with which diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index d44d4d4d2dee..041e30f75817 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -871,10 +871,6 @@ static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) if (!dev || !dev->platform_data) return -ENODEV; - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->gpio_ctrl) - return dev->platform_data->gpio_ctrl(sd, flag); - /* The OV2680 documents only one GPIO input (#XSHUTDN), but * existing integrations often wire two (reset/power_down) * because that is the way other sensors work. There is no diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c index d1f149e7599a..80f6aa0472ce 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -677,10 +677,6 @@ static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) if (!dev || !dev->platform_data) return -ENODEV; - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->gpio_ctrl) - return dev->platform_data->gpio_ctrl(sd, flag); - /* Note: the GPIO order is asymmetric: always RESET# * before PWDN# when turning it on or off. */ diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c index 796d33de2f08..8091817dead6 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c +++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c @@ -1332,10 +1332,6 @@ static int gpio_ctrl(struct v4l2_subdev *sd, bool flag) if (!dev || !dev->platform_data) return -ENODEV; - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->gpio_ctrl) - return dev->platform_data->gpio_ctrl(sd, flag); - return dev->platform_data->gpio0_ctrl(sd, flag); } diff --git a/drivers/staging/media/atomisp/i2c/ov8858.c b/drivers/staging/media/atomisp/i2c/ov8858.c index 10383b8b6ecb..00f2ca6ab939 100644 --- a/drivers/staging/media/atomisp/i2c/ov8858.c +++ b/drivers/staging/media/atomisp/i2c/ov8858.c @@ -767,10 +767,6 @@ static int __gpio_ctrl(struct v4l2_subdev *sd, bool flag) if (!client || !dev || !dev->platform_data) return -ENODEV; - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->gpio_ctrl) - return dev->platform_data->gpio_ctrl(sd, flag); - if (dev->platform_data->gpio0_ctrl) return dev->platform_data->gpio0_ctrl(sd, flag); diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h index dbac2b777dad..94ddb46d415b 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h @@ -205,7 +205,6 @@ struct camera_vcm_control { }; struct camera_sensor_platform_data { - int (*gpio_ctrl)(struct v4l2_subdev *subdev, int flag); int (*flisclk_ctrl)(struct v4l2_subdev *subdev, int flag); int (*power_ctrl)(struct v4l2_subdev *subdev, int flag); int (*csi_cfg)(struct v4l2_subdev *subdev, int flag); @@ -214,7 +213,6 @@ struct camera_sensor_platform_data { int (*platform_deinit)(void); char *(*msr_file_name)(void); struct atomisp_camera_caps *(*get_camera_caps)(void); - int (*gpio_intr_ctrl)(struct v4l2_subdev *subdev); /* New G-Min power and GPIO interface, replaces * power/gpio_ctrl with methods to control individual -- cgit v1.2.3 From ab9a68834a43c6a6b30d835268615a0c7734515e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 27 Sep 2017 14:25:03 -0400 Subject: media: staging: atomisp: Remove ->power_ctrl() callback There is redundant callback which does nothing in upstreamed version of the driver. Remove it along with user call places. Mostly done with help of coccinelle. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-gc0310.c | 4 ---- drivers/staging/media/atomisp/i2c/atomisp-gc2235.c | 4 ---- drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c | 4 ---- drivers/staging/media/atomisp/i2c/atomisp-ov2680.c | 4 ---- drivers/staging/media/atomisp/i2c/atomisp-ov2722.c | 4 ---- drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c | 4 ---- drivers/staging/media/atomisp/i2c/ov8858.c | 4 ---- drivers/staging/media/atomisp/include/linux/atomisp_platform.h | 8 ++++---- 8 files changed, 4 insertions(+), 32 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c index 70cc041f549c..5d2fe23347a1 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c @@ -737,10 +737,6 @@ static int power_ctrl(struct v4l2_subdev *sd, bool flag) if (!dev || !dev->platform_data) return -ENODEV; - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->power_ctrl) - return dev->platform_data->power_ctrl(sd, flag); - if (flag) { /* The upstream module driver (written to Crystal * Cove) had this logic to pulse the rails low first. diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c index 9a97db696f55..ccbc3df92dff 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -547,10 +547,6 @@ static int power_ctrl(struct v4l2_subdev *sd, bool flag) if (!dev || !dev->platform_data) return -ENODEV; - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->power_ctrl) - return dev->platform_data->power_ctrl(sd, flag); - if (flag) { ret = dev->platform_data->v1p8_ctrl(sd, 1); usleep_range(60, 90); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index 81f90bc3f4e2..7c3ecc6f2c65 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -454,10 +454,6 @@ static int power_ctrl(struct v4l2_subdev *sd, bool flag) if (!dev || !dev->platform_data) return -ENODEV; - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->power_ctrl) - return dev->platform_data->power_ctrl(sd, flag); - if (flag) { ret = dev->platform_data->v2p8_ctrl(sd, 1); if (ret == 0) { diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 041e30f75817..588bc0b15411 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -846,10 +846,6 @@ static int power_ctrl(struct v4l2_subdev *sd, bool flag) if (!dev || !dev->platform_data) return -ENODEV; - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->power_ctrl) - return dev->platform_data->power_ctrl(sd, flag); - if (flag) { ret |= dev->platform_data->v1p8_ctrl(sd, 1); ret |= dev->platform_data->v2p8_ctrl(sd, 1); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c index 80f6aa0472ce..50ee36da7109 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -650,10 +650,6 @@ static int power_ctrl(struct v4l2_subdev *sd, bool flag) if (!dev || !dev->platform_data) return -ENODEV; - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->power_ctrl) - return dev->platform_data->power_ctrl(sd, flag); - if (flag) { ret = dev->platform_data->v1p8_ctrl(sd, 1); if (ret == 0) { diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c index 8091817dead6..d45a810cfcee 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c +++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c @@ -1297,10 +1297,6 @@ static int power_ctrl(struct v4l2_subdev *sd, bool flag) if (!dev || !dev->platform_data) return -ENODEV; - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->power_ctrl) - return dev->platform_data->power_ctrl(sd, flag); - /* This driver assumes "internal DVDD, PWDNB tied to DOVDD". * In this set up only gpio0 (XSHUTDN) should be available * but in some products (for example ECS) gpio1 (PWDNB) is diff --git a/drivers/staging/media/atomisp/i2c/ov8858.c b/drivers/staging/media/atomisp/i2c/ov8858.c index 00f2ca6ab939..75f64d1a5f77 100644 --- a/drivers/staging/media/atomisp/i2c/ov8858.c +++ b/drivers/staging/media/atomisp/i2c/ov8858.c @@ -712,10 +712,6 @@ static int __power_ctrl(struct v4l2_subdev *sd, bool flag) if (!dev || !dev->platform_data) return -ENODEV; - /* Non-gmin platforms use the legacy callback */ - if (dev->platform_data->power_ctrl) - return dev->platform_data->power_ctrl(sd, flag); - if (dev->platform_data->v1p2_ctrl) { ret = dev->platform_data->v1p2_ctrl(sd, flag); if (ret) { diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h index 94ddb46d415b..5ce8678dacf3 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h @@ -206,7 +206,6 @@ struct camera_vcm_control { struct camera_sensor_platform_data { int (*flisclk_ctrl)(struct v4l2_subdev *subdev, int flag); - int (*power_ctrl)(struct v4l2_subdev *subdev, int flag); int (*csi_cfg)(struct v4l2_subdev *subdev, int flag); bool (*low_fps)(void); int (*platform_init)(struct i2c_client *); @@ -214,9 +213,10 @@ struct camera_sensor_platform_data { char *(*msr_file_name)(void); struct atomisp_camera_caps *(*get_camera_caps)(void); - /* New G-Min power and GPIO interface, replaces - * power/gpio_ctrl with methods to control individual - * lines as implemented on all known camera modules. */ + /* + * New G-Min power and GPIO interface to control individual + * lines as implemented on all known camera modules. + */ int (*gpio0_ctrl)(struct v4l2_subdev *subdev, int on); int (*gpio1_ctrl)(struct v4l2_subdev *subdev, int on); int (*v1p8_ctrl)(struct v4l2_subdev *subdev, int on); -- cgit v1.2.3 From a760bca51edc9410d409a87a96319798a1b9a00b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 27 Sep 2017 14:25:07 -0400 Subject: media: staging: atomisp: Remove duplicate declaration in header There are 3 declarations that are present in atomisp_platform.h and atomisp_gmin_platform.h. Remove duplications from the latter. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h index 5390b97ac6e7..7e3ca12dd4e9 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp_gmin_platform.h @@ -17,9 +17,6 @@ #include "atomisp_platform.h" -const struct atomisp_camera_caps *atomisp_get_default_camera_caps(void); -const struct atomisp_platform_data *atomisp_get_platform_data(void); -const struct camera_af_platform_data *camera_get_af_platform_data(void); int atomisp_register_i2c_module(struct v4l2_subdev *subdev, struct camera_sensor_platform_data *plat_data, enum intel_v4l2_subdev_type type); -- cgit v1.2.3 From 4eee79141bc51ff5de9145f50298d8495dc67a8b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 27 Sep 2017 14:25:04 -0400 Subject: media: staging: atomisp: Remove unused members of camera_sensor_platform_data Remove unused members along with dead code. Mostly done with help of coccinelle. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-gc0310.c | 13 ------------- drivers/staging/media/atomisp/i2c/atomisp-gc2235.c | 13 ------------- drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c | 9 --------- drivers/staging/media/atomisp/i2c/atomisp-ov2722.c | 13 ------------- drivers/staging/media/atomisp/i2c/ov8858.c | 13 ------------- .../staging/media/atomisp/include/linux/atomisp_platform.h | 5 ----- drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c | 9 +-------- .../atomisp/platform/intel-mid/atomisp_gmin_platform.c | 12 ------------ 8 files changed, 1 insertion(+), 86 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c index 5d2fe23347a1..e70d8afcc229 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc0310.c @@ -1156,13 +1156,6 @@ static int gc0310_s_config(struct v4l2_subdev *sd, (struct camera_sensor_platform_data *)platform_data; mutex_lock(&dev->input_lock); - if (dev->platform_data->platform_init) { - ret = dev->platform_data->platform_init(client); - if (ret) { - dev_err(&client->dev, "platform init err\n"); - goto platform_init_failed; - } - } /* power off the module, then power on it in future * as first power on by board may not fulfill the * power on sequqence needed by the module @@ -1207,9 +1200,6 @@ fail_power_on: power_down(sd); dev_err(&client->dev, "sensor power-gating failed\n"); fail_power_off: - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); -platform_init_failed: mutex_unlock(&dev->input_lock); return ret; } @@ -1353,9 +1343,6 @@ static int gc0310_remove(struct i2c_client *client) struct gc0310_device *dev = to_gc0310_sensor(sd); dev_dbg(&client->dev, "gc0310_remove...\n"); - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); - dev->platform_data->csi_cfg(sd, 0); v4l2_device_unregister_subdev(sd); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c index ccbc3df92dff..85da5fe24033 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-gc2235.c @@ -897,13 +897,6 @@ static int gc2235_s_config(struct v4l2_subdev *sd, (struct camera_sensor_platform_data *)platform_data; mutex_lock(&dev->input_lock); - if (dev->platform_data->platform_init) { - ret = dev->platform_data->platform_init(client); - if (ret) { - dev_err(&client->dev, "platform init err\n"); - goto platform_init_failed; - } - } /* power off the module, then power on it in future * as first power on by board may not fulfill the * power on sequqence needed by the module @@ -947,9 +940,6 @@ fail_power_on: power_down(sd); dev_err(&client->dev, "sensor power-gating failed\n"); fail_power_off: - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); -platform_init_failed: mutex_unlock(&dev->input_lock); return ret; } @@ -1092,9 +1082,6 @@ static int gc2235_remove(struct i2c_client *client) struct gc2235_device *dev = to_gc2235_sensor(sd); dev_dbg(&client->dev, "gc2235_remove...\n"); - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); - dev->platform_data->csi_cfg(sd, 0); v4l2_device_unregister_subdev(sd); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index 7c3ecc6f2c65..706eea52e36f 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -1575,13 +1575,6 @@ mt9m114_s_config(struct v4l2_subdev *sd, int irq, void *platform_data) dev->platform_data = (struct camera_sensor_platform_data *)platform_data; - if (dev->platform_data->platform_init) { - ret = dev->platform_data->platform_init(client); - if (ret) { - v4l2_err(client, "mt9m114 platform init err\n"); - return ret; - } - } ret = power_up(sd); if (ret) { v4l2_err(client, "mt9m114 power-up err"); @@ -1835,8 +1828,6 @@ static int mt9m114_remove(struct i2c_client *client) dev = container_of(sd, struct mt9m114_device, sd); dev->platform_data->csi_cfg(sd, 0); - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); v4l2_device_unregister_subdev(sd); media_entity_cleanup(&dev->sd.entity); v4l2_ctrl_handler_free(&dev->ctrl_handler); diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c index 50ee36da7109..4df7eba8d375 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2722.c @@ -1035,13 +1035,6 @@ static int ov2722_s_config(struct v4l2_subdev *sd, (struct camera_sensor_platform_data *)platform_data; mutex_lock(&dev->input_lock); - if (dev->platform_data->platform_init) { - ret = dev->platform_data->platform_init(client); - if (ret) { - dev_err(&client->dev, "platform init err\n"); - goto platform_init_failed; - } - } /* power off the module, then power on it in future * as first power on by board may not fulfill the @@ -1086,9 +1079,6 @@ fail_power_on: power_down(sd); dev_err(&client->dev, "sensor power-gating failed\n"); fail_power_off: - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); -platform_init_failed: mutex_unlock(&dev->input_lock); return ret; } @@ -1232,9 +1222,6 @@ static int ov2722_remove(struct i2c_client *client) struct ov2722_device *dev = to_ov2722_sensor(sd); dev_dbg(&client->dev, "ov2722_remove...\n"); - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); - dev->platform_data->csi_cfg(sd, 0); v4l2_ctrl_handler_free(&dev->ctrl_handler); v4l2_device_unregister_subdev(sd); diff --git a/drivers/staging/media/atomisp/i2c/ov8858.c b/drivers/staging/media/atomisp/i2c/ov8858.c index 75f64d1a5f77..51d65931dc03 100644 --- a/drivers/staging/media/atomisp/i2c/ov8858.c +++ b/drivers/staging/media/atomisp/i2c/ov8858.c @@ -1565,15 +1565,6 @@ static int ov8858_s_config(struct v4l2_subdev *sd, mutex_lock(&dev->input_lock); - if (dev->platform_data->platform_init) { - ret = dev->platform_data->platform_init(client); - if (ret) { - mutex_unlock(&dev->input_lock); - dev_err(&client->dev, "platform init error %d!\n", ret); - return ret; - } - } - ret = __ov8858_s_power(sd, 1); if (ret) { dev_err(&client->dev, "power-up error %d!\n", ret); @@ -1618,8 +1609,6 @@ fail_detect: fail_csi_cfg: __ov8858_s_power(sd, 0); fail_update: - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); mutex_unlock(&dev->input_lock); dev_err(&client->dev, "sensor power-gating failed\n"); return ret; @@ -1920,8 +1909,6 @@ static int ov8858_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); struct ov8858_device *dev = to_ov8858_sensor(sd); - if (dev->platform_data->platform_deinit) - dev->platform_data->platform_deinit(); media_entity_cleanup(&dev->sd.entity); v4l2_ctrl_handler_free(&dev->ctrl_handler); diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h index 5ce8678dacf3..a8c1825e1d0d 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h @@ -207,11 +207,6 @@ struct camera_vcm_control { struct camera_sensor_platform_data { int (*flisclk_ctrl)(struct v4l2_subdev *subdev, int flag); int (*csi_cfg)(struct v4l2_subdev *subdev, int flag); - bool (*low_fps)(void); - int (*platform_init)(struct i2c_client *); - int (*platform_deinit)(void); - char *(*msr_file_name)(void); - struct atomisp_camera_caps *(*get_camera_caps)(void); /* * New G-Min power and GPIO interface to control individual diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c index 20aff7faf44a..6d2920155fa4 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c @@ -750,7 +750,6 @@ static int atomisp_subdev_probe(struct atomisp_device *isp) &subdevs->v4l2_subdev.board_info; struct i2c_adapter *adapter = i2c_get_adapter(subdevs->v4l2_subdev.i2c_adapter_id); - struct camera_sensor_platform_data *sensor_pdata; int sensor_num, i; if (adapter == NULL) { @@ -802,13 +801,7 @@ static int atomisp_subdev_probe(struct atomisp_device *isp) * pixel_format. */ isp->inputs[isp->input_cnt].frame_size.pixel_format = 0; - sensor_pdata = (struct camera_sensor_platform_data *) - board_info->platform_data; - if (sensor_pdata->get_camera_caps) - isp->inputs[isp->input_cnt].camera_caps = - sensor_pdata->get_camera_caps(); - else - isp->inputs[isp->input_cnt].camera_caps = + isp->inputs[isp->input_cnt].camera_caps = atomisp_get_default_camera_caps(); sensor_num = isp->inputs[isp->input_cnt] .camera_caps->sensor_num; diff --git a/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c index 704d66b83106..129608a7b792 100644 --- a/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c @@ -332,16 +332,6 @@ static const struct { #define CFG_VAR_NAME_MAX 64 -static int gmin_platform_init(struct i2c_client *client) -{ - return 0; -} - -static int gmin_platform_deinit(void) -{ - return 0; -} - #define GMIN_PMC_CLK_NAME 14 /* "pmc_plt_clk_[0..5]" */ static char gmin_pmc_clk_name[GMIN_PMC_CLK_NAME]; @@ -628,8 +618,6 @@ static struct camera_sensor_platform_data gmin_plat = { .v2p8_ctrl = gmin_v2p8_ctrl, .v1p2_ctrl = gmin_v1p2_ctrl, .flisclk_ctrl = gmin_flisclk_ctrl, - .platform_init = gmin_platform_init, - .platform_deinit = gmin_platform_deinit, .csi_cfg = gmin_csi_cfg, .get_vcm_ctrl = gmin_get_vcm_ctrl, }; -- cgit v1.2.3 From 3118eea4cfc705768411447604e70457c19bc1b3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 27 Sep 2017 14:25:05 -0400 Subject: media: staging: atomisp: Remove Gmin dead code #1 struct camera_af_platform_data and bound functions are not used anywhere. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../media/atomisp/include/linux/atomisp_platform.h | 6 --- .../platform/intel-mid/atomisp_gmin_platform.c | 43 ---------------------- 2 files changed, 49 deletions(-) diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h index a8c1825e1d0d..2dae4935ed75 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h @@ -221,12 +221,6 @@ struct camera_sensor_platform_data { char *module_id); }; -struct camera_af_platform_data { - int (*power_ctrl)(struct v4l2_subdev *subdev, int flag); -}; - -const struct camera_af_platform_data *camera_get_af_platform_data(void); - struct camera_mipi_info { enum atomisp_camera_port port; unsigned int num_lanes; diff --git a/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c b/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c index 129608a7b792..bf9f34b7ad72 100644 --- a/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c +++ b/drivers/staging/media/atomisp/platform/intel-mid/atomisp_gmin_platform.c @@ -106,49 +106,6 @@ const struct atomisp_platform_data *atomisp_get_platform_data(void) } EXPORT_SYMBOL_GPL(atomisp_get_platform_data); -static int af_power_ctrl(struct v4l2_subdev *subdev, int flag) -{ - struct gmin_subdev *gs = find_gmin_subdev(subdev); - - if (gs && gs->v2p8_vcm_on == flag) - return 0; - gs->v2p8_vcm_on = flag; - - /* - * The power here is used for dw9817, - * regulator is from rear sensor - */ - if (gs->v2p8_vcm_reg) { - if (flag) - return regulator_enable(gs->v2p8_vcm_reg); - else - return regulator_disable(gs->v2p8_vcm_reg); - } - return 0; -} - -/* - * Used in a handful of modules. Focus motor control, I think. Note - * that there is no configurability in the API, so this needs to be - * fixed where it is used. - * - * struct camera_af_platform_data { - * int (*power_ctrl)(struct v4l2_subdev *subdev, int flag); - * }; - * - * Note that the implementation in MCG platform_camera.c is stubbed - * out anyway (i.e. returns zero from the callback) on BYT. So - * neither needed on gmin platforms or supported upstream. - */ -const struct camera_af_platform_data *camera_get_af_platform_data(void) -{ - static struct camera_af_platform_data afpd = { - .power_ctrl = af_power_ctrl, - }; - return &afpd; -} -EXPORT_SYMBOL_GPL(camera_get_af_platform_data); - int atomisp_register_i2c_module(struct v4l2_subdev *subdev, struct camera_sensor_platform_data *plat_data, enum intel_v4l2_subdev_type type) -- cgit v1.2.3 From 3a698c9fd7cfeaf1a79c46d289f3dad94300b96a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 27 Sep 2017 14:25:06 -0400 Subject: media: staging: atomisp: Remove Gmin dead code #2 media/lm3642.h is not used anywhere. Moreover, there is a driver under LEDs framework for very same IP which would be used anyway. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- .../staging/media/atomisp/include/media/lm3642.h | 153 --------------------- 1 file changed, 153 deletions(-) delete mode 100644 drivers/staging/media/atomisp/include/media/lm3642.h diff --git a/drivers/staging/media/atomisp/include/media/lm3642.h b/drivers/staging/media/atomisp/include/media/lm3642.h deleted file mode 100644 index 545d95763335..000000000000 --- a/drivers/staging/media/atomisp/include/media/lm3642.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * include/media/lm3642.h - * - * Copyright (c) 2010-2012 Intel Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. - */ - -#ifndef _LM3642_H_ -#define _LM3642_H_ - -#include -#include - -#define LM3642_NAME "lm3642" -#define LM3642_ID 3642 - -#define v4l2_queryctrl_entry_integer(_id, _name,\ - _minimum, _maximum, _step, \ - _default_value, _flags) \ - {\ - .id = (_id), \ - .type = V4L2_CTRL_TYPE_INTEGER, \ - .name = _name, \ - .minimum = (_minimum), \ - .maximum = (_maximum), \ - .step = (_step), \ - .default_value = (_default_value),\ - .flags = (_flags),\ - } -#define v4l2_queryctrl_entry_boolean(_id, _name,\ - _default_value, _flags) \ - {\ - .id = (_id), \ - .type = V4L2_CTRL_TYPE_BOOLEAN, \ - .name = _name, \ - .minimum = 0, \ - .maximum = 1, \ - .step = 1, \ - .default_value = (_default_value),\ - .flags = (_flags),\ - } - -#define s_ctrl_id_entry_integer(_id, _name, \ - _minimum, _maximum, _step, \ - _default_value, _flags, \ - _s_ctrl, _g_ctrl) \ - {\ - .qc = v4l2_queryctrl_entry_integer(_id, _name,\ - _minimum, _maximum, _step,\ - _default_value, _flags), \ - .s_ctrl = _s_ctrl, \ - .g_ctrl = _g_ctrl, \ - } - -#define s_ctrl_id_entry_boolean(_id, _name, \ - _default_value, _flags, \ - _s_ctrl, _g_ctrl) \ - {\ - .qc = v4l2_queryctrl_entry_boolean(_id, _name,\ - _default_value, _flags), \ - .s_ctrl = _s_ctrl, \ - .g_ctrl = _g_ctrl, \ - } - - -/* Default Values */ -#define LM3642_DEFAULT_TIMEOUT 300U -#define LM3642_DEFAULT_RAMP_TIME 0x10 /* 1.024ms */ -#define LM3642_DEFAULT_INDICATOR_CURRENT 0x01 /* 1.88A */ -#define LM3642_DEFAULT_FLASH_CURRENT 0x0f /* 1500mA */ - -/* Value settings for Flash Time-out Duration*/ -#define LM3642_MIN_TIMEOUT 100U -#define LM3642_MAX_TIMEOUT 800U -#define LM3642_TIMEOUT_STEPSIZE 100U - -/* Flash modes */ -#define LM3642_MODE_SHUTDOWN 0 -#define LM3642_MODE_INDICATOR 1 -#define LM3642_MODE_TORCH 2 -#define LM3642_MODE_FLASH 3 - -/* timer delay time */ -#define LM3642_TIMER_DELAY 5 - -/* Percentage <-> value macros */ -#define LM3642_MIN_PERCENT 0U -#define LM3642_MAX_PERCENT 100U -#define LM3642_CLAMP_PERCENTAGE(val) \ - clamp(val, LM3642_MIN_PERCENT, LM3642_MAX_PERCENT) - -#define LM3642_VALUE_TO_PERCENT(v, step) \ - (((((unsigned long)((v)+1))*(step))+50)/100) -#define LM3642_PERCENT_TO_VALUE(p, step) \ - (((((unsigned long)(p))*100)+((step)>>1))/(step)-1) - -/* Product specific limits - * TODO: get these from platform data */ -#define LM3642_FLASH_MAX_LVL 0x0F /* 1500mA */ -#define LM3642_TORCH_MAX_LVL 0x07 /* 187mA */ -#define LM3642_INDICATOR_MAX_LVL 0x01 /* 1.88A */ - -/* Flash brightness, input is percentage, output is [0..15] */ -#define LM3642_FLASH_STEP \ - ((100ul*(LM3642_MAX_PERCENT) \ - +((LM3642_FLASH_MAX_LVL+1)>>1)) \ - /((LM3642_FLASH_MAX_LVL+1))) -#define LM3642_FLASH_DEFAULT_BRIGHTNESS \ - LM3642_VALUE_TO_PERCENT(15, LM3642_FLASH_STEP) - -/* Torch brightness, input is percentage, output is [0..7] */ -#define LM3642_TORCH_STEP \ - ((100ul*(LM3642_MAX_PERCENT) \ - +((LM3642_TORCH_MAX_LVL+1)>>1)) \ - /((LM3642_TORCH_MAX_LVL+1))) -#define LM3642_TORCH_DEFAULT_BRIGHTNESS \ - LM3642_VALUE_TO_PERCENT(0, LM3642_TORCH_STEP) - -/* Indicator brightness, input is percentage, output is [0..1] */ -#define LM3642_INDICATOR_STEP \ - ((100ul*(LM3642_MAX_PERCENT) \ - +((LM3642_INDICATOR_MAX_LVL+1)>>1)) \ - /((LM3642_INDICATOR_MAX_LVL+1))) -#define LM3642_INDICATOR_DEFAULT_BRIGHTNESS \ - LM3642_VALUE_TO_PERCENT(1, LM3642_INDICATOR_STEP) - -/* - * lm3642_platform_data - Flash controller platform data - */ -struct lm3642_platform_data { - int gpio_torch; - int gpio_strobe; - int (*power_ctrl)(struct v4l2_subdev *subdev, int on); - - unsigned int torch_en; - unsigned int flash_en; - unsigned int tx_en; - unsigned int ivfm_en; -}; - -#endif /* _LM3642_H_ */ - -- cgit v1.2.3 From b5027c520f35979f702bf42b4e55640f4168c317 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 27 Sep 2017 14:25:08 -0400 Subject: media: staging: atomisp: Remove FSF snail address Snail address is subject to change, remove it completely from the code. This has been done using the following script: sed -i '/You should/,/02110-1301/d' \ $(git grep -n -w Franklin -- drivers/staging/media/atomisp/ | cut -f1 -d:) No functional change intended. Signed-off-by: Andy Shevchenko Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c | 4 ---- drivers/staging/media/atomisp/i2c/atomisp-lm3554.c | 4 ---- drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c | 4 ---- drivers/staging/media/atomisp/i2c/gc0310.h | 4 ---- drivers/staging/media/atomisp/i2c/mt9m114.h | 4 ---- drivers/staging/media/atomisp/i2c/ov2680.h | 4 ---- drivers/staging/media/atomisp/i2c/ov2722.h | 4 ---- drivers/staging/media/atomisp/i2c/ov5693/ad5823.h | 4 ---- drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c | 4 ---- drivers/staging/media/atomisp/i2c/ov5693/ov5693.h | 4 ---- drivers/staging/media/atomisp/i2c/ov8858.c | 4 ---- drivers/staging/media/atomisp/i2c/ov8858.h | 4 ---- drivers/staging/media/atomisp/i2c/ov8858_btns.h | 4 ---- drivers/staging/media/atomisp/include/linux/atomisp.h | 4 ---- drivers/staging/media/atomisp/include/linux/atomisp_platform.h | 4 ---- drivers/staging/media/atomisp/include/linux/libmsrlisthelper.h | 4 ---- drivers/staging/media/atomisp/include/media/lm3554.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp-regs.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_acc.c | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_acc.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_common.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_csi2.c | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_csi2.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_dfs_tables.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_drvfs.c | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_drvfs.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_file.c | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_file.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_helper.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_internal.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_tables.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_tpg.c | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_tpg.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_trace_event.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm.c | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_bo.c | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_dynamic_pool.c | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_reserved_pool.c | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_vm.c | 4 ---- .../media/atomisp/pci/atomisp2/hrt/hive_isp_css_custom_host_hrt.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/hrt/hive_isp_css_mm_hrt.c | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/hrt/hive_isp_css_mm_hrt.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_bo.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_bo_dev.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_common.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_pool.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_vm.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/include/mmu/isp_mmu.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/include/mmu/sh_mmu.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/include/mmu/sh_mmu_mrfld.h | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/mmu/isp_mmu.c | 4 ---- drivers/staging/media/atomisp/pci/atomisp2/mmu/sh_mmu_mrfld.c | 4 ---- 68 files changed, 272 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c b/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c index decb65cfd7c9..81e5ec0c2b64 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c @@ -10,10 +10,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #include diff --git a/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c index a4e8a55db587..a37ab5c5c9a3 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #include diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c index 706eea52e36f..55882bea2049 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/i2c/gc0310.h b/drivers/staging/media/atomisp/i2c/gc0310.h index 7e97e45b4f79..c422d0398fc7 100644 --- a/drivers/staging/media/atomisp/i2c/gc0310.h +++ b/drivers/staging/media/atomisp/i2c/gc0310.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/i2c/mt9m114.h b/drivers/staging/media/atomisp/i2c/mt9m114.h index 1ad1b1ac55e7..0af79d77a404 100644 --- a/drivers/staging/media/atomisp/i2c/mt9m114.h +++ b/drivers/staging/media/atomisp/i2c/mt9m114.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/i2c/ov2680.h b/drivers/staging/media/atomisp/i2c/ov2680.h index 198c158de3f2..bf4897347df7 100644 --- a/drivers/staging/media/atomisp/i2c/ov2680.h +++ b/drivers/staging/media/atomisp/i2c/ov2680.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/i2c/ov2722.h b/drivers/staging/media/atomisp/i2c/ov2722.h index 3ee8eaadba49..d8a973d71699 100644 --- a/drivers/staging/media/atomisp/i2c/ov2722.h +++ b/drivers/staging/media/atomisp/i2c/ov2722.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/i2c/ov5693/ad5823.h b/drivers/staging/media/atomisp/i2c/ov5693/ad5823.h index 2dd894989cd9..4de44569fe54 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/ad5823.h +++ b/drivers/staging/media/atomisp/i2c/ov5693/ad5823.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c index d45a810cfcee..50da7130f9ca 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c +++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h index b94a72a300d4..2ea63807c56d 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h +++ b/drivers/staging/media/atomisp/i2c/ov5693/ov5693.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/i2c/ov8858.c b/drivers/staging/media/atomisp/i2c/ov8858.c index 51d65931dc03..ba147ac2e36f 100644 --- a/drivers/staging/media/atomisp/i2c/ov8858.c +++ b/drivers/staging/media/atomisp/i2c/ov8858.c @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/i2c/ov8858.h b/drivers/staging/media/atomisp/i2c/ov8858.h index 0f1b76e49a34..6c89568bb44e 100644 --- a/drivers/staging/media/atomisp/i2c/ov8858.h +++ b/drivers/staging/media/atomisp/i2c/ov8858.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/i2c/ov8858_btns.h b/drivers/staging/media/atomisp/i2c/ov8858_btns.h index 5cf03c220876..f81851306832 100644 --- a/drivers/staging/media/atomisp/i2c/ov8858_btns.h +++ b/drivers/staging/media/atomisp/i2c/ov8858_btns.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/include/linux/atomisp.h b/drivers/staging/media/atomisp/include/linux/atomisp.h index d67dd658cff9..b5533197226d 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #ifdef CSS15 diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h index 2dae4935ed75..e0f0c379e7ce 100644 --- a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h +++ b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #ifndef ATOMISP_PLATFORM_H_ diff --git a/drivers/staging/media/atomisp/include/linux/libmsrlisthelper.h b/drivers/staging/media/atomisp/include/linux/libmsrlisthelper.h index 589f4eae38ca..8988b37943b3 100644 --- a/drivers/staging/media/atomisp/include/linux/libmsrlisthelper.h +++ b/drivers/staging/media/atomisp/include/linux/libmsrlisthelper.h @@ -10,10 +10,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #ifndef __LIBMSRLISTHELPER_H__ diff --git a/drivers/staging/media/atomisp/include/media/lm3554.h b/drivers/staging/media/atomisp/include/media/lm3554.h index df17d546f661..9276ce44d907 100644 --- a/drivers/staging/media/atomisp/include/media/lm3554.h +++ b/drivers/staging/media/atomisp/include/media/lm3554.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #ifndef _LM3554_H_ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp-regs.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp-regs.h index 513a430ee01a..5d102a4f8aff 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp-regs.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp-regs.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_acc.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_acc.c index 1eac329339b7..a6638edee360 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_acc.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_acc.c @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_acc.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_acc.h index 5b58e7d9ca5b..56386154643b 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_acc.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_acc.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c index f3cf4ecba630..8a18c528cad4 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.c @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #include diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.h index 4bb83864da2e..bdc73862fb79 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_cmd.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_common.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_common.h index 69d1526da362..2558193045a6 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_common.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_common.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat.h index fb8b8fab4e92..3ef850cd25bd 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c index 0b907474e024..c32240262f57 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.c @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.h index b62ad9082018..b03711668eda 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_css20.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c index 0592ac1f2832..44c21813a06e 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.c @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #ifdef CONFIG_COMPAT diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.h index 750478f614d6..685da0f48bab 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_compat_ioctl32.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #ifndef __ATOMISP_COMPAT_IOCTL32_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_csi2.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_csi2.c index 2c5036685447..fa03b78c3580 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_csi2.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_csi2.c @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_csi2.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_csi2.h index faa9cf7e05c0..0191d28a55bc 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_csi2.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_csi2.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #ifndef __ATOMISP_CSI2_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_dfs_tables.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_dfs_tables.h index 204d941cdb6c..54e28605b5de 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_dfs_tables.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_dfs_tables.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #ifndef __ATOMISP_DFS_TABLES_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_drvfs.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_drvfs.c index 9f74b2dcbfaf..7129b88456cb 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_drvfs.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_drvfs.c @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_drvfs.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_drvfs.h index 5cb717b0c1c2..b91bfef21639 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_drvfs.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_drvfs.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_file.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_file.c index c766119bf798..377ec2a9fa6d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_file.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_file.c @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_file.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_file.h index 1b86abd35c38..61fdeb5ee60a 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_file.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_file.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c index d64c98944d49..dd7596d8763d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.c @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.h index 8471e391501a..2faab3429d43 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_fops.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_helper.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_helper.h index e9650cb75ba5..55ba185b43a0 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_helper.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_helper.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #ifndef _atomisp_helper_h_ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_internal.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_internal.h index 6c1eb417361d..52a6f8002048 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_internal.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_internal.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #ifndef __ATOMISP_INTERNAL_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c index ccb78f0bc7a2..8698f8f758ca 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.h index fb5fadb5332b..0d2785b9ef99 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c index d27a50e66be2..70b53988553c 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.c @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #include diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.h index ba5c2ab14253..f3d61827ae8c 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_subdev.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #ifndef __ATOMISP_SUBDEV_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_tables.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_tables.h index af09218d8b71..319ded6a96da 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_tables.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_tables.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #ifndef __ATOMISP_TABLES_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_tpg.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_tpg.c index 48b96048cab4..b71cc7bcdbab 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_tpg.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_tpg.c @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_tpg.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_tpg.h index 64ab60f02e85..af354c4bfd3e 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_tpg.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_tpg.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_trace_event.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_trace_event.h index 5ce282d6c939..462b296554c7 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_trace_event.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_trace_event.h @@ -12,10 +12,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #undef TRACE_SYSTEM diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c index 6d2920155fa4..bdfe8c855b23 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #include diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.h b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.h index 191b2e57a810..944a6cf40a2f 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm.c b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm.c index b8aae4ba5a78..a1c81c12718c 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm.c @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ /* diff --git a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_bo.c b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_bo.c index 12c96c4f284d..9e957514108e 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_bo.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_bo.c @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ /* diff --git a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_dynamic_pool.c b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_dynamic_pool.c index eb82c3e4c776..f59fd9908257 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_dynamic_pool.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_dynamic_pool.c @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ /* diff --git a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_reserved_pool.c b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_reserved_pool.c index 177bc354f1d7..f300e7547997 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_reserved_pool.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_reserved_pool.c @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ /* diff --git a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_vm.c b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_vm.c index 402ffd9cb480..0df96e661983 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_vm.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/hmm/hmm_vm.c @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ /* diff --git a/drivers/staging/media/atomisp/pci/atomisp2/hrt/hive_isp_css_custom_host_hrt.h b/drivers/staging/media/atomisp/pci/atomisp2/hrt/hive_isp_css_custom_host_hrt.h index 46a5d29e2d3a..fb38fc540b81 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/hrt/hive_isp_css_custom_host_hrt.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/hrt/hive_isp_css_custom_host_hrt.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #ifndef _hive_isp_css_custom_host_hrt_h_ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/hrt/hive_isp_css_mm_hrt.c b/drivers/staging/media/atomisp/pci/atomisp2/hrt/hive_isp_css_mm_hrt.c index 2e78976bb2ac..a94958bde718 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/hrt/hive_isp_css_mm_hrt.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/hrt/hive_isp_css_mm_hrt.c @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/hrt/hive_isp_css_mm_hrt.h b/drivers/staging/media/atomisp/pci/atomisp2/hrt/hive_isp_css_mm_hrt.h index 1328944a7afd..15c2dfb6794e 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/hrt/hive_isp_css_mm_hrt.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/hrt/hive_isp_css_mm_hrt.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm.h b/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm.h index 6b9fb1b2caaf..1e135c7c6d9b 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_bo.h b/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_bo.h index dffd6e9cf693..bd44ebbc427c 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_bo.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_bo.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_bo_dev.h b/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_bo_dev.h index a9446adb4c70..9e51a657ece4 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_bo_dev.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_bo_dev.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_common.h b/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_common.h index f1593aa38ce1..00885203fb14 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_common.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_common.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_pool.h b/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_pool.h index 1ba360433d88..bf24e44462bc 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_pool.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_pool.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #ifndef __HMM_POOL_H__ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_vm.h b/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_vm.h index 07d40662de32..52098161082d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_vm.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/include/hmm/hmm_vm.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/include/mmu/isp_mmu.h b/drivers/staging/media/atomisp/pci/atomisp2/include/mmu/isp_mmu.h index 6b4eefc929e2..560014add005 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/include/mmu/isp_mmu.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/include/mmu/isp_mmu.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ /* diff --git a/drivers/staging/media/atomisp/pci/atomisp2/include/mmu/sh_mmu.h b/drivers/staging/media/atomisp/pci/atomisp2/include/mmu/sh_mmu.h index 06041e94cbb2..031c0398bf65 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/include/mmu/sh_mmu.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/include/mmu/sh_mmu.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #ifndef SH_MMU_H_ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/include/mmu/sh_mmu_mrfld.h b/drivers/staging/media/atomisp/pci/atomisp2/include/mmu/sh_mmu_mrfld.h index b9bad9f06235..662e98f41da2 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/include/mmu/sh_mmu_mrfld.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/include/mmu/sh_mmu_mrfld.h @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/mmu/isp_mmu.c b/drivers/staging/media/atomisp/pci/atomisp2/mmu/isp_mmu.c index 706bd43e8b1b..e36c2a33b41a 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/mmu/isp_mmu.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/mmu/isp_mmu.c @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ /* diff --git a/drivers/staging/media/atomisp/pci/atomisp2/mmu/sh_mmu_mrfld.c b/drivers/staging/media/atomisp/pci/atomisp2/mmu/sh_mmu_mrfld.c index 97546bd124cd..c59bcc982966 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/mmu/sh_mmu_mrfld.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/mmu/sh_mmu_mrfld.c @@ -14,10 +14,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. * */ #include "type_support.h" -- cgit v1.2.3 From fdbc17101e4eb68dda73abda1df72f2852eaeda0 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 24 Oct 2017 04:22:11 -0400 Subject: media: staging: atomisp: i2c: Convert timers to use timer_setup() In preparation for unconditionally passing the struct timer_list pointer to all timer callbacks, switch to using the new timer_setup() and from_timer() to pass the timer pointer explicitly. Signed-off-by: Kees Cook Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/i2c/atomisp-lm3554.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c index a37ab5c5c9a3..4fd9f538ac95 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-lm3554.c @@ -167,10 +167,9 @@ static int lm3554_set_config1(struct lm3554 *flash) /* ----------------------------------------------------------------------------- * Hardware trigger */ -static void lm3554_flash_off_delay(long unsigned int arg) +static void lm3554_flash_off_delay(struct timer_list *t) { - struct v4l2_subdev *sd = i2c_get_clientdata((struct i2c_client *)arg); - struct lm3554 *flash = to_lm3554(sd); + struct lm3554 *flash = from_timer(flash, t, flash_off_delay); struct lm3554_platform_data *pdata = flash->pdata; gpio_set_value(pdata->gpio_strobe, 0); @@ -908,8 +907,7 @@ static int lm3554_probe(struct i2c_client *client) mutex_init(&flash->power_lock); - setup_timer(&flash->flash_off_delay, lm3554_flash_off_delay, - (unsigned long)client); + timer_setup(&flash->flash_off_delay, lm3554_flash_off_delay, 0); err = lm3554_gpio_init(client); if (err) { -- cgit v1.2.3 From 715e3f4d01957df0d256d08fb7ed3b389f7a8523 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 27 Oct 2017 06:35:11 -0400 Subject: media: staging: atomisp: Add videobuf2 switch to TODO The atomisp driver uses the videobuf1 framework for buffer management. The framework is being removed; switch to videobuf2 needs to be made. There are only a handful of remaining non-staging drivers using videobuf1. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/atomisp/TODO | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/media/atomisp/TODO b/drivers/staging/media/atomisp/TODO index 447cb59c215a..255ce3630c2a 100644 --- a/drivers/staging/media/atomisp/TODO +++ b/drivers/staging/media/atomisp/TODO @@ -48,6 +48,8 @@ 10. Use LED flash API for flash LED drivers such as LM3554 (which already has a LED class driver). +11. Switch from videobuf1 to videobuf2. Videobuf1 is being removed! + Limitations: 1. To test the patches, you also need the ISP firmware -- cgit v1.2.3 From b17ec78a42713a477151e9a78c07eb7dea0e10e9 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 24 Oct 2017 11:23:14 -0400 Subject: media: rc: Convert timers to use timer_setup() In preparation for unconditionally passing the struct timer_list pointer to all timer callbacks, switch to using the new timer_setup() and from_timer() to pass the timer pointer explicitly. Cc: Maxim Levitsky Cc: James Hogan Cc: Hans Verkuil Cc: "Antti Seppälä" Cc: Heiner Kallweit Cc: "David Härdeman" Cc: Andi Shyti Signed-off-by: Kees Cook Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ene_ir.c | 7 +++---- drivers/media/rc/igorplugusb.c | 6 +++--- drivers/media/rc/img-ir/img-ir-hw.c | 13 ++++++------- drivers/media/rc/img-ir/img-ir-raw.c | 6 +++--- drivers/media/rc/imon.c | 7 +++---- drivers/media/rc/ir-mce_kbd-decoder.c | 7 +++---- drivers/media/rc/rc-ir-raw.c | 8 ++++---- drivers/media/rc/rc-main.c | 7 +++---- drivers/media/rc/sir_ir.c | 4 ++-- 9 files changed, 30 insertions(+), 35 deletions(-) diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index af7ba23e16e1..71b8c9bbf6c4 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -670,9 +670,9 @@ exit: } /* timer to simulate tx done interrupt */ -static void ene_tx_irqsim(unsigned long data) +static void ene_tx_irqsim(struct timer_list *t) { - struct ene_device *dev = (struct ene_device *)data; + struct ene_device *dev = from_timer(dev, t, tx_sim_timer); unsigned long flags; spin_lock_irqsave(&dev->hw_lock, flags); @@ -1045,8 +1045,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) if (!dev->hw_learning_and_tx_capable && txsim) { dev->hw_learning_and_tx_capable = true; - setup_timer(&dev->tx_sim_timer, ene_tx_irqsim, - (long unsigned int)dev); + timer_setup(&dev->tx_sim_timer, ene_tx_irqsim, 0); pr_warn("Simulation of TX activated\n"); } diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c index 4b715eb995f8..f563ddd7f739 100644 --- a/drivers/media/rc/igorplugusb.c +++ b/drivers/media/rc/igorplugusb.c @@ -137,9 +137,9 @@ static void igorplugusb_cmd(struct igorplugusb *ir, int cmd) dev_err(ir->dev, "submit urb failed: %d", ret); } -static void igorplugusb_timer(unsigned long data) +static void igorplugusb_timer(struct timer_list *t) { - struct igorplugusb *ir = (struct igorplugusb *)data; + struct igorplugusb *ir = from_timer(ir, t, timer); igorplugusb_cmd(ir, GET_INFRACODE); } @@ -174,7 +174,7 @@ static int igorplugusb_probe(struct usb_interface *intf, ir->dev = &intf->dev; - setup_timer(&ir->timer, igorplugusb_timer, (unsigned long)ir); + timer_setup(&ir->timer, igorplugusb_timer, 0); ir->request.bRequest = GET_INFRACODE; ir->request.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN; diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c index 82fdf4cc0824..f54bc5d23893 100644 --- a/drivers/media/rc/img-ir/img-ir-hw.c +++ b/drivers/media/rc/img-ir/img-ir-hw.c @@ -867,9 +867,9 @@ static void img_ir_handle_data(struct img_ir_priv *priv, u32 len, u64 raw) } /* timer function to end waiting for repeat. */ -static void img_ir_end_timer(unsigned long arg) +static void img_ir_end_timer(struct timer_list *t) { - struct img_ir_priv *priv = (struct img_ir_priv *)arg; + struct img_ir_priv *priv = from_timer(priv, t, hw.end_timer); spin_lock_irq(&priv->lock); img_ir_end_repeat(priv); @@ -881,9 +881,9 @@ static void img_ir_end_timer(unsigned long arg) * cleared when invalid interrupts were generated due to a quirk in the * img-ir decoder. */ -static void img_ir_suspend_timer(unsigned long arg) +static void img_ir_suspend_timer(struct timer_list *t) { - struct img_ir_priv *priv = (struct img_ir_priv *)arg; + struct img_ir_priv *priv = from_timer(priv, t, hw.suspend_timer); spin_lock_irq(&priv->lock); /* @@ -1055,9 +1055,8 @@ int img_ir_probe_hw(struct img_ir_priv *priv) img_ir_probe_hw_caps(priv); /* Set up the end timer */ - setup_timer(&hw->end_timer, img_ir_end_timer, (unsigned long)priv); - setup_timer(&hw->suspend_timer, img_ir_suspend_timer, - (unsigned long)priv); + timer_setup(&hw->end_timer, img_ir_end_timer, 0); + timer_setup(&hw->suspend_timer, img_ir_suspend_timer, 0); /* Register a clock notifier */ if (!IS_ERR(priv->clk)) { diff --git a/drivers/media/rc/img-ir/img-ir-raw.c b/drivers/media/rc/img-ir/img-ir-raw.c index 64714efc1145..6e545680d3b6 100644 --- a/drivers/media/rc/img-ir/img-ir-raw.c +++ b/drivers/media/rc/img-ir/img-ir-raw.c @@ -67,9 +67,9 @@ void img_ir_isr_raw(struct img_ir_priv *priv, u32 irq_status) * order to be assured of the final space. If there are no edges for a certain * time we use this timer to emit a final sample to satisfy them. */ -static void img_ir_echo_timer(unsigned long arg) +static void img_ir_echo_timer(struct timer_list *t) { - struct img_ir_priv *priv = (struct img_ir_priv *)arg; + struct img_ir_priv *priv = from_timer(priv, t, raw.timer); spin_lock_irq(&priv->lock); @@ -107,7 +107,7 @@ int img_ir_probe_raw(struct img_ir_priv *priv) int error; /* Set up the echo timer */ - setup_timer(&raw->timer, img_ir_echo_timer, (unsigned long)priv); + timer_setup(&raw->timer, img_ir_echo_timer, 0); /* Allocate raw decoder */ raw->rdev = rdev = rc_allocate_device(RC_DRIVER_IR_RAW); diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 9fef8cc17114..b25b35b3f6da 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -1090,9 +1090,9 @@ static void usb_tx_callback(struct urb *urb) /** * report touchscreen input */ -static void imon_touch_display_timeout(unsigned long data) +static void imon_touch_display_timeout(struct timer_list *t) { - struct imon_context *ictx = (struct imon_context *)data; + struct imon_context *ictx = from_timer(ictx, t, ttimer); if (ictx->display_type != IMON_DISPLAY_TYPE_VGA) return; @@ -2411,8 +2411,7 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf, mutex_lock(&ictx->lock); if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) { - setup_timer(&ictx->ttimer, imon_touch_display_timeout, - (unsigned long)ictx); + timer_setup(&ictx->ttimer, imon_touch_display_timeout, 0); } ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf)); diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index 7c572a643656..69d6264d54e6 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -115,9 +115,9 @@ static unsigned char kbd_keycodes[256] = { KEY_RESERVED }; -static void mce_kbd_rx_timeout(unsigned long data) +static void mce_kbd_rx_timeout(struct timer_list *t) { - struct mce_kbd_dec *mce_kbd = (struct mce_kbd_dec *)data; + struct mce_kbd_dec *mce_kbd = from_timer(mce_kbd, t, rx_timeout); int i; unsigned char maskcode; @@ -389,8 +389,7 @@ static int ir_mce_kbd_register(struct rc_dev *dev) set_bit(EV_MSC, idev->evbit); set_bit(MSC_SCAN, idev->mscbit); - setup_timer(&mce_kbd->rx_timeout, mce_kbd_rx_timeout, - (unsigned long)mce_kbd); + timer_setup(&mce_kbd->rx_timeout, mce_kbd_rx_timeout, 0); input_set_drvdata(idev, mce_kbd); diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index 503bc425a187..f6e5ba4fbb49 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -471,9 +471,10 @@ int ir_raw_encode_scancode(enum rc_proto protocol, u32 scancode, } EXPORT_SYMBOL(ir_raw_encode_scancode); -static void edge_handle(unsigned long arg) +static void edge_handle(struct timer_list *t) { - struct rc_dev *dev = (struct rc_dev *)arg; + struct ir_raw_event_ctrl *raw = from_timer(raw, t, edge_handle); + struct rc_dev *dev = raw->dev; ktime_t interval = ktime_sub(ktime_get(), dev->raw->last_event); if (ktime_to_ns(interval) >= dev->timeout) { @@ -513,8 +514,7 @@ int ir_raw_event_prepare(struct rc_dev *dev) dev->raw->dev = dev; dev->change_protocol = change_protocol; - setup_timer(&dev->raw->edge_handle, edge_handle, - (unsigned long)dev); + timer_setup(&dev->raw->edge_handle, edge_handle, 0); INIT_KFIFO(dev->raw->kfifo); return 0; diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index cb78e5702bef..17950e29d4e3 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -630,9 +630,9 @@ EXPORT_SYMBOL_GPL(rc_keyup); * This routine will generate a keyup event some time after a keydown event * is generated when no further activity has been detected. */ -static void ir_timer_keyup(unsigned long cookie) +static void ir_timer_keyup(struct timer_list *t) { - struct rc_dev *dev = (struct rc_dev *)cookie; + struct rc_dev *dev = from_timer(dev, t, timer_keyup); unsigned long flags; /* @@ -1570,8 +1570,7 @@ struct rc_dev *rc_allocate_device(enum rc_driver_type type) dev->input_dev->setkeycode = ir_setkeycode; input_set_drvdata(dev->input_dev, dev); - setup_timer(&dev->timer_keyup, ir_timer_keyup, - (unsigned long)dev); + timer_setup(&dev->timer_keyup, ir_timer_keyup, 0); spin_lock_init(&dev->rc_map.lock); spin_lock_init(&dev->keylock); diff --git a/drivers/media/rc/sir_ir.c b/drivers/media/rc/sir_ir.c index bc906fb128d5..76120664b700 100644 --- a/drivers/media/rc/sir_ir.c +++ b/drivers/media/rc/sir_ir.c @@ -120,7 +120,7 @@ static void add_read_queue(int flag, unsigned long val) } /* SECTION: Hardware */ -static void sir_timeout(unsigned long data) +static void sir_timeout(struct timer_list *unused) { /* * if last received signal was a pulse, but receiving stopped @@ -321,7 +321,7 @@ static int sir_ir_probe(struct platform_device *dev) rcdev->timeout = IR_DEFAULT_TIMEOUT; rcdev->dev.parent = &sir_ir_dev->dev; - setup_timer(&timerlist, sir_timeout, 0); + timer_setup(&timerlist, sir_timeout, 0); /* get I/O port access and IRQ line */ if (!devm_request_region(&sir_ir_dev->dev, io, 8, KBUILD_MODNAME)) { -- cgit v1.2.3 From 47f42f3e21182171686efec7fae48da9411fb1a0 Mon Sep 17 00:00:00 2001 From: Oleh Kravchenko Date: Sat, 28 Oct 2017 09:38:16 -0400 Subject: media: rc: mceusb: add support for 1b80:d3b2 Evromedia USB Full Hybrid Full HD (1b80:d3b2) has IR on Interface 0. Remote controller supplied with this tuner fully compatible with RC_MAP_MSI_DIGIVOX_III. Signed-off-by: Oleh Kravchenko Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 9 +++++++++ drivers/media/usb/cx231xx/cx231xx-cards.c | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 67c1ff099eb4..948699408764 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -188,6 +188,7 @@ enum mceusb_model_type { TIVO_KIT, MCE_GEN2_NO_TX, HAUPPAUGE_CX_HYBRID_TV, + EVROMEDIA_FULL_HYBRID_FULLHD, }; struct mceusb_model { @@ -247,6 +248,11 @@ static const struct mceusb_model mceusb_model[] = { .mce_gen2 = 1, .rc_map = RC_MAP_TIVO, }, + [EVROMEDIA_FULL_HYBRID_FULLHD] = { + .name = "Evromedia USB Full Hybrid Full HD", + .no_tx = 1, + .rc_map = RC_MAP_MSI_DIGIVOX_III, + }, }; static const struct usb_device_id mceusb_dev_table[] = { @@ -398,6 +404,9 @@ static const struct usb_device_id mceusb_dev_table[] = { .driver_info = HAUPPAUGE_CX_HYBRID_TV }, /* Adaptec / HP eHome Receiver */ { USB_DEVICE(VENDOR_ADAPTEC, 0x0094) }, + /* Evromedia USB Full Hybrid Full HD */ + { USB_DEVICE(0x1b80, 0xd3b2), + .driver_info = EVROMEDIA_FULL_HYBRID_FULLHD }, /* Terminating entry */ { } diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index 9b742d569fb5..f124b677d5a0 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -847,7 +847,6 @@ struct cx231xx_board cx231xx_boards[] = { .demod_addr = 0x64, /* 0xc8 >> 1 */ .demod_i2c_master = I2C_1_MUX_3, .has_dvb = 1, - .ir_i2c_master = I2C_0, .norm = V4L2_STD_PAL, .output_mode = OUT_MODE_VIP11, .tuner_addr = 0x60, /* 0xc0 >> 1 */ -- cgit v1.2.3 From ad596b68ad26bc2d3da9a0be3c5c21a265f5edcb Mon Sep 17 00:00:00 2001 From: Oleh Kravchenko Date: Sat, 28 Oct 2017 09:38:17 -0400 Subject: media: rc: Add Astrometa T2hybrid keymap module Add the keymap module for Astrometa T2hybrid remote control commands. Signed-off-by: Oleh Kravchenko Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/Makefile | 1 + drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c | 70 ++++++++++++++++++++++++ include/media/rc-map.h | 1 + 3 files changed, 72 insertions(+) create mode 100644 drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile index 3f196232904f..039a631b348e 100644 --- a/drivers/media/rc/keymaps/Makefile +++ b/drivers/media/rc/keymaps/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ rc-alink-dtu-m.o \ rc-anysee.o \ rc-apac-viewcomp.o \ + rc-astrometa-t2hybrid.o \ rc-asus-pc39.o \ rc-asus-ps3-100.o \ rc-ati-tv-wonder-hd-600.o \ diff --git a/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c b/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c new file mode 100644 index 000000000000..51690960fec4 --- /dev/null +++ b/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c @@ -0,0 +1,70 @@ +/* + * Keytable for the Astrometa T2hybrid remote controller + * + * Copyright (C) 2017 Oleh Kravchenko + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +static struct rc_map_table t2hybrid[] = { + { 0x4d, KEY_POWER2 }, + { 0x54, KEY_VIDEO }, /* Source */ + { 0x16, KEY_MUTE }, + + { 0x4c, KEY_RECORD }, + { 0x05, KEY_CHANNELUP }, + { 0x0c, KEY_TIME}, /* Timeshift */ + + { 0x0a, KEY_VOLUMEDOWN }, + { 0x40, KEY_ZOOM }, /* Fullscreen */ + { 0x1e, KEY_VOLUMEUP }, + + { 0x12, KEY_0 }, + { 0x02, KEY_CHANNELDOWN }, + { 0x1c, KEY_AGAIN }, /* Recall */ + + { 0x09, KEY_1 }, + { 0x1d, KEY_2 }, + { 0x1f, KEY_3 }, + + { 0x0d, KEY_4 }, + { 0x19, KEY_5 }, + { 0x1b, KEY_6 }, + + { 0x11, KEY_7 }, + { 0x15, KEY_8 }, + { 0x17, KEY_9 }, +}; + +static struct rc_map_list t2hybrid_map = { + .map = { + .scan = t2hybrid, + .size = ARRAY_SIZE(t2hybrid), + .rc_proto = RC_PROTO_NEC, + .name = RC_MAP_ASTROMETA_T2HYBRID, + } +}; + +static int __init init_rc_map_t2hybrid(void) +{ + return rc_map_register(&t2hybrid_map); +} + +static void __exit exit_rc_map_t2hybrid(void) +{ + rc_map_unregister(&t2hybrid_map); +} + +module_init(init_rc_map_t2hybrid) +module_exit(exit_rc_map_t2hybrid) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Oleh Kravchenko "); diff --git a/include/media/rc-map.h b/include/media/rc-map.h index cc59c72ac282..72197cb43781 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -211,6 +211,7 @@ struct rc_map *rc_map_get(const char *name); #define RC_MAP_ALINK_DTU_M "rc-alink-dtu-m" #define RC_MAP_ANYSEE "rc-anysee" #define RC_MAP_APAC_VIEWCOMP "rc-apac-viewcomp" +#define RC_MAP_ASTROMETA_T2HYBRID "rc-astrometa-t2hybrid" #define RC_MAP_ASUS_PC39 "rc-asus-pc39" #define RC_MAP_ASUS_PS3_100 "rc-asus-ps3-100" #define RC_MAP_ATI_TV_WONDER_HD_600 "rc-ati-tv-wonder-hd-600" -- cgit v1.2.3 From 8ff19cdbeee49e4148deb958d7af9ab389e94cac Mon Sep 17 00:00:00 2001 From: Oleh Kravchenko Date: Sat, 28 Oct 2017 09:38:18 -0400 Subject: media: rc: mceusb: add support for 15f4:0135 Astrometa T2hybrid (15f4:0135) has IR on Interface 0. Signed-off-by: Oleh Kravchenko Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 948699408764..a9187b0b46a1 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -189,6 +189,7 @@ enum mceusb_model_type { MCE_GEN2_NO_TX, HAUPPAUGE_CX_HYBRID_TV, EVROMEDIA_FULL_HYBRID_FULLHD, + ASTROMETA_T2HYBRID, }; struct mceusb_model { @@ -253,6 +254,11 @@ static const struct mceusb_model mceusb_model[] = { .no_tx = 1, .rc_map = RC_MAP_MSI_DIGIVOX_III, }, + [ASTROMETA_T2HYBRID] = { + .name = "Astrometa T2Hybrid", + .no_tx = 1, + .rc_map = RC_MAP_ASTROMETA_T2HYBRID, + } }; static const struct usb_device_id mceusb_dev_table[] = { @@ -407,6 +413,9 @@ static const struct usb_device_id mceusb_dev_table[] = { /* Evromedia USB Full Hybrid Full HD */ { USB_DEVICE(0x1b80, 0xd3b2), .driver_info = EVROMEDIA_FULL_HYBRID_FULLHD }, + /* Astrometa T2hybrid */ + { USB_DEVICE(0x15f4, 0x0135), + .driver_info = ASTROMETA_T2HYBRID }, /* Terminating entry */ { } -- cgit v1.2.3 From 9d377dae7f2d44d47f891b03d91cb8f695ddb06f Mon Sep 17 00:00:00 2001 From: Oleh Kravchenko Date: Sat, 28 Oct 2017 09:38:19 -0400 Subject: media: cx231xx: Fix NTSC/PAL on Evromedia USB Full Hybrid Full HD Signed-off-by: Oleh Kravchenko Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-cards.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index f124b677d5a0..4b3f6b5fe2e4 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -847,6 +847,7 @@ struct cx231xx_board cx231xx_boards[] = { .demod_addr = 0x64, /* 0xc8 >> 1 */ .demod_i2c_master = I2C_1_MUX_3, .has_dvb = 1, + .decoder = CX231XX_AVDECODER, .norm = V4L2_STD_PAL, .output_mode = OUT_MODE_VIP11, .tuner_addr = 0x60, /* 0xc0 >> 1 */ -- cgit v1.2.3 From 1bfbb88564b17bbc2187cbce9e867628532ce1a8 Mon Sep 17 00:00:00 2001 From: Oleh Kravchenko Date: Sat, 28 Oct 2017 09:38:20 -0400 Subject: media: cx231xx: Fix NTSC/PAL on Astrometa T2hybrid Signed-off-by: Oleh Kravchenko Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-cards.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index 4b3f6b5fe2e4..54d9d0cb326f 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -872,6 +872,7 @@ struct cx231xx_board cx231xx_boards[] = { .name = "Astrometa T2hybrid", .tuner_type = TUNER_ABSENT, .has_dvb = 1, + .decoder = CX231XX_AVDECODER, .output_mode = OUT_MODE_VIP11, .agc_analog_digital_select_gpio = 0x01, .ctl_pin_status_mask = 0xffffffc4, -- cgit v1.2.3 From bfba2b3e21b9426c0f9aca00f3cad8631b2da170 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 24 Sep 2017 05:00:57 -0400 Subject: media: omap_vout: Fix a possible null pointer dereference in omap_vout_open() Move a debug message so that a null pointer access can not happen for the variable "vout" in this function. Fixes: 5c7ab6348e7b3fcca2b8ee548306c774472971e2 ("V4L/DVB: V4L2: Add support for OMAP2/3 V4L2 display driver on top of DSS2") Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap/omap_vout.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index 4d29860d27b4..6f1b0c799e58 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -1004,11 +1004,12 @@ static int omap_vout_open(struct file *file) struct omap_vout_device *vout = NULL; vout = video_drvdata(file); - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__); if (vout == NULL) return -ENODEV; + v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__); + /* for now, we only support single open */ if (vout->opened) return -EBUSY; -- cgit v1.2.3 From 0dd7054129c9b3d54c3716b8e38dcfcb43fe305d Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Wed, 27 Sep 2017 04:05:43 -0400 Subject: media: cx231xx: make cx231xx_vbi_qops const Make this const as it is only passed to the const argument of the function videobuf_queue_vmalloc_init in the file referencing it. Also, make the declaration in the header const. Structure found using Coccienlle and changes done by hand. Signed-off-by: Bhumika Goyal Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-vbi.c | 2 +- drivers/media/usb/cx231xx/cx231xx-vbi.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c index 76e901920f6f..330b86e4e38f 100644 --- a/drivers/media/usb/cx231xx/cx231xx-vbi.c +++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c @@ -285,7 +285,7 @@ static void vbi_buffer_release(struct videobuf_queue *vq, free_buffer(vq, buf); } -struct videobuf_queue_ops cx231xx_vbi_qops = { +const struct videobuf_queue_ops cx231xx_vbi_qops = { .buf_setup = vbi_buffer_setup, .buf_prepare = vbi_buffer_prepare, .buf_queue = vbi_buffer_queue, diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.h b/drivers/media/usb/cx231xx/cx231xx-vbi.h index 16c7d20a22a4..b33d2bdb621c 100644 --- a/drivers/media/usb/cx231xx/cx231xx-vbi.h +++ b/drivers/media/usb/cx231xx/cx231xx-vbi.h @@ -22,7 +22,7 @@ #ifndef _CX231XX_VBI_H #define _CX231XX_VBI_H -extern struct videobuf_queue_ops cx231xx_vbi_qops; +extern const struct videobuf_queue_ops cx231xx_vbi_qops; #define NTSC_VBI_START_LINE 10 /* line 10 - 21 */ #define NTSC_VBI_END_LINE 21 -- cgit v1.2.3 From 82fad4762565ccae181c2d5ee332d47456e6ed7f Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Wed, 27 Sep 2017 04:38:29 -0400 Subject: media: radio-si470x: make si470x_viddev_template const Make this const as it is only used in a copy operation in the files referencing it. Add const to declaration in the header too. Structure found using Coccienlle and changes done by hand. Signed-off-by: Bhumika Goyal Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/si470x/radio-si470x-common.c | 2 +- drivers/media/radio/si470x/radio-si470x.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c index cd76facc22f5..c89a7d5b8c55 100644 --- a/drivers/media/radio/si470x/radio-si470x-common.c +++ b/drivers/media/radio/si470x/radio-si470x-common.c @@ -749,7 +749,7 @@ static const struct v4l2_ioctl_ops si470x_ioctl_ops = { /* * si470x_viddev_template - video device interface */ -struct video_device si470x_viddev_template = { +const struct video_device si470x_viddev_template = { .fops = &si470x_fops, .name = DRIVER_NAME, .release = video_device_release_empty, diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h index 7d2defd9d399..eb7b834a0ae5 100644 --- a/drivers/media/radio/si470x/radio-si470x.h +++ b/drivers/media/radio/si470x/radio-si470x.h @@ -209,7 +209,7 @@ struct si470x_device { /************************************************************************** * Common Functions **************************************************************************/ -extern struct video_device si470x_viddev_template; +extern const struct video_device si470x_viddev_template; extern const struct v4l2_ctrl_ops si470x_ctrl_ops; int si470x_get_register(struct si470x_device *radio, int regnr); int si470x_set_register(struct si470x_device *radio, int regnr); -- cgit v1.2.3 From 3e3149173fd831e554f45c694e5349370601dd5f Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 16 Oct 2017 19:10:12 -0400 Subject: media: media/saa7146: Convert timers to use timer_setup() In preparation for unconditionally passing the struct timer_list pointer to all timer callbacks, switch to using the new timer_setup() and from_timer() to pass the timer pointer explicitly. This requires adding a pointer to hold the timer's target file, as there won't be a way to pass this in the future. Signed-off-by: Kees Cook Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146/saa7146_fops.c | 2 +- drivers/media/common/saa7146/saa7146_vbi.c | 9 +++++---- include/media/drv-intf/saa7146_vv.h | 1 + 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c index 930d2c94d5d3..c4664f0da874 100644 --- a/drivers/media/common/saa7146/saa7146_fops.c +++ b/drivers/media/common/saa7146/saa7146_fops.c @@ -559,7 +559,7 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv) vbi->start[1] = 312; vbi->count[1] = 16; - init_timer(&vv->vbi_read_timeout); + timer_setup(&vv->vbi_read_timeout, NULL, 0); vv->ov_fb.capability = V4L2_FBUF_CAP_LIST_CLIPPING; vv->ov_fb.flags = V4L2_FBUF_FLAG_PRIMARY; diff --git a/drivers/media/common/saa7146/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c index 69525ca4f52c..ae66c2325228 100644 --- a/drivers/media/common/saa7146/saa7146_vbi.c +++ b/drivers/media/common/saa7146/saa7146_vbi.c @@ -348,9 +348,10 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file) spin_unlock_irqrestore(&dev->slock, flags); } -static void vbi_read_timeout(unsigned long data) +static void vbi_read_timeout(struct timer_list *t) { - struct file *file = (struct file*)data; + struct saa7146_vv *vv = from_timer(vv, t, vbi_read_timeout); + struct file *file = vv->vbi_read_timeout_file; struct saa7146_fh *fh = file->private_data; struct saa7146_dev *dev = fh->dev; @@ -401,8 +402,8 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file) sizeof(struct saa7146_buf), file, &dev->v4l2_lock); - vv->vbi_read_timeout.function = vbi_read_timeout; - vv->vbi_read_timeout.data = (unsigned long)file; + vv->vbi_read_timeout.function = (TIMER_FUNC_TYPE)vbi_read_timeout; + vv->vbi_read_timeout_file = file; /* initialize the brs */ if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) { diff --git a/include/media/drv-intf/saa7146_vv.h b/include/media/drv-intf/saa7146_vv.h index 736f4f2d8290..926c5b145279 100644 --- a/include/media/drv-intf/saa7146_vv.h +++ b/include/media/drv-intf/saa7146_vv.h @@ -107,6 +107,7 @@ struct saa7146_vv struct saa7146_dmaqueue vbi_dmaq; struct v4l2_vbi_format vbi_fmt; struct timer_list vbi_read_timeout; + struct file *vbi_read_timeout_file; /* vbi workaround interrupt queue */ wait_queue_head_t vbi_wq; int vbi_fieldcount; -- cgit v1.2.3 From a88cd60fc94e7e04e61adeb1c6f6ba16031913f8 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 16 Oct 2017 19:10:27 -0400 Subject: media: tc358743: Convert timers to use timer_setup() In preparation for unconditionally passing the struct timer_list pointer to all timer callbacks, switch to using the new timer_setup() and from_timer() to pass the timer pointer explicitly. Cc: Mats Randgaard Signed-off-by: Kees Cook Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358743.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index d3cf016ad0a0..2b8181469b93 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -1481,9 +1481,9 @@ static irqreturn_t tc358743_irq_handler(int irq, void *dev_id) return handled ? IRQ_HANDLED : IRQ_NONE; } -static void tc358743_irq_poll_timer(unsigned long arg) +static void tc358743_irq_poll_timer(struct timer_list *t) { - struct tc358743_state *state = (struct tc358743_state *)arg; + struct tc358743_state *state = from_timer(state, t, timer); unsigned int msecs; schedule_work(&state->work_i2c_poll); @@ -2153,8 +2153,7 @@ static int tc358743_probe(struct i2c_client *client, } else { INIT_WORK(&state->work_i2c_poll, tc358743_work_i2c_poll); - setup_timer(&state->timer, tc358743_irq_poll_timer, - (unsigned long)state); + timer_setup(&state->timer, tc358743_irq_poll_timer, 0); state->timer.expires = jiffies + msecs_to_jiffies(POLL_INTERVAL_MS); add_timer(&state->timer); -- cgit v1.2.3 From 12a83612ed23fccafe168828cafcce514f02e74d Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 16 Oct 2017 19:10:42 -0400 Subject: media: saa7146: Convert timers to use timer_setup() In preparation for unconditionally passing the struct timer_list pointer to all timer callbacks, switch to using the new timer_setup() and from_timer() to pass the timer pointer explicitly. Signed-off-by: Kees Cook Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146/saa7146_fops.c | 4 ++-- drivers/media/common/saa7146/saa7146_vbi.c | 3 +-- drivers/media/common/saa7146/saa7146_video.c | 3 +-- include/media/drv-intf/saa7146_vv.h | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c index c4664f0da874..8c87d6837c49 100644 --- a/drivers/media/common/saa7146/saa7146_fops.c +++ b/drivers/media/common/saa7146/saa7146_fops.c @@ -163,9 +163,9 @@ void saa7146_buffer_next(struct saa7146_dev *dev, } } -void saa7146_buffer_timeout(unsigned long data) +void saa7146_buffer_timeout(struct timer_list *t) { - struct saa7146_dmaqueue *q = (struct saa7146_dmaqueue*)data; + struct saa7146_dmaqueue *q = from_timer(q, t, timeout); struct saa7146_dev *dev = q->dev; unsigned long flags; diff --git a/drivers/media/common/saa7146/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c index ae66c2325228..7fa3147c2d7e 100644 --- a/drivers/media/common/saa7146/saa7146_vbi.c +++ b/drivers/media/common/saa7146/saa7146_vbi.c @@ -366,8 +366,7 @@ static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv) INIT_LIST_HEAD(&vv->vbi_dmaq.queue); - setup_timer(&vv->vbi_dmaq.timeout, saa7146_buffer_timeout, - (unsigned long)(&vv->vbi_dmaq)); + timer_setup(&vv->vbi_dmaq.timeout, saa7146_buffer_timeout, 0); vv->vbi_dmaq.dev = dev; init_waitqueue_head(&vv->vbi_wq); diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index 51eeed830de4..2b631eaa65b3 100644 --- a/drivers/media/common/saa7146/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c @@ -1201,8 +1201,7 @@ static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv) { INIT_LIST_HEAD(&vv->video_dmaq.queue); - setup_timer(&vv->video_dmaq.timeout, saa7146_buffer_timeout, - (unsigned long)(&vv->video_dmaq)); + timer_setup(&vv->video_dmaq.timeout, saa7146_buffer_timeout, 0); vv->video_dmaq.dev = dev; /* set some default values */ diff --git a/include/media/drv-intf/saa7146_vv.h b/include/media/drv-intf/saa7146_vv.h index 926c5b145279..17bbe3851d75 100644 --- a/include/media/drv-intf/saa7146_vv.h +++ b/include/media/drv-intf/saa7146_vv.h @@ -184,7 +184,7 @@ int saa7146_unregister_device(struct video_device *vid, struct saa7146_dev *dev) void saa7146_buffer_finish(struct saa7146_dev *dev, struct saa7146_dmaqueue *q, int state); void saa7146_buffer_next(struct saa7146_dev *dev, struct saa7146_dmaqueue *q,int vbi); int saa7146_buffer_queue(struct saa7146_dev *dev, struct saa7146_dmaqueue *q, struct saa7146_buf *buf); -void saa7146_buffer_timeout(unsigned long data); +void saa7146_buffer_timeout(struct timer_list *t); void saa7146_dma_free(struct saa7146_dev* dev,struct videobuf_queue *q, struct saa7146_buf *buf); -- cgit v1.2.3 From e7e0e2cfd1169ff8b53cdc182b3c10be3e088e61 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 16 Oct 2017 19:10:47 -0400 Subject: media: dvb-core: Convert timers to use timer_setup() In preparation for unconditionally passing the struct timer_list pointer to all timer callbacks, switch to using the new timer_setup() and from_timer() to pass the timer pointer explicitly. Cc: devendra sharma Signed-off-by: Kees Cook Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dmxdev.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 18e4230865be..3ddd44e1ee77 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -329,9 +329,9 @@ static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, return 0; } -static void dvb_dmxdev_filter_timeout(unsigned long data) +static void dvb_dmxdev_filter_timeout(struct timer_list *t) { - struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data; + struct dmxdev_filter *dmxdevfilter = from_timer(dmxdevfilter, t, timer); dmxdevfilter->buffer.error = -ETIMEDOUT; spin_lock_irq(&dmxdevfilter->dev->lock); @@ -346,8 +346,6 @@ static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter) del_timer(&dmxdevfilter->timer); if (para->timeout) { - dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout; - dmxdevfilter->timer.data = (unsigned long)dmxdevfilter; dmxdevfilter->timer.expires = jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000; add_timer(&dmxdevfilter->timer); @@ -754,7 +752,7 @@ static int dvb_demux_open(struct inode *inode, struct file *file) dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192); dmxdevfilter->type = DMXDEV_TYPE_NONE; dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); - init_timer(&dmxdevfilter->timer); + timer_setup(&dmxdevfilter->timer, dvb_dmxdev_filter_timeout, 0); dvbdev->users++; -- cgit v1.2.3 From 60793f4d3e79c3b90314f649d56ffd583046752d Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 16 Oct 2017 19:10:53 -0400 Subject: media: tvaudio: Convert timers to use timer_setup() In preparation for unconditionally passing the struct timer_list pointer to all timer callbacks, switch to using the new timer_setup() and from_timer() to pass the timer pointer explicitly. Signed-off-by: Kees Cook Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvaudio.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c index ce86534450ac..16a1e08ce06c 100644 --- a/drivers/media/i2c/tvaudio.c +++ b/drivers/media/i2c/tvaudio.c @@ -300,9 +300,9 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd) * if available, ... */ -static void chip_thread_wake(unsigned long data) +static void chip_thread_wake(struct timer_list *t) { - struct CHIPSTATE *chip = (struct CHIPSTATE*)data; + struct CHIPSTATE *chip = from_timer(chip, t, wt); wake_up_process(chip->thread); } @@ -1995,7 +1995,7 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id * v4l2_ctrl_handler_setup(&chip->hdl); chip->thread = NULL; - init_timer(&chip->wt); + timer_setup(&chip->wt, chip_thread_wake, 0); if (desc->flags & CHIP_NEED_CHECKMODE) { if (!desc->getrxsubchans || !desc->setaudmode) { /* This shouldn't be happen. Warn user, but keep working @@ -2005,8 +2005,6 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id * return 0; } /* start async thread */ - chip->wt.function = chip_thread_wake; - chip->wt.data = (unsigned long)chip; chip->thread = kthread_run(chip_thread, chip, "%s", client->name); if (IS_ERR(chip->thread)) { -- cgit v1.2.3 From 1e7126b4a86ad69e870099fb6b922a3b6e29598b Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 16 Oct 2017 19:11:30 -0400 Subject: media: saa7134: Convert timers to use timer_setup() In preparation for unconditionally passing the struct timer_list pointer to all timer callbacks, switch to using the new timer_setup() and from_timer() to pass the timer pointer explicitly. Cc: Geliang Tang Signed-off-by: Kees Cook Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-core.c | 6 +++--- drivers/media/pci/saa7134/saa7134-input.c | 9 ++++----- drivers/media/pci/saa7134/saa7134-ts.c | 3 +-- drivers/media/pci/saa7134/saa7134-vbi.c | 3 +-- drivers/media/pci/saa7134/saa7134-video.c | 3 +-- drivers/media/pci/saa7134/saa7134.h | 2 +- 6 files changed, 11 insertions(+), 15 deletions(-) diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c index 7976c5a12ca8..9e76de2411ae 100644 --- a/drivers/media/pci/saa7134/saa7134-core.c +++ b/drivers/media/pci/saa7134/saa7134-core.c @@ -338,9 +338,9 @@ void saa7134_buffer_next(struct saa7134_dev *dev, } } -void saa7134_buffer_timeout(unsigned long data) +void saa7134_buffer_timeout(struct timer_list *t) { - struct saa7134_dmaqueue *q = (struct saa7134_dmaqueue *)data; + struct saa7134_dmaqueue *q = from_timer(q, t, timeout); struct saa7134_dev *dev = q->dev; unsigned long flags; @@ -378,7 +378,7 @@ void saa7134_stop_streaming(struct saa7134_dev *dev, struct saa7134_dmaqueue *q) } } spin_unlock_irqrestore(&dev->slock, flags); - saa7134_buffer_timeout((unsigned long)q); /* also calls del_timer(&q->timeout) */ + saa7134_buffer_timeout(&q->timeout); /* also calls del_timer(&q->timeout) */ } EXPORT_SYMBOL_GPL(saa7134_stop_streaming); diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c index 9337e4615519..2d5abeddc079 100644 --- a/drivers/media/pci/saa7134/saa7134-input.c +++ b/drivers/media/pci/saa7134/saa7134-input.c @@ -447,10 +447,10 @@ void saa7134_input_irq(struct saa7134_dev *dev) } } -static void saa7134_input_timer(unsigned long data) +static void saa7134_input_timer(struct timer_list *t) { - struct saa7134_dev *dev = (struct saa7134_dev *)data; - struct saa7134_card_ir *ir = dev->remote; + struct saa7134_card_ir *ir = from_timer(ir, t, timer); + struct saa7134_dev *dev = ir->dev->priv; build_key(dev); mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); @@ -507,8 +507,7 @@ static int __saa7134_ir_start(void *priv) ir->running = true; if (ir->polling) { - setup_timer(&ir->timer, saa7134_input_timer, - (unsigned long)dev); + timer_setup(&ir->timer, saa7134_input_timer, 0); ir->timer.expires = jiffies + HZ; add_timer(&ir->timer); } diff --git a/drivers/media/pci/saa7134/saa7134-ts.c b/drivers/media/pci/saa7134/saa7134-ts.c index 7414878af9e0..2be703617e29 100644 --- a/drivers/media/pci/saa7134/saa7134-ts.c +++ b/drivers/media/pci/saa7134/saa7134-ts.c @@ -223,8 +223,7 @@ int saa7134_ts_init1(struct saa7134_dev *dev) dev->ts.nr_packets = ts_nr_packets; INIT_LIST_HEAD(&dev->ts_q.queue); - setup_timer(&dev->ts_q.timeout, saa7134_buffer_timeout, - (unsigned long)(&dev->ts_q)); + timer_setup(&dev->ts_q.timeout, saa7134_buffer_timeout, 0); dev->ts_q.dev = dev; dev->ts_q.need_two = 1; dev->ts_started = 0; diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c index 07a397bb775d..57bea543c39b 100644 --- a/drivers/media/pci/saa7134/saa7134-vbi.c +++ b/drivers/media/pci/saa7134/saa7134-vbi.c @@ -181,8 +181,7 @@ const struct vb2_ops saa7134_vbi_qops = { int saa7134_vbi_init1(struct saa7134_dev *dev) { INIT_LIST_HEAD(&dev->vbi_q.queue); - setup_timer(&dev->vbi_q.timeout, saa7134_buffer_timeout, - (unsigned long)(&dev->vbi_q)); + timer_setup(&dev->vbi_q.timeout, saa7134_buffer_timeout, 0); dev->vbi_q.dev = dev; if (vbibufs < 2) diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 51d42bbf969e..82d2a24644e4 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -2145,8 +2145,7 @@ int saa7134_video_init1(struct saa7134_dev *dev) dev->automute = 0; INIT_LIST_HEAD(&dev->video_q.queue); - setup_timer(&dev->video_q.timeout, saa7134_buffer_timeout, - (unsigned long)(&dev->video_q)); + timer_setup(&dev->video_q.timeout, saa7134_buffer_timeout, 0); dev->video_q.dev = dev; dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); dev->width = 720; diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h index 545f7ad8b16d..39c36e6aefbe 100644 --- a/drivers/media/pci/saa7134/saa7134.h +++ b/drivers/media/pci/saa7134/saa7134.h @@ -773,7 +773,7 @@ int saa7134_buffer_queue(struct saa7134_dev *dev, struct saa7134_dmaqueue *q, void saa7134_buffer_finish(struct saa7134_dev *dev, struct saa7134_dmaqueue *q, unsigned int state); void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q); -void saa7134_buffer_timeout(unsigned long data); +void saa7134_buffer_timeout(struct timer_list *t); void saa7134_stop_streaming(struct saa7134_dev *dev, struct saa7134_dmaqueue *q); int saa7134_set_dmabits(struct saa7134_dev *dev); -- cgit v1.2.3 From 1e6be014466e07d3ba95b396d0ea64d11ac0a79d Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Tue, 17 Oct 2017 08:27:24 -0400 Subject: media: davinci: make function arguments const Make the function arguments of functions vpfe_{register/unregister}_ccdc_device const as the pointer dev does not modify the fields of the structure it points to. Also, declare the variable ccdc_dev const as it points to the same structure as dev but it does not modify the fields as well. Signed-off-by: Bhumika Goyal Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/ccdc_hw_device.h | 4 ++-- drivers/media/platform/davinci/vpfe_capture.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/davinci/ccdc_hw_device.h b/drivers/media/platform/davinci/ccdc_hw_device.h index f1b521045d64..3482178cbf01 100644 --- a/drivers/media/platform/davinci/ccdc_hw_device.h +++ b/drivers/media/platform/davinci/ccdc_hw_device.h @@ -82,8 +82,8 @@ struct ccdc_hw_device { }; /* Used by CCDC module to register & unregister with vpfe capture driver */ -int vpfe_register_ccdc_device(struct ccdc_hw_device *dev); -void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev); +int vpfe_register_ccdc_device(const struct ccdc_hw_device *dev); +void vpfe_unregister_ccdc_device(const struct ccdc_hw_device *dev); #endif #endif diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 6792da16d9c7..7b3f6f8e3dc8 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -115,7 +115,7 @@ static struct vpfe_config_params config_params = { }; /* ccdc device registered */ -static struct ccdc_hw_device *ccdc_dev; +static const struct ccdc_hw_device *ccdc_dev; /* lock for accessing ccdc information */ static DEFINE_MUTEX(ccdc_lock); /* ccdc configuration */ @@ -203,7 +203,7 @@ static const struct vpfe_pixel_format *vpfe_lookup_pix_format(u32 pix_format) * vpfe_register_ccdc_device. CCDC module calls this to * register with vpfe capture */ -int vpfe_register_ccdc_device(struct ccdc_hw_device *dev) +int vpfe_register_ccdc_device(const struct ccdc_hw_device *dev) { int ret = 0; printk(KERN_NOTICE "vpfe_register_ccdc_device: %s\n", dev->name); @@ -259,7 +259,7 @@ EXPORT_SYMBOL(vpfe_register_ccdc_device); * vpfe_unregister_ccdc_device. CCDC module calls this to * unregister with vpfe capture */ -void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev) +void vpfe_unregister_ccdc_device(const struct ccdc_hw_device *dev) { if (!dev) { printk(KERN_ERR "invalid ccdc device ptr\n"); -- cgit v1.2.3 From 0cba3f438cd6154621a3b4d66e0875ba213cd7ab Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Tue, 17 Oct 2017 08:27:25 -0400 Subject: media: davinci: make ccdc_hw_device structures const Make these structures const as they are only getting passed to the functions vpfe_{register/unregister}_ccdc_device having the argument as const. Structures found using Coccinelle and changes done by hand. Signed-off-by: Bhumika Goyal Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/dm355_ccdc.c | 2 +- drivers/media/platform/davinci/dm644x_ccdc.c | 2 +- drivers/media/platform/davinci/isif.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/davinci/dm355_ccdc.c b/drivers/media/platform/davinci/dm355_ccdc.c index 6d492dc4c3a9..89cb3094d7e6 100644 --- a/drivers/media/platform/davinci/dm355_ccdc.c +++ b/drivers/media/platform/davinci/dm355_ccdc.c @@ -841,7 +841,7 @@ static int ccdc_set_hw_if_params(struct vpfe_hw_if_param *params) return 0; } -static struct ccdc_hw_device ccdc_hw_dev = { +static const struct ccdc_hw_device ccdc_hw_dev = { .name = "DM355 CCDC", .owner = THIS_MODULE, .hw_ops = { diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c b/drivers/media/platform/davinci/dm644x_ccdc.c index 3b2d8a9317b8..5fa0a1f32536 100644 --- a/drivers/media/platform/davinci/dm644x_ccdc.c +++ b/drivers/media/platform/davinci/dm644x_ccdc.c @@ -776,7 +776,7 @@ static void ccdc_restore_context(void) regw(ccdc_ctx[CCDC_VP_OUT >> 2], CCDC_VP_OUT); regw(ccdc_ctx[CCDC_PCR >> 2], CCDC_PCR); } -static struct ccdc_hw_device ccdc_hw_dev = { +static const struct ccdc_hw_device ccdc_hw_dev = { .name = "DM6446 CCDC", .owner = THIS_MODULE, .hw_ops = { diff --git a/drivers/media/platform/davinci/isif.c b/drivers/media/platform/davinci/isif.c index 5813b49391ed..d5ff58494c1e 100644 --- a/drivers/media/platform/davinci/isif.c +++ b/drivers/media/platform/davinci/isif.c @@ -1000,7 +1000,7 @@ static int isif_close(struct device *device) return 0; } -static struct ccdc_hw_device isif_hw_dev = { +static const struct ccdc_hw_device isif_hw_dev = { .name = "ISIF", .owner = THIS_MODULE, .hw_ops = { -- cgit v1.2.3 From 9cac9d2fb2fe0e0cadacdb94415b3fe49e3f724f Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Tue, 17 Oct 2017 11:48:50 -0400 Subject: media: v4l2-ctrl: Fix flags field on Control events VIDIOC_DQEVENT and VIDIOC_QUERY_EXT_CTRL should give the same output for the control flags field. This patch creates a new function user_flags(), that calculates the user exported flags value (which is different than the kernel internal flags structure). This function is then used by all the code that exports the internal flags to userspace. Reported-by: Dimitrios Katsaros Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Cc: # for v3.17 and up Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 4e53a8654690..c230bd5c6558 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1227,6 +1227,16 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, } EXPORT_SYMBOL(v4l2_ctrl_fill); +static u32 user_flags(const struct v4l2_ctrl *ctrl) +{ + u32 flags = ctrl->flags; + + if (ctrl->is_ptr) + flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD; + + return flags; +} + static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 changes) { memset(ev->reserved, 0, sizeof(ev->reserved)); @@ -1234,7 +1244,7 @@ static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 change ev->id = ctrl->id; ev->u.ctrl.changes = changes; ev->u.ctrl.type = ctrl->type; - ev->u.ctrl.flags = ctrl->flags; + ev->u.ctrl.flags = user_flags(ctrl); if (ctrl->is_ptr) ev->u.ctrl.value64 = 0; else @@ -2577,10 +2587,8 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctr else qc->id = ctrl->id; strlcpy(qc->name, ctrl->name, sizeof(qc->name)); - qc->flags = ctrl->flags; + qc->flags = user_flags(ctrl); qc->type = ctrl->type; - if (ctrl->is_ptr) - qc->flags |= V4L2_CTRL_FLAG_HAS_PAYLOAD; qc->elem_size = ctrl->elem_size; qc->elems = ctrl->elems; qc->nr_of_dims = ctrl->nr_of_dims; -- cgit v1.2.3 From 60757ee62be7ef4f2452265ab20cdf1f0b5d7934 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 18 Oct 2017 04:11:46 -0400 Subject: media: cec-pin: use IS_ERR instead of PTR_ERR_OR_ZERO cec_allocate_adapter never returns NULL, so just use IS_ERR instead of PTR_ERR_OR_ZERO. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-pin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/cec/cec-pin.c b/drivers/media/cec/cec-pin.c index a4c881dc81c4..b48dfe844118 100644 --- a/drivers/media/cec/cec-pin.c +++ b/drivers/media/cec/cec-pin.c @@ -797,7 +797,7 @@ struct cec_adapter *cec_pin_allocate_adapter(const struct cec_pin_ops *pin_ops, caps | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN, CEC_MAX_LOG_ADDRS); - if (PTR_ERR_OR_ZERO(adap)) { + if (IS_ERR(adap)) { kfree(pin); return adap; } -- cgit v1.2.3 From 94b28441c9c7168bfdef932703f968a43ba77f97 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 19 Oct 2017 05:30:34 -0400 Subject: media: rockchip/rga: annotate PM functions as __maybe_unused The newly added driver has incorrect #ifdef annotations on its PM functions, leading to a harmless compile-time warning when CONFIG_PM is disabled: drivers/media/platform/rockchip/rga/rga.c:760:13: error: 'rga_disable_clocks' defined but not used [-Werror=unused-function] static void rga_disable_clocks(struct rockchip_rga *rga) ^~~~~~~~~~~~~~~~~~ drivers/media/platform/rockchip/rga/rga.c:728:12: error: 'rga_enable_clocks' defined but not used [-Werror=unused-function] This removes the #ifdef and marks the functions as __maybe_unused, so gcc can silently drop all the unused code. Fixes: f7e7b48e6d79 ("[media] rockchip/rga: v4l2 m2m support") Signed-off-by: Arnd Bergmann Acked-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rockchip/rga/rga.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c index e7d1b34baf1c..89296de9cf4a 100644 --- a/drivers/media/platform/rockchip/rga/rga.c +++ b/drivers/media/platform/rockchip/rga/rga.c @@ -960,8 +960,7 @@ static int rga_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int rga_runtime_suspend(struct device *dev) +static int __maybe_unused rga_runtime_suspend(struct device *dev) { struct rockchip_rga *rga = dev_get_drvdata(dev); @@ -970,13 +969,12 @@ static int rga_runtime_suspend(struct device *dev) return 0; } -static int rga_runtime_resume(struct device *dev) +static int __maybe_unused rga_runtime_resume(struct device *dev) { struct rockchip_rga *rga = dev_get_drvdata(dev); return rga_enable_clocks(rga); } -#endif static const struct dev_pm_ops rga_pm = { SET_RUNTIME_PM_OPS(rga_runtime_suspend, -- cgit v1.2.3 From 6981d6e55c70b831acf8bea99545adcf940949b5 Mon Sep 17 00:00:00 2001 From: Jaejoong Kim Date: Fri, 20 Oct 2017 03:25:28 -0400 Subject: media: usb: usbtv: remove duplicate & operation usb_endpoint_maxp() has an inline keyword and searches for bits[10:0] by & operation with 0x7ff. So, we can remove the duplicate & operation with 0x7ff. Signed-off-by: Jaejoong Kim Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/usbtv/usbtv-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c index f06f09a0876e..b55b79b8e921 100644 --- a/drivers/media/usb/usbtv/usbtv-core.c +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -84,7 +84,7 @@ static int usbtv_probe(struct usb_interface *intf, /* Packet size is split into 11 bits of base size and count of * extra multiplies of it.*/ size = usb_endpoint_maxp(&ep->desc); - size = (size & 0x07ff) * usb_endpoint_maxp_mult(&ep->desc); + size = size * usb_endpoint_maxp_mult(&ep->desc); /* Device structure */ usbtv = kzalloc(sizeof(struct usbtv), GFP_KERNEL); -- cgit v1.2.3 From 3ddad1ae10c23a700e060edab11eb13ec01ea380 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 21 Oct 2017 04:37:49 -0400 Subject: media: tegra-cec: fix messy probe() cleanup The probe() cleanup code ('goto foo_error') was very messy. It appears that this code wasn't updated when I switched to the devm_ functions in an earlier version. Update the code to use 'return error' where it can and do proper cleanup where it needs to. Note that the original code wasn't buggy, it was just messy. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/tegra-cec/tegra_cec.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/media/platform/tegra-cec/tegra_cec.c b/drivers/media/platform/tegra-cec/tegra_cec.c index b53743f555e8..807c94c70049 100644 --- a/drivers/media/platform/tegra-cec/tegra_cec.c +++ b/drivers/media/platform/tegra-cec/tegra_cec.c @@ -356,40 +356,34 @@ static int tegra_cec_probe(struct platform_device *pdev) if (!res) { dev_err(&pdev->dev, "Unable to allocate resources for device\n"); - ret = -EBUSY; - goto cec_error; + return -EBUSY; } if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), pdev->name)) { dev_err(&pdev->dev, "Unable to request mem region for device\n"); - ret = -EBUSY; - goto cec_error; + return -EBUSY; } cec->tegra_cec_irq = platform_get_irq(pdev, 0); - if (cec->tegra_cec_irq <= 0) { - ret = -EBUSY; - goto cec_error; - } + if (cec->tegra_cec_irq <= 0) + return -EBUSY; cec->cec_base = devm_ioremap_nocache(&pdev->dev, res->start, - resource_size(res)); + resource_size(res)); if (!cec->cec_base) { dev_err(&pdev->dev, "Unable to grab IOs for device\n"); - ret = -EBUSY; - goto cec_error; + return -EBUSY; } cec->clk = devm_clk_get(&pdev->dev, "cec"); if (IS_ERR_OR_NULL(cec->clk)) { dev_err(&pdev->dev, "Can't get clock for CEC\n"); - ret = -ENOENT; - goto clk_error; + return -ENOENT; } clk_prepare_enable(cec->clk); @@ -406,13 +400,13 @@ static int tegra_cec_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "Unable to request interrupt for device\n"); - goto cec_error; + goto clk_error; } cec->notifier = cec_notifier_get(&hdmi_dev->dev); if (!cec->notifier) { ret = -ENOMEM; - goto cec_error; + goto clk_error; } cec->adap = cec_allocate_adapter(&tegra_cec_ops, cec, TEGRA_CEC_NAME, @@ -437,8 +431,8 @@ cec_error: if (cec->notifier) cec_notifier_put(cec->notifier); cec_delete_adapter(cec->adap); - clk_disable_unprepare(cec->clk); clk_error: + clk_disable_unprepare(cec->clk); return ret; } -- cgit v1.2.3 From 162e6376ac58440beb6a2d2ee294f5d88ea58dd1 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 24 Oct 2017 11:22:42 -0400 Subject: media: pci: Convert timers to use timer_setup() In preparation for unconditionally passing the struct timer_list pointer to all timer callbacks, switch to using the new timer_setup() and from_timer() to pass the timer pointer explicitly. Cc: Andy Walls Cc: Sergey Kozlov Cc: Abylay Ospan Cc: Ezequiel Garcia Cc: Arvind Yadav Cc: Geliang Tang Cc: Sean Young Cc: "Pali Rohár" Signed-off-by: Kees Cook [hans.verkuil@cisco.com: dropped pci/ttpci/av7110_ir.c patch chunk] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-driver.c | 6 +++--- drivers/media/pci/bt8xx/bttv-input.c | 19 ++++++++++--------- drivers/media/pci/bt8xx/bttvp.h | 1 + drivers/media/pci/cx18/cx18-fileops.c | 4 ++-- drivers/media/pci/cx18/cx18-fileops.h | 2 +- drivers/media/pci/cx18/cx18-streams.c | 2 +- drivers/media/pci/ivtv/ivtv-driver.c | 3 +-- drivers/media/pci/ivtv/ivtv-irq.c | 4 ++-- drivers/media/pci/ivtv/ivtv-irq.h | 2 +- drivers/media/pci/netup_unidvb/netup_unidvb_core.c | 7 +++---- drivers/media/pci/tw686x/tw686x-core.c | 7 +++---- 11 files changed, 28 insertions(+), 29 deletions(-) diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 227086a2e99c..b366a7e1d976 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -3652,9 +3652,9 @@ bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup, wake_up(&wakeup->vb.done); } -static void bttv_irq_timeout(unsigned long data) +static void bttv_irq_timeout(struct timer_list *t) { - struct bttv *btv = (struct bttv *)data; + struct bttv *btv = from_timer(btv, t, timeout); struct bttv_buffer_set old,new; struct bttv_buffer *ovbi; struct bttv_buffer *item; @@ -4043,7 +4043,7 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) INIT_LIST_HEAD(&btv->capture); INIT_LIST_HEAD(&btv->vcapture); - setup_timer(&btv->timeout, bttv_irq_timeout, (unsigned long)btv); + timer_setup(&btv->timeout, bttv_irq_timeout, 0); btv->i2c_rc = -1; btv->tuner_type = UNSET; diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c index 73d655d073d6..ac7674700685 100644 --- a/drivers/media/pci/bt8xx/bttv-input.c +++ b/drivers/media/pci/bt8xx/bttv-input.c @@ -133,10 +133,10 @@ void bttv_input_irq(struct bttv *btv) ir_handle_key(btv); } -static void bttv_input_timer(unsigned long data) +static void bttv_input_timer(struct timer_list *t) { - struct bttv *btv = (struct bttv*)data; - struct bttv_ir *ir = btv->remote; + struct bttv_ir *ir = from_timer(ir, t, timer); + struct bttv *btv = ir->btv; if (btv->c.type == BTTV_BOARD_ENLTV_FM_2) ir_enltv_handle_key(btv); @@ -189,9 +189,9 @@ static u32 bttv_rc5_decode(unsigned int code) return rc5; } -static void bttv_rc5_timer_end(unsigned long data) +static void bttv_rc5_timer_end(struct timer_list *t) { - struct bttv_ir *ir = (struct bttv_ir *)data; + struct bttv_ir *ir = from_timer(ir, t, timer); ktime_t tv; u32 gap, rc5, scancode; u8 toggle, command, system; @@ -296,15 +296,15 @@ static int bttv_rc5_irq(struct bttv *btv) /* ---------------------------------------------------------------------- */ -static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir) +static void bttv_ir_start(struct bttv_ir *ir) { if (ir->polling) { - setup_timer(&ir->timer, bttv_input_timer, (unsigned long)btv); + timer_setup(&ir->timer, bttv_input_timer, 0); ir->timer.expires = jiffies + msecs_to_jiffies(1000); add_timer(&ir->timer); } else if (ir->rc5_gpio) { /* set timer_end for code completion */ - setup_timer(&ir->timer, bttv_rc5_timer_end, (unsigned long)ir); + timer_setup(&ir->timer, bttv_rc5_timer_end, 0); ir->shift_by = 1; ir->rc5_remote_gap = ir_rc5_remote_gap; } @@ -531,6 +531,7 @@ int bttv_input_init(struct bttv *btv) /* init input device */ ir->dev = rc; + ir->btv = btv; snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)", btv->c.type); @@ -553,7 +554,7 @@ int bttv_input_init(struct bttv *btv) rc->driver_name = MODULE_NAME; btv->remote = ir; - bttv_ir_start(btv, ir); + bttv_ir_start(ir); /* all done */ err = rc_register_device(rc); diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h index 853cbb2f24a4..cb1b5e611130 100644 --- a/drivers/media/pci/bt8xx/bttvp.h +++ b/drivers/media/pci/bt8xx/bttvp.h @@ -122,6 +122,7 @@ struct bttv_format { struct bttv_ir { struct rc_dev *dev; + struct bttv *btv; struct timer_list timer; char name[32]; diff --git a/drivers/media/pci/cx18/cx18-fileops.c b/drivers/media/pci/cx18/cx18-fileops.c index 98467b2089fa..4f9c2395941b 100644 --- a/drivers/media/pci/cx18/cx18-fileops.c +++ b/drivers/media/pci/cx18/cx18-fileops.c @@ -684,9 +684,9 @@ int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma) return -EINVAL; } -void cx18_vb_timeout(unsigned long data) +void cx18_vb_timeout(struct timer_list *t) { - struct cx18_stream *s = (struct cx18_stream *)data; + struct cx18_stream *s = from_timer(s, t, vb_timeout); struct cx18_videobuf_buffer *buf; unsigned long flags; diff --git a/drivers/media/pci/cx18/cx18-fileops.h b/drivers/media/pci/cx18/cx18-fileops.h index 58b00b433708..37ef34e866cb 100644 --- a/drivers/media/pci/cx18/cx18-fileops.h +++ b/drivers/media/pci/cx18/cx18-fileops.h @@ -29,7 +29,7 @@ void cx18_stop_capture(struct cx18_open_id *id, int gop_end); void cx18_mute(struct cx18 *cx); void cx18_unmute(struct cx18 *cx); int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma); -void cx18_vb_timeout(unsigned long data); +void cx18_vb_timeout(struct timer_list *t); /* Shared with cx18-alsa module */ int cx18_claim_stream(struct cx18_open_id *id, int type); diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c index 8385411af641..f35f78d66985 100644 --- a/drivers/media/pci/cx18/cx18-streams.c +++ b/drivers/media/pci/cx18/cx18-streams.c @@ -282,7 +282,7 @@ static void cx18_stream_init(struct cx18 *cx, int type) INIT_WORK(&s->out_work_order, cx18_out_work_handler); INIT_LIST_HEAD(&s->vb_capture); - setup_timer(&s->vb_timeout, cx18_vb_timeout, (unsigned long)s); + timer_setup(&s->vb_timeout, cx18_vb_timeout, 0); spin_lock_init(&s->vb_lock); if (type == CX18_ENC_STREAM_TYPE_YUV) { spin_lock_init(&s->vbuf_q_lock); diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c index 54dcac4b2229..6b2ffdc96961 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.c +++ b/drivers/media/pci/ivtv/ivtv-driver.c @@ -770,8 +770,7 @@ static int ivtv_init_struct1(struct ivtv *itv) init_waitqueue_head(&itv->event_waitq); init_waitqueue_head(&itv->vsync_waitq); init_waitqueue_head(&itv->dma_waitq); - setup_timer(&itv->dma_timer, ivtv_unfinished_dma, - (unsigned long)itv); + timer_setup(&itv->dma_timer, ivtv_unfinished_dma, 0); itv->cur_dma_stream = -1; itv->cur_pio_stream = -1; diff --git a/drivers/media/pci/ivtv/ivtv-irq.c b/drivers/media/pci/ivtv/ivtv-irq.c index 6efe1f71262c..63b09bf73bf0 100644 --- a/drivers/media/pci/ivtv/ivtv-irq.c +++ b/drivers/media/pci/ivtv/ivtv-irq.c @@ -1074,9 +1074,9 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id) return vsync_force ? IRQ_NONE : IRQ_HANDLED; } -void ivtv_unfinished_dma(unsigned long arg) +void ivtv_unfinished_dma(struct timer_list *t) { - struct ivtv *itv = (struct ivtv *)arg; + struct ivtv *itv = from_timer(itv, t, dma_timer); if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) return; diff --git a/drivers/media/pci/ivtv/ivtv-irq.h b/drivers/media/pci/ivtv/ivtv-irq.h index 1e84433737cc..bcab5f07d37f 100644 --- a/drivers/media/pci/ivtv/ivtv-irq.h +++ b/drivers/media/pci/ivtv/ivtv-irq.h @@ -48,6 +48,6 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id); void ivtv_irq_work_handler(struct kthread_work *work); void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock); -void ivtv_unfinished_dma(unsigned long arg); +void ivtv_unfinished_dma(struct timer_list *t); #endif diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c index 60e6cd5b3a03..11829c0fa138 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c @@ -638,9 +638,9 @@ static void netup_unidvb_queue_cleanup(struct netup_dma *dma) spin_unlock_irqrestore(&dma->lock, flags); } -static void netup_unidvb_dma_timeout(unsigned long data) +static void netup_unidvb_dma_timeout(struct timer_list *t) { - struct netup_dma *dma = (struct netup_dma *)data; + struct netup_dma *dma = from_timer(dma, t, timeout); struct netup_unidvb_dev *ndev = dma->ndev; dev_dbg(&ndev->pci_dev->dev, "%s()\n", __func__); @@ -664,8 +664,7 @@ static int netup_unidvb_dma_init(struct netup_unidvb_dev *ndev, int num) spin_lock_init(&dma->lock); INIT_WORK(&dma->work, netup_unidvb_dma_worker); INIT_LIST_HEAD(&dma->free_buffers); - setup_timer(&dma->timeout, netup_unidvb_dma_timeout, - (unsigned long)dma); + timer_setup(&dma->timeout, netup_unidvb_dma_timeout, 0); dma->ring_buffer_size = ndev->dma_size / 2; dma->addr_virt = ndev->dma_virt + dma->ring_buffer_size * num; dma->addr_phys = (dma_addr_t)((u64)ndev->dma_phys + diff --git a/drivers/media/pci/tw686x/tw686x-core.c b/drivers/media/pci/tw686x/tw686x-core.c index 336e2f9bc1b6..c74c23cf8ced 100644 --- a/drivers/media/pci/tw686x/tw686x-core.c +++ b/drivers/media/pci/tw686x/tw686x-core.c @@ -126,9 +126,9 @@ void tw686x_enable_channel(struct tw686x_dev *dev, unsigned int channel) * channels "too fast" which makes some TW686x devices very * angry and freeze the CPU (see note 1). */ -static void tw686x_dma_delay(unsigned long data) +static void tw686x_dma_delay(struct timer_list *t) { - struct tw686x_dev *dev = (struct tw686x_dev *)data; + struct tw686x_dev *dev = from_timer(dev, t, dma_delay_timer); unsigned long flags; spin_lock_irqsave(&dev->lock, flags); @@ -325,8 +325,7 @@ static int tw686x_probe(struct pci_dev *pci_dev, goto iounmap; } - setup_timer(&dev->dma_delay_timer, - tw686x_dma_delay, (unsigned long) dev); + timer_setup(&dev->dma_delay_timer, tw686x_dma_delay, 0); /* * This must be set right before initializing v4l2_dev. -- cgit v1.2.3 From 297fced0f86a27b55729afa6a8e53f45095433a3 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 24 Oct 2017 11:23:03 -0400 Subject: media: radio: Convert timers to use timer_setup() In preparation for unconditionally passing the struct timer_list pointer to all timer callbacks, switch to using the new timer_setup() and from_timer() to pass the timer pointer explicitly. Cc: Hans Verkuil Cc: Mauro Carvalho Chehab Cc: "David S. Miller" Cc: Johannes Berg Signed-off-by: Kees Cook Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-cadet.c | 7 +++---- drivers/media/radio/wl128x/fmdrv_common.c | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 6888b7db449d..7575e5370a49 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -281,9 +281,9 @@ static bool cadet_has_rds_data(struct cadet *dev) } -static void cadet_handler(unsigned long data) +static void cadet_handler(struct timer_list *t) { - struct cadet *dev = (void *)data; + struct cadet *dev = from_timer(dev, t, readtimer); /* Service the RDS fifo */ if (mutex_trylock(&dev->lock)) { @@ -309,7 +309,6 @@ static void cadet_handler(unsigned long data) /* * Clean up and exit */ - setup_timer(&dev->readtimer, cadet_handler, data); dev->readtimer.expires = jiffies + msecs_to_jiffies(50); add_timer(&dev->readtimer); } @@ -318,7 +317,7 @@ static void cadet_start_rds(struct cadet *dev) { dev->rdsstat = 1; outb(0x80, dev->io); /* Select RDS fifo */ - setup_timer(&dev->readtimer, cadet_handler, (unsigned long)dev); + timer_setup(&dev->readtimer, cadet_handler, 0); dev->readtimer.expires = jiffies + msecs_to_jiffies(50); add_timer(&dev->readtimer); } diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index ab3428bf63fe..800d69c3f80b 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -543,13 +543,13 @@ static inline void fm_irq_common_cmd_resp_helper(struct fmdev *fmdev, u8 stage) * interrupt process. Therefore reset stage index to re-enable default * interrupts. So that next interrupt will be processed as usual. */ -static void int_timeout_handler(unsigned long data) +static void int_timeout_handler(struct timer_list *t) { struct fmdev *fmdev; struct fm_irq *fmirq; fmdbg("irq: timeout,trying to re-enable fm interrupts\n"); - fmdev = (struct fmdev *)data; + fmdev = from_timer(fmdev, t, irq_info.timer); fmirq = &fmdev->irq_info; fmirq->retry++; @@ -1550,8 +1550,7 @@ int fmc_prepare(struct fmdev *fmdev) atomic_set(&fmdev->tx_cnt, 1); fmdev->resp_comp = NULL; - setup_timer(&fmdev->irq_info.timer, &int_timeout_handler, - (unsigned long)fmdev); + timer_setup(&fmdev->irq_info.timer, int_timeout_handler, 0); /*TODO: add FM_STIC_EVENT later */ fmdev->irq_info.mask = FM_MAL_EVENT; -- cgit v1.2.3 From 74ee0477512b56c95ad2f7b0035120ada58b88fd Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 24 Oct 2017 11:23:21 -0400 Subject: media: s2255: Convert timers to use timer_setup() In preparation for unconditionally passing the struct timer_list pointer to all timer callbacks, switch to using the new timer_setup() and from_timer() to pass the timer pointer explicitly. Cc: Mauro Carvalho Chehab Cc: Laurent Pinchart Cc: Sakari Ailus Cc: Bhumika Goyal Cc: Mike Isely Cc: Arvind Yadav Signed-off-by: Kees Cook Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/s2255/s2255drv.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index b2f239c4ba42..7fee5766587a 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -485,9 +485,10 @@ static void s2255_reset_dsppower(struct s2255_dev *dev) /* kickstarts the firmware loading. from probe */ -static void s2255_timer(unsigned long user_data) +static void s2255_timer(struct timer_list *t) { - struct s2255_fw *data = (struct s2255_fw *)user_data; + struct s2255_dev *dev = from_timer(dev, t, timer); + struct s2255_fw *data = dev->fw_data; if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { pr_err("s2255: can't submit urb\n"); atomic_set(&data->fw_state, S2255_FW_FAILED); @@ -2283,7 +2284,7 @@ static int s2255_probe(struct usb_interface *interface, dev_err(&interface->dev, "Could not find bulk-in endpoint\n"); goto errorEP; } - setup_timer(&dev->timer, s2255_timer, (unsigned long)dev->fw_data); + timer_setup(&dev->timer, s2255_timer, 0); init_waitqueue_head(&dev->fw_data->wait_fw); for (i = 0; i < MAX_CHANNELS; i++) { struct s2255_vc *vc = &dev->vc[i]; -- cgit v1.2.3 From b3168c87c0492661badc3e908f977d79e7738a41 Mon Sep 17 00:00:00 2001 From: Adam Sampson Date: Tue, 24 Oct 2017 16:14:46 -0400 Subject: media: usbtv: fix brightness and contrast controls Because the brightness and contrast controls share a register, usbtv_s_ctrl needs to read the existing values for both controls before inserting the new value. However, the code accidentally wrote to the registers (from an uninitialised stack array), rather than reading them. The user-visible effect of this was that adjusting the brightness would also set the contrast to a random value, and vice versa -- so it wasn't possible to correctly adjust the brightness of usbtv's video output. Tested with an "EasyDAY" UTV007 device. Fixes: c53a846c48f2 ("usbtv: add video controls") Signed-off-by: Adam Sampson Reviewed-by: Lubomir Rintel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/usbtv/usbtv-video.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 95b5f4319ec2..3668a04359e8 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -718,8 +718,8 @@ static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl) */ if (ctrl->id == V4L2_CID_BRIGHTNESS || ctrl->id == V4L2_CID_CONTRAST) { ret = usb_control_msg(usbtv->udev, - usb_sndctrlpipe(usbtv->udev, 0), USBTV_CONTROL_REG, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + usb_rcvctrlpipe(usbtv->udev, 0), USBTV_CONTROL_REG, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, USBTV_BASE + 0x0244, (void *)data, 3, 0); if (ret < 0) goto error; -- cgit v1.2.3 From 66b72cf1857b508d99f4eabea278e9ec366ee7fd Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 27 Oct 2017 12:20:08 -0400 Subject: media: radio-raremono: remove redundant initialization of freq Variable freq is initialized to f->frequency however this value is never read and freq is later updated; hence the initialization is redundant and can be removed. Cleans up clang warning: drivers/media/radio/radio-raremono.c:257:6: warning: Value stored to 'freq' during its initialization is never read Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-raremono.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/radio/radio-raremono.c b/drivers/media/radio/radio-raremono.c index 3c0a22a54113..70a2c86774ce 100644 --- a/drivers/media/radio/radio-raremono.c +++ b/drivers/media/radio/radio-raremono.c @@ -254,7 +254,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *f) { struct raremono_device *radio = video_drvdata(file); - u32 freq = f->frequency; + u32 freq; unsigned band; if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) -- cgit v1.2.3 From da6a7a7806dfec0d7358bba474084abba03046a3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 28 Oct 2017 05:19:50 -0400 Subject: media: camss-video.c: drop unused header Drop unused vb1 header. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/camss-8x16/camss-video.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/platform/qcom/camss-8x16/camss-video.c b/drivers/media/platform/qcom/camss-8x16/camss-video.c index cf4219e871bd..ffaa2849e0c1 100644 --- a/drivers/media/platform/qcom/camss-8x16/camss-video.c +++ b/drivers/media/platform/qcom/camss-8x16/camss-video.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include "camss-video.h" -- cgit v1.2.3 From d1e2885e1e9bbc8d2d8d90d16c53977477c8d115 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 29 Oct 2017 08:50:58 -0400 Subject: media: mxl111sf: remove redundant assignment to index Variable index is set to zero and then set to zero again a few lines later in a for loop initialization. Remove the redundant setting of index to zero. Cleans up the clang warning: drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c:519:3: warning: Value stored to 'index' is never read Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c index 0eb33e043079..a221bb8a12b4 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c @@ -516,7 +516,6 @@ static int mxl111sf_i2c_hw_xfer_msg(struct mxl111sf_state *state, data required to program */ block_len = (msg->len / 8); left_over_len = (msg->len % 8); - index = 0; mxl_i2c("block_len %d, left_over_len %d", block_len, left_over_len); -- cgit v1.2.3 From a10444cc04eace87e49dea36e360a799112cd889 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 29 Oct 2017 09:06:07 -0400 Subject: media: gspca: remove redundant assignment to variable j Variable j is being set to zero before a loop and also immediately inside the loop and is not used after the loop. Hence the first assignment is redundant and can be removed. Cleans up clang warning: drivers/media/usb/gspca/gspca.c:1078:2: warning: Value stored to 'j' is never read Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/gspca.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 0f141762abf1..961343873fd0 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -1075,7 +1075,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, /* give an index to each format */ index = 0; - j = 0; for (i = gspca_dev->cam.nmodes; --i >= 0; ) { fmt_tb[index] = gspca_dev->cam.cam_mode[i].pixelformat; j = 0; -- cgit v1.2.3 From bf3881707b6f6350c3f8f8ff15524b6d719847bc Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 29 Oct 2017 09:43:39 -0400 Subject: media: bdisp: remove redundant assignment to pix Pointer pix is being initialized to a value and a little later being assigned the same value again. Remove the initial assignment to avoid a duplicate assignment. Cleans up the clang warning: drivers/media/platform/sti/bdisp/bdisp-v4l2.c:726:26: warning: Value stored to 'pix' during its initialization is never read Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/bdisp/bdisp-v4l2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c index 939da6da7644..7e9ed9c7b3e1 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c @@ -723,7 +723,7 @@ static int bdisp_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) static int bdisp_g_fmt(struct file *file, void *fh, struct v4l2_format *f) { struct bdisp_ctx *ctx = fh_to_ctx(fh); - struct v4l2_pix_format *pix = &f->fmt.pix; + struct v4l2_pix_format *pix; struct bdisp_frame *frame = ctx_get_frame(ctx, f->type); if (IS_ERR(frame)) { -- cgit v1.2.3 From d7ca1c9c15e309344e8dcd19826434359dff33b7 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Sun, 29 Oct 2017 20:46:50 -0400 Subject: media: atmel-isc: Fix clock ID for clk_prepare/unprepare Fix the clock ID to do the runtime pm should be ISC_ISPCK, instead of ISC_MCK in clk_prepare(), clk_unprepare() and isc_clk_is_enabled(). Signed-off-by: Wenyou Yang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 8b37656f035d..30f2867c2932 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -598,7 +598,7 @@ static int isc_clk_prepare(struct clk_hw *hw) { struct isc_clk *isc_clk = to_isc_clk(hw); - if (isc_clk->id == ISC_MCK) + if (isc_clk->id == ISC_ISPCK) pm_runtime_get_sync(isc_clk->dev); return isc_wait_clk_stable(hw); @@ -610,7 +610,7 @@ static void isc_clk_unprepare(struct clk_hw *hw) isc_wait_clk_stable(hw); - if (isc_clk->id == ISC_MCK) + if (isc_clk->id == ISC_ISPCK) pm_runtime_put_sync(isc_clk->dev); } @@ -657,12 +657,12 @@ static int isc_clk_is_enabled(struct clk_hw *hw) struct isc_clk *isc_clk = to_isc_clk(hw); u32 status; - if (isc_clk->id == ISC_MCK) + if (isc_clk->id == ISC_ISPCK) pm_runtime_get_sync(isc_clk->dev); regmap_read(isc_clk->regmap, ISC_CLKSR, &status); - if (isc_clk->id == ISC_MCK) + if (isc_clk->id == ISC_ISPCK) pm_runtime_put_sync(isc_clk->dev); return status & ISC_CLK(isc_clk->id) ? 1 : 0; -- cgit v1.2.3 From 3fa013be95bb046490d3b11d546bf06d73c7e0e3 Mon Sep 17 00:00:00 2001 From: Gustavo A. R. Silva Date: Mon, 30 Oct 2017 00:18:47 -0400 Subject: media: st-hva: hva-h264: use swap macro in hva_h264_encode Make use of the swap macro and remove unnecessary variable tmp_frame. This makes the code easier to read and maintain. This code was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/hva/hva-h264.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/media/platform/sti/hva/hva-h264.c b/drivers/media/platform/sti/hva/hva-h264.c index e6f247a983c7..a7e5eed17ada 100644 --- a/drivers/media/platform/sti/hva/hva-h264.c +++ b/drivers/media/platform/sti/hva/hva-h264.c @@ -999,7 +999,6 @@ static int hva_h264_encode(struct hva_ctx *pctx, struct hva_frame *frame, { struct hva_h264_ctx *ctx = (struct hva_h264_ctx *)pctx->priv; struct hva_h264_task *task = (struct hva_h264_task *)ctx->task->vaddr; - struct hva_buffer *tmp_frame; u32 stuffing_bytes = 0; int ret = 0; @@ -1023,9 +1022,7 @@ static int hva_h264_encode(struct hva_ctx *pctx, struct hva_frame *frame, &stream->bytesused); /* switch reference & reconstructed frame */ - tmp_frame = ctx->ref_frame; - ctx->ref_frame = ctx->rec_frame; - ctx->rec_frame = tmp_frame; + swap(ctx->ref_frame, ctx->rec_frame); return 0; err: -- cgit v1.2.3 From 5cc72c472654c493c461898d892e87cde97994be Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Thu, 19 Oct 2017 12:31:20 -0400 Subject: media: adv7180: don't clear V4L2_SUBDEV_FL_IS_I2C The v4l2_i2c_subdev_init() sets V4L2_SUBDEV_FL_IS_I2C flag in the subdev->flags. But this driver overwrites subdev->flags immediately after calling v4l2_i2c_subdev_init(). So V4L2_SUBDEV_FL_IS_I2C is not set after all. This stops breaking subdev->flags and preserves V4L2_SUBDEV_FL_IS_I2C. Side note: According to the comment in v4l2_device_unregister(), this is problematic only if the device is platform bus device. Device tree or ACPI based devices are not affected. Cc: Lars-Peter Clausen Cc: Mauro Carvalho Chehab Signed-off-by: Akinobu Mita Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7180.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 3df28f2f9b38..6fb818a775db 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -1328,7 +1328,7 @@ static int adv7180_probe(struct i2c_client *client, state->input = 0; sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &adv7180_ops); - sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; ret = adv7180_init_controls(state); if (ret) -- cgit v1.2.3 From baf1b186eaa1e0ac3a385c92b1a955b10c59ee84 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Thu, 19 Oct 2017 12:31:21 -0400 Subject: media: max2175: don't clear V4L2_SUBDEV_FL_IS_I2C The v4l2_i2c_subdev_init() sets V4L2_SUBDEV_FL_IS_I2C flag in the subdev->flags. But this driver overwrites subdev->flags immediately after calling v4l2_i2c_subdev_init(). So V4L2_SUBDEV_FL_IS_I2C is not set after all. This stops breaking subdev->flags and preserves V4L2_SUBDEV_FL_IS_I2C. Side note: According to the comment in v4l2_device_unregister(), this is problematic only if the device is platform bus device. Device tree or ACPI based devices are not affected. Cc: Mauro Carvalho Chehab Signed-off-by: Akinobu Mita Acked-by: Ramesh Shanmugasundaram Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/max2175.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/max2175.c b/drivers/media/i2c/max2175.c index bf0e821a2b93..2f1966bdc473 100644 --- a/drivers/media/i2c/max2175.c +++ b/drivers/media/i2c/max2175.c @@ -1345,7 +1345,7 @@ static int max2175_probe(struct i2c_client *client, v4l2_i2c_subdev_init(sd, client, &max2175_ops); ctx->client = client; - sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; /* Controls */ hdl = &ctx->ctrl_hdl; -- cgit v1.2.3 From 6b725eb682a634c6742660f85aa5736ee1009a42 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Thu, 19 Oct 2017 12:31:22 -0400 Subject: media: ov2640: don't clear V4L2_SUBDEV_FL_IS_I2C The v4l2_i2c_subdev_init() sets V4L2_SUBDEV_FL_IS_I2C flag in the subdev->flags. But this driver overwrites subdev->flags immediately after calling v4l2_i2c_subdev_init(). So V4L2_SUBDEV_FL_IS_I2C is not set after all. This stops breaking subdev->flags and preserves V4L2_SUBDEV_FL_IS_I2C. Side note: According to the comment in v4l2_device_unregister(), this is problematic only if the device is platform bus device. Device tree or ACPI based devices are not affected. Cc: Mauro Carvalho Chehab Signed-off-by: Akinobu Mita Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2640.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index 38b8bab7e6aa..518868388d65 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -1115,7 +1115,7 @@ static int ov2640_probe(struct i2c_client *client, goto err_clk; v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops); - priv->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; v4l2_ctrl_handler_init(&priv->hdl, 2); v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); -- cgit v1.2.3 From dae82d9d47e0ffeed7f7efee4e760863cf6fd542 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Thu, 19 Oct 2017 12:31:23 -0400 Subject: media: ov5640: don't clear V4L2_SUBDEV_FL_IS_I2C The v4l2_i2c_subdev_init() sets V4L2_SUBDEV_FL_IS_I2C flag in the subdev->flags. But this driver overwrites subdev->flags immediately after calling v4l2_i2c_subdev_init(). So V4L2_SUBDEV_FL_IS_I2C is not set after all. This stops breaking subdev->flags and preserves V4L2_SUBDEV_FL_IS_I2C. Side note: According to the comment in v4l2_device_unregister(), this is problematic only if the device is platform bus device. Device tree or ACPI based devices are not affected. Cc: Mauro Carvalho Chehab Signed-off-by: Akinobu Mita Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5640.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 39a2269c0bee..c89ed6609738 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -2271,7 +2271,7 @@ static int ov5640_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops); - sensor->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; sensor->pad.flags = MEDIA_PAD_FL_SOURCE; sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); -- cgit v1.2.3 From f283c01b8094da9454f4b51c997f578227c29d95 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 23 Oct 2017 13:30:26 -0400 Subject: media: ov9650: remove unnecessary terminated entry in menu items array The test_pattern_menu[] array has two valid items and a null terminated item. So the control's maximum value which is passed to v4l2_ctrl_new_std_menu_items() should be one. However, 'ARRAY_SIZE(test_pattern_menu) - 1' is actually passed and it's not correct. Fix it by removing unnecessary terminated entry and let the correct control's maximum value be passed to v4l2_ctrl_new_std_menu_items(). Cc: Sylwester Nawrocki Cc: Mauro Carvalho Chehab Signed-off-by: Akinobu Mita Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov9650.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index 6ffb460e8589..69433e1e2533 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -985,7 +985,6 @@ static const struct v4l2_ctrl_ops ov965x_ctrl_ops = { static const char * const test_pattern_menu[] = { "Disabled", "Color bars", - NULL }; static int ov965x_initialize_controls(struct ov965x *ov965x) -- cgit v1.2.3 From de8dd7b2afc3108a0dddd70f0fd897ab89e141ed Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 5 Sep 2017 08:11:59 -0400 Subject: media: v4l: async: Remove re-probing support Remove V4L2 async re-probing support. The re-probing support has been there to support cases where the sub-devices require resources provided by the main driver's hardware to function, such as clocks. Reprobing has allowed unbinding and again binding the main driver without explicitly unbinding the sub-device drivers. This is certainly not a common need, and the responsibility will be the user's going forward. An alternative could have been to introduce notifier specific locks. Considering the complexity of the re-probing and that it isn't really a solution to a problem but a workaround, remove re-probing instead. If there is a need to support the clock provider unregister/register cycle while keeping the clock references in the consumers in the future, this should be implemented in the clock framework instead, not in V4L2. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Acked-by: Niklas Söderlund Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-async.c | 54 +----------------------------------- 1 file changed, 1 insertion(+), 53 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index d741a8e0fdac..60a1a50b9537 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -198,78 +198,26 @@ EXPORT_SYMBOL(v4l2_async_notifier_register); void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) { struct v4l2_subdev *sd, *tmp; - unsigned int notif_n_subdev = notifier->num_subdevs; - unsigned int n_subdev = min(notif_n_subdev, V4L2_MAX_SUBDEVS); - struct device **dev; - int i = 0; if (!notifier->v4l2_dev) return; - dev = kvmalloc_array(n_subdev, sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(notifier->v4l2_dev->dev, - "Failed to allocate device cache!\n"); - } - mutex_lock(&list_lock); list_del(¬ifier->list); list_for_each_entry_safe(sd, tmp, ¬ifier->done, async_list) { - struct device *d; - - d = get_device(sd->dev); - v4l2_async_cleanup(sd); - /* If we handled USB devices, we'd have to lock the parent too */ - device_release_driver(d); - if (notifier->unbind) notifier->unbind(notifier, sd, sd->asd); - /* - * Store device at the device cache, in order to call - * put_device() on the final step - */ - if (dev) - dev[i++] = d; - else - put_device(d); + list_move(&sd->async_list, &subdev_list); } mutex_unlock(&list_lock); - /* - * Call device_attach() to reprobe devices - * - * NOTE: If dev allocation fails, i is 0, and the whole loop won't be - * executed. - */ - while (i--) { - struct device *d = dev[i]; - - if (d && device_attach(d) < 0) { - const char *name = "(none)"; - int lock = device_trylock(d); - - if (lock && d->driver) - name = d->driver->name; - dev_err(d, "Failed to re-probe to %s\n", name); - if (lock) - device_unlock(d); - } - put_device(d); - } - kvfree(dev); - notifier->v4l2_dev = NULL; - - /* - * Don't care about the waiting list, it is initialised and populated - * upon notifier registration. - */ } EXPORT_SYMBOL(v4l2_async_notifier_unregister); -- cgit v1.2.3 From 99b7a995a4a02522292ea6313bd626a33fb0e037 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 3 Oct 2017 07:10:41 -0400 Subject: media: v4l: async: Don't set sd->dev NULL in v4l2_async_cleanup v4l2_async_cleanup() is called when the async sub-device is unbound from the media device. As the pointer is set by the driver registering the async sub-device, leave the pointer as set by the driver. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Acked-by: Hans Verkuil Acked-by: Niklas Söderlund Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-async.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 60a1a50b9537..21c748bf3a7b 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -134,7 +134,6 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd) /* Subdevice driver will reprobe and put the subdev back onto the list */ list_del_init(&sd->async_list); sd->asd = NULL; - sd->dev = NULL; } int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, -- cgit v1.2.3 From 633d185b7239a4b342bab4cc15a414f7d74635ad Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Mon, 2 Oct 2017 16:16:52 -0400 Subject: media: v4l: async: fix unbind error in v4l2_async_notifier_unregister() The call to v4l2_async_cleanup() will set sd->asd to NULL so passing it to notifier->unbind() has no effect and leaves the notifier confused. Call the unbind() callback prior to cleaning up the subdevice to avoid this. Signed-off-by: Niklas Söderlund Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-async.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 21c748bf3a7b..ca281438a0ae 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -206,11 +206,11 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) list_del(¬ifier->list); list_for_each_entry_safe(sd, tmp, ¬ifier->done, async_list) { - v4l2_async_cleanup(sd); - if (notifier->unbind) notifier->unbind(notifier, sd, sd->asd); + v4l2_async_cleanup(sd); + list_move(&sd->async_list, &subdev_list); } @@ -268,11 +268,11 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) list_add(&sd->asd->list, ¬ifier->waiting); - v4l2_async_cleanup(sd); - if (notifier->unbind) notifier->unbind(notifier, sd, sd->asd); + v4l2_async_cleanup(sd); + mutex_unlock(&list_lock); } EXPORT_SYMBOL(v4l2_async_unregister_subdev); -- cgit v1.2.3 From fb45f436b8186cafc95939087ce1dc565be26c3d Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 2 Oct 2017 06:24:54 -0400 Subject: media: v4l: async: Fix notifier complete callback error handling The notifier complete callback may return an error. This error code was simply returned to the caller but never handled properly. Move calling the complete callback function to the caller from v4l2_async_test_notify and undo the work that was done either in async sub-device or async notifier registration. Reported-by: Russell King Signed-off-by: Sakari Ailus Acked-by: Niklas Söderlund Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-async.c | 78 +++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 18 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index ca281438a0ae..4924481451ca 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -122,9 +122,6 @@ static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier, /* Move from the global subdevice list to notifier's done */ list_move(&sd->async_list, ¬ifier->done); - if (list_empty(¬ifier->waiting) && notifier->complete) - return notifier->complete(notifier); - return 0; } @@ -136,11 +133,27 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd) sd->asd = NULL; } +static void v4l2_async_notifier_unbind_all_subdevs( + struct v4l2_async_notifier *notifier) +{ + struct v4l2_subdev *sd, *tmp; + + list_for_each_entry_safe(sd, tmp, ¬ifier->done, async_list) { + if (notifier->unbind) + notifier->unbind(notifier, sd, sd->asd); + + v4l2_async_cleanup(sd); + + list_move(&sd->async_list, &subdev_list); + } +} + int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, struct v4l2_async_notifier *notifier) { struct v4l2_subdev *sd, *tmp; struct v4l2_async_subdev *asd; + int ret; int i; if (!v4l2_dev || !notifier->num_subdevs || @@ -185,19 +198,30 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, } } + if (list_empty(¬ifier->waiting) && notifier->complete) { + ret = notifier->complete(notifier); + if (ret) + goto err_complete; + } + /* Keep also completed notifiers on the list */ list_add(¬ifier->list, ¬ifier_list); mutex_unlock(&list_lock); return 0; + +err_complete: + v4l2_async_notifier_unbind_all_subdevs(notifier); + + mutex_unlock(&list_lock); + + return ret; } EXPORT_SYMBOL(v4l2_async_notifier_register); void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) { - struct v4l2_subdev *sd, *tmp; - if (!notifier->v4l2_dev) return; @@ -205,14 +229,7 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) list_del(¬ifier->list); - list_for_each_entry_safe(sd, tmp, ¬ifier->done, async_list) { - if (notifier->unbind) - notifier->unbind(notifier, sd, sd->asd); - - v4l2_async_cleanup(sd); - - list_move(&sd->async_list, &subdev_list); - } + v4l2_async_notifier_unbind_all_subdevs(notifier); mutex_unlock(&list_lock); @@ -223,6 +240,7 @@ EXPORT_SYMBOL(v4l2_async_notifier_unregister); int v4l2_async_register_subdev(struct v4l2_subdev *sd) { struct v4l2_async_notifier *notifier; + int ret; /* * No reference taken. The reference is held by the device @@ -238,19 +256,43 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd) list_for_each_entry(notifier, ¬ifier_list, list) { struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd); - if (asd) { - int ret = v4l2_async_test_notify(notifier, sd, asd); - mutex_unlock(&list_lock); - return ret; - } + int ret; + + if (!asd) + continue; + + ret = v4l2_async_test_notify(notifier, sd, asd); + if (ret) + goto err_unlock; + + if (!list_empty(¬ifier->waiting) || !notifier->complete) + goto out_unlock; + + ret = notifier->complete(notifier); + if (ret) + goto err_cleanup; + + goto out_unlock; } /* None matched, wait for hot-plugging */ list_add(&sd->async_list, &subdev_list); +out_unlock: mutex_unlock(&list_lock); return 0; + +err_cleanup: + if (notifier->unbind) + notifier->unbind(notifier, sd, sd->asd); + + v4l2_async_cleanup(sd); + +err_unlock: + mutex_unlock(&list_lock); + + return ret; } EXPORT_SYMBOL(v4l2_async_register_subdev); -- cgit v1.2.3 From 7fc4fdb9e1bd821c0bd39543d233ac5246aef2de Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 3 Oct 2017 02:26:32 -0400 Subject: media: v4l: async: Correctly serialise async sub-device unregistration The check whether an async sub-device is bound to a notifier was performed without list_lock held, making it possible for another process to unbind the async sub-device before the sub-device unregistration function proceeds to take the lock. Fix this by first acquiring the lock and then proceeding with the check. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Acked-by: Hans Verkuil Acked-by: Niklas Söderlund Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-async.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 4924481451ca..cde2cf2ab4b0 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -298,20 +298,16 @@ EXPORT_SYMBOL(v4l2_async_register_subdev); void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) { - struct v4l2_async_notifier *notifier = sd->notifier; - - if (!sd->asd) { - if (!list_empty(&sd->async_list)) - v4l2_async_cleanup(sd); - return; - } - mutex_lock(&list_lock); - list_add(&sd->asd->list, ¬ifier->waiting); + if (sd->asd) { + struct v4l2_async_notifier *notifier = sd->notifier; - if (notifier->unbind) - notifier->unbind(notifier, sd, sd->asd); + list_add(&sd->asd->list, ¬ifier->waiting); + + if (notifier->unbind) + notifier->unbind(notifier, sd, sd->asd); + } v4l2_async_cleanup(sd); -- cgit v1.2.3 From c8114d90707d04922a8f23345a88eb6baa19424f Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 4 Sep 2017 12:44:39 -0400 Subject: media: v4l: async: Use more intuitive names for internal functions Rename internal functions to make the names of the functions better describe what they do. Old name New name v4l2_async_test_notify v4l2_async_match_notify v4l2_async_belongs v4l2_async_find_match Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Pavel Machek Reviewed-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Acked-by: Niklas Söderlund Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-async.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index cde2cf2ab4b0..8b84fea50c2a 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -60,8 +60,8 @@ static LIST_HEAD(subdev_list); static LIST_HEAD(notifier_list); static DEFINE_MUTEX(list_lock); -static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *sd) +static struct v4l2_async_subdev *v4l2_async_find_match( + struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd) { bool (*match)(struct v4l2_subdev *, struct v4l2_async_subdev *); struct v4l2_async_subdev *asd; @@ -95,9 +95,9 @@ static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier * return NULL; } -static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *sd, - struct v4l2_async_subdev *asd) +static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sd, + struct v4l2_async_subdev *asd) { int ret; @@ -187,11 +187,11 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) { int ret; - asd = v4l2_async_belongs(notifier, sd); + asd = v4l2_async_find_match(notifier, sd); if (!asd) continue; - ret = v4l2_async_test_notify(notifier, sd, asd); + ret = v4l2_async_match_notify(notifier, sd, asd); if (ret < 0) { mutex_unlock(&list_lock); return ret; @@ -255,13 +255,14 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd) INIT_LIST_HEAD(&sd->async_list); list_for_each_entry(notifier, ¬ifier_list, list) { - struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd); + struct v4l2_async_subdev *asd = v4l2_async_find_match(notifier, + sd); int ret; if (!asd) continue; - ret = v4l2_async_test_notify(notifier, sd, asd); + ret = v4l2_async_match_notify(notifier, sd, asd); if (ret) goto err_unlock; -- cgit v1.2.3 From d65b34135ff86e8e04144ccdfcc2824127e0a7e8 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 29 Aug 2017 06:17:06 -0400 Subject: media: v4l: async: Add V4L2 async documentation to the documentation build The V4L2 async wasn't part of the documentation build. Fix this. Signed-off-by: Sakari Ailus Reviewed-by: Niklas Söderlund Acked-by: Hans Verkuil Reviewed-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/kapi/v4l2-async.rst | 3 +++ Documentation/media/kapi/v4l2-core.rst | 1 + 2 files changed, 4 insertions(+) create mode 100644 Documentation/media/kapi/v4l2-async.rst diff --git a/Documentation/media/kapi/v4l2-async.rst b/Documentation/media/kapi/v4l2-async.rst new file mode 100644 index 000000000000..523ff9eb09a0 --- /dev/null +++ b/Documentation/media/kapi/v4l2-async.rst @@ -0,0 +1,3 @@ +V4L2 async kAPI +^^^^^^^^^^^^^^^ +.. kernel-doc:: include/media/v4l2-async.h diff --git a/Documentation/media/kapi/v4l2-core.rst b/Documentation/media/kapi/v4l2-core.rst index c7434f38fd9c..5cf292037a48 100644 --- a/Documentation/media/kapi/v4l2-core.rst +++ b/Documentation/media/kapi/v4l2-core.rst @@ -19,6 +19,7 @@ Video4Linux devices v4l2-mc v4l2-mediabus v4l2-mem2mem + v4l2-async v4l2-fwnode v4l2-rect v4l2-tuner -- cgit v1.2.3 From 9ca4653121329595443df4e7a458154e8f745edf Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 17 Aug 2017 11:28:21 -0400 Subject: media: v4l: fwnode: Support generic parsing of graph endpoints in a device Add two functions for parsing devices graph endpoints: v4l2_async_notifier_parse_fwnode_endpoints and v4l2_async_notifier_parse_fwnode_endpoints_by_port. The former iterates over all endpoints whereas the latter only iterates over the endpoints in a given port. The former is mostly useful for existing drivers that currently implement the iteration over all the endpoints themselves whereas the latter is especially intended for devices with both sinks and sources: async sub-devices for external devices connected to the device's sources will have already been set up, or the external sub-devices are part of the master device. Depends-on: ("device property: preserve usecount for node passed to of_fwnode_graph_get_port_parent()") Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Niklas Söderlund Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-async.c | 31 ++++++ drivers/media/v4l2-core/v4l2-fwnode.c | 196 ++++++++++++++++++++++++++++++++++ include/media/v4l2-async.h | 24 ++++- include/media/v4l2-fwnode.h | 118 ++++++++++++++++++++ 4 files changed, 367 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 8b84fea50c2a..46aebfc75e43 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -22,6 +22,7 @@ #include #include +#include #include static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) @@ -237,6 +238,36 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) } EXPORT_SYMBOL(v4l2_async_notifier_unregister); +void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier) +{ + unsigned int i; + + if (!notifier->max_subdevs) + return; + + for (i = 0; i < notifier->num_subdevs; i++) { + struct v4l2_async_subdev *asd = notifier->subdevs[i]; + + switch (asd->match_type) { + case V4L2_ASYNC_MATCH_FWNODE: + fwnode_handle_put(asd->match.fwnode.fwnode); + break; + default: + WARN_ON_ONCE(true); + break; + } + + kfree(asd); + } + + notifier->max_subdevs = 0; + notifier->num_subdevs = 0; + + kvfree(notifier->subdevs); + notifier->subdevs = NULL; +} +EXPORT_SYMBOL_GPL(v4l2_async_notifier_cleanup); + int v4l2_async_register_subdev(struct v4l2_subdev *sd) { struct v4l2_async_notifier *notifier; diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 40b2fbfe8865..df0695b7bbcc 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -19,6 +19,7 @@ */ #include #include +#include #include #include #include @@ -26,6 +27,7 @@ #include #include +#include #include enum v4l2_fwnode_bus_type { @@ -388,6 +390,200 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) } EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link); +static int v4l2_async_notifier_realloc(struct v4l2_async_notifier *notifier, + unsigned int max_subdevs) +{ + struct v4l2_async_subdev **subdevs; + + if (max_subdevs <= notifier->max_subdevs) + return 0; + + subdevs = kvmalloc_array( + max_subdevs, sizeof(*notifier->subdevs), + GFP_KERNEL | __GFP_ZERO); + if (!subdevs) + return -ENOMEM; + + if (notifier->subdevs) { + memcpy(subdevs, notifier->subdevs, + sizeof(*subdevs) * notifier->num_subdevs); + + kvfree(notifier->subdevs); + } + + notifier->subdevs = subdevs; + notifier->max_subdevs = max_subdevs; + + return 0; +} + +static int v4l2_async_notifier_fwnode_parse_endpoint( + struct device *dev, struct v4l2_async_notifier *notifier, + struct fwnode_handle *endpoint, unsigned int asd_struct_size, + int (*parse_endpoint)(struct device *dev, + struct v4l2_fwnode_endpoint *vep, + struct v4l2_async_subdev *asd)) +{ + struct v4l2_async_subdev *asd; + struct v4l2_fwnode_endpoint *vep; + int ret = 0; + + asd = kzalloc(asd_struct_size, GFP_KERNEL); + if (!asd) + return -ENOMEM; + + asd->match_type = V4L2_ASYNC_MATCH_FWNODE; + asd->match.fwnode.fwnode = + fwnode_graph_get_remote_port_parent(endpoint); + if (!asd->match.fwnode.fwnode) { + dev_warn(dev, "bad remote port parent\n"); + ret = -EINVAL; + goto out_err; + } + + vep = v4l2_fwnode_endpoint_alloc_parse(endpoint); + if (IS_ERR(vep)) { + ret = PTR_ERR(vep); + dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n", + ret); + goto out_err; + } + + ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0; + if (ret == -ENOTCONN) + dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep->base.port, + vep->base.id); + else if (ret < 0) + dev_warn(dev, + "driver could not parse port@%u/endpoint@%u (%d)\n", + vep->base.port, vep->base.id, ret); + v4l2_fwnode_endpoint_free(vep); + if (ret < 0) + goto out_err; + + notifier->subdevs[notifier->num_subdevs] = asd; + notifier->num_subdevs++; + + return 0; + +out_err: + fwnode_handle_put(asd->match.fwnode.fwnode); + kfree(asd); + + return ret == -ENOTCONN ? 0 : ret; +} + +static int __v4l2_async_notifier_parse_fwnode_endpoints( + struct device *dev, struct v4l2_async_notifier *notifier, + size_t asd_struct_size, unsigned int port, bool has_port, + int (*parse_endpoint)(struct device *dev, + struct v4l2_fwnode_endpoint *vep, + struct v4l2_async_subdev *asd)) +{ + struct fwnode_handle *fwnode; + unsigned int max_subdevs = notifier->max_subdevs; + int ret; + + if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev))) + return -EINVAL; + + for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint( + dev_fwnode(dev), fwnode)); ) { + struct fwnode_handle *dev_fwnode; + bool is_available; + + dev_fwnode = fwnode_graph_get_port_parent(fwnode); + is_available = fwnode_device_is_available(dev_fwnode); + fwnode_handle_put(dev_fwnode); + if (!is_available) + continue; + + if (has_port) { + struct fwnode_endpoint ep; + + ret = fwnode_graph_parse_endpoint(fwnode, &ep); + if (ret) { + fwnode_handle_put(fwnode); + return ret; + } + + if (ep.port != port) + continue; + } + max_subdevs++; + } + + /* No subdevs to add? Return here. */ + if (max_subdevs == notifier->max_subdevs) + return 0; + + ret = v4l2_async_notifier_realloc(notifier, max_subdevs); + if (ret) + return ret; + + for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint( + dev_fwnode(dev), fwnode)); ) { + struct fwnode_handle *dev_fwnode; + bool is_available; + + dev_fwnode = fwnode_graph_get_port_parent(fwnode); + is_available = fwnode_device_is_available(dev_fwnode); + fwnode_handle_put(dev_fwnode); + + if (!fwnode_device_is_available(dev_fwnode)) + continue; + + if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) { + ret = -EINVAL; + break; + } + + if (has_port) { + struct fwnode_endpoint ep; + + ret = fwnode_graph_parse_endpoint(fwnode, &ep); + if (ret) + break; + + if (ep.port != port) + continue; + } + + ret = v4l2_async_notifier_fwnode_parse_endpoint( + dev, notifier, fwnode, asd_struct_size, parse_endpoint); + if (ret < 0) + break; + } + + fwnode_handle_put(fwnode); + + return ret; +} + +int v4l2_async_notifier_parse_fwnode_endpoints( + struct device *dev, struct v4l2_async_notifier *notifier, + size_t asd_struct_size, + int (*parse_endpoint)(struct device *dev, + struct v4l2_fwnode_endpoint *vep, + struct v4l2_async_subdev *asd)) +{ + return __v4l2_async_notifier_parse_fwnode_endpoints( + dev, notifier, asd_struct_size, 0, false, parse_endpoint); +} +EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints); + +int v4l2_async_notifier_parse_fwnode_endpoints_by_port( + struct device *dev, struct v4l2_async_notifier *notifier, + size_t asd_struct_size, unsigned int port, + int (*parse_endpoint)(struct device *dev, + struct v4l2_fwnode_endpoint *vep, + struct v4l2_async_subdev *asd)) +{ + return __v4l2_async_notifier_parse_fwnode_endpoints( + dev, notifier, asd_struct_size, port, true, parse_endpoint); +} +EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Sakari Ailus "); MODULE_AUTHOR("Sylwester Nawrocki "); diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h index c69d8c8a66d0..329aeebd1a80 100644 --- a/include/media/v4l2-async.h +++ b/include/media/v4l2-async.h @@ -18,7 +18,6 @@ struct device; struct device_node; struct v4l2_device; struct v4l2_subdev; -struct v4l2_async_notifier; /* A random max subdevice number, used to allocate an array on stack */ #define V4L2_MAX_SUBDEVS 128U @@ -50,6 +49,10 @@ enum v4l2_async_match_type { * @match: union of per-bus type matching data sets * @list: used to link struct v4l2_async_subdev objects, waiting to be * probed, to a notifier->waiting list + * + * When this struct is used as a member in a driver specific struct, + * the driver specific struct shall contain the &struct + * v4l2_async_subdev as its first member. */ struct v4l2_async_subdev { enum v4l2_async_match_type match_type; @@ -78,7 +81,8 @@ struct v4l2_async_subdev { /** * struct v4l2_async_notifier - v4l2_device notifier data * - * @num_subdevs: number of subdevices + * @num_subdevs: number of subdevices used in the subdevs array + * @max_subdevs: number of subdevices allocated in the subdevs array * @subdevs: array of pointers to subdevice descriptors * @v4l2_dev: pointer to struct v4l2_device * @waiting: list of struct v4l2_async_subdev, waiting for their drivers @@ -90,6 +94,7 @@ struct v4l2_async_subdev { */ struct v4l2_async_notifier { unsigned int num_subdevs; + unsigned int max_subdevs; struct v4l2_async_subdev **subdevs; struct v4l2_device *v4l2_dev; struct list_head waiting; @@ -120,6 +125,21 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, */ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier); +/** + * v4l2_async_notifier_cleanup - clean up notifier resources + * @notifier: the notifier the resources of which are to be cleaned up + * + * Release memory resources related to a notifier, including the async + * sub-devices allocated for the purposes of the notifier but not the notifier + * itself. The user is responsible for calling this function to clean up the + * notifier after calling @v4l2_async_notifier_parse_fwnode_endpoints. + * + * There is no harm from calling v4l2_async_notifier_cleanup in other + * cases as long as its memory has been zeroed after it has been + * allocated. + */ +void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier); + /** * v4l2_async_register_subdev - registers a sub-device to the asynchronous * subdevice framework diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h index 7adec9851d9e..ac605af9b877 100644 --- a/include/media/v4l2-fwnode.h +++ b/include/media/v4l2-fwnode.h @@ -25,6 +25,8 @@ #include struct fwnode_handle; +struct v4l2_async_notifier; +struct v4l2_async_subdev; #define V4L2_FWNODE_CSI2_MAX_DATA_LANES 4 @@ -122,4 +124,120 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode, struct v4l2_fwnode_link *link); void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link); +/** + * v4l2_async_notifier_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints in a + * device node + * @dev: the device the endpoints of which are to be parsed + * @notifier: notifier for @dev + * @asd_struct_size: size of the driver's async sub-device struct, including + * sizeof(struct v4l2_async_subdev). The &struct + * v4l2_async_subdev shall be the first member of + * the driver's async sub-device struct, i.e. both + * begin at the same memory address. + * @parse_endpoint: Driver's callback function called on each V4L2 fwnode + * endpoint. Optional. + * Return: %0 on success + * %-ENOTCONN if the endpoint is to be skipped but this + * should not be considered as an error + * %-EINVAL if the endpoint configuration is invalid + * + * Parse the fwnode endpoints of the @dev device and populate the async sub- + * devices array of the notifier. The @parse_endpoint callback function is + * called for each endpoint with the corresponding async sub-device pointer to + * let the caller initialize the driver-specific part of the async sub-device + * structure. + * + * The notifier memory shall be zeroed before this function is called on the + * notifier. + * + * This function may not be called on a registered notifier and may be called on + * a notifier only once. + * + * Do not change the notifier's subdevs array, take references to the subdevs + * array itself or change the notifier's num_subdevs field. This is because this + * function allocates and reallocates the subdevs array based on parsing + * endpoints. + * + * The &struct v4l2_fwnode_endpoint passed to the callback function + * @parse_endpoint is released once the function is finished. If there is a need + * to retain that configuration, the user needs to allocate memory for it. + * + * Any notifier populated using this function must be released with a call to + * v4l2_async_notifier_cleanup() after it has been unregistered and the async + * sub-devices are no longer in use, even if the function returned an error. + * + * Return: %0 on success, including when no async sub-devices are found + * %-ENOMEM if memory allocation failed + * %-EINVAL if graph or endpoint parsing failed + * Other error codes as returned by @parse_endpoint + */ +int v4l2_async_notifier_parse_fwnode_endpoints( + struct device *dev, struct v4l2_async_notifier *notifier, + size_t asd_struct_size, + int (*parse_endpoint)(struct device *dev, + struct v4l2_fwnode_endpoint *vep, + struct v4l2_async_subdev *asd)); + +/** + * v4l2_async_notifier_parse_fwnode_endpoints_by_port - Parse V4L2 fwnode + * endpoints of a port in a + * device node + * @dev: the device the endpoints of which are to be parsed + * @notifier: notifier for @dev + * @asd_struct_size: size of the driver's async sub-device struct, including + * sizeof(struct v4l2_async_subdev). The &struct + * v4l2_async_subdev shall be the first member of + * the driver's async sub-device struct, i.e. both + * begin at the same memory address. + * @port: port number where endpoints are to be parsed + * @parse_endpoint: Driver's callback function called on each V4L2 fwnode + * endpoint. Optional. + * Return: %0 on success + * %-ENOTCONN if the endpoint is to be skipped but this + * should not be considered as an error + * %-EINVAL if the endpoint configuration is invalid + * + * This function is just like v4l2_async_notifier_parse_fwnode_endpoints() with + * the exception that it only parses endpoints in a given port. This is useful + * on devices that have both sinks and sources: the async sub-devices connected + * to sources have already been configured by another driver (on capture + * devices). In this case the driver must know which ports to parse. + * + * Parse the fwnode endpoints of the @dev device on a given @port and populate + * the async sub-devices array of the notifier. The @parse_endpoint callback + * function is called for each endpoint with the corresponding async sub-device + * pointer to let the caller initialize the driver-specific part of the async + * sub-device structure. + * + * The notifier memory shall be zeroed before this function is called on the + * notifier the first time. + * + * This function may not be called on a registered notifier and may be called on + * a notifier only once per port. + * + * Do not change the notifier's subdevs array, take references to the subdevs + * array itself or change the notifier's num_subdevs field. This is because this + * function allocates and reallocates the subdevs array based on parsing + * endpoints. + * + * The &struct v4l2_fwnode_endpoint passed to the callback function + * @parse_endpoint is released once the function is finished. If there is a need + * to retain that configuration, the user needs to allocate memory for it. + * + * Any notifier populated using this function must be released with a call to + * v4l2_async_notifier_cleanup() after it has been unregistered and the async + * sub-devices are no longer in use, even if the function returned an error. + * + * Return: %0 on success, including when no async sub-devices are found + * %-ENOMEM if memory allocation failed + * %-EINVAL if graph or endpoint parsing failed + * Other error codes as returned by @parse_endpoint + */ +int v4l2_async_notifier_parse_fwnode_endpoints_by_port( + struct device *dev, struct v4l2_async_notifier *notifier, + size_t asd_struct_size, unsigned int port, + int (*parse_endpoint)(struct device *dev, + struct v4l2_fwnode_endpoint *vep, + struct v4l2_async_subdev *asd)); + #endif /* _V4L2_FWNODE_H */ -- cgit v1.2.3 From df4975663f2002f6e6ce9a203f63bfcc51742732 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 1 Sep 2017 17:56:32 -0400 Subject: media: omap3isp: Use generic parser for parsing fwnode endpoints Instead of using a custom driver implementation, use v4l2_async_notifier_parse_fwnode_endpoints() to parse the fwnode endpoints of the device. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Reviewed-by: Laurent Pinchart Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 121 +++++++++++----------------------- drivers/media/platform/omap3isp/isp.h | 5 +- 2 files changed, 40 insertions(+), 86 deletions(-) diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 1a428fe9f070..97a5206b6ddc 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -2001,6 +2001,7 @@ static int isp_remove(struct platform_device *pdev) __omap3isp_put(isp, false); media_entity_enum_cleanup(&isp->crashed); + v4l2_async_notifier_cleanup(&isp->notifier); return 0; } @@ -2011,44 +2012,41 @@ enum isp_of_phy { ISP_OF_PHY_CSIPHY2, }; -static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode, - struct isp_async_subdev *isd) +static int isp_fwnode_parse(struct device *dev, + struct v4l2_fwnode_endpoint *vep, + struct v4l2_async_subdev *asd) { + struct isp_async_subdev *isd = + container_of(asd, struct isp_async_subdev, asd); struct isp_bus_cfg *buscfg = &isd->bus; - struct v4l2_fwnode_endpoint vep; - unsigned int i; - int ret; bool csi1 = false; - - ret = v4l2_fwnode_endpoint_parse(fwnode, &vep); - if (ret) - return ret; + unsigned int i; dev_dbg(dev, "parsing endpoint %pOF, interface %u\n", - to_of_node(fwnode), vep.base.port); + to_of_node(vep->base.local_fwnode), vep->base.port); - switch (vep.base.port) { + switch (vep->base.port) { case ISP_OF_PHY_PARALLEL: buscfg->interface = ISP_INTERFACE_PARALLEL; buscfg->bus.parallel.data_lane_shift = - vep.bus.parallel.data_shift; + vep->bus.parallel.data_shift; buscfg->bus.parallel.clk_pol = - !!(vep.bus.parallel.flags + !!(vep->bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_FALLING); buscfg->bus.parallel.hs_pol = - !!(vep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW); + !!(vep->bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW); buscfg->bus.parallel.vs_pol = - !!(vep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW); + !!(vep->bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW); buscfg->bus.parallel.fld_pol = - !!(vep.bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW); + !!(vep->bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW); buscfg->bus.parallel.data_pol = - !!(vep.bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW); - buscfg->bus.parallel.bt656 = vep.bus_type == V4L2_MBUS_BT656; + !!(vep->bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW); + buscfg->bus.parallel.bt656 = vep->bus_type == V4L2_MBUS_BT656; break; case ISP_OF_PHY_CSIPHY1: case ISP_OF_PHY_CSIPHY2: - switch (vep.bus_type) { + switch (vep->bus_type) { case V4L2_MBUS_CCP2: case V4L2_MBUS_CSI1: dev_dbg(dev, "CSI-1/CCP-2 configuration\n"); @@ -2060,11 +2058,11 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode, break; default: dev_err(dev, "unsupported bus type %u\n", - vep.bus_type); + vep->bus_type); return -EINVAL; } - switch (vep.base.port) { + switch (vep->base.port) { case ISP_OF_PHY_CSIPHY1: if (csi1) buscfg->interface = ISP_INTERFACE_CCP2B_PHY1; @@ -2080,47 +2078,47 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode, } if (csi1) { buscfg->bus.ccp2.lanecfg.clk.pos = - vep.bus.mipi_csi1.clock_lane; + vep->bus.mipi_csi1.clock_lane; buscfg->bus.ccp2.lanecfg.clk.pol = - vep.bus.mipi_csi1.lane_polarity[0]; + vep->bus.mipi_csi1.lane_polarity[0]; dev_dbg(dev, "clock lane polarity %u, pos %u\n", buscfg->bus.ccp2.lanecfg.clk.pol, buscfg->bus.ccp2.lanecfg.clk.pos); buscfg->bus.ccp2.lanecfg.data[0].pos = - vep.bus.mipi_csi1.data_lane; + vep->bus.mipi_csi1.data_lane; buscfg->bus.ccp2.lanecfg.data[0].pol = - vep.bus.mipi_csi1.lane_polarity[1]; + vep->bus.mipi_csi1.lane_polarity[1]; dev_dbg(dev, "data lane polarity %u, pos %u\n", buscfg->bus.ccp2.lanecfg.data[0].pol, buscfg->bus.ccp2.lanecfg.data[0].pos); buscfg->bus.ccp2.strobe_clk_pol = - vep.bus.mipi_csi1.clock_inv; - buscfg->bus.ccp2.phy_layer = vep.bus.mipi_csi1.strobe; + vep->bus.mipi_csi1.clock_inv; + buscfg->bus.ccp2.phy_layer = vep->bus.mipi_csi1.strobe; buscfg->bus.ccp2.ccp2_mode = - vep.bus_type == V4L2_MBUS_CCP2; + vep->bus_type == V4L2_MBUS_CCP2; buscfg->bus.ccp2.vp_clk_pol = 1; buscfg->bus.ccp2.crc = 1; } else { buscfg->bus.csi2.lanecfg.clk.pos = - vep.bus.mipi_csi2.clock_lane; + vep->bus.mipi_csi2.clock_lane; buscfg->bus.csi2.lanecfg.clk.pol = - vep.bus.mipi_csi2.lane_polarities[0]; + vep->bus.mipi_csi2.lane_polarities[0]; dev_dbg(dev, "clock lane polarity %u, pos %u\n", buscfg->bus.csi2.lanecfg.clk.pol, buscfg->bus.csi2.lanecfg.clk.pos); buscfg->bus.csi2.num_data_lanes = - vep.bus.mipi_csi2.num_data_lanes; + vep->bus.mipi_csi2.num_data_lanes; for (i = 0; i < buscfg->bus.csi2.num_data_lanes; i++) { buscfg->bus.csi2.lanecfg.data[i].pos = - vep.bus.mipi_csi2.data_lanes[i]; + vep->bus.mipi_csi2.data_lanes[i]; buscfg->bus.csi2.lanecfg.data[i].pol = - vep.bus.mipi_csi2.lane_polarities[i + 1]; + vep->bus.mipi_csi2.lane_polarities[i + 1]; dev_dbg(dev, "data lane %u polarity %u, pos %u\n", i, buscfg->bus.csi2.lanecfg.data[i].pol, @@ -2137,57 +2135,13 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode, default: dev_warn(dev, "%pOF: invalid interface %u\n", - to_of_node(fwnode), vep.base.port); + to_of_node(vep->base.local_fwnode), vep->base.port); return -EINVAL; } return 0; } -static int isp_fwnodes_parse(struct device *dev, - struct v4l2_async_notifier *notifier) -{ - struct fwnode_handle *fwnode = NULL; - - notifier->subdevs = devm_kcalloc( - dev, ISP_MAX_SUBDEVS, sizeof(*notifier->subdevs), GFP_KERNEL); - if (!notifier->subdevs) - return -ENOMEM; - - while (notifier->num_subdevs < ISP_MAX_SUBDEVS && - (fwnode = fwnode_graph_get_next_endpoint( - of_fwnode_handle(dev->of_node), fwnode))) { - struct isp_async_subdev *isd; - - isd = devm_kzalloc(dev, sizeof(*isd), GFP_KERNEL); - if (!isd) - goto error; - - if (isp_fwnode_parse(dev, fwnode, isd)) { - devm_kfree(dev, isd); - continue; - } - - notifier->subdevs[notifier->num_subdevs] = &isd->asd; - - isd->asd.match.fwnode.fwnode = - fwnode_graph_get_remote_port_parent(fwnode); - if (!isd->asd.match.fwnode.fwnode) { - dev_warn(dev, "bad remote port parent\n"); - goto error; - } - - isd->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; - notifier->num_subdevs++; - } - - return notifier->num_subdevs; - -error: - fwnode_handle_put(fwnode); - return -EINVAL; -} - static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async) { struct isp_device *isp = container_of(async, struct isp_device, @@ -2256,15 +2210,17 @@ static int isp_probe(struct platform_device *pdev) if (ret) return ret; - ret = isp_fwnodes_parse(&pdev->dev, &isp->notifier); - if (ret < 0) - return ret; - isp->autoidle = autoidle; mutex_init(&isp->isp_mutex); spin_lock_init(&isp->stat_lock); + ret = v4l2_async_notifier_parse_fwnode_endpoints( + &pdev->dev, &isp->notifier, sizeof(struct isp_async_subdev), + isp_fwnode_parse); + if (ret < 0) + goto error; + isp->dev = &pdev->dev; isp->ref_count = 0; @@ -2406,6 +2362,7 @@ error_isp: isp_xclk_cleanup(isp); __omap3isp_put(isp, false); error: + v4l2_async_notifier_cleanup(&isp->notifier); mutex_destroy(&isp->isp_mutex); return ret; diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h index e528df6efc09..8b9043db94b3 100644 --- a/drivers/media/platform/omap3isp/isp.h +++ b/drivers/media/platform/omap3isp/isp.h @@ -220,14 +220,11 @@ struct isp_device { unsigned int sbl_resources; unsigned int subclk_resources; - -#define ISP_MAX_SUBDEVS 8 - struct v4l2_subdev *subdevs[ISP_MAX_SUBDEVS]; }; struct isp_async_subdev { - struct isp_bus_cfg bus; struct v4l2_async_subdev asd; + struct isp_bus_cfg bus; }; #define v4l2_subdev_to_bus_cfg(sd) \ -- cgit v1.2.3 From 85999e8ec0ee7cf1039152b34a3fc3d91e7e27c3 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 1 Sep 2017 18:41:19 -0400 Subject: media: rcar-vin: Use generic parser for parsing fwnode endpoints Instead of using a custom driver implementation, use v4l2_async_notifier_parse_fwnode_endpoints() to parse the fwnode endpoints of the device. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Niklas Söderlund Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-core.c | 107 +++++++++------------------- drivers/media/platform/rcar-vin/rcar-dma.c | 10 +-- drivers/media/platform/rcar-vin/rcar-v4l2.c | 14 ++-- drivers/media/platform/rcar-vin/rcar-vin.h | 4 +- 4 files changed, 46 insertions(+), 89 deletions(-) diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 142de447aaaa..380288658601 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -21,6 +21,7 @@ #include #include +#include #include #include "rcar-vin.h" @@ -77,14 +78,14 @@ static int rvin_digital_notify_complete(struct v4l2_async_notifier *notifier) int ret; /* Verify subdevices mbus format */ - if (!rvin_mbus_supported(&vin->digital)) { + if (!rvin_mbus_supported(vin->digital)) { vin_err(vin, "Unsupported media bus format for %s\n", - vin->digital.subdev->name); + vin->digital->subdev->name); return -EINVAL; } vin_dbg(vin, "Found media bus format for %s: %d\n", - vin->digital.subdev->name, vin->digital.code); + vin->digital->subdev->name, vin->digital->code); ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev); if (ret < 0) { @@ -103,7 +104,7 @@ static void rvin_digital_notify_unbind(struct v4l2_async_notifier *notifier, vin_dbg(vin, "unbind digital subdev %s\n", subdev->name); rvin_v4l2_remove(vin); - vin->digital.subdev = NULL; + vin->digital->subdev = NULL; } static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier, @@ -120,117 +121,71 @@ static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier, ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SOURCE); if (ret < 0) return ret; - vin->digital.source_pad = ret; + vin->digital->source_pad = ret; ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SINK); - vin->digital.sink_pad = ret < 0 ? 0 : ret; + vin->digital->sink_pad = ret < 0 ? 0 : ret; - vin->digital.subdev = subdev; + vin->digital->subdev = subdev; vin_dbg(vin, "bound subdev %s source pad: %u sink pad: %u\n", - subdev->name, vin->digital.source_pad, - vin->digital.sink_pad); + subdev->name, vin->digital->source_pad, + vin->digital->sink_pad); return 0; } -static int rvin_digitial_parse_v4l2(struct rvin_dev *vin, - struct device_node *ep, - struct v4l2_mbus_config *mbus_cfg) +static int rvin_digital_parse_v4l2(struct device *dev, + struct v4l2_fwnode_endpoint *vep, + struct v4l2_async_subdev *asd) { - struct v4l2_fwnode_endpoint v4l2_ep; - int ret; + struct rvin_dev *vin = dev_get_drvdata(dev); + struct rvin_graph_entity *rvge = + container_of(asd, struct rvin_graph_entity, asd); - ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &v4l2_ep); - if (ret) { - vin_err(vin, "Could not parse v4l2 endpoint\n"); - return -EINVAL; - } + if (vep->base.port || vep->base.id) + return -ENOTCONN; - mbus_cfg->type = v4l2_ep.bus_type; + rvge->mbus_cfg.type = vep->bus_type; - switch (mbus_cfg->type) { + switch (rvge->mbus_cfg.type) { case V4L2_MBUS_PARALLEL: vin_dbg(vin, "Found PARALLEL media bus\n"); - mbus_cfg->flags = v4l2_ep.bus.parallel.flags; + rvge->mbus_cfg.flags = vep->bus.parallel.flags; break; case V4L2_MBUS_BT656: vin_dbg(vin, "Found BT656 media bus\n"); - mbus_cfg->flags = 0; + rvge->mbus_cfg.flags = 0; break; default: vin_err(vin, "Unknown media bus type\n"); return -EINVAL; } - return 0; -} - -static int rvin_digital_graph_parse(struct rvin_dev *vin) -{ - struct device_node *ep, *np; - int ret; - - vin->digital.asd.match.fwnode.fwnode = NULL; - vin->digital.subdev = NULL; - - /* - * Port 0 id 0 is local digital input, try to get it. - * Not all instances can or will have this, that is OK - */ - ep = of_graph_get_endpoint_by_regs(vin->dev->of_node, 0, 0); - if (!ep) - return 0; - - np = of_graph_get_remote_port_parent(ep); - if (!np) { - vin_err(vin, "No remote parent for digital input\n"); - of_node_put(ep); - return -EINVAL; - } - of_node_put(np); - - ret = rvin_digitial_parse_v4l2(vin, ep, &vin->digital.mbus_cfg); - of_node_put(ep); - if (ret) - return ret; - - vin->digital.asd.match.fwnode.fwnode = of_fwnode_handle(np); - vin->digital.asd.match_type = V4L2_ASYNC_MATCH_FWNODE; + vin->digital = rvge; return 0; } static int rvin_digital_graph_init(struct rvin_dev *vin) { - struct v4l2_async_subdev **subdevs = NULL; int ret; - ret = rvin_digital_graph_parse(vin); + ret = v4l2_async_notifier_parse_fwnode_endpoints( + vin->dev, &vin->notifier, + sizeof(struct rvin_graph_entity), rvin_digital_parse_v4l2); if (ret) return ret; - if (!vin->digital.asd.match.fwnode.fwnode) { - vin_dbg(vin, "No digital subdevice found\n"); + if (!vin->digital) return -ENODEV; - } - - /* Register the subdevices notifier. */ - subdevs = devm_kzalloc(vin->dev, sizeof(*subdevs), GFP_KERNEL); - if (subdevs == NULL) - return -ENOMEM; - - subdevs[0] = &vin->digital.asd; vin_dbg(vin, "Found digital subdevice %pOF\n", - to_of_node(subdevs[0]->match.fwnode.fwnode)); + to_of_node(vin->digital->asd.match.fwnode.fwnode)); - vin->notifier.num_subdevs = 1; - vin->notifier.subdevs = subdevs; vin->notifier.bound = rvin_digital_notify_bound; vin->notifier.unbind = rvin_digital_notify_unbind; vin->notifier.complete = rvin_digital_notify_complete; - ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier); if (ret < 0) { vin_err(vin, "Notifier registration failed\n"); @@ -290,6 +245,8 @@ static int rcar_vin_probe(struct platform_device *pdev) if (ret) return ret; + platform_set_drvdata(pdev, vin); + ret = rvin_digital_graph_init(vin); if (ret < 0) goto error; @@ -297,11 +254,10 @@ static int rcar_vin_probe(struct platform_device *pdev) pm_suspend_ignore_children(&pdev->dev, true); pm_runtime_enable(&pdev->dev); - platform_set_drvdata(pdev, vin); - return 0; error: rvin_dma_remove(vin); + v4l2_async_notifier_cleanup(&vin->notifier); return ret; } @@ -313,6 +269,7 @@ static int rcar_vin_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); v4l2_async_notifier_unregister(&vin->notifier); + v4l2_async_notifier_cleanup(&vin->notifier); rvin_dma_remove(vin); diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index b136844499f6..23fdff7a7370 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -183,7 +183,7 @@ static int rvin_setup(struct rvin_dev *vin) /* * Input interface */ - switch (vin->digital.code) { + switch (vin->digital->code) { case MEDIA_BUS_FMT_YUYV8_1X16: /* BT.601/BT.1358 16bit YCbCr422 */ vnmc |= VNMC_INF_YUV16; @@ -191,7 +191,7 @@ static int rvin_setup(struct rvin_dev *vin) break; case MEDIA_BUS_FMT_UYVY8_2X8: /* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */ - vnmc |= vin->digital.mbus_cfg.type == V4L2_MBUS_BT656 ? + vnmc |= vin->digital->mbus_cfg.type == V4L2_MBUS_BT656 ? VNMC_INF_YUV8_BT656 : VNMC_INF_YUV8_BT601; input_is_yuv = true; break; @@ -200,7 +200,7 @@ static int rvin_setup(struct rvin_dev *vin) break; case MEDIA_BUS_FMT_UYVY10_2X10: /* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */ - vnmc |= vin->digital.mbus_cfg.type == V4L2_MBUS_BT656 ? + vnmc |= vin->digital->mbus_cfg.type == V4L2_MBUS_BT656 ? VNMC_INF_YUV10_BT656 : VNMC_INF_YUV10_BT601; input_is_yuv = true; break; @@ -212,11 +212,11 @@ static int rvin_setup(struct rvin_dev *vin) dmr2 = VNDMR2_FTEV | VNDMR2_VLV(1); /* Hsync Signal Polarity Select */ - if (!(vin->digital.mbus_cfg.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) + if (!(vin->digital->mbus_cfg.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) dmr2 |= VNDMR2_HPS; /* Vsync Signal Polarity Select */ - if (!(vin->digital.mbus_cfg.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) + if (!(vin->digital->mbus_cfg.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) dmr2 |= VNDMR2_VPS; /* diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index dd37ea811680..b479b882da12 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -111,7 +111,7 @@ static int rvin_reset_format(struct rvin_dev *vin) struct v4l2_mbus_framefmt *mf = &fmt.format; int ret; - fmt.pad = vin->digital.source_pad; + fmt.pad = vin->digital->source_pad; ret = v4l2_subdev_call(vin_to_source(vin), pad, get_fmt, NULL, &fmt); if (ret) @@ -172,13 +172,13 @@ static int __rvin_try_format_source(struct rvin_dev *vin, sd = vin_to_source(vin); - v4l2_fill_mbus_format(&format.format, pix, vin->digital.code); + v4l2_fill_mbus_format(&format.format, pix, vin->digital->code); pad_cfg = v4l2_subdev_alloc_pad_config(sd); if (pad_cfg == NULL) return -ENOMEM; - format.pad = vin->digital.source_pad; + format.pad = vin->digital->source_pad; field = pix->field; @@ -555,7 +555,7 @@ static int rvin_enum_dv_timings(struct file *file, void *priv_fh, if (timings->pad) return -EINVAL; - timings->pad = vin->digital.sink_pad; + timings->pad = vin->digital->sink_pad; ret = v4l2_subdev_call(sd, pad, enum_dv_timings, timings); @@ -607,7 +607,7 @@ static int rvin_dv_timings_cap(struct file *file, void *priv_fh, if (cap->pad) return -EINVAL; - cap->pad = vin->digital.sink_pad; + cap->pad = vin->digital->sink_pad; ret = v4l2_subdev_call(sd, pad, dv_timings_cap, cap); @@ -625,7 +625,7 @@ static int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid) if (edid->pad) return -EINVAL; - edid->pad = vin->digital.sink_pad; + edid->pad = vin->digital->sink_pad; ret = v4l2_subdev_call(sd, pad, get_edid, edid); @@ -643,7 +643,7 @@ static int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid) if (edid->pad) return -EINVAL; - edid->pad = vin->digital.sink_pad; + edid->pad = vin->digital->sink_pad; ret = v4l2_subdev_call(sd, pad, set_edid, edid); diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h index 9bfb5a7c4dc4..5382078143fb 100644 --- a/drivers/media/platform/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/rcar-vin/rcar-vin.h @@ -126,7 +126,7 @@ struct rvin_dev { struct v4l2_device v4l2_dev; struct v4l2_ctrl_handler ctrl_handler; struct v4l2_async_notifier notifier; - struct rvin_graph_entity digital; + struct rvin_graph_entity *digital; struct mutex lock; struct vb2_queue queue; @@ -145,7 +145,7 @@ struct rvin_dev { struct v4l2_rect compose; }; -#define vin_to_source(vin) vin->digital.subdev +#define vin_to_source(vin) ((vin)->digital->subdev) /* Debug */ #define vin_dbg(d, fmt, arg...) dev_dbg(d->dev, fmt, ##arg) -- cgit v1.2.3 From eae4cf8f262e35b60928058e36ce1e841a2ab917 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 1 Sep 2017 19:42:05 -0400 Subject: media: omap3isp: Fix check for our own sub-devices We only want to link sub-devices that were bound to the async notifier the isp driver registered but there may be other sub-devices in the v4l2_device as well. Check for the correct async notifier. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Pavel Machek Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 97a5206b6ddc..4afd7ba4fad6 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -2155,7 +2155,7 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async) return ret; list_for_each_entry(sd, &v4l2_dev->subdevs, list) { - if (!sd->asd) + if (sd->notifier != &isp->notifier) continue; ret = isp_link_entity(isp, &sd->entity, -- cgit v1.2.3 From bce9e317cec9c4ffff3dde1170c0ad70f5e690c8 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 1 Sep 2017 19:43:31 -0400 Subject: media: omap3isp: Print the name of the entity where no source pads could be found If no source pads are found in an entity, print the name of the entity. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Pavel Machek Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 4afd7ba4fad6..35687c9707e0 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -1669,8 +1669,8 @@ static int isp_link_entity( break; } if (i == entity->num_pads) { - dev_err(isp->dev, "%s: no source pad in external entity\n", - __func__); + dev_err(isp->dev, "%s: no source pad in external entity %s\n", + __func__, entity->name); return -EINVAL; } -- cgit v1.2.3 From b6ee3f0dcf43dc3e8dbbe9be9c4e728c8d52f1ba Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 30 Aug 2017 13:18:04 -0400 Subject: media: v4l: async: Move async subdev notifier operations to a separate structure The async subdev notifier .bound(), .unbind() and .complete() operations are function pointers stored directly in the v4l2_async_subdev structure. As the structure isn't immutable, this creates a potential security risk as the function pointers are mutable. To fix this, move the function pointers to a new v4l2_async_subdev_operations structure that can be made const in drivers. Signed-off-by: Laurent Pinchart Acked-by: Hans Verkuil Acked-by: Niklas Söderlund Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/am437x/am437x-vpfe.c | 8 +++++-- drivers/media/platform/atmel/atmel-isc.c | 10 ++++++--- drivers/media/platform/atmel/atmel-isi.c | 10 ++++++--- drivers/media/platform/davinci/vpif_capture.c | 8 +++++-- drivers/media/platform/davinci/vpif_display.c | 8 +++++-- drivers/media/platform/exynos4-is/media-dev.c | 8 +++++-- drivers/media/platform/omap3isp/isp.c | 6 +++++- drivers/media/platform/pxa_camera.c | 8 +++++-- drivers/media/platform/qcom/camss-8x16/camss.c | 8 +++++-- drivers/media/platform/rcar-vin/rcar-core.c | 10 ++++++--- drivers/media/platform/rcar_drif.c | 10 ++++++--- drivers/media/platform/soc_camera/soc_camera.c | 14 ++++++------ drivers/media/platform/stm32/stm32-dcmi.c | 10 ++++++--- drivers/media/platform/ti-vpe/cal.c | 8 +++++-- drivers/media/platform/xilinx/xilinx-vipp.c | 8 +++++-- drivers/media/v4l2-core/v4l2-async.c | 30 ++++++++++++-------------- drivers/staging/media/imx/imx-media-dev.c | 8 +++++-- include/media/v4l2-async.h | 29 ++++++++++++++++--------- 18 files changed, 135 insertions(+), 66 deletions(-) diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index dfcc484cab89..0997c640191d 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -2417,6 +2417,11 @@ static int vpfe_async_complete(struct v4l2_async_notifier *notifier) return vpfe_probe_complete(vpfe); } +static const struct v4l2_async_notifier_operations vpfe_async_ops = { + .bound = vpfe_async_bound, + .complete = vpfe_async_complete, +}; + static struct vpfe_config * vpfe_get_pdata(struct platform_device *pdev) { @@ -2590,8 +2595,7 @@ static int vpfe_probe(struct platform_device *pdev) vpfe->notifier.subdevs = vpfe->cfg->asd; vpfe->notifier.num_subdevs = ARRAY_SIZE(vpfe->cfg->asd); - vpfe->notifier.bound = vpfe_async_bound; - vpfe->notifier.complete = vpfe_async_complete; + vpfe->notifier.ops = &vpfe_async_ops; ret = v4l2_async_notifier_register(&vpfe->v4l2_dev, &vpfe->notifier); if (ret) { diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 30f2867c2932..13f1c1c797b0 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -1979,6 +1979,12 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) return 0; } +static const struct v4l2_async_notifier_operations isc_async_ops = { + .bound = isc_async_bound, + .unbind = isc_async_unbind, + .complete = isc_async_complete, +}; + static void isc_subdev_cleanup(struct isc_device *isc) { struct isc_subdev_entity *subdev_entity; @@ -2203,9 +2209,7 @@ static int atmel_isc_probe(struct platform_device *pdev) list_for_each_entry(subdev_entity, &isc->subdev_entities, list) { subdev_entity->notifier.subdevs = &subdev_entity->asd; subdev_entity->notifier.num_subdevs = 1; - subdev_entity->notifier.bound = isc_async_bound; - subdev_entity->notifier.unbind = isc_async_unbind; - subdev_entity->notifier.complete = isc_async_complete; + subdev_entity->notifier.ops = &isc_async_ops; ret = v4l2_async_notifier_register(&isc->v4l2_dev, &subdev_entity->notifier); diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index 463c0146915e..e900995143a3 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -1103,6 +1103,12 @@ static int isi_graph_notify_bound(struct v4l2_async_notifier *notifier, return 0; } +static const struct v4l2_async_notifier_operations isi_graph_notify_ops = { + .bound = isi_graph_notify_bound, + .unbind = isi_graph_notify_unbind, + .complete = isi_graph_notify_complete, +}; + static int isi_graph_parse(struct atmel_isi *isi, struct device_node *node) { struct device_node *ep = NULL; @@ -1150,9 +1156,7 @@ static int isi_graph_init(struct atmel_isi *isi) isi->notifier.subdevs = subdevs; isi->notifier.num_subdevs = 1; - isi->notifier.bound = isi_graph_notify_bound; - isi->notifier.unbind = isi_graph_notify_unbind; - isi->notifier.complete = isi_graph_notify_complete; + isi->notifier.ops = &isi_graph_notify_ops; ret = v4l2_async_notifier_register(&isi->v4l2_dev, &isi->notifier); if (ret < 0) { diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 0ef36cec21d1..a89367ab1e06 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1500,6 +1500,11 @@ static int vpif_async_complete(struct v4l2_async_notifier *notifier) return vpif_probe_complete(); } +static const struct v4l2_async_notifier_operations vpif_async_ops = { + .bound = vpif_async_bound, + .complete = vpif_async_complete, +}; + static struct vpif_capture_config * vpif_capture_get_pdata(struct platform_device *pdev) { @@ -1691,8 +1696,7 @@ static __init int vpif_probe(struct platform_device *pdev) } else { vpif_obj.notifier.subdevs = vpif_obj.config->asd; vpif_obj.notifier.num_subdevs = vpif_obj.config->asd_sizes[0]; - vpif_obj.notifier.bound = vpif_async_bound; - vpif_obj.notifier.complete = vpif_async_complete; + vpif_obj.notifier.ops = &vpif_async_ops; err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev, &vpif_obj.notifier); if (err) { diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 56fe4e5b396e..ff2f75a328c9 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -1232,6 +1232,11 @@ static int vpif_async_complete(struct v4l2_async_notifier *notifier) return vpif_probe_complete(); } +static const struct v4l2_async_notifier_operations vpif_async_ops = { + .bound = vpif_async_bound, + .complete = vpif_async_complete, +}; + /* * vpif_probe: This function creates device entries by register itself to the * V4L2 driver and initializes fields of each channel objects @@ -1313,8 +1318,7 @@ static __init int vpif_probe(struct platform_device *pdev) } else { vpif_obj.notifier.subdevs = vpif_obj.config->asd; vpif_obj.notifier.num_subdevs = vpif_obj.config->asd_sizes[0]; - vpif_obj.notifier.bound = vpif_async_bound; - vpif_obj.notifier.complete = vpif_async_complete; + vpif_obj.notifier.ops = &vpif_async_ops; err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev, &vpif_obj.notifier); if (err) { diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index d4656d5175d7..c15596b56dc9 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -1405,6 +1405,11 @@ unlock: return media_device_register(&fmd->media_dev); } +static const struct v4l2_async_notifier_operations subdev_notifier_ops = { + .bound = subdev_notifier_bound, + .complete = subdev_notifier_complete, +}; + static int fimc_md_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1479,8 +1484,7 @@ static int fimc_md_probe(struct platform_device *pdev) if (fmd->num_sensors > 0) { fmd->subdev_notifier.subdevs = fmd->async_subdevs; fmd->subdev_notifier.num_subdevs = fmd->num_sensors; - fmd->subdev_notifier.bound = subdev_notifier_bound; - fmd->subdev_notifier.complete = subdev_notifier_complete; + fmd->subdev_notifier.ops = &subdev_notifier_ops; fmd->num_sensors = 0; ret = v4l2_async_notifier_register(&fmd->v4l2_dev, diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 35687c9707e0..b7ff3842afc0 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -2171,6 +2171,10 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async) return media_device_register(&isp->media_dev); } +static const struct v4l2_async_notifier_operations isp_subdev_notifier_ops = { + .complete = isp_subdev_notifier_complete, +}; + /* * isp_probe - Probe ISP platform device * @pdev: Pointer to ISP platform device @@ -2341,7 +2345,7 @@ static int isp_probe(struct platform_device *pdev) if (ret < 0) goto error_register_entities; - isp->notifier.complete = isp_subdev_notifier_complete; + isp->notifier.ops = &isp_subdev_notifier_ops; ret = v4l2_async_notifier_register(&isp->v4l2_dev, &isp->notifier); if (ret) diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c index edca993c2b1f..9d3f0cb1d95a 100644 --- a/drivers/media/platform/pxa_camera.c +++ b/drivers/media/platform/pxa_camera.c @@ -2221,6 +2221,11 @@ static void pxa_camera_sensor_unbind(struct v4l2_async_notifier *notifier, mutex_unlock(&pcdev->mlock); } +static const struct v4l2_async_notifier_operations pxa_camera_sensor_ops = { + .bound = pxa_camera_sensor_bound, + .unbind = pxa_camera_sensor_unbind, +}; + /* * Driver probe, remove, suspend and resume operations */ @@ -2489,8 +2494,7 @@ static int pxa_camera_probe(struct platform_device *pdev) pcdev->asds[0] = &pcdev->asd; pcdev->notifier.subdevs = pcdev->asds; pcdev->notifier.num_subdevs = 1; - pcdev->notifier.bound = pxa_camera_sensor_bound; - pcdev->notifier.unbind = pxa_camera_sensor_unbind; + pcdev->notifier.ops = &pxa_camera_sensor_ops; if (!of_have_populated_dt()) pcdev->asd.match_type = V4L2_ASYNC_MATCH_I2C; diff --git a/drivers/media/platform/qcom/camss-8x16/camss.c b/drivers/media/platform/qcom/camss-8x16/camss.c index a3760b5dd1d1..390a42c17b66 100644 --- a/drivers/media/platform/qcom/camss-8x16/camss.c +++ b/drivers/media/platform/qcom/camss-8x16/camss.c @@ -601,6 +601,11 @@ static int camss_subdev_notifier_complete(struct v4l2_async_notifier *async) return media_device_register(&camss->media_dev); } +static const struct v4l2_async_notifier_operations camss_subdev_notifier_ops = { + .bound = camss_subdev_notifier_bound, + .complete = camss_subdev_notifier_complete, +}; + static const struct media_device_ops camss_media_ops = { .link_notify = v4l2_pipeline_link_notify, }; @@ -655,8 +660,7 @@ static int camss_probe(struct platform_device *pdev) goto err_register_entities; if (camss->notifier.num_subdevs) { - camss->notifier.bound = camss_subdev_notifier_bound; - camss->notifier.complete = camss_subdev_notifier_complete; + camss->notifier.ops = &camss_subdev_notifier_ops; ret = v4l2_async_notifier_register(&camss->v4l2_dev, &camss->notifier); diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 380288658601..108d776f3265 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -134,6 +134,12 @@ static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier, return 0; } +static const struct v4l2_async_notifier_operations rvin_digital_notify_ops = { + .bound = rvin_digital_notify_bound, + .unbind = rvin_digital_notify_unbind, + .complete = rvin_digital_notify_complete, +}; + static int rvin_digital_parse_v4l2(struct device *dev, struct v4l2_fwnode_endpoint *vep, @@ -183,9 +189,7 @@ static int rvin_digital_graph_init(struct rvin_dev *vin) vin_dbg(vin, "Found digital subdevice %pOF\n", to_of_node(vin->digital->asd.match.fwnode.fwnode)); - vin->notifier.bound = rvin_digital_notify_bound; - vin->notifier.unbind = rvin_digital_notify_unbind; - vin->notifier.complete = rvin_digital_notify_complete; + vin->notifier.ops = &rvin_digital_notify_ops; ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier); if (ret < 0) { vin_err(vin, "Notifier registration failed\n"); diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c index 2c6afd38b78a..63c94f4028a7 100644 --- a/drivers/media/platform/rcar_drif.c +++ b/drivers/media/platform/rcar_drif.c @@ -1185,6 +1185,12 @@ error: return ret; } +static const struct v4l2_async_notifier_operations rcar_drif_notify_ops = { + .bound = rcar_drif_notify_bound, + .unbind = rcar_drif_notify_unbind, + .complete = rcar_drif_notify_complete, +}; + /* Read endpoint properties */ static void rcar_drif_get_ep_properties(struct rcar_drif_sdr *sdr, struct fwnode_handle *fwnode) @@ -1347,9 +1353,7 @@ static int rcar_drif_sdr_probe(struct rcar_drif_sdr *sdr) if (ret) goto error; - sdr->notifier.bound = rcar_drif_notify_bound; - sdr->notifier.unbind = rcar_drif_notify_unbind; - sdr->notifier.complete = rcar_drif_notify_complete; + sdr->notifier.ops = &rcar_drif_notify_ops; /* Register notifier */ ret = v4l2_async_notifier_register(&sdr->v4l2_dev, &sdr->notifier); diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 1f3c450c7a69..916ff68b73d4 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -1391,6 +1391,12 @@ static int soc_camera_async_complete(struct v4l2_async_notifier *notifier) return 0; } +static const struct v4l2_async_notifier_operations soc_camera_async_ops = { + .bound = soc_camera_async_bound, + .unbind = soc_camera_async_unbind, + .complete = soc_camera_async_complete, +}; + static int scan_async_group(struct soc_camera_host *ici, struct v4l2_async_subdev **asd, unsigned int size) { @@ -1437,9 +1443,7 @@ static int scan_async_group(struct soc_camera_host *ici, sasc->notifier.subdevs = asd; sasc->notifier.num_subdevs = size; - sasc->notifier.bound = soc_camera_async_bound; - sasc->notifier.unbind = soc_camera_async_unbind; - sasc->notifier.complete = soc_camera_async_complete; + sasc->notifier.ops = &soc_camera_async_ops; icd->sasc = sasc; icd->parent = ici->v4l2_dev.dev; @@ -1537,9 +1541,7 @@ static int soc_of_bind(struct soc_camera_host *ici, sasc->notifier.subdevs = &info->subdev; sasc->notifier.num_subdevs = 1; - sasc->notifier.bound = soc_camera_async_bound; - sasc->notifier.unbind = soc_camera_async_unbind; - sasc->notifier.complete = soc_camera_async_complete; + sasc->notifier.ops = &soc_camera_async_ops; icd->sasc = sasc; icd->parent = ici->v4l2_dev.dev; diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index 35ba6f211b79..ac4c450a6c7d 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -1495,6 +1495,12 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier, return 0; } +static const struct v4l2_async_notifier_operations dcmi_graph_notify_ops = { + .bound = dcmi_graph_notify_bound, + .unbind = dcmi_graph_notify_unbind, + .complete = dcmi_graph_notify_complete, +}; + static int dcmi_graph_parse(struct stm32_dcmi *dcmi, struct device_node *node) { struct device_node *ep = NULL; @@ -1542,9 +1548,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi) dcmi->notifier.subdevs = subdevs; dcmi->notifier.num_subdevs = 1; - dcmi->notifier.bound = dcmi_graph_notify_bound; - dcmi->notifier.unbind = dcmi_graph_notify_unbind; - dcmi->notifier.complete = dcmi_graph_notify_complete; + dcmi->notifier.ops = &dcmi_graph_notify_ops; ret = v4l2_async_notifier_register(&dcmi->v4l2_dev, &dcmi->notifier); if (ret < 0) { diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 42e383a48ffe..8b586c864524 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -1522,6 +1522,11 @@ static int cal_async_complete(struct v4l2_async_notifier *notifier) return 0; } +static const struct v4l2_async_notifier_operations cal_async_ops = { + .bound = cal_async_bound, + .complete = cal_async_complete, +}; + static int cal_complete_ctx(struct cal_ctx *ctx) { struct video_device *vfd; @@ -1736,8 +1741,7 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst) ctx->asd_list[0] = asd; ctx->notifier.subdevs = ctx->asd_list; ctx->notifier.num_subdevs = 1; - ctx->notifier.bound = cal_async_bound; - ctx->notifier.complete = cal_async_complete; + ctx->notifier.ops = &cal_async_ops; ret = v4l2_async_notifier_register(&ctx->v4l2_dev, &ctx->notifier); if (ret) { diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c index ebfdf334d99c..d881cf09876d 100644 --- a/drivers/media/platform/xilinx/xilinx-vipp.c +++ b/drivers/media/platform/xilinx/xilinx-vipp.c @@ -351,6 +351,11 @@ static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier, return -EINVAL; } +static const struct v4l2_async_notifier_operations xvip_graph_notify_ops = { + .bound = xvip_graph_notify_bound, + .complete = xvip_graph_notify_complete, +}; + static int xvip_graph_parse_one(struct xvip_composite_device *xdev, struct device_node *node) { @@ -548,8 +553,7 @@ static int xvip_graph_init(struct xvip_composite_device *xdev) xdev->notifier.subdevs = subdevs; xdev->notifier.num_subdevs = num_subdevs; - xdev->notifier.bound = xvip_graph_notify_bound; - xdev->notifier.complete = xvip_graph_notify_complete; + xdev->notifier.ops = &xvip_graph_notify_ops; ret = v4l2_async_notifier_register(&xdev->v4l2_dev, &xdev->notifier); if (ret < 0) { diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 46aebfc75e43..9d6fc5f25619 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -102,16 +102,16 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, { int ret; - if (notifier->bound) { - ret = notifier->bound(notifier, sd, asd); + if (notifier->ops->bound) { + ret = notifier->ops->bound(notifier, sd, asd); if (ret < 0) return ret; } ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd); if (ret < 0) { - if (notifier->unbind) - notifier->unbind(notifier, sd, asd); + if (notifier->ops->unbind) + notifier->ops->unbind(notifier, sd, asd); return ret; } @@ -140,9 +140,8 @@ static void v4l2_async_notifier_unbind_all_subdevs( struct v4l2_subdev *sd, *tmp; list_for_each_entry_safe(sd, tmp, ¬ifier->done, async_list) { - if (notifier->unbind) - notifier->unbind(notifier, sd, sd->asd); - + if (notifier->ops->unbind) + notifier->ops->unbind(notifier, sd, sd->asd); v4l2_async_cleanup(sd); list_move(&sd->async_list, &subdev_list); @@ -199,8 +198,8 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, } } - if (list_empty(¬ifier->waiting) && notifier->complete) { - ret = notifier->complete(notifier); + if (list_empty(¬ifier->waiting) && notifier->ops->complete) { + ret = notifier->ops->complete(notifier); if (ret) goto err_complete; } @@ -297,10 +296,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd) if (ret) goto err_unlock; - if (!list_empty(¬ifier->waiting) || !notifier->complete) + if (!list_empty(¬ifier->waiting) || !notifier->ops->complete) goto out_unlock; - ret = notifier->complete(notifier); + ret = notifier->ops->complete(notifier); if (ret) goto err_cleanup; @@ -316,9 +315,8 @@ out_unlock: return 0; err_cleanup: - if (notifier->unbind) - notifier->unbind(notifier, sd, sd->asd); - + if (notifier->ops->unbind) + notifier->ops->unbind(notifier, sd, sd->asd); v4l2_async_cleanup(sd); err_unlock: @@ -337,8 +335,8 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) list_add(&sd->asd->list, ¬ifier->waiting); - if (notifier->unbind) - notifier->unbind(notifier, sd, sd->asd); + if (notifier->ops->unbind) + notifier->ops->unbind(notifier, sd, sd->asd); } v4l2_async_cleanup(sd); diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c index b55e5ebba8b4..47c4c954fed5 100644 --- a/drivers/staging/media/imx/imx-media-dev.c +++ b/drivers/staging/media/imx/imx-media-dev.c @@ -440,6 +440,11 @@ unlock: return media_device_register(&imxmd->md); } +static const struct v4l2_async_notifier_operations imx_media_subdev_ops = { + .bound = imx_media_subdev_bound, + .complete = imx_media_probe_complete, +}; + /* * adds controls to a video device from an entity subdevice. * Continues upstream from the entity's sink pads. @@ -608,8 +613,7 @@ static int imx_media_probe(struct platform_device *pdev) /* prepare the async subdev notifier and register it */ imxmd->subdev_notifier.subdevs = imxmd->async_ptrs; - imxmd->subdev_notifier.bound = imx_media_subdev_bound; - imxmd->subdev_notifier.complete = imx_media_probe_complete; + imxmd->subdev_notifier.ops = &imx_media_subdev_ops; ret = v4l2_async_notifier_register(&imxmd->v4l2_dev, &imxmd->subdev_notifier); if (ret) { diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h index 329aeebd1a80..68606afb5ef9 100644 --- a/include/media/v4l2-async.h +++ b/include/media/v4l2-async.h @@ -18,6 +18,7 @@ struct device; struct device_node; struct v4l2_device; struct v4l2_subdev; +struct v4l2_async_notifier; /* A random max subdevice number, used to allocate an array on stack */ #define V4L2_MAX_SUBDEVS 128U @@ -78,9 +79,26 @@ struct v4l2_async_subdev { struct list_head list; }; +/** + * struct v4l2_async_notifier_operations - Asynchronous V4L2 notifier operations + * @bound: a subdevice driver has successfully probed one of the subdevices + * @complete: all subdevices have been probed successfully + * @unbind: a subdevice is leaving + */ +struct v4l2_async_notifier_operations { + int (*bound)(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd); + int (*complete)(struct v4l2_async_notifier *notifier); + void (*unbind)(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd); +}; + /** * struct v4l2_async_notifier - v4l2_device notifier data * + * @ops: notifier operations * @num_subdevs: number of subdevices used in the subdevs array * @max_subdevs: number of subdevices allocated in the subdevs array * @subdevs: array of pointers to subdevice descriptors @@ -88,11 +106,9 @@ struct v4l2_async_subdev { * @waiting: list of struct v4l2_async_subdev, waiting for their drivers * @done: list of struct v4l2_subdev, already probed * @list: member in a global list of notifiers - * @bound: a subdevice driver has successfully probed one of subdevices - * @complete: all subdevices have been probed successfully - * @unbind: a subdevice is leaving */ struct v4l2_async_notifier { + const struct v4l2_async_notifier_operations *ops; unsigned int num_subdevs; unsigned int max_subdevs; struct v4l2_async_subdev **subdevs; @@ -100,13 +116,6 @@ struct v4l2_async_notifier { struct list_head waiting; struct list_head done; struct list_head list; - int (*bound)(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *subdev, - struct v4l2_async_subdev *asd); - int (*complete)(struct v4l2_async_notifier *notifier); - void (*unbind)(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *subdev, - struct v4l2_async_subdev *asd); }; /** -- cgit v1.2.3 From ddddc18b219ada692704c5467d16fff8c79cf287 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 1 Sep 2017 08:27:32 -0400 Subject: media: v4l: async: Introduce helpers for calling async ops callbacks Add three helper functions to call async operations callbacks. Besides simplifying callbacks, this allows async notifiers to have no ops set, i.e. it can be left NULL. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Pavel Machek Acked-by: Niklas Söderlund Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-async.c | 56 +++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 9d6fc5f25619..e170682dae78 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -25,6 +25,34 @@ #include #include +static int v4l2_async_notifier_call_bound(struct v4l2_async_notifier *n, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + if (!n->ops || !n->ops->bound) + return 0; + + return n->ops->bound(n, subdev, asd); +} + +static void v4l2_async_notifier_call_unbind(struct v4l2_async_notifier *n, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + if (!n->ops || !n->ops->unbind) + return; + + n->ops->unbind(n, subdev, asd); +} + +static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n) +{ + if (!n->ops || !n->ops->complete) + return 0; + + return n->ops->complete(n); +} + static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) { #if IS_ENABLED(CONFIG_I2C) @@ -102,16 +130,13 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, { int ret; - if (notifier->ops->bound) { - ret = notifier->ops->bound(notifier, sd, asd); - if (ret < 0) - return ret; - } + ret = v4l2_async_notifier_call_bound(notifier, sd, asd); + if (ret < 0) + return ret; ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd); if (ret < 0) { - if (notifier->ops->unbind) - notifier->ops->unbind(notifier, sd, asd); + v4l2_async_notifier_call_unbind(notifier, sd, asd); return ret; } @@ -140,8 +165,7 @@ static void v4l2_async_notifier_unbind_all_subdevs( struct v4l2_subdev *sd, *tmp; list_for_each_entry_safe(sd, tmp, ¬ifier->done, async_list) { - if (notifier->ops->unbind) - notifier->ops->unbind(notifier, sd, sd->asd); + v4l2_async_notifier_call_unbind(notifier, sd, sd->asd); v4l2_async_cleanup(sd); list_move(&sd->async_list, &subdev_list); @@ -198,8 +222,8 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, } } - if (list_empty(¬ifier->waiting) && notifier->ops->complete) { - ret = notifier->ops->complete(notifier); + if (list_empty(¬ifier->waiting)) { + ret = v4l2_async_notifier_call_complete(notifier); if (ret) goto err_complete; } @@ -296,10 +320,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd) if (ret) goto err_unlock; - if (!list_empty(¬ifier->waiting) || !notifier->ops->complete) + if (!list_empty(¬ifier->waiting)) goto out_unlock; - ret = notifier->ops->complete(notifier); + ret = v4l2_async_notifier_call_complete(notifier); if (ret) goto err_cleanup; @@ -315,8 +339,7 @@ out_unlock: return 0; err_cleanup: - if (notifier->ops->unbind) - notifier->ops->unbind(notifier, sd, sd->asd); + v4l2_async_notifier_call_unbind(notifier, sd, sd->asd); v4l2_async_cleanup(sd); err_unlock: @@ -335,8 +358,7 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) list_add(&sd->asd->list, ¬ifier->waiting); - if (notifier->ops->unbind) - notifier->ops->unbind(notifier, sd, sd->asd); + v4l2_async_notifier_call_unbind(notifier, sd, sd->asd); } v4l2_async_cleanup(sd); -- cgit v1.2.3 From 24def9b586349ec1ecea7989fc219e688d1d1e74 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 17 Jul 2017 10:04:20 -0400 Subject: media: v4l: async: Register sub-devices before calling bound callback Register the sub-device before calling the notifier's bound callback. Doing this the other way around is problematic as the struct v4l2_device has not assigned for the sub-device yet and may be required by the bound callback. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Pavel Machek Acked-by: Niklas Söderlund Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-async.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index e170682dae78..46db85685894 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -130,13 +130,13 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, { int ret; - ret = v4l2_async_notifier_call_bound(notifier, sd, asd); + ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd); if (ret < 0) return ret; - ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd); + ret = v4l2_async_notifier_call_bound(notifier, sd, asd); if (ret < 0) { - v4l2_async_notifier_call_unbind(notifier, sd, asd); + v4l2_device_unregister_subdev(sd); return ret; } -- cgit v1.2.3 From 479bc5a8c662e9d9de47e95ee26ebaf15f36a771 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 6 Sep 2017 10:48:33 -0400 Subject: media: v4l: async: Allow async notifier register call succeed with no subdevs The information on how many async sub-devices would be bindable to a notifier is typically dependent on information from platform firmware and it's not driver's business to be aware of that. Many V4L2 main drivers are perfectly usable (and useful) without async sub-devices and so if there aren't any around, just proceed call the notifier's complete callback immediately without registering the notifier itself. If a driver needs to check whether there are async sub-devices available, it can be done by inspecting the notifier's num_subdevs field which tells the number of async sub-devices. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Niklas Söderlund Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-async.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 46db85685894..1b536d68cedf 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -180,14 +180,22 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, int ret; int i; - if (!v4l2_dev || !notifier->num_subdevs || - notifier->num_subdevs > V4L2_MAX_SUBDEVS) + if (!v4l2_dev || notifier->num_subdevs > V4L2_MAX_SUBDEVS) return -EINVAL; notifier->v4l2_dev = v4l2_dev; INIT_LIST_HEAD(¬ifier->waiting); INIT_LIST_HEAD(¬ifier->done); + if (!notifier->num_subdevs) { + int ret; + + ret = v4l2_async_notifier_call_complete(notifier); + notifier->v4l2_dev = NULL; + + return ret; + } + for (i = 0; i < notifier->num_subdevs; i++) { asd = notifier->subdevs[i]; -- cgit v1.2.3 From a3620cb48d303f07160694c00d9c1c8f0ea96690 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sun, 24 Sep 2017 20:48:08 -0400 Subject: media: v4l: async: Prepare for async sub-device notifiers Refactor the V4L2 async framework a little in preparation for async sub-device notifiers. This avoids making some structural changes in the patch actually implementing sub-device notifiers, making that patch easier to review. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Niklas Söderlund Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-async.c | 69 ++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 19 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 1b536d68cedf..6265717769d2 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -125,12 +125,13 @@ static struct v4l2_async_subdev *v4l2_async_find_match( } static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, + struct v4l2_device *v4l2_dev, struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) { int ret; - ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd); + ret = v4l2_device_register_subdev(v4l2_dev, sd); if (ret < 0) return ret; @@ -151,6 +152,29 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, return 0; } +/* Test all async sub-devices in a notifier for a match. */ +static int v4l2_async_notifier_try_all_subdevs( + struct v4l2_async_notifier *notifier) +{ + struct v4l2_device *v4l2_dev = notifier->v4l2_dev; + struct v4l2_subdev *sd, *tmp; + + list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) { + struct v4l2_async_subdev *asd; + int ret; + + asd = v4l2_async_find_match(notifier, sd); + if (!asd) + continue; + + ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd); + if (ret < 0) + return ret; + } + + return 0; +} + static void v4l2_async_cleanup(struct v4l2_subdev *sd) { v4l2_device_unregister_subdev(sd); @@ -172,18 +196,15 @@ static void v4l2_async_notifier_unbind_all_subdevs( } } -int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, - struct v4l2_async_notifier *notifier) +static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier) { - struct v4l2_subdev *sd, *tmp; struct v4l2_async_subdev *asd; int ret; int i; - if (!v4l2_dev || notifier->num_subdevs > V4L2_MAX_SUBDEVS) + if (notifier->num_subdevs > V4L2_MAX_SUBDEVS) return -EINVAL; - notifier->v4l2_dev = v4l2_dev; INIT_LIST_HEAD(¬ifier->waiting); INIT_LIST_HEAD(¬ifier->done); @@ -216,18 +237,10 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, mutex_lock(&list_lock); - list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) { - int ret; - - asd = v4l2_async_find_match(notifier, sd); - if (!asd) - continue; - - ret = v4l2_async_match_notify(notifier, sd, asd); - if (ret < 0) { - mutex_unlock(&list_lock); - return ret; - } + ret = v4l2_async_notifier_try_all_subdevs(notifier); + if (ret) { + mutex_unlock(&list_lock); + return ret; } if (list_empty(¬ifier->waiting)) { @@ -250,6 +263,23 @@ err_complete: return ret; } + +int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, + struct v4l2_async_notifier *notifier) +{ + int ret; + + if (WARN_ON(!v4l2_dev)) + return -EINVAL; + + notifier->v4l2_dev = v4l2_dev; + + ret = __v4l2_async_notifier_register(notifier); + if (ret) + notifier->v4l2_dev = NULL; + + return ret; +} EXPORT_SYMBOL(v4l2_async_notifier_register); void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) @@ -324,7 +354,8 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd) if (!asd) continue; - ret = v4l2_async_match_notify(notifier, sd, asd); + ret = v4l2_async_match_notify(notifier, notifier->v4l2_dev, sd, + asd); if (ret) goto err_unlock; -- cgit v1.2.3 From 2cab00bb076b9f0e8442e3d72425843d2b441143 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sun, 24 Sep 2017 20:54:31 -0400 Subject: media: v4l: async: Allow binding notifiers to sub-devices Registering a notifier has required the knowledge of struct v4l2_device for the reason that sub-devices generally are registered to the v4l2_device (as well as the media device, also available through v4l2_device). This information is not available for sub-device drivers at probe time. What this patch does is that it allows registering notifiers without having v4l2_device around. Instead the sub-device pointer is stored in the notifier. Once the sub-device of the driver that registered the notifier is registered, the notifier will gain the knowledge of the v4l2_device, and the binding of async sub-devices from the sub-device driver's notifier may proceed. The complete callback of the root notifier will be called only when the v4l2_device is available and no notifier has pending sub-devices to bind. No complete callbacks are supported for sub-device notifiers. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Niklas Söderlund Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-async.c | 212 ++++++++++++++++++++++++++++------- include/media/v4l2-async.h | 19 +++- 2 files changed, 189 insertions(+), 42 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 6265717769d2..ed539c4fd5dc 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -124,11 +124,87 @@ static struct v4l2_async_subdev *v4l2_async_find_match( return NULL; } +/* Find the sub-device notifier registered by a sub-device driver. */ +static struct v4l2_async_notifier *v4l2_async_find_subdev_notifier( + struct v4l2_subdev *sd) +{ + struct v4l2_async_notifier *n; + + list_for_each_entry(n, ¬ifier_list, list) + if (n->sd == sd) + return n; + + return NULL; +} + +/* Get v4l2_device related to the notifier if one can be found. */ +static struct v4l2_device *v4l2_async_notifier_find_v4l2_dev( + struct v4l2_async_notifier *notifier) +{ + while (notifier->parent) + notifier = notifier->parent; + + return notifier->v4l2_dev; +} + +/* + * Return true if all child sub-device notifiers are complete, false otherwise. + */ +static bool v4l2_async_notifier_can_complete( + struct v4l2_async_notifier *notifier) +{ + struct v4l2_subdev *sd; + + if (!list_empty(¬ifier->waiting)) + return false; + + list_for_each_entry(sd, ¬ifier->done, async_list) { + struct v4l2_async_notifier *subdev_notifier = + v4l2_async_find_subdev_notifier(sd); + + if (subdev_notifier && + !v4l2_async_notifier_can_complete(subdev_notifier)) + return false; + } + + return true; +} + +/* + * Complete the master notifier if possible. This is done when all async + * sub-devices have been bound; v4l2_device is also available then. + */ +static int v4l2_async_notifier_try_complete( + struct v4l2_async_notifier *notifier) +{ + /* Quick check whether there are still more sub-devices here. */ + if (!list_empty(¬ifier->waiting)) + return 0; + + /* Check the entire notifier tree; find the root notifier first. */ + while (notifier->parent) + notifier = notifier->parent; + + /* This is root if it has v4l2_dev. */ + if (!notifier->v4l2_dev) + return 0; + + /* Is everything ready? */ + if (!v4l2_async_notifier_can_complete(notifier)) + return 0; + + return v4l2_async_notifier_call_complete(notifier); +} + +static int v4l2_async_notifier_try_all_subdevs( + struct v4l2_async_notifier *notifier); + static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, struct v4l2_device *v4l2_dev, struct v4l2_subdev *sd, struct v4l2_async_subdev *asd) { + struct v4l2_async_notifier *subdev_notifier; int ret; ret = v4l2_device_register_subdev(v4l2_dev, sd); @@ -149,17 +225,36 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier, /* Move from the global subdevice list to notifier's done */ list_move(&sd->async_list, ¬ifier->done); - return 0; + /* + * See if the sub-device has a notifier. If not, return here. + */ + subdev_notifier = v4l2_async_find_subdev_notifier(sd); + if (!subdev_notifier || subdev_notifier->parent) + return 0; + + /* + * Proceed with checking for the sub-device notifier's async + * sub-devices, and return the result. The error will be handled by the + * caller. + */ + subdev_notifier->parent = notifier; + + return v4l2_async_notifier_try_all_subdevs(subdev_notifier); } /* Test all async sub-devices in a notifier for a match. */ static int v4l2_async_notifier_try_all_subdevs( struct v4l2_async_notifier *notifier) { - struct v4l2_device *v4l2_dev = notifier->v4l2_dev; - struct v4l2_subdev *sd, *tmp; + struct v4l2_device *v4l2_dev = + v4l2_async_notifier_find_v4l2_dev(notifier); + struct v4l2_subdev *sd; + + if (!v4l2_dev) + return 0; - list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) { +again: + list_for_each_entry(sd, &subdev_list, async_list) { struct v4l2_async_subdev *asd; int ret; @@ -170,6 +265,14 @@ static int v4l2_async_notifier_try_all_subdevs( ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd); if (ret < 0) return ret; + + /* + * v4l2_async_match_notify() may lead to registering a + * new notifier and thus changing the async subdevs + * list. In order to proceed safely from here, restart + * parsing the list from the beginning. + */ + goto again; } return 0; @@ -183,17 +286,26 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd) sd->asd = NULL; } +/* Unbind all sub-devices in the notifier tree. */ static void v4l2_async_notifier_unbind_all_subdevs( struct v4l2_async_notifier *notifier) { struct v4l2_subdev *sd, *tmp; list_for_each_entry_safe(sd, tmp, ¬ifier->done, async_list) { + struct v4l2_async_notifier *subdev_notifier = + v4l2_async_find_subdev_notifier(sd); + + if (subdev_notifier) + v4l2_async_notifier_unbind_all_subdevs(subdev_notifier); + v4l2_async_notifier_call_unbind(notifier, sd, sd->asd); v4l2_async_cleanup(sd); list_move(&sd->async_list, &subdev_list); } + + notifier->parent = NULL; } static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier) @@ -208,15 +320,6 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier) INIT_LIST_HEAD(¬ifier->waiting); INIT_LIST_HEAD(¬ifier->done); - if (!notifier->num_subdevs) { - int ret; - - ret = v4l2_async_notifier_call_complete(notifier); - notifier->v4l2_dev = NULL; - - return ret; - } - for (i = 0; i < notifier->num_subdevs; i++) { asd = notifier->subdevs[i]; @@ -238,16 +341,12 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier) mutex_lock(&list_lock); ret = v4l2_async_notifier_try_all_subdevs(notifier); - if (ret) { - mutex_unlock(&list_lock); - return ret; - } + if (ret) + goto err_unbind; - if (list_empty(¬ifier->waiting)) { - ret = v4l2_async_notifier_call_complete(notifier); - if (ret) - goto err_complete; - } + ret = v4l2_async_notifier_try_complete(notifier); + if (ret) + goto err_unbind; /* Keep also completed notifiers on the list */ list_add(¬ifier->list, ¬ifier_list); @@ -256,7 +355,10 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier) return 0; -err_complete: +err_unbind: + /* + * On failure, unbind all sub-devices registered through this notifier. + */ v4l2_async_notifier_unbind_all_subdevs(notifier); mutex_unlock(&list_lock); @@ -269,7 +371,7 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, { int ret; - if (WARN_ON(!v4l2_dev)) + if (WARN_ON(!v4l2_dev || notifier->sd)) return -EINVAL; notifier->v4l2_dev = v4l2_dev; @@ -282,20 +384,39 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, } EXPORT_SYMBOL(v4l2_async_notifier_register); +int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd, + struct v4l2_async_notifier *notifier) +{ + int ret; + + if (WARN_ON(!sd || notifier->v4l2_dev)) + return -EINVAL; + + notifier->sd = sd; + + ret = __v4l2_async_notifier_register(notifier); + if (ret) + notifier->sd = NULL; + + return ret; +} +EXPORT_SYMBOL(v4l2_async_subdev_notifier_register); + void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) { - if (!notifier->v4l2_dev) + if (!notifier->v4l2_dev && !notifier->sd) return; mutex_lock(&list_lock); - list_del(¬ifier->list); - v4l2_async_notifier_unbind_all_subdevs(notifier); - mutex_unlock(&list_lock); - + notifier->sd = NULL; notifier->v4l2_dev = NULL; + + list_del(¬ifier->list); + + mutex_unlock(&list_lock); } EXPORT_SYMBOL(v4l2_async_notifier_unregister); @@ -331,6 +452,7 @@ EXPORT_SYMBOL_GPL(v4l2_async_notifier_cleanup); int v4l2_async_register_subdev(struct v4l2_subdev *sd) { + struct v4l2_async_notifier *subdev_notifier; struct v4l2_async_notifier *notifier; int ret; @@ -347,24 +469,26 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd) INIT_LIST_HEAD(&sd->async_list); list_for_each_entry(notifier, ¬ifier_list, list) { - struct v4l2_async_subdev *asd = v4l2_async_find_match(notifier, - sd); + struct v4l2_device *v4l2_dev = + v4l2_async_notifier_find_v4l2_dev(notifier); + struct v4l2_async_subdev *asd; int ret; + if (!v4l2_dev) + continue; + + asd = v4l2_async_find_match(notifier, sd); if (!asd) continue; ret = v4l2_async_match_notify(notifier, notifier->v4l2_dev, sd, asd); if (ret) - goto err_unlock; - - if (!list_empty(¬ifier->waiting)) - goto out_unlock; + goto err_unbind; - ret = v4l2_async_notifier_call_complete(notifier); + ret = v4l2_async_notifier_try_complete(notifier); if (ret) - goto err_cleanup; + goto err_unbind; goto out_unlock; } @@ -377,11 +501,19 @@ out_unlock: return 0; -err_cleanup: - v4l2_async_notifier_call_unbind(notifier, sd, sd->asd); +err_unbind: + /* + * Complete failed. Unbind the sub-devices bound through registering + * this async sub-device. + */ + subdev_notifier = v4l2_async_find_subdev_notifier(sd); + if (subdev_notifier) + v4l2_async_notifier_unbind_all_subdevs(subdev_notifier); + + if (sd->asd) + v4l2_async_notifier_call_unbind(notifier, sd, sd->asd); v4l2_async_cleanup(sd); -err_unlock: mutex_unlock(&list_lock); return ret; diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h index 68606afb5ef9..17c4ac7c73e8 100644 --- a/include/media/v4l2-async.h +++ b/include/media/v4l2-async.h @@ -82,7 +82,8 @@ struct v4l2_async_subdev { /** * struct v4l2_async_notifier_operations - Asynchronous V4L2 notifier operations * @bound: a subdevice driver has successfully probed one of the subdevices - * @complete: all subdevices have been probed successfully + * @complete: All subdevices have been probed successfully. The complete + * callback is only executed for the root notifier. * @unbind: a subdevice is leaving */ struct v4l2_async_notifier_operations { @@ -102,7 +103,9 @@ struct v4l2_async_notifier_operations { * @num_subdevs: number of subdevices used in the subdevs array * @max_subdevs: number of subdevices allocated in the subdevs array * @subdevs: array of pointers to subdevice descriptors - * @v4l2_dev: pointer to struct v4l2_device + * @v4l2_dev: v4l2_device of the root notifier, NULL otherwise + * @sd: sub-device that registered the notifier, NULL otherwise + * @parent: parent notifier * @waiting: list of struct v4l2_async_subdev, waiting for their drivers * @done: list of struct v4l2_subdev, already probed * @list: member in a global list of notifiers @@ -113,6 +116,8 @@ struct v4l2_async_notifier { unsigned int max_subdevs; struct v4l2_async_subdev **subdevs; struct v4l2_device *v4l2_dev; + struct v4l2_subdev *sd; + struct v4l2_async_notifier *parent; struct list_head waiting; struct list_head done; struct list_head list; @@ -127,6 +132,16 @@ struct v4l2_async_notifier { int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev, struct v4l2_async_notifier *notifier); +/** + * v4l2_async_subdev_notifier_register - registers a subdevice asynchronous + * notifier for a sub-device + * + * @sd: pointer to &struct v4l2_subdev + * @notifier: pointer to &struct v4l2_async_notifier + */ +int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd, + struct v4l2_async_notifier *notifier); + /** * v4l2_async_notifier_unregister - unregisters a subdevice asynchronous notifier * -- cgit v1.2.3 From 466cae66eaa13c4895a80c19d7d8d3019c46ae6b Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 20 Sep 2017 03:51:54 -0400 Subject: media: v4l: async: Ensure only unique fwnodes are registered to notifiers While registering a notifier, check that each newly added fwnode is unique, and return an error if it is not. Also check that a newly added notifier does not have the same fwnodes twice. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Niklas Söderlund Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-async.c | 86 +++++++++++++++++++++++++++++++++--- 1 file changed, 79 insertions(+), 7 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index ed539c4fd5dc..57bd54016064 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -308,8 +308,71 @@ static void v4l2_async_notifier_unbind_all_subdevs( notifier->parent = NULL; } +/* See if an fwnode can be found in a notifier's lists. */ +static bool __v4l2_async_notifier_fwnode_has_async_subdev( + struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode) +{ + struct v4l2_async_subdev *asd; + struct v4l2_subdev *sd; + + list_for_each_entry(asd, ¬ifier->waiting, list) { + if (asd->match_type != V4L2_ASYNC_MATCH_FWNODE) + continue; + + if (asd->match.fwnode.fwnode == fwnode) + return true; + } + + list_for_each_entry(sd, ¬ifier->done, async_list) { + if (WARN_ON(!sd->asd)) + continue; + + if (sd->asd->match_type != V4L2_ASYNC_MATCH_FWNODE) + continue; + + if (sd->asd->match.fwnode.fwnode == fwnode) + return true; + } + + return false; +} + +/* + * Find out whether an async sub-device was set up for an fwnode already or + * whether it exists in a given notifier before @this_index. + */ +static bool v4l2_async_notifier_fwnode_has_async_subdev( + struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode, + unsigned int this_index) +{ + unsigned int j; + + lockdep_assert_held(&list_lock); + + /* Check that an fwnode is not being added more than once. */ + for (j = 0; j < this_index; j++) { + struct v4l2_async_subdev *asd = notifier->subdevs[this_index]; + struct v4l2_async_subdev *other_asd = notifier->subdevs[j]; + + if (other_asd->match_type == V4L2_ASYNC_MATCH_FWNODE && + asd->match.fwnode.fwnode == + other_asd->match.fwnode.fwnode) + return true; + } + + /* Check than an fwnode did not exist in other notifiers. */ + list_for_each_entry(notifier, ¬ifier_list, list) + if (__v4l2_async_notifier_fwnode_has_async_subdev( + notifier, fwnode)) + return true; + + return false; +} + static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier) { + struct device *dev = + notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL; struct v4l2_async_subdev *asd; int ret; int i; @@ -320,6 +383,8 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier) INIT_LIST_HEAD(¬ifier->waiting); INIT_LIST_HEAD(¬ifier->done); + mutex_lock(&list_lock); + for (i = 0; i < notifier->num_subdevs; i++) { asd = notifier->subdevs[i]; @@ -327,25 +392,31 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier) case V4L2_ASYNC_MATCH_CUSTOM: case V4L2_ASYNC_MATCH_DEVNAME: case V4L2_ASYNC_MATCH_I2C: + break; case V4L2_ASYNC_MATCH_FWNODE: + if (v4l2_async_notifier_fwnode_has_async_subdev( + notifier, asd->match.fwnode.fwnode, i)) { + dev_err(dev, + "fwnode has already been registered or in notifier's subdev list\n"); + ret = -EEXIST; + goto err_unlock; + } break; default: - dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL, - "Invalid match type %u on %p\n", + dev_err(dev, "Invalid match type %u on %p\n", asd->match_type, asd); - return -EINVAL; + ret = -EINVAL; + goto err_unlock; } list_add_tail(&asd->list, ¬ifier->waiting); } - mutex_lock(&list_lock); - ret = v4l2_async_notifier_try_all_subdevs(notifier); - if (ret) + if (ret < 0) goto err_unbind; ret = v4l2_async_notifier_try_complete(notifier); - if (ret) + if (ret < 0) goto err_unbind; /* Keep also completed notifiers on the list */ @@ -361,6 +432,7 @@ err_unbind: */ v4l2_async_notifier_unbind_all_subdevs(notifier); +err_unlock: mutex_unlock(&list_lock); return ret; -- cgit v1.2.3 From 26baf6dd63ddd2808561926cae6ecf16f56de38c Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 3 Mar 2017 13:14:02 -0500 Subject: media: dt: bindings: Add a binding for flash LED devices associated to a sensor Camera flash drivers (and LEDs) are separate from the sensor devices in DT. In order to make an association between the two, provide the association information to the software. Signed-off-by: Sakari Ailus Cc: devicetree@vger.kernel.org Acked-by: Hans Verkuil Acked-by: Pavel Machek Acked-by: Rob Herring Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/video-interfaces.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt index bd6474920510..dc66e3224692 100644 --- a/Documentation/devicetree/bindings/media/video-interfaces.txt +++ b/Documentation/devicetree/bindings/media/video-interfaces.txt @@ -76,6 +76,14 @@ are required in a relevant parent node: identifier, should be 1. - #size-cells : should be zero. + +Optional properties +------------------- + +- flash-leds: An array of phandles, each referring to a flash LED, a sub-node + of the LED driver device node. + + Optional endpoint properties ---------------------------- -- cgit v1.2.3 From 95293f79d53995142ed1f66be70216a6cbfc36f4 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 3 Mar 2017 17:07:51 -0500 Subject: media: dt: bindings: Add lens-focus binding for image sensors The lens-focus property contains a phandle to the lens voice coil driver that is associated to the sensor; typically both are contained in the same camera module. Signed-off-by: Sakari Ailus Cc: devicetree@vger.kernel.org Acked-by: Pavel Machek Reviewed-by: Sebastian Reichel Acked-by: Rob Herring Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/video-interfaces.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt index dc66e3224692..3994b0143dd1 100644 --- a/Documentation/devicetree/bindings/media/video-interfaces.txt +++ b/Documentation/devicetree/bindings/media/video-interfaces.txt @@ -83,6 +83,8 @@ Optional properties - flash-leds: An array of phandles, each referring to a flash LED, a sub-node of the LED driver device node. +- lens-focus: A phandle to the node of the focus lens controller. + Optional endpoint properties ---------------------------- -- cgit v1.2.3 From baf249e40fddd1793c7970b5afe7f10945dcfb0c Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 29 Aug 2017 06:13:19 -0400 Subject: media: v4l: fwnode: Move KernelDoc documentation to the header In V4L2 the practice is to have the KernelDoc documentation in the header and not in .c source code files. This consequently makes the V4L2 fwnode function documentation part of the Media documentation build. Also correct the link related function and argument naming in documentation and add an asterisk to v4l2_fwnode_endpoint_free() documentation to make it proper KernelDoc documentation. Signed-off-by: Sakari Ailus Reviewed-by: Niklas Söderlund Acked-by: Hans Verkuil Acked-by: Pavel Machek Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-fwnode.c | 75 -------------------------------- include/media/v4l2-fwnode.h | 81 ++++++++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 76 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index df0695b7bbcc..65bdcd59744a 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -183,25 +183,6 @@ v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode, vep->bus_type = V4L2_MBUS_CSI1; } -/** - * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties - * @fwnode: pointer to the endpoint's fwnode handle - * @vep: pointer to the V4L2 fwnode data structure - * - * All properties are optional. If none are found, we don't set any flags. This - * means the port has a static configuration and no properties have to be - * specified explicitly. If any properties that identify the bus as parallel - * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if - * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we - * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a - * reference to @fwnode. - * - * NOTE: This function does not parse properties the size of which is variable - * without a low fixed limit. Please use v4l2_fwnode_endpoint_alloc_parse() in - * new drivers instead. - * - * Return: 0 on success or a negative error code on failure. - */ int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep) { @@ -241,14 +222,6 @@ int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode, } EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse); -/* - * v4l2_fwnode_endpoint_free() - free the V4L2 fwnode acquired by - * v4l2_fwnode_endpoint_alloc_parse() - * @vep - the V4L2 fwnode the resources of which are to be released - * - * It is safe to call this function with NULL argument or on a V4L2 fwnode the - * parsing of which failed. - */ void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep) { if (IS_ERR_OR_NULL(vep)) @@ -259,29 +232,6 @@ void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep) } EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free); -/** - * v4l2_fwnode_endpoint_alloc_parse() - parse all fwnode node properties - * @fwnode: pointer to the endpoint's fwnode handle - * - * All properties are optional. If none are found, we don't set any flags. This - * means the port has a static configuration and no properties have to be - * specified explicitly. If any properties that identify the bus as parallel - * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if - * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we - * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a - * reference to @fwnode. - * - * v4l2_fwnode_endpoint_alloc_parse() has two important differences to - * v4l2_fwnode_endpoint_parse(): - * - * 1. It also parses variable size data. - * - * 2. The memory it has allocated to store the variable size data must be freed - * using v4l2_fwnode_endpoint_free() when no longer needed. - * - * Return: Pointer to v4l2_fwnode_endpoint if successful, on an error pointer - * on error. - */ struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse( struct fwnode_handle *fwnode) { @@ -324,24 +274,6 @@ out_err: } EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse); -/** - * v4l2_fwnode_endpoint_parse_link() - parse a link between two endpoints - * @__fwnode: pointer to the endpoint's fwnode at the local end of the link - * @link: pointer to the V4L2 fwnode link data structure - * - * Fill the link structure with the local and remote nodes and port numbers. - * The local_node and remote_node fields are set to point to the local and - * remote port's parent nodes respectively (the port parent node being the - * parent node of the port node if that node isn't a 'ports' node, or the - * grand-parent node of the port node otherwise). - * - * A reference is taken to both the local and remote nodes, the caller must use - * v4l2_fwnode_endpoint_put_link() to drop the references when done with the - * link. - * - * Return: 0 on success, or -ENOLINK if the remote endpoint fwnode can't be - * found. - */ int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode, struct v4l2_fwnode_link *link) { @@ -376,13 +308,6 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode, } EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link); -/** - * v4l2_fwnode_put_link() - drop references to nodes in a link - * @link: pointer to the V4L2 fwnode link data structure - * - * Drop references to the local and remote nodes in the link. This function - * must be called on every link parsed with v4l2_fwnode_parse_link(). - */ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) { fwnode_handle_put(link->local_node); diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h index ac605af9b877..105cfeee44ef 100644 --- a/include/media/v4l2-fwnode.h +++ b/include/media/v4l2-fwnode.h @@ -115,13 +115,92 @@ struct v4l2_fwnode_link { unsigned int remote_port; }; +/** + * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties + * @fwnode: pointer to the endpoint's fwnode handle + * @vep: pointer to the V4L2 fwnode data structure + * + * All properties are optional. If none are found, we don't set any flags. This + * means the port has a static configuration and no properties have to be + * specified explicitly. If any properties that identify the bus as parallel + * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if + * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we + * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a + * reference to @fwnode. + * + * NOTE: This function does not parse properties the size of which is variable + * without a low fixed limit. Please use v4l2_fwnode_endpoint_alloc_parse() in + * new drivers instead. + * + * Return: 0 on success or a negative error code on failure. + */ int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep); + +/** + * v4l2_fwnode_endpoint_free() - free the V4L2 fwnode acquired by + * v4l2_fwnode_endpoint_alloc_parse() + * @vep: the V4L2 fwnode the resources of which are to be released + * + * It is safe to call this function with NULL argument or on a V4L2 fwnode the + * parsing of which failed. + */ +void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep); + +/** + * v4l2_fwnode_endpoint_alloc_parse() - parse all fwnode node properties + * @fwnode: pointer to the endpoint's fwnode handle + * + * All properties are optional. If none are found, we don't set any flags. This + * means the port has a static configuration and no properties have to be + * specified explicitly. If any properties that identify the bus as parallel + * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if + * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we + * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a + * reference to @fwnode. + * + * v4l2_fwnode_endpoint_alloc_parse() has two important differences to + * v4l2_fwnode_endpoint_parse(): + * + * 1. It also parses variable size data. + * + * 2. The memory it has allocated to store the variable size data must be freed + * using v4l2_fwnode_endpoint_free() when no longer needed. + * + * Return: Pointer to v4l2_fwnode_endpoint if successful, on an error pointer + * on error. + */ struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse( struct fwnode_handle *fwnode); -void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep); + +/** + * v4l2_fwnode_parse_link() - parse a link between two endpoints + * @fwnode: pointer to the endpoint's fwnode at the local end of the link + * @link: pointer to the V4L2 fwnode link data structure + * + * Fill the link structure with the local and remote nodes and port numbers. + * The local_node and remote_node fields are set to point to the local and + * remote port's parent nodes respectively (the port parent node being the + * parent node of the port node if that node isn't a 'ports' node, or the + * grand-parent node of the port node otherwise). + * + * A reference is taken to both the local and remote nodes, the caller must use + * v4l2_fwnode_put_link() to drop the references when done with the + * link. + * + * Return: 0 on success, or -ENOLINK if the remote endpoint fwnode can't be + * found. + */ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode, struct v4l2_fwnode_link *link); + +/** + * v4l2_fwnode_put_link() - drop references to nodes in a link + * @link: pointer to the V4L2 fwnode link data structure + * + * Drop references to the local and remote nodes in the link. This function + * must be called on every link parsed with v4l2_fwnode_parse_link(). + */ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link); /** -- cgit v1.2.3 From d84285390f0722fb6844880c48fbe7db8a183fc1 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 20 Jun 2017 07:47:24 -0400 Subject: media: v4l: fwnode: Add a helper function for parsing generic references Add function v4l2_fwnode_reference_parse() for parsing them as async sub-devices. This can be done on e.g. flash or lens async sub-devices that are not part of but are associated with a sensor. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Niklas Söderlund Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-fwnode.c | 69 +++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 65bdcd59744a..edd2e8d983a1 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -509,6 +509,75 @@ int v4l2_async_notifier_parse_fwnode_endpoints_by_port( } EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port); +/* + * v4l2_fwnode_reference_parse - parse references for async sub-devices + * @dev: the device node the properties of which are parsed for references + * @notifier: the async notifier where the async subdevs will be added + * @prop: the name of the property + * + * Return: 0 on success + * -ENOENT if no entries were found + * -ENOMEM if memory allocation failed + * -EINVAL if property parsing failed + */ +static int v4l2_fwnode_reference_parse( + struct device *dev, struct v4l2_async_notifier *notifier, + const char *prop) +{ + struct fwnode_reference_args args; + unsigned int index; + int ret; + + for (index = 0; + !(ret = fwnode_property_get_reference_args( + dev_fwnode(dev), prop, NULL, 0, index, &args)); + index++) + fwnode_handle_put(args.fwnode); + + if (!index) + return -ENOENT; + + /* + * Note that right now both -ENODATA and -ENOENT may signal + * out-of-bounds access. Return the error in cases other than that. + */ + if (ret != -ENOENT && ret != -ENODATA) + return ret; + + ret = v4l2_async_notifier_realloc(notifier, + notifier->num_subdevs + index); + if (ret) + return ret; + + for (index = 0; !fwnode_property_get_reference_args( + dev_fwnode(dev), prop, NULL, 0, index, &args); + index++) { + struct v4l2_async_subdev *asd; + + if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) { + ret = -EINVAL; + goto error; + } + + asd = kzalloc(sizeof(*asd), GFP_KERNEL); + if (!asd) { + ret = -ENOMEM; + goto error; + } + + notifier->subdevs[notifier->num_subdevs] = asd; + asd->match.fwnode.fwnode = args.fwnode; + asd->match_type = V4L2_ASYNC_MATCH_FWNODE; + notifier->num_subdevs++; + } + + return 0; + +error: + fwnode_handle_put(args.fwnode); + return ret; +} + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Sakari Ailus "); MODULE_AUTHOR("Sylwester Nawrocki "); -- cgit v1.2.3 From a1699a4e525dedd2ecd03ce5f92e80c058e14e28 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 22 Jun 2017 08:03:28 -0400 Subject: media: v4l: fwnode: Add a helper function to obtain device / integer references v4l2_fwnode_reference_parse_int_prop() will find an fwnode such that under the device's own fwnode, it will follow child fwnodes with the given property-value pair and return the resulting fwnode. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-fwnode.c | 287 ++++++++++++++++++++++++++++++++++ 1 file changed, 287 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index edd2e8d983a1..f8cd88f791c4 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -578,6 +578,293 @@ error: return ret; } +/* + * v4l2_fwnode_reference_get_int_prop - parse a reference with integer + * arguments + * @fwnode: fwnode to read @prop from + * @notifier: notifier for @dev + * @prop: the name of the property + * @index: the index of the reference to get + * @props: the array of integer property names + * @nprops: the number of integer property names in @nprops + * + * First find an fwnode referred to by the reference at @index in @prop. + * + * Then under that fwnode, @nprops times, for each property in @props, + * iteratively follow child nodes starting from fwnode such that they have the + * property in @props array at the index of the child node distance from the + * root node and the value of that property matching with the integer argument + * of the reference, at the same index. + * + * The child fwnode reched at the end of the iteration is then returned to the + * caller. + * + * The core reason for this is that you cannot refer to just any node in ACPI. + * So to refer to an endpoint (easy in DT) you need to refer to a device, then + * provide a list of (property name, property value) tuples where each tuple + * uniquely identifies a child node. The first tuple identifies a child directly + * underneath the device fwnode, the next tuple identifies a child node + * underneath the fwnode identified by the previous tuple, etc. until you + * reached the fwnode you need. + * + * An example with a graph, as defined in Documentation/acpi/dsd/graph.txt: + * + * Scope (\_SB.PCI0.I2C2) + * { + * Device (CAM0) + * { + * Name (_DSD, Package () { + * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + * Package () { + * Package () { + * "compatible", + * Package () { "nokia,smia" } + * }, + * }, + * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), + * Package () { + * Package () { "port0", "PRT0" }, + * } + * }) + * Name (PRT0, Package() { + * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + * Package () { + * Package () { "port", 0 }, + * }, + * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), + * Package () { + * Package () { "endpoint0", "EP00" }, + * } + * }) + * Name (EP00, Package() { + * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + * Package () { + * Package () { "endpoint", 0 }, + * Package () { + * "remote-endpoint", + * Package() { + * \_SB.PCI0.ISP, 4, 0 + * } + * }, + * } + * }) + * } + * } + * + * Scope (\_SB.PCI0) + * { + * Device (ISP) + * { + * Name (_DSD, Package () { + * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), + * Package () { + * Package () { "port4", "PRT4" }, + * } + * }) + * + * Name (PRT4, Package() { + * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + * Package () { + * Package () { "port", 4 }, + * }, + * ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"), + * Package () { + * Package () { "endpoint0", "EP40" }, + * } + * }) + * + * Name (EP40, Package() { + * ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), + * Package () { + * Package () { "endpoint", 0 }, + * Package () { + * "remote-endpoint", + * Package () { + * \_SB.PCI0.I2C2.CAM0, + * 0, 0 + * } + * }, + * } + * }) + * } + * } + * + * From the EP40 node under ISP device, you could parse the graph remote + * endpoint using v4l2_fwnode_reference_get_int_prop with these arguments: + * + * @fwnode: fwnode referring to EP40 under ISP. + * @prop: "remote-endpoint" + * @index: 0 + * @props: "port", "endpoint" + * @nprops: 2 + * + * And you'd get back fwnode referring to EP00 under CAM0. + * + * The same works the other way around: if you use EP00 under CAM0 as the + * fwnode, you'll get fwnode referring to EP40 under ISP. + * + * The same example in DT syntax would look like this: + * + * cam: cam0 { + * compatible = "nokia,smia"; + * + * port { + * port = <0>; + * endpoint { + * endpoint = <0>; + * remote-endpoint = <&isp 4 0>; + * }; + * }; + * }; + * + * isp: isp { + * ports { + * port@4 { + * port = <4>; + * endpoint { + * endpoint = <0>; + * remote-endpoint = <&cam 0 0>; + * }; + * }; + * }; + * }; + * + * Return: 0 on success + * -ENOENT if no entries (or the property itself) were found + * -EINVAL if property parsing otherwise failed + * -ENOMEM if memory allocation failed + */ +static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop( + struct fwnode_handle *fwnode, const char *prop, unsigned int index, + const char * const *props, unsigned int nprops) +{ + struct fwnode_reference_args fwnode_args; + unsigned int *args = fwnode_args.args; + struct fwnode_handle *child; + int ret; + + /* + * Obtain remote fwnode as well as the integer arguments. + * + * Note that right now both -ENODATA and -ENOENT may signal + * out-of-bounds access. Return -ENOENT in that case. + */ + ret = fwnode_property_get_reference_args(fwnode, prop, NULL, nprops, + index, &fwnode_args); + if (ret) + return ERR_PTR(ret == -ENODATA ? -ENOENT : ret); + + /* + * Find a node in the tree under the referred fwnode corresponding to + * the integer arguments. + */ + fwnode = fwnode_args.fwnode; + while (nprops--) { + u32 val; + + /* Loop over all child nodes under fwnode. */ + fwnode_for_each_child_node(fwnode, child) { + if (fwnode_property_read_u32(child, *props, &val)) + continue; + + /* Found property, see if its value matches. */ + if (val == *args) + break; + } + + fwnode_handle_put(fwnode); + + /* No property found; return an error here. */ + if (!child) { + fwnode = ERR_PTR(-ENOENT); + break; + } + + props++; + args++; + fwnode = child; + } + + return fwnode; +} + +/* + * v4l2_fwnode_reference_parse_int_props - parse references for async + * sub-devices + * @dev: struct device pointer + * @notifier: notifier for @dev + * @prop: the name of the property + * @props: the array of integer property names + * @nprops: the number of integer properties + * + * Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in + * property @prop with integer arguments with child nodes matching in properties + * @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier + * accordingly. + * + * While it is technically possible to use this function on DT, it is only + * meaningful on ACPI. On Device tree you can refer to any node in the tree but + * on ACPI the references are limited to devices. + * + * Return: 0 on success + * -ENOENT if no entries (or the property itself) were found + * -EINVAL if property parsing otherwisefailed + * -ENOMEM if memory allocation failed + */ +static int v4l2_fwnode_reference_parse_int_props( + struct device *dev, struct v4l2_async_notifier *notifier, + const char *prop, const char * const *props, unsigned int nprops) +{ + struct fwnode_handle *fwnode; + unsigned int index; + int ret; + + for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop( + dev_fwnode(dev), prop, index, props, + nprops))); index++) + fwnode_handle_put(fwnode); + + /* + * Note that right now both -ENODATA and -ENOENT may signal + * out-of-bounds access. Return the error in cases other than that. + */ + if (PTR_ERR(fwnode) != -ENOENT && PTR_ERR(fwnode) != -ENODATA) + return PTR_ERR(fwnode); + + ret = v4l2_async_notifier_realloc(notifier, + notifier->num_subdevs + index); + if (ret) + return -ENOMEM; + + for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop( + dev_fwnode(dev), prop, index, props, + nprops))); index++) { + struct v4l2_async_subdev *asd; + + if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) { + ret = -EINVAL; + goto error; + } + + asd = kzalloc(sizeof(struct v4l2_async_subdev), GFP_KERNEL); + if (!asd) { + ret = -ENOMEM; + goto error; + } + + notifier->subdevs[notifier->num_subdevs] = asd; + asd->match.fwnode.fwnode = fwnode; + asd->match_type = V4L2_ASYNC_MATCH_FWNODE; + notifier->num_subdevs++; + } + + return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode); + +error: + fwnode_handle_put(fwnode); + return ret; +} + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Sakari Ailus "); MODULE_AUTHOR("Sylwester Nawrocki "); -- cgit v1.2.3 From 7a9ec808ad46d1e02e5e766a83adc5f88e5df264 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 6 Sep 2017 08:35:42 -0400 Subject: media: v4l: fwnode: Add convenience function for parsing common external refs Add v4l2_fwnode_parse_reference_sensor_common for parsing common sensor properties that refer to adjacent devices such as flash or lens driver chips. As this is an association only, there's little a regular driver needs to know about these devices as such. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Pavel Machek Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-fwnode.c | 35 +++++++++++++++++++++++++++++++++++ include/media/v4l2-async.h | 3 ++- include/media/v4l2-fwnode.h | 21 +++++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index f8cd88f791c4..39387dc6cadd 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -865,6 +865,41 @@ error: return ret; } +int v4l2_async_notifier_parse_fwnode_sensor_common( + struct device *dev, struct v4l2_async_notifier *notifier) +{ + static const char * const led_props[] = { "led" }; + static const struct { + const char *name; + const char * const *props; + unsigned int nprops; + } props[] = { + { "flash-leds", led_props, ARRAY_SIZE(led_props) }, + { "lens-focus", NULL, 0 }, + }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(props); i++) { + int ret; + + if (props[i].props && is_acpi_node(dev_fwnode(dev))) + ret = v4l2_fwnode_reference_parse_int_props( + dev, notifier, props[i].name, + props[i].props, props[i].nprops); + else + ret = v4l2_fwnode_reference_parse( + dev, notifier, props[i].name); + if (ret && ret != -ENOENT) { + dev_warn(dev, "parsing property \"%s\" failed (%d)\n", + props[i].name, ret); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Sakari Ailus "); MODULE_AUTHOR("Sylwester Nawrocki "); diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h index 17c4ac7c73e8..8d8cfc3f3100 100644 --- a/include/media/v4l2-async.h +++ b/include/media/v4l2-async.h @@ -156,7 +156,8 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier); * Release memory resources related to a notifier, including the async * sub-devices allocated for the purposes of the notifier but not the notifier * itself. The user is responsible for calling this function to clean up the - * notifier after calling @v4l2_async_notifier_parse_fwnode_endpoints. + * notifier after calling @v4l2_async_notifier_parse_fwnode_endpoints or + * @v4l2_fwnode_reference_parse_sensor_common. * * There is no harm from calling v4l2_async_notifier_cleanup in other * cases as long as its memory has been zeroed after it has been diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h index 105cfeee44ef..ca50108dfd8f 100644 --- a/include/media/v4l2-fwnode.h +++ b/include/media/v4l2-fwnode.h @@ -319,4 +319,25 @@ int v4l2_async_notifier_parse_fwnode_endpoints_by_port( struct v4l2_fwnode_endpoint *vep, struct v4l2_async_subdev *asd)); +/** + * v4l2_fwnode_reference_parse_sensor_common - parse common references on + * sensors for async sub-devices + * @dev: the device node the properties of which are parsed for references + * @notifier: the async notifier where the async subdevs will be added + * + * Parse common sensor properties for remote devices related to the + * sensor and set up async sub-devices for them. + * + * Any notifier populated using this function must be released with a call to + * v4l2_async_notifier_release() after it has been unregistered and the async + * sub-devices are no longer in use, even in the case the function returned an + * error. + * + * Return: 0 on success + * -ENOMEM if memory allocation failed + * -EINVAL if property parsing failed + */ +int v4l2_async_notifier_parse_fwnode_sensor_common( + struct device *dev, struct v4l2_async_notifier *notifier); + #endif /* _V4L2_FWNODE_H */ -- cgit v1.2.3 From aef69d54755d45edefbf347a51efd1673d7daed9 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sun, 24 Sep 2017 18:47:44 -0400 Subject: media: v4l: fwnode: Add a convenience function for registering sensors Add a convenience function for parsing firmware for information on related devices using v4l2_async_notifier_parse_fwnode_sensor_common() registering the notifier and finally the async sub-device itself. This should be useful for sensor drivers that do not have device specific requirements related to firmware information parsing or the async framework. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Reviewed-by: Niklas Söderlund Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-async.c | 19 ++++++++++++---- drivers/media/v4l2-core/v4l2-fwnode.c | 41 +++++++++++++++++++++++++++++++++++ include/media/v4l2-async.h | 22 +++++++++++++++++++ include/media/v4l2-subdev.h | 3 +++ 4 files changed, 81 insertions(+), 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 57bd54016064..49f7eccc76db 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -474,19 +474,25 @@ int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd, } EXPORT_SYMBOL(v4l2_async_subdev_notifier_register); -void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) +static void __v4l2_async_notifier_unregister( + struct v4l2_async_notifier *notifier) { - if (!notifier->v4l2_dev && !notifier->sd) + if (!notifier || (!notifier->v4l2_dev && !notifier->sd)) return; - mutex_lock(&list_lock); - v4l2_async_notifier_unbind_all_subdevs(notifier); notifier->sd = NULL; notifier->v4l2_dev = NULL; list_del(¬ifier->list); +} + +void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier) +{ + mutex_lock(&list_lock); + + __v4l2_async_notifier_unregister(notifier); mutex_unlock(&list_lock); } @@ -596,6 +602,11 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd) { mutex_lock(&list_lock); + __v4l2_async_notifier_unregister(sd->subdev_notifier); + v4l2_async_notifier_cleanup(sd->subdev_notifier); + kfree(sd->subdev_notifier); + sd->subdev_notifier = NULL; + if (sd->asd) { struct v4l2_async_notifier *notifier = sd->notifier; diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 39387dc6cadd..3b9c6afb49a3 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -29,6 +29,7 @@ #include #include +#include enum v4l2_fwnode_bus_type { V4L2_FWNODE_BUS_TYPE_GUESS = 0, @@ -900,6 +901,46 @@ int v4l2_async_notifier_parse_fwnode_sensor_common( } EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common); +int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd) +{ + struct v4l2_async_notifier *notifier; + int ret; + + if (WARN_ON(!sd->dev)) + return -ENODEV; + + notifier = kzalloc(sizeof(*notifier), GFP_KERNEL); + if (!notifier) + return -ENOMEM; + + ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev, + notifier); + if (ret < 0) + goto out_cleanup; + + ret = v4l2_async_subdev_notifier_register(sd, notifier); + if (ret < 0) + goto out_cleanup; + + ret = v4l2_async_register_subdev(sd); + if (ret < 0) + goto out_unregister; + + sd->subdev_notifier = notifier; + + return 0; + +out_unregister: + v4l2_async_notifier_unregister(notifier); + +out_cleanup: + v4l2_async_notifier_cleanup(notifier); + kfree(notifier); + + return ret; +} +EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor_common); + MODULE_LICENSE("GPL"); MODULE_AUTHOR("Sakari Ailus "); MODULE_AUTHOR("Sylwester Nawrocki "); diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h index 8d8cfc3f3100..6152434cbe82 100644 --- a/include/media/v4l2-async.h +++ b/include/media/v4l2-async.h @@ -173,6 +173,28 @@ void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier); */ int v4l2_async_register_subdev(struct v4l2_subdev *sd); +/** + * v4l2_async_register_subdev_sensor_common - registers a sensor sub-device to + * the asynchronous sub-device + * framework and parse set up common + * sensor related devices + * + * @sd: pointer to struct &v4l2_subdev + * + * This function is just like v4l2_async_register_subdev() with the exception + * that calling it will also parse firmware interfaces for remote references + * using v4l2_async_notifier_parse_fwnode_sensor_common() and registers the + * async sub-devices. The sub-device is similarly unregistered by calling + * v4l2_async_unregister_subdev(). + * + * While registered, the subdev module is marked as in-use. + * + * An error is returned if the module is no longer loaded on any attempts + * to register it. + */ +int __must_check v4l2_async_register_subdev_sensor_common( + struct v4l2_subdev *sd); + /** * v4l2_async_unregister_subdev - unregisters a sub-device to the asynchronous * subdevice framework diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index e83872078376..ec399c770301 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -793,6 +793,8 @@ struct v4l2_subdev_platform_data { * list. * @asd: Pointer to respective &struct v4l2_async_subdev. * @notifier: Pointer to the managing notifier. + * @subdev_notifier: A sub-device notifier implicitly registered for the sub- + * device using v4l2_device_register_sensor_subdev(). * @pdata: common part of subdevice platform data * * Each instance of a subdev driver should create this struct, either @@ -823,6 +825,7 @@ struct v4l2_subdev { struct list_head async_list; struct v4l2_async_subdev *asd; struct v4l2_async_notifier *notifier; + struct v4l2_async_notifier *subdev_notifier; struct v4l2_subdev_platform_data *pdata; }; -- cgit v1.2.3 From e4219f9f9c98ae28874c2b7390a561a2a77e6f64 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sun, 3 Sep 2017 15:41:53 -0400 Subject: media: dt: bindings: smiapp: Document lens-focus and flash-leds properties Document optional lens-focus and flash-leds properties for the smiapp driver. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Pavel Machek Acked-by: Rob Herring Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/i2c/nokia,smia.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt index 855e1faf73e2..33f10a94c381 100644 --- a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt +++ b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt @@ -27,6 +27,8 @@ Optional properties - nokia,nvm-size: The size of the NVM, in bytes. If the size is not given, the NVM contents will not be read. - reset-gpios: XSHUTDOWN GPIO +- flash-leds: See ../video-interfaces.txt +- lens-focus: See ../video-interfaces.txt Endpoint node mandatory properties -- cgit v1.2.3 From c121ce59152a9cc00fbff0ca12becfc0ef0b8663 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Sun, 24 Sep 2017 18:53:38 -0400 Subject: media: smiapp: Add support for flash and lens devices Parse async sub-devices related to the sensor by switching the async sub-device registration function. These types devices aren't directly related to the sensor, but are nevertheless handled by the smiapp driver due to the relationship of these component to the main part of the camera module --- the sensor. This does not yet address providing the user space with information on how to associate the sensor or lens devices but the kernel now has the necessary information to do that. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Pavel Machek Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index faf567569799..e6b717b83b18 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -3093,7 +3093,7 @@ static int smiapp_probe(struct i2c_client *client, if (rval < 0) goto out_media_entity_cleanup; - rval = v4l2_async_register_subdev(&sensor->src->sd); + rval = v4l2_async_register_subdev_sensor_common(&sensor->src->sd); if (rval < 0) goto out_media_entity_cleanup; -- cgit v1.2.3 From d8932f38c10ffb4b604c97d0765b500e8964cbd1 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 25 Sep 2017 05:51:51 -0400 Subject: media: et8ek8: Add support for flash and lens devices Parse async sub-devices related to the sensor by switching the async sub-device registration function. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Pavel Machek Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/et8ek8/et8ek8_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c index c14f0fd6ded3..e9eff9039ef5 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_driver.c +++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c @@ -1453,7 +1453,7 @@ static int et8ek8_probe(struct i2c_client *client, goto err_mutex; } - ret = v4l2_async_register_subdev(&sensor->subdev); + ret = v4l2_async_register_subdev_sensor_common(&sensor->subdev); if (ret < 0) goto err_entity; -- cgit v1.2.3 From a42e78da596b18319ebc447f60c22fd6ce32322b Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 25 Sep 2017 05:51:25 -0400 Subject: media: ov5670: Add support for flash and lens devices Parse async sub-devices related to the sensor by switching the async sub-device registration function. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov5670.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index a65469f88e36..9f9196568eb8 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -2529,7 +2529,7 @@ static int ov5670_probe(struct i2c_client *client) } /* Async register for subdev */ - ret = v4l2_async_register_subdev(&ov5670->sd); + ret = v4l2_async_register_subdev_sensor_common(&ov5670->sd); if (ret < 0) { err_msg = "v4l2_async_register_subdev() error"; goto error_entity_cleanup; -- cgit v1.2.3 From 2e8a9fbb79508261703835dd4977014249c9e18f Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 25 Sep 2017 05:50:16 -0400 Subject: media: ov13858: Add support for flash and lens devices Parse async sub-devices related to the sensor by switching the async sub-device registration function. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov13858.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index fdce2befed02..bf7d06f3f21a 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -1761,7 +1761,7 @@ static int ov13858_probe(struct i2c_client *client, goto error_handler_free; } - ret = v4l2_async_register_subdev(&ov13858->sd); + ret = v4l2_async_register_subdev_sensor_common(&ov13858->sd); if (ret < 0) goto error_media_entity; -- cgit v1.2.3 From ceb3c45b43ffd69220233e309f0f6f0a9d3125a6 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 17 Aug 2017 02:51:16 -0400 Subject: media: arm: dts: omap3: N9/N950: Add flash references to the camera Add flash and indicator LED phandles to the sensor node. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Acked-by: Pavel Machek Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- arch/arm/boot/dts/omap3-n9.dts | 1 + arch/arm/boot/dts/omap3-n950-n9.dtsi | 4 ++-- arch/arm/boot/dts/omap3-n950.dts | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/omap3-n9.dts b/arch/arm/boot/dts/omap3-n9.dts index b9e58c536afd..39e35f8b8206 100644 --- a/arch/arm/boot/dts/omap3-n9.dts +++ b/arch/arm/boot/dts/omap3-n9.dts @@ -26,6 +26,7 @@ clocks = <&isp 0>; clock-frequency = <9600000>; nokia,nvm-size = <(16 * 64)>; + flash-leds = <&as3645a_flash &as3645a_indicator>; port { smia_1_1: endpoint { link-frequencies = /bits/ 64 <199200000 210000000 499200000>; diff --git a/arch/arm/boot/dts/omap3-n950-n9.dtsi b/arch/arm/boot/dts/omap3-n950-n9.dtsi index 1b0bd72945f2..12fbb3da5fce 100644 --- a/arch/arm/boot/dts/omap3-n950-n9.dtsi +++ b/arch/arm/boot/dts/omap3-n950-n9.dtsi @@ -271,14 +271,14 @@ #size-cells = <0>; reg = <0x30>; compatible = "ams,as3645a"; - flash@0 { + as3645a_flash: flash@0 { reg = <0x0>; flash-timeout-us = <150000>; flash-max-microamp = <320000>; led-max-microamp = <60000>; ams,input-max-microamp = <1750000>; }; - indicator@1 { + as3645a_indicator: indicator@1 { reg = <0x1>; led-max-microamp = <10000>; }; diff --git a/arch/arm/boot/dts/omap3-n950.dts b/arch/arm/boot/dts/omap3-n950.dts index 646601a3ebd8..c354a1ed1e70 100644 --- a/arch/arm/boot/dts/omap3-n950.dts +++ b/arch/arm/boot/dts/omap3-n950.dts @@ -60,6 +60,7 @@ clocks = <&isp 0>; clock-frequency = <9600000>; nokia,nvm-size = <(16 * 64)>; + flash-leds = <&as3645a_flash &as3645a_indicator>; port { smia_1_1: endpoint { link-frequencies = /bits/ 64 <210000000 333600000 398400000>; -- cgit v1.2.3 From 1acce5f72cfabcafee5e101b9ac7d71ebe1c7af9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 31 Oct 2017 14:18:03 -0400 Subject: media: v4l2-fwnode: use the cached value instead of getting again There is a get/put operation in order to get firmware is_available data there at the __v4l2_async_notifier_parse_fwnode_endpoints() function. However, instead of using it, the code just reads again without the lock. That's a bug, as dev_fwnode isn't guaranteed to be there once fwnode_handle_put() has been called on it. This solves this smatch warning: drivers/media/v4l2-core/v4l2-fwnode.c:453:8: warning: variable 'is_available' set but not used [-Wunused-but-set-variable] bool is_available; ^~~~~~~~~~~~ Fixes: 9ca465312132 ("media: v4l: fwnode: Support generic parsing of graph endpoints in a device") Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-fwnode.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 3b9c6afb49a3..681b192420d9 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -455,8 +455,7 @@ static int __v4l2_async_notifier_parse_fwnode_endpoints( dev_fwnode = fwnode_graph_get_port_parent(fwnode); is_available = fwnode_device_is_available(dev_fwnode); fwnode_handle_put(dev_fwnode); - - if (!fwnode_device_is_available(dev_fwnode)) + if (!is_available) continue; if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) { -- cgit v1.2.3 From e2cec86528becf143341e2c5c59921bd6cfa1f45 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 1 Nov 2017 09:12:13 -0400 Subject: media: v4l2-fwnode: use a typedef for a function callback That allows having a kernel-doc markup for the function prototype. It also prevents the need of describing the return values twice. Signed-off-by: Mauro Carvalho Chehab Acked-by: Sakari Ailus --- include/media/v4l2-fwnode.h | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h index ca50108dfd8f..b5b465677d28 100644 --- a/include/media/v4l2-fwnode.h +++ b/include/media/v4l2-fwnode.h @@ -203,6 +203,26 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode, */ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link); + +/** + * typedef parse_endpoint_func - Driver's callback function to be called on + * each V4L2 fwnode endpoint. + * + * @dev: pointer to &struct device + * @vep: pointer to &struct v4l2_fwnode_endpoint + * @asd: pointer to &struct v4l2_async_subdev + * + * Return: + * * %0 on success + * * %-ENOTCONN if the endpoint is to be skipped but this + * should not be considered as an error + * * %-EINVAL if the endpoint configuration is invalid + */ +typedef int (*parse_endpoint_func)(struct device *dev, + struct v4l2_fwnode_endpoint *vep, + struct v4l2_async_subdev *asd); + + /** * v4l2_async_notifier_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints in a * device node @@ -215,10 +235,6 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link); * begin at the same memory address. * @parse_endpoint: Driver's callback function called on each V4L2 fwnode * endpoint. Optional. - * Return: %0 on success - * %-ENOTCONN if the endpoint is to be skipped but this - * should not be considered as an error - * %-EINVAL if the endpoint configuration is invalid * * Parse the fwnode endpoints of the @dev device and populate the async sub- * devices array of the notifier. The @parse_endpoint callback function is @@ -253,9 +269,7 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link); int v4l2_async_notifier_parse_fwnode_endpoints( struct device *dev, struct v4l2_async_notifier *notifier, size_t asd_struct_size, - int (*parse_endpoint)(struct device *dev, - struct v4l2_fwnode_endpoint *vep, - struct v4l2_async_subdev *asd)); + parse_endpoint_func parse_endpoint); /** * v4l2_async_notifier_parse_fwnode_endpoints_by_port - Parse V4L2 fwnode @@ -271,10 +285,6 @@ int v4l2_async_notifier_parse_fwnode_endpoints( * @port: port number where endpoints are to be parsed * @parse_endpoint: Driver's callback function called on each V4L2 fwnode * endpoint. Optional. - * Return: %0 on success - * %-ENOTCONN if the endpoint is to be skipped but this - * should not be considered as an error - * %-EINVAL if the endpoint configuration is invalid * * This function is just like v4l2_async_notifier_parse_fwnode_endpoints() with * the exception that it only parses endpoints in a given port. This is useful @@ -315,9 +325,7 @@ int v4l2_async_notifier_parse_fwnode_endpoints( int v4l2_async_notifier_parse_fwnode_endpoints_by_port( struct device *dev, struct v4l2_async_notifier *notifier, size_t asd_struct_size, unsigned int port, - int (*parse_endpoint)(struct device *dev, - struct v4l2_fwnode_endpoint *vep, - struct v4l2_async_subdev *asd)); + parse_endpoint_func parse_endpoint); /** * v4l2_fwnode_reference_parse_sensor_common - parse common references on -- cgit v1.2.3 From 130b31eccf3365bd5a2b8c49906dfbdfeb1b424f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 31 Oct 2017 09:07:18 -0400 Subject: media: atomisp: fix ident for assert/return On lots of places, assert/return are starting at the first column, causing indentation issues, as complained by spatch: drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/irq_private.h:32 irq_reg_store() warn: inconsistent indenting Used this small script to fix such occurrences: for i in $(git grep -l -E "^(assert|return)" drivers/staging/media/); do perl -ne 's/^(assert|return)\b/\t$1/; print $_' <$i >a && mv a $i; done Signed-off-by: Mauro Carvalho Chehab Acked-by: Sakari Ailus --- .../pci/atomisp2/css2400/camera/util/src/util.c | 2 +- .../hive_isp_css_common/host/event_fifo_private.h | 2 +- .../host/fifo_monitor_private.h | 28 +++++----- .../css2400/hive_isp_css_common/host/gdc.c | 8 +-- .../css2400/hive_isp_css_common/host/gp_device.c | 2 +- .../hive_isp_css_common/host/gp_device_private.h | 16 +++--- .../hive_isp_css_common/host/gpio_private.h | 4 +- .../hive_isp_css_common/host/hmem_private.h | 4 +- .../host/input_formatter_private.h | 16 +++--- .../hive_isp_css_common/host/input_system.c | 28 +++++----- .../host/input_system_private.h | 64 +++++++++++----------- .../css2400/hive_isp_css_common/host/irq.c | 30 +++++----- .../css2400/hive_isp_css_common/host/irq_private.h | 12 ++-- .../css2400/hive_isp_css_common/host/isp.c | 4 +- .../css2400/hive_isp_css_common/host/mmu.c | 6 +- .../css2400/hive_isp_css_common/host/mmu_private.h | 12 ++-- .../css2400/hive_isp_css_common/host/sp_private.h | 60 ++++++++++---------- .../atomisp/pci/atomisp2/css2400/sh_css_hrt.c | 2 +- 18 files changed, 150 insertions(+), 150 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/camera/util/src/util.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/camera/util/src/util.c index 08f486e20a65..54193789a809 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/camera/util/src/util.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/camera/util/src/util.c @@ -111,7 +111,7 @@ unsigned int ia_css_util_input_format_bpp( break; } -return rval; + return rval; } enum ia_css_err ia_css_util_check_vf_info( diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/event_fifo_private.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/event_fifo_private.h index 9d3a29696094..bcfb734c2ed3 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/event_fifo_private.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/event_fifo_private.h @@ -28,7 +28,7 @@ STORAGE_CLASS_EVENT_C void event_wait_for(const event_ID_t ID) assert(ID < N_EVENT_ID); assert(event_source_addr[ID] != ((hrt_address)-1)); (void)ia_css_device_load_uint32(event_source_addr[ID]); -return; + return; } STORAGE_CLASS_EVENT_C void cnd_event_wait_for(const event_ID_t ID, diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/fifo_monitor_private.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/fifo_monitor_private.h index 618b2f7e9c75..d58cd7d1828d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/fifo_monitor_private.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/fifo_monitor_private.h @@ -33,26 +33,26 @@ STORAGE_CLASS_FIFO_MONITOR_C void fifo_switch_set( const fifo_switch_t switch_id, const hrt_data sel) { -assert(ID == FIFO_MONITOR0_ID); -assert(FIFO_MONITOR_BASE[ID] != (hrt_address)-1); -assert(switch_id < N_FIFO_SWITCH); + assert(ID == FIFO_MONITOR0_ID); + assert(FIFO_MONITOR_BASE[ID] != (hrt_address)-1); + assert(switch_id < N_FIFO_SWITCH); (void)ID; gp_device_reg_store(GP_DEVICE0_ID, FIFO_SWITCH_ADDR[switch_id], sel); -return; + return; } STORAGE_CLASS_FIFO_MONITOR_C hrt_data fifo_switch_get( const fifo_monitor_ID_t ID, const fifo_switch_t switch_id) { -assert(ID == FIFO_MONITOR0_ID); -assert(FIFO_MONITOR_BASE[ID] != (hrt_address)-1); -assert(switch_id < N_FIFO_SWITCH); + assert(ID == FIFO_MONITOR0_ID); + assert(FIFO_MONITOR_BASE[ID] != (hrt_address)-1); + assert(switch_id < N_FIFO_SWITCH); (void)ID; -return gp_device_reg_load(GP_DEVICE0_ID, FIFO_SWITCH_ADDR[switch_id]); + return gp_device_reg_load(GP_DEVICE0_ID, FIFO_SWITCH_ADDR[switch_id]); } @@ -61,19 +61,19 @@ STORAGE_CLASS_FIFO_MONITOR_C void fifo_monitor_reg_store( const unsigned int reg, const hrt_data value) { -assert(ID < N_FIFO_MONITOR_ID); -assert(FIFO_MONITOR_BASE[ID] != (hrt_address)-1); + assert(ID < N_FIFO_MONITOR_ID); + assert(FIFO_MONITOR_BASE[ID] != (hrt_address)-1); ia_css_device_store_uint32(FIFO_MONITOR_BASE[ID] + reg*sizeof(hrt_data), value); -return; + return; } STORAGE_CLASS_FIFO_MONITOR_C hrt_data fifo_monitor_reg_load( const fifo_monitor_ID_t ID, const unsigned int reg) { -assert(ID < N_FIFO_MONITOR_ID); -assert(FIFO_MONITOR_BASE[ID] != (hrt_address)-1); -return ia_css_device_load_uint32(FIFO_MONITOR_BASE[ID] + reg*sizeof(hrt_data)); + assert(ID < N_FIFO_MONITOR_ID); + assert(FIFO_MONITOR_BASE[ID] != (hrt_address)-1); + return ia_css_device_load_uint32(FIFO_MONITOR_BASE[ID] + reg*sizeof(hrt_data)); } #endif /* __FIFO_MONITOR_PRIVATE_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/gdc.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/gdc.c index 69fa616889b1..4d6308abd036 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/gdc.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/gdc.c @@ -62,7 +62,7 @@ void gdc_lut_store( gdc_reg_store(ID, lut_offset++, word_0); gdc_reg_store(ID, lut_offset++, word_1); } -return; + return; } /* @@ -103,7 +103,7 @@ int gdc_get_unity( { assert(ID < N_GDC_ID); (void)ID; -return (int)(1UL << HRT_GDC_FRAC_BITS); + return (int)(1UL << HRT_GDC_FRAC_BITS); } @@ -116,12 +116,12 @@ STORAGE_CLASS_INLINE void gdc_reg_store( const hrt_data value) { ia_css_device_store_uint32(GDC_BASE[ID] + reg*sizeof(hrt_data), value); -return; + return; } STORAGE_CLASS_INLINE hrt_data gdc_reg_load( const gdc_ID_t ID, const unsigned int reg) { -return ia_css_device_load_uint32(GDC_BASE[ID] + reg*sizeof(hrt_data)); + return ia_css_device_load_uint32(GDC_BASE[ID] + reg*sizeof(hrt_data)); } diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/gp_device.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/gp_device.c index 9a34ac052adf..da88aa3af664 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/gp_device.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/gp_device.c @@ -104,5 +104,5 @@ void gp_device_get_state( _REG_GP_SYNCGEN_FRAME_CNT_ADDR); state->soft_reset = gp_device_reg_load(ID, _REG_GP_SOFT_RESET_ADDR); -return; + return; } diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/gp_device_private.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/gp_device_private.h index bce1fdf79114..7c0362c29411 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/gp_device_private.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/gp_device_private.h @@ -26,21 +26,21 @@ STORAGE_CLASS_GP_DEVICE_C void gp_device_reg_store( const unsigned int reg_addr, const hrt_data value) { -assert(ID < N_GP_DEVICE_ID); -assert(GP_DEVICE_BASE[ID] != (hrt_address)-1); -assert((reg_addr % sizeof(hrt_data)) == 0); + assert(ID < N_GP_DEVICE_ID); + assert(GP_DEVICE_BASE[ID] != (hrt_address)-1); + assert((reg_addr % sizeof(hrt_data)) == 0); ia_css_device_store_uint32(GP_DEVICE_BASE[ID] + reg_addr, value); -return; + return; } STORAGE_CLASS_GP_DEVICE_C hrt_data gp_device_reg_load( const gp_device_ID_t ID, const hrt_address reg_addr) { -assert(ID < N_GP_DEVICE_ID); -assert(GP_DEVICE_BASE[ID] != (hrt_address)-1); -assert((reg_addr % sizeof(hrt_data)) == 0); -return ia_css_device_load_uint32(GP_DEVICE_BASE[ID] + reg_addr); + assert(ID < N_GP_DEVICE_ID); + assert(GP_DEVICE_BASE[ID] != (hrt_address)-1); + assert((reg_addr % sizeof(hrt_data)) == 0); + return ia_css_device_load_uint32(GP_DEVICE_BASE[ID] + reg_addr); } #endif /* __GP_DEVICE_PRIVATE_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/gpio_private.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/gpio_private.h index 6ace2184b522..b6ebf34eaa9d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/gpio_private.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/gpio_private.h @@ -29,7 +29,7 @@ STORAGE_CLASS_GPIO_C void gpio_reg_store( OP___assert(ID < N_GPIO_ID); OP___assert(GPIO_BASE[ID] != (hrt_address)-1); ia_css_device_store_uint32(GPIO_BASE[ID] + reg*sizeof(hrt_data), value); -return; + return; } STORAGE_CLASS_GPIO_C hrt_data gpio_reg_load( @@ -38,7 +38,7 @@ STORAGE_CLASS_GPIO_C hrt_data gpio_reg_load( { OP___assert(ID < N_GPIO_ID); OP___assert(GPIO_BASE[ID] != (hrt_address)-1); -return ia_css_device_load_uint32(GPIO_BASE[ID] + reg*sizeof(hrt_data)); + return ia_css_device_load_uint32(GPIO_BASE[ID] + reg*sizeof(hrt_data)); } #endif /* __GPIO_PRIVATE_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/hmem_private.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/hmem_private.h index 2b636e0e6482..32a780380e11 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/hmem_private.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/hmem_private.h @@ -22,9 +22,9 @@ STORAGE_CLASS_HMEM_C size_t sizeof_hmem( const hmem_ID_t ID) { -assert(ID < N_HMEM_ID); + assert(ID < N_HMEM_ID); (void)ID; -return HMEM_SIZE*sizeof(hmem_data_t); + return HMEM_SIZE*sizeof(hmem_data_t); } #endif /* __HMEM_PRIVATE_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_formatter_private.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_formatter_private.h index d34933e44aa9..2f42a9c2771c 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_formatter_private.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_formatter_private.h @@ -26,21 +26,21 @@ STORAGE_CLASS_INPUT_FORMATTER_C void input_formatter_reg_store( const hrt_address reg_addr, const hrt_data value) { -assert(ID < N_INPUT_FORMATTER_ID); -assert(INPUT_FORMATTER_BASE[ID] != (hrt_address)-1); -assert((reg_addr % sizeof(hrt_data)) == 0); + assert(ID < N_INPUT_FORMATTER_ID); + assert(INPUT_FORMATTER_BASE[ID] != (hrt_address)-1); + assert((reg_addr % sizeof(hrt_data)) == 0); ia_css_device_store_uint32(INPUT_FORMATTER_BASE[ID] + reg_addr, value); -return; + return; } STORAGE_CLASS_INPUT_FORMATTER_C hrt_data input_formatter_reg_load( const input_formatter_ID_t ID, const unsigned int reg_addr) { -assert(ID < N_INPUT_FORMATTER_ID); -assert(INPUT_FORMATTER_BASE[ID] != (hrt_address)-1); -assert((reg_addr % sizeof(hrt_data)) == 0); -return ia_css_device_load_uint32(INPUT_FORMATTER_BASE[ID] + reg_addr); + assert(ID < N_INPUT_FORMATTER_ID); + assert(INPUT_FORMATTER_BASE[ID] != (hrt_address)-1); + assert((reg_addr % sizeof(hrt_data)) == 0); + return ia_css_device_load_uint32(INPUT_FORMATTER_BASE[ID] + reg_addr); } #endif /* __INPUT_FORMATTER_PRIVATE_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system.c index f35e18987b67..c9af2bfc1f88 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system.c @@ -173,7 +173,7 @@ void input_system_get_state( &(state->ctrl_unit_state[sub_id - CTRL_UNIT0_ID])); } -return; + return; } void receiver_get_state( @@ -245,7 +245,7 @@ void receiver_get_state( state->be_irq_clear = receiver_reg_load(ID, _HRT_CSS_RECEIVER_BE_IRQ_CLEAR_REG_IDX); -return; + return; } bool is_mipi_format_yuv420( @@ -258,7 +258,7 @@ bool is_mipi_format_yuv420( (mipi_format == MIPI_FORMAT_YUV420_10_SHIFT)); /* MIPI_FORMAT_YUV420_8_LEGACY is not YUV420 */ -return is_yuv420; + return is_yuv420; } void receiver_set_compression( @@ -300,7 +300,7 @@ void receiver_set_compression( reg = ((field_id < 6)?(val << (field_id * 5)):(val << ((field_id - 6) * 5))); receiver_reg_store(ID, addr, reg); -return; + return; } void receiver_port_enable( @@ -319,7 +319,7 @@ void receiver_port_enable( receiver_port_reg_store(ID, port_ID, _HRT_CSS_RECEIVER_DEVICE_READY_REG_IDX, reg); -return; + return; } bool is_receiver_port_enabled( @@ -328,7 +328,7 @@ bool is_receiver_port_enabled( { hrt_data reg = receiver_port_reg_load(ID, port_ID, _HRT_CSS_RECEIVER_DEVICE_READY_REG_IDX); -return ((reg & 0x01) != 0); + return ((reg & 0x01) != 0); } void receiver_irq_enable( @@ -338,14 +338,14 @@ void receiver_irq_enable( { receiver_port_reg_store(ID, port_ID, _HRT_CSS_RECEIVER_IRQ_ENABLE_REG_IDX, irq_info); -return; + return; } rx_irq_info_t receiver_get_irq_info( const rx_ID_t ID, const mipi_port_ID_t port_ID) { -return receiver_port_reg_load(ID, + return receiver_port_reg_load(ID, port_ID, _HRT_CSS_RECEIVER_IRQ_STATUS_REG_IDX); } @@ -356,7 +356,7 @@ void receiver_irq_clear( { receiver_port_reg_store(ID, port_ID, _HRT_CSS_RECEIVER_IRQ_STATUS_REG_IDX, irq_info); -return; + return; } STORAGE_CLASS_INLINE void capture_unit_get_state( @@ -418,7 +418,7 @@ STORAGE_CLASS_INLINE void capture_unit_get_state( sub_id, CAPT_FSM_STATE_INFO_REG_ID); -return; + return; } STORAGE_CLASS_INLINE void acquisition_unit_get_state( @@ -468,7 +468,7 @@ STORAGE_CLASS_INLINE void acquisition_unit_get_state( sub_id, ACQ_INT_CNTR_INFO_REG_ID); -return; + return; } STORAGE_CLASS_INLINE void ctrl_unit_get_state( @@ -551,7 +551,7 @@ STORAGE_CLASS_INLINE void ctrl_unit_get_state( sub_id, ISYS_CTRL_CAPT_RESERVE_ONE_MEM_REGION_REG_ID); -return; + return; } STORAGE_CLASS_INLINE void mipi_port_get_state( @@ -587,7 +587,7 @@ STORAGE_CLASS_INLINE void mipi_port_get_state( state->lane_rx_count[i] = (uint8_t)((state->rx_count)>>(i*8)); } -return; + return; } STORAGE_CLASS_INLINE void rx_channel_get_state( @@ -640,7 +640,7 @@ STORAGE_CLASS_INLINE void rx_channel_get_state( state->pred[i] = (mipi_predictor_t)((val & 0x18) >> 3); } -return; + return; } // MW: "2400" in the name is not good, but this is to avoid a naming conflict diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system_private.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system_private.h index ed1b947b00f9..118185eb86e9 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system_private.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system_private.h @@ -26,19 +26,19 @@ STORAGE_CLASS_INPUT_SYSTEM_C void input_system_reg_store( const hrt_address reg, const hrt_data value) { -assert(ID < N_INPUT_SYSTEM_ID); -assert(INPUT_SYSTEM_BASE[ID] != (hrt_address)-1); + assert(ID < N_INPUT_SYSTEM_ID); + assert(INPUT_SYSTEM_BASE[ID] != (hrt_address)-1); ia_css_device_store_uint32(INPUT_SYSTEM_BASE[ID] + reg*sizeof(hrt_data), value); -return; + return; } STORAGE_CLASS_INPUT_SYSTEM_C hrt_data input_system_reg_load( const input_system_ID_t ID, const hrt_address reg) { -assert(ID < N_INPUT_SYSTEM_ID); -assert(INPUT_SYSTEM_BASE[ID] != (hrt_address)-1); -return ia_css_device_load_uint32(INPUT_SYSTEM_BASE[ID] + reg*sizeof(hrt_data)); + assert(ID < N_INPUT_SYSTEM_ID); + assert(INPUT_SYSTEM_BASE[ID] != (hrt_address)-1); + return ia_css_device_load_uint32(INPUT_SYSTEM_BASE[ID] + reg*sizeof(hrt_data)); } STORAGE_CLASS_INPUT_SYSTEM_C void receiver_reg_store( @@ -46,19 +46,19 @@ STORAGE_CLASS_INPUT_SYSTEM_C void receiver_reg_store( const hrt_address reg, const hrt_data value) { -assert(ID < N_RX_ID); -assert(RX_BASE[ID] != (hrt_address)-1); + assert(ID < N_RX_ID); + assert(RX_BASE[ID] != (hrt_address)-1); ia_css_device_store_uint32(RX_BASE[ID] + reg*sizeof(hrt_data), value); -return; + return; } STORAGE_CLASS_INPUT_SYSTEM_C hrt_data receiver_reg_load( const rx_ID_t ID, const hrt_address reg) { -assert(ID < N_RX_ID); -assert(RX_BASE[ID] != (hrt_address)-1); -return ia_css_device_load_uint32(RX_BASE[ID] + reg*sizeof(hrt_data)); + assert(ID < N_RX_ID); + assert(RX_BASE[ID] != (hrt_address)-1); + return ia_css_device_load_uint32(RX_BASE[ID] + reg*sizeof(hrt_data)); } STORAGE_CLASS_INPUT_SYSTEM_C void receiver_port_reg_store( @@ -67,12 +67,12 @@ STORAGE_CLASS_INPUT_SYSTEM_C void receiver_port_reg_store( const hrt_address reg, const hrt_data value) { -assert(ID < N_RX_ID); -assert(port_ID < N_MIPI_PORT_ID); -assert(RX_BASE[ID] != (hrt_address)-1); -assert(MIPI_PORT_OFFSET[port_ID] != (hrt_address)-1); + assert(ID < N_RX_ID); + assert(port_ID < N_MIPI_PORT_ID); + assert(RX_BASE[ID] != (hrt_address)-1); + assert(MIPI_PORT_OFFSET[port_ID] != (hrt_address)-1); ia_css_device_store_uint32(RX_BASE[ID] + MIPI_PORT_OFFSET[port_ID] + reg*sizeof(hrt_data), value); -return; + return; } STORAGE_CLASS_INPUT_SYSTEM_C hrt_data receiver_port_reg_load( @@ -80,11 +80,11 @@ STORAGE_CLASS_INPUT_SYSTEM_C hrt_data receiver_port_reg_load( const mipi_port_ID_t port_ID, const hrt_address reg) { -assert(ID < N_RX_ID); -assert(port_ID < N_MIPI_PORT_ID); -assert(RX_BASE[ID] != (hrt_address)-1); -assert(MIPI_PORT_OFFSET[port_ID] != (hrt_address)-1); -return ia_css_device_load_uint32(RX_BASE[ID] + MIPI_PORT_OFFSET[port_ID] + reg*sizeof(hrt_data)); + assert(ID < N_RX_ID); + assert(port_ID < N_MIPI_PORT_ID); + assert(RX_BASE[ID] != (hrt_address)-1); + assert(MIPI_PORT_OFFSET[port_ID] != (hrt_address)-1); + return ia_css_device_load_uint32(RX_BASE[ID] + MIPI_PORT_OFFSET[port_ID] + reg*sizeof(hrt_data)); } STORAGE_CLASS_INPUT_SYSTEM_C void input_system_sub_system_reg_store( @@ -93,12 +93,12 @@ STORAGE_CLASS_INPUT_SYSTEM_C void input_system_sub_system_reg_store( const hrt_address reg, const hrt_data value) { -assert(ID < N_INPUT_SYSTEM_ID); -assert(sub_ID < N_SUB_SYSTEM_ID); -assert(INPUT_SYSTEM_BASE[ID] != (hrt_address)-1); -assert(SUB_SYSTEM_OFFSET[sub_ID] != (hrt_address)-1); + assert(ID < N_INPUT_SYSTEM_ID); + assert(sub_ID < N_SUB_SYSTEM_ID); + assert(INPUT_SYSTEM_BASE[ID] != (hrt_address)-1); + assert(SUB_SYSTEM_OFFSET[sub_ID] != (hrt_address)-1); ia_css_device_store_uint32(INPUT_SYSTEM_BASE[ID] + SUB_SYSTEM_OFFSET[sub_ID] + reg*sizeof(hrt_data), value); -return; + return; } STORAGE_CLASS_INPUT_SYSTEM_C hrt_data input_system_sub_system_reg_load( @@ -106,11 +106,11 @@ STORAGE_CLASS_INPUT_SYSTEM_C hrt_data input_system_sub_system_reg_load( const sub_system_ID_t sub_ID, const hrt_address reg) { -assert(ID < N_INPUT_SYSTEM_ID); -assert(sub_ID < N_SUB_SYSTEM_ID); -assert(INPUT_SYSTEM_BASE[ID] != (hrt_address)-1); -assert(SUB_SYSTEM_OFFSET[sub_ID] != (hrt_address)-1); -return ia_css_device_load_uint32(INPUT_SYSTEM_BASE[ID] + SUB_SYSTEM_OFFSET[sub_ID] + reg*sizeof(hrt_data)); + assert(ID < N_INPUT_SYSTEM_ID); + assert(sub_ID < N_SUB_SYSTEM_ID); + assert(INPUT_SYSTEM_BASE[ID] != (hrt_address)-1); + assert(SUB_SYSTEM_OFFSET[sub_ID] != (hrt_address)-1); + return ia_css_device_load_uint32(INPUT_SYSTEM_BASE[ID] + SUB_SYSTEM_OFFSET[sub_ID] + reg*sizeof(hrt_data)); } #endif /* __INPUT_SYSTEM_PRIVATE_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/irq.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/irq.c index 6b58bc13dc1b..a42dad69cb3c 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/irq.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/irq.c @@ -69,7 +69,7 @@ void irq_clear_all( irq_reg_store(ID, _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, mask); -return; + return; } /* @@ -114,7 +114,7 @@ void irq_enable_channel( irq_wait_for_write_complete(ID); -return; + return; } void irq_enable_pulse( @@ -129,7 +129,7 @@ void irq_enable_pulse( /* output is given as edge, not pulse */ irq_reg_store(ID, _HRT_IRQ_CONTROLLER_EDGE_NOT_PULSE_REG_IDX, edge_out); -return; + return; } void irq_disable_channel( @@ -160,7 +160,7 @@ void irq_disable_channel( irq_wait_for_write_complete(ID); -return; + return; } enum hrt_isp_css_irq_status irq_get_channel_id( @@ -195,7 +195,7 @@ enum hrt_isp_css_irq_status irq_get_channel_id( if (irq_id != NULL) *irq_id = (unsigned int)idx; -return status; + return status; } static const hrt_address IRQ_REQUEST_ADDR[N_IRQ_SW_CHANNEL_ID] = { @@ -220,7 +220,7 @@ void irq_raise( (unsigned int)addr, 1); gp_device_reg_store(GP_DEVICE0_ID, (unsigned int)addr, 0); -return; + return; } void irq_controller_get_state( @@ -240,7 +240,7 @@ void irq_controller_get_state( _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX); state->irq_level_not_pulse = irq_reg_load(ID, _HRT_IRQ_CONTROLLER_EDGE_NOT_PULSE_REG_IDX); -return; + return; } bool any_virq_signal(void) @@ -248,7 +248,7 @@ bool any_virq_signal(void) unsigned int irq_status = irq_reg_load(IRQ0_ID, _HRT_IRQ_CONTROLLER_STATUS_REG_IDX); -return (irq_status != 0); + return (irq_status != 0); } void cnd_virq_enable_channel( @@ -279,7 +279,7 @@ void cnd_virq_enable_channel( irq_disable_channel(IRQ0_ID, IRQ_NESTING_ID[ID]); } } -return; + return; } @@ -290,7 +290,7 @@ void virq_clear_all(void) for (irq_id = (irq_ID_t)0; irq_id < N_IRQ_ID; irq_id++) { irq_clear_all(irq_id); } -return; + return; } enum hrt_isp_css_irq_status virq_get_channel_signals( @@ -320,7 +320,7 @@ enum hrt_isp_css_irq_status virq_get_channel_signals( } } -return irq_status; + return irq_status; } void virq_clear_info( @@ -333,7 +333,7 @@ void virq_clear_info( for (ID = (irq_ID_t)0 ; ID < N_IRQ_ID; ID++) { irq_info->irq_status_reg[ID] = 0; } -return; + return; } enum hrt_isp_css_irq_status virq_get_channel_id( @@ -403,7 +403,7 @@ enum hrt_isp_css_irq_status virq_get_channel_id( if (irq_id != NULL) *irq_id = (virq_id_t)idx; -return status; + return status; } STORAGE_CLASS_INLINE void irq_wait_for_write_complete( @@ -425,7 +425,7 @@ STORAGE_CLASS_INLINE bool any_irq_channel_enabled( en_reg = irq_reg_load(ID, _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX); -return (en_reg != 0); + return (en_reg != 0); } STORAGE_CLASS_INLINE irq_ID_t virq_get_irq_id( @@ -444,5 +444,5 @@ STORAGE_CLASS_INLINE irq_ID_t virq_get_irq_id( *channel_ID = (unsigned int)irq_ID - IRQ_N_ID_OFFSET[ID]; -return ID; + return ID; } diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/irq_private.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/irq_private.h index eb325e870e88..23a13ac696c2 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/irq_private.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/irq_private.h @@ -26,19 +26,19 @@ STORAGE_CLASS_IRQ_C void irq_reg_store( const unsigned int reg, const hrt_data value) { -assert(ID < N_IRQ_ID); -assert(IRQ_BASE[ID] != (hrt_address)-1); + assert(ID < N_IRQ_ID); + assert(IRQ_BASE[ID] != (hrt_address)-1); ia_css_device_store_uint32(IRQ_BASE[ID] + reg*sizeof(hrt_data), value); -return; + return; } STORAGE_CLASS_IRQ_C hrt_data irq_reg_load( const irq_ID_t ID, const unsigned int reg) { -assert(ID < N_IRQ_ID); -assert(IRQ_BASE[ID] != (hrt_address)-1); -return ia_css_device_load_uint32(IRQ_BASE[ID] + reg*sizeof(hrt_data)); + assert(ID < N_IRQ_ID); + assert(IRQ_BASE[ID] != (hrt_address)-1); + return ia_css_device_load_uint32(IRQ_BASE[ID] + reg*sizeof(hrt_data)); } #endif /* __IRQ_PRIVATE_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/isp.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/isp.c index 47c21e486c25..531c932a48f5 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/isp.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/isp.c @@ -34,7 +34,7 @@ void cnd_isp_irq_enable( isp_ctrl_clearbit(ID, ISP_IRQ_READY_REG, ISP_IRQ_READY_BIT); } -return; + return; } void isp_get_state( @@ -94,7 +94,7 @@ void isp_get_state( !isp_ctrl_getbit(ID, ISP_ICACHE_MT_SINK_REG, ISP_ICACHE_MT_SINK_BIT); */ -return; + return; } /* ISP functions to control the ISP state from the host, even in crun. */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/mmu.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/mmu.c index b75d0f85d524..a28b67eb66ea 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/mmu.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/mmu.c @@ -24,20 +24,20 @@ void mmu_set_page_table_base_index( const hrt_data base_index) { mmu_reg_store(ID, _HRT_MMU_PAGE_TABLE_BASE_ADDRESS_REG_IDX, base_index); -return; + return; } hrt_data mmu_get_page_table_base_index( const mmu_ID_t ID) { -return mmu_reg_load(ID, _HRT_MMU_PAGE_TABLE_BASE_ADDRESS_REG_IDX); + return mmu_reg_load(ID, _HRT_MMU_PAGE_TABLE_BASE_ADDRESS_REG_IDX); } void mmu_invalidate_cache( const mmu_ID_t ID) { mmu_reg_store(ID, _HRT_MMU_INVALIDATE_TLB_REG_IDX, 1); -return; + return; } void mmu_invalidate_cache_all(void) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/mmu_private.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/mmu_private.h index 392b6cc24e8f..7377666f6eb7 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/mmu_private.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/mmu_private.h @@ -26,19 +26,19 @@ STORAGE_CLASS_MMU_H void mmu_reg_store( const unsigned int reg, const hrt_data value) { -assert(ID < N_MMU_ID); -assert(MMU_BASE[ID] != (hrt_address)-1); + assert(ID < N_MMU_ID); + assert(MMU_BASE[ID] != (hrt_address)-1); ia_css_device_store_uint32(MMU_BASE[ID] + reg*sizeof(hrt_data), value); -return; + return; } STORAGE_CLASS_MMU_H hrt_data mmu_reg_load( const mmu_ID_t ID, const unsigned int reg) { -assert(ID < N_MMU_ID); -assert(MMU_BASE[ID] != (hrt_address)-1); -return ia_css_device_load_uint32(MMU_BASE[ID] + reg*sizeof(hrt_data)); + assert(ID < N_MMU_ID); + assert(MMU_BASE[ID] != (hrt_address)-1); + return ia_css_device_load_uint32(MMU_BASE[ID] + reg*sizeof(hrt_data)); } #endif /* __MMU_PRIVATE_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/sp_private.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/sp_private.h index e6283bf67ad3..5ea81c0e82d1 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/sp_private.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/sp_private.h @@ -26,19 +26,19 @@ STORAGE_CLASS_SP_C void sp_ctrl_store( const hrt_address reg, const hrt_data value) { -assert(ID < N_SP_ID); -assert(SP_CTRL_BASE[ID] != (hrt_address)-1); + assert(ID < N_SP_ID); + assert(SP_CTRL_BASE[ID] != (hrt_address)-1); ia_css_device_store_uint32(SP_CTRL_BASE[ID] + reg*sizeof(hrt_data), value); -return; + return; } STORAGE_CLASS_SP_C hrt_data sp_ctrl_load( const sp_ID_t ID, const hrt_address reg) { -assert(ID < N_SP_ID); -assert(SP_CTRL_BASE[ID] != (hrt_address)-1); -return ia_css_device_load_uint32(SP_CTRL_BASE[ID] + reg*sizeof(hrt_data)); + assert(ID < N_SP_ID); + assert(SP_CTRL_BASE[ID] != (hrt_address)-1); + return ia_css_device_load_uint32(SP_CTRL_BASE[ID] + reg*sizeof(hrt_data)); } STORAGE_CLASS_SP_C bool sp_ctrl_getbit( @@ -47,7 +47,7 @@ STORAGE_CLASS_SP_C bool sp_ctrl_getbit( const unsigned int bit) { hrt_data val = sp_ctrl_load(ID, reg); -return (val & (1UL << bit)) != 0; + return (val & (1UL << bit)) != 0; } STORAGE_CLASS_SP_C void sp_ctrl_setbit( @@ -57,7 +57,7 @@ STORAGE_CLASS_SP_C void sp_ctrl_setbit( { hrt_data data = sp_ctrl_load(ID, reg); sp_ctrl_store(ID, reg, (data | (1UL << bit))); -return; + return; } STORAGE_CLASS_SP_C void sp_ctrl_clearbit( @@ -67,7 +67,7 @@ STORAGE_CLASS_SP_C void sp_ctrl_clearbit( { hrt_data data = sp_ctrl_load(ID, reg); sp_ctrl_store(ID, reg, (data & ~(1UL << bit))); -return; + return; } STORAGE_CLASS_SP_C void sp_dmem_store( @@ -76,10 +76,10 @@ STORAGE_CLASS_SP_C void sp_dmem_store( const void *data, const size_t size) { -assert(ID < N_SP_ID); -assert(SP_DMEM_BASE[ID] != (hrt_address)-1); + assert(ID < N_SP_ID); + assert(SP_DMEM_BASE[ID] != (hrt_address)-1); ia_css_device_store(SP_DMEM_BASE[ID] + addr, data, size); -return; + return; } STORAGE_CLASS_SP_C void sp_dmem_load( @@ -88,10 +88,10 @@ STORAGE_CLASS_SP_C void sp_dmem_load( void *data, const size_t size) { -assert(ID < N_SP_ID); -assert(SP_DMEM_BASE[ID] != (hrt_address)-1); + assert(ID < N_SP_ID); + assert(SP_DMEM_BASE[ID] != (hrt_address)-1); ia_css_device_load(SP_DMEM_BASE[ID] + addr, data, size); -return; + return; } STORAGE_CLASS_SP_C void sp_dmem_store_uint8( @@ -99,11 +99,11 @@ STORAGE_CLASS_SP_C void sp_dmem_store_uint8( hrt_address addr, const uint8_t data) { -assert(ID < N_SP_ID); -assert(SP_DMEM_BASE[ID] != (hrt_address)-1); + assert(ID < N_SP_ID); + assert(SP_DMEM_BASE[ID] != (hrt_address)-1); (void)ID; ia_css_device_store_uint8(SP_DMEM_BASE[SP0_ID] + addr, data); -return; + return; } STORAGE_CLASS_SP_C void sp_dmem_store_uint16( @@ -111,11 +111,11 @@ STORAGE_CLASS_SP_C void sp_dmem_store_uint16( hrt_address addr, const uint16_t data) { -assert(ID < N_SP_ID); -assert(SP_DMEM_BASE[ID] != (hrt_address)-1); + assert(ID < N_SP_ID); + assert(SP_DMEM_BASE[ID] != (hrt_address)-1); (void)ID; ia_css_device_store_uint16(SP_DMEM_BASE[SP0_ID] + addr, data); -return; + return; } STORAGE_CLASS_SP_C void sp_dmem_store_uint32( @@ -123,19 +123,19 @@ STORAGE_CLASS_SP_C void sp_dmem_store_uint32( hrt_address addr, const uint32_t data) { -assert(ID < N_SP_ID); -assert(SP_DMEM_BASE[ID] != (hrt_address)-1); + assert(ID < N_SP_ID); + assert(SP_DMEM_BASE[ID] != (hrt_address)-1); (void)ID; ia_css_device_store_uint32(SP_DMEM_BASE[SP0_ID] + addr, data); -return; + return; } STORAGE_CLASS_SP_C uint8_t sp_dmem_load_uint8( const sp_ID_t ID, const hrt_address addr) { -assert(ID < N_SP_ID); -assert(SP_DMEM_BASE[ID] != (hrt_address)-1); + assert(ID < N_SP_ID); + assert(SP_DMEM_BASE[ID] != (hrt_address)-1); (void)ID; return ia_css_device_load_uint8(SP_DMEM_BASE[SP0_ID] + addr); } @@ -144,8 +144,8 @@ STORAGE_CLASS_SP_C uint16_t sp_dmem_load_uint16( const sp_ID_t ID, const hrt_address addr) { -assert(ID < N_SP_ID); -assert(SP_DMEM_BASE[ID] != (hrt_address)-1); + assert(ID < N_SP_ID); + assert(SP_DMEM_BASE[ID] != (hrt_address)-1); (void)ID; return ia_css_device_load_uint16(SP_DMEM_BASE[SP0_ID] + addr); } @@ -154,8 +154,8 @@ STORAGE_CLASS_SP_C uint32_t sp_dmem_load_uint32( const sp_ID_t ID, const hrt_address addr) { -assert(ID < N_SP_ID); -assert(SP_DMEM_BASE[ID] != (hrt_address)-1); + assert(ID < N_SP_ID); + assert(SP_DMEM_BASE[ID] != (hrt_address)-1); (void)ID; return ia_css_device_load_uint32(SP_DMEM_BASE[SP0_ID] + addr); } diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_hrt.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_hrt.c index 0bfebced63af..716d808d56db 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_hrt.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_hrt.c @@ -80,5 +80,5 @@ enum ia_css_err sh_css_hrt_sp_wait(void) hrt_sleep(); } -return IA_CSS_SUCCESS; + return IA_CSS_SUCCESS; } -- cgit v1.2.3 From b5eb7ac16ee5f00a338f59fc0cb647302db5234c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 31 Oct 2017 09:48:43 -0400 Subject: media: atomisp: fix spatch warnings at sh_css.c drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c:5801:1: error: directive in argument list drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c:5803:1: error: directive in argument list drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c:3795 create_host_acc_pipeline() warn: inconsistent indenting drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c:4343 ia_css_pipe_enqueue_buffer() warn: inconsistent indenting drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c:6029 sh_css_pipe_configure_viewfinder() warn: inconsistent indenting drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c:8693 ia_css_stream_capture() warn: inconsistent indenting drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c:9781 ia_css_stream_create() warn: if statement not indented drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c:9988 ia_css_stream_load() warn: inconsistent indenting drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c:10525 ia_css_update_continuous_frames() warn: inconsistent indenting Signed-off-by: Mauro Carvalho Chehab Acked-by: Sakari Ailus --- .../media/atomisp/pci/atomisp2/css2400/sh_css.c | 91 +++++++++++----------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c index e61009faff27..f92b6a9f77eb 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css.c @@ -3779,6 +3779,7 @@ static enum ia_css_err create_host_acc_pipeline(struct ia_css_pipe *pipe) { enum ia_css_err err = IA_CSS_SUCCESS; + const struct ia_css_fw_info *fw; unsigned int i; IA_CSS_ENTER_PRIVATE("pipe = %p", pipe); @@ -3792,14 +3793,12 @@ create_host_acc_pipeline(struct ia_css_pipe *pipe) if (pipe->config.acc_extension) pipe->pipeline.pipe_qos_config = 0; -{ - const struct ia_css_fw_info *fw = pipe->vf_stage; + fw = pipe->vf_stage; for (i = 0; fw; fw = fw->next){ err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw); if (err != IA_CSS_SUCCESS) goto ERR; } -} for (i=0; iconfig.num_acc_stages; i++) { struct ia_css_fw_info *fw = pipe->config.acc_stages[i]; @@ -4331,12 +4330,13 @@ ia_css_pipe_enqueue_buffer(struct ia_css_pipe *pipe, } } } else if ((buf_type == IA_CSS_BUFFER_TYPE_INPUT_FRAME) - || (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) - || (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) - || (buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME) - || (buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME) - || (buf_type == IA_CSS_BUFFER_TYPE_METADATA)) { - return_err = ia_css_bufq_enqueue_buffer(thread_id, + || (buf_type == IA_CSS_BUFFER_TYPE_OUTPUT_FRAME) + || (buf_type == IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME) + || (buf_type == IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME) + || (buf_type == IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME) + || (buf_type == IA_CSS_BUFFER_TYPE_METADATA)) { + + return_err = ia_css_bufq_enqueue_buffer(thread_id, queue_id, (uint32_t)h_vbuf->vptr); #if defined(SH_CSS_ENABLE_PER_FRAME_PARAMS) @@ -5795,13 +5795,15 @@ static enum ia_css_err load_video_binaries(struct ia_css_pipe *pipe) #endif /* Make tnr reference buffers output block height align */ - tnr_info.res.height = #ifndef ISP2401 + tnr_info.res.height = CEIL_MUL(tnr_info.res.height, + mycs->video_binary.info->sp.block.output_block_height); #else + tnr_info.res.height = CEIL_MUL(tnr_height, + mycs->video_binary.info->sp.block.output_block_height); #endif - mycs->video_binary.info->sp.block.output_block_height); } else { tnr_info = mycs->video_binary.internal_frame_info; } @@ -6025,7 +6027,7 @@ sh_css_pipe_configure_viewfinder(struct ia_css_pipe *pipe, unsigned int width, err = ia_css_util_check_res(width, height); if (err != IA_CSS_SUCCESS) { - IA_CSS_LEAVE_ERR_PRIVATE(err); + IA_CSS_LEAVE_ERR_PRIVATE(err); return err; } if (pipe->vf_output_info[idx].res.width != width || @@ -8687,9 +8689,9 @@ enum ia_css_err ia_css_stream_capture( /* Check if the tag descriptor is valid */ if (num_captures < SH_CSS_MINIMUM_TAG_ID) { - ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, - "ia_css_stream_capture() leave: return_err=%d\n", - IA_CSS_ERR_INVALID_ARGUMENTS); + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + "ia_css_stream_capture() leave: return_err=%d\n", + IA_CSS_ERR_INVALID_ARGUMENTS); return IA_CSS_ERR_INVALID_ARGUMENTS; } @@ -9778,23 +9780,22 @@ ERR: if (err == IA_CSS_SUCCESS) { /* working mode: enter into the seed list */ - if (my_css_save.mode == sh_css_mode_working) - for(i = 0; i < MAX_ACTIVE_STREAMS; i++) - if (my_css_save.stream_seeds[i].stream == NULL) - { - IA_CSS_LOG("entered stream into loc=%d", i); - my_css_save.stream_seeds[i].orig_stream = stream; - my_css_save.stream_seeds[i].stream = curr_stream; - my_css_save.stream_seeds[i].num_pipes = num_pipes; - my_css_save.stream_seeds[i].stream_config = *stream_config; - for(j = 0; j < num_pipes; j++) - { - my_css_save.stream_seeds[i].pipe_config[j] = pipes[j]->config; - my_css_save.stream_seeds[i].pipes[j] = pipes[j]; - my_css_save.stream_seeds[i].orig_pipes[j] = &pipes[j]; - } - break; + if (my_css_save.mode == sh_css_mode_working) { + for (i = 0; i < MAX_ACTIVE_STREAMS; i++) + if (!my_css_save.stream_seeds[i].stream) { + IA_CSS_LOG("entered stream into loc=%d", i); + my_css_save.stream_seeds[i].orig_stream = stream; + my_css_save.stream_seeds[i].stream = curr_stream; + my_css_save.stream_seeds[i].num_pipes = num_pipes; + my_css_save.stream_seeds[i].stream_config = *stream_config; + for (j = 0; j < num_pipes; j++) { + my_css_save.stream_seeds[i].pipe_config[j] = pipes[j]->config; + my_css_save.stream_seeds[i].pipes[j] = pipes[j]; + my_css_save.stream_seeds[i].orig_pipes[j] = &pipes[j]; + } + break; } + } #else if (err == IA_CSS_SUCCESS) { err = ia_css_save_stream(curr_stream); @@ -9968,32 +9969,32 @@ ia_css_stream_load(struct ia_css_stream *stream) enum ia_css_err err; assert(stream != NULL); ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_stream_load() enter, \n"); - for(i=0;icontinuous_pipe; -- cgit v1.2.3 From 15b1f47df08800a082b82c90af54ca8352adf8d1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 31 Oct 2017 09:17:28 -0400 Subject: media: atomisp: fix switch coding style at input_system.c Fix a switch at input_system.c that were causing smatch warnings: drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system.c:610 rx_channel_get_state() warn: inconsistent indenting drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system.c:616 rx_channel_get_state() warn: inconsistent indenting drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system.c:622 rx_channel_get_state() warn: inconsistent indenting drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system.c:610 rx_channel_get_state() warn: inconsistent indenting drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system.c:616 rx_channel_get_state() warn: inconsistent indenting drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system.c:622 rx_channel_get_state() warn: inconsistent indenting Signed-off-by: Mauro Carvalho Chehab Acked-by: Sakari Ailus --- .../hive_isp_css_common/host/input_system.c | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system.c index c9af2bfc1f88..cd2096fa75c8 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system.c @@ -602,30 +602,30 @@ STORAGE_CLASS_INLINE void rx_channel_get_state( assert(state != NULL); switch (ch_id) { - case 0: - state->comp_scheme0 = receiver_reg_load(ID, + case 0: + state->comp_scheme0 = receiver_reg_load(ID, _HRT_CSS_RECEIVER_2400_COMP_SCHEME_VC0_REG0_IDX); - state->comp_scheme1 = receiver_reg_load(ID, + state->comp_scheme1 = receiver_reg_load(ID, _HRT_CSS_RECEIVER_2400_COMP_SCHEME_VC0_REG1_IDX); - break; - case 1: - state->comp_scheme0 = receiver_reg_load(ID, + break; + case 1: + state->comp_scheme0 = receiver_reg_load(ID, _HRT_CSS_RECEIVER_2400_COMP_SCHEME_VC1_REG0_IDX); - state->comp_scheme1 = receiver_reg_load(ID, + state->comp_scheme1 = receiver_reg_load(ID, _HRT_CSS_RECEIVER_2400_COMP_SCHEME_VC1_REG1_IDX); - break; - case 2: - state->comp_scheme0 = receiver_reg_load(ID, + break; + case 2: + state->comp_scheme0 = receiver_reg_load(ID, _HRT_CSS_RECEIVER_2400_COMP_SCHEME_VC2_REG0_IDX); - state->comp_scheme1 = receiver_reg_load(ID, + state->comp_scheme1 = receiver_reg_load(ID, _HRT_CSS_RECEIVER_2400_COMP_SCHEME_VC2_REG1_IDX); - break; - case 3: - state->comp_scheme0 = receiver_reg_load(ID, + break; + case 3: + state->comp_scheme0 = receiver_reg_load(ID, _HRT_CSS_RECEIVER_2400_COMP_SCHEME_VC3_REG0_IDX); - state->comp_scheme1 = receiver_reg_load(ID, + state->comp_scheme1 = receiver_reg_load(ID, _HRT_CSS_RECEIVER_2400_COMP_SCHEME_VC3_REG1_IDX); - break; + break; } /* See Table 7.1.17,..., 7.1.24 */ -- cgit v1.2.3 From fb5b78a5f660c8537f4e85ae1a613d37f1384bcd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 31 Oct 2017 10:29:06 -0400 Subject: media: atomisp: fix other inconsistent identing As reported by smatch: drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/src/pipeline.c:607 pipeline_stage_create() warn: inconsistent indenting drivers/staging/media/atomisp/i2c/atomisp-ov2680.c:255 ov2680_write_reg_array() warn: inconsistent indenting drivers/staging/media/atomisp/i2c/atomisp-ov2680.c:401 __ov2680_set_exposure() warn: inconsistent indenting drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_params.c:4269 sh_css_params_write_to_ddr_internal() warn: inconsistent indenting drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c:1008 atomisp_register_entities() warn: inconsistent indenting drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/src/binary.c:1709 ia_css_binary_find() warn: inconsistent indenting Signed-off-by: Mauro Carvalho Chehab Acked-by: Sakari Ailus --- drivers/staging/media/atomisp/i2c/atomisp-ov2680.c | 8 ++-- .../media/atomisp/i2c/ov5693/atomisp-ov5693.c | 4 +- .../media/atomisp/pci/atomisp2/atomisp_v4l2.c | 2 +- .../atomisp2/css2400/runtime/binary/src/binary.c | 12 ++--- .../css2400/runtime/pipeline/src/pipeline.c | 2 +- .../atomisp2/css2400/runtime/rmgr/src/rmgr_vbuf.c | 2 +- .../atomisp/pci/atomisp2/css2400/sh_css_params.c | 54 +++++++++++----------- 7 files changed, 43 insertions(+), 41 deletions(-) diff --git a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c index 588bc0b15411..cd67d38f183a 100644 --- a/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c +++ b/drivers/staging/media/atomisp/i2c/atomisp-ov2680.c @@ -252,8 +252,8 @@ static int ov2680_write_reg_array(struct i2c_client *client, if (!__ov2680_write_reg_is_consecutive(client, &ctrl, next)) { err = __ov2680_flush_reg_array(client, &ctrl); - if (err) - return err; + if (err) + return err; } err = __ov2680_buf_reg_array(client, &ctrl, next); if (err) { @@ -398,7 +398,9 @@ static long __ov2680_set_exposure(struct v4l2_subdev *sd, int coarse_itg, u16 vts,hts; int ret,exp_val; - dev_dbg(&client->dev, "+++++++__ov2680_set_exposure coarse_itg %d, gain %d, digitgain %d++\n",coarse_itg, gain, digitgain); + dev_dbg(&client->dev, + "+++++++__ov2680_set_exposure coarse_itg %d, gain %d, digitgain %d++\n", + coarse_itg, gain, digitgain); hts = ov2680_res[dev->fmt_idx].pixels_per_line; vts = ov2680_res[dev->fmt_idx].lines_per_frame; diff --git a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c index 50da7130f9ca..3e7c3851280f 100644 --- a/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c +++ b/drivers/staging/media/atomisp/i2c/ov5693/atomisp-ov5693.c @@ -386,8 +386,8 @@ static int ov5693_write_reg_array(struct i2c_client *client, if (!__ov5693_write_reg_is_consecutive(client, &ctrl, next)) { err = __ov5693_flush_reg_array(client, &ctrl); - if (err) - return err; + if (err) + return err; } err = __ov5693_buf_reg_array(client, &ctrl, next); if (err) { diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c index bdfe8c855b23..3c260f8b52e2 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_v4l2.c @@ -1004,7 +1004,7 @@ csi_and_subdev_probe_failed: v4l2_device_unregister(&isp->v4l2_dev); v4l2_device_failed: media_device_unregister(&isp->media_dev); - media_device_cleanup(&isp->media_dev); + media_device_cleanup(&isp->media_dev); return ret; } diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/src/binary.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/src/binary.c index 9f8a125f0d74..e028e460ae4c 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/src/binary.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/binary/src/binary.c @@ -1697,11 +1697,11 @@ ia_css_binary_find(struct ia_css_binary_descr *descr, } #endif if (xcandidate->num_output_pins > 1 && /* in case we have a second output pin, */ - req_vf_info && /* and we need vf output. */ + req_vf_info && /* and we need vf output. */ /* check if the required vf format is supported. */ - !binary_supports_output_format(xcandidate, req_vf_info->format)) { - ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, + !binary_supports_output_format(xcandidate, req_vf_info->format)) { + ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_binary_find() [%d] continue: (%d > %d) && (%p != NULL) && !%d\n", __LINE__, xcandidate->num_output_pins, 1, req_vf_info, @@ -1711,8 +1711,8 @@ ia_css_binary_find(struct ia_css_binary_descr *descr, /* Check if vf_veceven supports the requested vf format */ if (xcandidate->num_output_pins == 1 && - req_vf_info && candidate->enable.vf_veceven && - !binary_supports_vf_format(xcandidate, req_vf_info->format)) { + req_vf_info && candidate->enable.vf_veceven && + !binary_supports_vf_format(xcandidate, req_vf_info->format)) { ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_binary_find() [%d] continue: (%d == %d) && (%p != NULL) && %d && !%d\n", __LINE__, xcandidate->num_output_pins, 1, @@ -1723,7 +1723,7 @@ ia_css_binary_find(struct ia_css_binary_descr *descr, /* Check if vf_veceven supports the requested vf width */ if (xcandidate->num_output_pins == 1 && - req_vf_info && candidate->enable.vf_veceven) { /* and we need vf output. */ + req_vf_info && candidate->enable.vf_veceven) { /* and we need vf output. */ if (req_vf_info->res.width > candidate->output.max_width) { ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_binary_find() [%d] continue: (%d < %d)\n", diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/src/pipeline.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/src/pipeline.c index 95542fc82217..62d13978475d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/src/pipeline.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/pipeline/src/pipeline.c @@ -603,7 +603,7 @@ static enum ia_css_err pipeline_stage_create( /* Verify input parameters*/ if (!(stage_desc->in_frame) && !(stage_desc->firmware) && (stage_desc->binary) && !(stage_desc->binary->online)) { - err = IA_CSS_ERR_INTERNAL_ERROR; + err = IA_CSS_ERR_INTERNAL_ERROR; goto ERR; } diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/rmgr/src/rmgr_vbuf.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/rmgr/src/rmgr_vbuf.c index fa92d8da8f1c..e56006c07ee8 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/rmgr/src/rmgr_vbuf.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/rmgr/src/rmgr_vbuf.c @@ -174,7 +174,7 @@ void ia_css_rmgr_uninit_vbuf(struct ia_css_rmgr_vbuf_pool *pool) ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE, "ia_css_rmgr_uninit_vbuf()\n"); if (pool == NULL) { ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR, "ia_css_rmgr_uninit_vbuf(): NULL argument\n"); - return; + return; } if (pool->handles != NULL) { /* free the hmm buffers */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_params.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_params.c index 48224370b8bf..fbb36112fe3c 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_params.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_params.c @@ -4266,33 +4266,33 @@ sh_css_params_write_to_ddr_internal( size_t *virt_size_tetra_y[ IA_CSS_MORPH_TABLE_NUM_PLANES]; - virt_addr_tetra_x[0] = &ddr_map->tetra_r_x; - virt_addr_tetra_x[1] = &ddr_map->tetra_gr_x; - virt_addr_tetra_x[2] = &ddr_map->tetra_gb_x; - virt_addr_tetra_x[3] = &ddr_map->tetra_b_x; - virt_addr_tetra_x[4] = &ddr_map->tetra_ratb_x; - virt_addr_tetra_x[5] = &ddr_map->tetra_batr_x; - - virt_size_tetra_x[0] = &ddr_map_size->tetra_r_x; - virt_size_tetra_x[1] = &ddr_map_size->tetra_gr_x; - virt_size_tetra_x[2] = &ddr_map_size->tetra_gb_x; - virt_size_tetra_x[3] = &ddr_map_size->tetra_b_x; - virt_size_tetra_x[4] = &ddr_map_size->tetra_ratb_x; - virt_size_tetra_x[5] = &ddr_map_size->tetra_batr_x; - - virt_addr_tetra_y[0] = &ddr_map->tetra_r_y; - virt_addr_tetra_y[1] = &ddr_map->tetra_gr_y; - virt_addr_tetra_y[2] = &ddr_map->tetra_gb_y; - virt_addr_tetra_y[3] = &ddr_map->tetra_b_y; - virt_addr_tetra_y[4] = &ddr_map->tetra_ratb_y; - virt_addr_tetra_y[5] = &ddr_map->tetra_batr_y; - - virt_size_tetra_y[0] = &ddr_map_size->tetra_r_y; - virt_size_tetra_y[1] = &ddr_map_size->tetra_gr_y; - virt_size_tetra_y[2] = &ddr_map_size->tetra_gb_y; - virt_size_tetra_y[3] = &ddr_map_size->tetra_b_y; - virt_size_tetra_y[4] = &ddr_map_size->tetra_ratb_y; - virt_size_tetra_y[5] = &ddr_map_size->tetra_batr_y; + virt_addr_tetra_x[0] = &ddr_map->tetra_r_x; + virt_addr_tetra_x[1] = &ddr_map->tetra_gr_x; + virt_addr_tetra_x[2] = &ddr_map->tetra_gb_x; + virt_addr_tetra_x[3] = &ddr_map->tetra_b_x; + virt_addr_tetra_x[4] = &ddr_map->tetra_ratb_x; + virt_addr_tetra_x[5] = &ddr_map->tetra_batr_x; + + virt_size_tetra_x[0] = &ddr_map_size->tetra_r_x; + virt_size_tetra_x[1] = &ddr_map_size->tetra_gr_x; + virt_size_tetra_x[2] = &ddr_map_size->tetra_gb_x; + virt_size_tetra_x[3] = &ddr_map_size->tetra_b_x; + virt_size_tetra_x[4] = &ddr_map_size->tetra_ratb_x; + virt_size_tetra_x[5] = &ddr_map_size->tetra_batr_x; + + virt_addr_tetra_y[0] = &ddr_map->tetra_r_y; + virt_addr_tetra_y[1] = &ddr_map->tetra_gr_y; + virt_addr_tetra_y[2] = &ddr_map->tetra_gb_y; + virt_addr_tetra_y[3] = &ddr_map->tetra_b_y; + virt_addr_tetra_y[4] = &ddr_map->tetra_ratb_y; + virt_addr_tetra_y[5] = &ddr_map->tetra_batr_y; + + virt_size_tetra_y[0] = &ddr_map_size->tetra_r_y; + virt_size_tetra_y[1] = &ddr_map_size->tetra_gr_y; + virt_size_tetra_y[2] = &ddr_map_size->tetra_gb_y; + virt_size_tetra_y[3] = &ddr_map_size->tetra_b_y; + virt_size_tetra_y[4] = &ddr_map_size->tetra_ratb_y; + virt_size_tetra_y[5] = &ddr_map_size->tetra_batr_y; buff_realloced = false; for (i = 0; i < IA_CSS_MORPH_TABLE_NUM_PLANES; i++) { -- cgit v1.2.3 From 3708713fbf9b31f2241dca0519d80ebc247d272c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 31 Oct 2017 10:53:51 -0400 Subject: media: atomisp: get rid of wrong stddef.h include The places at atomisp.h that use stddef.h are wrong: the types it needs are actually defined at linux/types.h. Also, it causes lots of smatch warnings due to the redefinition of ofsetof() macro: /opt/gcc-7.1.0/x86/lib/gcc/x86_64-pc-linux-gnu/7.1.0/include/stddef.h:417:9: warning: preprocessor token offsetof redefined ./include/linux/stddef.h:16:9: this was the original definition Signed-off-by: Mauro Carvalho Chehab Acked-by: Sakari Ailus --- .../css2400/hive_isp_css_common/host/dma.c | 2 +- .../hive_isp_css_include/host/hmem_public.h | 4 +-- .../css2400/hive_isp_css_include/type_support.h | 42 ---------------------- 3 files changed, 3 insertions(+), 45 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/dma.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/dma.c index 87a25d4289ec..770db7dff5d3 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/dma.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/dma.c @@ -12,7 +12,7 @@ * more details. */ -#include /* NULL */ +#include #include "dma.h" diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/hmem_public.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/hmem_public.h index 9b8e7c92442d..8538f86ab5e6 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/hmem_public.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/hmem_public.h @@ -15,10 +15,10 @@ #ifndef __HMEM_PUBLIC_H_INCLUDED__ #define __HMEM_PUBLIC_H_INCLUDED__ -#include /* size_t */ +#include /* size_t */ /*! Return the size of HMEM[ID] - + \param ID[in] HMEM identifier \Note: The size is the byte size of the area it occupies diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/type_support.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/type_support.h index b82fa3eba79f..bc77537fa73a 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/type_support.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/type_support.h @@ -30,27 +30,6 @@ #define IA_CSS_INT32_T_BITS 32 #define IA_CSS_UINT64_T_BITS 64 -#if defined(_MSC_VER) -#include -/* For ATE compilation define the bool */ -#if defined(_ATE_) -#define bool int -#define true 1 -#define false 0 -#else -#include -#endif -#include -#include -#include -#if defined(_M_X64) -#define HOST_ADDRESS(x) (unsigned long long)(x) -#else -#define HOST_ADDRESS(x) (unsigned long)(x) -#endif - -#elif defined(__KERNEL__) - #define CHAR_BIT (8) #include @@ -58,25 +37,4 @@ #include #define HOST_ADDRESS(x) (unsigned long)(x) -#elif defined(__GNUC__) -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS 1 -#endif -#include -#include -#include -#include -#include -#define HOST_ADDRESS(x) (unsigned long)(x) - -#else /* default is for the FIST environment */ -#include -#include -#include -#include -#include -#define HOST_ADDRESS(x) (unsigned long)(x) - -#endif - #endif /* __TYPE_SUPPORT_H_INCLUDED__ */ -- cgit v1.2.3 From 4c5133f5c51647caa7715ba7025b86086a42a922 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 31 Oct 2017 11:03:04 -0400 Subject: media: atomisp: get rid of storage_class.h Don't hide function declaration on ugly macros. Signed-off-by: Mauro Carvalho Chehab Acked-by: Sakari Ailus --- .../base/circbuf/interface/ia_css_circbuf.h | 39 +++++++++++----------- .../base/circbuf/interface/ia_css_circbuf_desc.h | 15 ++++----- .../css_2401_csi2p_system/host/csi_rx_private.h | 18 +++++----- .../hive_isp_css_common/host/fifo_monitor.c | 8 ++--- .../css2400/hive_isp_css_common/host/gdc.c | 8 ++--- .../hive_isp_css_common/host/input_system.c | 20 +++++------ .../css2400/hive_isp_css_common/host/irq.c | 12 +++---- .../css2400/hive_isp_css_include/assert_support.h | 3 +- .../atomisp2/css2400/hive_isp_css_include/bamem.h | 7 ++-- .../atomisp2/css2400/hive_isp_css_include/csi_rx.h | 5 --- .../atomisp2/css2400/hive_isp_css_include/debug.h | 7 ++-- .../atomisp2/css2400/hive_isp_css_include/dma.h | 7 ++-- .../css2400/hive_isp_css_include/event_fifo.h | 7 ++-- .../css2400/hive_isp_css_include/fifo_monitor.h | 7 ++-- .../css2400/hive_isp_css_include/gdc_device.h | 7 ++-- .../css2400/hive_isp_css_include/gp_device.h | 7 ++-- .../css2400/hive_isp_css_include/gp_timer.h | 7 ++-- .../atomisp2/css2400/hive_isp_css_include/gpio.h | 7 ++-- .../atomisp2/css2400/hive_isp_css_include/hmem.h | 7 ++-- .../hive_isp_css_include/host/csi_rx_public.h | 18 +++++----- .../css2400/hive_isp_css_include/host/gdc_public.h | 6 ++-- .../css2400/hive_isp_css_include/host/isp_op1w.h | 9 +++-- .../css2400/hive_isp_css_include/host/isp_op2w.h | 9 +++-- .../css2400/hive_isp_css_include/host/mmu_public.h | 8 ++--- .../hive_isp_css_include/host/ref_vector_func.h | 9 +++-- .../css2400/hive_isp_css_include/ibuf_ctrl.h | 7 ++-- .../css2400/hive_isp_css_include/input_formatter.h | 7 ++-- .../css2400/hive_isp_css_include/input_system.h | 7 ++-- .../atomisp2/css2400/hive_isp_css_include/irq.h | 7 ++-- .../atomisp2/css2400/hive_isp_css_include/isp.h | 7 ++-- .../css2400/hive_isp_css_include/isys_dma.h | 7 ++-- .../css2400/hive_isp_css_include/isys_irq.h | 9 +++-- .../hive_isp_css_include/isys_stream2mmio.h | 7 ++-- .../css2400/hive_isp_css_include/math_support.h | 25 +++++++------- .../css2400/hive_isp_css_include/mmu_device.h | 7 ++-- .../atomisp2/css2400/hive_isp_css_include/mpmath.h | 9 +++-- .../atomisp2/css2400/hive_isp_css_include/osys.h | 7 ++-- .../css2400/hive_isp_css_include/pixelgen.h | 7 ++-- .../hive_isp_css_include/platform_support.h | 1 - .../css2400/hive_isp_css_include/print_support.h | 3 +- .../atomisp2/css2400/hive_isp_css_include/queue.h | 7 ++-- .../css2400/hive_isp_css_include/resource.h | 7 ++-- .../atomisp2/css2400/hive_isp_css_include/socket.h | 7 ++-- .../pci/atomisp2/css2400/hive_isp_css_include/sp.h | 7 ++-- .../css2400/hive_isp_css_include/storage_class.h | 34 ------------------- .../css2400/hive_isp_css_include/stream_buffer.h | 7 ++-- .../css2400/hive_isp_css_include/string_support.h | 7 ++-- .../atomisp2/css2400/hive_isp_css_include/tag.h | 7 ++-- .../css2400/hive_isp_css_include/timed_ctrl.h | 7 ++-- .../atomisp2/css2400/hive_isp_css_include/vamem.h | 7 ++-- .../css2400/hive_isp_css_include/vector_func.h | 7 ++-- .../css2400/hive_isp_css_include/vector_ops.h | 7 ++-- .../atomisp2/css2400/hive_isp_css_include/vmem.h | 7 ++-- .../atomisp2/css2400/hive_isp_css_include/xmem.h | 7 ++-- .../isp/kernels/s3a/s3a_1.0/ia_css_s3a.host.c | 2 +- .../pci/atomisp2/css2400/runtime/bufq/src/bufq.c | 2 +- .../css2400/runtime/debug/interface/ia_css_debug.h | 2 +- .../css2400/runtime/inputfifo/src/inputfifo.c | 28 ++++++++-------- .../css2400/runtime/rmgr/interface/ia_css_rmgr.h | 7 ++-- .../atomisp/pci/atomisp2/css2400/sh_css_internal.h | 4 +-- 60 files changed, 230 insertions(+), 314 deletions(-) delete mode 100644 drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/storage_class.h diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/interface/ia_css_circbuf.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/interface/ia_css_circbuf.h index 766218ed3649..914aa7f98700 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/interface/ia_css_circbuf.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/interface/ia_css_circbuf.h @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include "ia_css_circbuf_comm.h" @@ -45,7 +44,7 @@ struct ia_css_circbuf_s { * @param elems An array of elements. * @param desc The descriptor set to the size using ia_css_circbuf_desc_init(). */ -STORAGE_CLASS_EXTERN void ia_css_circbuf_create( +extern void ia_css_circbuf_create( ia_css_circbuf_t *cb, ia_css_circbuf_elem_t *elems, ia_css_circbuf_desc_t *desc); @@ -55,7 +54,7 @@ STORAGE_CLASS_EXTERN void ia_css_circbuf_create( * * @param cb The pointer to the circular buffer. */ -STORAGE_CLASS_EXTERN void ia_css_circbuf_destroy( +extern void ia_css_circbuf_destroy( ia_css_circbuf_t *cb); /** @@ -68,7 +67,7 @@ STORAGE_CLASS_EXTERN void ia_css_circbuf_destroy( * * @return the pop-out value. */ -STORAGE_CLASS_EXTERN uint32_t ia_css_circbuf_pop( +extern uint32_t ia_css_circbuf_pop( ia_css_circbuf_t *cb); /** @@ -82,7 +81,7 @@ STORAGE_CLASS_EXTERN uint32_t ia_css_circbuf_pop( * * @return the extracted value. */ -STORAGE_CLASS_EXTERN uint32_t ia_css_circbuf_extract( +extern uint32_t ia_css_circbuf_extract( ia_css_circbuf_t *cb, int offset); @@ -97,7 +96,7 @@ STORAGE_CLASS_EXTERN uint32_t ia_css_circbuf_extract( * @param elem The pointer to the element. * @param val The value to be set. */ -STORAGE_CLASS_INLINE void ia_css_circbuf_elem_set_val( +static inline void ia_css_circbuf_elem_set_val( ia_css_circbuf_elem_t *elem, uint32_t val) { @@ -111,7 +110,7 @@ STORAGE_CLASS_INLINE void ia_css_circbuf_elem_set_val( * * @param elem The pointer to the element. */ -STORAGE_CLASS_INLINE void ia_css_circbuf_elem_init( +static inline void ia_css_circbuf_elem_init( ia_css_circbuf_elem_t *elem) { OP___assert(elem != NULL); @@ -124,7 +123,7 @@ STORAGE_CLASS_INLINE void ia_css_circbuf_elem_init( * @param src The element as the copy source. * @param dest The element as the copy destination. */ -STORAGE_CLASS_INLINE void ia_css_circbuf_elem_cpy( +static inline void ia_css_circbuf_elem_cpy( ia_css_circbuf_elem_t *src, ia_css_circbuf_elem_t *dest) { @@ -143,7 +142,7 @@ STORAGE_CLASS_INLINE void ia_css_circbuf_elem_cpy( * * @return the position at offset. */ -STORAGE_CLASS_INLINE uint8_t ia_css_circbuf_get_pos_at_offset( +static inline uint8_t ia_css_circbuf_get_pos_at_offset( ia_css_circbuf_t *cb, uint32_t base, int offset) @@ -176,7 +175,7 @@ STORAGE_CLASS_INLINE uint8_t ia_css_circbuf_get_pos_at_offset( * * @return the offset. */ -STORAGE_CLASS_INLINE int ia_css_circbuf_get_offset( +static inline int ia_css_circbuf_get_offset( ia_css_circbuf_t *cb, uint32_t src_pos, uint32_t dest_pos) @@ -201,7 +200,7 @@ STORAGE_CLASS_INLINE int ia_css_circbuf_get_offset( * * TODO: Test this API. */ -STORAGE_CLASS_INLINE uint32_t ia_css_circbuf_get_size( +static inline uint32_t ia_css_circbuf_get_size( ia_css_circbuf_t *cb) { OP___assert(cb != NULL); @@ -217,7 +216,7 @@ STORAGE_CLASS_INLINE uint32_t ia_css_circbuf_get_size( * * @return the number of available elements. */ -STORAGE_CLASS_INLINE uint32_t ia_css_circbuf_get_num_elems( +static inline uint32_t ia_css_circbuf_get_num_elems( ia_css_circbuf_t *cb) { int num; @@ -239,7 +238,7 @@ STORAGE_CLASS_INLINE uint32_t ia_css_circbuf_get_num_elems( * - true when it is empty. * - false when it is not empty. */ -STORAGE_CLASS_INLINE bool ia_css_circbuf_is_empty( +static inline bool ia_css_circbuf_is_empty( ia_css_circbuf_t *cb) { OP___assert(cb != NULL); @@ -257,7 +256,7 @@ STORAGE_CLASS_INLINE bool ia_css_circbuf_is_empty( * - true when it is full. * - false when it is not full. */ -STORAGE_CLASS_INLINE bool ia_css_circbuf_is_full(ia_css_circbuf_t *cb) +static inline bool ia_css_circbuf_is_full(ia_css_circbuf_t *cb) { OP___assert(cb != NULL); OP___assert(cb->desc != NULL); @@ -274,7 +273,7 @@ STORAGE_CLASS_INLINE bool ia_css_circbuf_is_full(ia_css_circbuf_t *cb) * @param cb The pointer to the circular buffer. * @param elem The new element. */ -STORAGE_CLASS_INLINE void ia_css_circbuf_write( +static inline void ia_css_circbuf_write( ia_css_circbuf_t *cb, ia_css_circbuf_elem_t elem) { @@ -298,7 +297,7 @@ STORAGE_CLASS_INLINE void ia_css_circbuf_write( * @param cb The pointer to the circular buffer. * @param val The value to be pushed in. */ -STORAGE_CLASS_INLINE void ia_css_circbuf_push( +static inline void ia_css_circbuf_push( ia_css_circbuf_t *cb, uint32_t val) { @@ -321,7 +320,7 @@ STORAGE_CLASS_INLINE void ia_css_circbuf_push( * * @return: The number of free elements. */ -STORAGE_CLASS_INLINE uint32_t ia_css_circbuf_get_free_elems( +static inline uint32_t ia_css_circbuf_get_free_elems( ia_css_circbuf_t *cb) { OP___assert(cb != NULL); @@ -338,7 +337,7 @@ STORAGE_CLASS_INLINE uint32_t ia_css_circbuf_get_free_elems( * * @return the elements value. */ -STORAGE_CLASS_EXTERN uint32_t ia_css_circbuf_peek( +extern uint32_t ia_css_circbuf_peek( ia_css_circbuf_t *cb, int offset); @@ -350,7 +349,7 @@ STORAGE_CLASS_EXTERN uint32_t ia_css_circbuf_peek( * * @return the elements value. */ -STORAGE_CLASS_EXTERN uint32_t ia_css_circbuf_peek_from_start( +extern uint32_t ia_css_circbuf_peek_from_start( ia_css_circbuf_t *cb, int offset); @@ -369,7 +368,7 @@ STORAGE_CLASS_EXTERN uint32_t ia_css_circbuf_peek_from_start( * @return true on succesfully increasing the size * false on failure */ -STORAGE_CLASS_EXTERN bool ia_css_circbuf_increase_size( +extern bool ia_css_circbuf_increase_size( ia_css_circbuf_t *cb, unsigned int sz_delta, ia_css_circbuf_elem_t *elems); diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/interface/ia_css_circbuf_desc.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/interface/ia_css_circbuf_desc.h index a8447d409c31..8dd7cd6cd3d8 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/interface/ia_css_circbuf_desc.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/base/circbuf/interface/ia_css_circbuf_desc.h @@ -17,7 +17,6 @@ #include #include -#include #include #include #include "ia_css_circbuf_comm.h" @@ -35,7 +34,7 @@ * - true when it is empty. * - false when it is not empty. */ -STORAGE_CLASS_INLINE bool ia_css_circbuf_desc_is_empty( +static inline bool ia_css_circbuf_desc_is_empty( ia_css_circbuf_desc_t *cb_desc) { OP___assert(cb_desc != NULL); @@ -52,7 +51,7 @@ STORAGE_CLASS_INLINE bool ia_css_circbuf_desc_is_empty( * - true when it is full. * - false when it is not full. */ -STORAGE_CLASS_INLINE bool ia_css_circbuf_desc_is_full( +static inline bool ia_css_circbuf_desc_is_full( ia_css_circbuf_desc_t *cb_desc) { OP___assert(cb_desc != NULL); @@ -65,7 +64,7 @@ STORAGE_CLASS_INLINE bool ia_css_circbuf_desc_is_full( * @param cb_desc The pointer circular buffer descriptor * @param size The size of the circular buffer */ -STORAGE_CLASS_INLINE void ia_css_circbuf_desc_init( +static inline void ia_css_circbuf_desc_init( ia_css_circbuf_desc_t *cb_desc, int8_t size) { @@ -82,7 +81,7 @@ STORAGE_CLASS_INLINE void ia_css_circbuf_desc_init( * * @return the position in the circular buffer descriptor. */ -STORAGE_CLASS_INLINE uint8_t ia_css_circbuf_desc_get_pos_at_offset( +static inline uint8_t ia_css_circbuf_desc_get_pos_at_offset( ia_css_circbuf_desc_t *cb_desc, uint32_t base, int offset) @@ -114,7 +113,7 @@ STORAGE_CLASS_INLINE uint8_t ia_css_circbuf_desc_get_pos_at_offset( * * @return the offset. */ -STORAGE_CLASS_INLINE int ia_css_circbuf_desc_get_offset( +static inline int ia_css_circbuf_desc_get_offset( ia_css_circbuf_desc_t *cb_desc, uint32_t src_pos, uint32_t dest_pos) @@ -135,7 +134,7 @@ STORAGE_CLASS_INLINE int ia_css_circbuf_desc_get_offset( * * @return The number of available elements. */ -STORAGE_CLASS_INLINE uint32_t ia_css_circbuf_desc_get_num_elems( +static inline uint32_t ia_css_circbuf_desc_get_num_elems( ia_css_circbuf_desc_t *cb_desc) { int num; @@ -155,7 +154,7 @@ STORAGE_CLASS_INLINE uint32_t ia_css_circbuf_desc_get_num_elems( * * @return: The number of free elements. */ -STORAGE_CLASS_INLINE uint32_t ia_css_circbuf_desc_get_free_elems( +static inline uint32_t ia_css_circbuf_desc_get_free_elems( ia_css_circbuf_desc_t *cb_desc) { uint32_t num; diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/host/csi_rx_private.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/host/csi_rx_private.h index 5819bcff5e55..6720ab55d6f5 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/host/csi_rx_private.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/css_2401_csi2p_system/host/csi_rx_private.h @@ -34,7 +34,7 @@ * @brief Get the csi rx fe state. * Refer to "csi_rx_public.h" for details. */ -STORAGE_CLASS_CSI_RX_C void csi_rx_fe_ctrl_get_state( +static inline void csi_rx_fe_ctrl_get_state( const csi_rx_frontend_ID_t ID, csi_rx_fe_ctrl_state_t *state) { @@ -73,7 +73,7 @@ STORAGE_CLASS_CSI_RX_C void csi_rx_fe_ctrl_get_state( * @brief Get the state of the csi rx fe dlane process. * Refer to "csi_rx_public.h" for details. */ -STORAGE_CLASS_CSI_RX_C void csi_rx_fe_ctrl_get_dlane_state( +static inline void csi_rx_fe_ctrl_get_dlane_state( const csi_rx_frontend_ID_t ID, const uint32_t lane, csi_rx_fe_ctrl_lane_t *dlane_state) @@ -89,7 +89,7 @@ STORAGE_CLASS_CSI_RX_C void csi_rx_fe_ctrl_get_dlane_state( * @brief dump the csi rx fe state. * Refer to "csi_rx_public.h" for details. */ -STORAGE_CLASS_CSI_RX_C void csi_rx_fe_ctrl_dump_state( +static inline void csi_rx_fe_ctrl_dump_state( const csi_rx_frontend_ID_t ID, csi_rx_fe_ctrl_state_t *state) { @@ -118,7 +118,7 @@ STORAGE_CLASS_CSI_RX_C void csi_rx_fe_ctrl_dump_state( * @brief Get the csi rx be state. * Refer to "csi_rx_public.h" for details. */ -STORAGE_CLASS_CSI_RX_C void csi_rx_be_ctrl_get_state( +static inline void csi_rx_be_ctrl_get_state( const csi_rx_backend_ID_t ID, csi_rx_be_ctrl_state_t *state) { @@ -181,7 +181,7 @@ STORAGE_CLASS_CSI_RX_C void csi_rx_be_ctrl_get_state( * @brief Dump the csi rx be state. * Refer to "csi_rx_public.h" for details. */ -STORAGE_CLASS_CSI_RX_C void csi_rx_be_ctrl_dump_state( +static inline void csi_rx_be_ctrl_dump_state( const csi_rx_backend_ID_t ID, csi_rx_be_ctrl_state_t *state) { @@ -225,7 +225,7 @@ STORAGE_CLASS_CSI_RX_C void csi_rx_be_ctrl_dump_state( * @brief Load the register value. * Refer to "csi_rx_public.h" for details. */ -STORAGE_CLASS_CSI_RX_C hrt_data csi_rx_fe_ctrl_reg_load( +static inline hrt_data csi_rx_fe_ctrl_reg_load( const csi_rx_frontend_ID_t ID, const hrt_address reg) { @@ -239,7 +239,7 @@ STORAGE_CLASS_CSI_RX_C hrt_data csi_rx_fe_ctrl_reg_load( * @brief Store a value to the register. * Refer to "ibuf_ctrl_public.h" for details. */ -STORAGE_CLASS_CSI_RX_C void csi_rx_fe_ctrl_reg_store( +static inline void csi_rx_fe_ctrl_reg_store( const csi_rx_frontend_ID_t ID, const hrt_address reg, const hrt_data value) @@ -253,7 +253,7 @@ STORAGE_CLASS_CSI_RX_C void csi_rx_fe_ctrl_reg_store( * @brief Load the register value. * Refer to "csi_rx_public.h" for details. */ -STORAGE_CLASS_CSI_RX_C hrt_data csi_rx_be_ctrl_reg_load( +static inline hrt_data csi_rx_be_ctrl_reg_load( const csi_rx_backend_ID_t ID, const hrt_address reg) { @@ -267,7 +267,7 @@ STORAGE_CLASS_CSI_RX_C hrt_data csi_rx_be_ctrl_reg_load( * @brief Store a value to the register. * Refer to "ibuf_ctrl_public.h" for details. */ -STORAGE_CLASS_CSI_RX_C void csi_rx_be_ctrl_reg_store( +static inline void csi_rx_be_ctrl_reg_store( const csi_rx_backend_ID_t ID, const hrt_address reg, const hrt_data value) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/fifo_monitor.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/fifo_monitor.c index 1087944d637f..1bf292401adc 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/fifo_monitor.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/fifo_monitor.c @@ -38,12 +38,12 @@ STORAGE_CLASS_FIFO_MONITOR_DATA unsigned int FIFO_SWITCH_ADDR[N_FIFO_SWITCH] = { #include "fifo_monitor_private.h" #endif /* __INLINE_FIFO_MONITOR__ */ -STORAGE_CLASS_INLINE bool fifo_monitor_status_valid ( +static inline bool fifo_monitor_status_valid ( const fifo_monitor_ID_t ID, const unsigned int reg, const unsigned int port_id); -STORAGE_CLASS_INLINE bool fifo_monitor_status_accept( +static inline bool fifo_monitor_status_accept( const fifo_monitor_ID_t ID, const unsigned int reg, const unsigned int port_id); @@ -546,7 +546,7 @@ void fifo_monitor_get_state( return; } -STORAGE_CLASS_INLINE bool fifo_monitor_status_valid ( +static inline bool fifo_monitor_status_valid ( const fifo_monitor_ID_t ID, const unsigned int reg, const unsigned int port_id) @@ -556,7 +556,7 @@ STORAGE_CLASS_INLINE bool fifo_monitor_status_valid ( return (data >> (((port_id * 2) + _hive_str_mon_valid_offset))) & 0x1; } -STORAGE_CLASS_INLINE bool fifo_monitor_status_accept( +static inline bool fifo_monitor_status_accept( const fifo_monitor_ID_t ID, const unsigned int reg, const unsigned int port_id) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/gdc.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/gdc.c index 4d6308abd036..1966b147f8ab 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/gdc.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/gdc.c @@ -22,12 +22,12 @@ /* * Local function declarations */ -STORAGE_CLASS_INLINE void gdc_reg_store( +static inline void gdc_reg_store( const gdc_ID_t ID, const unsigned int reg, const hrt_data value); -STORAGE_CLASS_INLINE hrt_data gdc_reg_load( +static inline hrt_data gdc_reg_load( const gdc_ID_t ID, const unsigned int reg); @@ -110,7 +110,7 @@ int gdc_get_unity( /* * Local function implementations */ -STORAGE_CLASS_INLINE void gdc_reg_store( +static inline void gdc_reg_store( const gdc_ID_t ID, const unsigned int reg, const hrt_data value) @@ -119,7 +119,7 @@ STORAGE_CLASS_INLINE void gdc_reg_store( return; } -STORAGE_CLASS_INLINE hrt_data gdc_reg_load( +static inline hrt_data gdc_reg_load( const gdc_ID_t ID, const unsigned int reg) { diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system.c index cd2096fa75c8..bd6821e436b2 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/input_system.c @@ -81,27 +81,27 @@ static input_system_error_t input_system_multiplexer_cfg( -STORAGE_CLASS_INLINE void capture_unit_get_state( +static inline void capture_unit_get_state( const input_system_ID_t ID, const sub_system_ID_t sub_id, capture_unit_state_t *state); -STORAGE_CLASS_INLINE void acquisition_unit_get_state( +static inline void acquisition_unit_get_state( const input_system_ID_t ID, const sub_system_ID_t sub_id, acquisition_unit_state_t *state); -STORAGE_CLASS_INLINE void ctrl_unit_get_state( +static inline void ctrl_unit_get_state( const input_system_ID_t ID, const sub_system_ID_t sub_id, ctrl_unit_state_t *state); -STORAGE_CLASS_INLINE void mipi_port_get_state( +static inline void mipi_port_get_state( const rx_ID_t ID, const mipi_port_ID_t port_ID, mipi_port_state_t *state); -STORAGE_CLASS_INLINE void rx_channel_get_state( +static inline void rx_channel_get_state( const rx_ID_t ID, const unsigned int ch_id, rx_channel_state_t *state); @@ -359,7 +359,7 @@ void receiver_irq_clear( return; } -STORAGE_CLASS_INLINE void capture_unit_get_state( +static inline void capture_unit_get_state( const input_system_ID_t ID, const sub_system_ID_t sub_id, capture_unit_state_t *state) @@ -421,7 +421,7 @@ STORAGE_CLASS_INLINE void capture_unit_get_state( return; } -STORAGE_CLASS_INLINE void acquisition_unit_get_state( +static inline void acquisition_unit_get_state( const input_system_ID_t ID, const sub_system_ID_t sub_id, acquisition_unit_state_t *state) @@ -471,7 +471,7 @@ STORAGE_CLASS_INLINE void acquisition_unit_get_state( return; } -STORAGE_CLASS_INLINE void ctrl_unit_get_state( +static inline void ctrl_unit_get_state( const input_system_ID_t ID, const sub_system_ID_t sub_id, ctrl_unit_state_t *state) @@ -554,7 +554,7 @@ STORAGE_CLASS_INLINE void ctrl_unit_get_state( return; } -STORAGE_CLASS_INLINE void mipi_port_get_state( +static inline void mipi_port_get_state( const rx_ID_t ID, const mipi_port_ID_t port_ID, mipi_port_state_t *state) @@ -590,7 +590,7 @@ STORAGE_CLASS_INLINE void mipi_port_get_state( return; } -STORAGE_CLASS_INLINE void rx_channel_get_state( +static inline void rx_channel_get_state( const rx_ID_t ID, const unsigned int ch_id, rx_channel_state_t *state) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/irq.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/irq.c index a42dad69cb3c..51daf76c2aea 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/irq.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/irq.c @@ -22,13 +22,13 @@ #include "platform_support.h" /* hrt_sleep() */ -STORAGE_CLASS_INLINE void irq_wait_for_write_complete( +static inline void irq_wait_for_write_complete( const irq_ID_t ID); -STORAGE_CLASS_INLINE bool any_irq_channel_enabled( +static inline bool any_irq_channel_enabled( const irq_ID_t ID); -STORAGE_CLASS_INLINE irq_ID_t virq_get_irq_id( +static inline irq_ID_t virq_get_irq_id( const virq_id_t irq_ID, unsigned int *channel_ID); @@ -406,7 +406,7 @@ enum hrt_isp_css_irq_status virq_get_channel_id( return status; } -STORAGE_CLASS_INLINE void irq_wait_for_write_complete( +static inline void irq_wait_for_write_complete( const irq_ID_t ID) { assert(ID < N_IRQ_ID); @@ -415,7 +415,7 @@ STORAGE_CLASS_INLINE void irq_wait_for_write_complete( _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX*sizeof(hrt_data)); } -STORAGE_CLASS_INLINE bool any_irq_channel_enabled( +static inline bool any_irq_channel_enabled( const irq_ID_t ID) { hrt_data en_reg; @@ -428,7 +428,7 @@ STORAGE_CLASS_INLINE bool any_irq_channel_enabled( return (en_reg != 0); } -STORAGE_CLASS_INLINE irq_ID_t virq_get_irq_id( +static inline irq_ID_t virq_get_irq_id( const virq_id_t irq_ID, unsigned int *channel_ID) { diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/assert_support.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/assert_support.h index 92fb15d04703..fd0d92e87c36 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/assert_support.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/assert_support.h @@ -15,7 +15,6 @@ #ifndef __ASSERT_SUPPORT_H_INCLUDED__ #define __ASSERT_SUPPORT_H_INCLUDED__ -#include "storage_class.h" /** * The following macro can help to test the size of a struct at compile @@ -92,7 +91,7 @@ * The implemenation for the pipe generation tool is in see support.isp.h */ #define OP___assert(cnd) assert(cnd) -STORAGE_CLASS_INLINE void compile_time_assert (unsigned cond) +static inline void compile_time_assert (unsigned cond) { /* Call undefined function if cond is false */ extern void _compile_time_assert (void); diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/bamem.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/bamem.h index d71e08f27a42..6928965cf513 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/bamem.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/bamem.h @@ -29,18 +29,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "bamem_local.h" #ifndef __INLINE_BAMEM__ -#define STORAGE_CLASS_BAMEM_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_BAMEM_H extern #define STORAGE_CLASS_BAMEM_C #include "bamem_public.h" #else /* __INLINE_BAMEM__ */ -#define STORAGE_CLASS_BAMEM_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_BAMEM_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_BAMEM_H static inline +#define STORAGE_CLASS_BAMEM_C static inline #include "bamem_private.h" #endif /* __INLINE_BAMEM__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/csi_rx.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/csi_rx.h index 0398f5802f05..917ee8cdb1d9 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/csi_rx.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/csi_rx.h @@ -30,18 +30,13 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "csi_rx_local.h" #ifndef __INLINE_CSI_RX__ -#define STORAGE_CLASS_CSI_RX_H STORAGE_CLASS_EXTERN -#define STORAGE_CLASS_CSI_RX_C #include "csi_rx_public.h" #else /* __INLINE_CSI_RX__ */ -#define STORAGE_CLASS_CSI_RX_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_CSI_RX_C STORAGE_CLASS_INLINE #include "csi_rx_private.h" #endif /* __INLINE_CSI_RX__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/debug.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/debug.h index 7d8011735033..0aa22446e27e 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/debug.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/debug.h @@ -30,18 +30,17 @@ * */ -#include "storage_class.h" #include "system_local.h" #include "debug_local.h" #ifndef __INLINE_DEBUG__ -#define STORAGE_CLASS_DEBUG_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_DEBUG_H extern #define STORAGE_CLASS_DEBUG_C #include "debug_public.h" #else /* __INLINE_DEBUG__ */ -#define STORAGE_CLASS_DEBUG_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_DEBUG_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_DEBUG_H static inline +#define STORAGE_CLASS_DEBUG_C static inline #include "debug_private.h" #endif /* __INLINE_DEBUG__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/dma.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/dma.h index b266191f21ef..d9dee691e3f8 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/dma.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/dma.h @@ -30,18 +30,17 @@ * */ -#include "storage_class.h" #include "system_local.h" #include "dma_local.h" #ifndef __INLINE_DMA__ -#define STORAGE_CLASS_DMA_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_DMA_H extern #define STORAGE_CLASS_DMA_C #include "dma_public.h" #else /* __INLINE_DMA__ */ -#define STORAGE_CLASS_DMA_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_DMA_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_DMA_H static inline +#define STORAGE_CLASS_DMA_C static inline #include "dma_private.h" #endif /* __INLINE_DMA__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/event_fifo.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/event_fifo.h index 78827c554cc3..df579e902796 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/event_fifo.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/event_fifo.h @@ -29,18 +29,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "event_fifo_local.h" #ifndef __INLINE_EVENT__ -#define STORAGE_CLASS_EVENT_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_EVENT_H extern #define STORAGE_CLASS_EVENT_C #include "event_fifo_public.h" #else /* __INLINE_EVENT__ */ -#define STORAGE_CLASS_EVENT_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_EVENT_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_EVENT_H static inline +#define STORAGE_CLASS_EVENT_C static inline #include "event_fifo_private.h" #endif /* __INLINE_EVENT__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/fifo_monitor.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/fifo_monitor.h index 3bdd260bcaa5..f10c4fa2e32b 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/fifo_monitor.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/fifo_monitor.h @@ -29,18 +29,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "fifo_monitor_local.h" #ifndef __INLINE_FIFO_MONITOR__ -#define STORAGE_CLASS_FIFO_MONITOR_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_FIFO_MONITOR_H extern #define STORAGE_CLASS_FIFO_MONITOR_C #include "fifo_monitor_public.h" #else /* __INLINE_FIFO_MONITOR__ */ -#define STORAGE_CLASS_FIFO_MONITOR_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_FIFO_MONITOR_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_FIFO_MONITOR_H static inline +#define STORAGE_CLASS_FIFO_MONITOR_C static inline #include "fifo_monitor_private.h" #endif /* __INLINE_FIFO_MONITOR__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/gdc_device.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/gdc_device.h index 016132ba0b7f..75c6854c8e7b 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/gdc_device.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/gdc_device.h @@ -31,18 +31,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "gdc_local.h" #ifndef __INLINE_GDC__ -#define STORAGE_CLASS_GDC_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_GDC_H extern #define STORAGE_CLASS_GDC_C #include "gdc_public.h" #else /* __INLINE_GDC__ */ -#define STORAGE_CLASS_GDC_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_GDC_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_GDC_H static inline +#define STORAGE_CLASS_GDC_C static inline #include "gdc_private.h" #endif /* __INLINE_GDC__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/gp_device.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/gp_device.h index 766d2532d8f9..aba94e623043 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/gp_device.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/gp_device.h @@ -29,18 +29,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "gp_device_local.h" #ifndef __INLINE_GP_DEVICE__ -#define STORAGE_CLASS_GP_DEVICE_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_GP_DEVICE_H extern #define STORAGE_CLASS_GP_DEVICE_C #include "gp_device_public.h" #else /* __INLINE_GP_DEVICE__ */ -#define STORAGE_CLASS_GP_DEVICE_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_GP_DEVICE_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_GP_DEVICE_H static inline +#define STORAGE_CLASS_GP_DEVICE_C static inline #include "gp_device_private.h" #endif /* __INLINE_GP_DEVICE__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/gp_timer.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/gp_timer.h index ca70f5603bf8..d5d2df24e11a 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/gp_timer.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/gp_timer.h @@ -29,18 +29,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" /*GP_TIMER_BASE address */ #include "gp_timer_local.h" /*GP_TIMER register offsets */ #ifndef __INLINE_GP_TIMER__ -#define STORAGE_CLASS_GP_TIMER_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_GP_TIMER_H extern #define STORAGE_CLASS_GP_TIMER_C #include "gp_timer_public.h" /* functions*/ #else /* __INLINE_GP_TIMER__ */ -#define STORAGE_CLASS_GP_TIMER_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_GP_TIMER_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_GP_TIMER_H static inline +#define STORAGE_CLASS_GP_TIMER_C static inline #include "gp_timer_private.h" /* inline functions*/ #endif /* __INLINE_GP_TIMER__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/gpio.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/gpio.h index dec21bcb6f47..d37f7166aa4a 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/gpio.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/gpio.h @@ -29,18 +29,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "gpio_local.h" #ifndef __INLINE_GPIO__ -#define STORAGE_CLASS_GPIO_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_GPIO_H extern #define STORAGE_CLASS_GPIO_C #include "gpio_public.h" #else /* __INLINE_GPIO__ */ -#define STORAGE_CLASS_GPIO_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_GPIO_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_GPIO_H static inline +#define STORAGE_CLASS_GPIO_C static inline #include "gpio_private.h" #endif /* __INLINE_GPIO__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/hmem.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/hmem.h index 671dd5b5fca6..a82fd3a21e98 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/hmem.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/hmem.h @@ -29,18 +29,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "hmem_local.h" #ifndef __INLINE_HMEM__ -#define STORAGE_CLASS_HMEM_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_HMEM_H extern #define STORAGE_CLASS_HMEM_C #include "hmem_public.h" #else /* __INLINE_HMEM__ */ -#define STORAGE_CLASS_HMEM_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_HMEM_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_HMEM_H static inline +#define STORAGE_CLASS_HMEM_C static inline #include "hmem_private.h" #endif /* __INLINE_HMEM__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/csi_rx_public.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/csi_rx_public.h index 396240954bed..3b5df85fc510 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/csi_rx_public.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/csi_rx_public.h @@ -28,7 +28,7 @@ * @param[in] id The global unique ID of the csi rx fe controller. * @param[out] state Point to the register-state. */ -STORAGE_CLASS_CSI_RX_H void csi_rx_fe_ctrl_get_state( +extern void csi_rx_fe_ctrl_get_state( const csi_rx_frontend_ID_t ID, csi_rx_fe_ctrl_state_t *state); /** @@ -38,7 +38,7 @@ STORAGE_CLASS_CSI_RX_H void csi_rx_fe_ctrl_get_state( * @param[in] id The global unique ID of the csi rx fe controller. * @param[in] state Point to the register-state. */ -STORAGE_CLASS_CSI_RX_H void csi_rx_fe_ctrl_dump_state( +extern void csi_rx_fe_ctrl_dump_state( const csi_rx_frontend_ID_t ID, csi_rx_fe_ctrl_state_t *state); /** @@ -49,7 +49,7 @@ STORAGE_CLASS_CSI_RX_H void csi_rx_fe_ctrl_dump_state( * @param[in] lane The lane ID. * @param[out] state Point to the dlane state. */ -STORAGE_CLASS_CSI_RX_H void csi_rx_fe_ctrl_get_dlane_state( +extern void csi_rx_fe_ctrl_get_dlane_state( const csi_rx_frontend_ID_t ID, const uint32_t lane, csi_rx_fe_ctrl_lane_t *dlane_state); @@ -60,7 +60,7 @@ STORAGE_CLASS_CSI_RX_H void csi_rx_fe_ctrl_get_dlane_state( * @param[in] id The global unique ID of the csi rx be controller. * @param[out] state Point to the register-state. */ -STORAGE_CLASS_CSI_RX_H void csi_rx_be_ctrl_get_state( +extern void csi_rx_be_ctrl_get_state( const csi_rx_backend_ID_t ID, csi_rx_be_ctrl_state_t *state); /** @@ -70,7 +70,7 @@ STORAGE_CLASS_CSI_RX_H void csi_rx_be_ctrl_get_state( * @param[in] id The global unique ID of the csi rx be controller. * @param[in] state Point to the register-state. */ -STORAGE_CLASS_CSI_RX_H void csi_rx_be_ctrl_dump_state( +extern void csi_rx_be_ctrl_dump_state( const csi_rx_backend_ID_t ID, csi_rx_be_ctrl_state_t *state); /** end of NCI */ @@ -89,7 +89,7 @@ STORAGE_CLASS_CSI_RX_H void csi_rx_be_ctrl_dump_state( * * @return the value of the register. */ -STORAGE_CLASS_CSI_RX_H hrt_data csi_rx_fe_ctrl_reg_load( +extern hrt_data csi_rx_fe_ctrl_reg_load( const csi_rx_frontend_ID_t ID, const hrt_address reg); /** @@ -101,7 +101,7 @@ STORAGE_CLASS_CSI_RX_H hrt_data csi_rx_fe_ctrl_reg_load( * @param[in] value The value to be stored. * */ -STORAGE_CLASS_CSI_RX_H void csi_rx_fe_ctrl_reg_store( +extern void csi_rx_fe_ctrl_reg_store( const csi_rx_frontend_ID_t ID, const hrt_address reg, const hrt_data value); @@ -114,7 +114,7 @@ STORAGE_CLASS_CSI_RX_H void csi_rx_fe_ctrl_reg_store( * * @return the value of the register. */ -STORAGE_CLASS_CSI_RX_H hrt_data csi_rx_be_ctrl_reg_load( +extern hrt_data csi_rx_be_ctrl_reg_load( const csi_rx_backend_ID_t ID, const hrt_address reg); /** @@ -126,7 +126,7 @@ STORAGE_CLASS_CSI_RX_H hrt_data csi_rx_be_ctrl_reg_load( * @param[in] value The value to be stored. * */ -STORAGE_CLASS_CSI_RX_H void csi_rx_be_ctrl_reg_store( +extern void csi_rx_be_ctrl_reg_store( const csi_rx_backend_ID_t ID, const hrt_address reg, const hrt_data value); diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/gdc_public.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/gdc_public.h index d27f87a719db..d09d1e320306 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/gdc_public.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/gdc_public.h @@ -33,7 +33,7 @@ \return none, GDC[ID].lut[0...3][0...HRT_GDC_N-1] = data */ -STORAGE_CLASS_EXTERN void gdc_lut_store( +extern void gdc_lut_store( const gdc_ID_t ID, const int data[4][HRT_GDC_N]); @@ -43,7 +43,7 @@ STORAGE_CLASS_EXTERN void gdc_lut_store( \param in_lut[in] The data matrix to be converted \param out_lut[out] The data matrix as the output of conversion */ -STORAGE_CLASS_EXTERN void gdc_lut_convert_to_isp_format( +extern void gdc_lut_convert_to_isp_format( const int in_lut[4][HRT_GDC_N], int out_lut[4][HRT_GDC_N]); @@ -53,7 +53,7 @@ STORAGE_CLASS_EXTERN void gdc_lut_convert_to_isp_format( \return unity */ -STORAGE_CLASS_EXTERN int gdc_get_unity( +extern int gdc_get_unity( const gdc_ID_t ID); #endif /* __GDC_PUBLIC_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op1w.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op1w.h index 2251f372145b..a025ad562bd2 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op1w.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op1w.h @@ -27,14 +27,13 @@ * Prerequisites: * */ -#include "storage_class.h" #ifdef INLINE_ISP_OP1W -#define STORAGE_CLASS_ISP_OP1W_FUNC_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_ISP_OP1W_DATA_H STORAGE_CLASS_INLINE_DATA +#define STORAGE_CLASS_ISP_OP1W_FUNC_H static inline +#define STORAGE_CLASS_ISP_OP1W_DATA_H static inline_DATA #else /* INLINE_ISP_OP1W */ -#define STORAGE_CLASS_ISP_OP1W_FUNC_H STORAGE_CLASS_EXTERN -#define STORAGE_CLASS_ISP_OP1W_DATA_H STORAGE_CLASS_EXTERN_DATA +#define STORAGE_CLASS_ISP_OP1W_FUNC_H extern +#define STORAGE_CLASS_ISP_OP1W_DATA_H extern_DATA #endif /* INLINE_ISP_OP1W */ /* diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op2w.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op2w.h index 1cfe6d717283..cf7e7314842d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op2w.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/isp_op2w.h @@ -27,14 +27,13 @@ * Prerequisites: * */ -#include "storage_class.h" #ifdef INLINE_ISP_OP2W -#define STORAGE_CLASS_ISP_OP2W_FUNC_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_ISP_OP2W_DATA_H STORAGE_CLASS_INLINE_DATA +#define STORAGE_CLASS_ISP_OP2W_FUNC_H static inline +#define STORAGE_CLASS_ISP_OP2W_DATA_H static inline_DATA #else /* INLINE_ISP_OP2W */ -#define STORAGE_CLASS_ISP_OP2W_FUNC_H STORAGE_CLASS_EXTERN -#define STORAGE_CLASS_ISP_OP2W_DATA_H STORAGE_CLASS_EXTERN_DATA +#define STORAGE_CLASS_ISP_OP2W_FUNC_H extern +#define STORAGE_CLASS_ISP_OP2W_DATA_H extern_DATA #endif /* INLINE_ISP_OP2W */ /* diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/mmu_public.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/mmu_public.h index 4258fa872087..0a13eda73607 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/mmu_public.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/mmu_public.h @@ -24,7 +24,7 @@ \return none, MMU[ID].page_table_base_index = base_index */ -STORAGE_CLASS_EXTERN void mmu_set_page_table_base_index( +extern void mmu_set_page_table_base_index( const mmu_ID_t ID, const hrt_data base_index); @@ -35,7 +35,7 @@ STORAGE_CLASS_EXTERN void mmu_set_page_table_base_index( \return MMU[ID].page_table_base_index */ -STORAGE_CLASS_EXTERN hrt_data mmu_get_page_table_base_index( +extern hrt_data mmu_get_page_table_base_index( const mmu_ID_t ID); /*! Invalidate the page table cache of MMU[ID] @@ -44,7 +44,7 @@ STORAGE_CLASS_EXTERN hrt_data mmu_get_page_table_base_index( \return none */ -STORAGE_CLASS_EXTERN void mmu_invalidate_cache( +extern void mmu_invalidate_cache( const mmu_ID_t ID); @@ -52,7 +52,7 @@ STORAGE_CLASS_EXTERN void mmu_invalidate_cache( \return none */ -STORAGE_CLASS_EXTERN void mmu_invalidate_cache_all(void); +extern void mmu_invalidate_cache_all(void); /*! Write to a control register of MMU[ID] diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/ref_vector_func.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/ref_vector_func.h index 3e955fca2a94..a202d6dce106 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/ref_vector_func.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/host/ref_vector_func.h @@ -15,14 +15,13 @@ #ifndef _REF_VECTOR_FUNC_H_INCLUDED_ #define _REF_VECTOR_FUNC_H_INCLUDED_ -#include "storage_class.h" #ifdef INLINE_VECTOR_FUNC -#define STORAGE_CLASS_REF_VECTOR_FUNC_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_REF_VECTOR_DATA_H STORAGE_CLASS_INLINE_DATA +#define STORAGE_CLASS_REF_VECTOR_FUNC_H static inline +#define STORAGE_CLASS_REF_VECTOR_DATA_H static inline_DATA #else /* INLINE_VECTOR_FUNC */ -#define STORAGE_CLASS_REF_VECTOR_FUNC_H STORAGE_CLASS_EXTERN -#define STORAGE_CLASS_REF_VECTOR_DATA_H STORAGE_CLASS_EXTERN_DATA +#define STORAGE_CLASS_REF_VECTOR_FUNC_H extern +#define STORAGE_CLASS_REF_VECTOR_DATA_H extern_DATA #endif /* INLINE_VECTOR_FUNC */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/ibuf_ctrl.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/ibuf_ctrl.h index f5de0df7981e..c7d9095472b1 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/ibuf_ctrl.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/ibuf_ctrl.h @@ -31,18 +31,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "ibuf_ctrl_local.h" #ifndef __INLINE_IBUF_CTRL__ -#define STORAGE_CLASS_IBUF_CTRL_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_IBUF_CTRL_H extern #define STORAGE_CLASS_IBUF_CTRL_C #include "ibuf_ctrl_public.h" #else /* __INLINE_IBUF_CTRL__ */ -#define STORAGE_CLASS_IBUF_CTRL_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_IBUF_CTRL_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_IBUF_CTRL_H static inline +#define STORAGE_CLASS_IBUF_CTRL_C static inline #include "ibuf_ctrl_private.h" #endif /* __INLINE_IBUF_CTRL__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/input_formatter.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/input_formatter.h index 041c8b660aa4..eeaaecdd57ba 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/input_formatter.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/input_formatter.h @@ -29,18 +29,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "input_formatter_local.h" #ifndef __INLINE_INPUT_FORMATTER__ -#define STORAGE_CLASS_INPUT_FORMATTER_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_INPUT_FORMATTER_H extern #define STORAGE_CLASS_INPUT_FORMATTER_C #include "input_formatter_public.h" #else /* __INLINE_INPUT_FORMATTER__ */ -#define STORAGE_CLASS_INPUT_FORMATTER_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_INPUT_FORMATTER_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_INPUT_FORMATTER_H static inline +#define STORAGE_CLASS_INPUT_FORMATTER_C static inline #include "input_formatter_private.h" #endif /* __INLINE_INPUT_FORMATTER__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/input_system.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/input_system.h index 182867367b48..3f02d9ec9588 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/input_system.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/input_system.h @@ -29,18 +29,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "input_system_local.h" #ifndef __INLINE_INPUT_SYSTEM__ -#define STORAGE_CLASS_INPUT_SYSTEM_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_INPUT_SYSTEM_H extern #define STORAGE_CLASS_INPUT_SYSTEM_C #include "input_system_public.h" #else /* __INLINE_INPUT_SYSTEM__ */ -#define STORAGE_CLASS_INPUT_SYSTEM_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_INPUT_SYSTEM_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_INPUT_SYSTEM_H static inline +#define STORAGE_CLASS_INPUT_SYSTEM_C static inline #include "input_system_private.h" #endif /* __INLINE_INPUT_SYSTEM__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/irq.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/irq.h index 1dc443892cc5..e1446388dee5 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/irq.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/irq.h @@ -29,18 +29,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "irq_local.h" #ifndef __INLINE_IRQ__ -#define STORAGE_CLASS_IRQ_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_IRQ_H extern #define STORAGE_CLASS_IRQ_C #include "irq_public.h" #else /* __INLINE_IRQ__ */ -#define STORAGE_CLASS_IRQ_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_IRQ_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_IRQ_H static inline +#define STORAGE_CLASS_IRQ_C static inline #include "irq_private.h" #endif /* __INLINE_IRQ__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/isp.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/isp.h index 49190d0abc30..b916953e7f47 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/isp.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/isp.h @@ -29,18 +29,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "isp_local.h" #ifndef __INLINE_ISP__ -#define STORAGE_CLASS_ISP_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_ISP_H extern #define STORAGE_CLASS_ISP_C #include "isp_public.h" #else /* __INLINE_iSP__ */ -#define STORAGE_CLASS_ISP_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_ISP_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_ISP_H static inline +#define STORAGE_CLASS_ISP_C static inline #include "isp_private.h" #endif /* __INLINE_ISP__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/isys_dma.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/isys_dma.h index 9a608f07adcb..76aba114a5c1 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/isys_dma.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/isys_dma.h @@ -31,18 +31,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "isys_dma_local.h" #ifndef __INLINE_ISYS2401_DMA__ -#define STORAGE_CLASS_ISYS2401_DMA_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_ISYS2401_DMA_H extern #define STORAGE_CLASS_ISYS2401_DMA_C #include "isys_dma_public.h" #else /* __INLINE_ISYS2401_DMA__ */ -#define STORAGE_CLASS_ISYS2401_DMA_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_ISYS2401_DMA_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_ISYS2401_DMA_H static inline +#define STORAGE_CLASS_ISYS2401_DMA_C static inline #include "isys_dma_private.h" #endif /* __INLINE_ISYS2401_DMA__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/isys_irq.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/isys_irq.h index cf858bcc8e45..d3f64cfd0b7d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/isys_irq.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/isys_irq.h @@ -16,21 +16,20 @@ #define __IA_CSS_ISYS_IRQ_H__ #include -#include #include #if defined(USE_INPUT_SYSTEM_VERSION_2401) #ifndef __INLINE_ISYS2401_IRQ__ -#define STORAGE_CLASS_ISYS2401_IRQ_H STORAGE_CLASS_EXTERN -#define STORAGE_CLASS_ISYS2401_IRQ_C STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_ISYS2401_IRQ_H extern +#define STORAGE_CLASS_ISYS2401_IRQ_C extern #include "isys_irq_public.h" #else /* __INLINE_ISYS2401_IRQ__ */ -#define STORAGE_CLASS_ISYS2401_IRQ_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_ISYS2401_IRQ_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_ISYS2401_IRQ_H static inline +#define STORAGE_CLASS_ISYS2401_IRQ_C static inline #include "isys_irq_private.h" #endif /* __INLINE_ISYS2401_IRQ__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/isys_stream2mmio.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/isys_stream2mmio.h index 3e8cfe555ad5..16fbf9d25eba 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/isys_stream2mmio.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/isys_stream2mmio.h @@ -31,18 +31,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "isys_stream2mmio_local.h" #ifndef __INLINE_STREAM2MMIO__ -#define STORAGE_CLASS_STREAM2MMIO_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_STREAM2MMIO_H extern #define STORAGE_CLASS_STREAM2MMIO_C #include "isys_stream2mmio_public.h" #else /* __INLINE_STREAM2MMIO__ */ -#define STORAGE_CLASS_STREAM2MMIO_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_STREAM2MMIO_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_STREAM2MMIO_H static inline +#define STORAGE_CLASS_STREAM2MMIO_C static inline #include "isys_stream2mmio_private.h" #endif /* __INLINE_STREAM2MMIO__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/math_support.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/math_support.h index f74b405b0f39..e85e5c889c15 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/math_support.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/math_support.h @@ -15,7 +15,6 @@ #ifndef __MATH_SUPPORT_H #define __MATH_SUPPORT_H -#include "storage_class.h" /* for STORAGE_CLASS_INLINE */ #if defined(__KERNEL__) #include /* Override the definition of max/min from linux kernel*/ #endif /*__KERNEL__*/ @@ -110,60 +109,60 @@ Leaving out the other math utility functions as they are newly added #else /* !defined(INLINE_MATH_SUPPORT_UTILS) */ -STORAGE_CLASS_INLINE int max(int a, int b) +static inline int max(int a, int b) { return MAX(a, b); } -STORAGE_CLASS_INLINE int min(int a, int b) +static inline int min(int a, int b) { return MIN(a, b); } -STORAGE_CLASS_INLINE unsigned int ceil_div(unsigned int a, unsigned int b) +static inline unsigned int ceil_div(unsigned int a, unsigned int b) { return CEIL_DIV(a, b); } #endif /* !defined(INLINE_MATH_SUPPORT_UTILS) */ -STORAGE_CLASS_INLINE unsigned int umax(unsigned int a, unsigned int b) +static inline unsigned int umax(unsigned int a, unsigned int b) { return MAX(a, b); } -STORAGE_CLASS_INLINE unsigned int umin(unsigned int a, unsigned int b) +static inline unsigned int umin(unsigned int a, unsigned int b) { return MIN(a, b); } -STORAGE_CLASS_INLINE unsigned int ceil_mul(unsigned int a, unsigned int b) +static inline unsigned int ceil_mul(unsigned int a, unsigned int b) { return CEIL_MUL(a, b); } -STORAGE_CLASS_INLINE unsigned int ceil_mul2(unsigned int a, unsigned int b) +static inline unsigned int ceil_mul2(unsigned int a, unsigned int b) { return CEIL_MUL2(a, b); } -STORAGE_CLASS_INLINE unsigned int ceil_shift(unsigned int a, unsigned int b) +static inline unsigned int ceil_shift(unsigned int a, unsigned int b) { return CEIL_SHIFT(a, b); } -STORAGE_CLASS_INLINE unsigned int ceil_shift_mul(unsigned int a, unsigned int b) +static inline unsigned int ceil_shift_mul(unsigned int a, unsigned int b) { return CEIL_SHIFT_MUL(a, b); } #ifdef ISP2401 -STORAGE_CLASS_INLINE unsigned int round_half_down_div(unsigned int a, unsigned int b) +static inline unsigned int round_half_down_div(unsigned int a, unsigned int b) { return ROUND_HALF_DOWN_DIV(a, b); } -STORAGE_CLASS_INLINE unsigned int round_half_down_mul(unsigned int a, unsigned int b) +static inline unsigned int round_half_down_mul(unsigned int a, unsigned int b) { return ROUND_HALF_DOWN_MUL(a, b); } @@ -187,7 +186,7 @@ STORAGE_CLASS_INLINE unsigned int round_half_down_mul(unsigned int a, unsigned i * */ -STORAGE_CLASS_INLINE unsigned int ceil_pow2(unsigned int a) +static inline unsigned int ceil_pow2(unsigned int a) { if (a == 0) { return 1; diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/mmu_device.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/mmu_device.h index 1b2017b029f2..519e850ec390 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/mmu_device.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/mmu_device.h @@ -31,18 +31,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "mmu_local.h" #ifndef __INLINE_MMU__ -#define STORAGE_CLASS_MMU_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_MMU_H extern #define STORAGE_CLASS_MMU_C #include "mmu_public.h" #else /* __INLINE_MMU__ */ -#define STORAGE_CLASS_MMU_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_MMU_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_MMU_H static inline +#define STORAGE_CLASS_MMU_C static inline #include "mmu_private.h" #endif /* __INLINE_MMU__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/mpmath.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/mpmath.h index 565983aafa4d..cd938375e02e 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/mpmath.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/mpmath.h @@ -15,14 +15,13 @@ #ifndef __MPMATH_H_INCLUDED__ #define __MPMATH_H_INCLUDED__ -#include "storage_class.h" #ifdef INLINE_MPMATH -#define STORAGE_CLASS_MPMATH_FUNC_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_MPMATH_DATA_H STORAGE_CLASS_INLINE_DATA +#define STORAGE_CLASS_MPMATH_FUNC_H static inline +#define STORAGE_CLASS_MPMATH_DATA_H static inline_DATA #else /* INLINE_MPMATH */ -#define STORAGE_CLASS_MPMATH_FUNC_H STORAGE_CLASS_EXTERN -#define STORAGE_CLASS_MPMATH_DATA_H STORAGE_CLASS_EXTERN_DATA +#define STORAGE_CLASS_MPMATH_FUNC_H extern +#define STORAGE_CLASS_MPMATH_DATA_H extern_DATA #endif /* INLINE_MPMATH */ #include diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/osys.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/osys.h index 6e48ea9afc29..a607242c5f1a 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/osys.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/osys.h @@ -30,18 +30,17 @@ * */ -#include "storage_class.h" #include "system_local.h" #include "osys_local.h" #ifndef __INLINE_OSYS__ -#define STORAGE_CLASS_OSYS_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_OSYS_H extern #define STORAGE_CLASS_OSYS_C #include "osys_public.h" #else /* __INLINE_OSYS__ */ -#define STORAGE_CLASS_OSYS_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_OSYS_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_OSYS_H static inline +#define STORAGE_CLASS_OSYS_C static inline #include "osys_private.h" #endif /* __INLINE_OSYS__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/pixelgen.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/pixelgen.h index 67f7f3a14231..418d02382d76 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/pixelgen.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/pixelgen.h @@ -31,18 +31,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "pixelgen_local.h" #ifndef __INLINE_PIXELGEN__ -#define STORAGE_CLASS_PIXELGEN_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_PIXELGEN_H extern #define STORAGE_CLASS_PIXELGEN_C #include "pixelgen_public.h" #else /* __INLINE_PIXELGEN__ */ -#define STORAGE_CLASS_PIXELGEN_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_PIXELGEN_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_PIXELGEN_H static inline +#define STORAGE_CLASS_PIXELGEN_C static inline #include "pixelgen_private.h" #endif /* __INLINE_PIXELGEN__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/platform_support.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/platform_support.h index 02f9eee67ff3..39a125ba563d 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/platform_support.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/platform_support.h @@ -20,7 +20,6 @@ * Platform specific includes and functionality. */ -#include "storage_class.h" #include #include #include diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/print_support.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/print_support.h index cfbc222ea0c1..ca0fbbb57788 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/print_support.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/print_support.h @@ -15,7 +15,6 @@ #ifndef __PRINT_SUPPORT_H_INCLUDED__ #define __PRINT_SUPPORT_H_INCLUDED__ -#include "storage_class.h" #include #if !defined(__KERNEL__) @@ -24,7 +23,7 @@ extern int (*sh_css_printf) (const char *fmt, va_list args); /* depends on host supplied print function in ia_css_init() */ -STORAGE_CLASS_INLINE void ia_css_print(const char *fmt, ...) +static inline void ia_css_print(const char *fmt, ...) { va_list ap; if (sh_css_printf) { diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/queue.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/queue.h index a3d874b9516a..aa5fadf5aadb 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/queue.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/queue.h @@ -29,18 +29,17 @@ * */ -#include #include "queue_local.h" #ifndef __INLINE_QUEUE__ -#define STORAGE_CLASS_QUEUE_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_QUEUE_H extern #define STORAGE_CLASS_QUEUE_C /* #include "queue_public.h" */ #include "ia_css_queue.h" #else /* __INLINE_QUEUE__ */ -#define STORAGE_CLASS_QUEUE_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_QUEUE_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_QUEUE_H static inline +#define STORAGE_CLASS_QUEUE_C static inline #include "queue_private.h" #endif /* __INLINE_QUEUE__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/resource.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/resource.h index 82c55acd0380..bd9f53e6b680 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/resource.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/resource.h @@ -30,18 +30,17 @@ * */ -#include "storage_class.h" #include "system_local.h" #include "resource_local.h" #ifndef __INLINE_RESOURCE__ -#define STORAGE_CLASS_RESOURCE_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_RESOURCE_H extern #define STORAGE_CLASS_RESOURCE_C #include "resource_public.h" #else /* __INLINE_RESOURCE__ */ -#define STORAGE_CLASS_RESOURCE_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_RESOURCE_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_RESOURCE_H static inline +#define STORAGE_CLASS_RESOURCE_C static inline #include "resource_private.h" #endif /* __INLINE_RESOURCE__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/socket.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/socket.h index c34c2e75c51f..43cfb0cb4aa8 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/socket.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/socket.h @@ -30,18 +30,17 @@ * */ -#include "storage_class.h" #include "system_local.h" #include "socket_local.h" #ifndef __INLINE_SOCKET__ -#define STORAGE_CLASS_SOCKET_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_SOCKET_H extern #define STORAGE_CLASS_SOCKET_C #include "socket_public.h" #else /* __INLINE_SOCKET__ */ -#define STORAGE_CLASS_SOCKET_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_SOCKET_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_SOCKET_H static inline +#define STORAGE_CLASS_SOCKET_C static inline #include "socket_private.h" #endif /* __INLINE_SOCKET__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/sp.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/sp.h index 150fc2f6129b..8f57f2060791 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/sp.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/sp.h @@ -29,18 +29,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "sp_local.h" #ifndef __INLINE_SP__ -#define STORAGE_CLASS_SP_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_SP_H extern #define STORAGE_CLASS_SP_C #include "sp_public.h" #else /* __INLINE_SP__ */ -#define STORAGE_CLASS_SP_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_SP_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_SP_H static inline +#define STORAGE_CLASS_SP_C static inline #include "sp_private.h" #endif /* __INLINE_SP__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/storage_class.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/storage_class.h deleted file mode 100644 index 3908e668dacd..000000000000 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/storage_class.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Support for Intel Camera Imaging ISP subsystem. - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#ifndef __STORAGE_CLASS_H_INCLUDED__ -#define __STORAGE_CLASS_H_INCLUDED__ - -/** -* @file -* Platform specific includes and functionality. -*/ - -#define STORAGE_CLASS_EXTERN extern - -#if defined(_MSC_VER) -#define STORAGE_CLASS_INLINE static __inline -#else -#define STORAGE_CLASS_INLINE static inline -#endif - -#define STORAGE_CLASS_EXTERN_DATA extern const -#define STORAGE_CLASS_INLINE_DATA static const - -#endif /* __STORAGE_CLASS_H_INCLUDED__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/stream_buffer.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/stream_buffer.h index 8e41f60b5d39..53d535e4f2ae 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/stream_buffer.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/stream_buffer.h @@ -30,18 +30,17 @@ * */ -#include "storage_class.h" #include "system_local.h" #include "stream_buffer_local.h" #ifndef __INLINE_STREAM_BUFFER__ -#define STORAGE_CLASS_STREAM_BUFFER_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_STREAM_BUFFER_H extern #define STORAGE_CLASS_STREAM_BUFFER_C #include "stream_buffer_public.h" #else /* __INLINE_STREAM_BUFFER__ */ -#define STORAGE_CLASS_STREAM_BUFFER_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_STREAM_BUFFER_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_STREAM_BUFFER_H static inline +#define STORAGE_CLASS_STREAM_BUFFER_C static inline #include "stream_buffer_private.h" #endif /* __INLINE_STREAM_BUFFER__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/string_support.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/string_support.h index c53241a7a281..d80437c58bde 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/string_support.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/string_support.h @@ -16,7 +16,6 @@ #define __STRING_SUPPORT_H_INCLUDED__ #include #include -#include #if !defined(_MSC_VER) /* @@ -34,7 +33,7 @@ * @return EINVAL on Invalid arguments * @return ERANGE on Destination size too small */ -STORAGE_CLASS_INLINE int memcpy_s( +static inline int memcpy_s( void* dest_buf, size_t dest_size, const void* src_buf, @@ -89,7 +88,7 @@ static size_t strnlen_s( * @return Returns EINVAL on invalid arguments * @return Returns ERANGE on destination size too small */ -STORAGE_CLASS_INLINE int strncpy_s( +static inline int strncpy_s( char* dest_str, size_t dest_size, const char* src_str, @@ -130,7 +129,7 @@ STORAGE_CLASS_INLINE int strncpy_s( * @return Returns EINVAL on invalid arguments * @return Returns ERANGE on destination size too small */ -STORAGE_CLASS_INLINE int strcpy_s( +static inline int strcpy_s( char* dest_str, size_t dest_size, const char* src_str) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/tag.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/tag.h index 7385fd11c95f..ace695643369 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/tag.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/tag.h @@ -29,17 +29,16 @@ * */ -#include "storage_class.h" #include "tag_local.h" #ifndef __INLINE_TAG__ -#define STORAGE_CLASS_TAG_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_TAG_H extern #define STORAGE_CLASS_TAG_C #include "tag_public.h" #else /* __INLINE_TAG__ */ -#define STORAGE_CLASS_TAG_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_TAG_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_TAG_H static inline +#define STORAGE_CLASS_TAG_C static inline #include "tag_private.h" #endif /* __INLINE_TAG__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/timed_ctrl.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/timed_ctrl.h index ed13451c9261..f6bc1c47553f 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/timed_ctrl.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/timed_ctrl.h @@ -29,18 +29,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "timed_ctrl_local.h" #ifndef __INLINE_TIMED_CTRL__ -#define STORAGE_CLASS_TIMED_CTRL_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_TIMED_CTRL_H extern #define STORAGE_CLASS_TIMED_CTRL_C #include "timed_ctrl_public.h" #else /* __INLINE_TIMED_CTRL__ */ -#define STORAGE_CLASS_TIMED_CTRL_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_TIMED_CTRL_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_TIMED_CTRL_H static inline +#define STORAGE_CLASS_TIMED_CTRL_C static inline #include "timed_ctrl_private.h" #endif /* __INLINE_TIMED_CTRL__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vamem.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vamem.h index acf932e1f563..82d447bf9704 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vamem.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vamem.h @@ -29,18 +29,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "vamem_local.h" #ifndef __INLINE_VAMEM__ -#define STORAGE_CLASS_VAMEM_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_VAMEM_H extern #define STORAGE_CLASS_VAMEM_C #include "vamem_public.h" #else /* __INLINE_VAMEM__ */ -#define STORAGE_CLASS_VAMEM_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_VAMEM_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_VAMEM_H static inline +#define STORAGE_CLASS_VAMEM_C static inline #include "vamem_private.h" #endif /* __INLINE_VAMEM__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_func.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_func.h index 5d3be31759e4..5368b9062897 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_func.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_func.h @@ -15,7 +15,6 @@ #ifndef __VECTOR_FUNC_H_INCLUDED__ #define __VECTOR_FUNC_H_INCLUDED__ -#include "storage_class.h" /* TODO: Later filters will be moved to types directory, * and we should only include matrix_MxN types */ @@ -27,12 +26,12 @@ #include "vector_func_local.h" #ifndef __INLINE_VECTOR_FUNC__ -#define STORAGE_CLASS_VECTOR_FUNC_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_VECTOR_FUNC_H extern #define STORAGE_CLASS_VECTOR_FUNC_C #include "vector_func_public.h" #else /* __INLINE_VECTOR_FUNC__ */ -#define STORAGE_CLASS_VECTOR_FUNC_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_VECTOR_FUNC_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_VECTOR_FUNC_H static inline +#define STORAGE_CLASS_VECTOR_FUNC_C static inline #include "vector_func_private.h" #endif /* __INLINE_VECTOR_FUNC__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_ops.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_ops.h index 261f87378ce5..4923f2d5518b 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_ops.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vector_ops.h @@ -15,17 +15,16 @@ #ifndef __VECTOR_OPS_H_INCLUDED__ #define __VECTOR_OPS_H_INCLUDED__ -#include "storage_class.h" #include "vector_ops_local.h" #ifndef __INLINE_VECTOR_OPS__ -#define STORAGE_CLASS_VECTOR_OPS_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_VECTOR_OPS_H extern #define STORAGE_CLASS_VECTOR_OPS_C #include "vector_ops_public.h" #else /* __INLINE_VECTOR_OPS__ */ -#define STORAGE_CLASS_VECTOR_OPS_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_VECTOR_OPS_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_VECTOR_OPS_H static inline +#define STORAGE_CLASS_VECTOR_OPS_C static inline #include "vector_ops_private.h" #endif /* __INLINE_VECTOR_OPS__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vmem.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vmem.h index 79a36755bfd9..d3375729c441 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vmem.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/vmem.h @@ -29,18 +29,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "vmem_local.h" #ifndef __INLINE_VMEM__ -#define STORAGE_CLASS_VMEM_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_VMEM_H extern #define STORAGE_CLASS_VMEM_C #include "vmem_public.h" #else /* __INLINE_VMEM__ */ -#define STORAGE_CLASS_VMEM_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_VMEM_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_VMEM_H static inline +#define STORAGE_CLASS_VMEM_C static inline #include "vmem_private.h" #endif /* __INLINE_VMEM__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/xmem.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/xmem.h index 9169e04f9b4b..13083fe55141 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/xmem.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_include/xmem.h @@ -29,18 +29,17 @@ * - local: system and cell specific constants and identifiers */ -#include "storage_class.h" #include "system_local.h" #include "xmem_local.h" #ifndef __INLINE_XMEM__ -#define STORAGE_CLASS_XMEM_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_XMEM_H extern #define STORAGE_CLASS_XMEM_C #include "xmem_public.h" #else /* __INLINE_XMEM__ */ -#define STORAGE_CLASS_XMEM_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_XMEM_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_XMEM_H static inline +#define STORAGE_CLASS_XMEM_C static inline #include "xmem_private.h" #endif /* __INLINE_XMEM__ */ diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a/s3a_1.0/ia_css_s3a.host.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a/s3a_1.0/ia_css_s3a.host.c index 8ef6c54ee813..aa733674f42b 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a/s3a_1.0/ia_css_s3a.host.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/isp/kernels/s3a/s3a_1.0/ia_css_s3a.host.c @@ -321,7 +321,7 @@ ia_css_s3a_dmem_decode( } /* MW: this is an ISP function */ -STORAGE_CLASS_INLINE int +static inline int merge_hi_lo_14(unsigned short hi, unsigned short lo) { int val = (int) ((((unsigned int) hi << 14) & 0xfffc000) | diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/bufq/src/bufq.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/bufq/src/bufq.c index 5d40afd482f5..42d9a8508858 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/bufq/src/bufq.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/bufq/src/bufq.c @@ -280,7 +280,7 @@ static ia_css_queue_t *bufq_get_qhandle( /* Local function to initialize a buffer queue. This reduces * the chances of copy-paste errors or typos. */ -STORAGE_CLASS_INLINE void +static inline void init_bufq(unsigned int desc_offset, unsigned int elems_offset, ia_css_queue_t *handle) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/debug/interface/ia_css_debug.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/debug/interface/ia_css_debug.h index 91c105cc6204..3c8dcfd4bbc6 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/debug/interface/ia_css_debug.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/debug/interface/ia_css_debug.h @@ -130,7 +130,7 @@ enum ia_css_debug_enable_param_dump { * @param[in] fmt printf like format string * @param[in] args arguments for the format string */ -STORAGE_CLASS_INLINE void +static inline void ia_css_debug_vdtrace(unsigned int level, const char *fmt, va_list args) { if (ia_css_debug_trace_level >= level) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/inputfifo/src/inputfifo.c b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/inputfifo/src/inputfifo.c index cf02970d4f59..d9a5f3e9283a 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/inputfifo/src/inputfifo.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/inputfifo/src/inputfifo.c @@ -105,7 +105,7 @@ static struct inputfifo_instance /* Streaming to MIPI */ static unsigned inputfifo_wrap_marker( -/* STORAGE_CLASS_INLINE unsigned inputfifo_wrap_marker( */ +/* static inline unsigned inputfifo_wrap_marker( */ unsigned marker) { return marker | @@ -113,7 +113,7 @@ static unsigned inputfifo_wrap_marker( (inputfifo_curr_fmt_type << _HIVE_STR_TO_MIPI_FMT_TYPE_LSB); } -STORAGE_CLASS_INLINE void +static inline void _sh_css_fifo_snd(unsigned token) { while (!can_event_send_token(STR2MIPI_EVENT_ID)) @@ -123,7 +123,7 @@ _sh_css_fifo_snd(unsigned token) } static void inputfifo_send_data_a( -/* STORAGE_CLASS_INLINE void inputfifo_send_data_a( */ +/* static inline void inputfifo_send_data_a( */ unsigned int data) { unsigned int token = (1 << HIVE_STR_TO_MIPI_VALID_A_BIT) | @@ -135,7 +135,7 @@ unsigned int data) static void inputfifo_send_data_b( -/* STORAGE_CLASS_INLINE void inputfifo_send_data_b( */ +/* static inline void inputfifo_send_data_b( */ unsigned int data) { unsigned int token = (1 << HIVE_STR_TO_MIPI_VALID_B_BIT) | @@ -147,7 +147,7 @@ static void inputfifo_send_data_b( static void inputfifo_send_data( -/* STORAGE_CLASS_INLINE void inputfifo_send_data( */ +/* static inline void inputfifo_send_data( */ unsigned int a, unsigned int b) { @@ -162,7 +162,7 @@ static void inputfifo_send_data( static void inputfifo_send_sol(void) -/* STORAGE_CLASS_INLINE void inputfifo_send_sol(void) */ +/* static inline void inputfifo_send_sol(void) */ { hrt_data token = inputfifo_wrap_marker( 1 << HIVE_STR_TO_MIPI_SOL_BIT); @@ -174,7 +174,7 @@ static void inputfifo_send_sol(void) static void inputfifo_send_eol(void) -/* STORAGE_CLASS_INLINE void inputfifo_send_eol(void) */ +/* static inline void inputfifo_send_eol(void) */ { hrt_data token = inputfifo_wrap_marker( 1 << HIVE_STR_TO_MIPI_EOL_BIT); @@ -185,7 +185,7 @@ static void inputfifo_send_eol(void) static void inputfifo_send_sof(void) -/* STORAGE_CLASS_INLINE void inputfifo_send_sof(void) */ +/* static inline void inputfifo_send_sof(void) */ { hrt_data token = inputfifo_wrap_marker( 1 << HIVE_STR_TO_MIPI_SOF_BIT); @@ -197,7 +197,7 @@ static void inputfifo_send_sof(void) static void inputfifo_send_eof(void) -/* STORAGE_CLASS_INLINE void inputfifo_send_eof(void) */ +/* static inline void inputfifo_send_eof(void) */ { hrt_data token = inputfifo_wrap_marker( 1 << HIVE_STR_TO_MIPI_EOF_BIT); @@ -209,7 +209,7 @@ static void inputfifo_send_eof(void) #ifdef __ON__ static void inputfifo_send_ch_id( -/* STORAGE_CLASS_INLINE void inputfifo_send_ch_id( */ +/* static inline void inputfifo_send_ch_id( */ unsigned int ch_id) { hrt_data token; @@ -223,7 +223,7 @@ static void inputfifo_send_ch_id( } static void inputfifo_send_fmt_type( -/* STORAGE_CLASS_INLINE void inputfifo_send_fmt_type( */ +/* static inline void inputfifo_send_fmt_type( */ unsigned int fmt_type) { hrt_data token; @@ -240,7 +240,7 @@ static void inputfifo_send_fmt_type( static void inputfifo_send_ch_id_and_fmt_type( -/* STORAGE_CLASS_INLINE +/* static inline void inputfifo_send_ch_id_and_fmt_type( */ unsigned int ch_id, unsigned int fmt_type) @@ -259,7 +259,7 @@ void inputfifo_send_ch_id_and_fmt_type( */ static void inputfifo_send_empty_token(void) -/* STORAGE_CLASS_INLINE void inputfifo_send_empty_token(void) */ +/* static inline void inputfifo_send_empty_token(void) */ { hrt_data token = inputfifo_wrap_marker(0); _sh_css_fifo_snd(token); @@ -269,7 +269,7 @@ static void inputfifo_send_empty_token(void) static void inputfifo_start_frame( -/* STORAGE_CLASS_INLINE void inputfifo_start_frame( */ +/* static inline void inputfifo_start_frame( */ unsigned int ch_id, unsigned int fmt_type) { diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/rmgr/interface/ia_css_rmgr.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/rmgr/interface/ia_css_rmgr.h index a0bb9f663ce6..9f78e709b3d0 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/rmgr/interface/ia_css_rmgr.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/runtime/rmgr/interface/ia_css_rmgr.h @@ -31,15 +31,14 @@ more details. #ifndef _IA_CSS_RMGR_H #define _IA_CSS_RMGR_H -#include "storage_class.h" #include #ifndef __INLINE_RMGR__ -#define STORAGE_CLASS_RMGR_H STORAGE_CLASS_EXTERN +#define STORAGE_CLASS_RMGR_H extern #define STORAGE_CLASS_RMGR_C #else /* __INLINE_RMGR__ */ -#define STORAGE_CLASS_RMGR_H STORAGE_CLASS_INLINE -#define STORAGE_CLASS_RMGR_C STORAGE_CLASS_INLINE +#define STORAGE_CLASS_RMGR_H static inline +#define STORAGE_CLASS_RMGR_C static inline #endif /* __INLINE_RMGR__ */ /** diff --git a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_internal.h b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_internal.h index 5b2b78f96dc5..0910021286a4 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_internal.h +++ b/drivers/staging/media/atomisp/pci/atomisp2/css2400/sh_css_internal.h @@ -961,7 +961,7 @@ struct host_sp_queues { extern int (*sh_css_printf)(const char *fmt, va_list args); -STORAGE_CLASS_INLINE void +static inline void sh_css_print(const char *fmt, ...) { va_list ap; @@ -973,7 +973,7 @@ sh_css_print(const char *fmt, ...) } } -STORAGE_CLASS_INLINE void +static inline void sh_css_vprint(const char *fmt, va_list args) { if (sh_css_printf) -- cgit v1.2.3 From 58364c505d60cd49f287dd3ee0a4a085f412d3b1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 31 Oct 2017 11:54:07 -0400 Subject: media: atomisp: make function calls cleaner The #ifs inside the code makes confusing for reviewers and also cause problems with smatch: drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c:2937:1: error: directive in argument list drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c:2939:1: error: directive in argument list drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c:2941:1: error: directive in argument list Signed-off-by: Mauro Carvalho Chehab Acked-by: Sakari Ailus --- drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c index 8698f8f758ca..339b5d31e1f1 100644 --- a/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c +++ b/drivers/staging/media/atomisp/pci/atomisp2/atomisp_ioctl.c @@ -2933,13 +2933,15 @@ static long atomisp_vidioc_default(struct file *file, void *fh, #else if (isp->motor) #endif - err = v4l2_subdev_call( #ifndef ISP2401 + err = v4l2_subdev_call( isp->inputs[asd->input_curr].motor, + core, ioctl, cmd, arg); #else + err = v4l2_subdev_call( isp->motor, -#endif core, ioctl, cmd, arg); +#endif else err = v4l2_subdev_call( isp->inputs[asd->input_curr].camera, -- cgit v1.2.3 From 9917fbcfa20ab987d6381fd0365665e5c1402d75 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 1 Nov 2017 08:09:59 -0400 Subject: media: camss-vfe: always initialize reg at vfe_set_xbar_cfg() if output->wm_num is bigger than 2, the value for reg is not initialized, as warned by smatch: drivers/media/platform/qcom/camss-8x16/camss-vfe.c:633 vfe_set_xbar_cfg() error: uninitialized symbol 'reg'. drivers/media/platform/qcom/camss-8x16/camss-vfe.c:637 vfe_set_xbar_cfg() error: uninitialized symbol 'reg'. That shouldn't happen in practice, so add a logic that will break the loop if i > 1, fixing the warnings. Signed-off-by: Mauro Carvalho Chehab Acked-by: Todor Tomov --- drivers/media/platform/qcom/camss-8x16/camss-vfe.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/platform/qcom/camss-8x16/camss-vfe.c b/drivers/media/platform/qcom/camss-8x16/camss-vfe.c index b22d2dfcd3c2..55232a912950 100644 --- a/drivers/media/platform/qcom/camss-8x16/camss-vfe.c +++ b/drivers/media/platform/qcom/camss-8x16/camss-vfe.c @@ -622,6 +622,9 @@ static void vfe_set_xbar_cfg(struct vfe_device *vfe, struct vfe_output *output, reg = VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_EN; if (p == V4L2_PIX_FMT_NV12 || p == V4L2_PIX_FMT_NV16) reg |= VFE_0_BUS_XBAR_CFG_x_M_PAIR_STREAM_SWAP_INTER_INTRA; + } else { + /* On current devices output->wm_num is always <= 2 */ + break; } if (output->wm_idx[i] % 2 == 1) -- cgit v1.2.3 From 2b00e30fc33de720cedad69427931aa393cdbaf0 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 3 Nov 2017 02:41:06 -0400 Subject: media: imx274: fix missing return assignment from call to imx274_mode_regs The variable ret is being checked for failure however it is not being set from the return status from the call to imx274_mode_regs. Currently ret is alwayus zero and the check is redundant. Fix this by assigning it. Detected by CoverityScan, CID#1460278 ("Logically dead code") Fixes: 0985dd306f72 ("media: imx274: V4l2 driver for Sony imx274 CMOS sensor") Signed-off-by: Colin Ian King Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx274.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c index ab6a5f31da74..800b9bf9cdd3 100644 --- a/drivers/media/i2c/imx274.c +++ b/drivers/media/i2c/imx274.c @@ -1059,7 +1059,7 @@ static int imx274_s_stream(struct v4l2_subdev *sd, int on) if (on) { /* load mode registers */ - imx274_mode_regs(imx274, imx274->mode_index); + ret = imx274_mode_regs(imx274, imx274->mode_index); if (ret) goto fail; -- cgit v1.2.3 From 580db6ca62c168733c6fd338cd2f0ebf39135283 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 3 Nov 2017 02:58:27 -0400 Subject: media: v4l: async: fix return of unitialized variable ret A shadow declaration of variable ret is being assigned a return error status and this value is being lost when the error exit goto's jump out of the local scope. This leads to an uninitalized error return value in the outer scope being returned. Fix this by removing the inner scoped declaration of variable ret. Detected by CoverityScan, CID#1460380 ("Uninitialized scalar variable") Fixes: fb45f436b818 ("media: v4l: async: Fix notifier complete callback error handling") Signed-off-by: Colin Ian King Reviewed-by: Niklas Söderlund Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-async.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 49f7eccc76db..7020b2e6d158 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -550,7 +550,6 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd) struct v4l2_device *v4l2_dev = v4l2_async_notifier_find_v4l2_dev(notifier); struct v4l2_async_subdev *asd; - int ret; if (!v4l2_dev) continue; -- cgit v1.2.3 From 1453ad81a2be1bef9243671480694d483ab0dad0 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Fri, 3 Nov 2017 22:25:56 -0400 Subject: media: v4l: async: fix unregister for implicitly registered sub-device notifiers The commit aef69d54755d45ed ("media: v4l: fwnode: Add a convenience function for registering sensors") adds the function v4l2_async_notifier_parse_fwnode_sensor_common() to parse and register a subdevice and a subdev-notifier by parsing firmware information. This new subdev-notifier is stored in the new field 'subdev_notifier' in struct v4l2_subdev. In v4l2_async_unregister_subdev() this field is used to unregister and cleanup the subdev-notifier. A check for if the subdev-notifier is initialized or not was forgotten leading to a NULL pointer dereference in v4l2_async_notifier_cleanup() if a subdevice do not use the optional convince function to initialize the field. Fix this by checking in v4l2_async_notifier_cleanup() that it is provided whit a notifier making it safe to call with a NULL parameter. Fixes: aef69d54755d45ed ("media: v4l: fwnode: Add a convenience function for registering sensors") Signed-off-by: Niklas Söderlund Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-async.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c index 7020b2e6d158..a7c3464976f2 100644 --- a/drivers/media/v4l2-core/v4l2-async.c +++ b/drivers/media/v4l2-core/v4l2-async.c @@ -502,7 +502,7 @@ void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier) { unsigned int i; - if (!notifier->max_subdevs) + if (!notifier || !notifier->max_subdevs) return; for (i = 0; i < notifier->num_subdevs; i++) { -- cgit v1.2.3 From b3120d2cc447ee77b9d69bf4ad7b452c9adb4d39 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Mon, 6 Nov 2017 08:50:22 -0500 Subject: media: Don't do DMA on stack for firmware upload in the AS102 driver Firmware load on AS102 is using the stack which is not allowed any longer. We currently fail with: kernel: transfer buffer not dma capable kernel: ------------[ cut here ]------------ kernel: WARNING: CPU: 0 PID: 598 at drivers/usb/core/hcd.c:1595 usb_hcd_map_urb_for_dma+0x41d/0x620 kernel: Modules linked in: amd64_edac_mod(-) edac_mce_amd as102_fe dvb_as102(+) kvm_amd kvm snd_hda_codec_realtek dvb_core snd_hda_codec_generic snd_hda_codec_hdmi snd_hda_intel snd_hda_codec irqbypass crct10dif_pclmul crc32_pclmul snd_hda_core snd_hwdep snd_seq ghash_clmulni_intel sp5100_tco fam15h_power wmi k10temp i2c_piix4 snd_seq_device snd_pcm snd_timer parport_pc parport tpm_infineon snd tpm_tis soundcore tpm_tis_core tpm shpchp acpi_cpufreq xfs libcrc32c amdgpu amdkfd amd_iommu_v2 radeon hid_logitech_hidpp i2c_algo_bit drm_kms_helper crc32c_intel ttm drm r8169 mii hid_logitech_dj kernel: CPU: 0 PID: 598 Comm: systemd-udevd Not tainted 4.13.10-200.fc26.x86_64 #1 kernel: Hardware name: ASUS All Series/AM1I-A, BIOS 0505 03/13/2014 kernel: task: ffff979933b24c80 task.stack: ffffaf83413a4000 kernel: RIP: 0010:usb_hcd_map_urb_for_dma+0x41d/0x620 systemd-fsck[659]: /dev/sda2: clean, 49/128016 files, 268609/512000 blocks kernel: RSP: 0018:ffffaf83413a7728 EFLAGS: 00010282 systemd-udevd[604]: link_config: autonegotiation is unset or enabled, the speed and duplex are not writable. kernel: RAX: 000000000000001f RBX: ffff979930bce780 RCX: 0000000000000000 kernel: RDX: 0000000000000000 RSI: ffff97993ec0e118 RDI: ffff97993ec0e118 kernel: RBP: ffffaf83413a7768 R08: 000000000000039a R09: 0000000000000000 kernel: R10: 0000000000000001 R11: 00000000ffffffff R12: 00000000fffffff5 kernel: R13: 0000000001400000 R14: 0000000000000001 R15: ffff979930806800 kernel: FS: 00007effaca5c8c0(0000) GS:ffff97993ec00000(0000) knlGS:0000000000000000 kernel: CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 kernel: CR2: 00007effa9fca962 CR3: 0000000233089000 CR4: 00000000000406f0 kernel: Call Trace: kernel: usb_hcd_submit_urb+0x493/0xb40 kernel: ? page_cache_tree_insert+0x100/0x100 kernel: ? xfs_iunlock+0xd5/0x100 [xfs] kernel: ? xfs_file_buffered_aio_read+0x57/0xc0 [xfs] kernel: usb_submit_urb+0x22d/0x560 kernel: usb_start_wait_urb+0x6e/0x180 kernel: usb_bulk_msg+0xb8/0x160 kernel: as102_send_ep1+0x49/0xe0 [dvb_as102] kernel: ? devres_add+0x3f/0x50 kernel: as102_firmware_upload.isra.0+0x1dc/0x210 [dvb_as102] kernel: as102_fw_upload+0xb6/0x1f0 [dvb_as102] kernel: as102_dvb_register+0x2af/0x2d0 [dvb_as102] kernel: as102_usb_probe+0x1f3/0x260 [dvb_as102] kernel: usb_probe_interface+0x124/0x300 kernel: driver_probe_device+0x2ff/0x450 kernel: __driver_attach+0xa4/0xe0 kernel: ? driver_probe_device+0x450/0x450 kernel: bus_for_each_dev+0x6e/0xb0 kernel: driver_attach+0x1e/0x20 kernel: bus_add_driver+0x1c7/0x270 kernel: driver_register+0x60/0xe0 kernel: usb_register_driver+0x81/0x150 kernel: ? 0xffffffffc0807000 kernel: as102_usb_driver_init+0x1e/0x1000 [dvb_as102] kernel: do_one_initcall+0x50/0x190 kernel: ? __vunmap+0x81/0xb0 kernel: ? kfree+0x154/0x170 kernel: ? kmem_cache_alloc_trace+0x15f/0x1c0 kernel: ? do_init_module+0x27/0x1e9 kernel: do_init_module+0x5f/0x1e9 kernel: load_module+0x2602/0x2c30 kernel: SYSC_init_module+0x170/0x1a0 kernel: ? SYSC_init_module+0x170/0x1a0 kernel: SyS_init_module+0xe/0x10 kernel: do_syscall_64+0x67/0x140 kernel: entry_SYSCALL64_slow_path+0x25/0x25 kernel: RIP: 0033:0x7effab6cf3ea kernel: RSP: 002b:00007fff5cfcbbc8 EFLAGS: 00000246 ORIG_RAX: 00000000000000af kernel: RAX: ffffffffffffffda RBX: 00005569e0b83760 RCX: 00007effab6cf3ea kernel: RDX: 00007effac2099c5 RSI: 0000000000009a13 RDI: 00005569e0b98c50 kernel: RBP: 00007effac2099c5 R08: 00005569e0b83ed0 R09: 0000000000001d80 kernel: R10: 00007effab98db00 R11: 0000000000000246 R12: 00005569e0b98c50 kernel: R13: 00005569e0b81c60 R14: 0000000000020000 R15: 00005569dfadfdf7 kernel: Code: 48 39 c8 73 30 80 3d 59 60 9d 00 00 41 bc f5 ff ff ff 0f 85 26 ff ff ff 48 c7 c7 b8 6b d0 92 c6 05 3f 60 9d 00 01 e8 24 3d ad ff <0f> ff 8b 53 64 e9 09 ff ff ff 65 48 8b 0c 25 00 d3 00 00 48 8b kernel: ---[ end trace c4cae366180e70ec ]--- kernel: as10x_usb: error during firmware upload part1 Let's allocate the the structure dynamically so we can get the firmware loaded correctly: [ 14.243057] as10x_usb: firmware: as102_data1_st.hex loaded with success [ 14.500777] as10x_usb: firmware: as102_data2_st.hex loaded with success Signed-off-by: Michele Baldessari Cc: stable@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/as102/as102_fw.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/media/usb/as102/as102_fw.c b/drivers/media/usb/as102/as102_fw.c index 5a28ce3a1d49..38dbc128340d 100644 --- a/drivers/media/usb/as102/as102_fw.c +++ b/drivers/media/usb/as102/as102_fw.c @@ -101,18 +101,23 @@ static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap, unsigned char *cmd, const struct firmware *firmware) { - struct as10x_fw_pkt_t fw_pkt; + struct as10x_fw_pkt_t *fw_pkt; int total_read_bytes = 0, errno = 0; unsigned char addr_has_changed = 0; + fw_pkt = kmalloc(sizeof(*fw_pkt), GFP_KERNEL); + if (!fw_pkt) + return -ENOMEM; + + for (total_read_bytes = 0; total_read_bytes < firmware->size; ) { int read_bytes = 0, data_len = 0; /* parse intel hex line */ read_bytes = parse_hex_line( (u8 *) (firmware->data + total_read_bytes), - fw_pkt.raw.address, - fw_pkt.raw.data, + fw_pkt->raw.address, + fw_pkt->raw.data, &data_len, &addr_has_changed); @@ -122,28 +127,28 @@ static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap, /* detect the end of file */ total_read_bytes += read_bytes; if (total_read_bytes == firmware->size) { - fw_pkt.u.request[0] = 0x00; - fw_pkt.u.request[1] = 0x03; + fw_pkt->u.request[0] = 0x00; + fw_pkt->u.request[1] = 0x03; /* send EOF command */ errno = bus_adap->ops->upload_fw_pkt(bus_adap, (uint8_t *) - &fw_pkt, 2, 0); + fw_pkt, 2, 0); if (errno < 0) goto error; } else { if (!addr_has_changed) { /* prepare command to send */ - fw_pkt.u.request[0] = 0x00; - fw_pkt.u.request[1] = 0x01; + fw_pkt->u.request[0] = 0x00; + fw_pkt->u.request[1] = 0x01; - data_len += sizeof(fw_pkt.u.request); - data_len += sizeof(fw_pkt.raw.address); + data_len += sizeof(fw_pkt->u.request); + data_len += sizeof(fw_pkt->raw.address); /* send cmd to device */ errno = bus_adap->ops->upload_fw_pkt(bus_adap, (uint8_t *) - &fw_pkt, + fw_pkt, data_len, 0); if (errno < 0) @@ -152,6 +157,7 @@ static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap, } } error: + kfree(fw_pkt); return (errno == 0) ? total_read_bytes : errno; } -- cgit v1.2.3 From fe3652858a36bb1aa116f23258ea9cc353426566 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 6 Nov 2017 09:06:50 -0500 Subject: media: av7110: avoid 2038 overflow in debug print Using the deprecated do_gettimeofday() in print_time() will overflow in 2038 on 32-bit architectures. It'sbetter to use a structure that is safe everywhere. While we're at it, fix the missing leading zeroes on the sub-second portion. Signed-off-by: Arnd Bergmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ttpci/av7110.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index f89fb23f6c57..6d415bdeef18 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -347,9 +347,9 @@ static int DvbDmxFilterCallback(u8 *buffer1, size_t buffer1_len, static inline void print_time(char *s) { #ifdef DEBUG_TIMING - struct timeval tv; - do_gettimeofday(&tv); - printk("%s: %d.%d\n", s, (int)tv.tv_sec, (int)tv.tv_usec); + struct timespec64 ts; + ktime_get_real_ts64(&ts); + printk("%s: %lld.%09ld\n", s, (s64)ts.tv_sec, ts.tv_nsec); #endif } -- cgit v1.2.3 From f3eff2096a8d0ceb2782fa2e10fac3aa2d5b127c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 6 Nov 2017 13:21:06 -0500 Subject: media: ddbridge: fix build warnings Fix 2 build warnings. These functions are void, so drop the "return"s. ./drivers/media/pci/ddbridge/ddbridge-io.h: warning: 'return' with a value, in function returning void [enabled by default]: => 50:2, 55:2 Signed-off-by: Randy Dunlap Reported-by: Geert Uytterhoeven Cc: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ddbridge/ddbridge-io.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/pci/ddbridge/ddbridge-io.h b/drivers/media/pci/ddbridge/ddbridge-io.h index a4c6bbe09168..b3646c04f1a7 100644 --- a/drivers/media/pci/ddbridge/ddbridge-io.h +++ b/drivers/media/pci/ddbridge/ddbridge-io.h @@ -47,12 +47,12 @@ static inline void ddbwritel(struct ddb *dev, u32 val, u32 adr) static inline void ddbcpyto(struct ddb *dev, u32 adr, void *src, long count) { - return memcpy_toio(dev->regs + adr, src, count); + memcpy_toio(dev->regs + adr, src, count); } static inline void ddbcpyfrom(struct ddb *dev, void *dst, u32 adr, long count) { - return memcpy_fromio(dst, dev->regs + adr, count); + memcpy_fromio(dst, dev->regs + adr, count); } static inline u32 safe_ddbreadl(struct ddb *dev, u32 adr) -- cgit v1.2.3 From b436e26e484d259e0b658d558eb99b7ab004e997 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 2 Nov 2017 06:11:53 -0400 Subject: media: usb: fix spelling mistake: "synchronuously" -> "synchronously" Trivial fix to spelling mistake in error message text [mchehab@s-opensource.org: folded all similar patches into one] Signed-off-by: Colin Ian King Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-video.c | 4 ++-- drivers/media/usb/cx231xx/cx231xx-dvb.c | 4 ++-- drivers/media/usb/cx231xx/cx231xx-vbi.c | 4 ++-- drivers/media/usb/cx231xx/cx231xx-video.c | 4 ++-- drivers/media/usb/em28xx/em28xx-dvb.c | 4 ++-- drivers/media/usb/em28xx/em28xx-video.c | 4 ++-- drivers/media/usb/msi2500/msi2500.c | 2 +- drivers/media/usb/pwc/pwc-if.c | 3 ++- drivers/media/usb/stk1160/stk1160-video.c | 4 ++-- drivers/media/usb/tm6000/tm6000-dvb.c | 4 ++-- drivers/media/usb/tm6000/tm6000-video.c | 4 ++-- 11 files changed, 21 insertions(+), 20 deletions(-) diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 9342402b92f7..654f67c25863 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -67,10 +67,10 @@ static inline void print_err_status(struct au0828_dev *dev, switch (status) { case -ENOENT: - errmsg = "unlinked synchronuously"; + errmsg = "unlinked synchronously"; break; case -ECONNRESET: - errmsg = "unlinked asynchronuously"; + errmsg = "unlinked asynchronously"; break; case -ENOSR: errmsg = "Buffer error (overrun)"; diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index c18bb33e060e..54abc1a7c8e1 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -179,10 +179,10 @@ static inline void print_err_status(struct cx231xx *dev, int packet, int status) switch (status) { case -ENOENT: - errmsg = "unlinked synchronuously"; + errmsg = "unlinked synchronously"; break; case -ECONNRESET: - errmsg = "unlinked asynchronuously"; + errmsg = "unlinked asynchronously"; break; case -ENOSR: errmsg = "Buffer error (overrun)"; diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c index 330b86e4e38f..d3bfe8e23b1f 100644 --- a/drivers/media/usb/cx231xx/cx231xx-vbi.c +++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c @@ -43,10 +43,10 @@ static inline void print_err_status(struct cx231xx *dev, int packet, int status) switch (status) { case -ENOENT: - errmsg = "unlinked synchronuously"; + errmsg = "unlinked synchronously"; break; case -ECONNRESET: - errmsg = "unlinked asynchronuously"; + errmsg = "unlinked asynchronously"; break; case -ENOSR: errmsg = "Buffer error (overrun)"; diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 179b8481a870..226059fc672b 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -199,10 +199,10 @@ static inline void print_err_status(struct cx231xx *dev, int packet, int status) switch (status) { case -ENOENT: - errmsg = "unlinked synchronuously"; + errmsg = "unlinked synchronously"; break; case -ECONNRESET: - errmsg = "unlinked asynchronuously"; + errmsg = "unlinked asynchronously"; break; case -ENOSR: errmsg = "Buffer error (overrun)"; diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 4a7db623fe29..9950a740e04e 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -112,10 +112,10 @@ static inline void print_err_status(struct em28xx *dev, switch (status) { case -ENOENT: - errmsg = "unlinked synchronuously"; + errmsg = "unlinked synchronously"; break; case -ECONNRESET: - errmsg = "unlinked asynchronuously"; + errmsg = "unlinked asynchronously"; break; case -ENOSR: errmsg = "Buffer error (overrun)"; diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 8d253a5df0a9..a2ba2d905952 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -557,10 +557,10 @@ static inline void print_err_status(struct em28xx *dev, switch (status) { case -ENOENT: - errmsg = "unlinked synchronuously"; + errmsg = "unlinked synchronously"; break; case -ECONNRESET: - errmsg = "unlinked asynchronuously"; + errmsg = "unlinked asynchronously"; break; case -ENOSR: errmsg = "Buffer error (overrun)"; diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index a097d3dbc141..65ef755adfdc 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -386,7 +386,7 @@ static void msi2500_isoc_handler(struct urb *urb) if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) { - dev_dbg(dev->dev, "URB (%p) unlinked %ssynchronuously\n", + dev_dbg(dev->dev, "URB (%p) unlinked %ssynchronously\n", urb, urb->status == -ENOENT ? "" : "a"); return; } diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index eb6921d2743e..54b036d39c5b 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -262,7 +262,8 @@ static void pwc_isoc_handler(struct urb *urb) if (urb->status == -ENOENT || urb->status == -ECONNRESET || urb->status == -ESHUTDOWN) { - PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a"); + PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronously.\n", + urb, urb->status == -ENOENT ? "" : "a"); return; } diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c index ce8ebbe395a6..423c03a0638d 100644 --- a/drivers/media/usb/stk1160/stk1160-video.c +++ b/drivers/media/usb/stk1160/stk1160-video.c @@ -38,10 +38,10 @@ static inline void print_err_status(struct stk1160 *dev, switch (status) { case -ENOENT: - errmsg = "unlinked synchronuously"; + errmsg = "unlinked synchronously"; break; case -ECONNRESET: - errmsg = "unlinked asynchronuously"; + errmsg = "unlinked asynchronously"; break; case -ENOSR: errmsg = "Buffer error (overrun)"; diff --git a/drivers/media/usb/tm6000/tm6000-dvb.c b/drivers/media/usb/tm6000/tm6000-dvb.c index 2bc584f75f87..c811fc6cf48a 100644 --- a/drivers/media/usb/tm6000/tm6000-dvb.c +++ b/drivers/media/usb/tm6000/tm6000-dvb.c @@ -45,10 +45,10 @@ static inline void print_err_status(struct tm6000_core *dev, switch (status) { case -ENOENT: - errmsg = "unlinked synchronuously"; + errmsg = "unlinked synchronously"; break; case -ECONNRESET: - errmsg = "unlinked asynchronuously"; + errmsg = "unlinked asynchronously"; break; case -ENOSR: errmsg = "Buffer error (overrun)"; diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index 0d45f35e1697..9fa25de6b5a9 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -342,10 +342,10 @@ static inline void print_err_status(struct tm6000_core *dev, switch (status) { case -ENOENT: - errmsg = "unlinked synchronuously"; + errmsg = "unlinked synchronously"; break; case -ECONNRESET: - errmsg = "unlinked asynchronuously"; + errmsg = "unlinked asynchronously"; break; case -ENOSR: errmsg = "Buffer error (overrun)"; -- cgit v1.2.3 From eaa8c79eadc04b06d1434be09207074c9989cefb Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 2 Nov 2017 12:49:08 -0400 Subject: media: drxd: make const array fastIncrDecLUT static Don't populate array fastIncrDecLUT on the stack but instead make it static. Makes the object code smaller by over 360 bytes: text data bss dec hex filename 32680 944 64 33688 8398 drxd_hard.o text data bss dec hex filename 32223 1040 64 33327 822f drxd_hard.o (gcc version 7.2.0 x86_64) Signed-off-by: Colin Ian King Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/drxd_hard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index 3bdf9b1f4e7c..0696bc62dcc9 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -640,7 +640,7 @@ static int SetCfgIfAgc(struct drxd_state *state, struct SCfgAgc *cfg) const u16 maxRur = 8; static const u16 slowIncrDecLUT[] = { 3, 4, 4, 5, 6 }; - const u16 fastIncrDecLUT[] = { + static const u16 fastIncrDecLUT[] = { 14, 15, 15, 16, 17, 18, 18, 19, 20, 21, 22, 23, -- cgit v1.2.3 From 4b8a14c8f89def80e50a3feb5b8b797cd54e1f2a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 2 Nov 2017 13:16:59 -0400 Subject: media: cx88: make const arrays default_addr_list and pvr2000_addr_list static Don't populate arrays default_addr_list and pvr2000_addr_list on the stack but instead make them static. Makes the object code smaller by over 340 bytes: Before: text data bss dec hex filename 12520 2800 64 15384 3c18 drivers/media/pci/cx88/cx88-input.o After: text data bss dec hex filename 12142 2832 64 15038 3abe drivers/media/pci/cx88/cx88-input.o (gcc version 7.2.0 x86_64) Signed-off-by: Colin Ian King Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx88/cx88-input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c index e02449bf2041..4e9953e61a12 100644 --- a/drivers/media/pci/cx88/cx88-input.c +++ b/drivers/media/pci/cx88/cx88-input.c @@ -593,11 +593,11 @@ static int get_key_pvr2000(struct IR_i2c *ir, enum rc_proto *protocol, void cx88_i2c_init_ir(struct cx88_core *core) { struct i2c_board_info info; - const unsigned short default_addr_list[] = { + static const unsigned short default_addr_list[] = { 0x18, 0x6b, 0x71, I2C_CLIENT_END }; - const unsigned short pvr2000_addr_list[] = { + static const unsigned short pvr2000_addr_list[] = { 0x18, 0x1a, I2C_CLIENT_END }; -- cgit v1.2.3 From 213bc75a750363879792fd3793be8007a56ac477 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 2 Nov 2017 13:26:48 -0400 Subject: media: au0828: make const array addr_list static Don't populate array addr_list on the stack but instead make it static. Makes the object code smaller by over 360 bytes: Before: text data bss dec hex filename 8036 1488 192 9716 25f4 au0828-input.o After: text data bss dec hex filename 7696 1488 192 9376 24a0 au0828-input.o (gcc version 7.2.0 x86_64) Signed-off-by: Colin Ian King Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c index 7996eb83a54e..af68afe085b5 100644 --- a/drivers/media/usb/au0828/au0828-input.c +++ b/drivers/media/usb/au0828/au0828-input.c @@ -269,7 +269,7 @@ static void au0828_rc_stop(struct rc_dev *rc) static int au0828_probe_i2c_ir(struct au0828_dev *dev) { int i = 0; - const unsigned short addr_list[] = { + static const unsigned short addr_list[] = { 0x47, I2C_CLIENT_END }; -- cgit v1.2.3 From b4b138a9d31924cb9ab535138deb150d6ec418a5 Mon Sep 17 00:00:00 2001 From: Gustavo A. R. Silva Date: Mon, 6 Nov 2017 09:22:18 -0500 Subject: media: usb: dvb-usb-v2: dvb_usb_core: remove redundant code in dvb_usb_fe_sleep Check on return value and goto instruction is redundant as the code that follows is the goto label err. Addresses-Coverity-ID: 1268783 Signed-off-by: Gustavo A. R. Silva Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/dvb_usb_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index 096bb75a24e5..2bf3bd81280a 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -628,8 +628,7 @@ static int dvb_usb_fe_sleep(struct dvb_frontend *fe) } ret = dvb_usbv2_device_power_ctrl(d, 0); - if (ret < 0) - goto err; + err: if (!adap->suspend_resume_active) { adap->active_fe = -1; -- cgit v1.2.3 From 62229de19ff2b7f3e0ebf4d48ad99061127d0281 Mon Sep 17 00:00:00 2001 From: Daniel Scheller Date: Sun, 29 Oct 2017 11:43:22 -0400 Subject: media: dvb-core: always call invoke_release() in fe_free() Follow-up to: ead666000a5f ("media: dvb_frontend: only use kref after initialized") The aforementioned commit fixed refcount OOPSes when demod driver attaching succeeded but tuner driver didn't. However, the use count of the attached demod drivers don't go back to zero and thus couldn't be cleanly unloaded. Improve on this by calling dvb_frontend_invoke_release() in __dvb_frontend_free() regardless of fepriv being NULL, instead of returning when fepriv is NULL. This is safe to do since _invoke_release() will check for passed pointers being valid before calling the .release() function. [mchehab@s-opensource.com: changed the logic a little bit to reduce conflicts with another bug fix patch under review] Fixes: ead666000a5f ("media: dvb_frontend: only use kref after initialized") Signed-off-by: Daniel Scheller Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index daaf969719e4..d485d5f6cc88 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -145,13 +145,14 @@ static void __dvb_frontend_free(struct dvb_frontend *fe) { struct dvb_frontend_private *fepriv = fe->frontend_priv; - if (!fepriv) - return; - - dvb_free_device(fepriv->dvbdev); + if (fepriv) + dvb_free_device(fepriv->dvbdev); dvb_frontend_invoke_release(fe, fe->ops.release); + if (!fepriv) + return; + kfree(fepriv); fe->frontend_priv = NULL; } -- cgit v1.2.3 From 55a839a09395aaa21646cea328fb9afd7342dce6 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Mon, 30 Oct 2017 17:04:57 -0400 Subject: media: s5p-mfc: fix lockdep warning The driver mmap functions shouldn't take lock when calling vb2_mmap(). Fix it to not take the lock. The following lockdep warning is fixed with this change. [ 2106.181412] ====================================================== [ 2106.187563] WARNING: possible circular locking dependency detected [ 2106.193718] 4.14.0-rc2-00002-gfab205f-dirty #4 Not tainted [ 2106.199175] ------------------------------------------------------ [ 2106.205328] qtdemux0:sink/2614 is trying to acquire lock: [ 2106.210701] (&dev->mfc_mutex){+.+.}, at: [] s5p_mfc_mmap+0x28/0xd4 [s5p_mfc] [ 2106.218672] [ 2106.218672] but task is already holding lock: [ 2106.224477] (&mm->mmap_sem){++++}, at: [] vm_mmap_pgoff+0x44/0xb8 [ 2106.231497] [ 2106.231497] which lock already depends on the new lock. [ 2106.231497] [ 2106.239642] [ 2106.239642] the existing dependency chain (in reverse order) is: [ 2106.247095] [ 2106.247095] -> #1 (&mm->mmap_sem){++++}: [ 2106.252473] __might_fault+0x80/0xb0 [ 2106.256567] video_usercopy+0x1cc/0x510 [videodev] [ 2106.261845] v4l2_ioctl+0xa4/0xdc [videodev] [ 2106.266596] do_vfs_ioctl+0xa0/0xa18 [ 2106.270667] SyS_ioctl+0x34/0x5c [ 2106.274395] ret_fast_syscall+0x0/0x28 [ 2106.278637] [ 2106.278637] -> #0 (&dev->mfc_mutex){+.+.}: [ 2106.284186] lock_acquire+0x6c/0x88 [ 2106.288173] __mutex_lock+0x68/0xa34 [ 2106.292244] mutex_lock_interruptible_nested+0x1c/0x24 [ 2106.297893] s5p_mfc_mmap+0x28/0xd4 [s5p_mfc] [ 2106.302747] v4l2_mmap+0x54/0x88 [videodev] [ 2106.307409] mmap_region+0x3a8/0x638 [ 2106.311480] do_mmap+0x330/0x3a4 [ 2106.315207] vm_mmap_pgoff+0x90/0xb8 [ 2106.319279] SyS_mmap_pgoff+0x90/0xc0 [ 2106.323439] ret_fast_syscall+0x0/0x28 [ 2106.327683] [ 2106.327683] other info that might help us debug this: [ 2106.327683] [ 2106.335656] Possible unsafe locking scenario: [ 2106.335656] [ 2106.341548] CPU0 CPU1 [ 2106.346053] ---- ---- [ 2106.350559] lock(&mm->mmap_sem); [ 2106.353939] lock(&dev->mfc_mutex); [ 2106.353939] lock(&dev->mfc_mutex); [ 2106.365897] lock(&dev->mfc_mutex); [ 2106.369450] [ 2106.369450] *** DEADLOCK *** [ 2106.369450] [ 2106.375344] 1 lock held by qtdemux0:sink/2614: [ 2106.379762] #0: (&mm->mmap_sem){++++}, at: [] vm_mmap_pgoff+0x44/0xb8 [ 2106.387214] [ 2106.387214] stack backtrace: [ 2106.391550] CPU: 7 PID: 2614 Comm: qtdemux0:sink Not tainted 4.14.0-rc2-00002-gfab205f-dirty #4 [ 2106.400213] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [ 2106.406285] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 2106.413995] [] (show_stack) from [] (dump_stack+0x98/0xc4) [ 2106.421187] [] (dump_stack) from [] (print_circular_bug+0x254/0x410) [ 2106.429245] [] (print_circular_bug) from [] (check_prev_add+0x468/0x938) [ 2106.437651] [] (check_prev_add) from [] (__lock_acquire+0x1314/0x14fc) [ 2106.445883] [] (__lock_acquire) from [] (lock_acquire+0x6c/0x88) [ 2106.453596] [] (lock_acquire) from [] (__mutex_lock+0x68/0xa34) [ 2106.461221] [] (__mutex_lock) from [] (mutex_lock_interruptible_nested+0x1c/0x24) [ 2106.470425] [] (mutex_lock_interruptible_nested) from [] (s5p_mfc_mmap+0x28/0xd4 [s5p_mfc]) [ 2106.480494] [] (s5p_mfc_mmap [s5p_mfc]) from [] (v4l2_mmap+0x54/0x88 [videodev]) [ 2106.489575] [] (v4l2_mmap [videodev]) from [] (mmap_region+0x3a8/0x638) [ 2106.497875] [] (mmap_region) from [] (do_mmap+0x330/0x3a4) [ 2106.505068] [] (do_mmap) from [] (vm_mmap_pgoff+0x90/0xb8) [ 2106.512260] [] (vm_mmap_pgoff) from [] (SyS_mmap_pgoff+0x90/0xc0) [ 2106.520059] [] (SyS_mmap_pgoff) from [] (ret_fast_syscall+0x0/0x28) Signed-off-by: Shuah Khan Suggested-by: Hans Verkuil Acked-by: Marek Szyprowski Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index cf68aed59e0d..1839a86cc2a5 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1043,12 +1043,9 @@ end: static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma) { struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data); - struct s5p_mfc_dev *dev = ctx->dev; unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; int ret; - if (mutex_lock_interruptible(&dev->mfc_mutex)) - return -ERESTARTSYS; if (offset < DST_QUEUE_OFF_BASE) { mfc_debug(2, "mmaping source\n"); ret = vb2_mmap(&ctx->vq_src, vma); @@ -1057,7 +1054,6 @@ static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT); ret = vb2_mmap(&ctx->vq_dst, vma); } - mutex_unlock(&dev->mfc_mutex); return ret; } -- cgit v1.2.3 From 38929ea9a45ea8fe7fba34c09ada267cc2c10545 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 3 Nov 2017 09:35:39 -0400 Subject: media: v4l2-ctrls: Don't validate BITMASK twice There is no need to repeat what check_range() does for us, i.e. BITMASK validation in v4l2_ctrl_new(). Signed-off-by: Andy Shevchenko Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index c230bd5c6558..cbb2ef43945f 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -2013,10 +2013,6 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, handler_set_err(hdl, err); return NULL; } - if (type == V4L2_CTRL_TYPE_BITMASK && ((def & ~max) || min || step)) { - handler_set_err(hdl, -ERANGE); - return NULL; - } if (is_array && (type == V4L2_CTRL_TYPE_BUTTON || type == V4L2_CTRL_TYPE_CTRL_CLASS)) { -- cgit v1.2.3 From eb0c19942288569e0ae492476534d5a485fb8ab4 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Thu, 2 Nov 2017 10:38:21 -0400 Subject: media: dib0700: fix invalid dvb_detach argument dvb_detach(arg) calls symbol_put_addr(arg), where arg should be a pointer to a function. Right now a pointer to state->dib7000p_ops is passed to dvb_detach(), which causes a BUG() in symbol_put_addr() as discovered by syzkaller. Pass state->dib7000p_ops.set_wbd_ref instead. ------------[ cut here ]------------ kernel BUG at kernel/module.c:1081! invalid opcode: 0000 [#1] PREEMPT SMP KASAN Modules linked in: CPU: 1 PID: 1151 Comm: kworker/1:1 Tainted: G W 4.14.0-rc1-42251-gebb2c2437d80 #224 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 Workqueue: usb_hub_wq hub_event task: ffff88006a336300 task.stack: ffff88006a7c8000 RIP: 0010:symbol_put_addr+0x54/0x60 kernel/module.c:1083 RSP: 0018:ffff88006a7ce210 EFLAGS: 00010246 RAX: 0000000000000000 RBX: ffff880062a8d190 RCX: 0000000000000000 RDX: dffffc0000000020 RSI: ffffffff85876d60 RDI: ffff880062a8d190 RBP: ffff88006a7ce218 R08: 1ffff1000d4f9c12 R09: 1ffff1000d4f9ae4 R10: 1ffff1000d4f9bed R11: 0000000000000000 R12: ffff880062a8d180 R13: 00000000ffffffed R14: ffff880062a8d190 R15: ffff88006947c000 FS: 0000000000000000(0000) GS:ffff88006c900000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f6416532000 CR3: 00000000632f5000 CR4: 00000000000006e0 Call Trace: stk7070p_frontend_attach+0x515/0x610 drivers/media/usb/dvb-usb/dib0700_devices.c:1013 dvb_usb_adapter_frontend_init+0x32b/0x660 drivers/media/usb/dvb-usb/dvb-usb-dvb.c:286 dvb_usb_adapter_init drivers/media/usb/dvb-usb/dvb-usb-init.c:86 dvb_usb_init drivers/media/usb/dvb-usb/dvb-usb-init.c:162 dvb_usb_device_init+0xf70/0x17f0 drivers/media/usb/dvb-usb/dvb-usb-init.c:277 dib0700_probe+0x171/0x5a0 drivers/media/usb/dvb-usb/dib0700_core.c:886 usb_probe_interface+0x35d/0x8e0 drivers/usb/core/driver.c:361 really_probe drivers/base/dd.c:413 driver_probe_device+0x610/0xa00 drivers/base/dd.c:557 __device_attach_driver+0x230/0x290 drivers/base/dd.c:653 bus_for_each_drv+0x161/0x210 drivers/base/bus.c:463 __device_attach+0x26e/0x3d0 drivers/base/dd.c:710 device_initial_probe+0x1f/0x30 drivers/base/dd.c:757 bus_probe_device+0x1eb/0x290 drivers/base/bus.c:523 device_add+0xd0b/0x1660 drivers/base/core.c:1835 usb_set_configuration+0x104e/0x1870 drivers/usb/core/message.c:1932 generic_probe+0x73/0xe0 drivers/usb/core/generic.c:174 usb_probe_device+0xaf/0xe0 drivers/usb/core/driver.c:266 really_probe drivers/base/dd.c:413 driver_probe_device+0x610/0xa00 drivers/base/dd.c:557 __device_attach_driver+0x230/0x290 drivers/base/dd.c:653 bus_for_each_drv+0x161/0x210 drivers/base/bus.c:463 __device_attach+0x26e/0x3d0 drivers/base/dd.c:710 device_initial_probe+0x1f/0x30 drivers/base/dd.c:757 bus_probe_device+0x1eb/0x290 drivers/base/bus.c:523 device_add+0xd0b/0x1660 drivers/base/core.c:1835 usb_new_device+0x7b8/0x1020 drivers/usb/core/hub.c:2457 hub_port_connect drivers/usb/core/hub.c:4903 hub_port_connect_change drivers/usb/core/hub.c:5009 port_event drivers/usb/core/hub.c:5115 hub_event+0x194d/0x3740 drivers/usb/core/hub.c:5195 process_one_work+0xc7f/0x1db0 kernel/workqueue.c:2119 worker_thread+0x221/0x1850 kernel/workqueue.c:2253 kthread+0x3a1/0x470 kernel/kthread.c:231 ret_from_fork+0x2a/0x40 arch/x86/entry/entry_64.S:431 Code: ff ff 48 85 c0 74 24 48 89 c7 e8 48 ea ff ff bf 01 00 00 00 e8 de 20 e3 ff 65 8b 05 b7 2f c2 7e 85 c0 75 c9 e8 f9 0b c1 ff eb c2 <0f> 0b 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 48 b8 00 00 RIP: symbol_put_addr+0x54/0x60 RSP: ffff88006a7ce210 ---[ end trace b75b357739e7e116 ]--- Signed-off-by: Andrey Konovalov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/dib0700_devices.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index 6020170fe99a..92098c1b78e5 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -291,7 +291,7 @@ static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap) stk7700d_dib7000p_mt2266_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } } @@ -325,7 +325,7 @@ static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) stk7700d_dib7000p_mt2266_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } } @@ -478,7 +478,7 @@ static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap) &stk7700ph_dib7700_xc3028_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } @@ -1010,7 +1010,7 @@ static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap) &dib7070p_dib7000p_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } @@ -1068,7 +1068,7 @@ static int stk7770p_frontend_attach(struct dvb_usb_adapter *adap) &dib7770p_dib7000p_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } @@ -3056,7 +3056,7 @@ static int nim7090_frontend_attach(struct dvb_usb_adapter *adap) if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &nim7090_dib7000p_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config); @@ -3109,7 +3109,7 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap) /* initialize IC 0 */ if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, &tfe7090pvr_dib7000p_config[0]) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } @@ -3139,7 +3139,7 @@ static int tfe7090pvr_frontend1_attach(struct dvb_usb_adapter *adap) i2c = state->dib7000p_ops.get_i2c_master(adap->dev->adapter[0].fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1); if (state->dib7000p_ops.i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } @@ -3214,7 +3214,7 @@ static int tfe7790p_frontend_attach(struct dvb_usb_adapter *adap) 1, 0x10, &tfe7790p_dib7000p_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, @@ -3309,7 +3309,7 @@ static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap) stk7070pd_dib7000p_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } @@ -3384,7 +3384,7 @@ static int novatd_frontend_attach(struct dvb_usb_adapter *adap) stk7070pd_dib7000p_config) != 0) { err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } } @@ -3620,7 +3620,7 @@ static int pctv340e_frontend_attach(struct dvb_usb_adapter *adap) if (state->dib7000p_ops.dib7000pc_detection(&adap->dev->i2c_adap) == 0) { /* Demodulator not found for some reason? */ - dvb_detach(&state->dib7000p_ops); + dvb_detach(state->dib7000p_ops.set_wbd_ref); return -ENODEV; } -- cgit v1.2.3 From b1cb7372fa822af6c06c8045963571d13ad6348b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 7 Nov 2017 08:39:39 -0500 Subject: dvb_frontend: don't use-after-free the frontend struct dvb_frontend_invoke_release() may free the frontend struct. So, the free logic can't update it anymore after calling it. That's OK, as __dvb_frontend_free() is called only when the krefs are zeroed, so nobody is using it anymore. That should fix the following KASAN error: The KASAN report looks like this (running on kernel 3e0cc09a3a2c40ec1ffb6b4e12da86e98feccb11 (4.14-rc5+)): ================================================================== BUG: KASAN: use-after-free in __dvb_frontend_free+0x113/0x120 Write of size 8 at addr ffff880067d45a00 by task kworker/0:1/24 CPU: 0 PID: 24 Comm: kworker/0:1 Not tainted 4.14.0-rc5-43687-g06ab8a23e0e6 #545 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 Workqueue: usb_hub_wq hub_event Call Trace: __dump_stack lib/dump_stack.c:16 dump_stack+0x292/0x395 lib/dump_stack.c:52 print_address_description+0x78/0x280 mm/kasan/report.c:252 kasan_report_error mm/kasan/report.c:351 kasan_report+0x23d/0x350 mm/kasan/report.c:409 __asan_report_store8_noabort+0x1c/0x20 mm/kasan/report.c:435 __dvb_frontend_free+0x113/0x120 drivers/media/dvb-core/dvb_frontend.c:156 dvb_frontend_put+0x59/0x70 drivers/media/dvb-core/dvb_frontend.c:176 dvb_frontend_detach+0x120/0x150 drivers/media/dvb-core/dvb_frontend.c:2803 dvb_usb_adapter_frontend_exit+0xd6/0x160 drivers/media/usb/dvb-usb/dvb-usb-dvb.c:340 dvb_usb_adapter_exit drivers/media/usb/dvb-usb/dvb-usb-init.c:116 dvb_usb_exit+0x9b/0x200 drivers/media/usb/dvb-usb/dvb-usb-init.c:132 dvb_usb_device_exit+0xa5/0xf0 drivers/media/usb/dvb-usb/dvb-usb-init.c:295 usb_unbind_interface+0x21c/0xa90 drivers/usb/core/driver.c:423 __device_release_driver drivers/base/dd.c:861 device_release_driver_internal+0x4f1/0x5c0 drivers/base/dd.c:893 device_release_driver+0x1e/0x30 drivers/base/dd.c:918 bus_remove_device+0x2f4/0x4b0 drivers/base/bus.c:565 device_del+0x5c4/0xab0 drivers/base/core.c:1985 usb_disable_device+0x1e9/0x680 drivers/usb/core/message.c:1170 usb_disconnect+0x260/0x7a0 drivers/usb/core/hub.c:2124 hub_port_connect drivers/usb/core/hub.c:4754 hub_port_connect_change drivers/usb/core/hub.c:5009 port_event drivers/usb/core/hub.c:5115 hub_event+0x1318/0x3740 drivers/usb/core/hub.c:5195 process_one_work+0xc73/0x1d90 kernel/workqueue.c:2119 worker_thread+0x221/0x1850 kernel/workqueue.c:2253 kthread+0x363/0x440 kernel/kthread.c:231 ret_from_fork+0x2a/0x40 arch/x86/entry/entry_64.S:431 Allocated by task 24: save_stack_trace+0x1b/0x20 arch/x86/kernel/stacktrace.c:59 save_stack+0x43/0xd0 mm/kasan/kasan.c:447 set_track mm/kasan/kasan.c:459 kasan_kmalloc+0xad/0xe0 mm/kasan/kasan.c:551 kmem_cache_alloc_trace+0x11e/0x2d0 mm/slub.c:2772 kmalloc ./include/linux/slab.h:493 kzalloc ./include/linux/slab.h:666 dtt200u_fe_attach+0x4c/0x110 drivers/media/usb/dvb-usb/dtt200u-fe.c:212 dtt200u_frontend_attach+0x35/0x80 drivers/media/usb/dvb-usb/dtt200u.c:136 dvb_usb_adapter_frontend_init+0x32b/0x660 drivers/media/usb/dvb-usb/dvb-usb-dvb.c:286 dvb_usb_adapter_init drivers/media/usb/dvb-usb/dvb-usb-init.c:86 dvb_usb_init drivers/media/usb/dvb-usb/dvb-usb-init.c:162 dvb_usb_device_init+0xf73/0x17f0 drivers/media/usb/dvb-usb/dvb-usb-init.c:277 dtt200u_usb_probe+0xa1/0xe0 drivers/media/usb/dvb-usb/dtt200u.c:155 usb_probe_interface+0x35d/0x8e0 drivers/usb/core/driver.c:361 really_probe drivers/base/dd.c:413 driver_probe_device+0x610/0xa00 drivers/base/dd.c:557 __device_attach_driver+0x230/0x290 drivers/base/dd.c:653 bus_for_each_drv+0x161/0x210 drivers/base/bus.c:463 __device_attach+0x26b/0x3c0 drivers/base/dd.c:710 device_initial_probe+0x1f/0x30 drivers/base/dd.c:757 bus_probe_device+0x1eb/0x290 drivers/base/bus.c:523 device_add+0xd0b/0x1660 drivers/base/core.c:1835 usb_set_configuration+0x104e/0x1870 drivers/usb/core/message.c:1932 generic_probe+0x73/0xe0 drivers/usb/core/generic.c:174 usb_probe_device+0xaf/0xe0 drivers/usb/core/driver.c:266 really_probe drivers/base/dd.c:413 driver_probe_device+0x610/0xa00 drivers/base/dd.c:557 __device_attach_driver+0x230/0x290 drivers/base/dd.c:653 bus_for_each_drv+0x161/0x210 drivers/base/bus.c:463 __device_attach+0x26b/0x3c0 drivers/base/dd.c:710 device_initial_probe+0x1f/0x30 drivers/base/dd.c:757 bus_probe_device+0x1eb/0x290 drivers/base/bus.c:523 device_add+0xd0b/0x1660 drivers/base/core.c:1835 usb_new_device+0x7b8/0x1020 drivers/usb/core/hub.c:2457 hub_port_connect drivers/usb/core/hub.c:4903 hub_port_connect_change drivers/usb/core/hub.c:5009 port_event drivers/usb/core/hub.c:5115 hub_event+0x194d/0x3740 drivers/usb/core/hub.c:5195 process_one_work+0xc73/0x1d90 kernel/workqueue.c:2119 worker_thread+0x221/0x1850 kernel/workqueue.c:2253 kthread+0x363/0x440 kernel/kthread.c:231 ret_from_fork+0x2a/0x40 arch/x86/entry/entry_64.S:431 Freed by task 24: save_stack_trace+0x1b/0x20 arch/x86/kernel/stacktrace.c:59 save_stack+0x43/0xd0 mm/kasan/kasan.c:447 set_track mm/kasan/kasan.c:459 kasan_slab_free+0x72/0xc0 mm/kasan/kasan.c:524 slab_free_hook mm/slub.c:1390 slab_free_freelist_hook mm/slub.c:1412 slab_free mm/slub.c:2988 kfree+0xf6/0x2f0 mm/slub.c:3919 dtt200u_fe_release+0x3c/0x50 drivers/media/usb/dvb-usb/dtt200u-fe.c:202 dvb_frontend_invoke_release.part.13+0x1c/0x30 drivers/media/dvb-core/dvb_frontend.c:2790 dvb_frontend_invoke_release drivers/media/dvb-core/dvb_frontend.c:2789 __dvb_frontend_free+0xad/0x120 drivers/media/dvb-core/dvb_frontend.c:153 dvb_frontend_put+0x59/0x70 drivers/media/dvb-core/dvb_frontend.c:176 dvb_frontend_detach+0x120/0x150 drivers/media/dvb-core/dvb_frontend.c:2803 dvb_usb_adapter_frontend_exit+0xd6/0x160 drivers/media/usb/dvb-usb/dvb-usb-dvb.c:340 dvb_usb_adapter_exit drivers/media/usb/dvb-usb/dvb-usb-init.c:116 dvb_usb_exit+0x9b/0x200 drivers/media/usb/dvb-usb/dvb-usb-init.c:132 dvb_usb_device_exit+0xa5/0xf0 drivers/media/usb/dvb-usb/dvb-usb-init.c:295 usb_unbind_interface+0x21c/0xa90 drivers/usb/core/driver.c:423 __device_release_driver drivers/base/dd.c:861 device_release_driver_internal+0x4f1/0x5c0 drivers/base/dd.c:893 device_release_driver+0x1e/0x30 drivers/base/dd.c:918 bus_remove_device+0x2f4/0x4b0 drivers/base/bus.c:565 device_del+0x5c4/0xab0 drivers/base/core.c:1985 usb_disable_device+0x1e9/0x680 drivers/usb/core/message.c:1170 usb_disconnect+0x260/0x7a0 drivers/usb/core/hub.c:2124 hub_port_connect drivers/usb/core/hub.c:4754 hub_port_connect_change drivers/usb/core/hub.c:5009 port_event drivers/usb/core/hub.c:5115 hub_event+0x1318/0x3740 drivers/usb/core/hub.c:5195 process_one_work+0xc73/0x1d90 kernel/workqueue.c:2119 worker_thread+0x221/0x1850 kernel/workqueue.c:2253 kthread+0x363/0x440 kernel/kthread.c:231 ret_from_fork+0x2a/0x40 arch/x86/entry/entry_64.S:431 The buggy address belongs to the object at ffff880067d45500 which belongs to the cache kmalloc-2048 of size 2048 The buggy address is located 1280 bytes inside of 2048-byte region [ffff880067d45500, ffff880067d45d00) The buggy address belongs to the page: page:ffffea00019f5000 count:1 mapcount:0 mapping: (null) index:0x0 compound_mapcount: 0 flags: 0x100000000008100(slab|head) raw: 0100000000008100 0000000000000000 0000000000000000 00000001000f000f raw: dead000000000100 dead000000000200 ffff88006c002d80 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff880067d45900: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff880067d45980: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff880067d45a00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ^ ffff880067d45a80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff880067d45b00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ================================================================== Fixes: ead666000a5f ("media: dvb_frontend: only use kref after initialized") Reported-by: Andrey Konovalov Suggested-by: Matthias Schwarzott Tested-by: Andrey Konovalov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index d485d5f6cc88..3ad83359098b 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -150,11 +150,8 @@ static void __dvb_frontend_free(struct dvb_frontend *fe) dvb_frontend_invoke_release(fe, fe->ops.release); - if (!fepriv) - return; - - kfree(fepriv); - fe->frontend_priv = NULL; + if (fepriv) + kfree(fepriv); } static void dvb_frontend_free(struct kref *ref) -- cgit v1.2.3