1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /**
3*4882a593Smuzhiyun * Rockchip rk1608 device driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) Rockchip Electronics Co., Ltd.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun #include <linux/of_platform.h>
9*4882a593Smuzhiyun #include <linux/ctype.h>
10*4882a593Smuzhiyun #include <media/v4l2-ctrls.h>
11*4882a593Smuzhiyun #include <media/v4l2-fwnode.h>
12*4882a593Smuzhiyun #include <media/v4l2-subdev.h>
13*4882a593Smuzhiyun #include <linux/compat.h>
14*4882a593Smuzhiyun #include <linux/rk-preisp.h>
15*4882a593Smuzhiyun #include "rk1608_dev.h"
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #define DEBUG_DUMP_ALL_SEND_RECV_MSG 0
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #define MSG_QUEUE_DEFAULT_SIZE (8 * 1024)
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun struct msg_queue {
22*4882a593Smuzhiyun u32 *buf_head; /* msg buffer head */
23*4882a593Smuzhiyun u32 *buf_tail; /* msg buffer tail */
24*4882a593Smuzhiyun u32 *cur_send; /* current msg send position */
25*4882a593Smuzhiyun u32 *cur_recv; /* current msg receive position */
26*4882a593Smuzhiyun };
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun struct rk1608_client {
29*4882a593Smuzhiyun s8 id;
30*4882a593Smuzhiyun struct msg_queue q;
31*4882a593Smuzhiyun struct list_head list;
32*4882a593Smuzhiyun wait_queue_head_t wait;
33*4882a593Smuzhiyun void *private_data;
34*4882a593Smuzhiyun };
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun enum {
37*4882a593Smuzhiyun AUTO_ARG_TYPE_STR,
38*4882a593Smuzhiyun AUTO_ARG_TYPE_INT32,
39*4882a593Smuzhiyun };
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun struct auto_arg {
42*4882a593Smuzhiyun int type;
43*4882a593Smuzhiyun union {
44*4882a593Smuzhiyun s32 m_int32;
45*4882a593Smuzhiyun const char *m_str;
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun };
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun struct auto_args {
50*4882a593Smuzhiyun int argc;
51*4882a593Smuzhiyun struct auto_arg *argv;
52*4882a593Smuzhiyun };
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun /**
55*4882a593Smuzhiyun * msq_init - Initialize msg queue
56*4882a593Smuzhiyun *
57*4882a593Smuzhiyun * @q: the msg queue to initialize
58*4882a593Smuzhiyun * @size: size of msg queue buf
59*4882a593Smuzhiyun *
60*4882a593Smuzhiyun * It returns zero on success, else a negative error code.
61*4882a593Smuzhiyun */
msq_init(struct msg_queue * q,int size)62*4882a593Smuzhiyun static int msq_init(struct msg_queue *q, int size)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun u32 *buf = kmalloc(size, GFP_KERNEL);
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun q->buf_head = buf;
67*4882a593Smuzhiyun q->buf_tail = buf + size / sizeof(u32);
68*4882a593Smuzhiyun q->cur_send = buf;
69*4882a593Smuzhiyun q->cur_recv = buf;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun return 0;
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun /**
75*4882a593Smuzhiyun * msq_release - release msg queue buf
76*4882a593Smuzhiyun *
77*4882a593Smuzhiyun * @q: the msg queue to release
78*4882a593Smuzhiyun */
msq_release(struct msg_queue * q)79*4882a593Smuzhiyun static void msq_release(struct msg_queue *q)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun kfree(q->buf_head);
82*4882a593Smuzhiyun q->buf_head = NULL;
83*4882a593Smuzhiyun q->buf_tail = NULL;
84*4882a593Smuzhiyun q->cur_send = NULL;
85*4882a593Smuzhiyun q->cur_recv = NULL;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun /**
89*4882a593Smuzhiyun * msq_is_empty - tests whether a msg queue is empty
90*4882a593Smuzhiyun *
91*4882a593Smuzhiyun * @q: the msg queue to test
92*4882a593Smuzhiyun *
93*4882a593Smuzhiyun * It returns true on msg queue is empty, else false.
94*4882a593Smuzhiyun */
msq_is_empty(const struct msg_queue * q)95*4882a593Smuzhiyun static int msq_is_empty(const struct msg_queue *q)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun return q->cur_send == q->cur_recv;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun /**
101*4882a593Smuzhiyun * msq_tail_free_size - get msg queue tail unused buf size
102*4882a593Smuzhiyun *
103*4882a593Smuzhiyun * @q: msg queue
104*4882a593Smuzhiyun *
105*4882a593Smuzhiyun * It returns size of msg queue tail unused buf size, unit 4 bytes
106*4882a593Smuzhiyun */
msq_tail_free_size(const struct msg_queue * q)107*4882a593Smuzhiyun static u32 msq_tail_free_size(const struct msg_queue *q)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun if (q->cur_send >= q->cur_recv)
110*4882a593Smuzhiyun return (q->buf_tail - q->cur_send);
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun return q->cur_recv - q->cur_send;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun /**
116*4882a593Smuzhiyun * msq_head_free_size - get msg queue head unused buf size
117*4882a593Smuzhiyun *
118*4882a593Smuzhiyun * @q: msg queue
119*4882a593Smuzhiyun *
120*4882a593Smuzhiyun * It returns size of msg queue head unused buf size, unit 4 bytes
121*4882a593Smuzhiyun */
msq_head_free_size(const struct msg_queue * q)122*4882a593Smuzhiyun static u32 msq_head_free_size(const struct msg_queue *q)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun if (q->cur_send >= q->cur_recv)
125*4882a593Smuzhiyun return (q->cur_recv - q->buf_head);
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun return 0;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun /**
131*4882a593Smuzhiyun * msq_send_msg - send a msg to msg queue
132*4882a593Smuzhiyun *
133*4882a593Smuzhiyun * @q: msg queue
134*4882a593Smuzhiyun * @m: a msg to queue
135*4882a593Smuzhiyun *
136*4882a593Smuzhiyun * It returns zero on success, else a negative error code.
137*4882a593Smuzhiyun */
msq_send_msg(struct msg_queue * q,const struct msg * m)138*4882a593Smuzhiyun static int msq_send_msg(struct msg_queue *q, const struct msg *m)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun int ret = 0;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun if (msq_tail_free_size(q) > m->size) {
143*4882a593Smuzhiyun u32 *next_send;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun memcpy(q->cur_send, m, m->size * sizeof(u32));
146*4882a593Smuzhiyun next_send = q->cur_send + m->size;
147*4882a593Smuzhiyun if (next_send == q->buf_tail)
148*4882a593Smuzhiyun next_send = q->buf_head;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun q->cur_send = next_send;
151*4882a593Smuzhiyun } else if (msq_head_free_size(q) > m->size) {
152*4882a593Smuzhiyun *q->cur_send = 0; /* set size to 0 for skip to head mark */
153*4882a593Smuzhiyun memcpy(q->buf_head, m, m->size * sizeof(u32));
154*4882a593Smuzhiyun q->cur_send = q->buf_head + m->size;
155*4882a593Smuzhiyun } else {
156*4882a593Smuzhiyun ret = -1;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun return ret;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun /**
163*4882a593Smuzhiyun * msq_recv_msg - receive a msg from msg queue
164*4882a593Smuzhiyun *
165*4882a593Smuzhiyun * @q: msg queue
166*4882a593Smuzhiyun * @m: a msg pointer buf [out]
167*4882a593Smuzhiyun *
168*4882a593Smuzhiyun * need call msq_recv_msg_free to free msg after msg use done
169*4882a593Smuzhiyun *
170*4882a593Smuzhiyun * It returns zero on success, else a negative error code.
171*4882a593Smuzhiyun */
msq_recv_msg(struct msg_queue * q,struct msg ** m)172*4882a593Smuzhiyun static int msq_recv_msg(struct msg_queue *q, struct msg **m)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun *m = NULL;
175*4882a593Smuzhiyun if (msq_is_empty(q))
176*4882a593Smuzhiyun return -1;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /* skip to head when size is 0 */
179*4882a593Smuzhiyun if (*q->cur_recv == 0)
180*4882a593Smuzhiyun *m = (struct msg *)q->buf_head;
181*4882a593Smuzhiyun else
182*4882a593Smuzhiyun *m = (struct msg *)q->cur_recv;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun return 0;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun /**
188*4882a593Smuzhiyun * msq_free_received_msg - free a received msg to msg queue
189*4882a593Smuzhiyun *
190*4882a593Smuzhiyun * @q: msg queue
191*4882a593Smuzhiyun * @m: a msg
192*4882a593Smuzhiyun *
193*4882a593Smuzhiyun * It returns zero on success, else a negative error code.
194*4882a593Smuzhiyun */
msq_free_received_msg(struct msg_queue * q,const struct msg * m)195*4882a593Smuzhiyun static int msq_free_received_msg(struct msg_queue *q, const struct msg *m)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun /* skip to head when size is 0 */
198*4882a593Smuzhiyun if (*q->cur_recv == 0) {
199*4882a593Smuzhiyun q->cur_recv = q->buf_head + m->size;
200*4882a593Smuzhiyun } else {
201*4882a593Smuzhiyun u32 *next_recv;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun next_recv = q->cur_recv + m->size;
204*4882a593Smuzhiyun if (next_recv == q->buf_tail)
205*4882a593Smuzhiyun next_recv = q->buf_head;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun q->cur_recv = next_recv;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun return 0;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun
rk1608_client_list_init(struct rk1608_client_list * s)213*4882a593Smuzhiyun static void rk1608_client_list_init(struct rk1608_client_list *s)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun mutex_init(&s->mutex);
216*4882a593Smuzhiyun INIT_LIST_HEAD(&s->list);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
rk1608_client_new(void)219*4882a593Smuzhiyun static struct rk1608_client *rk1608_client_new(void)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun struct rk1608_client *c = kzalloc(sizeof(*c), GFP_KERNEL);
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun if (!c)
224*4882a593Smuzhiyun return NULL;
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun c->id = INVALID_ID;
227*4882a593Smuzhiyun INIT_LIST_HEAD(&c->list);
228*4882a593Smuzhiyun msq_init(&c->q, MSG_QUEUE_DEFAULT_SIZE);
229*4882a593Smuzhiyun init_waitqueue_head(&c->wait);
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun return c;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
rk1608_client_release(struct rk1608_client * c)234*4882a593Smuzhiyun static void rk1608_client_release(struct rk1608_client *c)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun msq_release(&c->q);
237*4882a593Smuzhiyun kfree(c);
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun static struct rk1608_client *
rk1608_client_find(struct rk1608_client_list * s,struct rk1608_client * c)241*4882a593Smuzhiyun rk1608_client_find(struct rk1608_client_list *s,
242*4882a593Smuzhiyun struct rk1608_client *c)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun struct rk1608_client *client = NULL;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun list_for_each_entry(client, &s->list, list) {
247*4882a593Smuzhiyun if (c == client)
248*4882a593Smuzhiyun return c;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun return NULL;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
rk1608_client_connect(struct rk1608_state * pdata,struct rk1608_client * c)254*4882a593Smuzhiyun static int rk1608_client_connect(struct rk1608_state *pdata,
255*4882a593Smuzhiyun struct rk1608_client *c)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun struct rk1608_client_list *s = &pdata->clients;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun mutex_lock(&s->mutex);
260*4882a593Smuzhiyun if (rk1608_client_find(s, c)) {
261*4882a593Smuzhiyun mutex_unlock(&s->mutex);
262*4882a593Smuzhiyun return -1;
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun list_add_tail(&c->list, &s->list);
266*4882a593Smuzhiyun mutex_unlock(&s->mutex);
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun return 0;
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
rk1608_client_disconnect(struct rk1608_state * pdata,struct rk1608_client * c)271*4882a593Smuzhiyun static void rk1608_client_disconnect(struct rk1608_state *pdata,
272*4882a593Smuzhiyun struct rk1608_client *c)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun struct rk1608_client_list *s = &pdata->clients;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun mutex_lock(&s->mutex);
277*4882a593Smuzhiyun if (rk1608_client_find(s, c))
278*4882a593Smuzhiyun list_del_init(&c->list);
279*4882a593Smuzhiyun mutex_unlock(&s->mutex);
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
parse_arg(const char * s,struct auto_arg * arg)282*4882a593Smuzhiyun static int parse_arg(const char *s, struct auto_arg *arg)
283*4882a593Smuzhiyun {
284*4882a593Smuzhiyun if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
285*4882a593Smuzhiyun long v;
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun v = simple_strtol(s, NULL, 16);
288*4882a593Smuzhiyun arg->type = AUTO_ARG_TYPE_INT32;
289*4882a593Smuzhiyun arg->m_int32 = v;
290*4882a593Smuzhiyun } else if (isdigit(s[0])) {
291*4882a593Smuzhiyun long v;
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun v = simple_strtol(s, NULL, 10);
294*4882a593Smuzhiyun arg->type = AUTO_ARG_TYPE_INT32;
295*4882a593Smuzhiyun arg->m_int32 = v;
296*4882a593Smuzhiyun } else {
297*4882a593Smuzhiyun arg->type = AUTO_ARG_TYPE_STR;
298*4882a593Smuzhiyun arg->m_str = s;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun return 0;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun
parse_auto_args(char * s,struct auto_args * args)304*4882a593Smuzhiyun static int parse_auto_args(char *s, struct auto_args *args)
305*4882a593Smuzhiyun {
306*4882a593Smuzhiyun int i = 0;
307*4882a593Smuzhiyun char c = 0;
308*4882a593Smuzhiyun int last_is_arg_flag = 0;
309*4882a593Smuzhiyun const char *last_arg;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun args->argc = 0;
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun i = -1;
314*4882a593Smuzhiyun do {
315*4882a593Smuzhiyun c = s[++i];
316*4882a593Smuzhiyun if (c == ' ' || c == ',' || c == '\n' || c == '\r' || c == 0) {
317*4882a593Smuzhiyun if (last_is_arg_flag)
318*4882a593Smuzhiyun args->argc++;
319*4882a593Smuzhiyun
320*4882a593Smuzhiyun last_is_arg_flag = 0;
321*4882a593Smuzhiyun } else {
322*4882a593Smuzhiyun last_is_arg_flag = 1;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun } while (c != 0 && c != '\n' && c != '\r');
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun args->argv =
327*4882a593Smuzhiyun kmalloc_array(args->argc, sizeof(struct auto_arg), GFP_KERNEL);
328*4882a593Smuzhiyun if (!args->argv)
329*4882a593Smuzhiyun return -ENOMEM;
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun i = -1;
332*4882a593Smuzhiyun last_is_arg_flag = 0;
333*4882a593Smuzhiyun last_arg = s;
334*4882a593Smuzhiyun args->argc = 0;
335*4882a593Smuzhiyun do {
336*4882a593Smuzhiyun c = s[++i];
337*4882a593Smuzhiyun if (c == ' ' || c == ',' || c == '\n' || c == '\r' || c == 0) {
338*4882a593Smuzhiyun if (last_is_arg_flag) {
339*4882a593Smuzhiyun parse_arg(last_arg, args->argv + args->argc++);
340*4882a593Smuzhiyun s[i] = 0;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun last_is_arg_flag = 0;
343*4882a593Smuzhiyun } else {
344*4882a593Smuzhiyun if (last_is_arg_flag == 0)
345*4882a593Smuzhiyun last_arg = s + i;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun last_is_arg_flag = 1;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun } while (c != 0 && c != '\n' && c != '\r');
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun return c == 0 ? i : i + 1;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun
free_auto_args(struct auto_args * args)354*4882a593Smuzhiyun static void free_auto_args(struct auto_args *args)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun kfree(args->argv);
357*4882a593Smuzhiyun args->argv = NULL;
358*4882a593Smuzhiyun args->argc = 0;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun
int32_hexdump(const char * prefix,s32 * data,int len)361*4882a593Smuzhiyun static void int32_hexdump(const char *prefix, s32 *data, int len)
362*4882a593Smuzhiyun {
363*4882a593Smuzhiyun pr_err("%s\n", prefix);
364*4882a593Smuzhiyun print_hex_dump(KERN_ERR, "offset ", DUMP_PREFIX_OFFSET,
365*4882a593Smuzhiyun 16, 4, data, len, false);
366*4882a593Smuzhiyun pr_err("\n");
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
do_cmd_write(struct rk1608_state * pdata,const struct auto_args * args)369*4882a593Smuzhiyun static int do_cmd_write(struct rk1608_state *pdata,
370*4882a593Smuzhiyun const struct auto_args *args)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun s32 addr;
373*4882a593Smuzhiyun s32 len = (args->argc - 2) * sizeof(s32);
374*4882a593Smuzhiyun s32 *data;
375*4882a593Smuzhiyun int i;
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun if (args->argc < 3 || args->argv[1].type != AUTO_ARG_TYPE_INT32) {
378*4882a593Smuzhiyun dev_err(pdata->dev, "Mis or unknown args!\n");
379*4882a593Smuzhiyun return -1;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun len = MIN(len, RK1608_MAX_OP_BYTES);
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun addr = args->argv[1].m_int32;
385*4882a593Smuzhiyun data = kmalloc(len, GFP_KERNEL);
386*4882a593Smuzhiyun if (!data)
387*4882a593Smuzhiyun return -ENOMEM;
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun for (i = 0; i < len / 4; i++) {
390*4882a593Smuzhiyun if (args->argv[i + 2].type != AUTO_ARG_TYPE_INT32) {
391*4882a593Smuzhiyun dev_err(pdata->dev, "Unknown args!\n");
392*4882a593Smuzhiyun kfree(data);
393*4882a593Smuzhiyun return -1;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun data[i] = args->argv[i + 2].m_int32;
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun rk1608_write(pdata->spi, addr, data, len);
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun kfree(data);
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun dev_info(pdata->dev, "write addr: 0x%x, len: %d bytes\n", addr, len);
404*4882a593Smuzhiyun return 0;
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun
do_cmd_read(struct rk1608_state * pdata,const struct auto_args * args)407*4882a593Smuzhiyun static int do_cmd_read(struct rk1608_state *pdata,
408*4882a593Smuzhiyun const struct auto_args *args)
409*4882a593Smuzhiyun {
410*4882a593Smuzhiyun s32 addr;
411*4882a593Smuzhiyun s32 len;
412*4882a593Smuzhiyun s32 *data;
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun if (args->argc < 3 || args->argv[1].type != AUTO_ARG_TYPE_INT32) {
415*4882a593Smuzhiyun dev_err(pdata->dev, "Mis or unknown args!\n");
416*4882a593Smuzhiyun return -1;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun addr = args->argv[1].m_int32;
420*4882a593Smuzhiyun if (args->argc == 2) {
421*4882a593Smuzhiyun len = 32;
422*4882a593Smuzhiyun } else {
423*4882a593Smuzhiyun if (args->argv[2].type != AUTO_ARG_TYPE_INT32) {
424*4882a593Smuzhiyun dev_err(pdata->dev, "Unknown args!\n");
425*4882a593Smuzhiyun return -1;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun len = args->argv[2].m_int32 * sizeof(s32);
428*4882a593Smuzhiyun len = MIN(len, RK1608_MAX_OP_BYTES);
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun data = kmalloc(len, GFP_KERNEL);
432*4882a593Smuzhiyun if (!data)
433*4882a593Smuzhiyun return -ENOMEM;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun dev_info(pdata->dev, "\nread addr: %x, len: %d bytes\n", addr, len);
436*4882a593Smuzhiyun rk1608_read(pdata->spi, addr, data, len);
437*4882a593Smuzhiyun int32_hexdump("read data:", data, len);
438*4882a593Smuzhiyun kfree(data);
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun return 0;
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun
do_cmd_set_spi_rate(struct rk1608_state * pdata,const struct auto_args * args)443*4882a593Smuzhiyun static int do_cmd_set_spi_rate(struct rk1608_state *pdata,
444*4882a593Smuzhiyun const struct auto_args *args)
445*4882a593Smuzhiyun {
446*4882a593Smuzhiyun if (args->argc < 2 || args->argv[1].type != AUTO_ARG_TYPE_INT32) {
447*4882a593Smuzhiyun dev_err(pdata->dev, "Mis or unknown args!\n");
448*4882a593Smuzhiyun return -1;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun pdata->max_speed_hz = args->argv[1].m_int32;
452*4882a593Smuzhiyun dev_info(pdata->dev, "set spi max speed to %d!\n", pdata->max_speed_hz);
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun if (args->argc == 3 && args->argv[2].type == AUTO_ARG_TYPE_INT32) {
455*4882a593Smuzhiyun pdata->min_speed_hz = args->argv[2].m_int32;
456*4882a593Smuzhiyun dev_info(pdata->dev, "set spi min speed to %d!\n",
457*4882a593Smuzhiyun pdata->min_speed_hz);
458*4882a593Smuzhiyun }
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun return 0;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun
do_cmd_query(struct rk1608_state * pdata,const struct auto_args * args)463*4882a593Smuzhiyun static int do_cmd_query(struct rk1608_state *pdata,
464*4882a593Smuzhiyun const struct auto_args *args)
465*4882a593Smuzhiyun {
466*4882a593Smuzhiyun s32 state;
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun rk1608_operation_query(pdata->spi, &state);
469*4882a593Smuzhiyun dev_info(pdata->dev, "state %x\n", state);
470*4882a593Smuzhiyun return 0;
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun
do_cmd_download_fw(struct rk1608_state * pdata,const struct auto_args * args)473*4882a593Smuzhiyun static int do_cmd_download_fw(struct rk1608_state *pdata,
474*4882a593Smuzhiyun const struct auto_args *args)
475*4882a593Smuzhiyun {
476*4882a593Smuzhiyun int ret = 0;
477*4882a593Smuzhiyun const char *fw_name = NULL;
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun if (args->argc == 2 && args->argv[1].type == AUTO_ARG_TYPE_STR)
480*4882a593Smuzhiyun fw_name = args->argv[1].m_str;
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun ret = rk1608_download_fw(pdata, pdata->spi, fw_name);
483*4882a593Smuzhiyun if (ret)
484*4882a593Smuzhiyun dev_err(pdata->dev, "download firmware failed!\n");
485*4882a593Smuzhiyun else
486*4882a593Smuzhiyun dev_info(pdata->dev, "download firmware success!\n");
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun return 0;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun
do_cmd_fast_write(struct rk1608_state * pdata,const struct auto_args * args)491*4882a593Smuzhiyun static int do_cmd_fast_write(struct rk1608_state *pdata,
492*4882a593Smuzhiyun const struct auto_args *args)
493*4882a593Smuzhiyun {
494*4882a593Smuzhiyun int ret = 0;
495*4882a593Smuzhiyun s32 reg;
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun if (args->argc != 2 || args->argv[1].type != AUTO_ARG_TYPE_INT32) {
498*4882a593Smuzhiyun dev_err(pdata->dev, "Mis or unknown args!\n");
499*4882a593Smuzhiyun return -1;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun reg = args->argv[1].m_int32;
503*4882a593Smuzhiyun
504*4882a593Smuzhiyun ret = rk1608_interrupt_request(pdata->spi, reg);
505*4882a593Smuzhiyun dev_info(pdata->dev, "interrupt request reg1:%x ret:%x\n", reg, ret);
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun return 0;
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun
do_cmd_fast_read(struct rk1608_state * pdata,const struct auto_args * args)510*4882a593Smuzhiyun static int do_cmd_fast_read(struct rk1608_state *pdata,
511*4882a593Smuzhiyun const struct auto_args *args)
512*4882a593Smuzhiyun {
513*4882a593Smuzhiyun s32 state;
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun rk1608_state_query(pdata->spi, &state);
516*4882a593Smuzhiyun dev_info(pdata->dev, "dsp state %x\n", state);
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun return 0;
519*4882a593Smuzhiyun }
520*4882a593Smuzhiyun
do_cmd_send_msg(struct rk1608_state * pdata,const struct auto_args * args)521*4882a593Smuzhiyun static int do_cmd_send_msg(struct rk1608_state *pdata,
522*4882a593Smuzhiyun const struct auto_args *args)
523*4882a593Smuzhiyun {
524*4882a593Smuzhiyun struct msg *m;
525*4882a593Smuzhiyun int ret = 0;
526*4882a593Smuzhiyun int msg_len;
527*4882a593Smuzhiyun u32 i = 0;
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun if (args->argc < 2) {
530*4882a593Smuzhiyun dev_err(pdata->dev, "need more args\n");
531*4882a593Smuzhiyun return -1;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun msg_len = args->argc * sizeof(u32);
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun m = kmalloc(msg_len, GFP_KERNEL);
537*4882a593Smuzhiyun if (!m)
538*4882a593Smuzhiyun return -ENOMEM;
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun m->size = msg_len / 4;
541*4882a593Smuzhiyun for (i = 1; i < m->size; i++) {
542*4882a593Smuzhiyun if (args->argv[i].type != AUTO_ARG_TYPE_INT32) {
543*4882a593Smuzhiyun dev_err(pdata->dev, "Unknown args!\n");
544*4882a593Smuzhiyun kfree(m);
545*4882a593Smuzhiyun return -1;
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun *((s32 *)m + i) = args->argv[i].m_int32;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun ret = rk1608_send_msg_to_dsp(pdata, m);
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun dev_info(pdata->dev, "send msg len: %d, ret: %x\n", m->size, ret);
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun kfree(m);
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun return 0;
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun
do_cmd_recv_msg(struct rk1608_state * pdata,const struct auto_args * args)560*4882a593Smuzhiyun static int do_cmd_recv_msg(struct rk1608_state *pdata,
561*4882a593Smuzhiyun const struct auto_args *args)
562*4882a593Smuzhiyun {
563*4882a593Smuzhiyun struct msg *m;
564*4882a593Smuzhiyun char buf[256] = "";
565*4882a593Smuzhiyun int ret = 0;
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun ret = rk1608_msq_recv_msg(pdata, pdata->spi, &m);
568*4882a593Smuzhiyun if (ret || !m)
569*4882a593Smuzhiyun return 0;
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun dev_info(pdata->dev, "\nrecv msg len: %d, ret: %x\n", m->size, ret);
572*4882a593Smuzhiyun int32_hexdump("recv msg:", (s32 *)m, m->size * 4);
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun dev_info(pdata->dev, buf);
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun kfree(m);
577*4882a593Smuzhiyun
578*4882a593Smuzhiyun return 0;
579*4882a593Smuzhiyun }
580*4882a593Smuzhiyun
do_cmd_power_on(struct rk1608_state * pdata,const struct auto_args * args)581*4882a593Smuzhiyun static int do_cmd_power_on(struct rk1608_state *pdata,
582*4882a593Smuzhiyun const struct auto_args *args)
583*4882a593Smuzhiyun {
584*4882a593Smuzhiyun int ret;
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun ret = rk1608_set_power(pdata, 1);
587*4882a593Smuzhiyun dev_info(pdata->dev, "do cmd power on, count++\n");
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun return ret;
590*4882a593Smuzhiyun }
591*4882a593Smuzhiyun
do_cmd_power_off(struct rk1608_state * pdata,const struct auto_args * args)592*4882a593Smuzhiyun static int do_cmd_power_off(struct rk1608_state *pdata,
593*4882a593Smuzhiyun const struct auto_args *args)
594*4882a593Smuzhiyun {
595*4882a593Smuzhiyun int ret;
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun ret = rk1608_set_power(pdata, 0);
598*4882a593Smuzhiyun dev_info(pdata->dev, "do cmd power off, count--\n");
599*4882a593Smuzhiyun
600*4882a593Smuzhiyun return ret;
601*4882a593Smuzhiyun }
602*4882a593Smuzhiyun
do_cmd_set_dsp_log_level(struct rk1608_state * pdata,const struct auto_args * args)603*4882a593Smuzhiyun static int do_cmd_set_dsp_log_level(struct rk1608_state *pdata,
604*4882a593Smuzhiyun const struct auto_args *args)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun int ret;
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun if (args->argc != 2 || args->argv[1].type != AUTO_ARG_TYPE_INT32) {
609*4882a593Smuzhiyun dev_err(pdata->dev, "Mis or unknown args!\n");
610*4882a593Smuzhiyun return -1;
611*4882a593Smuzhiyun }
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun pdata->log_level = args->argv[1].m_int32;
614*4882a593Smuzhiyun ret = rk1608_set_log_level(pdata, pdata->log_level);
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun dev_info(pdata->dev, "set dsp log level %d, ret: %d\n",
617*4882a593Smuzhiyun pdata->log_level, ret);
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun return ret;
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun
do_cmd_version(struct rk1608_state * pdata,const struct auto_args * args)622*4882a593Smuzhiyun static int do_cmd_version(struct rk1608_state *pdata,
623*4882a593Smuzhiyun const struct auto_args *args)
624*4882a593Smuzhiyun {
625*4882a593Smuzhiyun dev_info(pdata->dev, "driver version: v%02x.%02x.%02x\n",
626*4882a593Smuzhiyun RK1608_VERSION >> 16,
627*4882a593Smuzhiyun (RK1608_VERSION & 0xff00) >> 8,
628*4882a593Smuzhiyun RK1608_VERSION & 0x00ff);
629*4882a593Smuzhiyun return 0;
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun
do_cmd_help(struct rk1608_state * pdata)632*4882a593Smuzhiyun static int do_cmd_help(struct rk1608_state *pdata)
633*4882a593Smuzhiyun {
634*4882a593Smuzhiyun dev_info(pdata->dev, "\n"
635*4882a593Smuzhiyun "support debug commands:\n"
636*4882a593Smuzhiyun "v -- rk1608 driver version.\n"
637*4882a593Smuzhiyun "log level -- set rk1608 log level.\n"
638*4882a593Smuzhiyun "on -- power count + 1.\n"
639*4882a593Smuzhiyun "off -- power count - 1.\n"
640*4882a593Smuzhiyun "f [fw_name] -- download fw.\n"
641*4882a593Smuzhiyun "q -- query operation status.\n"
642*4882a593Smuzhiyun "r addr [length=32] -- read addr.\n"
643*4882a593Smuzhiyun "w addr value,... -- write addr.\n"
644*4882a593Smuzhiyun "s type,... -- send msg.\n"
645*4882a593Smuzhiyun "rate max [min] -- set spi speed.\n\n");
646*4882a593Smuzhiyun return 0;
647*4882a593Smuzhiyun }
648*4882a593Smuzhiyun
do_cmd(struct rk1608_state * pdata,const struct auto_args * args)649*4882a593Smuzhiyun static int do_cmd(struct rk1608_state *pdata, const struct auto_args *args)
650*4882a593Smuzhiyun {
651*4882a593Smuzhiyun const char *s;
652*4882a593Smuzhiyun
653*4882a593Smuzhiyun if (args->argv->type != AUTO_ARG_TYPE_STR)
654*4882a593Smuzhiyun return 0;
655*4882a593Smuzhiyun
656*4882a593Smuzhiyun s = args->argv->m_str;
657*4882a593Smuzhiyun /* echo c > /dev/rk_preisp */
658*4882a593Smuzhiyun if (!strcmp(s, "c"))
659*4882a593Smuzhiyun return do_cmd_recv_msg(pdata, args);
660*4882a593Smuzhiyun /* echo f [fw_name] > /dev/rk_preisp */
661*4882a593Smuzhiyun if (!strcmp(s, "f"))
662*4882a593Smuzhiyun return do_cmd_download_fw(pdata, args);
663*4882a593Smuzhiyun /* echo fw reg1 > /dev/rk_preisp */
664*4882a593Smuzhiyun if (!strcmp(s, "fw"))
665*4882a593Smuzhiyun return do_cmd_fast_write(pdata, args);
666*4882a593Smuzhiyun /* echo fr > /dev/rk_preisp */
667*4882a593Smuzhiyun if (!strcmp(s, "fr"))
668*4882a593Smuzhiyun return do_cmd_fast_read(pdata, args);
669*4882a593Smuzhiyun /* echo log level > /dev/rk_preisp */
670*4882a593Smuzhiyun if (!strcmp(s, "log"))
671*4882a593Smuzhiyun return do_cmd_set_dsp_log_level(pdata, args);
672*4882a593Smuzhiyun /* echo on > /dev/rk_preisp */
673*4882a593Smuzhiyun if (!strcmp(s, "on"))
674*4882a593Smuzhiyun return do_cmd_power_on(pdata, args);
675*4882a593Smuzhiyun /* echo off > /dev/rk_preisp */
676*4882a593Smuzhiyun if (!strcmp(s, "off"))
677*4882a593Smuzhiyun return do_cmd_power_off(pdata, args);
678*4882a593Smuzhiyun /* echo q > /dev/rk_preisp */
679*4882a593Smuzhiyun if (!strcmp(s, "q"))
680*4882a593Smuzhiyun return do_cmd_query(pdata, args);
681*4882a593Smuzhiyun /* echo r addr [length] > /dev/rk_preisp */
682*4882a593Smuzhiyun if (!strcmp(s, "r"))
683*4882a593Smuzhiyun return do_cmd_read(pdata, args);
684*4882a593Smuzhiyun /* echo rate > /dev/rk_preisp */
685*4882a593Smuzhiyun if (!strcmp(s, "rate"))
686*4882a593Smuzhiyun return do_cmd_set_spi_rate(pdata, args);
687*4882a593Smuzhiyun /* echo s type,... > /dev/rk_preisp */
688*4882a593Smuzhiyun if (!strcmp(s, "s"))
689*4882a593Smuzhiyun return do_cmd_send_msg(pdata, args);
690*4882a593Smuzhiyun /* echo v > /dev/rk_preisp */
691*4882a593Smuzhiyun if (!strcmp(s, "v"))
692*4882a593Smuzhiyun return do_cmd_version(pdata, args);
693*4882a593Smuzhiyun /* echo w addr value,... > /dev/rk_preisp */
694*4882a593Smuzhiyun if (!strcmp(s, "w"))
695*4882a593Smuzhiyun return do_cmd_write(pdata, args);
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun dev_err(pdata->dev, "unknown commands:%s\n", s);
698*4882a593Smuzhiyun do_cmd_help(pdata);
699*4882a593Smuzhiyun
700*4882a593Smuzhiyun return 0;
701*4882a593Smuzhiyun }
702*4882a593Smuzhiyun
rk1608_dev_open(struct inode * inode,struct file * file)703*4882a593Smuzhiyun static int rk1608_dev_open(struct inode *inode, struct file *file)
704*4882a593Smuzhiyun {
705*4882a593Smuzhiyun struct rk1608_state *pdata =
706*4882a593Smuzhiyun container_of(file->private_data, struct rk1608_state, misc);
707*4882a593Smuzhiyun struct rk1608_client *client = rk1608_client_new();
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun client->private_data = pdata;
710*4882a593Smuzhiyun file->private_data = client;
711*4882a593Smuzhiyun
712*4882a593Smuzhiyun rk1608_set_power(pdata, 1);
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun return 0;
715*4882a593Smuzhiyun }
716*4882a593Smuzhiyun
rk1608_dev_release(struct inode * inode,struct file * file)717*4882a593Smuzhiyun static int rk1608_dev_release(struct inode *inode, struct file *file)
718*4882a593Smuzhiyun {
719*4882a593Smuzhiyun struct rk1608_client *client = file->private_data;
720*4882a593Smuzhiyun struct rk1608_state *pdata = client->private_data;
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun rk1608_client_disconnect(pdata, client);
723*4882a593Smuzhiyun rk1608_client_release(client);
724*4882a593Smuzhiyun rk1608_set_power(pdata, 0);
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun return 0;
727*4882a593Smuzhiyun }
728*4882a593Smuzhiyun
rk1608_dev_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)729*4882a593Smuzhiyun static ssize_t rk1608_dev_write(struct file *file, const char __user *user_buf,
730*4882a593Smuzhiyun size_t count, loff_t *ppos)
731*4882a593Smuzhiyun {
732*4882a593Smuzhiyun char *buf;
733*4882a593Smuzhiyun struct auto_args args;
734*4882a593Smuzhiyun int i;
735*4882a593Smuzhiyun struct rk1608_client *client = file->private_data;
736*4882a593Smuzhiyun struct rk1608_state *pdata = client->private_data;
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun buf = kmalloc(count + 1, GFP_KERNEL);
739*4882a593Smuzhiyun if (!buf)
740*4882a593Smuzhiyun return -ENOMEM;
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun if (copy_from_user(buf, user_buf, count))
743*4882a593Smuzhiyun return -EFAULT;
744*4882a593Smuzhiyun
745*4882a593Smuzhiyun buf[count] = 0;
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun i = 0;
748*4882a593Smuzhiyun while (buf[i] != 0) {
749*4882a593Smuzhiyun int ret = parse_auto_args(buf + i, &args);
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun if (ret < 0)
752*4882a593Smuzhiyun break;
753*4882a593Smuzhiyun
754*4882a593Smuzhiyun i += ret;
755*4882a593Smuzhiyun if (args.argc == 0)
756*4882a593Smuzhiyun continue;
757*4882a593Smuzhiyun
758*4882a593Smuzhiyun do_cmd(pdata, &args);
759*4882a593Smuzhiyun free_auto_args(&args);
760*4882a593Smuzhiyun }
761*4882a593Smuzhiyun
762*4882a593Smuzhiyun kfree(buf);
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun return count;
765*4882a593Smuzhiyun }
766*4882a593Smuzhiyun
rk1608_dev_ioctl(struct file * file,unsigned int cmd,unsigned long arg)767*4882a593Smuzhiyun static long rk1608_dev_ioctl(struct file *file, unsigned int cmd,
768*4882a593Smuzhiyun unsigned long arg)
769*4882a593Smuzhiyun {
770*4882a593Smuzhiyun int ret = 0;
771*4882a593Smuzhiyun void __user *ubuf = (void __user *)arg;
772*4882a593Smuzhiyun struct rk1608_client *client = file->private_data;
773*4882a593Smuzhiyun struct rk1608_state *pdata = client->private_data;
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun switch (cmd) {
776*4882a593Smuzhiyun case PREISP_POWER_ON:
777*4882a593Smuzhiyun ret = rk1608_set_power(pdata, 1);
778*4882a593Smuzhiyun break;
779*4882a593Smuzhiyun case PREISP_POWER_OFF:
780*4882a593Smuzhiyun ret = rk1608_set_power(pdata, 0);
781*4882a593Smuzhiyun break;
782*4882a593Smuzhiyun case PREISP_DOWNLOAD_FW: {
783*4882a593Smuzhiyun char fw_name[PREISP_FW_NAME_LEN];
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun if (strncpy_from_user(fw_name, ubuf, PREISP_FW_NAME_LEN) <= 0) {
786*4882a593Smuzhiyun ret = -EFAULT;
787*4882a593Smuzhiyun break;
788*4882a593Smuzhiyun }
789*4882a593Smuzhiyun dev_info(pdata->dev, "download fw:%s\n", fw_name);
790*4882a593Smuzhiyun ret = rk1608_download_fw(pdata, pdata->spi, fw_name);
791*4882a593Smuzhiyun break;
792*4882a593Smuzhiyun }
793*4882a593Smuzhiyun case PREISP_WRITE: {
794*4882a593Smuzhiyun struct preisp_apb_pkt pkt;
795*4882a593Smuzhiyun s32 *data;
796*4882a593Smuzhiyun
797*4882a593Smuzhiyun if (copy_from_user(&pkt, ubuf, sizeof(pkt))) {
798*4882a593Smuzhiyun ret = -EFAULT;
799*4882a593Smuzhiyun break;
800*4882a593Smuzhiyun }
801*4882a593Smuzhiyun pkt.data_len = MIN(pkt.data_len, RK1608_MAX_OP_BYTES);
802*4882a593Smuzhiyun data = memdup_user((void __user *)pkt.data, pkt.data_len);
803*4882a593Smuzhiyun if (IS_ERR(data)) {
804*4882a593Smuzhiyun ret = (long)ERR_PTR((long)data);
805*4882a593Smuzhiyun break;
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun
808*4882a593Smuzhiyun ret = rk1608_safe_write(pdata, pdata->spi, pkt.addr, data, pkt.data_len);
809*4882a593Smuzhiyun kfree(data);
810*4882a593Smuzhiyun break;
811*4882a593Smuzhiyun }
812*4882a593Smuzhiyun case PREISP_READ: {
813*4882a593Smuzhiyun struct preisp_apb_pkt pkt;
814*4882a593Smuzhiyun s32 *data;
815*4882a593Smuzhiyun
816*4882a593Smuzhiyun if (copy_from_user(&pkt, ubuf, sizeof(pkt))) {
817*4882a593Smuzhiyun ret = -EFAULT;
818*4882a593Smuzhiyun break;
819*4882a593Smuzhiyun }
820*4882a593Smuzhiyun pkt.data_len = MIN(pkt.data_len, RK1608_MAX_OP_BYTES);
821*4882a593Smuzhiyun data = kmalloc(pkt.data_len, GFP_KERNEL);
822*4882a593Smuzhiyun if (!data) {
823*4882a593Smuzhiyun ret = -ENOMEM;
824*4882a593Smuzhiyun break;
825*4882a593Smuzhiyun }
826*4882a593Smuzhiyun
827*4882a593Smuzhiyun ret = rk1608_safe_read(pdata, pdata->spi, pkt.addr, data, pkt.data_len);
828*4882a593Smuzhiyun if (ret) {
829*4882a593Smuzhiyun kfree(data);
830*4882a593Smuzhiyun break;
831*4882a593Smuzhiyun }
832*4882a593Smuzhiyun ret = copy_to_user((void __user *)pkt.data, data, pkt.data_len);
833*4882a593Smuzhiyun
834*4882a593Smuzhiyun kfree(data);
835*4882a593Smuzhiyun break;
836*4882a593Smuzhiyun }
837*4882a593Smuzhiyun case PREISP_ST_QUERY: {
838*4882a593Smuzhiyun s32 state;
839*4882a593Smuzhiyun
840*4882a593Smuzhiyun ret = rk1608_state_query(pdata->spi, &state);
841*4882a593Smuzhiyun if (ret)
842*4882a593Smuzhiyun break;
843*4882a593Smuzhiyun
844*4882a593Smuzhiyun ret = put_user(state, (s32 __user *)ubuf);
845*4882a593Smuzhiyun break;
846*4882a593Smuzhiyun }
847*4882a593Smuzhiyun case PREISP_IRQ_REQUEST: {
848*4882a593Smuzhiyun int int_num = arg;
849*4882a593Smuzhiyun
850*4882a593Smuzhiyun ret = rk1608_interrupt_request(pdata->spi, int_num);
851*4882a593Smuzhiyun break;
852*4882a593Smuzhiyun }
853*4882a593Smuzhiyun case PREISP_SEND_MSG: {
854*4882a593Smuzhiyun struct msg *msg;
855*4882a593Smuzhiyun u32 len;
856*4882a593Smuzhiyun
857*4882a593Smuzhiyun if (get_user(len, (u32 __user *)ubuf)) {
858*4882a593Smuzhiyun ret = -EFAULT;
859*4882a593Smuzhiyun break;
860*4882a593Smuzhiyun }
861*4882a593Smuzhiyun len = len * sizeof(s32);
862*4882a593Smuzhiyun msg = memdup_user(ubuf, len);
863*4882a593Smuzhiyun if (IS_ERR(msg)) {
864*4882a593Smuzhiyun ret = (long)ERR_PTR((long)msg);
865*4882a593Smuzhiyun break;
866*4882a593Smuzhiyun }
867*4882a593Smuzhiyun
868*4882a593Smuzhiyun #if DEBUG_DUMP_ALL_SEND_RECV_MSG == 1
869*4882a593Smuzhiyun int32_hexdump("send msg:", (s32 *)msg, len);
870*4882a593Smuzhiyun #endif
871*4882a593Smuzhiyun
872*4882a593Smuzhiyun ret = rk1608_send_msg_to_dsp(pdata, msg);
873*4882a593Smuzhiyun kfree(msg);
874*4882a593Smuzhiyun break;
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun case PREISP_QUERY_MSG: {
877*4882a593Smuzhiyun struct msg *msg;
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun ret = msq_recv_msg(&client->q, &msg);
880*4882a593Smuzhiyun if (ret)
881*4882a593Smuzhiyun break;
882*4882a593Smuzhiyun
883*4882a593Smuzhiyun ret = put_user(msg->size, (u32 __user *)ubuf);
884*4882a593Smuzhiyun break;
885*4882a593Smuzhiyun }
886*4882a593Smuzhiyun case PREISP_RECV_MSG: {
887*4882a593Smuzhiyun struct msg *msg;
888*4882a593Smuzhiyun
889*4882a593Smuzhiyun ret = msq_recv_msg(&client->q, &msg);
890*4882a593Smuzhiyun if (ret)
891*4882a593Smuzhiyun break;
892*4882a593Smuzhiyun
893*4882a593Smuzhiyun ret = copy_to_user(ubuf, msg, msg->size * sizeof(u32));
894*4882a593Smuzhiyun msq_free_received_msg(&client->q, msg);
895*4882a593Smuzhiyun break;
896*4882a593Smuzhiyun }
897*4882a593Smuzhiyun case PREISP_CLIENT_CONNECT: {
898*4882a593Smuzhiyun client->id = (int)arg;
899*4882a593Smuzhiyun ret = rk1608_client_connect(pdata, client);
900*4882a593Smuzhiyun break;
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun case PREISP_CLIENT_DISCONNECT: {
903*4882a593Smuzhiyun rk1608_client_disconnect(pdata, client);
904*4882a593Smuzhiyun client->id = INVALID_ID;
905*4882a593Smuzhiyun break;
906*4882a593Smuzhiyun }
907*4882a593Smuzhiyun default:
908*4882a593Smuzhiyun ret = -EFAULT;
909*4882a593Smuzhiyun break;
910*4882a593Smuzhiyun }
911*4882a593Smuzhiyun
912*4882a593Smuzhiyun return ret;
913*4882a593Smuzhiyun }
914*4882a593Smuzhiyun
915*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
916*4882a593Smuzhiyun #define PREISP_WRITE32 _IOW('p', 6, struct preisp_apb_pkt32)
917*4882a593Smuzhiyun #define PREISP_READ32 _IOR('p', 7, struct preisp_apb_pkt32)
918*4882a593Smuzhiyun
919*4882a593Smuzhiyun struct preisp_apb_pkt32 {
920*4882a593Smuzhiyun s32 data_len;
921*4882a593Smuzhiyun s32 addr;
922*4882a593Smuzhiyun compat_uptr_t data;
923*4882a593Smuzhiyun };
924*4882a593Smuzhiyun
rk1608_compat_ioctl(struct file * file,unsigned int cmd,unsigned long arg)925*4882a593Smuzhiyun static long rk1608_compat_ioctl(struct file *file, unsigned int cmd,
926*4882a593Smuzhiyun unsigned long arg)
927*4882a593Smuzhiyun {
928*4882a593Smuzhiyun int ret = 0;
929*4882a593Smuzhiyun struct preisp_apb_pkt32 pkt32;
930*4882a593Smuzhiyun struct preisp_apb_pkt *pkt;
931*4882a593Smuzhiyun
932*4882a593Smuzhiyun switch (cmd) {
933*4882a593Smuzhiyun case PREISP_WRITE32:
934*4882a593Smuzhiyun cmd = PREISP_WRITE;
935*4882a593Smuzhiyun break;
936*4882a593Smuzhiyun case PREISP_READ32:
937*4882a593Smuzhiyun cmd = PREISP_READ;
938*4882a593Smuzhiyun break;
939*4882a593Smuzhiyun default:
940*4882a593Smuzhiyun break;
941*4882a593Smuzhiyun }
942*4882a593Smuzhiyun
943*4882a593Smuzhiyun switch (cmd) {
944*4882a593Smuzhiyun case PREISP_WRITE:
945*4882a593Smuzhiyun case PREISP_READ:
946*4882a593Smuzhiyun if (copy_from_user(&pkt32, (void __user *)arg, sizeof(pkt32)))
947*4882a593Smuzhiyun return -EFAULT;
948*4882a593Smuzhiyun
949*4882a593Smuzhiyun pkt = compat_alloc_user_space(sizeof(*pkt));
950*4882a593Smuzhiyun if (!pkt ||
951*4882a593Smuzhiyun put_user(pkt32.data_len, &pkt->data_len) ||
952*4882a593Smuzhiyun put_user(pkt32.addr, &pkt->addr) ||
953*4882a593Smuzhiyun put_user(compat_ptr(pkt32.data), &pkt->data))
954*4882a593Smuzhiyun return -EFAULT;
955*4882a593Smuzhiyun
956*4882a593Smuzhiyun ret = rk1608_dev_ioctl(file, cmd, (unsigned long)pkt);
957*4882a593Smuzhiyun break;
958*4882a593Smuzhiyun default:
959*4882a593Smuzhiyun ret = rk1608_dev_ioctl(file, cmd, arg);
960*4882a593Smuzhiyun break;
961*4882a593Smuzhiyun }
962*4882a593Smuzhiyun
963*4882a593Smuzhiyun return ret;
964*4882a593Smuzhiyun }
965*4882a593Smuzhiyun #endif
966*4882a593Smuzhiyun
rk1608_dev_poll(struct file * file,poll_table * wait)967*4882a593Smuzhiyun static unsigned int rk1608_dev_poll(struct file *file, poll_table *wait)
968*4882a593Smuzhiyun {
969*4882a593Smuzhiyun struct rk1608_client *client = file->private_data;
970*4882a593Smuzhiyun unsigned int mask = 0;
971*4882a593Smuzhiyun
972*4882a593Smuzhiyun poll_wait(file, &client->wait, wait);
973*4882a593Smuzhiyun
974*4882a593Smuzhiyun if (!msq_is_empty(&client->q))
975*4882a593Smuzhiyun mask |= POLLIN;
976*4882a593Smuzhiyun
977*4882a593Smuzhiyun return mask;
978*4882a593Smuzhiyun }
979*4882a593Smuzhiyun
980*4882a593Smuzhiyun static const struct file_operations rk1608_fops = {
981*4882a593Smuzhiyun .owner = THIS_MODULE,
982*4882a593Smuzhiyun .open = rk1608_dev_open,
983*4882a593Smuzhiyun .release = rk1608_dev_release,
984*4882a593Smuzhiyun .write = rk1608_dev_write,
985*4882a593Smuzhiyun .poll = rk1608_dev_poll,
986*4882a593Smuzhiyun .unlocked_ioctl = rk1608_dev_ioctl,
987*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
988*4882a593Smuzhiyun .compat_ioctl = rk1608_compat_ioctl,
989*4882a593Smuzhiyun #endif
990*4882a593Smuzhiyun };
991*4882a593Smuzhiyun
rk1608_dev_receive_msg(struct rk1608_state * pdata,struct msg * msg)992*4882a593Smuzhiyun void rk1608_dev_receive_msg(struct rk1608_state *pdata, struct msg *msg)
993*4882a593Smuzhiyun {
994*4882a593Smuzhiyun struct rk1608_client_list *s = &pdata->clients;
995*4882a593Smuzhiyun struct rk1608_client *client;
996*4882a593Smuzhiyun
997*4882a593Smuzhiyun #if DEBUG_DUMP_ALL_SEND_RECV_MSG == 1
998*4882a593Smuzhiyun int32_hexdump("recv msg:", (s32 *)msg, msg->size * 4);
999*4882a593Smuzhiyun #endif
1000*4882a593Smuzhiyun
1001*4882a593Smuzhiyun mutex_lock(&s->mutex);
1002*4882a593Smuzhiyun list_for_each_entry(client, &s->list, list) {
1003*4882a593Smuzhiyun if (client->id == msg->id.camera_id) {
1004*4882a593Smuzhiyun msq_send_msg(&client->q, msg);
1005*4882a593Smuzhiyun wake_up_interruptible(&client->wait);
1006*4882a593Smuzhiyun }
1007*4882a593Smuzhiyun }
1008*4882a593Smuzhiyun mutex_unlock(&s->mutex);
1009*4882a593Smuzhiyun }
1010*4882a593Smuzhiyun
rk1608_dev_register(struct rk1608_state * pdata)1011*4882a593Smuzhiyun int rk1608_dev_register(struct rk1608_state *pdata)
1012*4882a593Smuzhiyun {
1013*4882a593Smuzhiyun int ret;
1014*4882a593Smuzhiyun
1015*4882a593Smuzhiyun rk1608_client_list_init(&pdata->clients);
1016*4882a593Smuzhiyun
1017*4882a593Smuzhiyun pdata->misc.minor = MISC_DYNAMIC_MINOR;
1018*4882a593Smuzhiyun pdata->misc.name = "rk_preisp";
1019*4882a593Smuzhiyun pdata->misc.fops = &rk1608_fops;
1020*4882a593Smuzhiyun
1021*4882a593Smuzhiyun ret = misc_register(&pdata->misc);
1022*4882a593Smuzhiyun if (ret < 0)
1023*4882a593Smuzhiyun dev_err(pdata->dev, "Error: misc_register returned %d\n", ret);
1024*4882a593Smuzhiyun
1025*4882a593Smuzhiyun return 0;
1026*4882a593Smuzhiyun }
1027*4882a593Smuzhiyun
rk1608_dev_unregister(struct rk1608_state * pdata)1028*4882a593Smuzhiyun void rk1608_dev_unregister(struct rk1608_state *pdata)
1029*4882a593Smuzhiyun {
1030*4882a593Smuzhiyun misc_deregister(&pdata->misc);
1031*4882a593Smuzhiyun }
1032