• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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