1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include "smipcie.h"
18
19#define SMI_SAMPLE_PERIOD 83
20#define SMI_SAMPLE_IDLEMIN (10000 / SMI_SAMPLE_PERIOD)
21
22static 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
29static 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
36static 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
43static 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
51static 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
68static 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
109int 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
123void 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
136int 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
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;
176ir_err:
177 rc_free_device(rc_dev);
178 return ret;
179}
180
181void 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}
190