1 /*
2 *
3 * SPDX-License-Identifier: GPL-2.0
4 *
5 * Copyright (C) 2011-2018 ARM or its affiliates
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20 #include "system_interrupts.h"
21 #include "acamera_firmware_config.h"
22 #include <linux/kernel.h>
23 #include <linux/interrupt.h>
24 #include "acamera_logger.h"
25 #include "acamera_isp_config.h"
26 #include <linux/delay.h>
27
28 //#define ENABLE_BOTTOM_HALF_TASKLET
29
30 #ifdef ENABLE_BOTTOM_HALF_TASKLET
31 #include <linux/list.h>
32
33 #define ISP_TASKLET_Q_SIZE 16
34
35 // tasklet queue command structure
36 struct isp_tasklet_q_cmd {
37 struct list_head list;
38 uint32_t irq_status;
39 uint8_t cmd_used;
40 };
41
42 // tasklet structure
43 struct isp_tasklet_t {
44 // tasklet
45 atomic_t tasklet_irq_cnt;
46 spinlock_t tasklet_lock;
47 struct tasklet_struct tasklet_obj;
48 // tasklet q
49 uint8_t tasklet_q_idx;
50 struct list_head tasklet_q;
51 struct isp_tasklet_q_cmd tasklet_q_cmd[ISP_TASKLET_Q_SIZE];
52 };
53
54 // gloval variable for tasklet access
55 static struct isp_tasklet_t isp_tasklet;
56 static int temp_irq = 0;
57 #endif
58
59 typedef enum {
60 ISP_IRQ_STATUS_DEINIT = 0,
61 ISP_IRQ_STATUS_ENABLED,
62 ISP_IRQ_STATUS_DISABLED,
63 ISP_IRQ_STATUS_MAX
64 } irq_status;
65
66 static system_interrupt_handler_t app_handler = NULL;
67 static void *app_param = NULL;
68 static int interrupt_line_ACAMERA_JUNO_IRQ = -1;
69 static int interrupt_line_ACAMERA_JUNO_IRQ_FLAGS = -1;
70 static irq_status interrupt_request_status = ISP_IRQ_STATUS_DEINIT;
71 static const char dev_id[] = "isp_dev";
72
73 #ifdef ENABLE_BOTTOM_HALF_TASKLET
isp_do_tasklet(unsigned long data)74 void isp_do_tasklet( unsigned long data )
75 {
76 unsigned long flags;
77 uint32_t irq_status;
78 struct isp_tasklet_q_cmd *queue_cmd;
79
80 while ( atomic_read( &isp_tasklet.tasklet_irq_cnt ) ) {
81 spin_lock_irqsave( &isp_tasklet.tasklet_lock, flags );
82 queue_cmd = list_first_entry( &isp_tasklet.tasklet_q, struct isp_tasklet_q_cmd, list );
83 if ( !queue_cmd ) {
84 atomic_set( &isp_tasklet.tasklet_irq_cnt, 0 );
85 spin_unlock_irqrestore( &isp_tasklet.tasklet_lock, flags );
86 return;
87 }
88 atomic_sub( 1, &isp_tasklet.tasklet_irq_cnt );
89 list_del( &queue_cmd->list );
90 queue_cmd->cmd_used = 0;
91 irq_status = queue_cmd->irq_status;
92
93 spin_unlock_irqrestore( &isp_tasklet.tasklet_lock, flags );
94
95 LOG( LOG_INFO, "debug value on tasklet: 0x%x\n", irq_status );
96 }
97 }
98 #endif
system_interrupt_handler(int irq,void * dev_id)99 irqreturn_t system_interrupt_handler( int irq, void *dev_id )
100 {
101 #ifdef ENABLE_BOTTOM_HALF_TASKLET
102 unsigned long flags;
103 uint32_t irq_status;
104 struct isp_tasklet_q_cmd *queue_cmd;
105 irq_status = temp_irq++;
106 LOG( LOG_INFO, "debug value: 0x%x\n", irq_status );
107
108 spin_lock_irqsave( &isp_tasklet.tasklet_lock, flags );
109 queue_cmd = &isp_tasklet.tasklet_q_cmd[isp_tasklet.tasklet_q_idx];
110 if ( queue_cmd->cmd_used ) {
111 LOG( LOG_ERR, "Error: isp tasklet queue overflow !\n" );
112 list_del( &queue_cmd->list );
113 } else {
114 atomic_add( 1, &isp_tasklet.tasklet_irq_cnt );
115 }
116 queue_cmd->irq_status = irq_status;
117 queue_cmd->cmd_used = 1;
118 isp_tasklet.tasklet_q_idx =
119 ( isp_tasklet.tasklet_q_idx + 1 ) % ISP_TASKLET_Q_SIZE;
120 list_add_tail( &queue_cmd->list, &isp_tasklet.tasklet_q );
121 spin_unlock_irqrestore( &isp_tasklet.tasklet_lock, flags );
122
123 tasklet_schedule( &isp_tasklet.tasklet_obj );
124
125 if ( app_handler )
126 app_handler( app_param, 0 );
127 #else
128 //LOG( LOG_INFO, "interrupt comes in (irq = %d)\n", irq );
129 if ( app_handler )
130 app_handler( app_param, 0 );
131 #endif
132 if (!app_handler) {
133 u32 status_val = acamera_isp_isp_global_interrupt_status_vector_read(0);
134 u32 pulse_mode = acamera_isp_isp_global_interrupt_pulse_mode_read(0);
135
136 printk("interrupt comes in (irq = %d) without app handler, status: 0x%x, pusle mode:%d\n", irq, status_val, pulse_mode);
137
138 acamera_isp_isp_global_interrupt_clear_vector_write(0, 0xffffffff);
139 acamera_isp_isp_global_interrupt_clear_write( 0, 0 );
140 acamera_isp_isp_global_interrupt_clear_write( 0, 1 );
141 acamera_isp_isp_global_interrupt_clear_write( 0, 0 );
142 }
143 return IRQ_HANDLED;
144 }
145
system_interrupts_set_irq(int irq_num,int flags)146 void system_interrupts_set_irq( int irq_num, int flags )
147 {
148 interrupt_line_ACAMERA_JUNO_IRQ = irq_num;
149 interrupt_line_ACAMERA_JUNO_IRQ_FLAGS = IRQF_SHARED;//flags & IRQF_TRIGGER_MASK;
150 LOG( LOG_INFO, "interrupt id is set to %d\n", interrupt_line_ACAMERA_JUNO_IRQ );
151 }
152
system_interrupts_init(void)153 void system_interrupts_init( void )
154 {
155 int ret = 0;
156
157 if ( interrupt_line_ACAMERA_JUNO_IRQ < 0 ) {
158 LOG( LOG_ERR, "invalid irq id ! (id = %d)\n", interrupt_line_ACAMERA_JUNO_IRQ );
159 }
160
161 if ( interrupt_request_status != ISP_IRQ_STATUS_DEINIT ) {
162 LOG( LOG_WARNING, "irq %d is already initied (status = %d)",
163 interrupt_line_ACAMERA_JUNO_IRQ, interrupt_request_status );
164 return;
165 }
166 interrupt_request_status = ISP_IRQ_STATUS_ENABLED;
167
168 #ifdef ENABLE_BOTTOM_HALF_TASKLET
169 // init tasklet and tasklet_q
170 atomic_set( &isp_tasklet.tasklet_irq_cnt, 0 );
171 spin_lock_init( &isp_tasklet.tasklet_lock );
172 isp_tasklet.tasklet_q_idx = 0;
173 INIT_LIST_HEAD( &isp_tasklet.tasklet_q );
174 tasklet_init( &isp_tasklet.tasklet_obj, isp_do_tasklet, (unsigned long)&isp_tasklet );
175 #endif
176
177 // No dev_id for now, but will need this to be shared
178 if ( ( ret = request_irq( interrupt_line_ACAMERA_JUNO_IRQ,
179 &system_interrupt_handler, interrupt_line_ACAMERA_JUNO_IRQ_FLAGS, "isp", (void *)dev_id ) ) ) {
180 LOG( LOG_ERR, "Could not get interrupt %d (ret=%d)\n", interrupt_line_ACAMERA_JUNO_IRQ, ret );
181 } else {
182 LOG( LOG_INFO, "Interrupt %d requested (flags = 0x%x, ret = %d)\n",
183 interrupt_line_ACAMERA_JUNO_IRQ, interrupt_line_ACAMERA_JUNO_IRQ_FLAGS, ret );
184 }
185 }
186
system_interrupts_deinit(void)187 void system_interrupts_deinit( void )
188 {
189
190 if ( interrupt_request_status == ISP_IRQ_STATUS_DEINIT ) {
191 LOG( LOG_WARNING, "irq %d is already deinitied (status = %d)",
192 interrupt_line_ACAMERA_JUNO_IRQ, interrupt_request_status );
193 } else {
194 //interrupt_request_status = ISP_IRQ_STATUS_DISABLED;
195 interrupt_request_status = ISP_IRQ_STATUS_DEINIT;
196 // No dev_id for now, but will need this to be shared
197 free_irq( interrupt_line_ACAMERA_JUNO_IRQ, (void *)dev_id );
198 LOG( LOG_INFO, "Interrupt %d released\n", interrupt_line_ACAMERA_JUNO_IRQ );
199 }
200 app_handler = NULL;
201 app_param = NULL;
202
203 #ifdef ENABLE_BOTTOM_HALF_TASKLET
204 // kill tasklet
205 tasklet_kill( &isp_tasklet.tasklet_obj );
206 atomic_set( &isp_tasklet.tasklet_irq_cnt, 0 );
207 #endif
208 }
209
system_interrupt_set_handler(system_interrupt_handler_t handler,void * param)210 void system_interrupt_set_handler( system_interrupt_handler_t handler, void *param )
211 {
212 app_handler = handler;
213 app_param = param;
214 }
215
system_interrupts_enable(void)216 void system_interrupts_enable( void )
217 {
218 if ( interrupt_request_status == ISP_IRQ_STATUS_DISABLED ) {
219 enable_irq( interrupt_line_ACAMERA_JUNO_IRQ );
220 interrupt_request_status = ISP_IRQ_STATUS_ENABLED;
221 }
222 }
223
system_interrupts_disable(void)224 void system_interrupts_disable( void )
225 {
226 if ( interrupt_request_status == ISP_IRQ_STATUS_ENABLED ) {
227 disable_irq( interrupt_line_ACAMERA_JUNO_IRQ );
228 interrupt_request_status = ISP_IRQ_STATUS_DISABLED;
229 }
230 }
231