]> git.proxmox.com Git - mirror_ubuntu-kernels.git/blob - drivers/media/pci/smipcie/smipcie-ir.c
Merge branches 'for-5.1/upstream-fixes', 'for-5.2/core', 'for-5.2/ish', 'for-5.2...
[mirror_ubuntu-kernels.git] / drivers / media / pci / smipcie / smipcie-ir.c
1 /*
2 * SMI PCIe driver for DVBSky cards.
3 *
4 * Copyright (C) 2014 Max nibble <nibble.max@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17 #include "smipcie.h"
18
19 #define SMI_SAMPLE_PERIOD 83
20 #define SMI_SAMPLE_IDLEMIN (10000 / SMI_SAMPLE_PERIOD)
21
22 static void smi_ir_enableInterrupt(struct smi_rc *ir)
23 {
24 struct smi_dev *dev = ir->dev;
25
26 smi_write(MSI_INT_ENA_SET, IR_X_INT);
27 }
28
29 static void smi_ir_disableInterrupt(struct smi_rc *ir)
30 {
31 struct smi_dev *dev = ir->dev;
32
33 smi_write(MSI_INT_ENA_CLR, IR_X_INT);
34 }
35
36 static void smi_ir_clearInterrupt(struct smi_rc *ir)
37 {
38 struct smi_dev *dev = ir->dev;
39
40 smi_write(MSI_INT_STATUS_CLR, IR_X_INT);
41 }
42
43 static void smi_ir_stop(struct smi_rc *ir)
44 {
45 struct smi_dev *dev = ir->dev;
46
47 smi_ir_disableInterrupt(ir);
48 smi_clear(IR_Init_Reg, rbIRen);
49 }
50
51 static void smi_raw_process(struct rc_dev *rc_dev, const u8 *buffer,
52 const u8 length)
53 {
54 struct ir_raw_event rawir = {};
55 int cnt;
56
57 for (cnt = 0; cnt < length; cnt++) {
58 if (buffer[cnt] & 0x7f) {
59 rawir.pulse = (buffer[cnt] & 0x80) == 0;
60 rawir.duration = ((buffer[cnt] & 0x7f) +
61 (rawir.pulse ? 0 : -1)) *
62 rc_dev->rx_resolution;
63 ir_raw_event_store_with_filter(rc_dev, &rawir);
64 }
65 }
66 }
67
68 static void smi_ir_decode(struct smi_rc *ir)
69 {
70 struct smi_dev *dev = ir->dev;
71 struct rc_dev *rc_dev = ir->rc_dev;
72 u32 dwIRControl, dwIRData;
73 u8 index, ucIRCount, readLoop;
74
75 dwIRControl = smi_read(IR_Init_Reg);
76
77 if (dwIRControl & rbIRVld) {
78 ucIRCount = (u8) smi_read(IR_Data_Cnt);
79
80 readLoop = ucIRCount/4;
81 if (ucIRCount % 4)
82 readLoop += 1;
83 for (index = 0; index < readLoop; index++) {
84 dwIRData = smi_read(IR_DATA_BUFFER_BASE + (index * 4));
85
86 ir->irData[index*4 + 0] = (u8)(dwIRData);
87 ir->irData[index*4 + 1] = (u8)(dwIRData >> 8);
88 ir->irData[index*4 + 2] = (u8)(dwIRData >> 16);
89 ir->irData[index*4 + 3] = (u8)(dwIRData >> 24);
90 }
91 smi_raw_process(rc_dev, ir->irData, ucIRCount);
92 smi_set(IR_Init_Reg, rbIRVld);
93 }
94
95 if (dwIRControl & rbIRhighidle) {
96 struct ir_raw_event rawir = {};
97
98 rawir.pulse = 0;
99 rawir.duration = US_TO_NS(SMI_SAMPLE_PERIOD *
100 SMI_SAMPLE_IDLEMIN);
101 ir_raw_event_store_with_filter(rc_dev, &rawir);
102 smi_set(IR_Init_Reg, rbIRhighidle);
103 }
104
105 ir_raw_event_handle(rc_dev);
106 }
107
108 /* ir functions call by main driver.*/
109 int smi_ir_irq(struct smi_rc *ir, u32 int_status)
110 {
111 int handled = 0;
112
113 if (int_status & IR_X_INT) {
114 smi_ir_disableInterrupt(ir);
115 smi_ir_clearInterrupt(ir);
116 smi_ir_decode(ir);
117 smi_ir_enableInterrupt(ir);
118 handled = 1;
119 }
120 return handled;
121 }
122
123 void smi_ir_start(struct smi_rc *ir)
124 {
125 struct smi_dev *dev = ir->dev;
126
127 smi_write(IR_Idle_Cnt_Low,
128 (((SMI_SAMPLE_PERIOD - 1) & 0xFFFF) << 16) |
129 (SMI_SAMPLE_IDLEMIN & 0xFFFF));
130 msleep(20);
131 smi_set(IR_Init_Reg, rbIRen | rbIRhighidle);
132
133 smi_ir_enableInterrupt(ir);
134 }
135
136 int smi_ir_init(struct smi_dev *dev)
137 {
138 int ret;
139 struct rc_dev *rc_dev;
140 struct smi_rc *ir = &dev->ir;
141
142 rc_dev = rc_allocate_device(RC_DRIVER_IR_RAW);
143 if (!rc_dev)
144 return -ENOMEM;
145
146 /* init input device */
147 snprintf(ir->device_name, sizeof(ir->device_name), "IR (%s)",
148 dev->info->name);
149 snprintf(ir->input_phys, sizeof(ir->input_phys), "pci-%s/ir0",
150 pci_name(dev->pci_dev));
151
152 rc_dev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
153 rc_dev->driver_name = "SMI_PCIe";
154 rc_dev->input_phys = ir->input_phys;
155 rc_dev->device_name = ir->device_name;
156 rc_dev->input_id.bustype = BUS_PCI;
157 rc_dev->input_id.version = 1;
158 rc_dev->input_id.vendor = dev->pci_dev->subsystem_vendor;
159 rc_dev->input_id.product = dev->pci_dev->subsystem_device;
160 rc_dev->dev.parent = &dev->pci_dev->dev;
161
162 rc_dev->map_name = dev->info->rc_map;
163 rc_dev->timeout = MS_TO_NS(100);
164 rc_dev->rx_resolution = US_TO_NS(SMI_SAMPLE_PERIOD);
165
166 ir->rc_dev = rc_dev;
167 ir->dev = dev;
168
169 smi_ir_disableInterrupt(ir);
170
171 ret = rc_register_device(rc_dev);
172 if (ret)
173 goto ir_err;
174
175 return 0;
176 ir_err:
177 rc_free_device(rc_dev);
178 return ret;
179 }
180
181 void smi_ir_exit(struct smi_dev *dev)
182 {
183 struct smi_rc *ir = &dev->ir;
184 struct rc_dev *rc_dev = ir->rc_dev;
185
186 smi_ir_stop(ir);
187 rc_unregister_device(rc_dev);
188 ir->rc_dev = NULL;
189 }