blob: 2dfa4041a180db4a3d659d0cb076c9b0864b70ef [file] [log] [blame]
Gilad Broner6049ea32014-04-10 09:48:44 +03001/* Copyright (c) 2011-2014, 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 Nider435ad8e2011-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 Nider435ad8e2011-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 Nider435ad8e2011-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 Nider435ad8e2011-12-14 16:53:30 +020026#include <linux/ioport.h> /* XXX_ mem_region */
27#include <linux/dma-mapping.h> /* dma_XXX */
Hamad Kadmany090709b2013-01-06 12:08:13 +020028#include <linux/dmapool.h> /* DMA pools */
Joel Nider435ad8e2011-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 Nider435ad8e2011-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 */
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -070036#include <linux/regulator/consumer.h>
Joel Nider435ad8e2011-12-14 16:53:30 +020037#include <mach/sps.h> /* BAM stuff */
Joel Nider5556a852011-10-16 10:52:13 +020038#include <mach/gpio.h>
Joel Nider435ad8e2011-12-14 16:53:30 +020039#include <linux/wakelock.h> /* Locking functions */
Hamad Kadmany81cee052012-11-29 14:15:57 +020040#include <linux/timer.h> /* Timer services */
41#include <linux/jiffies.h> /* Jiffies counter */
Joel Nider5556a852011-10-16 10:52:13 +020042#include <mach/dma.h>
43#include <mach/msm_tspp.h>
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -070044#include <mach/rpm-regulator-smd.h>
Joel Nider5556a852011-10-16 10:52:13 +020045#include <linux/debugfs.h>
Liron Kuch59339922013-01-01 18:29:47 +020046#include <linux/of.h>
47#include <linux/of_gpio.h>
Liron Kuch275c0b32013-02-10 15:19:32 +020048#include <linux/string.h>
Hamad Kadmanyef5ce992013-06-03 09:30:50 +030049#include <mach/msm_bus.h>
Joel Nider5556a852011-10-16 10:52:13 +020050
51/*
52 * General defines
53 */
Joel Nider5556a852011-10-16 10:52:13 +020054#define TSPP_TSIF_INSTANCES 2
Liron Kuch275c0b32013-02-10 15:19:32 +020055#define TSPP_GPIOS_PER_TSIF 4
Joel Nider5556a852011-10-16 10:52:13 +020056#define TSPP_FILTER_TABLES 3
Joel Nider435ad8e2011-12-14 16:53:30 +020057#define TSPP_MAX_DEVICES 1
Joel Nider5556a852011-10-16 10:52:13 +020058#define TSPP_NUM_CHANNELS 16
59#define TSPP_NUM_PRIORITIES 16
60#define TSPP_NUM_KEYS 8
61#define INVALID_CHANNEL 0xFFFFFFFF
Hamad Kadmany81cee052012-11-29 14:15:57 +020062
63/*
64 * BAM descriptor FIFO size (in number of descriptors).
65 * Max number of descriptors allowed by SPS which is 8K-1.
Hamad Kadmany81cee052012-11-29 14:15:57 +020066 */
Hamad Kadmany24020352013-05-22 12:54:18 +030067#define TSPP_SPS_DESCRIPTOR_COUNT (8 * 1024 - 1)
Joel Nider5556a852011-10-16 10:52:13 +020068#define TSPP_PACKET_LENGTH 188
69#define TSPP_MIN_BUFFER_SIZE (TSPP_PACKET_LENGTH)
Hamad Kadmany81cee052012-11-29 14:15:57 +020070
71/* Max descriptor buffer size allowed by SPS */
72#define TSPP_MAX_BUFFER_SIZE (32 * 1024 - 1)
73
74/*
Hamad Kadmany090709b2013-01-06 12:08:13 +020075 * Returns whether to use DMA pool for TSPP output buffers.
76 * For buffers smaller than page size, using DMA pool
77 * provides better memory utilization as dma_alloc_coherent
78 * allocates minimum of page size.
79 */
80#define TSPP_USE_DMA_POOL(buff_size) ((buff_size) < PAGE_SIZE)
81
82/*
Hamad Kadmany81cee052012-11-29 14:15:57 +020083 * Max allowed TSPP buffers/descriptors.
84 * If SPS desc FIFO holds X descriptors, we can queue up to X-1 descriptors.
85 */
86#define TSPP_NUM_BUFFERS (TSPP_SPS_DESCRIPTOR_COUNT - 1)
Joel Nider5556a852011-10-16 10:52:13 +020087#define TSPP_TSIF_DEFAULT_TIME_LIMIT 60
88#define SPS_DESCRIPTOR_SIZE 8
89#define MIN_ACCEPTABLE_BUFFER_COUNT 2
Joel Nider435ad8e2011-12-14 16:53:30 +020090#define TSPP_DEBUG(msg...)
Joel Nider5556a852011-10-16 10:52:13 +020091
92/*
93 * TSIF register offsets
94 */
95#define TSIF_STS_CTL_OFF (0x0)
96#define TSIF_TIME_LIMIT_OFF (0x4)
97#define TSIF_CLK_REF_OFF (0x8)
98#define TSIF_LPBK_FLAGS_OFF (0xc)
99#define TSIF_LPBK_DATA_OFF (0x10)
100#define TSIF_TEST_CTL_OFF (0x14)
101#define TSIF_TEST_MODE_OFF (0x18)
102#define TSIF_TEST_RESET_OFF (0x1c)
103#define TSIF_TEST_EXPORT_OFF (0x20)
104#define TSIF_TEST_CURRENT_OFF (0x24)
105
106#define TSIF_DATA_PORT_OFF (0x100)
107
108/* bits for TSIF_STS_CTL register */
109#define TSIF_STS_CTL_EN_IRQ BIT(28)
110#define TSIF_STS_CTL_PACK_AVAIL BIT(27)
111#define TSIF_STS_CTL_1ST_PACKET BIT(26)
112#define TSIF_STS_CTL_OVERFLOW BIT(25)
113#define TSIF_STS_CTL_LOST_SYNC BIT(24)
114#define TSIF_STS_CTL_TIMEOUT BIT(23)
115#define TSIF_STS_CTL_INV_SYNC BIT(21)
116#define TSIF_STS_CTL_INV_NULL BIT(20)
117#define TSIF_STS_CTL_INV_ERROR BIT(19)
118#define TSIF_STS_CTL_INV_ENABLE BIT(18)
119#define TSIF_STS_CTL_INV_DATA BIT(17)
120#define TSIF_STS_CTL_INV_CLOCK BIT(16)
121#define TSIF_STS_CTL_SPARE BIT(15)
122#define TSIF_STS_CTL_EN_NULL BIT(11)
123#define TSIF_STS_CTL_EN_ERROR BIT(10)
124#define TSIF_STS_CTL_LAST_BIT BIT(9)
125#define TSIF_STS_CTL_EN_TIME_LIM BIT(8)
126#define TSIF_STS_CTL_EN_TCR BIT(7)
127#define TSIF_STS_CTL_TEST_MODE BIT(6)
Joel Nider435ad8e2011-12-14 16:53:30 +0200128#define TSIF_STS_CTL_MODE_2 BIT(5)
Joel Nider5556a852011-10-16 10:52:13 +0200129#define TSIF_STS_CTL_EN_DM BIT(4)
130#define TSIF_STS_CTL_STOP BIT(3)
131#define TSIF_STS_CTL_START BIT(0)
132
133/*
134 * TSPP register offsets
135 */
Liron Kuch72b78552012-10-30 17:47:50 +0200136#define TSPP_RST 0x00
Joel Nider5556a852011-10-16 10:52:13 +0200137#define TSPP_CLK_CONTROL 0x04
Liron Kuch72b78552012-10-30 17:47:50 +0200138#define TSPP_CONFIG 0x08
139#define TSPP_CONTROL 0x0C
Joel Nider5556a852011-10-16 10:52:13 +0200140#define TSPP_PS_DISABLE 0x10
Liron Kuch72b78552012-10-30 17:47:50 +0200141#define TSPP_MSG_IRQ_STATUS 0x14
Joel Nider5556a852011-10-16 10:52:13 +0200142#define TSPP_MSG_IRQ_MASK 0x18
143#define TSPP_IRQ_STATUS 0x1C
144#define TSPP_IRQ_MASK 0x20
145#define TSPP_IRQ_CLEAR 0x24
146#define TSPP_PIPE_ERROR_STATUS(_n) (0x28 + (_n << 2))
Liron Kuch72b78552012-10-30 17:47:50 +0200147#define TSPP_STATUS 0x68
148#define TSPP_CURR_TSP_HEADER 0x6C
149#define TSPP_CURR_PID_FILTER 0x70
150#define TSPP_SYSTEM_KEY(_n) (0x74 + (_n << 2))
151#define TSPP_CBC_INIT_VAL(_n) (0x94 + (_n << 2))
152#define TSPP_DATA_KEY_RESET 0x9C
Joel Nider5556a852011-10-16 10:52:13 +0200153#define TSPP_KEY_VALID 0xA0
154#define TSPP_KEY_ERROR 0xA4
155#define TSPP_TEST_CTRL 0xA8
Liron Kuch72b78552012-10-30 17:47:50 +0200156#define TSPP_VERSION 0xAC
Joel Nider5556a852011-10-16 10:52:13 +0200157#define TSPP_GENERICS 0xB0
Liron Kuch72b78552012-10-30 17:47:50 +0200158#define TSPP_NOP 0xB4
Joel Nider5556a852011-10-16 10:52:13 +0200159
160/*
161 * Register bit definitions
162 */
163/* TSPP_RST */
164#define TSPP_RST_RESET BIT(0)
165
166/* TSPP_CLK_CONTROL */
167#define TSPP_CLK_CONTROL_FORCE_CRYPTO BIT(9)
168#define TSPP_CLK_CONTROL_FORCE_PES_PL BIT(8)
169#define TSPP_CLK_CONTROL_FORCE_PES_AF BIT(7)
170#define TSPP_CLK_CONTROL_FORCE_RAW_CTRL BIT(6)
171#define TSPP_CLK_CONTROL_FORCE_PERF_CNT BIT(5)
172#define TSPP_CLK_CONTROL_FORCE_CTX_SEARCH BIT(4)
173#define TSPP_CLK_CONTROL_FORCE_TSP_PROC BIT(3)
174#define TSPP_CLK_CONTROL_FORCE_CONS_AHB2MEM BIT(2)
175#define TSPP_CLK_CONTROL_FORCE_TS_AHB2MEM BIT(1)
176#define TSPP_CLK_CONTROL_SET_CLKON BIT(0)
177
178/* TSPP_CONFIG */
179#define TSPP_CONFIG_SET_PACKET_LENGTH(_a, _b) (_a = (_a & 0xF0) | \
180((_b & 0xF) << 8))
181#define TSPP_CONFIG_GET_PACKET_LENGTH(_a) ((_a >> 8) & 0xF)
182#define TSPP_CONFIG_DUP_WITH_DISC_EN BIT(7)
183#define TSPP_CONFIG_PES_SYNC_ERROR_MASK BIT(6)
184#define TSPP_CONFIG_PS_LEN_ERR_MASK BIT(5)
185#define TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK BIT(4)
186#define TSPP_CONFIG_PS_CONT_ERR_MASK BIT(3)
187#define TSPP_CONFIG_PS_DUP_TSP_MASK BIT(2)
188#define TSPP_CONFIG_TSP_ERR_IND_MASK BIT(1)
189#define TSPP_CONFIG_TSP_SYNC_ERR_MASK BIT(0)
190
191/* TSPP_CONTROL */
192#define TSPP_CONTROL_PID_FILTER_LOCK BIT(5)
193#define TSPP_CONTROL_FORCE_KEY_CALC BIT(4)
194#define TSPP_CONTROL_TSP_CONS_SRC_DIS BIT(3)
195#define TSPP_CONTROL_TSP_TSIF1_SRC_DIS BIT(2)
196#define TSPP_CONTROL_TSP_TSIF0_SRC_DIS BIT(1)
197#define TSPP_CONTROL_PERF_COUNT_INIT BIT(0)
198
199/* TSPP_MSG_IRQ_STATUS + TSPP_MSG_IRQ_MASK */
200#define TSPP_MSG_TSPP_IRQ BIT(2)
201#define TSPP_MSG_TSIF_1_IRQ BIT(1)
202#define TSPP_MSG_TSIF_0_IRQ BIT(0)
203
204/* TSPP_IRQ_STATUS + TSPP_IRQ_MASK + TSPP_IRQ_CLEAR */
Liron Kuch72b78552012-10-30 17:47:50 +0200205#define TSPP_IRQ_STATUS_TSP_RD_CMPL BIT(19)
206#define TSPP_IRQ_STATUS_KEY_ERROR BIT(18)
Joel Nider5556a852011-10-16 10:52:13 +0200207#define TSPP_IRQ_STATUS_KEY_SWITCHED_BAD BIT(17)
208#define TSPP_IRQ_STATUS_KEY_SWITCHED BIT(16)
209#define TSPP_IRQ_STATUS_PS_BROKEN(_n) BIT((_n))
210
211/* TSPP_PIPE_ERROR_STATUS */
Liron Kuch72b78552012-10-30 17:47:50 +0200212#define TSPP_PIPE_PES_SYNC_ERROR BIT(3)
213#define TSPP_PIPE_PS_LENGTH_ERROR BIT(2)
Joel Nider5556a852011-10-16 10:52:13 +0200214#define TSPP_PIPE_PS_CONTINUITY_ERROR BIT(1)
Liron Kuch72b78552012-10-30 17:47:50 +0200215#define TSPP_PIP_PS_LOST_START BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200216
217/* TSPP_STATUS */
Liron Kuch72b78552012-10-30 17:47:50 +0200218#define TSPP_STATUS_TSP_PKT_AVAIL BIT(10)
219#define TSPP_STATUS_TSIF1_DM_REQ BIT(6)
220#define TSPP_STATUS_TSIF0_DM_REQ BIT(2)
221#define TSPP_CURR_FILTER_TABLE BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200222
223/* TSPP_GENERICS */
Liron Kuch72b78552012-10-30 17:47:50 +0200224#define TSPP_GENERICS_CRYPTO_GEN BIT(12)
Joel Nider5556a852011-10-16 10:52:13 +0200225#define TSPP_GENERICS_MAX_CONS_PIPES BIT(7)
Liron Kuch72b78552012-10-30 17:47:50 +0200226#define TSPP_GENERICS_MAX_PIPES BIT(2)
227#define TSPP_GENERICS_TSIF_1_GEN BIT(1)
228#define TSPP_GENERICS_TSIF_0_GEN BIT(0)
Joel Nider5556a852011-10-16 10:52:13 +0200229
230/*
231 * TSPP memory regions
232 */
233#define TSPP_PID_FILTER_TABLE0 0x800
234#define TSPP_PID_FILTER_TABLE1 0x880
235#define TSPP_PID_FILTER_TABLE2 0x900
236#define TSPP_GLOBAL_PERFORMANCE 0x980 /* see tspp_global_performance */
237#define TSPP_PIPE_CONTEXT 0x990 /* see tspp_pipe_context */
238#define TSPP_PIPE_PERFORMANCE 0x998 /* see tspp_pipe_performance */
239#define TSPP_TSP_BUFF_WORD(_n) (0xC10 + (_n << 2))
240#define TSPP_DATA_KEY 0xCD0
241
Joel Nider5556a852011-10-16 10:52:13 +0200242struct debugfs_entry {
243 const char *name;
244 mode_t mode;
245 int offset;
246};
247
248static const struct debugfs_entry debugfs_tsif_regs[] = {
249 {"sts_ctl", S_IRUGO | S_IWUSR, TSIF_STS_CTL_OFF},
250 {"time_limit", S_IRUGO | S_IWUSR, TSIF_TIME_LIMIT_OFF},
251 {"clk_ref", S_IRUGO | S_IWUSR, TSIF_CLK_REF_OFF},
252 {"lpbk_flags", S_IRUGO | S_IWUSR, TSIF_LPBK_FLAGS_OFF},
253 {"lpbk_data", S_IRUGO | S_IWUSR, TSIF_LPBK_DATA_OFF},
254 {"test_ctl", S_IRUGO | S_IWUSR, TSIF_TEST_CTL_OFF},
255 {"test_mode", S_IRUGO | S_IWUSR, TSIF_TEST_MODE_OFF},
256 {"test_reset", S_IWUSR, TSIF_TEST_RESET_OFF},
257 {"test_export", S_IRUGO | S_IWUSR, TSIF_TEST_EXPORT_OFF},
258 {"test_current", S_IRUGO, TSIF_TEST_CURRENT_OFF},
259 {"data_port", S_IRUSR, TSIF_DATA_PORT_OFF},
260};
261
262static const struct debugfs_entry debugfs_tspp_regs[] = {
263 {"rst", S_IRUGO | S_IWUSR, TSPP_RST},
264 {"clk_control", S_IRUGO | S_IWUSR, TSPP_CLK_CONTROL},
265 {"config", S_IRUGO | S_IWUSR, TSPP_CONFIG},
266 {"control", S_IRUGO | S_IWUSR, TSPP_CONTROL},
267 {"ps_disable", S_IRUGO | S_IWUSR, TSPP_PS_DISABLE},
268 {"msg_irq_status", S_IRUGO | S_IWUSR, TSPP_MSG_IRQ_STATUS},
269 {"msg_irq_mask", S_IRUGO | S_IWUSR, TSPP_MSG_IRQ_MASK},
270 {"irq_status", S_IRUGO | S_IWUSR, TSPP_IRQ_STATUS},
271 {"irq_mask", S_IRUGO | S_IWUSR, TSPP_IRQ_MASK},
272 {"irq_clear", S_IRUGO | S_IWUSR, TSPP_IRQ_CLEAR},
273 /* {"pipe_error_status",S_IRUGO | S_IWUSR, TSPP_PIPE_ERROR_STATUS}, */
274 {"status", S_IRUGO | S_IWUSR, TSPP_STATUS},
275 {"curr_tsp_header", S_IRUGO | S_IWUSR, TSPP_CURR_TSP_HEADER},
276 {"curr_pid_filter", S_IRUGO | S_IWUSR, TSPP_CURR_PID_FILTER},
277 /* {"system_key", S_IRUGO | S_IWUSR, TSPP_SYSTEM_KEY}, */
278 /* {"cbc_init_val", S_IRUGO | S_IWUSR, TSPP_CBC_INIT_VAL}, */
279 {"data_key_reset", S_IRUGO | S_IWUSR, TSPP_DATA_KEY_RESET},
280 {"key_valid", S_IRUGO | S_IWUSR, TSPP_KEY_VALID},
281 {"key_error", S_IRUGO | S_IWUSR, TSPP_KEY_ERROR},
282 {"test_ctrl", S_IRUGO | S_IWUSR, TSPP_TEST_CTRL},
283 {"version", S_IRUGO | S_IWUSR, TSPP_VERSION},
284 {"generics", S_IRUGO | S_IWUSR, TSPP_GENERICS},
285 {"pid_filter_table0", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE0},
286 {"pid_filter_table1", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE1},
287 {"pid_filter_table2", S_IRUGO | S_IWUSR, TSPP_PID_FILTER_TABLE2},
288 {"global_performance", S_IRUGO | S_IWUSR, TSPP_GLOBAL_PERFORMANCE},
289 {"pipe_context", S_IRUGO | S_IWUSR, TSPP_PIPE_CONTEXT},
290 {"pipe_performance", S_IRUGO | S_IWUSR, TSPP_PIPE_PERFORMANCE},
291 {"data_key", S_IRUGO | S_IWUSR, TSPP_DATA_KEY}
292};
293
Joel Nider5556a852011-10-16 10:52:13 +0200294struct tspp_pid_filter {
295 u32 filter; /* see FILTER_ macros */
296 u32 config; /* see FILTER_ macros */
297};
298
299/* tsp_info */
300#define FILTER_HEADER_ERROR_MASK BIT(7)
301#define FILTER_TRANS_END_DISABLE BIT(6)
302#define FILTER_DEC_ON_ERROR_EN BIT(5)
303#define FILTER_DECRYPT BIT(4)
304#define FILTER_HAS_ENCRYPTION(_p) (_p->config & FILTER_DECRYPT)
305#define FILTER_GET_PIPE_NUMBER0(_p) (_p->config & 0xF)
306#define FILTER_SET_PIPE_NUMBER0(_p, _b) (_p->config = \
307 (_p->config & ~0xF) | (_b & 0xF))
308#define FILTER_GET_PIPE_PROCESS0(_p) ((_p->filter >> 30) & 0x3)
309#define FILTER_SET_PIPE_PROCESS0(_p, _b) (_p->filter = \
310 (_p->filter & ~(0x3<<30)) | ((_b & 0x3) << 30))
311#define FILTER_GET_PIPE_PID(_p) ((_p->filter >> 13) & 0x1FFF)
312#define FILTER_SET_PIPE_PID(_p, _b) (_p->filter = \
313 (_p->filter & ~(0x1FFF<<13)) | ((_b & 0x1FFF) << 13))
314#define FILTER_GET_PID_MASK(_p) (_p->filter & 0x1FFF)
315#define FILTER_SET_PID_MASK(_p, _b) (_p->filter = \
316 (_p->filter & ~0x1FFF) | (_b & 0x1FFF))
317#define FILTER_GET_PIPE_PROCESS1(_p) ((_p->config >> 30) & 0x3)
318#define FILTER_SET_PIPE_PROCESS1(_p, _b) (_p->config = \
319 (_p->config & ~(0x3<<30)) | ((_b & 0x3) << 30))
320#define FILTER_GET_KEY_NUMBER(_p) ((_p->config >> 8) & 0x7)
321#define FILTER_SET_KEY_NUMBER(_p, _b) (_p->config = \
322 (_p->config & ~(0x7<<8)) | ((_b & 0x7) << 8))
323
324struct tspp_global_performance_regs {
325 u32 tsp_total;
326 u32 tsp_ignored;
327 u32 tsp_error;
328 u32 tsp_sync;
329};
330
331struct tspp_pipe_context_regs {
332 u16 pes_bytes_left;
333 u16 count;
334 u32 tsif_suffix;
335} __packed;
336#define CONTEXT_GET_STATE(_a) (_a & 0x3)
337#define CONTEXT_UNSPEC_LENGTH BIT(11)
338#define CONTEXT_GET_CONT_COUNT(_a) ((_a >> 12) & 0xF)
339
Hamad Kadmany81cee052012-11-29 14:15:57 +0200340#define MSEC_TO_JIFFIES(msec) ((msec) * HZ / 1000)
341
Joel Nider5556a852011-10-16 10:52:13 +0200342struct tspp_pipe_performance_regs {
343 u32 tsp_total;
344 u32 ps_duplicate_tsp;
345 u32 tsp_no_payload;
346 u32 tsp_broken_ps;
347 u32 ps_total_num;
348 u32 ps_continuity_error;
349 u32 ps_length_error;
350 u32 pes_sync_error;
351};
352
353struct tspp_tsif_device {
354 void __iomem *base;
355 u32 time_limit;
356 u32 ref_count;
Joel Nider435ad8e2011-12-14 16:53:30 +0200357 enum tspp_tsif_mode mode;
Hamad Kadmany92705b32012-10-23 14:15:41 +0200358 int clock_inverse;
359 int data_inverse;
360 int sync_inverse;
361 int enable_inverse;
Hamad Kadmany44307d32012-11-25 09:49:51 +0200362 u32 tsif_irq;
Joel Nider5556a852011-10-16 10:52:13 +0200363
364 /* debugfs */
Joel Nider5556a852011-10-16 10:52:13 +0200365 struct dentry *dent_tsif;
366 struct dentry *debugfs_tsif_regs[ARRAY_SIZE(debugfs_tsif_regs)];
Hamad Kadmany44307d32012-11-25 09:49:51 +0200367 u32 stat_rx;
368 u32 stat_overflow;
369 u32 stat_lost_sync;
370 u32 stat_timeout;
Joel Nider5556a852011-10-16 10:52:13 +0200371};
372
373enum tspp_buf_state {
374 TSPP_BUF_STATE_EMPTY, /* buffer has been allocated, but not waiting */
375 TSPP_BUF_STATE_WAITING, /* buffer is waiting to be filled */
Joel Nider435ad8e2011-12-14 16:53:30 +0200376 TSPP_BUF_STATE_DATA, /* buffer is not empty and can be read */
377 TSPP_BUF_STATE_LOCKED /* buffer is being read by a client */
Joel Nider5556a852011-10-16 10:52:13 +0200378};
379
380struct tspp_mem_buffer {
Joel Nider435ad8e2011-12-14 16:53:30 +0200381 struct tspp_mem_buffer *next;
382 struct sps_mem_buffer sps;
383 struct tspp_data_descriptor desc; /* buffer descriptor for kernel api */
Joel Nider5556a852011-10-16 10:52:13 +0200384 enum tspp_buf_state state;
385 size_t filled; /* how much data this buffer is holding */
386 int read_index; /* where to start reading data from */
387};
388
389/* this represents each char device 'channel' */
390struct tspp_channel {
391 struct cdev cdev;
392 struct device *dd;
Joel Nider435ad8e2011-12-14 16:53:30 +0200393 struct tspp_device *pdev; /* can use container_of instead? */
Joel Nider5556a852011-10-16 10:52:13 +0200394 struct sps_pipe *pipe;
395 struct sps_connect config;
396 struct sps_register_event event;
Joel Nider435ad8e2011-12-14 16:53:30 +0200397 struct tspp_mem_buffer *data; /* list of buffers */
398 struct tspp_mem_buffer *read; /* first buffer ready to be read */
399 struct tspp_mem_buffer *waiting; /* first outstanding transfer */
400 struct tspp_mem_buffer *locked; /* buffer currently being read */
Joel Nider5556a852011-10-16 10:52:13 +0200401 wait_queue_head_t in_queue; /* set when data is received */
Joel Nider435ad8e2011-12-14 16:53:30 +0200402 u32 id; /* channel id (0-15) */
403 int used; /* is this channel in use? */
404 int key; /* which encryption key index is used */
405 u32 buffer_size; /* size of the sps transfer buffers */
406 u32 max_buffers; /* how many buffers should be allocated */
407 u32 buffer_count; /* how many buffers are actually allocated */
408 u32 filter_count; /* how many filters have been added to this channel */
409 u32 int_freq; /* generate interrupts every x descriptors */
Joel Nider5556a852011-10-16 10:52:13 +0200410 enum tspp_source src;
411 enum tspp_mode mode;
Joel Nider435ad8e2011-12-14 16:53:30 +0200412 tspp_notifier *notifier; /* used only with kernel api */
413 void *notify_data; /* data to be passed with the notifier */
Hamad Kadmany81cee052012-11-29 14:15:57 +0200414 u32 expiration_period_ms; /* notification on partially filled buffers */
415 struct timer_list expiration_timer;
Hamad Kadmany090709b2013-01-06 12:08:13 +0200416 struct dma_pool *dma_pool;
Liron Kuch72b78552012-10-30 17:47:50 +0200417 tspp_memfree *memfree; /* user defined memory free function */
418 void *user_info; /* user cookie passed to memory alloc/free function */
Joel Nider5556a852011-10-16 10:52:13 +0200419};
420
421struct tspp_pid_filter_table {
422 struct tspp_pid_filter filter[TSPP_NUM_PRIORITIES];
423};
424
425struct tspp_key_entry {
426 u32 even_lsb;
427 u32 even_msb;
428 u32 odd_lsb;
429 u32 odd_msb;
430};
431
432struct tspp_key_table {
433 struct tspp_key_entry entry[TSPP_NUM_KEYS];
434};
435
Joel Nider435ad8e2011-12-14 16:53:30 +0200436/* this represents the actual hardware device */
437struct tspp_device {
438 struct list_head devlist; /* list of all devices */
439 struct platform_device *pdev;
440 void __iomem *base;
Hamad Kadmanyef5ce992013-06-03 09:30:50 +0300441 uint32_t tsif_bus_client;
Joel Nider435ad8e2011-12-14 16:53:30 +0200442 unsigned int tspp_irq;
443 unsigned int bam_irq;
444 u32 bam_handle;
445 struct sps_bam_props bam_props;
446 struct wake_lock wake_lock;
447 spinlock_t spinlock;
448 struct tasklet_struct tlet;
449 struct tspp_tsif_device tsif[TSPP_TSIF_INSTANCES];
450 /* clocks */
451 struct clk *tsif_pclk;
452 struct clk *tsif_ref_clk;
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -0700453 /* regulators */
454 struct regulator *tsif_vreg;
Joel Nider435ad8e2011-12-14 16:53:30 +0200455 /* data */
456 struct tspp_pid_filter_table *filters[TSPP_FILTER_TABLES];
457 struct tspp_channel channels[TSPP_NUM_CHANNELS];
458 struct tspp_key_table *tspp_key_table;
459 struct tspp_global_performance_regs *tspp_global_performance;
460 struct tspp_pipe_context_regs *tspp_pipe_context;
461 struct tspp_pipe_performance_regs *tspp_pipe_performance;
462
463 struct dentry *dent;
464 struct dentry *debugfs_regs[ARRAY_SIZE(debugfs_tspp_regs)];
465};
466
467
Joel Nider5556a852011-10-16 10:52:13 +0200468static struct class *tspp_class;
469static int tspp_key_entry;
470static dev_t tspp_minor; /* next minor number to assign */
Joel Nider435ad8e2011-12-14 16:53:30 +0200471
472static LIST_HEAD(tspp_devices);
473
474/* forward declarations */
475static ssize_t tspp_read(struct file *, char __user *, size_t, loff_t *);
476static ssize_t tspp_open(struct inode *inode, struct file *filp);
477static unsigned int tspp_poll(struct file *filp, struct poll_table_struct *p);
478static ssize_t tspp_release(struct inode *inode, struct file *filp);
479static long tspp_ioctl(struct file *, unsigned int, unsigned long);
480
481/* file operations */
482static const struct file_operations tspp_fops = {
483 .owner = THIS_MODULE,
484 .read = tspp_read,
485 .open = tspp_open,
486 .poll = tspp_poll,
487 .release = tspp_release,
488 .unlocked_ioctl = tspp_ioctl,
489};
Joel Nider5556a852011-10-16 10:52:13 +0200490
491/*** IRQ ***/
Joel Nider435ad8e2011-12-14 16:53:30 +0200492static irqreturn_t tspp_isr(int irq, void *dev)
Joel Nider5556a852011-10-16 10:52:13 +0200493{
Joel Nider435ad8e2011-12-14 16:53:30 +0200494 struct tspp_device *device = dev;
Joel Nider5556a852011-10-16 10:52:13 +0200495 u32 status, mask;
496 u32 data;
497
498 status = readl_relaxed(device->base + TSPP_IRQ_STATUS);
499 mask = readl_relaxed(device->base + TSPP_IRQ_MASK);
500 status &= mask;
501
502 if (!status) {
503 dev_warn(&device->pdev->dev, "Spurious interrupt");
504 return IRQ_NONE;
505 }
506
507 /* if (status & TSPP_IRQ_STATUS_TSP_RD_CMPL) */
508
509 if (status & TSPP_IRQ_STATUS_KEY_ERROR) {
510 /* read the key error info */
511 data = readl_relaxed(device->base + TSPP_KEY_ERROR);
512 dev_info(&device->pdev->dev, "key error 0x%x", data);
513 }
514 if (status & TSPP_IRQ_STATUS_KEY_SWITCHED_BAD) {
515 data = readl_relaxed(device->base + TSPP_KEY_VALID);
516 dev_info(&device->pdev->dev, "key invalidated: 0x%x", data);
517 }
518 if (status & TSPP_IRQ_STATUS_KEY_SWITCHED)
519 dev_info(&device->pdev->dev, "key switched");
520
521 if (status & 0xffff)
Joel Nider435ad8e2011-12-14 16:53:30 +0200522 dev_info(&device->pdev->dev, "broken pipe %i", status & 0xffff);
Joel Nider5556a852011-10-16 10:52:13 +0200523
524 writel_relaxed(status, device->base + TSPP_IRQ_CLEAR);
Hamad Kadmany44307d32012-11-25 09:49:51 +0200525
526 /*
527 * Before returning IRQ_HANDLED to the generic interrupt handling
528 * framework need to make sure all operations including clearing of
529 * interrupt status registers in the hardware is performed.
530 * Thus a barrier after clearing the interrupt status register
531 * is required to guarantee that the interrupt status register has
532 * really been cleared by the time we return from this handler.
533 */
534 wmb();
535 return IRQ_HANDLED;
536}
537
538static irqreturn_t tsif_isr(int irq, void *dev)
539{
540 struct tspp_tsif_device *tsif_device = dev;
541 u32 sts_ctl = ioread32(tsif_device->base + TSIF_STS_CTL_OFF);
542
543 if (!(sts_ctl & (TSIF_STS_CTL_PACK_AVAIL |
544 TSIF_STS_CTL_OVERFLOW |
545 TSIF_STS_CTL_LOST_SYNC |
546 TSIF_STS_CTL_TIMEOUT)))
547 return IRQ_NONE;
548
549 if (sts_ctl & TSIF_STS_CTL_OVERFLOW)
550 tsif_device->stat_overflow++;
551
552 if (sts_ctl & TSIF_STS_CTL_LOST_SYNC)
553 tsif_device->stat_lost_sync++;
554
555 if (sts_ctl & TSIF_STS_CTL_TIMEOUT)
556 tsif_device->stat_timeout++;
557
558 iowrite32(sts_ctl, tsif_device->base + TSIF_STS_CTL_OFF);
559
560 /*
561 * Before returning IRQ_HANDLED to the generic interrupt handling
562 * framework need to make sure all operations including clearing of
563 * interrupt status registers in the hardware is performed.
564 * Thus a barrier after clearing the interrupt status register
565 * is required to guarantee that the interrupt status register has
566 * really been cleared by the time we return from this handler.
567 */
Joel Nider5556a852011-10-16 10:52:13 +0200568 wmb();
569 return IRQ_HANDLED;
570}
571
572/*** callbacks ***/
573static void tspp_sps_complete_cb(struct sps_event_notify *notify)
574{
Joel Nider435ad8e2011-12-14 16:53:30 +0200575 struct tspp_device *pdev = notify->user;
576 tasklet_schedule(&pdev->tlet);
Joel Nider5556a852011-10-16 10:52:13 +0200577}
578
Hamad Kadmany81cee052012-11-29 14:15:57 +0200579static void tspp_expiration_timer(unsigned long data)
580{
581 struct tspp_device *pdev = (struct tspp_device *)data;
582
583 if (pdev)
584 tasklet_schedule(&pdev->tlet);
585}
586
Joel Nider5556a852011-10-16 10:52:13 +0200587/*** tasklet ***/
588static void tspp_sps_complete_tlet(unsigned long data)
589{
590 int i;
591 int complete;
592 unsigned long flags;
593 struct sps_iovec iovec;
594 struct tspp_channel *channel;
595 struct tspp_device *device = (struct tspp_device *)data;
Joel Nider5556a852011-10-16 10:52:13 +0200596 spin_lock_irqsave(&device->spinlock, flags);
597
598 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
599 complete = 0;
Joel Nider435ad8e2011-12-14 16:53:30 +0200600 channel = &device->channels[i];
Hamad Kadmany81cee052012-11-29 14:15:57 +0200601
Joel Nider435ad8e2011-12-14 16:53:30 +0200602 if (!channel->used || !channel->waiting)
603 continue;
Joel Nider5556a852011-10-16 10:52:13 +0200604
Hamad Kadmany81cee052012-11-29 14:15:57 +0200605 /* stop the expiration timer */
606 if (channel->expiration_period_ms)
607 del_timer(&channel->expiration_timer);
608
Joel Nider5556a852011-10-16 10:52:13 +0200609 /* get completions */
Joel Nider435ad8e2011-12-14 16:53:30 +0200610 while (channel->waiting->state == TSPP_BUF_STATE_WAITING) {
Joel Nider5556a852011-10-16 10:52:13 +0200611 if (sps_get_iovec(channel->pipe, &iovec) != 0) {
612 pr_err("tspp: Error in iovec on channel %i",
613 channel->id);
614 break;
615 }
616 if (iovec.size == 0)
617 break;
618
Joel Nider435ad8e2011-12-14 16:53:30 +0200619 if (iovec.addr != channel->waiting->sps.phys_base)
Hamad Kadmanya23457e2013-07-02 16:51:20 +0300620 pr_err("tspp: buffer mismatch %pa",
621 &channel->waiting->sps.phys_base);
Joel Nider5556a852011-10-16 10:52:13 +0200622
623 complete = 1;
Joel Nider435ad8e2011-12-14 16:53:30 +0200624 channel->waiting->state = TSPP_BUF_STATE_DATA;
625 channel->waiting->filled = iovec.size;
626 channel->waiting->read_index = 0;
627
Hamad Kadmany44307d32012-11-25 09:49:51 +0200628 if (channel->src == TSPP_SOURCE_TSIF0)
629 device->tsif[0].stat_rx++;
630 else if (channel->src == TSPP_SOURCE_TSIF1)
631 device->tsif[1].stat_rx++;
632
Joel Nider435ad8e2011-12-14 16:53:30 +0200633 /* update the pointers */
634 channel->waiting = channel->waiting->next;
Joel Nider5556a852011-10-16 10:52:13 +0200635 }
636
Joel Nider435ad8e2011-12-14 16:53:30 +0200637 /* wake any waiting processes */
Joel Nider5556a852011-10-16 10:52:13 +0200638 if (complete) {
Joel Nider5556a852011-10-16 10:52:13 +0200639 wake_up_interruptible(&channel->in_queue);
Joel Nider435ad8e2011-12-14 16:53:30 +0200640
641 /* call notifiers */
642 if (channel->notifier)
643 channel->notifier(channel->id,
644 channel->notify_data);
Joel Nider5556a852011-10-16 10:52:13 +0200645 }
Hamad Kadmany81cee052012-11-29 14:15:57 +0200646
647 /* restart expiration timer */
648 if (channel->expiration_period_ms)
649 mod_timer(&channel->expiration_timer,
650 jiffies +
651 MSEC_TO_JIFFIES(
652 channel->expiration_period_ms));
Joel Nider5556a852011-10-16 10:52:13 +0200653 }
654
655 spin_unlock_irqrestore(&device->spinlock, flags);
656}
657
658/*** GPIO functions ***/
Liron Kuch275c0b32013-02-10 15:19:32 +0200659static int tspp_gpios_disable(const struct tspp_tsif_device *tsif_device,
660 const struct msm_gpio *table,
661 int size)
Joel Nider5556a852011-10-16 10:52:13 +0200662{
663 int rc = 0;
664 int i;
665 const struct msm_gpio *g;
Liron Kuch59339922013-01-01 18:29:47 +0200666
Joel Nider5556a852011-10-16 10:52:13 +0200667 for (i = size-1; i >= 0; i--) {
668 int tmp;
669 g = table + i;
Liron Kuch59339922013-01-01 18:29:47 +0200670
Liron Kuch275c0b32013-02-10 15:19:32 +0200671 /* don't use sync GPIO when not working in mode 2 */
672 if ((tsif_device->mode != TSPP_TSIF_MODE_2) &&
673 (strnstr(g->label, "sync", strlen(g->label)) != NULL))
674 continue;
675
Liron Kuch59339922013-01-01 18:29:47 +0200676 tmp = gpio_tlmm_config(GPIO_CFG(GPIO_PIN(g->gpio_cfg),
677 0, GPIO_CFG_INPUT, GPIO_CFG_PULL_DOWN, GPIO_CFG_2MA),
678 GPIO_CFG_DISABLE);
Joel Nider5556a852011-10-16 10:52:13 +0200679 if (tmp) {
Liron Kuch72b78552012-10-30 17:47:50 +0200680 pr_err("tspp_gpios_disable(0x%08x, GPIO_CFG_DISABLE) <%s> failed: %d\n",
Joel Nider5556a852011-10-16 10:52:13 +0200681 g->gpio_cfg, g->label ?: "?", rc);
682 pr_err("tspp: pin %d func %d dir %d pull %d drvstr %d\n",
683 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
684 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
685 GPIO_DRVSTR(g->gpio_cfg));
686 if (!rc)
687 rc = tmp;
688 }
689 }
690
691 return rc;
692}
693
Liron Kuch275c0b32013-02-10 15:19:32 +0200694static int tspp_gpios_enable(const struct tspp_tsif_device *tsif_device,
695 const struct msm_gpio *table,
696 int size)
Joel Nider5556a852011-10-16 10:52:13 +0200697{
698 int rc;
Liron Kuch275c0b32013-02-10 15:19:32 +0200699 int i;
Joel Nider5556a852011-10-16 10:52:13 +0200700 const struct msm_gpio *g;
Liron Kuch59339922013-01-01 18:29:47 +0200701
Joel Nider5556a852011-10-16 10:52:13 +0200702 for (i = 0; i < size; i++) {
703 g = table + i;
Liron Kuch275c0b32013-02-10 15:19:32 +0200704
705 /* don't use sync GPIO when not working in mode 2 */
706 if ((tsif_device->mode != TSPP_TSIF_MODE_2) &&
707 (strnstr(g->label, "sync", strlen(g->label)) != NULL))
708 continue;
709
Joel Nider5556a852011-10-16 10:52:13 +0200710 rc = gpio_tlmm_config(g->gpio_cfg, GPIO_CFG_ENABLE);
711 if (rc) {
Liron Kuch72b78552012-10-30 17:47:50 +0200712 pr_err("tspp: gpio_tlmm_config(0x%08x, GPIO_CFG_ENABLE) <%s> failed: %d\n",
Joel Nider5556a852011-10-16 10:52:13 +0200713 g->gpio_cfg, g->label ?: "?", rc);
714 pr_err("tspp: pin %d func %d dir %d pull %d drvstr %d\n",
715 GPIO_PIN(g->gpio_cfg), GPIO_FUNC(g->gpio_cfg),
716 GPIO_DIR(g->gpio_cfg), GPIO_PULL(g->gpio_cfg),
717 GPIO_DRVSTR(g->gpio_cfg));
718 goto err;
719 }
720 }
721 return 0;
722err:
Liron Kuch275c0b32013-02-10 15:19:32 +0200723 tspp_gpios_disable(tsif_device, table, i);
Joel Nider5556a852011-10-16 10:52:13 +0200724
Joel Nider5556a852011-10-16 10:52:13 +0200725 return rc;
726}
727
Liron Kuch275c0b32013-02-10 15:19:32 +0200728
729static int tspp_config_gpios(struct tspp_device *device,
730 enum tspp_source source,
731 int enable)
Joel Nider5556a852011-10-16 10:52:13 +0200732{
Liron Kuch275c0b32013-02-10 15:19:32 +0200733 const struct msm_gpio *table;
734 struct msm_tspp_platform_data *pdata = device->pdev->dev.platform_data;
735 int num_gpios = (pdata->num_gpios / TSPP_TSIF_INSTANCES);
736 int i = 0;
Liron Kuch59339922013-01-01 18:29:47 +0200737
Liron Kuch275c0b32013-02-10 15:19:32 +0200738 if (num_gpios != TSPP_GPIOS_PER_TSIF) {
739 pr_err("tspp %s: unexpected number of GPIOs %d, expected %d\n",
740 __func__, num_gpios, TSPP_GPIOS_PER_TSIF);
741 return -EINVAL;
742 }
Joel Nider5556a852011-10-16 10:52:13 +0200743
Liron Kuch275c0b32013-02-10 15:19:32 +0200744 /*
745 * Note: this code assumes that the GPIO definitions in the
746 * pdata->gpios table are according to the TSIF instance number,
747 * i.e., that TSIF0 GPIOs are defined first, then TSIF1 GPIOs etc.
748 */
749 switch (source) {
750 case TSPP_SOURCE_TSIF0:
751 i = 0;
752 break;
753 case TSPP_SOURCE_TSIF1:
754 i = 1;
755 break;
756 default:
757 pr_err("tspp %s: invalid source\n", __func__);
758 return -EINVAL;
759 }
Liron Kuch59339922013-01-01 18:29:47 +0200760
Liron Kuch275c0b32013-02-10 15:19:32 +0200761 table = pdata->gpios + (i * num_gpios);
762 if (enable)
763 return tspp_gpios_enable(&device->tsif[i], table, num_gpios);
764 else
765 return tspp_gpios_disable(&device->tsif[i], table, num_gpios);
Joel Nider5556a852011-10-16 10:52:13 +0200766}
767
Joel Nider435ad8e2011-12-14 16:53:30 +0200768/*** Clock functions ***/
769static int tspp_clock_start(struct tspp_device *device)
770{
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -0700771 int rc;
772
Liron Kuch605cc122013-02-21 14:25:57 +0200773 if (device == NULL) {
774 pr_err("tspp: Can't start clocks, invalid device\n");
775 return -EINVAL;
776 }
777
Hamad Kadmanyef5ce992013-06-03 09:30:50 +0300778 if (device->tsif_bus_client) {
779 rc = msm_bus_scale_client_update_request(
780 device->tsif_bus_client, 1);
781 if (rc) {
782 pr_err("tspp: Can't enable bus\n");
783 return -EBUSY;
784 }
785 }
786
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -0700787 if (device->tsif_vreg) {
788 rc = regulator_set_voltage(device->tsif_vreg,
789 RPM_REGULATOR_CORNER_SUPER_TURBO,
790 RPM_REGULATOR_CORNER_SUPER_TURBO);
791 if (rc) {
792 pr_err("Unable to set CX voltage.\n");
Hamad Kadmanyef5ce992013-06-03 09:30:50 +0300793 if (device->tsif_bus_client)
794 msm_bus_scale_client_update_request(
795 device->tsif_bus_client, 0);
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -0700796 return rc;
797 }
798 }
799
Joel Nider435ad8e2011-12-14 16:53:30 +0200800 if (device->tsif_pclk && clk_prepare_enable(device->tsif_pclk) != 0) {
801 pr_err("tspp: Can't start pclk");
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -0700802
803 if (device->tsif_vreg) {
804 regulator_set_voltage(device->tsif_vreg,
Hamad Kadmanyfde29382013-06-26 08:03:51 +0300805 RPM_REGULATOR_CORNER_NONE,
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -0700806 RPM_REGULATOR_CORNER_SUPER_TURBO);
807 }
Hamad Kadmanyef5ce992013-06-03 09:30:50 +0300808
809 if (device->tsif_bus_client)
810 msm_bus_scale_client_update_request(
811 device->tsif_bus_client, 0);
Joel Nider435ad8e2011-12-14 16:53:30 +0200812 return -EBUSY;
813 }
814
815 if (device->tsif_ref_clk &&
816 clk_prepare_enable(device->tsif_ref_clk) != 0) {
817 pr_err("tspp: Can't start ref clk");
818 clk_disable_unprepare(device->tsif_pclk);
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -0700819 if (device->tsif_vreg) {
820 regulator_set_voltage(device->tsif_vreg,
Hamad Kadmanyfde29382013-06-26 08:03:51 +0300821 RPM_REGULATOR_CORNER_NONE,
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -0700822 RPM_REGULATOR_CORNER_SUPER_TURBO);
823 }
Hamad Kadmanyef5ce992013-06-03 09:30:50 +0300824
825 if (device->tsif_bus_client)
826 msm_bus_scale_client_update_request(
827 device->tsif_bus_client, 0);
Joel Nider435ad8e2011-12-14 16:53:30 +0200828 return -EBUSY;
829 }
830
831 return 0;
832}
833
834static void tspp_clock_stop(struct tspp_device *device)
835{
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -0700836 int rc;
837
Liron Kuch605cc122013-02-21 14:25:57 +0200838 if (device == NULL) {
839 pr_err("tspp: Can't stop clocks, invalid device\n");
840 return;
841 }
842
Joel Nider435ad8e2011-12-14 16:53:30 +0200843 if (device->tsif_pclk)
Liron Kuch605cc122013-02-21 14:25:57 +0200844 clk_disable_unprepare(device->tsif_pclk);
Joel Nider435ad8e2011-12-14 16:53:30 +0200845
846 if (device->tsif_ref_clk)
Liron Kuch605cc122013-02-21 14:25:57 +0200847 clk_disable_unprepare(device->tsif_ref_clk);
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -0700848
849 if (device->tsif_vreg) {
850 rc = regulator_set_voltage(device->tsif_vreg,
Hamad Kadmanyfde29382013-06-26 08:03:51 +0300851 RPM_REGULATOR_CORNER_NONE,
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -0700852 RPM_REGULATOR_CORNER_SUPER_TURBO);
853 if (rc)
854 pr_err("Unable to set CX voltage.\n");
855 }
Hamad Kadmanyef5ce992013-06-03 09:30:50 +0300856
857 if (device->tsif_bus_client) {
858 rc = msm_bus_scale_client_update_request(
859 device->tsif_bus_client, 0);
860 if (rc)
861 pr_err("tspp: Can't disable bus\n");
862 }
Joel Nider435ad8e2011-12-14 16:53:30 +0200863}
864
Joel Nider5556a852011-10-16 10:52:13 +0200865/*** TSIF functions ***/
866static int tspp_start_tsif(struct tspp_tsif_device *tsif_device)
867{
868 int start_hardware = 0;
869 u32 ctl;
870
871 if (tsif_device->ref_count == 0) {
872 start_hardware = 1;
873 } else if (tsif_device->ref_count > 0) {
874 ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
875 if ((ctl & TSIF_STS_CTL_START) != 1) {
876 /* this hardware should already be running */
877 pr_warn("tspp: tsif hw not started but ref count > 0");
878 start_hardware = 1;
879 }
880 }
881
882 if (start_hardware) {
Joel Nider435ad8e2011-12-14 16:53:30 +0200883 ctl = TSIF_STS_CTL_EN_IRQ |
Joel Nider5556a852011-10-16 10:52:13 +0200884 TSIF_STS_CTL_EN_DM;
Hamad Kadmany92705b32012-10-23 14:15:41 +0200885
886 if (tsif_device->clock_inverse)
887 ctl |= TSIF_STS_CTL_INV_CLOCK;
888
889 if (tsif_device->data_inverse)
890 ctl |= TSIF_STS_CTL_INV_DATA;
891
892 if (tsif_device->sync_inverse)
893 ctl |= TSIF_STS_CTL_INV_SYNC;
894
895 if (tsif_device->enable_inverse)
896 ctl |= TSIF_STS_CTL_INV_ENABLE;
897
Joel Nider435ad8e2011-12-14 16:53:30 +0200898 switch (tsif_device->mode) {
899 case TSPP_TSIF_MODE_LOOPBACK:
900 ctl |= TSIF_STS_CTL_EN_NULL |
901 TSIF_STS_CTL_EN_ERROR |
902 TSIF_STS_CTL_TEST_MODE;
903 break;
904 case TSPP_TSIF_MODE_1:
905 ctl |= TSIF_STS_CTL_EN_TIME_LIM |
906 TSIF_STS_CTL_EN_TCR;
907 break;
908 case TSPP_TSIF_MODE_2:
909 ctl |= TSIF_STS_CTL_EN_TIME_LIM |
910 TSIF_STS_CTL_EN_TCR |
911 TSIF_STS_CTL_MODE_2;
912 break;
913 default:
914 pr_warn("tspp: unknown tsif mode 0x%x",
915 tsif_device->mode);
Joel Nider5556a852011-10-16 10:52:13 +0200916 }
917 writel_relaxed(ctl, tsif_device->base + TSIF_STS_CTL_OFF);
918 writel_relaxed(tsif_device->time_limit,
919 tsif_device->base + TSIF_TIME_LIMIT_OFF);
920 wmb();
921 writel_relaxed(ctl | TSIF_STS_CTL_START,
922 tsif_device->base + TSIF_STS_CTL_OFF);
923 wmb();
Joel Nider5556a852011-10-16 10:52:13 +0200924 }
925
Joel Nider435ad8e2011-12-14 16:53:30 +0200926 ctl = readl_relaxed(tsif_device->base + TSIF_STS_CTL_OFF);
Gilad Broner6049ea32014-04-10 09:48:44 +0300927 if (!(ctl & TSIF_STS_CTL_START))
928 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +0200929
Gilad Broner6049ea32014-04-10 09:48:44 +0300930 tsif_device->ref_count++;
931 return 0;
Joel Nider5556a852011-10-16 10:52:13 +0200932}
933
934static void tspp_stop_tsif(struct tspp_tsif_device *tsif_device)
935{
936 if (tsif_device->ref_count == 0)
937 return;
938
939 tsif_device->ref_count--;
940
941 if (tsif_device->ref_count == 0) {
942 writel_relaxed(TSIF_STS_CTL_STOP,
943 tsif_device->base + TSIF_STS_CTL_OFF);
944 wmb();
945 }
946}
947
Joel Nider435ad8e2011-12-14 16:53:30 +0200948/*** local TSPP functions ***/
949static int tspp_channels_in_use(struct tspp_device *pdev)
950{
951 int i;
952 int count = 0;
953 for (i = 0; i < TSPP_NUM_CHANNELS; i++)
954 count += (pdev->channels[i].used ? 1 : 0);
955
956 return count;
957}
958
959static struct tspp_device *tspp_find_by_id(int id)
960{
961 struct tspp_device *dev;
962 list_for_each_entry(dev, &tspp_devices, devlist) {
963 if (dev->pdev->id == id)
964 return dev;
965 }
966 return NULL;
967}
968
Joel Nider5556a852011-10-16 10:52:13 +0200969static int tspp_get_key_entry(void)
970{
971 int i;
972 for (i = 0; i < TSPP_NUM_KEYS; i++) {
973 if (!(tspp_key_entry & (1 << i))) {
974 tspp_key_entry |= (1 << i);
975 return i;
976 }
977 }
Joel Nider435ad8e2011-12-14 16:53:30 +0200978 return 1 < TSPP_NUM_KEYS;
Joel Nider5556a852011-10-16 10:52:13 +0200979}
980
981static void tspp_free_key_entry(int entry)
982{
983 if (entry > TSPP_NUM_KEYS) {
984 pr_err("tspp_free_key_entry: index out of bounds");
985 return;
986 }
987
988 tspp_key_entry &= ~(1 << entry);
989}
990
Joel Nider435ad8e2011-12-14 16:53:30 +0200991static int tspp_alloc_buffer(u32 channel_id, struct tspp_data_descriptor *desc,
Hamad Kadmany090709b2013-01-06 12:08:13 +0200992 u32 size, struct dma_pool *dma_pool, tspp_allocator *alloc, void *user)
Joel Nider5556a852011-10-16 10:52:13 +0200993{
Joel Nider435ad8e2011-12-14 16:53:30 +0200994 if (size < TSPP_MIN_BUFFER_SIZE ||
995 size > TSPP_MAX_BUFFER_SIZE) {
996 pr_err("tspp: bad buffer size %i", size);
Joel Nider5556a852011-10-16 10:52:13 +0200997 return -ENOMEM;
998 }
Joel Nider435ad8e2011-12-14 16:53:30 +0200999
1000 if (alloc) {
1001 TSPP_DEBUG("tspp using alloc function");
1002 desc->virt_base = alloc(channel_id, size,
1003 &desc->phys_base, user);
1004 } else {
Hamad Kadmany090709b2013-01-06 12:08:13 +02001005 if (!dma_pool)
1006 desc->virt_base = dma_alloc_coherent(NULL, size,
1007 &desc->phys_base, GFP_KERNEL);
1008 else
1009 desc->virt_base = dma_pool_alloc(dma_pool, GFP_KERNEL,
1010 &desc->phys_base);
1011
Liron Kuch72b78552012-10-30 17:47:50 +02001012 if (desc->virt_base == 0) {
Hamad Kadmany090709b2013-01-06 12:08:13 +02001013 pr_err("tspp: dma buffer allocation failed %i\n", size);
Liron Kuch72b78552012-10-30 17:47:50 +02001014 return -ENOMEM;
1015 }
Joel Nider435ad8e2011-12-14 16:53:30 +02001016 }
1017
1018 desc->size = size;
1019 return 0;
1020}
1021
1022static int tspp_queue_buffer(struct tspp_channel *channel,
1023 struct tspp_mem_buffer *buffer)
1024{
1025 int rc;
1026 u32 flags = 0;
1027
1028 /* make sure the interrupt frequency is valid */
1029 if (channel->int_freq < 1)
1030 channel->int_freq = 1;
1031
1032 /* generate interrupt according to requested frequency */
1033 if (buffer->desc.id % channel->int_freq == channel->int_freq-1)
Hamad Kadmany81cee052012-11-29 14:15:57 +02001034 flags = SPS_IOVEC_FLAG_INT;
Joel Nider435ad8e2011-12-14 16:53:30 +02001035
1036 /* start the transfer */
1037 rc = sps_transfer_one(channel->pipe,
1038 buffer->sps.phys_base,
1039 buffer->sps.size,
1040 channel->pdev,
1041 flags);
1042 if (rc < 0)
1043 return rc;
1044
1045 buffer->state = TSPP_BUF_STATE_WAITING;
Joel Nider5556a852011-10-16 10:52:13 +02001046
1047 return 0;
1048}
1049
1050static int tspp_global_reset(struct tspp_device *pdev)
1051{
1052 u32 i, val;
1053
1054 /* stop all TSIFs */
1055 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
1056 pdev->tsif[i].ref_count = 1; /* allows stopping hw */
1057 tspp_stop_tsif(&pdev->tsif[i]); /* will reset ref_count to 0 */
1058 pdev->tsif[i].time_limit = TSPP_TSIF_DEFAULT_TIME_LIMIT;
Hamad Kadmany92705b32012-10-23 14:15:41 +02001059 pdev->tsif[i].clock_inverse = 0;
1060 pdev->tsif[i].data_inverse = 0;
1061 pdev->tsif[i].sync_inverse = 0;
1062 pdev->tsif[i].enable_inverse = 0;
Joel Nider5556a852011-10-16 10:52:13 +02001063 }
1064 writel_relaxed(TSPP_RST_RESET, pdev->base + TSPP_RST);
1065 wmb();
1066
1067 /* BAM */
1068 if (sps_device_reset(pdev->bam_handle) != 0) {
1069 pr_err("tspp: error resetting bam");
Joel Nider435ad8e2011-12-14 16:53:30 +02001070 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001071 }
1072
1073 /* TSPP tables */
1074 for (i = 0; i < TSPP_FILTER_TABLES; i++)
Joel Nider435ad8e2011-12-14 16:53:30 +02001075 memset(pdev->filters[i],
Joel Nider5556a852011-10-16 10:52:13 +02001076 0, sizeof(struct tspp_pid_filter_table));
1077
1078 /* disable all filters */
1079 val = (2 << TSPP_NUM_CHANNELS) - 1;
1080 writel_relaxed(val, pdev->base + TSPP_PS_DISABLE);
1081
1082 /* TSPP registers */
1083 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1084 writel_relaxed(val | TSPP_CLK_CONTROL_FORCE_PERF_CNT,
1085 pdev->base + TSPP_CONTROL);
1086 wmb();
Joel Nider435ad8e2011-12-14 16:53:30 +02001087 memset(pdev->tspp_global_performance, 0,
Joel Nider5556a852011-10-16 10:52:13 +02001088 sizeof(struct tspp_global_performance_regs));
Joel Nider435ad8e2011-12-14 16:53:30 +02001089 memset(pdev->tspp_pipe_context, 0,
Joel Nider5556a852011-10-16 10:52:13 +02001090 sizeof(struct tspp_pipe_context_regs));
Joel Nider435ad8e2011-12-14 16:53:30 +02001091 memset(pdev->tspp_pipe_performance, 0,
Joel Nider5556a852011-10-16 10:52:13 +02001092 sizeof(struct tspp_pipe_performance_regs));
1093 wmb();
1094 writel_relaxed(val & ~TSPP_CLK_CONTROL_FORCE_PERF_CNT,
1095 pdev->base + TSPP_CONTROL);
1096 wmb();
1097
1098 val = readl_relaxed(pdev->base + TSPP_CONFIG);
1099 val &= ~(TSPP_CONFIG_PS_LEN_ERR_MASK |
1100 TSPP_CONFIG_PS_CONT_ERR_UNSP_MASK |
1101 TSPP_CONFIG_PS_CONT_ERR_MASK);
1102 TSPP_CONFIG_SET_PACKET_LENGTH(val, TSPP_PACKET_LENGTH);
1103 writel_relaxed(val, pdev->base + TSPP_CONFIG);
Hamad Kadmany6bac7832012-12-20 18:30:40 +02001104 writel_relaxed(0x0007ffff, pdev->base + TSPP_IRQ_MASK);
Joel Nider5556a852011-10-16 10:52:13 +02001105 writel_relaxed(0x000fffff, pdev->base + TSPP_IRQ_CLEAR);
1106 writel_relaxed(0, pdev->base + TSPP_RST);
1107 wmb();
1108
1109 tspp_key_entry = 0;
1110
1111 return 0;
1112}
1113
Joel Nider435ad8e2011-12-14 16:53:30 +02001114static int tspp_select_source(u32 dev, u32 channel_id,
1115 struct tspp_select_source *src)
1116{
1117 /* make sure the requested src id is in bounds */
1118 if (src->source > TSPP_SOURCE_MEM) {
1119 pr_err("tspp source out of bounds");
1120 return -EINVAL;
1121 }
1122
1123 /* open the stream */
Hamad Kadmany92705b32012-10-23 14:15:41 +02001124 tspp_open_stream(dev, channel_id, src);
Joel Nider435ad8e2011-12-14 16:53:30 +02001125
1126 return 0;
1127}
1128
1129static int tspp_set_iv(struct tspp_channel *channel, struct tspp_iv *iv)
1130{
1131 struct tspp_device *pdev = channel->pdev;
1132
1133 writel_relaxed(iv->data[0], pdev->base + TSPP_CBC_INIT_VAL(0));
1134 writel_relaxed(iv->data[1], pdev->base + TSPP_CBC_INIT_VAL(1));
1135 return 0;
1136}
1137
1138static int tspp_set_system_keys(struct tspp_channel *channel,
1139 struct tspp_system_keys *keys)
1140{
1141 int i;
1142 struct tspp_device *pdev = channel->pdev;
1143
1144 for (i = 0; i < TSPP_NUM_SYSTEM_KEYS; i++)
1145 writel_relaxed(keys->data[i], pdev->base + TSPP_SYSTEM_KEY(i));
1146
1147 return 0;
1148}
1149
1150static int tspp_channel_init(struct tspp_channel *channel,
1151 struct tspp_device *pdev)
1152{
1153 channel->cdev.owner = THIS_MODULE;
1154 cdev_init(&channel->cdev, &tspp_fops);
1155 channel->pdev = pdev;
1156 channel->data = NULL;
1157 channel->read = NULL;
1158 channel->waiting = NULL;
1159 channel->locked = NULL;
1160 channel->id = MINOR(tspp_minor);
1161 channel->used = 0;
1162 channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
1163 channel->max_buffers = TSPP_NUM_BUFFERS;
1164 channel->buffer_count = 0;
1165 channel->filter_count = 0;
1166 channel->int_freq = 1;
Liron Kuch72b78552012-10-30 17:47:50 +02001167 channel->src = TSPP_SOURCE_NONE;
1168 channel->mode = TSPP_MODE_DISABLED;
Joel Nider435ad8e2011-12-14 16:53:30 +02001169 channel->notifier = NULL;
1170 channel->notify_data = NULL;
Hamad Kadmany81cee052012-11-29 14:15:57 +02001171 channel->expiration_period_ms = 0;
Liron Kuch72b78552012-10-30 17:47:50 +02001172 channel->memfree = NULL;
1173 channel->user_info = NULL;
Joel Nider435ad8e2011-12-14 16:53:30 +02001174 init_waitqueue_head(&channel->in_queue);
1175
1176 if (cdev_add(&channel->cdev, tspp_minor++, 1) != 0) {
1177 pr_err("tspp: cdev_add failed");
1178 return -EBUSY;
1179 }
1180
1181 channel->dd = device_create(tspp_class, NULL, channel->cdev.dev,
1182 channel, "tspp%02d", channel->id);
1183 if (IS_ERR(channel->dd)) {
1184 pr_err("tspp: device_create failed: %i",
1185 (int)PTR_ERR(channel->dd));
1186 cdev_del(&channel->cdev);
1187 return -EBUSY;
1188 }
1189
1190 return 0;
1191}
1192
1193static int tspp_set_buffer_size(struct tspp_channel *channel,
1194 struct tspp_buffer *buf)
1195{
Liron Kuch72b78552012-10-30 17:47:50 +02001196 if (channel->buffer_count > 0) {
1197 pr_err("tspp: cannot set buffer size - buffers already allocated\n");
1198 return -EPERM;
1199 }
1200
Joel Nider435ad8e2011-12-14 16:53:30 +02001201 if (buf->size < TSPP_MIN_BUFFER_SIZE)
1202 channel->buffer_size = TSPP_MIN_BUFFER_SIZE;
1203 else if (buf->size > TSPP_MAX_BUFFER_SIZE)
1204 channel->buffer_size = TSPP_MAX_BUFFER_SIZE;
1205 else
1206 channel->buffer_size = buf->size;
1207
1208 return 0;
1209}
1210
1211static void tspp_set_tsif_mode(struct tspp_channel *channel,
1212 enum tspp_tsif_mode mode)
1213{
1214 int index;
1215
1216 switch (channel->src) {
1217 case TSPP_SOURCE_TSIF0:
1218 index = 0;
1219 break;
1220 case TSPP_SOURCE_TSIF1:
1221 index = 1;
1222 break;
1223 default:
1224 pr_warn("tspp: can't set mode for non-tsif source %d",
1225 channel->src);
1226 return;
1227 }
1228 channel->pdev->tsif[index].mode = mode;
1229}
1230
Hamad Kadmany92705b32012-10-23 14:15:41 +02001231static void tspp_set_signal_inversion(struct tspp_channel *channel,
Liron Kuch72b78552012-10-30 17:47:50 +02001232 int clock_inverse, int data_inverse,
1233 int sync_inverse, int enable_inverse)
Hamad Kadmany92705b32012-10-23 14:15:41 +02001234{
1235 int index;
1236
1237 switch (channel->src) {
1238 case TSPP_SOURCE_TSIF0:
1239 index = 0;
1240 break;
1241 case TSPP_SOURCE_TSIF1:
1242 index = 1;
1243 break;
1244 default:
1245 return;
1246 }
1247 channel->pdev->tsif[index].clock_inverse = clock_inverse;
1248 channel->pdev->tsif[index].data_inverse = data_inverse;
1249 channel->pdev->tsif[index].sync_inverse = sync_inverse;
1250 channel->pdev->tsif[index].enable_inverse = enable_inverse;
1251}
1252
Liron Kuch72b78552012-10-30 17:47:50 +02001253static int tspp_is_buffer_size_aligned(u32 size, enum tspp_mode mode)
1254{
1255 u32 alignment;
1256
1257 switch (mode) {
1258 case TSPP_MODE_RAW:
1259 /* must be a multiple of 192 */
1260 alignment = (TSPP_PACKET_LENGTH + 4);
1261 if (size % alignment)
1262 return 0;
1263 return 1;
1264
1265 case TSPP_MODE_RAW_NO_SUFFIX:
1266 /* must be a multiple of 188 */
1267 alignment = TSPP_PACKET_LENGTH;
1268 if (size % alignment)
1269 return 0;
1270 return 1;
1271
1272 case TSPP_MODE_DISABLED:
1273 case TSPP_MODE_PES:
1274 default:
1275 /* no alignment requirement */
1276 return 1;
1277 }
1278
1279}
1280
1281static u32 tspp_align_buffer_size_by_mode(u32 size, enum tspp_mode mode)
1282{
1283 u32 new_size;
1284 u32 alignment;
1285
1286 switch (mode) {
1287 case TSPP_MODE_RAW:
1288 /* must be a multiple of 192 */
1289 alignment = (TSPP_PACKET_LENGTH + 4);
1290 break;
1291
1292 case TSPP_MODE_RAW_NO_SUFFIX:
1293 /* must be a multiple of 188 */
1294 alignment = TSPP_PACKET_LENGTH;
1295 break;
1296
1297 case TSPP_MODE_DISABLED:
1298 case TSPP_MODE_PES:
1299 default:
1300 /* no alignment requirement - give the user what he asks for */
1301 alignment = 1;
1302 break;
1303 }
1304 /* align up */
1305 new_size = (((size + alignment - 1) / alignment) * alignment);
1306 return new_size;
1307}
1308
1309static void tspp_destroy_buffers(u32 channel_id, struct tspp_channel *channel)
1310{
1311 int i;
1312 struct tspp_mem_buffer *pbuf, *temp;
1313
1314 pbuf = channel->data;
1315 for (i = 0; i < channel->buffer_count; i++) {
1316 if (pbuf->desc.phys_base) {
1317 if (channel->memfree) {
1318 channel->memfree(channel_id,
1319 pbuf->desc.size,
1320 pbuf->desc.virt_base,
1321 pbuf->desc.phys_base,
1322 channel->user_info);
1323 } else {
Hamad Kadmany090709b2013-01-06 12:08:13 +02001324 if (!channel->dma_pool)
1325 dma_free_coherent(NULL,
1326 pbuf->desc.size,
1327 pbuf->desc.virt_base,
1328 pbuf->desc.phys_base);
1329 else
1330 dma_pool_free(channel->dma_pool,
1331 pbuf->desc.virt_base,
1332 pbuf->desc.phys_base);
Liron Kuch72b78552012-10-30 17:47:50 +02001333 }
1334 pbuf->desc.phys_base = 0;
1335 }
1336 pbuf->desc.virt_base = 0;
1337 pbuf->state = TSPP_BUF_STATE_EMPTY;
1338 temp = pbuf;
1339 pbuf = pbuf->next;
1340 kfree(temp);
1341 }
1342}
1343
Gilad Broner6049ea32014-04-10 09:48:44 +03001344static int msm_tspp_req_irqs(struct tspp_device *device)
1345{
1346 int rc;
1347 int i;
1348 int j;
1349
1350 rc = request_irq(device->tspp_irq, tspp_isr, IRQF_SHARED,
1351 dev_name(&device->pdev->dev), device);
1352 if (rc) {
1353 dev_err(&device->pdev->dev,
1354 "failed to request TSPP IRQ %d : %d",
1355 device->tspp_irq, rc);
1356 return rc;
1357 }
1358
1359 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
1360 rc = request_irq(device->tsif[i].tsif_irq,
1361 tsif_isr, IRQF_SHARED, dev_name(&device->pdev->dev),
1362 &device->tsif[i]);
1363 if (rc) {
1364 dev_err(&device->pdev->dev,
1365 "failed to request TSIF%d IRQ: %d",
1366 i, rc);
1367 goto failed;
1368 }
1369 }
1370
1371 return 0;
1372
1373failed:
1374 free_irq(device->tspp_irq, device);
1375 for (j = 0; j < i; j++)
1376 free_irq(device->tsif[j].tsif_irq, device);
1377
1378 return rc;
1379}
1380
1381static inline void msm_tspp_free_irqs(struct tspp_device *device)
1382{
1383 int i;
1384
1385 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
1386 if (device->tsif[i].tsif_irq)
1387 free_irq(device->tsif[i].tsif_irq, &device->tsif[i]);
1388 }
1389
1390 if (device->tspp_irq)
1391 free_irq(device->tspp_irq, device);
1392}
1393
Joel Nider435ad8e2011-12-14 16:53:30 +02001394/*** TSPP API functions ***/
Liron Kuch72b78552012-10-30 17:47:50 +02001395
1396/**
1397 * tspp_open_stream - open a TSPP stream for use.
1398 *
1399 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1400 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1401 * @source: stream source parameters.
1402 *
1403 * Return error status
1404 *
1405 */
1406int tspp_open_stream(u32 dev, u32 channel_id,
1407 struct tspp_select_source *source)
Joel Nider5556a852011-10-16 10:52:13 +02001408{
1409 u32 val;
Gilad Broner6049ea32014-04-10 09:48:44 +03001410 int rc;
1411 bool req_irq = false;
Joel Nider5556a852011-10-16 10:52:13 +02001412 struct tspp_device *pdev;
Joel Nider435ad8e2011-12-14 16:53:30 +02001413 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001414
Hamad Kadmany92705b32012-10-23 14:15:41 +02001415 TSPP_DEBUG("tspp_open_stream %i %i %i %i",
1416 dev, channel_id, source->source, source->mode);
Liron Kuch72b78552012-10-30 17:47:50 +02001417
Joel Nider435ad8e2011-12-14 16:53:30 +02001418 if (dev >= TSPP_MAX_DEVICES) {
1419 pr_err("tspp: device id out of range");
1420 return -ENODEV;
1421 }
Joel Nider5556a852011-10-16 10:52:13 +02001422
Joel Nider435ad8e2011-12-14 16:53:30 +02001423 if (channel_id >= TSPP_NUM_CHANNELS) {
1424 pr_err("tspp: channel id out of range");
1425 return -ECHRNG;
1426 }
1427
1428 pdev = tspp_find_by_id(dev);
1429 if (!pdev) {
1430 pr_err("tspp_str: can't find device %i", dev);
1431 return -ENODEV;
1432 }
1433 channel = &pdev->channels[channel_id];
Hamad Kadmany92705b32012-10-23 14:15:41 +02001434 channel->src = source->source;
1435 tspp_set_tsif_mode(channel, source->mode);
1436 tspp_set_signal_inversion(channel, source->clk_inverse,
Liron Kuch72b78552012-10-30 17:47:50 +02001437 source->data_inverse, source->sync_inverse,
1438 source->enable_inverse);
Joel Nider5556a852011-10-16 10:52:13 +02001439
Gilad Broner6049ea32014-04-10 09:48:44 +03001440 /* Request IRQ resources on first open */
1441 if ((source->source == TSPP_SOURCE_TSIF0 ||
1442 source->source == TSPP_SOURCE_TSIF1) &&
1443 (pdev->tsif[0].ref_count + pdev->tsif[1].ref_count) == 0) {
1444 rc = msm_tspp_req_irqs(pdev);
1445 if (rc) {
1446 pr_err("tspp: error requesting irqs\n");
1447 return rc;
1448 }
1449 req_irq = true;
1450 }
1451
Hamad Kadmany92705b32012-10-23 14:15:41 +02001452 switch (source->source) {
Joel Nider5556a852011-10-16 10:52:13 +02001453 case TSPP_SOURCE_TSIF0:
Liron Kuch275c0b32013-02-10 15:19:32 +02001454 if (tspp_config_gpios(pdev, channel->src, 1) != 0) {
Gilad Broner6049ea32014-04-10 09:48:44 +03001455 rc = -EBUSY;
Liron Kuch275c0b32013-02-10 15:19:32 +02001456 pr_err("tspp: error enabling tsif0 GPIOs\n");
Gilad Broner6049ea32014-04-10 09:48:44 +03001457 goto free_irq;
Liron Kuch275c0b32013-02-10 15:19:32 +02001458 }
Joel Nider5556a852011-10-16 10:52:13 +02001459 /* make sure TSIF0 is running & enabled */
1460 if (tspp_start_tsif(&pdev->tsif[0]) != 0) {
Gilad Broner6049ea32014-04-10 09:48:44 +03001461 rc = -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001462 pr_err("tspp: error starting tsif0");
Gilad Broner6049ea32014-04-10 09:48:44 +03001463 goto free_irq;
Joel Nider5556a852011-10-16 10:52:13 +02001464 }
Liron Kucha7b49ae2013-02-14 16:26:38 +02001465 if (pdev->tsif[0].ref_count == 1) {
1466 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1467 writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
1468 pdev->base + TSPP_CONTROL);
1469 wmb();
1470 }
Joel Nider5556a852011-10-16 10:52:13 +02001471 break;
1472 case TSPP_SOURCE_TSIF1:
Liron Kuch275c0b32013-02-10 15:19:32 +02001473 if (tspp_config_gpios(pdev, channel->src, 1) != 0) {
Gilad Broner6049ea32014-04-10 09:48:44 +03001474 rc = -EBUSY;
Liron Kuch275c0b32013-02-10 15:19:32 +02001475 pr_err("tspp: error enabling tsif1 GPIOs\n");
Gilad Broner6049ea32014-04-10 09:48:44 +03001476 goto free_irq;
Liron Kuch275c0b32013-02-10 15:19:32 +02001477 }
Joel Nider5556a852011-10-16 10:52:13 +02001478 /* make sure TSIF1 is running & enabled */
1479 if (tspp_start_tsif(&pdev->tsif[1]) != 0) {
Gilad Broner6049ea32014-04-10 09:48:44 +03001480 rc = -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001481 pr_err("tspp: error starting tsif1");
Gilad Broner6049ea32014-04-10 09:48:44 +03001482 goto free_irq;
Joel Nider5556a852011-10-16 10:52:13 +02001483 }
Liron Kucha7b49ae2013-02-14 16:26:38 +02001484 if (pdev->tsif[1].ref_count == 1) {
1485 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1486 writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
1487 pdev->base + TSPP_CONTROL);
1488 wmb();
1489 }
Joel Nider5556a852011-10-16 10:52:13 +02001490 break;
1491 case TSPP_SOURCE_MEM:
1492 break;
1493 default:
Hamad Kadmany92705b32012-10-23 14:15:41 +02001494 pr_err("tspp: channel %i invalid source %i",
1495 channel->id, source->source);
Joel Nider435ad8e2011-12-14 16:53:30 +02001496 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001497 }
1498
Joel Nider5556a852011-10-16 10:52:13 +02001499 return 0;
Gilad Broner6049ea32014-04-10 09:48:44 +03001500
1501free_irq:
1502 if (req_irq)
1503 msm_tspp_free_irqs(pdev);
1504 return rc;
Joel Nider5556a852011-10-16 10:52:13 +02001505}
1506EXPORT_SYMBOL(tspp_open_stream);
1507
Liron Kuch72b78552012-10-30 17:47:50 +02001508/**
1509 * tspp_close_stream - close a TSPP stream.
1510 *
1511 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1512 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1513 *
1514 * Return error status
1515 *
1516 */
Joel Nider435ad8e2011-12-14 16:53:30 +02001517int tspp_close_stream(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001518{
1519 u32 val;
Gilad Broner6049ea32014-04-10 09:48:44 +03001520 u32 prev_ref_count = 0;
Joel Nider5556a852011-10-16 10:52:13 +02001521 struct tspp_device *pdev;
Joel Nider435ad8e2011-12-14 16:53:30 +02001522 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001523
Joel Nider435ad8e2011-12-14 16:53:30 +02001524 if (channel_id >= TSPP_NUM_CHANNELS) {
1525 pr_err("tspp: channel id out of range");
1526 return -ECHRNG;
1527 }
1528 pdev = tspp_find_by_id(dev);
1529 if (!pdev) {
1530 pr_err("tspp_cs: can't find device %i", dev);
1531 return -EBUSY;
1532 }
1533 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001534
1535 switch (channel->src) {
1536 case TSPP_SOURCE_TSIF0:
Liron Kucha7b49ae2013-02-14 16:26:38 +02001537 prev_ref_count = pdev->tsif[0].ref_count;
Joel Nider5556a852011-10-16 10:52:13 +02001538 tspp_stop_tsif(&pdev->tsif[0]);
Liron Kuch275c0b32013-02-10 15:19:32 +02001539 if (tspp_config_gpios(pdev, channel->src, 0) != 0)
1540 pr_err("tspp: error disabling tsif0 GPIOs\n");
1541
Liron Kucha7b49ae2013-02-14 16:26:38 +02001542 if (prev_ref_count == 1) {
1543 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1544 writel_relaxed(val | TSPP_CONTROL_TSP_TSIF0_SRC_DIS,
1545 pdev->base + TSPP_CONTROL);
1546 wmb();
1547 }
Joel Nider5556a852011-10-16 10:52:13 +02001548 break;
1549 case TSPP_SOURCE_TSIF1:
Liron Kucha7b49ae2013-02-14 16:26:38 +02001550 prev_ref_count = pdev->tsif[1].ref_count;
Joel Nider5556a852011-10-16 10:52:13 +02001551 tspp_stop_tsif(&pdev->tsif[1]);
Liron Kuch275c0b32013-02-10 15:19:32 +02001552 if (tspp_config_gpios(pdev, channel->src, 0) != 0)
1553 pr_err("tspp: error disabling tsif0 GPIOs\n");
1554
Liron Kucha7b49ae2013-02-14 16:26:38 +02001555 if (prev_ref_count == 1) {
1556 val = readl_relaxed(pdev->base + TSPP_CONTROL);
1557 writel_relaxed(val | TSPP_CONTROL_TSP_TSIF1_SRC_DIS,
1558 pdev->base + TSPP_CONTROL);
1559 wmb();
1560 }
Joel Nider5556a852011-10-16 10:52:13 +02001561 break;
1562 case TSPP_SOURCE_MEM:
1563 break;
1564 case TSPP_SOURCE_NONE:
1565 break;
1566 }
1567
Joel Nider435ad8e2011-12-14 16:53:30 +02001568 channel->src = TSPP_SOURCE_NONE;
Gilad Broner6049ea32014-04-10 09:48:44 +03001569
1570 /* Free requested interrupts to save power */
1571 if ((pdev->tsif[0].ref_count + pdev->tsif[1].ref_count) == 0 &&
1572 prev_ref_count)
1573 msm_tspp_free_irqs(pdev);
1574
Joel Nider5556a852011-10-16 10:52:13 +02001575 return 0;
1576}
1577EXPORT_SYMBOL(tspp_close_stream);
1578
Liron Kuch72b78552012-10-30 17:47:50 +02001579/**
1580 * tspp_open_channel - open a TSPP channel.
1581 *
1582 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1583 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1584 *
1585 * Return error status
1586 *
1587 */
Joel Nider435ad8e2011-12-14 16:53:30 +02001588int tspp_open_channel(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001589{
1590 int rc = 0;
Joel Nider435ad8e2011-12-14 16:53:30 +02001591 struct sps_connect *config;
1592 struct sps_register_event *event;
1593 struct tspp_channel *channel;
1594 struct tspp_device *pdev;
1595
1596 if (channel_id >= TSPP_NUM_CHANNELS) {
1597 pr_err("tspp: channel id out of range");
1598 return -ECHRNG;
1599 }
1600 pdev = tspp_find_by_id(dev);
1601 if (!pdev) {
1602 pr_err("tspp_oc: can't find device %i", dev);
1603 return -ENODEV;
1604 }
1605 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02001606
1607 if (channel->used) {
1608 pr_err("tspp channel already in use");
Joel Nider435ad8e2011-12-14 16:53:30 +02001609 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02001610 }
1611
Joel Nider435ad8e2011-12-14 16:53:30 +02001612 config = &channel->config;
1613 event = &channel->event;
1614
1615 /* start the clocks if needed */
Liron Kuch59339922013-01-01 18:29:47 +02001616 if (tspp_channels_in_use(pdev) == 0) {
Liron Kuch605cc122013-02-21 14:25:57 +02001617 rc = tspp_clock_start(pdev);
1618 if (rc)
1619 return rc;
1620
Joel Nider435ad8e2011-12-14 16:53:30 +02001621 wake_lock(&pdev->wake_lock);
Liron Kuch59339922013-01-01 18:29:47 +02001622 }
Joel Nider435ad8e2011-12-14 16:53:30 +02001623
Joel Nider5556a852011-10-16 10:52:13 +02001624 /* mark it as used */
1625 channel->used = 1;
1626
1627 /* start the bam */
1628 channel->pipe = sps_alloc_endpoint();
1629 if (channel->pipe == 0) {
1630 pr_err("tspp: error allocating endpoint");
1631 rc = -ENOMEM;
1632 goto err_sps_alloc;
1633 }
1634
1635 /* get default configuration */
1636 sps_get_config(channel->pipe, config);
1637
Joel Nider435ad8e2011-12-14 16:53:30 +02001638 config->source = pdev->bam_handle;
Joel Nider5556a852011-10-16 10:52:13 +02001639 config->destination = SPS_DEV_HANDLE_MEM;
1640 config->mode = SPS_MODE_SRC;
Joel Nider435ad8e2011-12-14 16:53:30 +02001641 config->options =
1642 SPS_O_AUTO_ENABLE | /* connection is auto-enabled */
1643 SPS_O_STREAMING | /* streaming mode */
1644 SPS_O_DESC_DONE | /* interrupt on end of descriptor */
Hamad Kadmany81cee052012-11-29 14:15:57 +02001645 SPS_O_ACK_TRANSFERS | /* must use sps_get_iovec() */
1646 SPS_O_HYBRID; /* Read actual descriptors in sps_get_iovec() */
Joel Nider5556a852011-10-16 10:52:13 +02001647 config->src_pipe_index = channel->id;
1648 config->desc.size =
Hamad Kadmany81cee052012-11-29 14:15:57 +02001649 TSPP_SPS_DESCRIPTOR_COUNT * SPS_DESCRIPTOR_SIZE;
Joel Nider5556a852011-10-16 10:52:13 +02001650 config->desc.base = dma_alloc_coherent(NULL,
1651 config->desc.size,
1652 &config->desc.phys_base,
1653 GFP_KERNEL);
1654 if (config->desc.base == 0) {
1655 pr_err("tspp: error allocating sps descriptors");
1656 rc = -ENOMEM;
1657 goto err_desc_alloc;
1658 }
1659
1660 memset(config->desc.base, 0, config->desc.size);
1661
1662 rc = sps_connect(channel->pipe, config);
1663 if (rc) {
1664 pr_err("tspp: error connecting bam");
1665 goto err_connect;
1666 }
1667
1668 event->mode = SPS_TRIGGER_CALLBACK;
Joel Nider435ad8e2011-12-14 16:53:30 +02001669 event->options = SPS_O_DESC_DONE;
Joel Nider5556a852011-10-16 10:52:13 +02001670 event->callback = tspp_sps_complete_cb;
1671 event->xfer_done = NULL;
Joel Nider435ad8e2011-12-14 16:53:30 +02001672 event->user = pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001673
1674 rc = sps_register_event(channel->pipe, event);
1675 if (rc) {
1676 pr_err("tspp: error registering event");
1677 goto err_event;
1678 }
1679
Hamad Kadmany81cee052012-11-29 14:15:57 +02001680 init_timer(&channel->expiration_timer);
1681 channel->expiration_timer.function = tspp_expiration_timer;
1682 channel->expiration_timer.data = (unsigned long)pdev;
1683 channel->expiration_timer.expires = 0xffffffffL;
1684
Joel Nider435ad8e2011-12-14 16:53:30 +02001685 rc = pm_runtime_get(&pdev->pdev->dev);
Joel Nider5556a852011-10-16 10:52:13 +02001686 if (rc < 0) {
Joel Nider435ad8e2011-12-14 16:53:30 +02001687 dev_err(&pdev->pdev->dev,
Joel Nider5556a852011-10-16 10:52:13 +02001688 "Runtime PM: Unable to wake up tspp device, rc = %d",
1689 rc);
1690 }
Joel Nider5556a852011-10-16 10:52:13 +02001691 return 0;
1692
1693err_event:
1694 sps_disconnect(channel->pipe);
1695err_connect:
1696 dma_free_coherent(NULL, config->desc.size, config->desc.base,
1697 config->desc.phys_base);
1698err_desc_alloc:
1699 sps_free_endpoint(channel->pipe);
1700err_sps_alloc:
1701 return rc;
1702}
1703EXPORT_SYMBOL(tspp_open_channel);
1704
Liron Kuch72b78552012-10-30 17:47:50 +02001705/**
1706 * tspp_close_channel - close a TSPP channel.
1707 *
1708 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1709 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1710 *
1711 * Return error status
1712 *
1713 */
Joel Nider435ad8e2011-12-14 16:53:30 +02001714int tspp_close_channel(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02001715{
1716 int i;
1717 int id;
Liron Kuch4ed3bf62013-03-28 09:44:42 +02001718 int table_idx;
Joel Nider5556a852011-10-16 10:52:13 +02001719 u32 val;
Liron Kuche0acb412013-04-21 13:16:45 +03001720 unsigned long flags;
Joel Nider5556a852011-10-16 10:52:13 +02001721
Joel Nider435ad8e2011-12-14 16:53:30 +02001722 struct sps_connect *config;
1723 struct tspp_device *pdev;
1724 struct tspp_channel *channel;
Joel Nider435ad8e2011-12-14 16:53:30 +02001725
1726 if (channel_id >= TSPP_NUM_CHANNELS) {
1727 pr_err("tspp: channel id out of range");
1728 return -ECHRNG;
1729 }
1730 pdev = tspp_find_by_id(dev);
1731 if (!pdev) {
1732 pr_err("tspp_close: can't find device %i", dev);
1733 return -ENODEV;
1734 }
1735 channel = &pdev->channels[channel_id];
1736
1737 /* if the channel is not used, we are done */
1738 if (!channel->used)
1739 return 0;
1740
Liron Kuche0acb412013-04-21 13:16:45 +03001741 /*
1742 * Need to protect access to used and waiting fields, as they are
1743 * used by the tasklet which is invoked from interrupt context
1744 */
1745 spin_lock_irqsave(&pdev->spinlock, flags);
1746 channel->used = 0;
1747 channel->waiting = NULL;
1748 spin_unlock_irqrestore(&pdev->spinlock, flags);
1749
Hamad Kadmany81cee052012-11-29 14:15:57 +02001750 if (channel->expiration_period_ms)
1751 del_timer(&channel->expiration_timer);
1752
Joel Nider435ad8e2011-12-14 16:53:30 +02001753 channel->notifier = NULL;
1754 channel->notify_data = NULL;
Hamad Kadmany81cee052012-11-29 14:15:57 +02001755 channel->expiration_period_ms = 0;
Joel Nider435ad8e2011-12-14 16:53:30 +02001756
1757 config = &channel->config;
1758 pdev = channel->pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001759
1760 /* disable pipe (channel) */
1761 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1762 writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE);
1763 wmb();
1764
1765 /* unregister all filters for this channel */
Liron Kuch4ed3bf62013-03-28 09:44:42 +02001766 for (table_idx = 0; table_idx < TSPP_FILTER_TABLES; table_idx++) {
1767 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1768 struct tspp_pid_filter *filter =
1769 &pdev->filters[table_idx]->filter[i];
1770 id = FILTER_GET_PIPE_NUMBER0(filter);
1771 if (id == channel->id) {
1772 if (FILTER_HAS_ENCRYPTION(filter))
1773 tspp_free_key_entry(
1774 FILTER_GET_KEY_NUMBER(filter));
1775 filter->config = 0;
1776 filter->filter = 0;
1777 }
Joel Nider5556a852011-10-16 10:52:13 +02001778 }
1779 }
1780 channel->filter_count = 0;
1781
Joel Nider5556a852011-10-16 10:52:13 +02001782 /* disconnect the bam */
1783 if (sps_disconnect(channel->pipe) != 0)
1784 pr_warn("tspp: Error freeing sps endpoint (%i)", channel->id);
1785
1786 /* destroy the buffers */
1787 dma_free_coherent(NULL, config->desc.size, config->desc.base,
1788 config->desc.phys_base);
1789
Hamad Kadmany06ccf822013-12-12 14:10:20 +02001790 sps_free_endpoint(channel->pipe);
1791
Liron Kuch72b78552012-10-30 17:47:50 +02001792 tspp_destroy_buffers(channel_id, channel);
Hamad Kadmany090709b2013-01-06 12:08:13 +02001793 if (channel->dma_pool) {
1794 dma_pool_destroy(channel->dma_pool);
1795 channel->dma_pool = NULL;
1796 }
Liron Kuch72b78552012-10-30 17:47:50 +02001797
1798 channel->src = TSPP_SOURCE_NONE;
1799 channel->mode = TSPP_MODE_DISABLED;
1800 channel->memfree = NULL;
1801 channel->user_info = NULL;
Joel Nider5556a852011-10-16 10:52:13 +02001802 channel->buffer_count = 0;
Joel Nider435ad8e2011-12-14 16:53:30 +02001803 channel->data = NULL;
1804 channel->read = NULL;
Joel Nider435ad8e2011-12-14 16:53:30 +02001805 channel->locked = NULL;
Joel Nider5556a852011-10-16 10:52:13 +02001806
Liron Kuch59339922013-01-01 18:29:47 +02001807 if (tspp_channels_in_use(pdev) == 0) {
Joel Nider435ad8e2011-12-14 16:53:30 +02001808 wake_unlock(&pdev->wake_lock);
Liron Kuch59339922013-01-01 18:29:47 +02001809 tspp_clock_stop(pdev);
1810 }
Joel Nider435ad8e2011-12-14 16:53:30 +02001811
Liron Kuch605cc122013-02-21 14:25:57 +02001812 pm_runtime_put(&pdev->pdev->dev);
1813
Joel Nider5556a852011-10-16 10:52:13 +02001814 return 0;
1815}
1816EXPORT_SYMBOL(tspp_close_channel);
1817
Liron Kuch72b78552012-10-30 17:47:50 +02001818/**
Hamad Kadmany6d2a9c72013-01-31 14:49:20 +02001819 * tspp_get_ref_clk_counter - return the TSIF clock reference (TCR) counter.
1820 *
1821 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1822 * @source: The TSIF source from which the counter should be read
1823 * @tcr_counter: the value of TCR counter
1824 *
1825 * Return error status
1826 *
1827 * TCR increments at a rate equal to 27 MHz/256 = 105.47 kHz.
1828 * If source is neither TSIF 0 or TSIF1 0 is returned.
1829 */
1830int tspp_get_ref_clk_counter(u32 dev, enum tspp_source source, u32 *tcr_counter)
1831{
1832 struct tspp_device *pdev;
1833 struct tspp_tsif_device *tsif_device;
1834
1835 if (!tcr_counter)
1836 return -EINVAL;
1837
1838 pdev = tspp_find_by_id(dev);
1839 if (!pdev) {
1840 pr_err("tspp_get_ref_clk_counter: can't find device %i\n", dev);
1841 return -ENODEV;
1842 }
1843
1844 switch (source) {
1845 case TSPP_SOURCE_TSIF0:
1846 tsif_device = &pdev->tsif[0];
1847 break;
1848
1849 case TSPP_SOURCE_TSIF1:
1850 tsif_device = &pdev->tsif[1];
1851 break;
1852
1853 default:
1854 tsif_device = NULL;
1855 break;
1856 }
1857
1858 if (tsif_device && tsif_device->ref_count)
1859 *tcr_counter = ioread32(tsif_device->base + TSIF_CLK_REF_OFF);
1860 else
1861 *tcr_counter = 0;
1862
1863 return 0;
1864}
1865EXPORT_SYMBOL(tspp_get_ref_clk_counter);
1866
1867/**
Liron Kuch72b78552012-10-30 17:47:50 +02001868 * tspp_add_filter - add a TSPP filter to a channel.
1869 *
1870 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
1871 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
1872 * @filter: TSPP filter parameters
1873 *
1874 * Return error status
1875 *
1876 */
Joel Nider435ad8e2011-12-14 16:53:30 +02001877int tspp_add_filter(u32 dev, u32 channel_id,
Joel Nider5556a852011-10-16 10:52:13 +02001878 struct tspp_filter *filter)
1879{
Liron Kuch72b78552012-10-30 17:47:50 +02001880 int i, rc;
Joel Nider5556a852011-10-16 10:52:13 +02001881 int other_channel;
1882 int entry;
1883 u32 val, pid, enabled;
Joel Nider435ad8e2011-12-14 16:53:30 +02001884 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02001885 struct tspp_pid_filter p;
Joel Nider435ad8e2011-12-14 16:53:30 +02001886 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02001887
Joel Nider435ad8e2011-12-14 16:53:30 +02001888 TSPP_DEBUG("tspp: add filter");
1889 if (channel_id >= TSPP_NUM_CHANNELS) {
1890 pr_err("tspp: channel id out of range");
1891 return -ECHRNG;
1892 }
1893 pdev = tspp_find_by_id(dev);
1894 if (!pdev) {
1895 pr_err("tspp_add: can't find device %i", dev);
1896 return -ENODEV;
1897 }
1898
1899 channel = &pdev->channels[channel_id];
1900
Joel Nider5556a852011-10-16 10:52:13 +02001901 if (filter->source > TSPP_SOURCE_MEM) {
1902 pr_err("tspp invalid source");
Joel Nider435ad8e2011-12-14 16:53:30 +02001903 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001904 }
1905
1906 if (filter->priority >= TSPP_NUM_PRIORITIES) {
Hamad Kadmany7d8a6f82013-11-17 11:31:01 +02001907 pr_err("tspp invalid filter priority");
Joel Nider435ad8e2011-12-14 16:53:30 +02001908 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001909 }
1910
Liron Kuch72b78552012-10-30 17:47:50 +02001911 channel->mode = filter->mode;
1912 /*
1913 * if buffers are already allocated, verify they fulfil
1914 * the alignment requirements.
1915 */
1916 if ((channel->buffer_count > 0) &&
1917 (!tspp_is_buffer_size_aligned(channel->buffer_size, channel->mode)))
1918 pr_warn("tspp: buffers allocated with incorrect alignment\n");
Joel Nider5556a852011-10-16 10:52:13 +02001919
1920 if (filter->mode == TSPP_MODE_PES) {
1921 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
1922 struct tspp_pid_filter *tspp_filter =
Joel Nider435ad8e2011-12-14 16:53:30 +02001923 &pdev->filters[channel->src]->filter[i];
Joel Nider5556a852011-10-16 10:52:13 +02001924 pid = FILTER_GET_PIPE_PID((tspp_filter));
1925 enabled = FILTER_GET_PIPE_PROCESS0(tspp_filter);
1926 if (enabled && (pid == filter->pid)) {
1927 other_channel =
1928 FILTER_GET_PIPE_NUMBER0(tspp_filter);
1929 pr_err("tspp: pid 0x%x already in use by channel %i",
1930 filter->pid, other_channel);
Joel Nider435ad8e2011-12-14 16:53:30 +02001931 return -EBADSLT;
Joel Nider5556a852011-10-16 10:52:13 +02001932 }
1933 }
1934 }
1935
1936 /* make sure this priority is not already in use */
1937 enabled = FILTER_GET_PIPE_PROCESS0(
Joel Nider435ad8e2011-12-14 16:53:30 +02001938 (&(pdev->filters[channel->src]->filter[filter->priority])));
Joel Nider5556a852011-10-16 10:52:13 +02001939 if (enabled) {
1940 pr_err("tspp: filter priority %i source %i is already enabled\n",
1941 filter->priority, channel->src);
Joel Nider435ad8e2011-12-14 16:53:30 +02001942 return -ENOSR;
Joel Nider5556a852011-10-16 10:52:13 +02001943 }
1944
1945 if (channel->mode == TSPP_MODE_PES) {
1946 /* if we are already processing in PES mode, disable pipe
1947 (channel) and filter to be updated */
1948 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1949 writel_relaxed(val | (1 << channel->id),
1950 pdev->base + TSPP_PS_DISABLE);
1951 wmb();
1952 }
1953
1954 /* update entry */
1955 p.filter = 0;
Joel Nider435ad8e2011-12-14 16:53:30 +02001956 p.config = FILTER_TRANS_END_DISABLE;
Joel Nider5556a852011-10-16 10:52:13 +02001957 FILTER_SET_PIPE_PROCESS0((&p), filter->mode);
1958 FILTER_SET_PIPE_PID((&p), filter->pid);
1959 FILTER_SET_PID_MASK((&p), filter->mask);
1960 FILTER_SET_PIPE_NUMBER0((&p), channel->id);
1961 FILTER_SET_PIPE_PROCESS1((&p), TSPP_MODE_DISABLED);
1962 if (filter->decrypt) {
1963 entry = tspp_get_key_entry();
1964 if (entry == -1) {
1965 pr_err("tspp: no more keys available!");
1966 } else {
1967 p.config |= FILTER_DECRYPT;
1968 FILTER_SET_KEY_NUMBER((&p), entry);
1969 }
1970 }
Joel Nider5556a852011-10-16 10:52:13 +02001971
Joel Nider435ad8e2011-12-14 16:53:30 +02001972 pdev->filters[channel->src]->
Joel Nider5556a852011-10-16 10:52:13 +02001973 filter[filter->priority].config = p.config;
Joel Nider435ad8e2011-12-14 16:53:30 +02001974 pdev->filters[channel->src]->
Joel Nider5556a852011-10-16 10:52:13 +02001975 filter[filter->priority].filter = p.filter;
1976
Liron Kuch72b78552012-10-30 17:47:50 +02001977 /*
1978 * allocate buffers if needed (i.e. if user did has not already called
1979 * tspp_allocate_buffers() explicitly).
1980 */
1981 if (channel->buffer_count == 0) {
1982 channel->buffer_size =
Hamad Kadmany090709b2013-01-06 12:08:13 +02001983 tspp_align_buffer_size_by_mode(channel->buffer_size,
Liron Kuch72b78552012-10-30 17:47:50 +02001984 channel->mode);
1985 rc = tspp_allocate_buffers(dev, channel->id,
1986 channel->max_buffers,
1987 channel->buffer_size,
1988 channel->int_freq, NULL, NULL, NULL);
1989 if (rc != 0) {
1990 pr_err("tspp: tspp_allocate_buffers failed\n");
1991 return rc;
1992 }
Joel Nider435ad8e2011-12-14 16:53:30 +02001993 }
1994
Joel Nider5556a852011-10-16 10:52:13 +02001995 /* reenable pipe */
1996 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
1997 writel_relaxed(val & ~(1 << channel->id), pdev->base + TSPP_PS_DISABLE);
1998 wmb();
1999 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
2000
Joel Nider5556a852011-10-16 10:52:13 +02002001 channel->filter_count++;
2002
2003 return 0;
2004}
2005EXPORT_SYMBOL(tspp_add_filter);
2006
Liron Kuch72b78552012-10-30 17:47:50 +02002007/**
2008 * tspp_remove_filter - remove a TSPP filter from a channel.
2009 *
2010 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2011 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2012 * @filter: TSPP filter parameters
2013 *
2014 * Return error status
2015 *
2016 */
Joel Nider435ad8e2011-12-14 16:53:30 +02002017int tspp_remove_filter(u32 dev, u32 channel_id,
Joel Nider5556a852011-10-16 10:52:13 +02002018 struct tspp_filter *filter)
2019{
2020 int entry;
2021 u32 val;
Joel Nider435ad8e2011-12-14 16:53:30 +02002022 struct tspp_device *pdev;
2023 int src;
2024 struct tspp_pid_filter *tspp_filter;
2025 struct tspp_channel *channel;
2026
2027 if (channel_id >= TSPP_NUM_CHANNELS) {
2028 pr_err("tspp: channel id out of range");
2029 return -ECHRNG;
2030 }
2031 pdev = tspp_find_by_id(dev);
2032 if (!pdev) {
2033 pr_err("tspp_remove: can't find device %i", dev);
2034 return -ENODEV;
2035 }
Hamad Kadmany7d8a6f82013-11-17 11:31:01 +02002036 if (filter->priority >= TSPP_NUM_PRIORITIES) {
2037 pr_err("tspp invalid filter priority");
2038 return -ENOSR;
2039 }
Joel Nider435ad8e2011-12-14 16:53:30 +02002040 channel = &pdev->channels[channel_id];
2041
2042 src = channel->src;
2043 tspp_filter = &(pdev->filters[src]->filter[filter->priority]);
Joel Nider5556a852011-10-16 10:52:13 +02002044
2045 /* disable pipe (channel) */
2046 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
2047 writel_relaxed(val | channel->id, pdev->base + TSPP_PS_DISABLE);
2048 wmb();
2049
2050 /* update data keys */
2051 if (tspp_filter->config & FILTER_DECRYPT) {
2052 entry = FILTER_GET_KEY_NUMBER(tspp_filter);
2053 tspp_free_key_entry(entry);
2054 }
2055
2056 /* update pid table */
2057 tspp_filter->config = 0;
2058 tspp_filter->filter = 0;
2059
2060 channel->filter_count--;
2061
2062 /* reenable pipe */
2063 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
2064 writel_relaxed(val & ~(1 << channel->id),
2065 pdev->base + TSPP_PS_DISABLE);
2066 wmb();
2067 val = readl_relaxed(pdev->base + TSPP_PS_DISABLE);
2068
2069 return 0;
2070}
2071EXPORT_SYMBOL(tspp_remove_filter);
2072
Liron Kuch72b78552012-10-30 17:47:50 +02002073/**
2074 * tspp_set_key - set TSPP key in key table.
2075 *
2076 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2077 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2078 * @key: TSPP key parameters
2079 *
2080 * Return error status
2081 *
2082 */
Joel Nider435ad8e2011-12-14 16:53:30 +02002083int tspp_set_key(u32 dev, u32 channel_id, struct tspp_key *key)
Joel Nider5556a852011-10-16 10:52:13 +02002084{
2085 int i;
2086 int id;
2087 int key_index;
2088 int data;
Joel Nider435ad8e2011-12-14 16:53:30 +02002089 struct tspp_channel *channel;
2090 struct tspp_device *pdev;
2091
2092 if (channel_id >= TSPP_NUM_CHANNELS) {
2093 pr_err("tspp: channel id out of range");
2094 return -ECHRNG;
2095 }
2096 pdev = tspp_find_by_id(dev);
2097 if (!pdev) {
2098 pr_err("tspp_set: can't find device %i", dev);
2099 return -ENODEV;
2100 }
2101 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02002102
2103 /* read the key index used by this channel */
2104 for (i = 0; i < TSPP_NUM_PRIORITIES; i++) {
2105 struct tspp_pid_filter *tspp_filter =
Joel Nider435ad8e2011-12-14 16:53:30 +02002106 &(pdev->filters[channel->src]->filter[i]);
Joel Nider5556a852011-10-16 10:52:13 +02002107 id = FILTER_GET_PIPE_NUMBER0(tspp_filter);
2108 if (id == channel->id) {
2109 if (FILTER_HAS_ENCRYPTION(tspp_filter)) {
2110 key_index = FILTER_GET_KEY_NUMBER(tspp_filter);
2111 break;
2112 }
2113 }
2114 }
2115 if (i == TSPP_NUM_PRIORITIES) {
2116 pr_err("tspp: no encryption on this channel");
Joel Nider435ad8e2011-12-14 16:53:30 +02002117 return -ENOKEY;
Joel Nider5556a852011-10-16 10:52:13 +02002118 }
2119
2120 if (key->parity == TSPP_KEY_PARITY_EVEN) {
Joel Nider435ad8e2011-12-14 16:53:30 +02002121 pdev->tspp_key_table->entry[key_index].even_lsb = key->lsb;
2122 pdev->tspp_key_table->entry[key_index].even_msb = key->msb;
Joel Nider5556a852011-10-16 10:52:13 +02002123 } else {
Joel Nider435ad8e2011-12-14 16:53:30 +02002124 pdev->tspp_key_table->entry[key_index].odd_lsb = key->lsb;
2125 pdev->tspp_key_table->entry[key_index].odd_msb = key->msb;
Joel Nider5556a852011-10-16 10:52:13 +02002126 }
2127 data = readl_relaxed(channel->pdev->base + TSPP_KEY_VALID);
2128
2129 return 0;
2130}
2131EXPORT_SYMBOL(tspp_set_key);
2132
Liron Kuch72b78552012-10-30 17:47:50 +02002133/**
2134 * tspp_register_notification - register TSPP channel notification function.
2135 *
2136 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2137 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2138 * @pNotify: notification function
2139 * @userdata: user data to pass to notification function
2140 * @timer_ms: notification for partially filled buffers
2141 *
2142 * Return error status
2143 *
2144 */
Joel Nider435ad8e2011-12-14 16:53:30 +02002145int tspp_register_notification(u32 dev, u32 channel_id,
2146 tspp_notifier *pNotify, void *userdata, u32 timer_ms)
Joel Nider5556a852011-10-16 10:52:13 +02002147{
Joel Nider435ad8e2011-12-14 16:53:30 +02002148 struct tspp_channel *channel;
2149 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02002150
Joel Nider435ad8e2011-12-14 16:53:30 +02002151 if (channel_id >= TSPP_NUM_CHANNELS) {
2152 pr_err("tspp: channel id out of range");
2153 return -ECHRNG;
2154 }
2155 pdev = tspp_find_by_id(dev);
2156 if (!pdev) {
2157 pr_err("tspp_reg: can't find device %i", dev);
2158 return -ENODEV;
2159 }
2160 channel = &pdev->channels[channel_id];
2161 channel->notifier = pNotify;
2162 channel->notify_data = userdata;
Hamad Kadmany81cee052012-11-29 14:15:57 +02002163 channel->expiration_period_ms = timer_ms;
2164
Joel Nider5556a852011-10-16 10:52:13 +02002165 return 0;
2166}
Joel Nider435ad8e2011-12-14 16:53:30 +02002167EXPORT_SYMBOL(tspp_register_notification);
Joel Nider5556a852011-10-16 10:52:13 +02002168
Liron Kuch72b78552012-10-30 17:47:50 +02002169/**
2170 * tspp_unregister_notification - unregister TSPP channel notification function.
2171 *
2172 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2173 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2174 *
2175 * Return error status
2176 *
2177 */
Joel Nider435ad8e2011-12-14 16:53:30 +02002178int tspp_unregister_notification(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02002179{
Joel Nider435ad8e2011-12-14 16:53:30 +02002180 struct tspp_channel *channel;
2181 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02002182
Joel Nider435ad8e2011-12-14 16:53:30 +02002183 if (channel_id >= TSPP_NUM_CHANNELS) {
2184 pr_err("tspp: channel id out of range");
2185 return -ECHRNG;
2186 }
2187 pdev = tspp_find_by_id(dev);
2188 if (!pdev) {
2189 pr_err("tspp_unreg: can't find device %i", dev);
2190 return -ENODEV;
2191 }
2192 channel = &pdev->channels[channel_id];
2193 channel->notifier = NULL;
2194 channel->notify_data = 0;
Joel Nider5556a852011-10-16 10:52:13 +02002195 return 0;
2196}
Joel Nider435ad8e2011-12-14 16:53:30 +02002197EXPORT_SYMBOL(tspp_unregister_notification);
Joel Nider5556a852011-10-16 10:52:13 +02002198
Liron Kuch72b78552012-10-30 17:47:50 +02002199/**
2200 * tspp_get_buffer - get TSPP data buffer.
2201 *
2202 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2203 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2204 *
2205 * Return error status
2206 *
2207 */
Joel Nider435ad8e2011-12-14 16:53:30 +02002208const struct tspp_data_descriptor *tspp_get_buffer(u32 dev, u32 channel_id)
Joel Nider5556a852011-10-16 10:52:13 +02002209{
Joel Nider435ad8e2011-12-14 16:53:30 +02002210 struct tspp_mem_buffer *buffer;
2211 struct tspp_channel *channel;
2212 struct tspp_device *pdev;
Joel Nider5556a852011-10-16 10:52:13 +02002213
Joel Nider435ad8e2011-12-14 16:53:30 +02002214 if (channel_id >= TSPP_NUM_CHANNELS) {
2215 pr_err("tspp: channel id out of range");
2216 return NULL;
2217 }
2218 pdev = tspp_find_by_id(dev);
2219 if (!pdev) {
2220 pr_err("tspp_get: can't find device %i", dev);
2221 return NULL;
2222 }
2223 channel = &pdev->channels[channel_id];
Joel Nider5556a852011-10-16 10:52:13 +02002224
Joel Nider435ad8e2011-12-14 16:53:30 +02002225 if (!channel->read) {
2226 pr_warn("tspp: no buffer to get on channel %i!",
2227 channel->id);
2228 return NULL;
2229 }
2230
2231 buffer = channel->read;
2232 /* see if we have any buffers ready to read */
2233 if (buffer->state != TSPP_BUF_STATE_DATA)
2234 return 0;
2235
2236 if (buffer->state == TSPP_BUF_STATE_DATA) {
2237 /* mark the buffer as busy */
2238 buffer->state = TSPP_BUF_STATE_LOCKED;
2239
2240 /* increment the pointer along the list */
2241 channel->read = channel->read->next;
2242 }
2243
2244 return &buffer->desc;
2245}
2246EXPORT_SYMBOL(tspp_get_buffer);
2247
Liron Kuch72b78552012-10-30 17:47:50 +02002248/**
2249 * tspp_release_buffer - release TSPP data buffer back to TSPP.
2250 *
2251 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2252 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2253 * @descriptor_id: buffer descriptor ID
2254 *
2255 * Return error status
2256 *
2257 */
Joel Nider435ad8e2011-12-14 16:53:30 +02002258int tspp_release_buffer(u32 dev, u32 channel_id, u32 descriptor_id)
2259{
2260 int i, found = 0;
2261 struct tspp_mem_buffer *buffer;
2262 struct tspp_channel *channel;
2263 struct tspp_device *pdev;
2264
2265 if (channel_id >= TSPP_NUM_CHANNELS) {
2266 pr_err("tspp: channel id out of range");
2267 return -ECHRNG;
2268 }
2269 pdev = tspp_find_by_id(dev);
2270 if (!pdev) {
2271 pr_err("tspp: can't find device %i", dev);
2272 return -ENODEV;
2273 }
2274 channel = &pdev->channels[channel_id];
2275
2276 if (descriptor_id > channel->buffer_count)
2277 pr_warn("tspp: desc id looks weird 0x%08x", descriptor_id);
2278
2279 /* find the correct descriptor */
2280 buffer = channel->locked;
2281 for (i = 0; i < channel->buffer_count; i++) {
2282 if (buffer->desc.id == descriptor_id) {
2283 found = 1;
2284 break;
2285 }
2286 buffer = buffer->next;
2287 }
2288 channel->locked = channel->locked->next;
2289
2290 if (!found) {
2291 pr_err("tspp: cant find desc %i", descriptor_id);
2292 return -EINVAL;
2293 }
2294
2295 /* make sure the buffer is in the expected state */
2296 if (buffer->state != TSPP_BUF_STATE_LOCKED) {
2297 pr_err("tspp: buffer %i not locked", descriptor_id);
2298 return -EINVAL;
2299 }
2300 /* unlock the buffer and requeue it */
2301 buffer->state = TSPP_BUF_STATE_WAITING;
2302
2303 if (tspp_queue_buffer(channel, buffer))
2304 pr_warn("tspp: can't requeue buffer");
Joel Nider5556a852011-10-16 10:52:13 +02002305 return 0;
2306}
Joel Nider435ad8e2011-12-14 16:53:30 +02002307EXPORT_SYMBOL(tspp_release_buffer);
2308
Liron Kuch72b78552012-10-30 17:47:50 +02002309/**
2310 * tspp_allocate_buffers - allocate TSPP data buffers.
2311 *
2312 * @dev: TSPP device (up to TSPP_MAX_DEVICES)
2313 * @channel_id: Channel ID number (up to TSPP_NUM_CHANNELS)
2314 * @count: number of buffers to allocate
2315 * @size: size of each buffer to allocate
2316 * @int_freq: interrupt frequency
2317 * @alloc: user defined memory allocator function. Pass NULL for default.
2318 * @memfree: user defined memory free function. Pass NULL for default.
2319 * @user: user data to pass to the memory allocator/free function
2320 *
2321 * Return error status
2322 *
2323 * The user can optionally call this function explicitly to allocate the TSPP
2324 * data buffers. Alternatively, if the user did not call this function, it
2325 * is called implicitly by tspp_add_filter().
2326 */
2327int tspp_allocate_buffers(u32 dev, u32 channel_id, u32 count, u32 size,
2328 u32 int_freq, tspp_allocator *alloc,
2329 tspp_memfree *memfree, void *user)
Joel Nider435ad8e2011-12-14 16:53:30 +02002330{
2331 struct tspp_channel *channel;
2332 struct tspp_device *pdev;
2333 struct tspp_mem_buffer *last = NULL;
2334
2335 TSPP_DEBUG("tspp_allocate_buffers");
2336
2337 if (channel_id >= TSPP_NUM_CHANNELS) {
Liron Kuch72b78552012-10-30 17:47:50 +02002338 pr_err("%s: channel id out of range", __func__);
Joel Nider435ad8e2011-12-14 16:53:30 +02002339 return -ECHRNG;
2340 }
Liron Kuch72b78552012-10-30 17:47:50 +02002341
Joel Nider435ad8e2011-12-14 16:53:30 +02002342 pdev = tspp_find_by_id(dev);
2343 if (!pdev) {
Liron Kuch72b78552012-10-30 17:47:50 +02002344 pr_err("%s: can't find device %i", __func__, dev);
Joel Nider435ad8e2011-12-14 16:53:30 +02002345 return -ENODEV;
2346 }
Liron Kuch72b78552012-10-30 17:47:50 +02002347
2348 if (count < MIN_ACCEPTABLE_BUFFER_COUNT) {
2349 pr_err("%s: tspp requires a minimum of %i buffers\n",
2350 __func__, MIN_ACCEPTABLE_BUFFER_COUNT);
2351 return -EINVAL;
2352 }
2353
Hamad Kadmany24020352013-05-22 12:54:18 +03002354 if (count > TSPP_NUM_BUFFERS) {
2355 pr_err("%s: tspp requires a maximum of %i buffers\n",
2356 __func__, TSPP_NUM_BUFFERS);
2357 return -EINVAL;
2358 }
2359
Joel Nider435ad8e2011-12-14 16:53:30 +02002360 channel = &pdev->channels[channel_id];
Hamad Kadmany090709b2013-01-06 12:08:13 +02002361
Liron Kuch72b78552012-10-30 17:47:50 +02002362 /* allow buffer allocation only if there was no previous buffer
2363 * allocation for this channel.
2364 */
2365 if (channel->buffer_count > 0) {
2366 pr_err("%s: buffers already allocated for channel %u",
2367 __func__, channel_id);
2368 return -EINVAL;
2369 }
Joel Nider435ad8e2011-12-14 16:53:30 +02002370
2371 channel->max_buffers = count;
2372
2373 /* set up interrupt frequency */
Liron Kuch72b78552012-10-30 17:47:50 +02002374 if (int_freq > channel->max_buffers) {
Joel Nider435ad8e2011-12-14 16:53:30 +02002375 int_freq = channel->max_buffers;
Liron Kuch72b78552012-10-30 17:47:50 +02002376 pr_warn("%s: setting interrupt frequency to %u\n",
2377 __func__, int_freq);
Joel Nider435ad8e2011-12-14 16:53:30 +02002378 }
Liron Kuch72b78552012-10-30 17:47:50 +02002379 channel->int_freq = int_freq;
2380 /*
2381 * it is the responsibility of the caller to tspp_allocate_buffers(),
2382 * whether it's the user or the driver, to make sure the size parameter
2383 * is compatible to the channel mode.
2384 */
2385 channel->buffer_size = size;
Joel Nider435ad8e2011-12-14 16:53:30 +02002386
Liron Kuch72b78552012-10-30 17:47:50 +02002387 /* save user defined memory free function for later use */
2388 channel->memfree = memfree;
2389 channel->user_info = user;
2390
Hamad Kadmany090709b2013-01-06 12:08:13 +02002391 /*
2392 * For small buffers, create a DMA pool so that memory
2393 * is not wasted through dma_alloc_coherent.
2394 */
2395 if (TSPP_USE_DMA_POOL(channel->buffer_size)) {
2396 channel->dma_pool = dma_pool_create("tspp",
2397 NULL, channel->buffer_size, 0, 0);
2398 if (!channel->dma_pool) {
2399 pr_err("%s: Can't allocate memory pool\n", __func__);
2400 return -ENOMEM;
2401 }
2402 } else {
2403 channel->dma_pool = NULL;
2404 }
2405
2406
Liron Kuch72b78552012-10-30 17:47:50 +02002407 for (channel->buffer_count = 0;
2408 channel->buffer_count < channel->max_buffers;
Joel Nider435ad8e2011-12-14 16:53:30 +02002409 channel->buffer_count++) {
2410
2411 /* allocate the descriptor */
2412 struct tspp_mem_buffer *desc = (struct tspp_mem_buffer *)
2413 kmalloc(sizeof(struct tspp_mem_buffer), GFP_KERNEL);
2414 if (!desc) {
Liron Kuch72b78552012-10-30 17:47:50 +02002415 pr_warn("%s: Can't allocate desc %i",
2416 __func__, channel->buffer_count);
Joel Nider435ad8e2011-12-14 16:53:30 +02002417 break;
2418 }
2419
2420 desc->desc.id = channel->buffer_count;
2421 /* allocate the buffer */
2422 if (tspp_alloc_buffer(channel_id, &desc->desc,
Hamad Kadmany090709b2013-01-06 12:08:13 +02002423 channel->buffer_size, channel->dma_pool,
2424 alloc, user) != 0) {
Joel Nider435ad8e2011-12-14 16:53:30 +02002425 kfree(desc);
Liron Kuch72b78552012-10-30 17:47:50 +02002426 pr_warn("%s: Can't allocate buffer %i",
2427 __func__, channel->buffer_count);
Joel Nider435ad8e2011-12-14 16:53:30 +02002428 break;
2429 }
2430
2431 /* add the descriptor to the list */
2432 desc->filled = 0;
2433 desc->read_index = 0;
2434 if (!channel->data) {
2435 channel->data = desc;
2436 desc->next = channel->data;
2437 } else {
2438 last->next = desc;
2439 }
2440 last = desc;
2441 desc->next = channel->data;
2442
2443 /* prepare the sps descriptor */
2444 desc->sps.phys_base = desc->desc.phys_base;
2445 desc->sps.base = desc->desc.virt_base;
2446 desc->sps.size = desc->desc.size;
2447
2448 /* start the transfer */
2449 if (tspp_queue_buffer(channel, desc))
Liron Kuch72b78552012-10-30 17:47:50 +02002450 pr_err("%s: can't queue buffer %i",
2451 __func__, desc->desc.id);
2452 }
2453
2454 if (channel->buffer_count < channel->max_buffers) {
2455 /*
2456 * we failed to allocate the requested number of buffers.
2457 * we don't allow a partial success, so need to clean up here.
2458 */
2459 tspp_destroy_buffers(channel_id, channel);
2460 channel->buffer_count = 0;
Hamad Kadmany090709b2013-01-06 12:08:13 +02002461
2462 if (channel->dma_pool) {
2463 dma_pool_destroy(channel->dma_pool);
2464 channel->dma_pool = NULL;
2465 }
Liron Kuch72b78552012-10-30 17:47:50 +02002466 return -ENOMEM;
Joel Nider435ad8e2011-12-14 16:53:30 +02002467 }
2468
2469 channel->waiting = channel->data;
2470 channel->read = channel->data;
2471 channel->locked = channel->data;
Liron Kuch72b78552012-10-30 17:47:50 +02002472
Hamad Kadmany81cee052012-11-29 14:15:57 +02002473 /* Now that buffers are scheduled to HW, kick data expiration timer */
2474 if (channel->expiration_period_ms)
2475 mod_timer(&channel->expiration_timer,
2476 jiffies +
2477 MSEC_TO_JIFFIES(
2478 channel->expiration_period_ms));
2479
Joel Nider435ad8e2011-12-14 16:53:30 +02002480 return 0;
2481}
2482EXPORT_SYMBOL(tspp_allocate_buffers);
Joel Nider5556a852011-10-16 10:52:13 +02002483
2484/*** File Operations ***/
2485static ssize_t tspp_open(struct inode *inode, struct file *filp)
2486{
Joel Nider435ad8e2011-12-14 16:53:30 +02002487 u32 dev;
Joel Nider5556a852011-10-16 10:52:13 +02002488 struct tspp_channel *channel;
Joel Nider435ad8e2011-12-14 16:53:30 +02002489
2490 TSPP_DEBUG("tspp_open");
Joel Nider5556a852011-10-16 10:52:13 +02002491 channel = container_of(inode->i_cdev, struct tspp_channel, cdev);
2492 filp->private_data = channel;
Joel Nider435ad8e2011-12-14 16:53:30 +02002493 dev = channel->pdev->pdev->id;
Joel Nider5556a852011-10-16 10:52:13 +02002494
2495 /* if this channel is already in use, quit */
2496 if (channel->used) {
2497 pr_err("tspp channel %i already in use",
2498 MINOR(channel->cdev.dev));
2499 return -EACCES;
2500 }
2501
Joel Nider435ad8e2011-12-14 16:53:30 +02002502 if (tspp_open_channel(dev, channel->id) != 0) {
Joel Nider5556a852011-10-16 10:52:13 +02002503 pr_err("tspp: error opening channel");
2504 return -EACCES;
2505 }
2506
2507 return 0;
2508}
2509
2510static unsigned int tspp_poll(struct file *filp, struct poll_table_struct *p)
2511{
2512 unsigned long flags;
2513 unsigned int mask = 0;
2514 struct tspp_channel *channel;
2515 channel = filp->private_data;
2516
2517 /* register the wait queue for this channel */
2518 poll_wait(filp, &channel->in_queue, p);
2519
2520 spin_lock_irqsave(&channel->pdev->spinlock, flags);
Joel Nider435ad8e2011-12-14 16:53:30 +02002521 if (channel->read &&
2522 channel->read->state == TSPP_BUF_STATE_DATA)
Joel Nider5556a852011-10-16 10:52:13 +02002523 mask = POLLIN | POLLRDNORM;
2524
2525 spin_unlock_irqrestore(&channel->pdev->spinlock, flags);
2526
2527 return mask;
2528}
2529
2530static ssize_t tspp_release(struct inode *inode, struct file *filp)
2531{
Joel Nider435ad8e2011-12-14 16:53:30 +02002532 struct tspp_channel *channel = filp->private_data;
2533 u32 dev = channel->pdev->pdev->id;
2534 TSPP_DEBUG("tspp_release");
Joel Nider5556a852011-10-16 10:52:13 +02002535
Joel Nider435ad8e2011-12-14 16:53:30 +02002536 tspp_close_channel(dev, channel->id);
Joel Nider5556a852011-10-16 10:52:13 +02002537
2538 return 0;
2539}
2540
2541static ssize_t tspp_read(struct file *filp, char __user *buf, size_t count,
2542 loff_t *f_pos)
2543{
2544 size_t size = 0;
2545 size_t transferred = 0;
2546 struct tspp_channel *channel;
2547 struct tspp_mem_buffer *buffer;
2548 channel = filp->private_data;
2549
2550 TSPP_DEBUG("tspp_read");
Joel Nider435ad8e2011-12-14 16:53:30 +02002551
2552 while (!channel->read) {
2553 if (filp->f_flags & O_NONBLOCK) {
2554 pr_warn("tspp: no buffer on channel %i!",
2555 channel->id);
2556 return -EAGAIN;
2557 }
2558 /* go to sleep if there is nothing to read */
2559 if (wait_event_interruptible(channel->in_queue,
2560 (channel->read != NULL))) {
2561 pr_err("tspp: rude awakening\n");
2562 return -ERESTARTSYS;
2563 }
2564 }
2565
2566 buffer = channel->read;
2567
Joel Nider5556a852011-10-16 10:52:13 +02002568 /* see if we have any buffers ready to read */
2569 while (buffer->state != TSPP_BUF_STATE_DATA) {
2570 if (filp->f_flags & O_NONBLOCK) {
2571 pr_warn("tspp: nothing to read on channel %i!",
2572 channel->id);
2573 return -EAGAIN;
2574 }
2575 /* go to sleep if there is nothing to read */
Joel Nider5556a852011-10-16 10:52:13 +02002576 if (wait_event_interruptible(channel->in_queue,
2577 (buffer->state == TSPP_BUF_STATE_DATA))) {
2578 pr_err("tspp: rude awakening\n");
2579 return -ERESTARTSYS;
2580 }
2581 }
2582
2583 while (buffer->state == TSPP_BUF_STATE_DATA) {
2584 size = min(count, buffer->filled);
Joel Nider5556a852011-10-16 10:52:13 +02002585 if (size == 0)
2586 break;
2587
Joel Nider435ad8e2011-12-14 16:53:30 +02002588 if (copy_to_user(buf, buffer->desc.virt_base +
Joel Nider5556a852011-10-16 10:52:13 +02002589 buffer->read_index, size)) {
2590 pr_err("tspp: error copying to user buffer");
Joel Nider435ad8e2011-12-14 16:53:30 +02002591 return -EBUSY;
Joel Nider5556a852011-10-16 10:52:13 +02002592 }
2593 buf += size;
2594 count -= size;
2595 transferred += size;
2596 buffer->read_index += size;
2597
Liron Kuch72b78552012-10-30 17:47:50 +02002598 /*
2599 * after reading the end of the buffer, requeue it,
2600 * and set up for reading the next one
2601 */
Joel Nider435ad8e2011-12-14 16:53:30 +02002602 if (buffer->read_index == buffer->filled) {
Joel Nider5556a852011-10-16 10:52:13 +02002603 buffer->state = TSPP_BUF_STATE_WAITING;
Hamad Kadmany090709b2013-01-06 12:08:13 +02002604
Joel Nider435ad8e2011-12-14 16:53:30 +02002605 if (tspp_queue_buffer(channel, buffer))
2606 pr_err("tspp: can't submit transfer");
Hamad Kadmany090709b2013-01-06 12:08:13 +02002607
Joel Nider435ad8e2011-12-14 16:53:30 +02002608 channel->locked = channel->read;
2609 channel->read = channel->read->next;
Joel Nider5556a852011-10-16 10:52:13 +02002610 }
2611 }
2612
2613 return transferred;
2614}
2615
2616static long tspp_ioctl(struct file *filp,
2617 unsigned int param0, unsigned long param1)
2618{
Joel Nider435ad8e2011-12-14 16:53:30 +02002619 u32 dev;
Joel Nider5556a852011-10-16 10:52:13 +02002620 int rc = -1;
2621 struct tspp_channel *channel;
Joel Nider435ad8e2011-12-14 16:53:30 +02002622 struct tspp_select_source ss;
2623 struct tspp_filter f;
2624 struct tspp_key k;
2625 struct tspp_iv iv;
2626 struct tspp_system_keys sk;
2627 struct tspp_buffer b;
Joel Nider5556a852011-10-16 10:52:13 +02002628 channel = filp->private_data;
Joel Nider435ad8e2011-12-14 16:53:30 +02002629 dev = channel->pdev->pdev->id;
Joel Nider5556a852011-10-16 10:52:13 +02002630
Liron Kucha7b49ae2013-02-14 16:26:38 +02002631 if ((param0 != TSPP_IOCTL_CLOSE_STREAM) && !param1)
Joel Nider5556a852011-10-16 10:52:13 +02002632 return -EINVAL;
2633
2634 switch (param0) {
2635 case TSPP_IOCTL_SELECT_SOURCE:
Joel Nider435ad8e2011-12-14 16:53:30 +02002636 if (!access_ok(VERIFY_READ, param1,
2637 sizeof(struct tspp_select_source))) {
2638 return -EBUSY;
2639 }
2640 if (__copy_from_user(&ss, (void *)param1,
2641 sizeof(struct tspp_select_source)) == 0)
2642 rc = tspp_select_source(dev, channel->id, &ss);
Joel Nider5556a852011-10-16 10:52:13 +02002643 break;
2644 case TSPP_IOCTL_ADD_FILTER:
Joel Nider435ad8e2011-12-14 16:53:30 +02002645 if (!access_ok(VERIFY_READ, param1,
2646 sizeof(struct tspp_filter))) {
2647 return -ENOSR;
2648 }
2649 if (__copy_from_user(&f, (void *)param1,
2650 sizeof(struct tspp_filter)) == 0)
2651 rc = tspp_add_filter(dev, channel->id, &f);
Joel Nider5556a852011-10-16 10:52:13 +02002652 break;
2653 case TSPP_IOCTL_REMOVE_FILTER:
Joel Nider435ad8e2011-12-14 16:53:30 +02002654 if (!access_ok(VERIFY_READ, param1,
2655 sizeof(struct tspp_filter))) {
2656 return -EBUSY;
2657 }
2658 if (__copy_from_user(&f, (void *)param1,
2659 sizeof(struct tspp_filter)) == 0)
2660 rc = tspp_remove_filter(dev, channel->id, &f);
Joel Nider5556a852011-10-16 10:52:13 +02002661 break;
2662 case TSPP_IOCTL_SET_KEY:
Joel Nider435ad8e2011-12-14 16:53:30 +02002663 if (!access_ok(VERIFY_READ, param1,
2664 sizeof(struct tspp_key))) {
2665 return -EBUSY;
2666 }
2667 if (__copy_from_user(&k, (void *)param1,
2668 sizeof(struct tspp_key)) == 0)
2669 rc = tspp_set_key(dev, channel->id, &k);
Joel Nider5556a852011-10-16 10:52:13 +02002670 break;
2671 case TSPP_IOCTL_SET_IV:
Joel Nider435ad8e2011-12-14 16:53:30 +02002672 if (!access_ok(VERIFY_READ, param1,
2673 sizeof(struct tspp_iv))) {
2674 return -EBUSY;
2675 }
2676 if (__copy_from_user(&iv, (void *)param1,
2677 sizeof(struct tspp_iv)) == 0)
2678 rc = tspp_set_iv(channel, &iv);
Joel Nider5556a852011-10-16 10:52:13 +02002679 break;
2680 case TSPP_IOCTL_SET_SYSTEM_KEYS:
Joel Nider435ad8e2011-12-14 16:53:30 +02002681 if (!access_ok(VERIFY_READ, param1,
2682 sizeof(struct tspp_system_keys))) {
2683 return -EINVAL;
2684 }
2685 if (__copy_from_user(&sk, (void *)param1,
2686 sizeof(struct tspp_system_keys)) == 0)
2687 rc = tspp_set_system_keys(channel, &sk);
Joel Nider5556a852011-10-16 10:52:13 +02002688 break;
2689 case TSPP_IOCTL_BUFFER_SIZE:
Joel Nider435ad8e2011-12-14 16:53:30 +02002690 if (!access_ok(VERIFY_READ, param1,
2691 sizeof(struct tspp_buffer))) {
2692 rc = -EINVAL;
2693 }
2694 if (__copy_from_user(&b, (void *)param1,
2695 sizeof(struct tspp_buffer)) == 0)
2696 rc = tspp_set_buffer_size(channel, &b);
Joel Nider5556a852011-10-16 10:52:13 +02002697 break;
Liron Kucha7b49ae2013-02-14 16:26:38 +02002698 case TSPP_IOCTL_CLOSE_STREAM:
2699 rc = tspp_close_stream(dev, channel->id);
2700 break;
Joel Nider5556a852011-10-16 10:52:13 +02002701 default:
2702 pr_err("tspp: Unknown ioctl %i", param0);
2703 }
2704
Liron Kuch72b78552012-10-30 17:47:50 +02002705 /*
2706 * normalize the return code in case one of the subfunctions does
2707 * something weird
2708 */
Joel Nider5556a852011-10-16 10:52:13 +02002709 if (rc != 0)
Joel Nider435ad8e2011-12-14 16:53:30 +02002710 rc = -ENOIOCTLCMD;
Joel Nider5556a852011-10-16 10:52:13 +02002711
2712 return rc;
2713}
2714
2715/*** debugfs ***/
Joel Nider5556a852011-10-16 10:52:13 +02002716static int debugfs_iomem_x32_set(void *data, u64 val)
2717{
2718 writel_relaxed(val, data);
2719 wmb();
2720 return 0;
2721}
2722
2723static int debugfs_iomem_x32_get(void *data, u64 *val)
2724{
2725 *val = readl_relaxed(data);
2726 return 0;
2727}
2728
2729DEFINE_SIMPLE_ATTRIBUTE(fops_iomem_x32, debugfs_iomem_x32_get,
2730 debugfs_iomem_x32_set, "0x%08llx");
2731
2732static void tsif_debugfs_init(struct tspp_tsif_device *tsif_device,
2733 int instance)
2734{
2735 char name[10];
2736 snprintf(name, 10, "tsif%i", instance);
2737 tsif_device->dent_tsif = debugfs_create_dir(
2738 name, NULL);
2739 if (tsif_device->dent_tsif) {
2740 int i;
2741 void __iomem *base = tsif_device->base;
2742 for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++) {
2743 tsif_device->debugfs_tsif_regs[i] =
2744 debugfs_create_file(
2745 debugfs_tsif_regs[i].name,
2746 debugfs_tsif_regs[i].mode,
2747 tsif_device->dent_tsif,
2748 base + debugfs_tsif_regs[i].offset,
2749 &fops_iomem_x32);
2750 }
Hamad Kadmany44307d32012-11-25 09:49:51 +02002751
2752 debugfs_create_u32(
2753 "stat_rx_chunks",
Hamad Kadmanya1dde822013-03-28 08:23:26 +02002754 S_IRUGO | S_IWUSR | S_IWGRP,
Hamad Kadmany44307d32012-11-25 09:49:51 +02002755 tsif_device->dent_tsif,
2756 &tsif_device->stat_rx);
2757
2758 debugfs_create_u32(
2759 "stat_overflow",
Hamad Kadmanya1dde822013-03-28 08:23:26 +02002760 S_IRUGO | S_IWUSR | S_IWGRP,
Hamad Kadmany44307d32012-11-25 09:49:51 +02002761 tsif_device->dent_tsif,
2762 &tsif_device->stat_overflow);
2763
2764 debugfs_create_u32(
2765 "stat_lost_sync",
Hamad Kadmanya1dde822013-03-28 08:23:26 +02002766 S_IRUGO | S_IWUSR | S_IWGRP,
Hamad Kadmany44307d32012-11-25 09:49:51 +02002767 tsif_device->dent_tsif,
2768 &tsif_device->stat_lost_sync);
2769
2770 debugfs_create_u32(
2771 "stat_timeout",
Hamad Kadmanya1dde822013-03-28 08:23:26 +02002772 S_IRUGO | S_IWUSR | S_IWGRP,
Hamad Kadmany44307d32012-11-25 09:49:51 +02002773 tsif_device->dent_tsif,
2774 &tsif_device->stat_timeout);
Joel Nider5556a852011-10-16 10:52:13 +02002775 }
2776}
2777
2778static void tsif_debugfs_exit(struct tspp_tsif_device *tsif_device)
2779{
2780 if (tsif_device->dent_tsif) {
2781 int i;
2782 debugfs_remove_recursive(tsif_device->dent_tsif);
2783 tsif_device->dent_tsif = NULL;
2784 for (i = 0; i < ARRAY_SIZE(debugfs_tsif_regs); i++)
2785 tsif_device->debugfs_tsif_regs[i] = NULL;
2786 }
2787}
2788
2789static void tspp_debugfs_init(struct tspp_device *device, int instance)
2790{
2791 char name[10];
2792 snprintf(name, 10, "tspp%i", instance);
2793 device->dent = debugfs_create_dir(
2794 name, NULL);
2795 if (device->dent) {
2796 int i;
2797 void __iomem *base = device->base;
2798 for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++) {
2799 device->debugfs_regs[i] =
2800 debugfs_create_file(
2801 debugfs_tspp_regs[i].name,
2802 debugfs_tspp_regs[i].mode,
2803 device->dent,
2804 base + debugfs_tspp_regs[i].offset,
2805 &fops_iomem_x32);
2806 }
2807 }
2808}
2809
2810static void tspp_debugfs_exit(struct tspp_device *device)
2811{
2812 if (device->dent) {
2813 int i;
2814 debugfs_remove_recursive(device->dent);
2815 device->dent = NULL;
2816 for (i = 0; i < ARRAY_SIZE(debugfs_tspp_regs); i++)
2817 device->debugfs_regs[i] = NULL;
2818 }
2819}
Joel Nider5556a852011-10-16 10:52:13 +02002820
Liron Kuch59339922013-01-01 18:29:47 +02002821/* copy device-tree data to platfrom data struct */
2822static __devinit struct msm_tspp_platform_data *
2823msm_tspp_dt_to_pdata(struct platform_device *pdev)
2824{
2825 struct device_node *node = pdev->dev.of_node;
2826 struct msm_tspp_platform_data *data;
2827 struct msm_gpio *gpios;
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -07002828 struct property *prop;
Liron Kuch59339922013-01-01 18:29:47 +02002829 int i, rc;
2830 int gpio;
2831 u32 gpio_func;
2832
2833 /* Note: memory allocated by devm_kzalloc is freed automatically */
2834 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
2835 if (!data) {
2836 pr_err("tspp: Unable to allocate platform data\n");
2837 return NULL;
2838 }
2839 rc = of_property_read_string(node, "qcom,tsif-pclk", &data->tsif_pclk);
2840 if (rc) {
2841 pr_err("tspp: Could not find tsif-pclk property, err = %d\n",
2842 rc);
2843 return NULL;
2844 }
2845 rc = of_property_read_string(node, "qcom,tsif-ref-clk",
2846 &data->tsif_ref_clk);
2847 if (rc) {
2848 pr_err("tspp: Could not find tsif-ref-clk property, err = %d\n",
2849 rc);
2850 return NULL;
2851 }
2852
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -07002853 data->tsif_vreg_present = 0;
2854 prop = of_find_property(node, "vdd_cx-supply", NULL);
2855 if (prop)
2856 data->tsif_vreg_present = 1;
2857
Liron Kuch59339922013-01-01 18:29:47 +02002858 data->num_gpios = of_gpio_count(node);
2859 if (data->num_gpios == 0) {
2860 pr_err("tspp: Could not find GPIO definitions\n");
2861 return NULL;
2862 }
2863 gpios = devm_kzalloc(&pdev->dev,
2864 (data->num_gpios * sizeof(struct msm_gpio)),
2865 GFP_KERNEL);
2866 if (!gpios) {
2867 pr_err("tspp: Unable to allocate memory for GPIOs table\n");
2868 return NULL;
2869 }
2870 /* Assuming GPIO FUNC property is the same for all GPIOs */
2871 if (of_property_read_u32(node, "qcom,gpios-func", &gpio_func)) {
2872 pr_err("tspp: Could not find gpios-func property\n");
2873 return NULL;
2874 }
2875 for (i = 0; i < data->num_gpios; i++) {
2876 gpio = of_get_gpio(node, i);
2877 gpios[i].gpio_cfg = GPIO_CFG(gpio, gpio_func,
2878 GPIO_CFG_INPUT,
2879 GPIO_CFG_PULL_DOWN,
2880 GPIO_CFG_2MA);
2881 rc = of_property_read_string_index(node, "qcom,gpio-names",
2882 i, &gpios[i].label);
2883 if (rc)
2884 pr_warn("tspp: Could not find gpio-names property\n");
2885 }
2886
2887 data->gpios = gpios;
2888
2889 return data;
2890}
2891
2892static int msm_tspp_map_irqs(struct platform_device *pdev,
2893 struct tspp_device *device)
2894{
2895 int rc;
Liron Kuch59339922013-01-01 18:29:47 +02002896
2897 /* get IRQ numbers from platform information */
2898
2899 /* map TSPP IRQ */
2900 rc = platform_get_irq_byname(pdev, "TSIF_TSPP_IRQ");
2901 if (rc > 0) {
2902 device->tspp_irq = rc;
Liron Kuch59339922013-01-01 18:29:47 +02002903 } else {
2904 dev_err(&pdev->dev, "failed to get TSPP IRQ");
2905 return -EINVAL;
2906 }
2907
2908 /* map TSIF IRQs */
2909 rc = platform_get_irq_byname(pdev, "TSIF0_IRQ");
2910 if (rc > 0) {
2911 device->tsif[0].tsif_irq = rc;
2912 } else {
2913 dev_err(&pdev->dev, "failed to get TSIF0 IRQ");
2914 return -EINVAL;
2915 }
2916
2917 rc = platform_get_irq_byname(pdev, "TSIF1_IRQ");
2918 if (rc > 0) {
2919 device->tsif[1].tsif_irq = rc;
2920 } else {
2921 dev_err(&pdev->dev, "failed to get TSIF1 IRQ");
2922 return -EINVAL;
2923 }
2924
Liron Kuch59339922013-01-01 18:29:47 +02002925 /* map BAM IRQ */
2926 rc = platform_get_irq_byname(pdev, "TSIF_BAM_IRQ");
2927 if (rc > 0) {
2928 device->bam_irq = rc;
2929 } else {
2930 dev_err(&pdev->dev, "failed to get TSPP BAM IRQ");
2931 return -EINVAL;
2932 }
2933
2934 return 0;
2935}
2936
Joel Nider5556a852011-10-16 10:52:13 +02002937static int __devinit msm_tspp_probe(struct platform_device *pdev)
2938{
2939 int rc = -ENODEV;
2940 u32 version;
Liron Kuch72b78552012-10-30 17:47:50 +02002941 u32 i, j;
Joel Nider5556a852011-10-16 10:52:13 +02002942 struct msm_tspp_platform_data *data;
2943 struct tspp_device *device;
2944 struct resource *mem_tsif0;
2945 struct resource *mem_tsif1;
2946 struct resource *mem_tspp;
2947 struct resource *mem_bam;
Liron Kuch72b78552012-10-30 17:47:50 +02002948 struct tspp_channel *channel;
Hamad Kadmanyef5ce992013-06-03 09:30:50 +03002949 struct msm_bus_scale_pdata *tspp_bus_pdata = NULL;
Joel Nider5556a852011-10-16 10:52:13 +02002950
Liron Kuch59339922013-01-01 18:29:47 +02002951 if (pdev->dev.of_node) {
2952 /* get information from device tree */
2953 data = msm_tspp_dt_to_pdata(pdev);
2954 /* get device ID */
2955 rc = of_property_read_u32(pdev->dev.of_node,
2956 "cell-index", &pdev->id);
2957 if (rc)
2958 pdev->id = -1;
2959
2960 pdev->dev.platform_data = data;
Hamad Kadmanyef5ce992013-06-03 09:30:50 +03002961
2962 tspp_bus_pdata = msm_bus_cl_get_pdata(pdev);
Liron Kuch59339922013-01-01 18:29:47 +02002963 } else {
2964 /* must have platform data */
2965 data = pdev->dev.platform_data;
Hamad Kadmanyef5ce992013-06-03 09:30:50 +03002966 tspp_bus_pdata = NULL;
Liron Kuch59339922013-01-01 18:29:47 +02002967 }
Joel Nider5556a852011-10-16 10:52:13 +02002968 if (!data) {
2969 pr_err("tspp: Platform data not available");
2970 rc = -EINVAL;
2971 goto out;
2972 }
2973
2974 /* check for valid device id */
Joel Nider435ad8e2011-12-14 16:53:30 +02002975 if ((pdev->id < 0) || (pdev->id >= TSPP_MAX_DEVICES)) {
Joel Nider5556a852011-10-16 10:52:13 +02002976 pr_err("tspp: Invalid device ID %d", pdev->id);
2977 rc = -EINVAL;
2978 goto out;
2979 }
2980
2981 /* OK, we will use this device */
2982 device = kzalloc(sizeof(struct tspp_device), GFP_KERNEL);
2983 if (!device) {
2984 pr_err("tspp: Failed to allocate memory for device");
2985 rc = -ENOMEM;
2986 goto out;
2987 }
2988
2989 /* set up references */
2990 device->pdev = pdev;
2991 platform_set_drvdata(pdev, device);
2992
Hamad Kadmanyef5ce992013-06-03 09:30:50 +03002993 /* register bus client */
2994 if (tspp_bus_pdata) {
2995 device->tsif_bus_client =
2996 msm_bus_scale_register_client(tspp_bus_pdata);
2997 if (!device->tsif_bus_client)
2998 pr_err("tspp: Unable to register bus client\n");
2999 } else {
3000 device->tsif_bus_client = 0;
3001 }
3002
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -07003003 /* map regulators */
3004 if (data->tsif_vreg_present) {
3005 device->tsif_vreg = devm_regulator_get(&pdev->dev, "vdd_cx");
3006 if (IS_ERR(device->tsif_vreg)) {
3007 rc = PTR_ERR(device->tsif_vreg);
3008 device->tsif_vreg = NULL;
3009 goto err_regultaor;
3010 }
3011
3012 /* Set an initial voltage and enable the regulator */
3013 rc = regulator_set_voltage(device->tsif_vreg,
Hamad Kadmanyfde29382013-06-26 08:03:51 +03003014 RPM_REGULATOR_CORNER_NONE,
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -07003015 RPM_REGULATOR_CORNER_SUPER_TURBO);
3016 if (rc) {
3017 dev_err(&pdev->dev, "Unable to set CX voltage.\n");
3018 goto err_regultaor;
3019 }
3020
3021 rc = regulator_enable(device->tsif_vreg);
3022 if (rc) {
3023 dev_err(&pdev->dev, "Unable to enable CX regulator.\n");
3024 goto err_regultaor;
3025 }
3026 }
3027
Joel Nider5556a852011-10-16 10:52:13 +02003028 /* map clocks */
3029 if (data->tsif_pclk) {
Joel Niderb9662ca2012-06-10 14:21:11 +03003030 device->tsif_pclk = clk_get(&pdev->dev, data->tsif_pclk);
Joel Nider5556a852011-10-16 10:52:13 +02003031 if (IS_ERR(device->tsif_pclk)) {
Joel Nider5556a852011-10-16 10:52:13 +02003032 rc = PTR_ERR(device->tsif_pclk);
3033 device->tsif_pclk = NULL;
3034 goto err_pclock;
3035 }
3036 }
3037 if (data->tsif_ref_clk) {
Joel Niderb9662ca2012-06-10 14:21:11 +03003038 device->tsif_ref_clk = clk_get(&pdev->dev, data->tsif_ref_clk);
Joel Nider5556a852011-10-16 10:52:13 +02003039 if (IS_ERR(device->tsif_ref_clk)) {
Joel Nider5556a852011-10-16 10:52:13 +02003040 rc = PTR_ERR(device->tsif_ref_clk);
3041 device->tsif_ref_clk = NULL;
3042 goto err_refclock;
3043 }
3044 }
3045
3046 /* map I/O memory */
Liron Kuch59339922013-01-01 18:29:47 +02003047 mem_tsif0 = platform_get_resource_byname(pdev,
3048 IORESOURCE_MEM, "MSM_TSIF0_PHYS");
Joel Nider5556a852011-10-16 10:52:13 +02003049 if (!mem_tsif0) {
3050 pr_err("tspp: Missing tsif0 MEM resource");
3051 rc = -ENXIO;
3052 goto err_res_tsif0;
3053 }
3054 device->tsif[0].base = ioremap(mem_tsif0->start,
3055 resource_size(mem_tsif0));
3056 if (!device->tsif[0].base) {
3057 pr_err("tspp: ioremap failed");
3058 goto err_map_tsif0;
3059 }
3060
Liron Kuch59339922013-01-01 18:29:47 +02003061 mem_tsif1 = platform_get_resource_byname(pdev,
3062 IORESOURCE_MEM, "MSM_TSIF1_PHYS");
Joel Nider5556a852011-10-16 10:52:13 +02003063 if (!mem_tsif1) {
3064 dev_err(&pdev->dev, "Missing tsif1 MEM resource");
3065 rc = -ENXIO;
3066 goto err_res_tsif1;
3067 }
3068 device->tsif[1].base = ioremap(mem_tsif1->start,
3069 resource_size(mem_tsif1));
3070 if (!device->tsif[1].base) {
3071 dev_err(&pdev->dev, "ioremap failed");
3072 goto err_map_tsif1;
3073 }
3074
Liron Kuch59339922013-01-01 18:29:47 +02003075 mem_tspp = platform_get_resource_byname(pdev,
3076 IORESOURCE_MEM, "MSM_TSPP_PHYS");
Joel Nider5556a852011-10-16 10:52:13 +02003077 if (!mem_tspp) {
3078 dev_err(&pdev->dev, "Missing MEM resource");
3079 rc = -ENXIO;
3080 goto err_res_dev;
3081 }
3082 device->base = ioremap(mem_tspp->start, resource_size(mem_tspp));
3083 if (!device->base) {
3084 dev_err(&pdev->dev, "ioremap failed");
3085 goto err_map_dev;
3086 }
3087
Liron Kuch59339922013-01-01 18:29:47 +02003088 mem_bam = platform_get_resource_byname(pdev,
3089 IORESOURCE_MEM, "MSM_TSPP_BAM_PHYS");
Joel Nider5556a852011-10-16 10:52:13 +02003090 if (!mem_bam) {
3091 pr_err("tspp: Missing bam MEM resource");
3092 rc = -ENXIO;
3093 goto err_res_bam;
3094 }
3095 memset(&device->bam_props, 0, sizeof(device->bam_props));
3096 device->bam_props.phys_addr = mem_bam->start;
3097 device->bam_props.virt_addr = ioremap(mem_bam->start,
3098 resource_size(mem_bam));
3099 if (!device->bam_props.virt_addr) {
3100 dev_err(&pdev->dev, "ioremap failed");
3101 goto err_map_bam;
3102 }
3103
Liron Kuch59339922013-01-01 18:29:47 +02003104 if (msm_tspp_map_irqs(pdev, device))
Joel Nider5556a852011-10-16 10:52:13 +02003105 goto err_irq;
Joel Nider5556a852011-10-16 10:52:13 +02003106
Joel Nider5556a852011-10-16 10:52:13 +02003107 /* power management */
3108 pm_runtime_set_active(&pdev->dev);
3109 pm_runtime_enable(&pdev->dev);
3110
Joel Nider5556a852011-10-16 10:52:13 +02003111 tspp_debugfs_init(device, 0);
3112
3113 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
3114 tsif_debugfs_init(&device->tsif[i], i);
Joel Nider5556a852011-10-16 10:52:13 +02003115
3116 wake_lock_init(&device->wake_lock, WAKE_LOCK_SUSPEND,
3117 dev_name(&pdev->dev));
3118
3119 /* set up pointers to ram-based 'registers' */
Joel Nider435ad8e2011-12-14 16:53:30 +02003120 device->filters[0] = device->base + TSPP_PID_FILTER_TABLE0;
3121 device->filters[1] = device->base + TSPP_PID_FILTER_TABLE1;
3122 device->filters[2] = device->base + TSPP_PID_FILTER_TABLE2;
3123 device->tspp_key_table = device->base + TSPP_DATA_KEY;
3124 device->tspp_global_performance =
3125 device->base + TSPP_GLOBAL_PERFORMANCE;
3126 device->tspp_pipe_context =
3127 device->base + TSPP_PIPE_CONTEXT;
3128 device->tspp_pipe_performance =
3129 device->base + TSPP_PIPE_PERFORMANCE;
Joel Nider5556a852011-10-16 10:52:13 +02003130
3131 device->bam_props.summing_threshold = 0x10;
3132 device->bam_props.irq = device->bam_irq;
3133 device->bam_props.manage = SPS_BAM_MGR_LOCAL;
3134
Liron Kuch59339922013-01-01 18:29:47 +02003135 if (tspp_clock_start(device) != 0) {
3136 dev_err(&pdev->dev, "Can't start clocks");
3137 goto err_clock;
3138 }
3139
Joel Nider5556a852011-10-16 10:52:13 +02003140 if (sps_register_bam_device(&device->bam_props,
3141 &device->bam_handle) != 0) {
3142 pr_err("tspp: failed to register bam");
3143 goto err_bam;
3144 }
3145
Joel Nider5556a852011-10-16 10:52:13 +02003146 spin_lock_init(&device->spinlock);
3147 tasklet_init(&device->tlet, tspp_sps_complete_tlet,
3148 (unsigned long)device);
3149
3150 /* initialize everything to a known state */
3151 tspp_global_reset(device);
3152
3153 version = readl_relaxed(device->base + TSPP_VERSION);
Liron Kuch59339922013-01-01 18:29:47 +02003154 /*
3155 * TSPP version can be bits [7:0] or alternatively,
3156 * TSPP major version is bits [31:28].
3157 */
3158 if ((version != 0x1) && (((version >> 28) & 0xF) != 0x1))
Joel Nider5556a852011-10-16 10:52:13 +02003159 pr_warn("tspp: unrecognized hw version=%i", version);
3160
Joel Nider435ad8e2011-12-14 16:53:30 +02003161 /* initialize the channels */
Joel Nider5556a852011-10-16 10:52:13 +02003162 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
Joel Nider435ad8e2011-12-14 16:53:30 +02003163 if (tspp_channel_init(&(device->channels[i]), device) != 0) {
3164 pr_err("tspp_channel_init failed");
3165 goto err_channel;
3166 }
Joel Nider5556a852011-10-16 10:52:13 +02003167 }
3168
Joel Nider435ad8e2011-12-14 16:53:30 +02003169 /* stop the clocks for power savings */
3170 tspp_clock_stop(device);
3171
3172 /* everything is ok, so add the device to the list */
3173 list_add_tail(&(device->devlist), &tspp_devices);
3174
Joel Nider5556a852011-10-16 10:52:13 +02003175 return 0;
3176
Joel Nider435ad8e2011-12-14 16:53:30 +02003177err_channel:
Liron Kuch59339922013-01-01 18:29:47 +02003178 /* un-initialize channels */
Liron Kuch72b78552012-10-30 17:47:50 +02003179 for (j = 0; j < i; j++) {
3180 channel = &(device->channels[i]);
3181 device_destroy(tspp_class, channel->cdev.dev);
3182 cdev_del(&channel->cdev);
3183 }
Liron Kuch59339922013-01-01 18:29:47 +02003184
Joel Nider5556a852011-10-16 10:52:13 +02003185 sps_deregister_bam_device(device->bam_handle);
Liron Kuch59339922013-01-01 18:29:47 +02003186err_clock:
Joel Nider5556a852011-10-16 10:52:13 +02003187err_bam:
Joel Nider5556a852011-10-16 10:52:13 +02003188 tspp_debugfs_exit(device);
3189 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
3190 tsif_debugfs_exit(&device->tsif[i]);
Joel Nider5556a852011-10-16 10:52:13 +02003191err_irq:
Joel Nider5556a852011-10-16 10:52:13 +02003192 iounmap(device->bam_props.virt_addr);
3193err_map_bam:
3194err_res_bam:
3195 iounmap(device->base);
3196err_map_dev:
3197err_res_dev:
3198 iounmap(device->tsif[1].base);
3199err_map_tsif1:
3200err_res_tsif1:
3201 iounmap(device->tsif[0].base);
3202err_map_tsif0:
3203err_res_tsif0:
3204 if (device->tsif_ref_clk)
3205 clk_put(device->tsif_ref_clk);
3206err_refclock:
3207 if (device->tsif_pclk)
3208 clk_put(device->tsif_pclk);
3209err_pclock:
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -07003210 if (device->tsif_vreg)
3211 regulator_disable(device->tsif_vreg);
3212err_regultaor:
Hamad Kadmanyef5ce992013-06-03 09:30:50 +03003213 if (device->tsif_bus_client)
3214 msm_bus_scale_unregister_client(device->tsif_bus_client);
Joel Nider5556a852011-10-16 10:52:13 +02003215 kfree(device);
3216
3217out:
3218 return rc;
3219}
3220
3221static int __devexit msm_tspp_remove(struct platform_device *pdev)
3222{
Joel Nider435ad8e2011-12-14 16:53:30 +02003223 struct tspp_channel *channel;
Joel Nider5556a852011-10-16 10:52:13 +02003224 u32 i;
Liron Kuch605cc122013-02-21 14:25:57 +02003225 int rc;
Joel Nider5556a852011-10-16 10:52:13 +02003226
3227 struct tspp_device *device = platform_get_drvdata(pdev);
3228
Joel Nider435ad8e2011-12-14 16:53:30 +02003229 /* free the buffers, and delete the channels */
3230 for (i = 0; i < TSPP_NUM_CHANNELS; i++) {
3231 channel = &device->channels[i];
3232 tspp_close_channel(device->pdev->id, i);
3233 device_destroy(tspp_class, channel->cdev.dev);
3234 cdev_del(&channel->cdev);
3235 }
3236
Liron Kuch59339922013-01-01 18:29:47 +02003237 /* de-registering BAM device requires clocks */
Liron Kuch605cc122013-02-21 14:25:57 +02003238 rc = tspp_clock_start(device);
3239 if (rc == 0) {
3240 sps_deregister_bam_device(device->bam_handle);
3241 tspp_clock_stop(device);
3242 }
Joel Nider5556a852011-10-16 10:52:13 +02003243
Hamad Kadmany44307d32012-11-25 09:49:51 +02003244 for (i = 0; i < TSPP_TSIF_INSTANCES; i++) {
Joel Nider5556a852011-10-16 10:52:13 +02003245 tsif_debugfs_exit(&device->tsif[i]);
Hamad Kadmany44307d32012-11-25 09:49:51 +02003246 if (device->tsif[i].tsif_irq)
3247 free_irq(device->tsif[i].tsif_irq, &device->tsif[i]);
3248 }
Joel Nider5556a852011-10-16 10:52:13 +02003249
Hamad Kadmanyef5ce992013-06-03 09:30:50 +03003250 if (device->tsif_bus_client)
3251 msm_bus_scale_unregister_client(device->tsif_bus_client);
3252
Joel Nider5556a852011-10-16 10:52:13 +02003253 wake_lock_destroy(&device->wake_lock);
3254 free_irq(device->tspp_irq, device);
Joel Nider5556a852011-10-16 10:52:13 +02003255
3256 iounmap(device->bam_props.virt_addr);
3257 iounmap(device->base);
3258 for (i = 0; i < TSPP_TSIF_INSTANCES; i++)
3259 iounmap(device->tsif[i].base);
3260
3261 if (device->tsif_ref_clk)
3262 clk_put(device->tsif_ref_clk);
3263
3264 if (device->tsif_pclk)
3265 clk_put(device->tsif_pclk);
3266
Vikram Mulukutlae9ca54b2013-04-19 11:08:42 -07003267 if (device->tsif_vreg)
3268 regulator_disable(device->tsif_vreg);
3269
Joel Nider5556a852011-10-16 10:52:13 +02003270 pm_runtime_disable(&pdev->dev);
Liron Kuch605cc122013-02-21 14:25:57 +02003271
Joel Nider5556a852011-10-16 10:52:13 +02003272 kfree(device);
3273
3274 return 0;
3275}
3276
3277/*** power management ***/
3278
3279static int tspp_runtime_suspend(struct device *dev)
3280{
3281 dev_dbg(dev, "pm_runtime: suspending...");
3282 return 0;
3283}
3284
3285static int tspp_runtime_resume(struct device *dev)
3286{
3287 dev_dbg(dev, "pm_runtime: resuming...");
3288 return 0;
3289}
3290
3291static const struct dev_pm_ops tspp_dev_pm_ops = {
3292 .runtime_suspend = tspp_runtime_suspend,
3293 .runtime_resume = tspp_runtime_resume,
3294};
3295
Liron Kuch59339922013-01-01 18:29:47 +02003296static struct of_device_id msm_match_table[] = {
3297 {.compatible = "qcom,msm_tspp"},
3298 {}
3299};
3300
Joel Nider5556a852011-10-16 10:52:13 +02003301static struct platform_driver msm_tspp_driver = {
3302 .probe = msm_tspp_probe,
3303 .remove = __exit_p(msm_tspp_remove),
3304 .driver = {
3305 .name = "msm_tspp",
3306 .pm = &tspp_dev_pm_ops,
Liron Kuch59339922013-01-01 18:29:47 +02003307 .of_match_table = msm_match_table,
Joel Nider5556a852011-10-16 10:52:13 +02003308 },
3309};
3310
3311
3312static int __init mod_init(void)
3313{
Joel Nider5556a852011-10-16 10:52:13 +02003314 int rc;
3315
Joel Nider435ad8e2011-12-14 16:53:30 +02003316 /* make the char devs (channels) */
Joel Nider5556a852011-10-16 10:52:13 +02003317 rc = alloc_chrdev_region(&tspp_minor, 0, TSPP_NUM_CHANNELS, "tspp");
3318 if (rc) {
3319 pr_err("tspp: alloc_chrdev_region failed: %d", rc);
3320 goto err_devrgn;
3321 }
3322
3323 tspp_class = class_create(THIS_MODULE, "tspp");
3324 if (IS_ERR(tspp_class)) {
3325 rc = PTR_ERR(tspp_class);
3326 pr_err("tspp: Error creating class: %d", rc);
3327 goto err_class;
3328 }
3329
Joel Nider435ad8e2011-12-14 16:53:30 +02003330 /* register the driver, and check hardware */
3331 rc = platform_driver_register(&msm_tspp_driver);
3332 if (rc) {
3333 pr_err("tspp: platform_driver_register failed: %d", rc);
3334 goto err_register;
Joel Nider5556a852011-10-16 10:52:13 +02003335 }
3336
3337 return 0;
3338
Joel Nider435ad8e2011-12-14 16:53:30 +02003339err_register:
3340 class_destroy(tspp_class);
Joel Nider5556a852011-10-16 10:52:13 +02003341err_class:
3342 unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
3343err_devrgn:
Joel Nider5556a852011-10-16 10:52:13 +02003344 return rc;
3345}
3346
3347static void __exit mod_exit(void)
3348{
Joel Nider435ad8e2011-12-14 16:53:30 +02003349 /* delete low level driver */
3350 platform_driver_unregister(&msm_tspp_driver);
Joel Nider5556a852011-10-16 10:52:13 +02003351
Joel Nider435ad8e2011-12-14 16:53:30 +02003352 /* delete upper layer interface */
Joel Nider5556a852011-10-16 10:52:13 +02003353 class_destroy(tspp_class);
3354 unregister_chrdev_region(0, TSPP_NUM_CHANNELS);
Joel Nider5556a852011-10-16 10:52:13 +02003355}
3356
3357module_init(mod_init);
3358module_exit(mod_exit);
3359
Joel Nider435ad8e2011-12-14 16:53:30 +02003360MODULE_DESCRIPTION("TSPP platform device and char dev");
Joel Nider5556a852011-10-16 10:52:13 +02003361MODULE_LICENSE("GPL v2");