blob: 0715d6dc9e4ec6368d5fddae0a0095592d1c8b59 [file] [log] [blame]
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02001/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
Joel Nider5556a852011-10-16 10:52:13 +02002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
Joel Nider5bd73f82011-12-14 16:53:30 +020013#include <linux/module.h> /* Just for modules */
14#include <linux/kernel.h> /* Only for KERN_INFO */
15#include <linux/err.h> /* Error macros */
16#include <linux/list.h> /* Linked list */
Joel Nider5556a852011-10-16 10:52:13 +020017#include <linux/cdev.h>
Joel Nider5bd73f82011-12-14 16:53:30 +020018#include <linux/init.h> /* Needed for the macros */
19#include <linux/io.h> /* IO macros */
20#include <linux/device.h> /* Device drivers need this */
21#include <linux/sched.h> /* Externally defined globals */
22#include <linux/pm_runtime.h> /* Runtime power management */
Joel Nider5556a852011-10-16 10:52:13 +020023#include <linux/fs.h>
Joel Nider5bd73f82011-12-14 16:53:30 +020024#include <linux/uaccess.h> /* copy_to_user */
Joel Nider5556a852011-10-16 10:52:13 +020025#include <linux/slab.h> /* kfree, kzalloc */
Joel Nider5bd73f82011-12-14 16:53:30 +020026#include <linux/ioport.h> /* XXX_ mem_region */
27#include <linux/dma-mapping.h> /* dma_XXX */
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +020028#include <linux/dmapool.h> /* DMA pools */
Joel Nider5bd73f82011-12-14 16:53:30 +020029#include <linux/delay.h> /* msleep */
30#include <linux/platform_device.h>
Joel Nider5556a852011-10-16 10:52:13 +020031#include <linux/clk.h>
Joel Nider5bd73f82011-12-14 16:53:30 +020032#include <linux/poll.h> /* poll() file op */
33#include <linux/wait.h> /* wait() macros, sleeping */
34#include <linux/tspp.h> /* tspp functions */
Joel Nider5556a852011-10-16 10:52:13 +020035#include <linux/bitops.h> /* BIT() macro */
Joel Nider5bd73f82011-12-14 16:53:30 +020036#include <mach/sps.h> /* BAM stuff */
Joel Nider5556a852011-10-16 10:52:13 +020037#include <mach/gpio.h>
Joel Nider5bd73f82011-12-14 16:53:30 +020038#include <linux/wakelock.h> /* Locking functions */
Hamad Kadmany567bed82012-11-29 14:15:57 +020039#include <linux/timer.h> /* Timer services */
40#include <linux/jiffies.h> /* Jiffies counter */
Joel Nider5556a852011-10-16 10:52:13 +020041#include <mach/dma.h>
42#include <mach/msm_tspp.h>
Joel Nider5556a852011-10-16 10:52:13 +020043#include <linux/debugfs.h>
Joel Nider5556a852011-10-16 10:52:13 +020044
45/*
46 * General defines
47 */
Joel Nider5556a852011-10-16 10:52:13 +020048#define TSPP_TSIF_INSTANCES 2
49#define TSPP_FILTER_TABLES 3
Joel Nider5bd73f82011-12-14 16:53:30 +020050#define TSPP_MAX_DEVICES 1
Joel Nider5556a852011-10-16 10:52:13 +020051#define TSPP_NUM_CHANNELS 16
52#define TSPP_NUM_PRIORITIES 16
53#define TSPP_NUM_KEYS 8
54#define INVALID_CHANNEL 0xFFFFFFFF
Hamad Kadmany567bed82012-11-29 14:15:57 +020055
56/*
57 * BAM descriptor FIFO size (in number of descriptors).
58 * Max number of descriptors allowed by SPS which is 8K-1.
59 * Restrict it to half of this to save DMA memory.
60 */
61#define TSPP_SPS_DESCRIPTOR_COUNT (4 * 1024 - 1)
Joel Nider5556a852011-10-16 10:52:13 +020062#define TSPP_PACKET_LENGTH 188
63#define TSPP_MIN_BUFFER_SIZE (TSPP_PACKET_LENGTH)
Hamad Kadmany567bed82012-11-29 14:15:57 +020064
65/* Max descriptor buffer size allowed by SPS */
66#define TSPP_MAX_BUFFER_SIZE (32 * 1024 - 1)
67
68/*
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +020069 * Returns whether to use DMA pool for TSPP output buffers.
70 * For buffers smaller than page size, using DMA pool
71 * provides better memory utilization as dma_alloc_coherent
72 * allocates minimum of page size.
73 */
74#define TSPP_USE_DMA_POOL(buff_size) ((buff_size) < PAGE_SIZE)
75
76/*
Hamad Kadmany567bed82012-11-29 14:15:57 +020077 * Max allowed TSPP buffers/descriptors.
78 * If SPS desc FIFO holds X descriptors, we can queue up to X-1 descriptors.
79 */
80#define TSPP_NUM_BUFFERS (TSPP_SPS_DESCRIPTOR_COUNT - 1)
Joel Nider5556a852011-10-16 10:52:13 +020081#define TSPP_TSIF_DEFAULT_TIME_LIMIT 60
82#define SPS_DESCRIPTOR_SIZE 8
83#define MIN_ACCEPTABLE_BUFFER_COUNT 2
Joel Nider5bd73f82011-12-14 16:53:30 +020084#define TSPP_DEBUG(msg...)
Joel Nider5556a852011-10-16 10:52:13 +020085
86/*
87 * TSIF register offsets
88 */
89#define TSIF_STS_CTL_OFF (0x0)
90#define TSIF_TIME_LIMIT_OFF (0x4)
91#define TSIF_CLK_REF_OFF (0x8)
92#define TSIF_LPBK_FLAGS_OFF (0xc)
93#define TSIF_LPBK_DATA_OFF (0x10)
94#define TSIF_TEST_CTL_OFF (0x14)
95#define TSIF_TEST_MODE_OFF (0x18)
96#define TSIF_TEST_RESET_OFF (0x1c)
97#define TSIF_TEST_EXPORT_OFF (0x20)
98#define TSIF_TEST_CURRENT_OFF (0x24)
99
100#define TSIF_DATA_PORT_OFF (0x100)
101
102/* bits for TSIF_STS_CTL register */
103#define TSIF_STS_CTL_EN_IRQ BIT(28)
104#define TSIF_STS_CTL_PACK_AVAIL BIT(27)
105#define TSIF_STS_CTL_1ST_PACKET BIT(26)
106#define TSIF_STS_CTL_OVERFLOW BIT(25)
107#define TSIF_STS_CTL_LOST_SYNC BIT(24)
108#define TSIF_STS_CTL_TIMEOUT BIT(23)
109#define TSIF_STS_CTL_INV_SYNC BIT(21)
110#define TSIF_STS_CTL_INV_NULL BIT(20)
111#define TSIF_STS_CTL_INV_ERROR BIT(19)
112#define TSIF_STS_CTL_INV_ENABLE BIT(18)
113#define TSIF_STS_CTL_INV_DATA BIT(17)
114#define TSIF_STS_CTL_INV_CLOCK BIT(16)
115#define TSIF_STS_CTL_SPARE BIT(15)
116#define TSIF_STS_CTL_EN_NULL BIT(11)
117#define TSIF_STS_CTL_EN_ERROR BIT(10)
118#define TSIF_STS_CTL_LAST_BIT BIT(9)
119#define TSIF_STS_CTL_EN_TIME_LIM BIT(8)
120#define TSIF_STS_CTL_EN_TCR BIT(7)
121#define TSIF_STS_CTL_TEST_MODE BIT(6)
Joel Nider5bd73f82011-12-14 16:53:30 +0200122#define TSIF_STS_CTL_MODE_2 BIT(5)
Joel Nider5556a852011-10-16 10:52:13 +0200123#define TSIF_STS_CTL_EN_DM BIT(4)
124#define TSIF_STS_CTL_STOP BIT(3)
125#define TSIF_STS_CTL_START BIT(0)
126
127/*
128 * TSPP register offsets
129 */
Liron Kuch229090d2012-10-30 17:47:50 +0200130#define TSPP_RST 0x00
Joel Nider5556a852011-10-16 10:52:13 +0200131#define TSPP_CLK_CONTROL 0x04
Liron Kuch229090d2012-10-30 17:47:50 +0200132#define TSPP_CONFIG 0x08
133#define TSPP_CONTROL 0x0C
Joel Nider5556a852011-10-16 10:52:13 +0200134#define TSPP_PS_DISABLE 0x10
Liron Kuch229090d2012-10-30 17:47:50 +0200135#define TSPP_MSG_IRQ_STATUS 0x14
Joel Nider5556a852011-10-16 10:52:13 +0200136#define TSPP_MSG_IRQ_MASK 0x18
137#define TSPP_IRQ_STATUS 0x1C
138#define TSPP_IRQ_MASK 0x20
139#define TSPP_IRQ_CLEAR 0x24
140#define TSPP_PIPE_ERROR_STATUS(_n) (0x28 + (_n << 2))
Liron Kuch229090d2012-10-30 17:47:50 +0200141#define TSPP_STATUS 0x68
142#define TSPP_CURR_TSP_HEADER 0x6C
143#define TSPP_CURR_PID_FILTER 0x70
144#define TSPP_SYSTEM_KEY(_n) (0x74 + (_n << 2))
145#define TSPP_CBC_INIT_VAL(_n) (0x94 + (_n << 2))
146#define TSPP_DATA_KEY_RESET 0x9C
Joel Nider5556a852011-10-16 10:52:13 +0200147#define TSPP_KEY_VALID 0xA0
148#define TSPP_KEY_ERROR 0xA4
149#define TSPP_TEST_CTRL 0xA8
Liron Kuch229090d2012-10-30 17:47:50 +0200150#define TSPP_VERSION 0xAC
Joel Nider5556a852011-10-16 10:52:13 +0200151#define TSPP_GENERICS 0xB0
Liron Kuch229090d2012-10-30 17:47:50 +0200152#define TSPP_NOP 0xB4
Joel Nider5556a852011-10-16 10:52:13 +0200153
154/*
155 * Register bit definitions
156 */
157/* TSPP_RST */
158#define TSPP_RST_RESET BIT(0)
159
160/* TSPP_CLK_CONTROL */
161#define TSPP_CLK_CONTROL_FORCE_CRYPTO BIT(9)
162#define TSPP_CLK_CONTROL_FORCE_PES_PL BIT(8)
163#define TSPP_CLK_CONTROL_FORCE_PES_AF BIT(7)
164#define TSPP_CLK_CONTROL_FORCE_RAW_CTRL BIT(6)
165#define TSPP_CLK_CONTROL_FORCE_PERF_CNT BIT(5)
166#define TSPP_CLK_CONTROL_FORCE_CTX_SEARCH BIT(4)
167#define TSPP_CLK_CONTROL_FORCE_TSP_PROC BIT(3)
168#define TSPP_CLK_CONTROL_FORCE_CONS_AHB2MEM BIT(2)
169#define TSPP_CLK_CONTROL_FORCE_TS_AHB2MEM BIT(1)
170#define TSPP_CLK_CONTROL_SET_CLKON BIT(0)
171
172/* TSPP_CONFIG */
173#define TSPP_CONFIG_SET_PACKET_LENGTH(_a, _b) (_a = (_a & 0xF0) | \
174((_b & 0xF) << 8))
175#define TSPP_CONFIG_GET_PACKET_LENGTH(_a) ((_a >> 8) & 0xF)
176#define TSPP_CONFIG_DUP_WITH_DISC_EN BIT(7)
177#define TSPP_CONFIG_PES_SYNC_ERROR_MASK BIT(6)
178#define TSPP_CONFIG_PS_LEN_ERR_MASK BIT(5)
179#define TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK BIT(4)
180#define TSPP_CONFIG_PS_CONT_ERR_MASK BIT(3)
181#define TSPP_CONFIG_PS_DUP_TSP_MASK BIT(2)
182#define TSPP_CONFIG_TSP_ERR_IND_MASK BIT(1)
183#define TSPP_CONFIG_TSP_SYNC_ERR_MASK BIT(0)
184
185/* TSPP_CONTROL */
186#define TSPP_CONTROL_PID_FILTER_LOCK BIT(5)
187#define TSPP_CONTROL_FORCE_KEY_CALC BIT(4)
188#define TSPP_CONTROL_TSP_CONS_SRC_DIS BIT(3)
189#define TSPP_CONTROL_TSP_TSIF1_SRC_DIS BIT(2)
190#define TSPP_CONTROL_TSP_TSIF0_SRC_DIS BIT(1)
191#define TSPP_CONTROL_PERF_COUNT_INIT BIT(0)
192
193/* TSPP_MSG_IRQ_STATUS + TSPP_MSG_IRQ_MASK */
194#define TSPP_MSG_TSPP_IRQ BIT(2)
195#define TSPP_MSG_TSIF_1_IRQ BIT(1)
196#define TSPP_MSG_TSIF_0_IRQ BIT(0)
197
198/* TSPP_IRQ_STATUS + TSPP_IRQ_MASK + TSPP_IRQ_CLEAR */
Liron Kuch229090d2012-10-30 17:47:50 +0200199#define TSPP_IRQ_STATUS_TSP_RD_CMPL BIT(19)
200#define TSPP_IRQ_STATUS_KEY_ERROR BIT(18)
Joel Nider5556a852011-10-16 10:52:13 +0200201#define TSPP_IRQ_STATUS_KEY_SWITCHED_BAD BIT(17)
202#define TSPP_IRQ_STATUS_KEY_SWITCHED BIT(16)
203#define TSPP_IRQ_STATUS_PS_BROKEN(_n) BIT((_n))
204
205/* TSPP_PIPE_ERROR_STATUS */
Liron Kuch229090d2012-10-30 17:47:50 +0200206#define TSPP_PIPE_PES_SYNC_ERROR BIT(3)
207#define TSPP_PIPE_PS_LENGTH_ERROR BIT(2)
Joel Nider5556a852011-10-16 10:52:13 +0200208#define TSPP_PIPE_PS_CONTINUITY_ERROR BIT(1)
Liron Kuch229090d2012-10-30 17:47:50 +0200209#define TSPP_PIP_PS_LOST_START BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200210
211/* TSPP_STATUS */
Liron Kuch229090d2012-10-30 17:47:50 +0200212#define TSPP_STATUS_TSP_PKT_AVAIL BIT(10)
213#define TSPP_STATUS_TSIF1_DM_REQ BIT(6)
214#define TSPP_STATUS_TSIF0_DM_REQ BIT(2)
215#define TSPP_CURR_FILTER_TABLE BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200216
217/* TSPP_GENERICS */
Liron Kuch229090d2012-10-30 17:47:50 +0200218#define TSPP_GENERICS_CRYPTO_GEN BIT(12)
Joel Nider5556a852011-10-16 10:52:13 +0200219#define TSPP_GENERICS_MAX_CONS_PIPES BIT(7)
Liron Kuch229090d2012-10-30 17:47:50 +0200220#define TSPP_GENERICS_MAX_PIPES BIT(2)
221#define TSPP_GENERICS_TSIF_1_GEN BIT(1)
222#define TSPP_GENERICS_TSIF_0_GEN BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200223
224/*
225 * TSPP memory regions
226 */
227#define TSPP_PID_FILTER_TABLE0 0x800
228#define TSPP_PID_FILTER_TABLE1 0x880
229#define TSPP_PID_FILTER_TABLE2 0x900
230#define TSPP_GLOBAL_PERFORMANCE 0x980 /* see tspp_global_performance */
231#define TSPP_PIPE_CONTEXT 0x990 /* see tspp_pipe_context */
232#define TSPP_PIPE_PERFORMANCE 0x998 /* see tspp_pipe_performance */
233#define TSPP_TSP_BUFF_WORD(_n) (0xC10 + (_n << 2))
234#define TSPP_DATA_KEY 0xCD0
235
Joel Nider5556a852011-10-16 10:52:13 +0200236struct debugfs_entry {
237 const char *name;
238 mode_t mode;
239 int offset;
240};
241
242static const struct debugfs_entry debugfs_tsif_regs[] = {
243 {"sts_ctl", S_IRUGO | S_IWUSR, TSIF_STS_CTL_OFF},
244 {"time_limit", S_IRUGO | S_IWUSR, TSIF_TIME_LIMIT_OFF},
245 {"clk_ref", S_IRUGO | S_IWUSR, TSIF_CLK_REF_OFF},
246 {"lpbk_flags", S_IRUGO | S_IWUSR, TSIF_LPBK_FLAGS_OFF},
247 {"lpbk_data", S_IRUGO | S_IWUSR, TSIF_LPBK_DATA_OFF},
248 {"test_ctl", S_IRUGO | S_IWUSR, TSIF_TEST_CTL_OFF},
249 {"test_mode", S_IRUGO | S_IWUSR, TSIF_TEST_MODE_OFF},
250 {"test_reset", S_IWUSR, TSIF_TEST_RESET_OFF},
251 {"test_export", S_IRUGO | S_IWUSR, TSIF_TEST_EXPORT_OFF},
252 {"test_current", S_IRUGO, TSIF_TEST_CURRENT_OFF},
253 {"data_port", S_IRUSR, TSIF_DATA_PORT_OFF},
254};
255
256static const struct debugfs_entry debugfs_tspp_regs[] = {
257 {"rst", S_IRUGO | S_IWUSR, TSPP_RST},
258 {"clk_control", S_IRUGO | S_IWUSR, TSPP_CLK_CONTROL},
259 {"config", S_IRUGO | S_IWUSR, TSPP_CONFIG},
260 {"control", S_IRUGO | S_IWUSR, TSPP_CONTROL},
261 {"ps_disable", S_IRUGO | S_IWUSR, TSPP_PS_DISABLE},
262 {"msg_irq_status", S_IRUGO | S_IWUSR, TSPP_MSG_IRQ_STATUS},
263 {"msg_irq_mask", S_IRUGO | S_IWUSR, TSPP_MSG_IRQ_MASK},
264 {"irq_status", S_IRUGO | S_IWUSR, TSPP_IRQ_STATUS},
265 {"irq_mask", S_IRUGO | S_IWUSR, TSPP_IRQ_MASK},
266 {"irq_clear", S_IRUGO | S_IWUSR, TSPP_IRQ_CLEAR},
267 /* {"pipe_error_status",S_IRUGO | S_IWUSR, TSPP_PIPE_ERROR_STATUS}, */
268 {"status", S_IRUGO | S_IWUSR, TSPP_STATUS},
269 {"curr_tsp_header", S_IRUGO | S_IWUSR, TSPP_CURR_TSP_HEADER},
270 {"curr_pid_filter", S_IRUGO | S_IWUSR, TSPP_CURR_PID_FILTER},
271 /* {"system_key", S_IRUGO | S_IWUSR, TSPP_SYSTEM_KEY}, */
272 /* {"cbc_init_val", S_IRUGO | S_IWUSR, TSPP_CBC_INIT_VAL}, */
273 {"data_key_reset", S_IRUGO | S_IWUSR, TSPP_DATA_KEY_RESET},
274 {"key_valid", S_IRUGO | S_IWUSR, TSPP_KEY_VALID},
275 {"key_error", S_IRUGO | S_IWUSR, TSPP_KEY_ERROR},
276 {"test_ctrl", S_IRUGO | S_IWUSR, TSPP_TEST_CTRL},
277 {"version", S_IRUGO | S_IWUSR, TSPP_VERSION},
278 {"generics", S_IRUGO | S_IWUSR, TSPP_GENERICS},
279 {"pid_filter_table0", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE0},
280 {"pid_filter_table1", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE1},
281 {"pid_filter_table2", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE2},
282 {"global_performance", S_IRUGO | S_IWUSR, TSPP_GLOBAL_PERFORMANCE},
283 {"pipe_context", S_IRUGO | S_IWUSR, TSPP_PIPE_CONTEXT},
284 {"pipe_performance", S_IRUGO | S_IWUSR, TSPP_PIPE_PERFORMANCE},
285 {"data_key", S_IRUGO | S_IWUSR, TSPP_DATA_KEY}
286};
287
Joel Nider5556a852011-10-16 10:52:13 +0200288struct tspp_pid_filter {
289 u32 filter; /* see FILTER_ macros */
290 u32 config; /* see FILTER_ macros */
291};
292
293/* tsp_info */
294#define FILTER_HEADER_ERROR_MASK BIT(7)
295#define FILTER_TRANS_END_DISABLE BIT(6)
296#define FILTER_DEC_ON_ERROR_EN BIT(5)
297#define FILTER_DECRYPT BIT(4)
298#define FILTER_HAS_ENCRYPTION(_p) (_p->config & FILTER_DECRYPT)
299#define FILTER_GET_PIPE_NUMBER0(_p) (_p->config & 0xF)
300#define FILTER_SET_PIPE_NUMBER0(_p, _b) (_p->config = \
301 (_p->config & ~0xF) | (_b & 0xF))
302#define FILTER_GET_PIPE_PROCESS0(_p) ((_p->filter >> 30) & 0x3)
303#define FILTER_SET_PIPE_PROCESS0(_p, _b) (_p->filter = \
304 (_p->filter & ~(0x3<<30)) | ((_b & 0x3) << 30))
305#define FILTER_GET_PIPE_PID(_p) ((_p->filter >> 13) & 0x1FFF)
306#define FILTER_SET_PIPE_PID(_p, _b) (_p->filter = \
307 (_p->filter & ~(0x1FFF<<13)) | ((_b & 0x1FFF) << 13))
308#define FILTER_GET_PID_MASK(_p) (_p->filter & 0x1FFF)
309#define FILTER_SET_PID_MASK(_p, _b) (_p->filter = \
310 (_p->filter & ~0x1FFF) | (_b & 0x1FFF))
311#define FILTER_GET_PIPE_PROCESS1(_p) ((_p->config >> 30) & 0x3)
312#define FILTER_SET_PIPE_PROCESS1(_p, _b) (_p->config = \
313 (_p->config & ~(0x3<<30)) | ((_b & 0x3) << 30))
314#define FILTER_GET_KEY_NUMBER(_p) ((_p->config >> 8) & 0x7)
315#define FILTER_SET_KEY_NUMBER(_p, _b) (_p->config = \
316 (_p->config & ~(0x7<<8)) | ((_b & 0x7) << 8))
317
318struct tspp_global_performance_regs {
319 u32 tsp_total;
320 u32 tsp_ignored;
321 u32 tsp_error;
322 u32 tsp_sync;
323};
324
325struct tspp_pipe_context_regs {
326 u16 pes_bytes_left;
327 u16 count;
328 u32 tsif_suffix;
329} __packed;
330#define CONTEXT_GET_STATE(_a) (_a & 0x3)
331#define CONTEXT_UNSPEC_LENGTH BIT(11)
332#define CONTEXT_GET_CONT_COUNT(_a) ((_a >> 12) & 0xF)
333
Hamad Kadmany567bed82012-11-29 14:15:57 +0200334#define MSEC_TO_JIFFIES(msec) ((msec) * HZ / 1000)
335
Joel Nider5556a852011-10-16 10:52:13 +0200336struct tspp_pipe_performance_regs {
337 u32 tsp_total;
338 u32 ps_duplicate_tsp;
339 u32 tsp_no_payload;
340 u32 tsp_broken_ps;
341 u32 ps_total_num;
342 u32 ps_continuity_error;
343 u32 ps_length_error;
344 u32 pes_sync_error;
345};
346
347struct tspp_tsif_device {
348 void __iomem *base;
349 u32 time_limit;
350 u32 ref_count;
Joel Nider5bd73f82011-12-14 16:53:30 +0200351 enum tspp_tsif_mode mode;
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +0200352 int clock_inverse;
353 int data_inverse;
354 int sync_inverse;
355 int enable_inverse;
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +0200356 u32 tsif_irq;
Joel Nider5556a852011-10-16 10:52:13 +0200357
358 /* debugfs */
Joel Nider5556a852011-10-16 10:52:13 +0200359 struct dentry *dent_tsif;
360 struct dentry *debugfs_tsif_regs[ARRAY_SIZE(debugfs_tsif_regs)];
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +0200361 u32 stat_rx;
362 u32 stat_overflow;
363 u32 stat_lost_sync;
364 u32 stat_timeout;
Joel Nider5556a852011-10-16 10:52:13 +0200365};
366
367enum tspp_buf_state {
368 TSPP_BUF_STATE_EMPTY, /* buffer has been allocated, but not waiting */
369 TSPP_BUF_STATE_WAITING, /* buffer is waiting to be filled */
Joel Nider5bd73f82011-12-14 16:53:30 +0200370 TSPP_BUF_STATE_DATA, /* buffer is not empty and can be read */
371 TSPP_BUF_STATE_LOCKED /* buffer is being read by a client */
Joel Nider5556a852011-10-16 10:52:13 +0200372};
373
374struct tspp_mem_buffer {
Joel Nider5bd73f82011-12-14 16:53:30 +0200375 struct tspp_mem_buffer *next;
376 struct sps_mem_buffer sps;
377 struct tspp_data_descriptor desc; /* buffer descriptor for kernel api */
Joel Nider5556a852011-10-16 10:52:13 +0200378 enum tspp_buf_state state;
379 size_t filled; /* how much data this buffer is holding */
380 int read_index; /* where to start reading data from */
381};
382
383/* this represents each char device 'channel' */
384struct tspp_channel {
385 struct cdev cdev;
386 struct device *dd;
Joel Nider5bd73f82011-12-14 16:53:30 +0200387 struct tspp_device *pdev; /* can use container_of instead? */
Joel Nider5556a852011-10-16 10:52:13 +0200388 struct sps_pipe *pipe;
389 struct sps_connect config;
390 struct sps_register_event event;
Joel Nider5bd73f82011-12-14 16:53:30 +0200391 struct tspp_mem_buffer *data; /* list of buffers */
392 struct tspp_mem_buffer *read; /* first buffer ready to be read */
393 struct tspp_mem_buffer *waiting; /* first outstanding transfer */
394 struct tspp_mem_buffer *locked; /* buffer currently being read */
Joel Nider5556a852011-10-16 10:52:13 +0200395 wait_queue_head_t in_queue; /* set when data is received */
Joel Nider5bd73f82011-12-14 16:53:30 +0200396 u32 id; /* channel id (0-15) */
397 int used; /* is this channel in use? */
398 int key; /* which encryption key index is used */
399 u32 buffer_size; /* size of the sps transfer buffers */
400 u32 max_buffers; /* how many buffers should be allocated */
401 u32 buffer_count; /* how many buffers are actually allocated */
402 u32 filter_count; /* how many filters have been added to this channel */
403 u32 int_freq; /* generate interrupts every x descriptors */
Joel Nider5556a852011-10-16 10:52:13 +0200404 enum tspp_source src;
405 enum tspp_mode mode;
Joel Nider5bd73f82011-12-14 16:53:30 +0200406 tspp_notifier *notifier; /* used only with kernel api */
407 void *notify_data; /* data to be passed with the notifier */
Hamad Kadmany567bed82012-11-29 14:15:57 +0200408 u32 expiration_period_ms; /* notification on partially filled buffers */
409 struct timer_list expiration_timer;
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +0200410 struct dma_pool *dma_pool;
Liron Kuch229090d2012-10-30 17:47:50 +0200411 tspp_memfree *memfree; /* user defined memory free function */
412 void *user_info; /* user cookie passed to memory alloc/free function */
Joel Nider5556a852011-10-16 10:52:13 +0200413};
414
415struct tspp_pid_filter_table {
416 struct tspp_pid_filter filter[TSPP_NUM_PRIORITIES];
417};
418
419struct tspp_key_entry {
420 u32 even_lsb;
421 u32 even_msb;
422 u32 odd_lsb;
423 u32 odd_msb;
424};
425
426struct tspp_key_table {
427 struct tspp_key_entry entry[TSPP_NUM_KEYS];
428};
429
Joel Nider5bd73f82011-12-14 16:53:30 +0200430/* this represents the actual hardware device */
431struct tspp_device {
432 struct list_head devlist; /* list of all devices */
433 struct platform_device *pdev;
434 void __iomem *base;
435 unsigned int tspp_irq;
436 unsigned int bam_irq;
437 u32 bam_handle;
438 struct sps_bam_props bam_props;
439 struct wake_lock wake_lock;
440 spinlock_t spinlock;
441 struct tasklet_struct tlet;
442 struct tspp_tsif_device tsif[TSPP_TSIF_INSTANCES];
443 /* clocks */
444 struct clk *tsif_pclk;
445 struct clk *tsif_ref_clk;
446 /* data */
447 struct tspp_pid_filter_table *filters[TSPP_FILTER_TABLES];
448 struct tspp_channel channels[TSPP_NUM_CHANNELS];
449 struct tspp_key_table *tspp_key_table;
450 struct tspp_global_performance_regs *tspp_global_performance;
451 struct tspp_pipe_context_regs *tspp_pipe_context;
452 struct tspp_pipe_performance_regs *tspp_pipe_performance;
453
454 struct dentry *dent;
455 struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)];
456};
457
458
Joel Nider5556a852011-10-16 10:52:13 +0200459static struct class *tspp_class;
460static int tspp_key_entry;
461static dev_t tspp_minor; /* next minor number to assign */
Joel Nider5bd73f82011-12-14 16:53:30 +0200462
463static LIST_HEAD(tspp_devices);
464
465/* forward declarations */
466static ssize_t tspp_read(struct file *, char __user *, size_t, loff_t *);
467static ssize_t tspp_open(struct inode *inode, struct file *filp);
468static unsigned int tspp_poll(struct file *filp, struct poll_table_struct *p);
469static ssize_t tspp_release(struct inode *inode, struct file *filp);
470static long tspp_ioctl(struct file *, unsigned int, unsigned long);
471
472/* file operations */
473static const struct file_operations tspp_fops = {
474 .owner = THIS_MODULE,
475 .read = tspp_read,
476 .open = tspp_open,
477 .poll = tspp_poll,
478 .release = tspp_release,
479 .unlocked_ioctl = tspp_ioctl,
480};
Joel Nider5556a852011-10-16 10:52:13 +0200481
482/*** IRQ ***/
Joel Nider5bd73f82011-12-14 16:53:30 +0200483static irqreturn_t tspp_isr(int irq, void *dev)
Joel Nider5556a852011-10-16 10:52:13 +0200484{
Joel Nider5bd73f82011-12-14 16:53:30 +0200485 struct tspp_device *device = dev;
Joel Nider5556a852011-10-16 10:52:13 +0200486 u32 status, mask;
487 u32 data;
488
489 status = readl_relaxed(device->base + TSPP_IRQ_STATUS);
490 mask = readl_relaxed(device->base + TSPP_IRQ_MASK);
491 status &= mask;
492
493 if (!status) {
494 dev_warn(&device->pdev->dev, "Spurious interrupt");
495 return IRQ_NONE;
496 }
497
498 /* if (status & TSPP_IRQ_STATUS_TSP_RD_CMPL) */
499
500 if (status & TSPP_IRQ_STATUS_KEY_ERROR) {
501 /* read the key error info */
502 data = readl_relaxed(device->base + TSPP_KEY_ERROR);
503 dev_info(&device->pdev->dev, "key error 0x%x", data);
504 }
505 if (status & TSPP_IRQ_STATUS_KEY_SWITCHED_BAD) {
506 data = readl_relaxed(device->base + TSPP_KEY_VALID);
507 dev_info(&device->pdev->dev, "key invalidated: 0x%x", data);
508 }
509 if (status & TSPP_IRQ_STATUS_KEY_SWITCHED)
510 dev_info(&device->pdev->dev, "key switched");
511
512 if (status & 0xffff)
Joel Nider5bd73f82011-12-14 16:53:30 +0200513 dev_info(&device->pdev->dev, "broken pipe %i", status & 0xffff);
Joel Nider5556a852011-10-16 10:52:13 +0200514
515 writel_relaxed(status, device->base + TSPP_IRQ_CLEAR);
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +0200516
517 /*
518 * Before returning IRQ_HANDLED to the generic interrupt handling
519 * framework need to make sure all operations including clearing of
520 * interrupt status registers in the hardware is performed.
521 * Thus a barrier after clearing the interrupt status register
522 * is required to guarantee that the interrupt status register has
523 * really been cleared by the time we return from this handler.
524 */
525 wmb();
526 return IRQ_HANDLED;
527}
528
529static irqreturn_t tsif_isr(int irq, void *dev)
530{
531 struct tspp_tsif_device *tsif_device = dev;
532 u32 sts_ctl = ioread32(tsif_device->base + TSIF_STS_CTL_OFF);
533
534 if (!(sts_ctl & (TSIF_STS_CTL_PACK_AVAIL |
535 TSIF_STS_CTL_OVERFLOW |
536 TSIF_STS_CTL_LOST_SYNC |
537 TSIF_STS_CTL_TIMEOUT)))
538 return IRQ_NONE;
539
540 if (sts_ctl & TSIF_STS_CTL_OVERFLOW)
541 tsif_device->stat_overflow++;
542
543 if (sts_ctl & TSIF_STS_CTL_LOST_SYNC)
544 tsif_device->stat_lost_sync++;
545
546 if (sts_ctl & TSIF_STS_CTL_TIMEOUT)
547 tsif_device->stat_timeout++;
548
549 iowrite32(sts_ctl, tsif_device->base + TSIF_STS_CTL_OFF);
550
551 /*
552 * Before returning IRQ_HANDLED to the generic interrupt handling
553 * framework need to make sure all operations including clearing of
554 * interrupt status registers in the hardware is performed.
555 * Thus a barrier after clearing the interrupt status register
556 * is required to guarantee that the interrupt status register has
557 * really been cleared by the time we return from this handler.
558 */
Joel Nider5556a852011-10-16 10:52:13 +0200559 wmb();
560 return IRQ_HANDLED;
561}
562
563/*** callbacks ***/
564static void tspp_sps_complete_cb(struct sps_event_notify *notify)
565{
Joel Nider5bd73f82011-12-14 16:53:30 +0200566 struct tspp_device *pdev = notify->user;
567 tasklet_schedule(&pdev->tlet);
Joel Nider5556a852011-10-16 10:52:13 +0200568}
569
Hamad Kadmany567bed82012-11-29 14:15:57 +0200570static void tspp_expiration_timer(unsigned long data)
571{
572 struct tspp_device *pdev = (struct tspp_device *)data;
573
574 if (pdev)
575 tasklet_schedule(&pdev->tlet);
576}
577
Joel Nider5556a852011-10-16 10:52:13 +0200578/*** tasklet ***/
579static void tspp_sps_complete_tlet(unsigned long data)
580{
581 int i;
582 int complete;
583 unsigned long flags;
584 struct sps_iovec iovec;
585 struct tspp_channel *channel;
586 struct tspp_device *device = (struct tspp_device *)data;
Joel Nider5556a852011-10-16 10:52:13 +0200587 spin_lock_irqsave(&device->spinlock, flags);
588
589 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
590 complete = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +0200591 channel = &device->channels[i];
Hamad Kadmany567bed82012-11-29 14:15:57 +0200592
Joel Nider5bd73f82011-12-14 16:53:30 +0200593 if (!channel->used || !channel->waiting)
594 continue;
Joel Nider5556a852011-10-16 10:52:13 +0200595
Hamad Kadmany567bed82012-11-29 14:15:57 +0200596 /* stop the expiration timer */
597 if (channel->expiration_period_ms)
598 del_timer(&channel->expiration_timer);
599
Joel Nider5556a852011-10-16 10:52:13 +0200600 /* get completions */
Joel Nider5bd73f82011-12-14 16:53:30 +0200601 while (channel->waiting->state == TSPP_BUF_STATE_WAITING) {
Joel Nider5556a852011-10-16 10:52:13 +0200602 if (sps_get_iovec(channel->pipe, &iovec) != 0) {
603 pr_err("tspp: Error in iovec on channel %i",
604 channel->id);
605 break;
606 }
607 if (iovec.size == 0)
608 break;
609
Joel Nider5bd73f82011-12-14 16:53:30 +0200610 if (iovec.addr != channel->waiting->sps.phys_base)
Joel Nider5556a852011-10-16 10:52:13 +0200611 pr_err("tspp: buffer mismatch 0x%08x",
Joel Nider5bd73f82011-12-14 16:53:30 +0200612 channel->waiting->sps.phys_base);
Joel Nider5556a852011-10-16 10:52:13 +0200613
614 complete = 1;
Joel Nider5bd73f82011-12-14 16:53:30 +0200615 channel->waiting->state = TSPP_BUF_STATE_DATA;
616 channel->waiting->filled = iovec.size;
617 channel->waiting->read_index = 0;
618
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +0200619 if (channel->src == TSPP_SOURCE_TSIF0)
620 device->tsif[0].stat_rx++;
621 else if (channel->src == TSPP_SOURCE_TSIF1)
622 device->tsif[1].stat_rx++;
623
Joel Nider5bd73f82011-12-14 16:53:30 +0200624 /* update the pointers */
625 channel->waiting = channel->waiting->next;
Joel Nider5556a852011-10-16 10:52:13 +0200626 }
627
Joel Nider5bd73f82011-12-14 16:53:30 +0200628 /* wake any waiting processes */
Joel Nider5556a852011-10-16 10:52:13 +0200629 if (complete) {
Joel Nider5556a852011-10-16 10:52:13 +0200630 wake_up_interruptible(&channel->in_queue);
Joel Nider5bd73f82011-12-14 16:53:30 +0200631
632 /* call notifiers */
633 if (channel->notifier)
634 channel->notifier(channel->id,
635 channel->notify_data);
Joel Nider5556a852011-10-16 10:52:13 +0200636 }
Hamad Kadmany567bed82012-11-29 14:15:57 +0200637
638 /* restart expiration timer */
639 if (channel->expiration_period_ms)
640 mod_timer(&channel->expiration_timer,
641 jiffies +
642 MSEC_TO_JIFFIES(
643 channel->expiration_period_ms));
Joel Nider5556a852011-10-16 10:52:13 +0200644 }
645
646 spin_unlock_irqrestore(&device->spinlock, flags);
647}
648
649/*** GPIO functions ***/
650static void tspp_gpios_free(const struct msm_gpio *table, int size)
651{
652 int i;
653 const struct msm_gpio *g;
654 for (i = size-1; i >= 0; i--) {
655 g = table + i;
656 gpio_free(GPIO_PIN(g->gpio_cfg));
657 }
658}
659
660static int tspp_gpios_request(const struct msm_gpio *table, int size)
661{
662 int rc;
663 int i;
664 const struct msm_gpio *g;
665 for (i = 0; i < size; i++) {
666 g = table + i;
667 rc = gpio_request(GPIO_PIN(g->gpio_cfg), g->label);
668 if (rc) {
669 pr_err("tspp: gpio_request(%d) <%s> failed: %d\n",
670 GPIO_PIN(g->gpio_cfg), g->label ?: "?", rc);
671 goto err;
672 }
673 }
674 return 0;
675err:
676 tspp_gpios_free(table, i);
677 return rc;
678}
679
680static int tspp_gpios_disable(const struct msm_gpio *table, int size)
681{
682 int rc = 0;
683 int i;
684 const struct msm_gpio *g;
685 for (i = size-1; i >= 0; i--) {
686 int tmp;
687 g = table + i;
688 tmp = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_DISABLE);
689 if (tmp) {
Liron Kuch229090d2012-10-30 17:47:50 +0200690 pr_err("tspp_gpios_disable(0x%08x, GPIO_CFG_DISABLE) <%s> failed: %d\n",
Joel Nider5556a852011-10-16 10:52:13 +0200691 g->gpio_cfg, g->label ?: "?", rc);
692 pr_err("tspp: pin %d func %d dir %d pull %d drvstr %d\n",
693 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
694 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
695 GPIO_DRVSTR(g->gpio_cfg));
696 if (!rc)
697 rc = tmp;
698 }
699 }
700
701 return rc;
702}
703
704static int tspp_gpios_enable(const struct msm_gpio *table, int size)
705{
706 int rc;
707 int i;
708 const struct msm_gpio *g;
709 for (i = 0; i < size; i++) {
710 g = table + i;
711 rc = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_ENABLE);
712 if (rc) {
Liron Kuch229090d2012-10-30 17:47:50 +0200713 pr_err("tspp: gpio_tlmm_config(0x%08x, GPIO_CFG_ENABLE) <%s> failed: %d\n",
Joel Nider5556a852011-10-16 10:52:13 +0200714 g->gpio_cfg, g->label ?: "?", rc);
715 pr_err("tspp: pin %d func %d dir %d pull %d drvstr %d\n",
716 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
717 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
718 GPIO_DRVSTR(g->gpio_cfg));
719 goto err;
720 }
721 }
722 return 0;
723err:
724 tspp_gpios_disable(table, i);
725 return rc;
726}
727
728static int tspp_gpios_request_enable(const struct msm_gpio *table, int size)
729{
730 int rc = tspp_gpios_request(table, size);
731 if (rc)
732 return rc;
733 rc = tspp_gpios_enable(table, size);
734 if (rc)
735 tspp_gpios_free(table, size);
736 return rc;
737}
738
739static void tspp_gpios_disable_free(const struct msm_gpio *table, int size)
740{
741 tspp_gpios_disable(table, size);
742 tspp_gpios_free(table, size);
743}
744
745static int tspp_start_gpios(struct tspp_device *device)
746{
747 struct msm_tspp_platform_data *pdata =
748 device->pdev->dev.platform_data;
749 return tspp_gpios_request_enable(pdata->gpios, pdata->num_gpios);
750}
751
752static void tspp_stop_gpios(struct tspp_device *device)
753{
754 struct msm_tspp_platform_data *pdata =
755 device->pdev->dev.platform_data;
756 tspp_gpios_disable_free(pdata->gpios, pdata->num_gpios);
757}
758
Joel Nider5bd73f82011-12-14 16:53:30 +0200759/*** Clock functions ***/
760static int tspp_clock_start(struct tspp_device *device)
761{
762 if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) {
763 pr_err("tspp: Can't start pclk");
764 return -EBUSY;
765 }
766
767 if (device->tsif_ref_clk &&
768 clk_prepare_enable(device->tsif_ref_clk) != 0) {
769 pr_err("tspp: Can't start ref clk");
770 clk_disable_unprepare(device->tsif_pclk);
771 return -EBUSY;
772 }
773
774 return 0;
775}
776
777static void tspp_clock_stop(struct tspp_device *device)
778{
779 if (device->tsif_pclk)
780 clk_disable(device->tsif_pclk);
781
782 if (device->tsif_ref_clk)
783 clk_disable(device->tsif_ref_clk);
784}
785
Joel Nider5556a852011-10-16 10:52:13 +0200786/*** TSIF functions ***/
787static int tspp_start_tsif(struct tspp_tsif_device *tsif_device)
788{
789 int start_hardware = 0;
790 u32 ctl;
791
792 if (tsif_device->ref_count == 0) {
793 start_hardware = 1;
794 } else if (tsif_device->ref_count > 0) {
795 ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
796 if ((ctl & TSIF_STS_CTL_START) != 1) {
797 /* this hardware should already be running */
798 pr_warn("tspp: tsif hw not started but ref count > 0");
799 start_hardware = 1;
800 }
801 }
802
803 if (start_hardware) {
Joel Nider5bd73f82011-12-14 16:53:30 +0200804 ctl = TSIF_STS_CTL_EN_IRQ |
Joel Nider5556a852011-10-16 10:52:13 +0200805 TSIF_STS_CTL_EN_DM;
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +0200806
807 if (tsif_device->clock_inverse)
808 ctl |= TSIF_STS_CTL_INV_CLOCK;
809
810 if (tsif_device->data_inverse)
811 ctl |= TSIF_STS_CTL_INV_DATA;
812
813 if (tsif_device->sync_inverse)
814 ctl |= TSIF_STS_CTL_INV_SYNC;
815
816 if (tsif_device->enable_inverse)
817 ctl |= TSIF_STS_CTL_INV_ENABLE;
818
Joel Nider5bd73f82011-12-14 16:53:30 +0200819 switch (tsif_device->mode) {
820 case TSPP_TSIF_MODE_LOOPBACK:
821 ctl |= TSIF_STS_CTL_EN_NULL |
822 TSIF_STS_CTL_EN_ERROR |
823 TSIF_STS_CTL_TEST_MODE;
824 break;
825 case TSPP_TSIF_MODE_1:
826 ctl |= TSIF_STS_CTL_EN_TIME_LIM |
827 TSIF_STS_CTL_EN_TCR;
828 break;
829 case TSPP_TSIF_MODE_2:
830 ctl |= TSIF_STS_CTL_EN_TIME_LIM |
831 TSIF_STS_CTL_EN_TCR |
832 TSIF_STS_CTL_MODE_2;
833 break;
834 default:
835 pr_warn("tspp: unknown tsif mode 0x%x",
836 tsif_device->mode);
Joel Nider5556a852011-10-16 10:52:13 +0200837 }
838 writel_relaxed(ctl, tsif_device->base + TSIF_STS_CTL_OFF);
839 writel_relaxed(tsif_device->time_limit,
840 tsif_device->base + TSIF_TIME_LIMIT_OFF);
841 wmb();
842 writel_relaxed(ctl | TSIF_STS_CTL_START,
843 tsif_device->base + TSIF_STS_CTL_OFF);
844 wmb();
Joel Nider5556a852011-10-16 10:52:13 +0200845 }
846
Joel Nider5bd73f82011-12-14 16:53:30 +0200847 ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
Joel Nider5556a852011-10-16 10:52:13 +0200848 tsif_device->ref_count++;
849
Joel Nider5bd73f82011-12-14 16:53:30 +0200850 return (ctl & TSIF_STS_CTL_START) ? 0 : -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +0200851}
852
853static void tspp_stop_tsif(struct tspp_tsif_device *tsif_device)
854{
855 if (tsif_device->ref_count == 0)
856 return;
857
858 tsif_device->ref_count--;
859
860 if (tsif_device->ref_count == 0) {
861 writel_relaxed(TSIF_STS_CTL_STOP,
862 tsif_device->base + TSIF_STS_CTL_OFF);
863 wmb();
864 }
865}
866
Joel Nider5bd73f82011-12-14 16:53:30 +0200867/*** local TSPP functions ***/
868static int tspp_channels_in_use(struct tspp_device *pdev)
869{
870 int i;
871 int count = 0;
872 for (i = 0; i < TSPP_NUM_CHANNELS; i++)
873 count += (pdev->channels[i].used ? 1 : 0);
874
875 return count;
876}
877
878static struct tspp_device *tspp_find_by_id(int id)
879{
880 struct tspp_device *dev;
881 list_for_each_entry(dev, &tspp_devices, devlist) {
882 if (dev->pdev->id == id)
883 return dev;
884 }
885 return NULL;
886}
887
Joel Nider5556a852011-10-16 10:52:13 +0200888static int tspp_get_key_entry(void)
889{
890 int i;
891 for (i = 0; i < TSPP_NUM_KEYS; i++) {
892 if (!(tspp_key_entry & (1 << i))) {
893 tspp_key_entry |= (1 << i);
894 return i;
895 }
896 }
Joel Nider5bd73f82011-12-14 16:53:30 +0200897 return 1 < TSPP_NUM_KEYS;
Joel Nider5556a852011-10-16 10:52:13 +0200898}
899
900static void tspp_free_key_entry(int entry)
901{
902 if (entry > TSPP_NUM_KEYS) {
903 pr_err("tspp_free_key_entry: index out of bounds");
904 return;
905 }
906
907 tspp_key_entry &= ~(1 << entry);
908}
909
Joel Nider5bd73f82011-12-14 16:53:30 +0200910static int tspp_alloc_buffer(u32 channel_id, struct tspp_data_descriptor *desc,
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +0200911 u32 size, struct dma_pool *dma_pool, tspp_allocator *alloc, void *user)
Joel Nider5556a852011-10-16 10:52:13 +0200912{
Joel Nider5bd73f82011-12-14 16:53:30 +0200913 if (size < TSPP_MIN_BUFFER_SIZE ||
914 size > TSPP_MAX_BUFFER_SIZE) {
915 pr_err("tspp: bad buffer size %i", size);
Joel Nider5556a852011-10-16 10:52:13 +0200916 return -ENOMEM;
917 }
Joel Nider5bd73f82011-12-14 16:53:30 +0200918
919 if (alloc) {
920 TSPP_DEBUG("tspp using alloc function");
921 desc->virt_base = alloc(channel_id, size,
922 &desc->phys_base, user);
923 } else {
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +0200924 if (!dma_pool)
925 desc->virt_base = dma_alloc_coherent(NULL, size,
926 &desc->phys_base, GFP_KERNEL);
927 else
928 desc->virt_base = dma_pool_alloc(dma_pool, GFP_KERNEL,
929 &desc->phys_base);
930
Liron Kuch229090d2012-10-30 17:47:50 +0200931 if (desc->virt_base == 0) {
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +0200932 pr_err("tspp: dma buffer allocation failed %i\n", size);
Liron Kuch229090d2012-10-30 17:47:50 +0200933 return -ENOMEM;
934 }
Joel Nider5bd73f82011-12-14 16:53:30 +0200935 }
936
937 desc->size = size;
938 return 0;
939}
940
941static int tspp_queue_buffer(struct tspp_channel *channel,
942 struct tspp_mem_buffer *buffer)
943{
944 int rc;
945 u32 flags = 0;
946
947 /* make sure the interrupt frequency is valid */
948 if (channel->int_freq < 1)
949 channel->int_freq = 1;
950
951 /* generate interrupt according to requested frequency */
952 if (buffer->desc.id % channel->int_freq == channel->int_freq-1)
Hamad Kadmany567bed82012-11-29 14:15:57 +0200953 flags = SPS_IOVEC_FLAG_INT;
Joel Nider5bd73f82011-12-14 16:53:30 +0200954
955 /* start the transfer */
956 rc = sps_transfer_one(channel->pipe,
957 buffer->sps.phys_base,
958 buffer->sps.size,
959 channel->pdev,
960 flags);
961 if (rc < 0)
962 return rc;
963
964 buffer->state = TSPP_BUF_STATE_WAITING;
Joel Nider5556a852011-10-16 10:52:13 +0200965
966 return 0;
967}
968
969static int tspp_global_reset(struct tspp_device *pdev)
970{
971 u32 i, val;
972
973 /* stop all TSIFs */
974 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
975 pdev->tsif[i].ref_count = 1; /* allows stopping hw */
976 tspp_stop_tsif(&pdev->tsif[i]); /* will reset ref_count to 0 */
977 pdev->tsif[i].time_limit = TSPP_TSIF_DEFAULT_TIME_LIMIT;
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +0200978 pdev->tsif[i].clock_inverse = 0;
979 pdev->tsif[i].data_inverse = 0;
980 pdev->tsif[i].sync_inverse = 0;
981 pdev->tsif[i].enable_inverse = 0;
Joel Nider5556a852011-10-16 10:52:13 +0200982 }
983 writel_relaxed(TSPP_RST_RESET, pdev->base + TSPP_RST);
984 wmb();
985
986 /* BAM */
987 if (sps_device_reset(pdev->bam_handle) != 0) {
988 pr_err("tspp: error resetting bam");
Joel Nider5bd73f82011-12-14 16:53:30 +0200989 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +0200990 }
991
992 /* TSPP tables */
993 for (i = 0; i < TSPP_FILTER_TABLES; i++)
Joel Nider5bd73f82011-12-14 16:53:30 +0200994 memset(pdev->filters[i],
Joel Nider5556a852011-10-16 10:52:13 +0200995 0, sizeof(struct tspp_pid_filter_table));
996
997 /* disable all filters */
998 val = (2 << TSPP_NUM_CHANNELS) - 1;
999 writel_relaxed(val, pdev->base + TSPP_PS_DISABLE);
1000
1001 /* TSPP registers */
1002 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1003 writel_relaxed(val | TSPP_CLK_CONTROL_FORCE_PERF_CNT,
1004 pdev->base + TSPP_CONTROL);
1005 wmb();
Joel Nider5bd73f82011-12-14 16:53:30 +02001006 memset(pdev->tspp_global_performance, 0,
Joel Nider5556a852011-10-16 10:52:13 +02001007 sizeof(struct tspp_global_performance_regs));
Joel Nider5bd73f82011-12-14 16:53:30 +02001008 memset(pdev->tspp_pipe_context, 0,
Joel Nider5556a852011-10-16 10:52:13 +02001009 sizeof(struct tspp_pipe_context_regs));
Joel Nider5bd73f82011-12-14 16:53:30 +02001010 memset(pdev->tspp_pipe_performance, 0,
Joel Nider5556a852011-10-16 10:52:13 +02001011 sizeof(struct tspp_pipe_performance_regs));
1012 wmb();
1013 writel_relaxed(val & ~TSPP_CLK_CONTROL_FORCE_PERF_CNT,
1014 pdev->base + TSPP_CONTROL);
1015 wmb();
1016
1017 val = readl_relaxed(pdev->base + TSPP_CONFIG);
1018 val &= ~(TSPP_CONFIG_PS_LEN_ERR_MASK |
1019 TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK |
1020 TSPP_CONFIG_PS_CONT_ERR_MASK);
1021 TSPP_CONFIG_SET_PACKET_LENGTH(val, TSPP_PACKET_LENGTH);
1022 writel_relaxed(val, pdev->base + TSPP_CONFIG);
Hamad Kadmany57f5ac82012-12-20 18:30:40 +02001023 writel_relaxed(0x0007ffff, pdev->base + TSPP_IRQ_MASK);
Joel Nider5556a852011-10-16 10:52:13 +02001024 writel_relaxed(0x000fffff, pdev->base + TSPP_IRQ_CLEAR);
1025 writel_relaxed(0, pdev->base + TSPP_RST);
1026 wmb();
1027
1028 tspp_key_entry = 0;
1029
1030 return 0;
1031}
1032
Joel Nider5bd73f82011-12-14 16:53:30 +02001033static int tspp_select_source(u32 dev, u32 channel_id,
1034 struct tspp_select_source *src)
1035{
1036 /* make sure the requested src id is in bounds */
1037 if (src->source > TSPP_SOURCE_MEM) {
1038 pr_err("tspp source out of bounds");
1039 return -EINVAL;
1040 }
1041
1042 /* open the stream */
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001043 tspp_open_stream(dev, channel_id, src);
Joel Nider5bd73f82011-12-14 16:53:30 +02001044
1045 return 0;
1046}
1047
1048static int tspp_set_iv(struct tspp_channel *channel, struct tspp_iv *iv)
1049{
1050 struct tspp_device *pdev = channel->pdev;
1051
1052 writel_relaxed(iv->data[0], pdev->base + TSPP_CBC_INIT_VAL(0));
1053 writel_relaxed(iv->data[1], pdev->base + TSPP_CBC_INIT_VAL(1));
1054 return 0;
1055}
1056
1057static int tspp_set_system_keys(struct tspp_channel *channel,
1058 struct tspp_system_keys *keys)
1059{
1060 int i;
1061 struct tspp_device *pdev = channel->pdev;
1062
1063 for (i = 0; i < TSPP_NUM_SYSTEM_KEYS; i++)
1064 writel_relaxed(keys->data[i], pdev->base + TSPP_SYSTEM_KEY(i));
1065
1066 return 0;
1067}
1068
1069static int tspp_channel_init(struct tspp_channel *channel,
1070 struct tspp_device *pdev)
1071{
1072 channel->cdev.owner = THIS_MODULE;
1073 cdev_init(&channel->cdev, &tspp_fops);
1074 channel->pdev = pdev;
1075 channel->data = NULL;
1076 channel->read = NULL;
1077 channel->waiting = NULL;
1078 channel->locked = NULL;
1079 channel->id = MINOR(tspp_minor);
1080 channel->used = 0;
1081 channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
1082 channel->max_buffers = TSPP_NUM_BUFFERS;
1083 channel->buffer_count = 0;
1084 channel->filter_count = 0;
1085 channel->int_freq = 1;
Liron Kuch229090d2012-10-30 17:47:50 +02001086 channel->src = TSPP_SOURCE_NONE;
1087 channel->mode = TSPP_MODE_DISABLED;
Joel Nider5bd73f82011-12-14 16:53:30 +02001088 channel->notifier = NULL;
1089 channel->notify_data = NULL;
Hamad Kadmany567bed82012-11-29 14:15:57 +02001090 channel->expiration_period_ms = 0;
Liron Kuch229090d2012-10-30 17:47:50 +02001091 channel->memfree = NULL;
1092 channel->user_info = NULL;
Joel Nider5bd73f82011-12-14 16:53:30 +02001093 init_waitqueue_head(&channel->in_queue);
1094
1095 if (cdev_add(&channel->cdev, tspp_minor++, 1) != 0) {
1096 pr_err("tspp: cdev_add failed");
1097 return -EBUSY;
1098 }
1099
1100 channel->dd = device_create(tspp_class, NULL, channel->cdev.dev,
1101 channel, "tspp%02d", channel->id);
1102 if (IS_ERR(channel->dd)) {
1103 pr_err("tspp: device_create failed: %i",
1104 (int)PTR_ERR(channel->dd));
1105 cdev_del(&channel->cdev);
1106 return -EBUSY;
1107 }
1108
1109 return 0;
1110}
1111
1112static int tspp_set_buffer_size(struct tspp_channel *channel,
1113 struct tspp_buffer *buf)
1114{
Liron Kuch229090d2012-10-30 17:47:50 +02001115 if (channel->buffer_count > 0) {
1116 pr_err("tspp: cannot set buffer size - buffers already allocated\n");
1117 return -EPERM;
1118 }
1119
Joel Nider5bd73f82011-12-14 16:53:30 +02001120 if (buf->size < TSPP_MIN_BUFFER_SIZE)
1121 channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
1122 else if (buf->size > TSPP_MAX_BUFFER_SIZE)
1123 channel->buffer_size = TSPP_MAX_BUFFER_SIZE;
1124 else
1125 channel->buffer_size = buf->size;
1126
1127 return 0;
1128}
1129
1130static void tspp_set_tsif_mode(struct tspp_channel *channel,
1131 enum tspp_tsif_mode mode)
1132{
1133 int index;
1134
1135 switch (channel->src) {
1136 case TSPP_SOURCE_TSIF0:
1137 index = 0;
1138 break;
1139 case TSPP_SOURCE_TSIF1:
1140 index = 1;
1141 break;
1142 default:
1143 pr_warn("tspp: can't set mode for non-tsif source %d",
1144 channel->src);
1145 return;
1146 }
1147 channel->pdev->tsif[index].mode = mode;
1148}
1149
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001150static void tspp_set_signal_inversion(struct tspp_channel *channel,
Liron Kuch229090d2012-10-30 17:47:50 +02001151 int clock_inverse, int data_inverse,
1152 int sync_inverse, int enable_inverse)
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001153{
1154 int index;
1155
1156 switch (channel->src) {
1157 case TSPP_SOURCE_TSIF0:
1158 index = 0;
1159 break;
1160 case TSPP_SOURCE_TSIF1:
1161 index = 1;
1162 break;
1163 default:
1164 return;
1165 }
1166 channel->pdev->tsif[index].clock_inverse = clock_inverse;
1167 channel->pdev->tsif[index].data_inverse = data_inverse;
1168 channel->pdev->tsif[index].sync_inverse = sync_inverse;
1169 channel->pdev->tsif[index].enable_inverse = enable_inverse;
1170}
1171
Liron Kuch229090d2012-10-30 17:47:50 +02001172static int tspp_is_buffer_size_aligned(u32 size, enum tspp_mode mode)
1173{
1174 u32 alignment;
1175
1176 switch (mode) {
1177 case TSPP_MODE_RAW:
1178 /* must be a multiple of 192 */
1179 alignment = (TSPP_PACKET_LENGTH + 4);
1180 if (size % alignment)
1181 return 0;
1182 return 1;
1183
1184 case TSPP_MODE_RAW_NO_SUFFIX:
1185 /* must be a multiple of 188 */
1186 alignment = TSPP_PACKET_LENGTH;
1187 if (size % alignment)
1188 return 0;
1189 return 1;
1190
1191 case TSPP_MODE_DISABLED:
1192 case TSPP_MODE_PES:
1193 default:
1194 /* no alignment requirement */
1195 return 1;
1196 }
1197
1198}
1199
1200static u32 tspp_align_buffer_size_by_mode(u32 size, enum tspp_mode mode)
1201{
1202 u32 new_size;
1203 u32 alignment;
1204
1205 switch (mode) {
1206 case TSPP_MODE_RAW:
1207 /* must be a multiple of 192 */
1208 alignment = (TSPP_PACKET_LENGTH + 4);
1209 break;
1210
1211 case TSPP_MODE_RAW_NO_SUFFIX:
1212 /* must be a multiple of 188 */
1213 alignment = TSPP_PACKET_LENGTH;
1214 break;
1215
1216 case TSPP_MODE_DISABLED:
1217 case TSPP_MODE_PES:
1218 default:
1219 /* no alignment requirement - give the user what he asks for */
1220 alignment = 1;
1221 break;
1222 }
1223 /* align up */
1224 new_size = (((size + alignment - 1) / alignment) * alignment);
1225 return new_size;
1226}
1227
1228static void tspp_destroy_buffers(u32 channel_id, struct tspp_channel *channel)
1229{
1230 int i;
1231 struct tspp_mem_buffer *pbuf, *temp;
1232
1233 pbuf = channel->data;
1234 for (i = 0; i < channel->buffer_count; i++) {
1235 if (pbuf->desc.phys_base) {
1236 if (channel->memfree) {
1237 channel->memfree(channel_id,
1238 pbuf->desc.size,
1239 pbuf->desc.virt_base,
1240 pbuf->desc.phys_base,
1241 channel->user_info);
1242 } else {
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02001243 if (!channel->dma_pool)
1244 dma_free_coherent(NULL,
1245 pbuf->desc.size,
1246 pbuf->desc.virt_base,
1247 pbuf->desc.phys_base);
1248 else
1249 dma_pool_free(channel->dma_pool,
1250 pbuf->desc.virt_base,
1251 pbuf->desc.phys_base);
Liron Kuch229090d2012-10-30 17:47:50 +02001252 }
1253 pbuf->desc.phys_base = 0;
1254 }
1255 pbuf->desc.virt_base = 0;
1256 pbuf->state = TSPP_BUF_STATE_EMPTY;
1257 temp = pbuf;
1258 pbuf = pbuf->next;
1259 kfree(temp);
1260 }
1261}
1262
Joel Nider5bd73f82011-12-14 16:53:30 +02001263/*** TSPP API functions ***/
Liron Kuch229090d2012-10-30 17:47:50 +02001264
1265/**
1266 * tspp_open_stream - open a TSPP stream for use.
1267 *
1268 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1269 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1270 * @source: stream source parameters.
1271 *
1272 * Return error status
1273 *
1274 */
1275int tspp_open_stream(u32 dev, u32 channel_id,
1276 struct tspp_select_source *source)
Joel Nider5556a852011-10-16 10:52:13 +02001277{
1278 u32 val;
1279 struct tspp_device *pdev;
Joel Nider5bd73f82011-12-14 16:53:30 +02001280 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001281
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001282 TSPP_DEBUG("tspp_open_stream %i %i %i %i",
1283 dev, channel_id, source->source, source->mode);
Liron Kuch229090d2012-10-30 17:47:50 +02001284
Joel Nider5bd73f82011-12-14 16:53:30 +02001285 if (dev >= TSPP_MAX_DEVICES) {
1286 pr_err("tspp: device id out of range");
1287 return -ENODEV;
1288 }
Joel Nider5556a852011-10-16 10:52:13 +02001289
Joel Nider5bd73f82011-12-14 16:53:30 +02001290 if (channel_id >= TSPP_NUM_CHANNELS) {
1291 pr_err("tspp: channel id out of range");
1292 return -ECHRNG;
1293 }
1294
1295 pdev = tspp_find_by_id(dev);
1296 if (!pdev) {
1297 pr_err("tspp_str: can't find device %i", dev);
1298 return -ENODEV;
1299 }
1300 channel = &pdev->channels[channel_id];
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001301 channel->src = source->source;
1302 tspp_set_tsif_mode(channel, source->mode);
1303 tspp_set_signal_inversion(channel, source->clk_inverse,
Liron Kuch229090d2012-10-30 17:47:50 +02001304 source->data_inverse, source->sync_inverse,
1305 source->enable_inverse);
Joel Nider5556a852011-10-16 10:52:13 +02001306
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001307 switch (source->source) {
Joel Nider5556a852011-10-16 10:52:13 +02001308 case TSPP_SOURCE_TSIF0:
1309 /* make sure TSIF0 is running & enabled */
1310 if (tspp_start_tsif(&pdev->tsif[0]) != 0) {
1311 pr_err("tspp: error starting tsif0");
Joel Nider5bd73f82011-12-14 16:53:30 +02001312 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001313 }
1314 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1315 writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
1316 pdev->base + TSPP_CONTROL);
1317 wmb();
1318 break;
1319 case TSPP_SOURCE_TSIF1:
1320 /* make sure TSIF1 is running & enabled */
1321 if (tspp_start_tsif(&pdev->tsif[1]) != 0) {
1322 pr_err("tspp: error starting tsif1");
Joel Nider5bd73f82011-12-14 16:53:30 +02001323 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001324 }
1325 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1326 writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
1327 pdev->base + TSPP_CONTROL);
1328 wmb();
1329 break;
1330 case TSPP_SOURCE_MEM:
1331 break;
1332 default:
Hamad Kadmanybbd06bf2012-10-23 14:15:41 +02001333 pr_err("tspp: channel %i invalid source %i",
1334 channel->id, source->source);
Joel Nider5bd73f82011-12-14 16:53:30 +02001335 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001336 }
1337
Joel Nider5556a852011-10-16 10:52:13 +02001338 return 0;
1339}
1340EXPORT_SYMBOL(tspp_open_stream);
1341
Liron Kuch229090d2012-10-30 17:47:50 +02001342/**
1343 * tspp_close_stream - close a TSPP stream.
1344 *
1345 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1346 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1347 *
1348 * Return error status
1349 *
1350 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001351int tspp_close_stream(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001352{
1353 u32 val;
1354 struct tspp_device *pdev;
Joel Nider5bd73f82011-12-14 16:53:30 +02001355 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001356
Joel Nider5bd73f82011-12-14 16:53:30 +02001357 if (channel_id >= TSPP_NUM_CHANNELS) {
1358 pr_err("tspp: channel id out of range");
1359 return -ECHRNG;
1360 }
1361 pdev = tspp_find_by_id(dev);
1362 if (!pdev) {
1363 pr_err("tspp_cs: can't find device %i", dev);
1364 return -EBUSY;
1365 }
1366 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001367
1368 switch (channel->src) {
1369 case TSPP_SOURCE_TSIF0:
1370 tspp_stop_tsif(&pdev->tsif[0]);
1371 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1372 writel_relaxed(val | TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
1373 pdev->base + TSPP_CONTROL);
1374 wmb();
1375 break;
1376 case TSPP_SOURCE_TSIF1:
1377 tspp_stop_tsif(&pdev->tsif[1]);
1378 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1379 writel_relaxed(val | TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
1380 pdev->base + TSPP_CONTROL);
1381 break;
1382 case TSPP_SOURCE_MEM:
1383 break;
1384 case TSPP_SOURCE_NONE:
1385 break;
1386 }
1387
Joel Nider5bd73f82011-12-14 16:53:30 +02001388 channel->src = TSPP_SOURCE_NONE;
Joel Nider5556a852011-10-16 10:52:13 +02001389 return 0;
1390}
1391EXPORT_SYMBOL(tspp_close_stream);
1392
Liron Kuch229090d2012-10-30 17:47:50 +02001393/**
1394 * tspp_open_channel - open a TSPP channel.
1395 *
1396 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1397 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1398 *
1399 * Return error status
1400 *
1401 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001402int tspp_open_channel(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001403{
1404 int rc = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001405 struct sps_connect *config;
1406 struct sps_register_event *event;
1407 struct tspp_channel *channel;
1408 struct tspp_device *pdev;
1409
1410 if (channel_id >= TSPP_NUM_CHANNELS) {
1411 pr_err("tspp: channel id out of range");
1412 return -ECHRNG;
1413 }
1414 pdev = tspp_find_by_id(dev);
1415 if (!pdev) {
1416 pr_err("tspp_oc: can't find device %i", dev);
1417 return -ENODEV;
1418 }
1419 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001420
1421 if (channel->used) {
1422 pr_err("tspp channel already in use");
Joel Nider5bd73f82011-12-14 16:53:30 +02001423 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001424 }
1425
Joel Nider5bd73f82011-12-14 16:53:30 +02001426 config = &channel->config;
1427 event = &channel->event;
1428
1429 /* start the clocks if needed */
1430 tspp_clock_start(pdev);
1431 if (tspp_channels_in_use(pdev) == 0)
1432 wake_lock(&pdev->wake_lock);
1433
Joel Nider5556a852011-10-16 10:52:13 +02001434 /* mark it as used */
1435 channel->used = 1;
1436
1437 /* start the bam */
1438 channel->pipe = sps_alloc_endpoint();
1439 if (channel->pipe == 0) {
1440 pr_err("tspp: error allocating endpoint");
1441 rc = -ENOMEM;
1442 goto err_sps_alloc;
1443 }
1444
1445 /* get default configuration */
1446 sps_get_config(channel->pipe, config);
1447
Joel Nider5bd73f82011-12-14 16:53:30 +02001448 config->source = pdev->bam_handle;
Joel Nider5556a852011-10-16 10:52:13 +02001449 config->destination = SPS_DEV_HANDLE_MEM;
1450 config->mode = SPS_MODE_SRC;
Joel Nider5bd73f82011-12-14 16:53:30 +02001451 config->options =
1452 SPS_O_AUTO_ENABLE | /* connection is auto-enabled */
1453 SPS_O_STREAMING | /* streaming mode */
1454 SPS_O_DESC_DONE | /* interrupt on end of descriptor */
Hamad Kadmany567bed82012-11-29 14:15:57 +02001455 SPS_O_ACK_TRANSFERS | /* must use sps_get_iovec() */
1456 SPS_O_HYBRID; /* Read actual descriptors in sps_get_iovec() */
Joel Nider5556a852011-10-16 10:52:13 +02001457 config->src_pipe_index = channel->id;
1458 config->desc.size =
Hamad Kadmany567bed82012-11-29 14:15:57 +02001459 TSPP_SPS_DESCRIPTOR_COUNT * SPS_DESCRIPTOR_SIZE;
Joel Nider5556a852011-10-16 10:52:13 +02001460 config->desc.base = dma_alloc_coherent(NULL,
1461 config->desc.size,
1462 &config->desc.phys_base,
1463 GFP_KERNEL);
1464 if (config->desc.base == 0) {
1465 pr_err("tspp: error allocating sps descriptors");
1466 rc = -ENOMEM;
1467 goto err_desc_alloc;
1468 }
1469
1470 memset(config->desc.base, 0, config->desc.size);
1471
1472 rc = sps_connect(channel->pipe, config);
1473 if (rc) {
1474 pr_err("tspp: error connecting bam");
1475 goto err_connect;
1476 }
1477
1478 event->mode = SPS_TRIGGER_CALLBACK;
Joel Nider5bd73f82011-12-14 16:53:30 +02001479 event->options = SPS_O_DESC_DONE;
Joel Nider5556a852011-10-16 10:52:13 +02001480 event->callback = tspp_sps_complete_cb;
1481 event->xfer_done = NULL;
Joel Nider5bd73f82011-12-14 16:53:30 +02001482 event->user = pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001483
1484 rc = sps_register_event(channel->pipe, event);
1485 if (rc) {
1486 pr_err("tspp: error registering event");
1487 goto err_event;
1488 }
1489
Hamad Kadmany567bed82012-11-29 14:15:57 +02001490 init_timer(&channel->expiration_timer);
1491 channel->expiration_timer.function = tspp_expiration_timer;
1492 channel->expiration_timer.data = (unsigned long)pdev;
1493 channel->expiration_timer.expires = 0xffffffffL;
1494
Joel Nider5bd73f82011-12-14 16:53:30 +02001495 rc = pm_runtime_get(&pdev->pdev->dev);
Joel Nider5556a852011-10-16 10:52:13 +02001496 if (rc < 0) {
Joel Nider5bd73f82011-12-14 16:53:30 +02001497 dev_err(&pdev->pdev->dev,
Joel Nider5556a852011-10-16 10:52:13 +02001498 "Runtime PM: Unable to wake up tspp device, rc = %d",
1499 rc);
1500 }
Joel Nider5556a852011-10-16 10:52:13 +02001501 return 0;
1502
1503err_event:
1504 sps_disconnect(channel->pipe);
1505err_connect:
1506 dma_free_coherent(NULL, config->desc.size, config->desc.base,
1507 config->desc.phys_base);
1508err_desc_alloc:
1509 sps_free_endpoint(channel->pipe);
1510err_sps_alloc:
1511 return rc;
1512}
1513EXPORT_SYMBOL(tspp_open_channel);
1514
Liron Kuch229090d2012-10-30 17:47:50 +02001515/**
1516 * tspp_close_channel - close a TSPP channel.
1517 *
1518 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1519 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1520 *
1521 * Return error status
1522 *
1523 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001524int tspp_close_channel(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001525{
1526 int i;
1527 int id;
1528 u32 val;
Joel Nider5556a852011-10-16 10:52:13 +02001529
Joel Nider5bd73f82011-12-14 16:53:30 +02001530 struct sps_connect *config;
1531 struct tspp_device *pdev;
1532 struct tspp_channel *channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02001533
1534 if (channel_id >= TSPP_NUM_CHANNELS) {
1535 pr_err("tspp: channel id out of range");
1536 return -ECHRNG;
1537 }
1538 pdev = tspp_find_by_id(dev);
1539 if (!pdev) {
1540 pr_err("tspp_close: can't find device %i", dev);
1541 return -ENODEV;
1542 }
1543 channel = &pdev->channels[channel_id];
1544
1545 /* if the channel is not used, we are done */
1546 if (!channel->used)
1547 return 0;
1548
Hamad Kadmany567bed82012-11-29 14:15:57 +02001549 if (channel->expiration_period_ms)
1550 del_timer(&channel->expiration_timer);
1551
Joel Nider5bd73f82011-12-14 16:53:30 +02001552 channel->notifier = NULL;
1553 channel->notify_data = NULL;
Hamad Kadmany567bed82012-11-29 14:15:57 +02001554 channel->expiration_period_ms = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001555
1556 config = &channel->config;
1557 pdev = channel->pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001558
1559 /* disable pipe (channel) */
1560 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1561 writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE);
1562 wmb();
1563
1564 /* unregister all filters for this channel */
1565 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1566 struct tspp_pid_filter *tspp_filter =
Joel Nider5bd73f82011-12-14 16:53:30 +02001567 &pdev->filters[channel->src]->filter[i];
Joel Nider5556a852011-10-16 10:52:13 +02001568 id = FILTER_GET_PIPE_NUMBER0(tspp_filter);
1569 if (id == channel->id) {
1570 if (FILTER_HAS_ENCRYPTION(tspp_filter))
1571 tspp_free_key_entry(
1572 FILTER_GET_KEY_NUMBER(tspp_filter));
1573 tspp_filter->config = 0;
1574 tspp_filter->filter = 0;
1575 }
1576 }
1577 channel->filter_count = 0;
1578
1579 /* stop the stream */
Joel Nider5bd73f82011-12-14 16:53:30 +02001580 tspp_close_stream(dev, channel->id);
Joel Nider5556a852011-10-16 10:52:13 +02001581
1582 /* disconnect the bam */
1583 if (sps_disconnect(channel->pipe) != 0)
1584 pr_warn("tspp: Error freeing sps endpoint (%i)", channel->id);
1585
1586 /* destroy the buffers */
1587 dma_free_coherent(NULL, config->desc.size, config->desc.base,
1588 config->desc.phys_base);
1589
Liron Kuch229090d2012-10-30 17:47:50 +02001590 tspp_destroy_buffers(channel_id, channel);
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02001591 if (channel->dma_pool) {
1592 dma_pool_destroy(channel->dma_pool);
1593 channel->dma_pool = NULL;
1594 }
Liron Kuch229090d2012-10-30 17:47:50 +02001595
1596 channel->src = TSPP_SOURCE_NONE;
1597 channel->mode = TSPP_MODE_DISABLED;
1598 channel->memfree = NULL;
1599 channel->user_info = NULL;
Joel Nider5556a852011-10-16 10:52:13 +02001600 channel->buffer_count = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001601 channel->data = NULL;
1602 channel->read = NULL;
1603 channel->waiting = NULL;
1604 channel->locked = NULL;
1605 channel->used = 0;
Joel Nider5556a852011-10-16 10:52:13 +02001606
Joel Nider5bd73f82011-12-14 16:53:30 +02001607 if (tspp_channels_in_use(pdev) == 0)
1608 wake_unlock(&pdev->wake_lock);
1609 tspp_clock_stop(pdev);
1610
Joel Nider5556a852011-10-16 10:52:13 +02001611 return 0;
1612}
1613EXPORT_SYMBOL(tspp_close_channel);
1614
Liron Kuch229090d2012-10-30 17:47:50 +02001615/**
Hamad Kadmany586fb392013-01-31 14:49:20 +02001616 * tspp_get_ref_clk_counter - return the TSIF clock reference (TCR) counter.
1617 *
1618 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1619 * @source: The TSIF source from which the counter should be read
1620 * @tcr_counter: the value of TCR counter
1621 *
1622 * Return error status
1623 *
1624 * TCR increments at a rate equal to 27 MHz/256 = 105.47 kHz.
1625 * If source is neither TSIF 0 or TSIF1 0 is returned.
1626 */
1627int tspp_get_ref_clk_counter(u32 dev, enum tspp_source source, u32 *tcr_counter)
1628{
1629 struct tspp_device *pdev;
1630 struct tspp_tsif_device *tsif_device;
1631
1632 if (!tcr_counter)
1633 return -EINVAL;
1634
1635 pdev = tspp_find_by_id(dev);
1636 if (!pdev) {
1637 pr_err("tspp_get_ref_clk_counter: can't find device %i\n", dev);
1638 return -ENODEV;
1639 }
1640
1641 switch (source) {
1642 case TSPP_SOURCE_TSIF0:
1643 tsif_device = &pdev->tsif[0];
1644 break;
1645
1646 case TSPP_SOURCE_TSIF1:
1647 tsif_device = &pdev->tsif[1];
1648 break;
1649
1650 default:
1651 tsif_device = NULL;
1652 break;
1653 }
1654
1655 if (tsif_device && tsif_device->ref_count)
1656 *tcr_counter = ioread32(tsif_device->base + TSIF_CLK_REF_OFF);
1657 else
1658 *tcr_counter = 0;
1659
1660 return 0;
1661}
1662EXPORT_SYMBOL(tspp_get_ref_clk_counter);
1663
1664/**
Liron Kuch229090d2012-10-30 17:47:50 +02001665 * tspp_add_filter - add a TSPP filter to a channel.
1666 *
1667 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1668 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1669 * @filter: TSPP filter parameters
1670 *
1671 * Return error status
1672 *
1673 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001674int tspp_add_filter(u32 dev, u32 channel_id,
Joel Nider5556a852011-10-16 10:52:13 +02001675 struct tspp_filter *filter)
1676{
Liron Kuch229090d2012-10-30 17:47:50 +02001677 int i, rc;
Joel Nider5556a852011-10-16 10:52:13 +02001678 int other_channel;
1679 int entry;
1680 u32 val, pid, enabled;
Joel Nider5bd73f82011-12-14 16:53:30 +02001681 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001682 struct tspp_pid_filter p;
Joel Nider5bd73f82011-12-14 16:53:30 +02001683 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001684
Joel Nider5bd73f82011-12-14 16:53:30 +02001685 TSPP_DEBUG("tspp: add filter");
1686 if (channel_id >= TSPP_NUM_CHANNELS) {
1687 pr_err("tspp: channel id out of range");
1688 return -ECHRNG;
1689 }
1690 pdev = tspp_find_by_id(dev);
1691 if (!pdev) {
1692 pr_err("tspp_add: can't find device %i", dev);
1693 return -ENODEV;
1694 }
1695
1696 channel = &pdev->channels[channel_id];
1697
Joel Nider5556a852011-10-16 10:52:13 +02001698 if (filter->source > TSPP_SOURCE_MEM) {
1699 pr_err("tspp invalid source");
Joel Nider5bd73f82011-12-14 16:53:30 +02001700 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001701 }
1702
1703 if (filter->priority >= TSPP_NUM_PRIORITIES) {
1704 pr_err("tspp invalid source");
Joel Nider5bd73f82011-12-14 16:53:30 +02001705 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001706 }
1707
Liron Kuch229090d2012-10-30 17:47:50 +02001708 channel->mode = filter->mode;
1709 /*
1710 * if buffers are already allocated, verify they fulfil
1711 * the alignment requirements.
1712 */
1713 if ((channel->buffer_count > 0) &&
1714 (!tspp_is_buffer_size_aligned(channel->buffer_size, channel->mode)))
1715 pr_warn("tspp: buffers allocated with incorrect alignment\n");
Joel Nider5556a852011-10-16 10:52:13 +02001716
1717 if (filter->mode == TSPP_MODE_PES) {
1718 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1719 struct tspp_pid_filter *tspp_filter =
Joel Nider5bd73f82011-12-14 16:53:30 +02001720 &pdev->filters[channel->src]->filter[i];
Joel Nider5556a852011-10-16 10:52:13 +02001721 pid = FILTER_GET_PIPE_PID((tspp_filter));
1722 enabled = FILTER_GET_PIPE_PROCESS0(tspp_filter);
1723 if (enabled && (pid == filter->pid)) {
1724 other_channel =
1725 FILTER_GET_PIPE_NUMBER0(tspp_filter);
1726 pr_err("tspp: pid 0x%x already in use by channel %i",
1727 filter->pid, other_channel);
Joel Nider5bd73f82011-12-14 16:53:30 +02001728 return -EBADSLT;
Joel Nider5556a852011-10-16 10:52:13 +02001729 }
1730 }
1731 }
1732
1733 /* make sure this priority is not already in use */
1734 enabled = FILTER_GET_PIPE_PROCESS0(
Joel Nider5bd73f82011-12-14 16:53:30 +02001735 (&(pdev->filters[channel->src]->filter[filter->priority])));
Joel Nider5556a852011-10-16 10:52:13 +02001736 if (enabled) {
1737 pr_err("tspp: filter priority %i source %i is already enabled\n",
1738 filter->priority, channel->src);
Joel Nider5bd73f82011-12-14 16:53:30 +02001739 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001740 }
1741
1742 if (channel->mode == TSPP_MODE_PES) {
1743 /* if we are already processing in PES mode, disable pipe
1744 (channel) and filter to be updated */
1745 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1746 writel_relaxed(val | (1 << channel->id),
1747 pdev->base + TSPP_PS_DISABLE);
1748 wmb();
1749 }
1750
1751 /* update entry */
1752 p.filter = 0;
Joel Nider5bd73f82011-12-14 16:53:30 +02001753 p.config = FILTER_TRANS_END_DISABLE;
Joel Nider5556a852011-10-16 10:52:13 +02001754 FILTER_SET_PIPE_PROCESS0((&p), filter->mode);
1755 FILTER_SET_PIPE_PID((&p), filter->pid);
1756 FILTER_SET_PID_MASK((&p), filter->mask);
1757 FILTER_SET_PIPE_NUMBER0((&p), channel->id);
1758 FILTER_SET_PIPE_PROCESS1((&p), TSPP_MODE_DISABLED);
1759 if (filter->decrypt) {
1760 entry = tspp_get_key_entry();
1761 if (entry == -1) {
1762 pr_err("tspp: no more keys available!");
1763 } else {
1764 p.config |= FILTER_DECRYPT;
1765 FILTER_SET_KEY_NUMBER((&p), entry);
1766 }
1767 }
Joel Nider5556a852011-10-16 10:52:13 +02001768
Joel Nider5bd73f82011-12-14 16:53:30 +02001769 pdev->filters[channel->src]->
Joel Nider5556a852011-10-16 10:52:13 +02001770 filter[filter->priority].config = p.config;
Joel Nider5bd73f82011-12-14 16:53:30 +02001771 pdev->filters[channel->src]->
Joel Nider5556a852011-10-16 10:52:13 +02001772 filter[filter->priority].filter = p.filter;
1773
Liron Kuch229090d2012-10-30 17:47:50 +02001774 /*
1775 * allocate buffers if needed (i.e. if user did has not already called
1776 * tspp_allocate_buffers() explicitly).
1777 */
1778 if (channel->buffer_count == 0) {
1779 channel->buffer_size =
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02001780 tspp_align_buffer_size_by_mode(channel->buffer_size,
Liron Kuch229090d2012-10-30 17:47:50 +02001781 channel->mode);
1782 rc = tspp_allocate_buffers(dev, channel->id,
1783 channel->max_buffers,
1784 channel->buffer_size,
1785 channel->int_freq, NULL, NULL, NULL);
1786 if (rc != 0) {
1787 pr_err("tspp: tspp_allocate_buffers failed\n");
1788 return rc;
1789 }
Joel Nider5bd73f82011-12-14 16:53:30 +02001790 }
1791
Joel Nider5556a852011-10-16 10:52:13 +02001792 /* reenable pipe */
1793 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1794 writel_relaxed(val & ~(1 << channel->id), pdev->base + TSPP_PS_DISABLE);
1795 wmb();
1796 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1797
Joel Nider5556a852011-10-16 10:52:13 +02001798 channel->filter_count++;
1799
1800 return 0;
1801}
1802EXPORT_SYMBOL(tspp_add_filter);
1803
Liron Kuch229090d2012-10-30 17:47:50 +02001804/**
1805 * tspp_remove_filter - remove a TSPP filter from a channel.
1806 *
1807 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1808 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1809 * @filter: TSPP filter parameters
1810 *
1811 * Return error status
1812 *
1813 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001814int tspp_remove_filter(u32 dev, u32 channel_id,
Joel Nider5556a852011-10-16 10:52:13 +02001815 struct tspp_filter *filter)
1816{
1817 int entry;
1818 u32 val;
Joel Nider5bd73f82011-12-14 16:53:30 +02001819 struct tspp_device *pdev;
1820 int src;
1821 struct tspp_pid_filter *tspp_filter;
1822 struct tspp_channel *channel;
1823
1824 if (channel_id >= TSPP_NUM_CHANNELS) {
1825 pr_err("tspp: channel id out of range");
1826 return -ECHRNG;
1827 }
1828 pdev = tspp_find_by_id(dev);
1829 if (!pdev) {
1830 pr_err("tspp_remove: can't find device %i", dev);
1831 return -ENODEV;
1832 }
1833 channel = &pdev->channels[channel_id];
1834
1835 src = channel->src;
1836 tspp_filter = &(pdev->filters[src]->filter[filter->priority]);
Joel Nider5556a852011-10-16 10:52:13 +02001837
1838 /* disable pipe (channel) */
1839 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1840 writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE);
1841 wmb();
1842
1843 /* update data keys */
1844 if (tspp_filter->config & FILTER_DECRYPT) {
1845 entry = FILTER_GET_KEY_NUMBER(tspp_filter);
1846 tspp_free_key_entry(entry);
1847 }
1848
1849 /* update pid table */
1850 tspp_filter->config = 0;
1851 tspp_filter->filter = 0;
1852
1853 channel->filter_count--;
1854
1855 /* reenable pipe */
1856 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1857 writel_relaxed(val & ~(1 << channel->id),
1858 pdev->base + TSPP_PS_DISABLE);
1859 wmb();
1860 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1861
1862 return 0;
1863}
1864EXPORT_SYMBOL(tspp_remove_filter);
1865
Liron Kuch229090d2012-10-30 17:47:50 +02001866/**
1867 * tspp_set_key - set TSPP key in key table.
1868 *
1869 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1870 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1871 * @key: TSPP key parameters
1872 *
1873 * Return error status
1874 *
1875 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001876int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key)
Joel Nider5556a852011-10-16 10:52:13 +02001877{
1878 int i;
1879 int id;
1880 int key_index;
1881 int data;
Joel Nider5bd73f82011-12-14 16:53:30 +02001882 struct tspp_channel *channel;
1883 struct tspp_device *pdev;
1884
1885 if (channel_id >= TSPP_NUM_CHANNELS) {
1886 pr_err("tspp: channel id out of range");
1887 return -ECHRNG;
1888 }
1889 pdev = tspp_find_by_id(dev);
1890 if (!pdev) {
1891 pr_err("tspp_set: can't find device %i", dev);
1892 return -ENODEV;
1893 }
1894 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001895
1896 /* read the key index used by this channel */
1897 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1898 struct tspp_pid_filter *tspp_filter =
Joel Nider5bd73f82011-12-14 16:53:30 +02001899 &(pdev->filters[channel->src]->filter[i]);
Joel Nider5556a852011-10-16 10:52:13 +02001900 id = FILTER_GET_PIPE_NUMBER0(tspp_filter);
1901 if (id == channel->id) {
1902 if (FILTER_HAS_ENCRYPTION(tspp_filter)) {
1903 key_index = FILTER_GET_KEY_NUMBER(tspp_filter);
1904 break;
1905 }
1906 }
1907 }
1908 if (i == TSPP_NUM_PRIORITIES) {
1909 pr_err("tspp: no encryption on this channel");
Joel Nider5bd73f82011-12-14 16:53:30 +02001910 return -ENOKEY;
Joel Nider5556a852011-10-16 10:52:13 +02001911 }
1912
1913 if (key->parity == TSPP_KEY_PARITY_EVEN) {
Joel Nider5bd73f82011-12-14 16:53:30 +02001914 pdev->tspp_key_table->entry[key_index].even_lsb = key->lsb;
1915 pdev->tspp_key_table->entry[key_index].even_msb = key->msb;
Joel Nider5556a852011-10-16 10:52:13 +02001916 } else {
Joel Nider5bd73f82011-12-14 16:53:30 +02001917 pdev->tspp_key_table->entry[key_index].odd_lsb = key->lsb;
1918 pdev->tspp_key_table->entry[key_index].odd_msb = key->msb;
Joel Nider5556a852011-10-16 10:52:13 +02001919 }
1920 data = readl_relaxed(channel->pdev->base + TSPP_KEY_VALID);
1921
1922 return 0;
1923}
1924EXPORT_SYMBOL(tspp_set_key);
1925
Liron Kuch229090d2012-10-30 17:47:50 +02001926/**
1927 * tspp_register_notification - register TSPP channel notification function.
1928 *
1929 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1930 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1931 * @pNotify: notification function
1932 * @userdata: user data to pass to notification function
1933 * @timer_ms: notification for partially filled buffers
1934 *
1935 * Return error status
1936 *
1937 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001938int tspp_register_notification(u32 dev, u32 channel_id,
1939 tspp_notifier *pNotify, void *userdata, u32 timer_ms)
Joel Nider5556a852011-10-16 10:52:13 +02001940{
Joel Nider5bd73f82011-12-14 16:53:30 +02001941 struct tspp_channel *channel;
1942 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001943
Joel Nider5bd73f82011-12-14 16:53:30 +02001944 if (channel_id >= TSPP_NUM_CHANNELS) {
1945 pr_err("tspp: channel id out of range");
1946 return -ECHRNG;
1947 }
1948 pdev = tspp_find_by_id(dev);
1949 if (!pdev) {
1950 pr_err("tspp_reg: can't find device %i", dev);
1951 return -ENODEV;
1952 }
1953 channel = &pdev->channels[channel_id];
1954 channel->notifier = pNotify;
1955 channel->notify_data = userdata;
Hamad Kadmany567bed82012-11-29 14:15:57 +02001956 channel->expiration_period_ms = timer_ms;
1957
Joel Nider5556a852011-10-16 10:52:13 +02001958 return 0;
1959}
Joel Nider5bd73f82011-12-14 16:53:30 +02001960EXPORT_SYMBOL(tspp_register_notification);
Joel Nider5556a852011-10-16 10:52:13 +02001961
Liron Kuch229090d2012-10-30 17:47:50 +02001962/**
1963 * tspp_unregister_notification - unregister TSPP channel notification function.
1964 *
1965 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1966 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1967 *
1968 * Return error status
1969 *
1970 */
Joel Nider5bd73f82011-12-14 16:53:30 +02001971int tspp_unregister_notification(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001972{
Joel Nider5bd73f82011-12-14 16:53:30 +02001973 struct tspp_channel *channel;
1974 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001975
Joel Nider5bd73f82011-12-14 16:53:30 +02001976 if (channel_id >= TSPP_NUM_CHANNELS) {
1977 pr_err("tspp: channel id out of range");
1978 return -ECHRNG;
1979 }
1980 pdev = tspp_find_by_id(dev);
1981 if (!pdev) {
1982 pr_err("tspp_unreg: can't find device %i", dev);
1983 return -ENODEV;
1984 }
1985 channel = &pdev->channels[channel_id];
1986 channel->notifier = NULL;
1987 channel->notify_data = 0;
Joel Nider5556a852011-10-16 10:52:13 +02001988 return 0;
1989}
Joel Nider5bd73f82011-12-14 16:53:30 +02001990EXPORT_SYMBOL(tspp_unregister_notification);
Joel Nider5556a852011-10-16 10:52:13 +02001991
Liron Kuch229090d2012-10-30 17:47:50 +02001992/**
1993 * tspp_get_buffer - get TSPP data buffer.
1994 *
1995 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1996 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1997 *
1998 * Return error status
1999 *
2000 */
Joel Nider5bd73f82011-12-14 16:53:30 +02002001const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02002002{
Joel Nider5bd73f82011-12-14 16:53:30 +02002003 struct tspp_mem_buffer *buffer;
2004 struct tspp_channel *channel;
2005 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02002006
Joel Nider5bd73f82011-12-14 16:53:30 +02002007 if (channel_id >= TSPP_NUM_CHANNELS) {
2008 pr_err("tspp: channel id out of range");
2009 return NULL;
2010 }
2011 pdev = tspp_find_by_id(dev);
2012 if (!pdev) {
2013 pr_err("tspp_get: can't find device %i", dev);
2014 return NULL;
2015 }
2016 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02002017
Joel Nider5bd73f82011-12-14 16:53:30 +02002018 if (!channel->read) {
2019 pr_warn("tspp: no buffer to get on channel %i!",
2020 channel->id);
2021 return NULL;
2022 }
2023
2024 buffer = channel->read;
2025 /* see if we have any buffers ready to read */
2026 if (buffer->state != TSPP_BUF_STATE_DATA)
2027 return 0;
2028
2029 if (buffer->state == TSPP_BUF_STATE_DATA) {
2030 /* mark the buffer as busy */
2031 buffer->state = TSPP_BUF_STATE_LOCKED;
2032
2033 /* increment the pointer along the list */
2034 channel->read = channel->read->next;
2035 }
2036
2037 return &buffer->desc;
2038}
2039EXPORT_SYMBOL(tspp_get_buffer);
2040
Liron Kuch229090d2012-10-30 17:47:50 +02002041/**
2042 * tspp_release_buffer - release TSPP data buffer back to TSPP.
2043 *
2044 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2045 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2046 * @descriptor_id: buffer descriptor ID
2047 *
2048 * Return error status
2049 *
2050 */
Joel Nider5bd73f82011-12-14 16:53:30 +02002051int tspp_release_buffer(u32 dev, u32 channel_id, u32 descriptor_id)
2052{
2053 int i, found = 0;
2054 struct tspp_mem_buffer *buffer;
2055 struct tspp_channel *channel;
2056 struct tspp_device *pdev;
2057
2058 if (channel_id >= TSPP_NUM_CHANNELS) {
2059 pr_err("tspp: channel id out of range");
2060 return -ECHRNG;
2061 }
2062 pdev = tspp_find_by_id(dev);
2063 if (!pdev) {
2064 pr_err("tspp: can't find device %i", dev);
2065 return -ENODEV;
2066 }
2067 channel = &pdev->channels[channel_id];
2068
2069 if (descriptor_id > channel->buffer_count)
2070 pr_warn("tspp: desc id looks weird 0x%08x", descriptor_id);
2071
2072 /* find the correct descriptor */
2073 buffer = channel->locked;
2074 for (i = 0; i < channel->buffer_count; i++) {
2075 if (buffer->desc.id == descriptor_id) {
2076 found = 1;
2077 break;
2078 }
2079 buffer = buffer->next;
2080 }
2081 channel->locked = channel->locked->next;
2082
2083 if (!found) {
2084 pr_err("tspp: cant find desc %i", descriptor_id);
2085 return -EINVAL;
2086 }
2087
2088 /* make sure the buffer is in the expected state */
2089 if (buffer->state != TSPP_BUF_STATE_LOCKED) {
2090 pr_err("tspp: buffer %i not locked", descriptor_id);
2091 return -EINVAL;
2092 }
2093 /* unlock the buffer and requeue it */
2094 buffer->state = TSPP_BUF_STATE_WAITING;
2095
2096 if (tspp_queue_buffer(channel, buffer))
2097 pr_warn("tspp: can't requeue buffer");
Joel Nider5556a852011-10-16 10:52:13 +02002098 return 0;
2099}
Joel Nider5bd73f82011-12-14 16:53:30 +02002100EXPORT_SYMBOL(tspp_release_buffer);
2101
Liron Kuch229090d2012-10-30 17:47:50 +02002102/**
2103 * tspp_allocate_buffers - allocate TSPP data buffers.
2104 *
2105 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2106 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2107 * @count: number of buffers to allocate
2108 * @size: size of each buffer to allocate
2109 * @int_freq: interrupt frequency
2110 * @alloc: user defined memory allocator function. Pass NULL for default.
2111 * @memfree: user defined memory free function. Pass NULL for default.
2112 * @user: user data to pass to the memory allocator/free function
2113 *
2114 * Return error status
2115 *
2116 * The user can optionally call this function explicitly to allocate the TSPP
2117 * data buffers. Alternatively, if the user did not call this function, it
2118 * is called implicitly by tspp_add_filter().
2119 */
2120int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count, u32 size,
2121 u32 int_freq, tspp_allocator *alloc,
2122 tspp_memfree *memfree, void *user)
Joel Nider5bd73f82011-12-14 16:53:30 +02002123{
2124 struct tspp_channel *channel;
2125 struct tspp_device *pdev;
2126 struct tspp_mem_buffer *last = NULL;
2127
2128 TSPP_DEBUG("tspp_allocate_buffers");
2129
2130 if (channel_id >= TSPP_NUM_CHANNELS) {
Liron Kuch229090d2012-10-30 17:47:50 +02002131 pr_err("%s: channel id out of range", __func__);
Joel Nider5bd73f82011-12-14 16:53:30 +02002132 return -ECHRNG;
2133 }
Liron Kuch229090d2012-10-30 17:47:50 +02002134
Joel Nider5bd73f82011-12-14 16:53:30 +02002135 pdev = tspp_find_by_id(dev);
2136 if (!pdev) {
Liron Kuch229090d2012-10-30 17:47:50 +02002137 pr_err("%s: can't find device %i", __func__, dev);
Joel Nider5bd73f82011-12-14 16:53:30 +02002138 return -ENODEV;
2139 }
Liron Kuch229090d2012-10-30 17:47:50 +02002140
2141 if (count < MIN_ACCEPTABLE_BUFFER_COUNT) {
2142 pr_err("%s: tspp requires a minimum of %i buffers\n",
2143 __func__, MIN_ACCEPTABLE_BUFFER_COUNT);
2144 return -EINVAL;
2145 }
2146
Joel Nider5bd73f82011-12-14 16:53:30 +02002147 channel = &pdev->channels[channel_id];
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02002148
Liron Kuch229090d2012-10-30 17:47:50 +02002149 /* allow buffer allocation only if there was no previous buffer
2150 * allocation for this channel.
2151 */
2152 if (channel->buffer_count > 0) {
2153 pr_err("%s: buffers already allocated for channel %u",
2154 __func__, channel_id);
2155 return -EINVAL;
2156 }
Joel Nider5bd73f82011-12-14 16:53:30 +02002157
2158 channel->max_buffers = count;
2159
2160 /* set up interrupt frequency */
Liron Kuch229090d2012-10-30 17:47:50 +02002161 if (int_freq > channel->max_buffers) {
Joel Nider5bd73f82011-12-14 16:53:30 +02002162 int_freq = channel->max_buffers;
Liron Kuch229090d2012-10-30 17:47:50 +02002163 pr_warn("%s: setting interrupt frequency to %u\n",
2164 __func__, int_freq);
Joel Nider5bd73f82011-12-14 16:53:30 +02002165 }
Liron Kuch229090d2012-10-30 17:47:50 +02002166 channel->int_freq = int_freq;
2167 /*
2168 * it is the responsibility of the caller to tspp_allocate_buffers(),
2169 * whether it's the user or the driver, to make sure the size parameter
2170 * is compatible to the channel mode.
2171 */
2172 channel->buffer_size = size;
Joel Nider5bd73f82011-12-14 16:53:30 +02002173
Liron Kuch229090d2012-10-30 17:47:50 +02002174 /* save user defined memory free function for later use */
2175 channel->memfree = memfree;
2176 channel->user_info = user;
2177
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02002178 /*
2179 * For small buffers, create a DMA pool so that memory
2180 * is not wasted through dma_alloc_coherent.
2181 */
2182 if (TSPP_USE_DMA_POOL(channel->buffer_size)) {
2183 channel->dma_pool = dma_pool_create("tspp",
2184 NULL, channel->buffer_size, 0, 0);
2185 if (!channel->dma_pool) {
2186 pr_err("%s: Can't allocate memory pool\n", __func__);
2187 return -ENOMEM;
2188 }
2189 } else {
2190 channel->dma_pool = NULL;
2191 }
2192
2193
Liron Kuch229090d2012-10-30 17:47:50 +02002194 for (channel->buffer_count = 0;
2195 channel->buffer_count < channel->max_buffers;
Joel Nider5bd73f82011-12-14 16:53:30 +02002196 channel->buffer_count++) {
2197
2198 /* allocate the descriptor */
2199 struct tspp_mem_buffer *desc = (struct tspp_mem_buffer *)
2200 kmalloc(sizeof(struct tspp_mem_buffer), GFP_KERNEL);
2201 if (!desc) {
Liron Kuch229090d2012-10-30 17:47:50 +02002202 pr_warn("%s: Can't allocate desc %i",
2203 __func__, channel->buffer_count);
Joel Nider5bd73f82011-12-14 16:53:30 +02002204 break;
2205 }
2206
2207 desc->desc.id = channel->buffer_count;
2208 /* allocate the buffer */
2209 if (tspp_alloc_buffer(channel_id, &desc->desc,
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02002210 channel->buffer_size, channel->dma_pool,
2211 alloc, user) != 0) {
Joel Nider5bd73f82011-12-14 16:53:30 +02002212 kfree(desc);
Liron Kuch229090d2012-10-30 17:47:50 +02002213 pr_warn("%s: Can't allocate buffer %i",
2214 __func__, channel->buffer_count);
Joel Nider5bd73f82011-12-14 16:53:30 +02002215 break;
2216 }
2217
2218 /* add the descriptor to the list */
2219 desc->filled = 0;
2220 desc->read_index = 0;
2221 if (!channel->data) {
2222 channel->data = desc;
2223 desc->next = channel->data;
2224 } else {
2225 last->next = desc;
2226 }
2227 last = desc;
2228 desc->next = channel->data;
2229
2230 /* prepare the sps descriptor */
2231 desc->sps.phys_base = desc->desc.phys_base;
2232 desc->sps.base = desc->desc.virt_base;
2233 desc->sps.size = desc->desc.size;
2234
2235 /* start the transfer */
2236 if (tspp_queue_buffer(channel, desc))
Liron Kuch229090d2012-10-30 17:47:50 +02002237 pr_err("%s: can't queue buffer %i",
2238 __func__, desc->desc.id);
2239 }
2240
2241 if (channel->buffer_count < channel->max_buffers) {
2242 /*
2243 * we failed to allocate the requested number of buffers.
2244 * we don't allow a partial success, so need to clean up here.
2245 */
2246 tspp_destroy_buffers(channel_id, channel);
2247 channel->buffer_count = 0;
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02002248
2249 if (channel->dma_pool) {
2250 dma_pool_destroy(channel->dma_pool);
2251 channel->dma_pool = NULL;
2252 }
Liron Kuch229090d2012-10-30 17:47:50 +02002253 return -ENOMEM;
Joel Nider5bd73f82011-12-14 16:53:30 +02002254 }
2255
2256 channel->waiting = channel->data;
2257 channel->read = channel->data;
2258 channel->locked = channel->data;
Liron Kuch229090d2012-10-30 17:47:50 +02002259
Hamad Kadmany567bed82012-11-29 14:15:57 +02002260 /* Now that buffers are scheduled to HW, kick data expiration timer */
2261 if (channel->expiration_period_ms)
2262 mod_timer(&channel->expiration_timer,
2263 jiffies +
2264 MSEC_TO_JIFFIES(
2265 channel->expiration_period_ms));
2266
Joel Nider5bd73f82011-12-14 16:53:30 +02002267 return 0;
2268}
2269EXPORT_SYMBOL(tspp_allocate_buffers);
Joel Nider5556a852011-10-16 10:52:13 +02002270
2271/*** File Operations ***/
2272static ssize_t tspp_open(struct inode *inode, struct file *filp)
2273{
Joel Nider5bd73f82011-12-14 16:53:30 +02002274 u32 dev;
Joel Nider5556a852011-10-16 10:52:13 +02002275 struct tspp_channel *channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02002276
2277 TSPP_DEBUG("tspp_open");
Joel Nider5556a852011-10-16 10:52:13 +02002278 channel = container_of(inode->i_cdev, struct tspp_channel, cdev);
2279 filp->private_data = channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02002280 dev = channel->pdev->pdev->id;
Joel Nider5556a852011-10-16 10:52:13 +02002281
2282 /* if this channel is already in use, quit */
2283 if (channel->used) {
2284 pr_err("tspp channel %i already in use",
2285 MINOR(channel->cdev.dev));
2286 return -EACCES;
2287 }
2288
Joel Nider5bd73f82011-12-14 16:53:30 +02002289 if (tspp_open_channel(dev, channel->id) != 0) {
Joel Nider5556a852011-10-16 10:52:13 +02002290 pr_err("tspp: error opening channel");
2291 return -EACCES;
2292 }
2293
2294 return 0;
2295}
2296
2297static unsigned int tspp_poll(struct file *filp, struct poll_table_struct *p)
2298{
2299 unsigned long flags;
2300 unsigned int mask = 0;
2301 struct tspp_channel *channel;
2302 channel = filp->private_data;
2303
2304 /* register the wait queue for this channel */
2305 poll_wait(filp, &channel->in_queue, p);
2306
2307 spin_lock_irqsave(&channel->pdev->spinlock, flags);
Joel Nider5bd73f82011-12-14 16:53:30 +02002308 if (channel->read &&
2309 channel->read->state == TSPP_BUF_STATE_DATA)
Joel Nider5556a852011-10-16 10:52:13 +02002310 mask = POLLIN | POLLRDNORM;
2311
2312 spin_unlock_irqrestore(&channel->pdev->spinlock, flags);
2313
2314 return mask;
2315}
2316
2317static ssize_t tspp_release(struct inode *inode, struct file *filp)
2318{
Joel Nider5bd73f82011-12-14 16:53:30 +02002319 struct tspp_channel *channel = filp->private_data;
2320 u32 dev = channel->pdev->pdev->id;
2321 TSPP_DEBUG("tspp_release");
Joel Nider5556a852011-10-16 10:52:13 +02002322
Joel Nider5bd73f82011-12-14 16:53:30 +02002323 tspp_close_channel(dev, channel->id);
Joel Nider5556a852011-10-16 10:52:13 +02002324
2325 return 0;
2326}
2327
2328static ssize_t tspp_read(struct file *filp, char __user *buf, size_t count,
2329 loff_t *f_pos)
2330{
2331 size_t size = 0;
2332 size_t transferred = 0;
2333 struct tspp_channel *channel;
2334 struct tspp_mem_buffer *buffer;
2335 channel = filp->private_data;
2336
2337 TSPP_DEBUG("tspp_read");
Joel Nider5bd73f82011-12-14 16:53:30 +02002338
2339 while (!channel->read) {
2340 if (filp->f_flags & O_NONBLOCK) {
2341 pr_warn("tspp: no buffer on channel %i!",
2342 channel->id);
2343 return -EAGAIN;
2344 }
2345 /* go to sleep if there is nothing to read */
2346 if (wait_event_interruptible(channel->in_queue,
2347 (channel->read != NULL))) {
2348 pr_err("tspp: rude awakening\n");
2349 return -ERESTARTSYS;
2350 }
2351 }
2352
2353 buffer = channel->read;
2354
Joel Nider5556a852011-10-16 10:52:13 +02002355 /* see if we have any buffers ready to read */
2356 while (buffer->state != TSPP_BUF_STATE_DATA) {
2357 if (filp->f_flags & O_NONBLOCK) {
2358 pr_warn("tspp: nothing to read on channel %i!",
2359 channel->id);
2360 return -EAGAIN;
2361 }
2362 /* go to sleep if there is nothing to read */
Joel Nider5556a852011-10-16 10:52:13 +02002363 if (wait_event_interruptible(channel->in_queue,
2364 (buffer->state == TSPP_BUF_STATE_DATA))) {
2365 pr_err("tspp: rude awakening\n");
2366 return -ERESTARTSYS;
2367 }
2368 }
2369
2370 while (buffer->state == TSPP_BUF_STATE_DATA) {
2371 size = min(count, buffer->filled);
Joel Nider5556a852011-10-16 10:52:13 +02002372 if (size == 0)
2373 break;
2374
Joel Nider5bd73f82011-12-14 16:53:30 +02002375 if (copy_to_user(buf, buffer->desc.virt_base +
Joel Nider5556a852011-10-16 10:52:13 +02002376 buffer->read_index, size)) {
2377 pr_err("tspp: error copying to user buffer");
Joel Nider5bd73f82011-12-14 16:53:30 +02002378 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02002379 }
2380 buf += size;
2381 count -= size;
2382 transferred += size;
2383 buffer->read_index += size;
2384
Liron Kuch229090d2012-10-30 17:47:50 +02002385 /*
2386 * after reading the end of the buffer, requeue it,
2387 * and set up for reading the next one
2388 */
Joel Nider5bd73f82011-12-14 16:53:30 +02002389 if (buffer->read_index == buffer->filled) {
Joel Nider5556a852011-10-16 10:52:13 +02002390 buffer->state = TSPP_BUF_STATE_WAITING;
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02002391
Joel Nider5bd73f82011-12-14 16:53:30 +02002392 if (tspp_queue_buffer(channel, buffer))
2393 pr_err("tspp: can't submit transfer");
Hamad Kadmanybb0d0f92013-01-06 12:08:13 +02002394
Joel Nider5bd73f82011-12-14 16:53:30 +02002395 channel->locked = channel->read;
2396 channel->read = channel->read->next;
Joel Nider5556a852011-10-16 10:52:13 +02002397 }
2398 }
2399
2400 return transferred;
2401}
2402
2403static long tspp_ioctl(struct file *filp,
2404 unsigned int param0, unsigned long param1)
2405{
Joel Nider5bd73f82011-12-14 16:53:30 +02002406 u32 dev;
Joel Nider5556a852011-10-16 10:52:13 +02002407 int rc = -1;
2408 struct tspp_channel *channel;
Joel Nider5bd73f82011-12-14 16:53:30 +02002409 struct tspp_select_source ss;
2410 struct tspp_filter f;
2411 struct tspp_key k;
2412 struct tspp_iv iv;
2413 struct tspp_system_keys sk;
2414 struct tspp_buffer b;
Joel Nider5556a852011-10-16 10:52:13 +02002415 channel = filp->private_data;
Joel Nider5bd73f82011-12-14 16:53:30 +02002416 dev = channel->pdev->pdev->id;
Joel Nider5556a852011-10-16 10:52:13 +02002417
2418 if (!param1)
2419 return -EINVAL;
2420
2421 switch (param0) {
2422 case TSPP_IOCTL_SELECT_SOURCE:
Joel Nider5bd73f82011-12-14 16:53:30 +02002423 if (!access_ok(VERIFY_READ, param1,
2424 sizeof(struct tspp_select_source))) {
2425 return -EBUSY;
2426 }
2427 if (__copy_from_user(&ss, (void *)param1,
2428 sizeof(struct tspp_select_source)) == 0)
2429 rc = tspp_select_source(dev, channel->id, &ss);
Joel Nider5556a852011-10-16 10:52:13 +02002430 break;
2431 case TSPP_IOCTL_ADD_FILTER:
Joel Nider5bd73f82011-12-14 16:53:30 +02002432 if (!access_ok(VERIFY_READ, param1,
2433 sizeof(struct tspp_filter))) {
2434 return -ENOSR;
2435 }
2436 if (__copy_from_user(&f, (void *)param1,
2437 sizeof(struct tspp_filter)) == 0)
2438 rc = tspp_add_filter(dev, channel->id, &f);
Joel Nider5556a852011-10-16 10:52:13 +02002439 break;
2440 case TSPP_IOCTL_REMOVE_FILTER:
Joel Nider5bd73f82011-12-14 16:53:30 +02002441 if (!access_ok(VERIFY_READ, param1,
2442 sizeof(struct tspp_filter))) {
2443 return -EBUSY;
2444 }
2445 if (__copy_from_user(&f, (void *)param1,
2446 sizeof(struct tspp_filter)) == 0)
2447 rc = tspp_remove_filter(dev, channel->id, &f);
Joel Nider5556a852011-10-16 10:52:13 +02002448 break;
2449 case TSPP_IOCTL_SET_KEY:
Joel Nider5bd73f82011-12-14 16:53:30 +02002450 if (!access_ok(VERIFY_READ, param1,
2451 sizeof(struct tspp_key))) {
2452 return -EBUSY;
2453 }
2454 if (__copy_from_user(&k, (void *)param1,
2455 sizeof(struct tspp_key)) == 0)
2456 rc = tspp_set_key(dev, channel->id, &k);
Joel Nider5556a852011-10-16 10:52:13 +02002457 break;
2458 case TSPP_IOCTL_SET_IV:
Joel Nider5bd73f82011-12-14 16:53:30 +02002459 if (!access_ok(VERIFY_READ, param1,
2460 sizeof(struct tspp_iv))) {
2461 return -EBUSY;
2462 }
2463 if (__copy_from_user(&iv, (void *)param1,
2464 sizeof(struct tspp_iv)) == 0)
2465 rc = tspp_set_iv(channel, &iv);
Joel Nider5556a852011-10-16 10:52:13 +02002466 break;
2467 case TSPP_IOCTL_SET_SYSTEM_KEYS:
Joel Nider5bd73f82011-12-14 16:53:30 +02002468 if (!access_ok(VERIFY_READ, param1,
2469 sizeof(struct tspp_system_keys))) {
2470 return -EINVAL;
2471 }
2472 if (__copy_from_user(&sk, (void *)param1,
2473 sizeof(struct tspp_system_keys)) == 0)
2474 rc = tspp_set_system_keys(channel, &sk);
Joel Nider5556a852011-10-16 10:52:13 +02002475 break;
2476 case TSPP_IOCTL_BUFFER_SIZE:
Joel Nider5bd73f82011-12-14 16:53:30 +02002477 if (!access_ok(VERIFY_READ, param1,
2478 sizeof(struct tspp_buffer))) {
2479 rc = -EINVAL;
2480 }
2481 if (__copy_from_user(&b, (void *)param1,
2482 sizeof(struct tspp_buffer)) == 0)
2483 rc = tspp_set_buffer_size(channel, &b);
Joel Nider5556a852011-10-16 10:52:13 +02002484 break;
2485 default:
2486 pr_err("tspp: Unknown ioctl %i", param0);
2487 }
2488
Liron Kuch229090d2012-10-30 17:47:50 +02002489 /*
2490 * normalize the return code in case one of the subfunctions does
2491 * something weird
2492 */
Joel Nider5556a852011-10-16 10:52:13 +02002493 if (rc != 0)
Joel Nider5bd73f82011-12-14 16:53:30 +02002494 rc = -ENOIOCTLCMD;
Joel Nider5556a852011-10-16 10:52:13 +02002495
2496 return rc;
2497}
2498
2499/*** debugfs ***/
Joel Nider5556a852011-10-16 10:52:13 +02002500static int debugfs_iomem_x32_set(void *data, u64 val)
2501{
2502 writel_relaxed(val, data);
2503 wmb();
2504 return 0;
2505}
2506
2507static int debugfs_iomem_x32_get(void *data, u64 *val)
2508{
2509 *val = readl_relaxed(data);
2510 return 0;
2511}
2512
2513DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, debugfs_iomem_x32_get,
2514 debugfs_iomem_x32_set, "0x%08llx");
2515
2516static void tsif_debugfs_init(struct tspp_tsif_device *tsif_device,
2517 int instance)
2518{
2519 char name[10];
2520 snprintf(name, 10, "tsif%i", instance);
2521 tsif_device->dent_tsif = debugfs_create_dir(
2522 name, NULL);
2523 if (tsif_device->dent_tsif) {
2524 int i;
2525 void __iomem *base = tsif_device->base;
2526 for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++) {
2527 tsif_device->debugfs_tsif_regs[i] =
2528 debugfs_create_file(
2529 debugfs_tsif_regs[i].name,
2530 debugfs_tsif_regs[i].mode,
2531 tsif_device->dent_tsif,
2532 base + debugfs_tsif_regs[i].offset,
2533 &fops_iomem_x32);
2534 }
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002535
2536 debugfs_create_u32(
2537 "stat_rx_chunks",
2538 S_IRUGO|S_IWUGO,
2539 tsif_device->dent_tsif,
2540 &tsif_device->stat_rx);
2541
2542 debugfs_create_u32(
2543 "stat_overflow",
2544 S_IRUGO|S_IWUGO,
2545 tsif_device->dent_tsif,
2546 &tsif_device->stat_overflow);
2547
2548 debugfs_create_u32(
2549 "stat_lost_sync",
2550 S_IRUGO|S_IWUGO,
2551 tsif_device->dent_tsif,
2552 &tsif_device->stat_lost_sync);
2553
2554 debugfs_create_u32(
2555 "stat_timeout",
2556 S_IRUGO|S_IWUGO,
2557 tsif_device->dent_tsif,
2558 &tsif_device->stat_timeout);
2559
Joel Nider5556a852011-10-16 10:52:13 +02002560 }
2561}
2562
2563static void tsif_debugfs_exit(struct tspp_tsif_device *tsif_device)
2564{
2565 if (tsif_device->dent_tsif) {
2566 int i;
2567 debugfs_remove_recursive(tsif_device->dent_tsif);
2568 tsif_device->dent_tsif = NULL;
2569 for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++)
2570 tsif_device->debugfs_tsif_regs[i] = NULL;
2571 }
2572}
2573
2574static void tspp_debugfs_init(struct tspp_device *device, int instance)
2575{
2576 char name[10];
2577 snprintf(name, 10, "tspp%i", instance);
2578 device->dent = debugfs_create_dir(
2579 name, NULL);
2580 if (device->dent) {
2581 int i;
2582 void __iomem *base = device->base;
2583 for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++) {
2584 device->debugfs_regs[i] =
2585 debugfs_create_file(
2586 debugfs_tspp_regs[i].name,
2587 debugfs_tspp_regs[i].mode,
2588 device->dent,
2589 base + debugfs_tspp_regs[i].offset,
2590 &fops_iomem_x32);
2591 }
2592 }
2593}
2594
2595static void tspp_debugfs_exit(struct tspp_device *device)
2596{
2597 if (device->dent) {
2598 int i;
2599 debugfs_remove_recursive(device->dent);
2600 device->dent = NULL;
2601 for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++)
2602 device->debugfs_regs[i] = NULL;
2603 }
2604}
Joel Nider5556a852011-10-16 10:52:13 +02002605
2606static int __devinit msm_tspp_probe(struct platform_device *pdev)
2607{
2608 int rc = -ENODEV;
2609 u32 version;
Liron Kuch229090d2012-10-30 17:47:50 +02002610 u32 i, j;
Joel Nider5556a852011-10-16 10:52:13 +02002611 struct msm_tspp_platform_data *data;
2612 struct tspp_device *device;
2613 struct resource *mem_tsif0;
2614 struct resource *mem_tsif1;
2615 struct resource *mem_tspp;
2616 struct resource *mem_bam;
Liron Kuch229090d2012-10-30 17:47:50 +02002617 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02002618
2619 /* must have platform data */
2620 data = pdev->dev.platform_data;
2621 if (!data) {
2622 pr_err("tspp: Platform data not available");
2623 rc = -EINVAL;
2624 goto out;
2625 }
2626
2627 /* check for valid device id */
Joel Nider5bd73f82011-12-14 16:53:30 +02002628 if ((pdev->id < 0) || (pdev->id >= TSPP_MAX_DEVICES)) {
Joel Nider5556a852011-10-16 10:52:13 +02002629 pr_err("tspp: Invalid device ID %d", pdev->id);
2630 rc = -EINVAL;
2631 goto out;
2632 }
2633
2634 /* OK, we will use this device */
2635 device = kzalloc(sizeof(struct tspp_device), GFP_KERNEL);
2636 if (!device) {
2637 pr_err("tspp: Failed to allocate memory for device");
2638 rc = -ENOMEM;
2639 goto out;
2640 }
2641
2642 /* set up references */
2643 device->pdev = pdev;
2644 platform_set_drvdata(pdev, device);
2645
2646 /* map clocks */
2647 if (data->tsif_pclk) {
Joel Niderb9662ca2012-06-10 14:21:11 +03002648 device->tsif_pclk = clk_get(&pdev->dev, data->tsif_pclk);
Joel Nider5556a852011-10-16 10:52:13 +02002649 if (IS_ERR(device->tsif_pclk)) {
2650 pr_err("tspp: failed to get %s",
2651 data->tsif_pclk);
2652 rc = PTR_ERR(device->tsif_pclk);
2653 device->tsif_pclk = NULL;
2654 goto err_pclock;
2655 }
2656 }
2657 if (data->tsif_ref_clk) {
Joel Niderb9662ca2012-06-10 14:21:11 +03002658 device->tsif_ref_clk = clk_get(&pdev->dev, data->tsif_ref_clk);
Joel Nider5556a852011-10-16 10:52:13 +02002659 if (IS_ERR(device->tsif_ref_clk)) {
2660 pr_err("tspp: failed to get %s",
2661 data->tsif_ref_clk);
2662 rc = PTR_ERR(device->tsif_ref_clk);
2663 device->tsif_ref_clk = NULL;
2664 goto err_refclock;
2665 }
2666 }
2667
2668 /* map I/O memory */
2669 mem_tsif0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2670 if (!mem_tsif0) {
2671 pr_err("tspp: Missing tsif0 MEM resource");
2672 rc = -ENXIO;
2673 goto err_res_tsif0;
2674 }
2675 device->tsif[0].base = ioremap(mem_tsif0->start,
2676 resource_size(mem_tsif0));
2677 if (!device->tsif[0].base) {
2678 pr_err("tspp: ioremap failed");
2679 goto err_map_tsif0;
2680 }
2681
2682 mem_tsif1 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
2683 if (!mem_tsif1) {
2684 dev_err(&pdev->dev, "Missing tsif1 MEM resource");
2685 rc = -ENXIO;
2686 goto err_res_tsif1;
2687 }
2688 device->tsif[1].base = ioremap(mem_tsif1->start,
2689 resource_size(mem_tsif1));
2690 if (!device->tsif[1].base) {
2691 dev_err(&pdev->dev, "ioremap failed");
2692 goto err_map_tsif1;
2693 }
2694
2695 mem_tspp = platform_get_resource(pdev, IORESOURCE_MEM, 2);
2696 if (!mem_tspp) {
2697 dev_err(&pdev->dev, "Missing MEM resource");
2698 rc = -ENXIO;
2699 goto err_res_dev;
2700 }
2701 device->base = ioremap(mem_tspp->start, resource_size(mem_tspp));
2702 if (!device->base) {
2703 dev_err(&pdev->dev, "ioremap failed");
2704 goto err_map_dev;
2705 }
2706
2707 mem_bam = platform_get_resource(pdev, IORESOURCE_MEM, 3);
2708 if (!mem_bam) {
2709 pr_err("tspp: Missing bam MEM resource");
2710 rc = -ENXIO;
2711 goto err_res_bam;
2712 }
2713 memset(&device->bam_props, 0, sizeof(device->bam_props));
2714 device->bam_props.phys_addr = mem_bam->start;
2715 device->bam_props.virt_addr = ioremap(mem_bam->start,
2716 resource_size(mem_bam));
2717 if (!device->bam_props.virt_addr) {
2718 dev_err(&pdev->dev, "ioremap failed");
2719 goto err_map_bam;
2720 }
2721
2722 /* map TSPP IRQ */
2723 rc = platform_get_irq(pdev, 0);
2724 if (rc > 0) {
2725 device->tspp_irq = rc;
2726 rc = request_irq(device->tspp_irq, tspp_isr, IRQF_SHARED,
2727 dev_name(&pdev->dev), device);
2728 if (rc) {
2729 dev_err(&pdev->dev, "failed to request IRQ %d : %d",
2730 device->tspp_irq, rc);
2731 goto err_irq;
2732 }
2733 } else {
2734 dev_err(&pdev->dev, "failed to get tspp IRQ");
2735 goto err_irq;
2736 }
2737
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002738 /* map TSIF IRQs */
2739 device->tsif[0].tsif_irq = TSIF1_IRQ;
2740 device->tsif[1].tsif_irq = TSIF2_IRQ;
2741
2742 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
2743 rc = request_irq(device->tsif[i].tsif_irq,
2744 tsif_isr, IRQF_SHARED,
2745 dev_name(&pdev->dev), &device->tsif[i]);
2746 if (rc) {
2747 dev_warn(&pdev->dev, "failed to request TSIF%d IRQ: %d",
2748 i, rc);
2749 device->tsif[i].tsif_irq = 0;
2750 }
2751 }
2752
Joel Nider5556a852011-10-16 10:52:13 +02002753 /* BAM IRQ */
2754 device->bam_irq = TSIF_BAM_IRQ;
2755
2756 /* GPIOs */
2757 rc = tspp_start_gpios(device);
2758 if (rc)
2759 goto err_gpio;
2760
2761 /* power management */
2762 pm_runtime_set_active(&pdev->dev);
2763 pm_runtime_enable(&pdev->dev);
2764
Joel Nider5556a852011-10-16 10:52:13 +02002765 tspp_debugfs_init(device, 0);
2766
2767 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
2768 tsif_debugfs_init(&device->tsif[i], i);
Joel Nider5556a852011-10-16 10:52:13 +02002769
2770 wake_lock_init(&device->wake_lock, WAKE_LOCK_SUSPEND,
2771 dev_name(&pdev->dev));
2772
2773 /* set up pointers to ram-based 'registers' */
Joel Nider5bd73f82011-12-14 16:53:30 +02002774 device->filters[0] = device->base + TSPP_PID_FILTER_TABLE0;
2775 device->filters[1] = device->base + TSPP_PID_FILTER_TABLE1;
2776 device->filters[2] = device->base + TSPP_PID_FILTER_TABLE2;
2777 device->tspp_key_table = device->base + TSPP_DATA_KEY;
2778 device->tspp_global_performance =
2779 device->base + TSPP_GLOBAL_PERFORMANCE;
2780 device->tspp_pipe_context =
2781 device->base + TSPP_PIPE_CONTEXT;
2782 device->tspp_pipe_performance =
2783 device->base + TSPP_PIPE_PERFORMANCE;
Joel Nider5556a852011-10-16 10:52:13 +02002784
2785 device->bam_props.summing_threshold = 0x10;
2786 device->bam_props.irq = device->bam_irq;
2787 device->bam_props.manage = SPS_BAM_MGR_LOCAL;
2788
2789 if (sps_register_bam_device(&device->bam_props,
2790 &device->bam_handle) != 0) {
2791 pr_err("tspp: failed to register bam");
2792 goto err_bam;
2793 }
2794
Joel Nider5bd73f82011-12-14 16:53:30 +02002795 if (tspp_clock_start(device) != 0) {
2796 dev_err(&pdev->dev, "Can't start clocks");
2797 goto err_clock;
Joel Nider5556a852011-10-16 10:52:13 +02002798 }
2799
2800 spin_lock_init(&device->spinlock);
2801 tasklet_init(&device->tlet, tspp_sps_complete_tlet,
2802 (unsigned long)device);
2803
2804 /* initialize everything to a known state */
2805 tspp_global_reset(device);
2806
2807 version = readl_relaxed(device->base + TSPP_VERSION);
2808 if (version != 1)
2809 pr_warn("tspp: unrecognized hw version=%i", version);
2810
Joel Nider5bd73f82011-12-14 16:53:30 +02002811 /* initialize the channels */
Joel Nider5556a852011-10-16 10:52:13 +02002812 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
Joel Nider5bd73f82011-12-14 16:53:30 +02002813 if (tspp_channel_init(&(device->channels[i]), device) != 0) {
2814 pr_err("tspp_channel_init failed");
2815 goto err_channel;
2816 }
Joel Nider5556a852011-10-16 10:52:13 +02002817 }
2818
Joel Nider5bd73f82011-12-14 16:53:30 +02002819 /* stop the clocks for power savings */
2820 tspp_clock_stop(device);
2821
2822 /* everything is ok, so add the device to the list */
2823 list_add_tail(&(device->devlist), &tspp_devices);
2824
Joel Nider5556a852011-10-16 10:52:13 +02002825 return 0;
2826
Joel Nider5bd73f82011-12-14 16:53:30 +02002827err_channel:
Liron Kuch229090d2012-10-30 17:47:50 +02002828 /* uninitialize channels */
2829 for (j = 0; j < i; j++) {
2830 channel = &(device->channels[i]);
2831 device_destroy(tspp_class, channel->cdev.dev);
2832 cdev_del(&channel->cdev);
2833 }
Joel Nider5bd73f82011-12-14 16:53:30 +02002834err_clock:
Joel Nider5556a852011-10-16 10:52:13 +02002835 sps_deregister_bam_device(device->bam_handle);
2836err_bam:
Joel Nider5556a852011-10-16 10:52:13 +02002837 tspp_debugfs_exit(device);
2838 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
2839 tsif_debugfs_exit(&device->tsif[i]);
Joel Nider5556a852011-10-16 10:52:13 +02002840err_gpio:
2841err_irq:
2842 tspp_stop_gpios(device);
2843 iounmap(device->bam_props.virt_addr);
2844err_map_bam:
2845err_res_bam:
2846 iounmap(device->base);
2847err_map_dev:
2848err_res_dev:
2849 iounmap(device->tsif[1].base);
2850err_map_tsif1:
2851err_res_tsif1:
2852 iounmap(device->tsif[0].base);
2853err_map_tsif0:
2854err_res_tsif0:
2855 if (device->tsif_ref_clk)
2856 clk_put(device->tsif_ref_clk);
2857err_refclock:
2858 if (device->tsif_pclk)
2859 clk_put(device->tsif_pclk);
2860err_pclock:
2861 kfree(device);
2862
2863out:
2864 return rc;
2865}
2866
2867static int __devexit msm_tspp_remove(struct platform_device *pdev)
2868{
Joel Nider5bd73f82011-12-14 16:53:30 +02002869 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02002870 u32 i;
Joel Nider5556a852011-10-16 10:52:13 +02002871
2872 struct tspp_device *device = platform_get_drvdata(pdev);
2873
Joel Nider5bd73f82011-12-14 16:53:30 +02002874 /* free the buffers, and delete the channels */
2875 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
2876 channel = &device->channels[i];
2877 tspp_close_channel(device->pdev->id, i);
2878 device_destroy(tspp_class, channel->cdev.dev);
2879 cdev_del(&channel->cdev);
2880 }
2881
Joel Nider5556a852011-10-16 10:52:13 +02002882 sps_deregister_bam_device(device->bam_handle);
2883
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002884 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
Joel Nider5556a852011-10-16 10:52:13 +02002885 tsif_debugfs_exit(&device->tsif[i]);
Hamad Kadmanyf0cc2712012-11-25 09:49:51 +02002886 if (device->tsif[i].tsif_irq)
2887 free_irq(device->tsif[i].tsif_irq, &device->tsif[i]);
2888 }
Joel Nider5556a852011-10-16 10:52:13 +02002889
2890 wake_lock_destroy(&device->wake_lock);
2891 free_irq(device->tspp_irq, device);
2892 tspp_stop_gpios(device);
2893
2894 iounmap(device->bam_props.virt_addr);
2895 iounmap(device->base);
2896 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
2897 iounmap(device->tsif[i].base);
2898
2899 if (device->tsif_ref_clk)
2900 clk_put(device->tsif_ref_clk);
2901
2902 if (device->tsif_pclk)
2903 clk_put(device->tsif_pclk);
2904
2905 pm_runtime_disable(&pdev->dev);
2906 pm_runtime_put(&pdev->dev);
2907 kfree(device);
2908
2909 return 0;
2910}
2911
2912/*** power management ***/
2913
2914static int tspp_runtime_suspend(struct device *dev)
2915{
2916 dev_dbg(dev, "pm_runtime: suspending...");
2917 return 0;
2918}
2919
2920static int tspp_runtime_resume(struct device *dev)
2921{
2922 dev_dbg(dev, "pm_runtime: resuming...");
2923 return 0;
2924}
2925
2926static const struct dev_pm_ops tspp_dev_pm_ops = {
2927 .runtime_suspend = tspp_runtime_suspend,
2928 .runtime_resume = tspp_runtime_resume,
2929};
2930
2931static struct platform_driver msm_tspp_driver = {
2932 .probe = msm_tspp_probe,
2933 .remove = __exit_p(msm_tspp_remove),
2934 .driver = {
2935 .name = "msm_tspp",
2936 .pm = &tspp_dev_pm_ops,
2937 },
2938};
2939
2940
2941static int __init mod_init(void)
2942{
Joel Nider5556a852011-10-16 10:52:13 +02002943 int rc;
2944
Joel Nider5bd73f82011-12-14 16:53:30 +02002945 /* make the char devs (channels) */
Joel Nider5556a852011-10-16 10:52:13 +02002946 rc = alloc_chrdev_region(&tspp_minor, 0, TSPP_NUM_CHANNELS, "tspp");
2947 if (rc) {
2948 pr_err("tspp: alloc_chrdev_region failed: %d", rc);
2949 goto err_devrgn;
2950 }
2951
2952 tspp_class = class_create(THIS_MODULE, "tspp");
2953 if (IS_ERR(tspp_class)) {
2954 rc = PTR_ERR(tspp_class);
2955 pr_err("tspp: Error creating class: %d", rc);
2956 goto err_class;
2957 }
2958
Joel Nider5bd73f82011-12-14 16:53:30 +02002959 /* register the driver, and check hardware */
2960 rc = platform_driver_register(&msm_tspp_driver);
2961 if (rc) {
2962 pr_err("tspp: platform_driver_register failed: %d", rc);
2963 goto err_register;
Joel Nider5556a852011-10-16 10:52:13 +02002964 }
2965
2966 return 0;
2967
Joel Nider5bd73f82011-12-14 16:53:30 +02002968err_register:
2969 class_destroy(tspp_class);
Joel Nider5556a852011-10-16 10:52:13 +02002970err_class:
2971 unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
2972err_devrgn:
Joel Nider5556a852011-10-16 10:52:13 +02002973 return rc;
2974}
2975
2976static void __exit mod_exit(void)
2977{
Joel Nider5bd73f82011-12-14 16:53:30 +02002978 /* delete low level driver */
2979 platform_driver_unregister(&msm_tspp_driver);
Joel Nider5556a852011-10-16 10:52:13 +02002980
Joel Nider5bd73f82011-12-14 16:53:30 +02002981 /* delete upper layer interface */
Joel Nider5556a852011-10-16 10:52:13 +02002982 class_destroy(tspp_class);
2983 unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
Joel Nider5556a852011-10-16 10:52:13 +02002984}
2985
2986module_init(mod_init);
2987module_exit(mod_exit);
2988
Joel Nider5bd73f82011-12-14 16:53:30 +02002989MODULE_DESCRIPTION("TSPP platform device and char dev");
Joel Nider5556a852011-10-16 10:52:13 +02002990MODULE_LICENSE("GPL v2");