1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * PRU-ICSS INTC IRQChip driver for various TI SoCs 4 * 5 * Copyright (C) 2016-2020 Texas Instruments Incorporated - http://www.ti.com/ 6 * 7 * Author(s): 8 * Andrew F. Davis <afd@ti.com> 9 * Suman Anna <s-anna@ti.com> 10 * Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org> for Texas Instruments 11 * 12 * Copyright (C) 2019 David Lechner <david@lechnology.com> 13 */ 14 15 #include <linux/interrupt.h> 16 #include <linux/irq.h> 17 #include <linux/irqchip/chained_irq.h> 18 #include <linux/irqdomain.h> 19 #include <linux/module.h> 20 #include <linux/of_device.h> 21 #include <linux/platform_device.h> 22 23 /* 24 * Number of host interrupts reaching the main MPU sub-system. Note that this 25 * is not the same as the total number of host interrupts supported by the PRUSS 26 * INTC instance 27 */ 28 #define MAX_NUM_HOST_IRQS 8 29 30 /* minimum starting host interrupt number for MPU */ 31 #define FIRST_PRU_HOST_INT 2 32 33 /* PRU_ICSS_INTC registers */ 34 #define PRU_INTC_REVID 0x0000 35 #define PRU_INTC_CR 0x0004 36 #define PRU_INTC_GER 0x0010 37 #define PRU_INTC_GNLR 0x001c 38 #define PRU_INTC_SISR 0x0020 39 #define PRU_INTC_SICR 0x0024 40 #define PRU_INTC_EISR 0x0028 41 #define PRU_INTC_EICR 0x002c 42 #define PRU_INTC_HIEISR 0x0034 43 #define PRU_INTC_HIDISR 0x0038 44 #define PRU_INTC_GPIR 0x0080 45 #define PRU_INTC_SRSR(x) (0x0200 + (x) * 4) 46 #define PRU_INTC_SECR(x) (0x0280 + (x) * 4) 47 #define PRU_INTC_ESR(x) (0x0300 + (x) * 4) 48 #define PRU_INTC_ECR(x) (0x0380 + (x) * 4) 49 #define PRU_INTC_CMR(x) (0x0400 + (x) * 4) 50 #define PRU_INTC_HMR(x) (0x0800 + (x) * 4) 51 #define PRU_INTC_HIPIR(x) (0x0900 + (x) * 4) 52 #define PRU_INTC_SIPR(x) (0x0d00 + (x) * 4) 53 #define PRU_INTC_SITR(x) (0x0d80 + (x) * 4) 54 #define PRU_INTC_HINLR(x) (0x1100 + (x) * 4) 55 #define PRU_INTC_HIER 0x1500 56 57 /* CMR register bit-field macros */ 58 #define CMR_EVT_MAP_MASK 0xf 59 #define CMR_EVT_MAP_BITS 8 60 #define CMR_EVT_PER_REG 4 61 62 /* HMR register bit-field macros */ 63 #define HMR_CH_MAP_MASK 0xf 64 #define HMR_CH_MAP_BITS 8 65 #define HMR_CH_PER_REG 4 66 67 /* HIPIR register bit-fields */ 68 #define INTC_HIPIR_NONE_HINT 0x80000000 69 70 #define MAX_PRU_SYS_EVENTS 160 71 #define MAX_PRU_CHANNELS 20 72 73 /** 74 * struct pruss_intc_map_record - keeps track of actual mapping state 75 * @value: The currently mapped value (channel or host) 76 * @ref_count: Keeps track of number of current users of this resource 77 */ 78 struct pruss_intc_map_record { 79 u8 value; 80 u8 ref_count; 81 }; 82 83 /** 84 * struct pruss_intc_match_data - match data to handle SoC variations 85 * @num_system_events: number of input system events handled by the PRUSS INTC 86 * @num_host_events: number of host events (which is equal to number of 87 * channels) supported by the PRUSS INTC 88 */ 89 struct pruss_intc_match_data { 90 u8 num_system_events; 91 u8 num_host_events; 92 }; 93 94 /** 95 * struct pruss_intc - PRUSS interrupt controller structure 96 * @event_channel: current state of system event to channel mappings 97 * @channel_host: current state of channel to host mappings 98 * @irqs: kernel irq numbers corresponding to PRUSS host interrupts 99 * @base: base virtual address of INTC register space 100 * @domain: irq domain for this interrupt controller 101 * @soc_config: cached PRUSS INTC IP configuration data 102 * @dev: PRUSS INTC device pointer 103 * @lock: mutex to serialize interrupts mapping 104 */ 105 struct pruss_intc { 106 struct pruss_intc_map_record event_channel[MAX_PRU_SYS_EVENTS]; 107 struct pruss_intc_map_record channel_host[MAX_PRU_CHANNELS]; 108 unsigned int irqs[MAX_NUM_HOST_IRQS]; 109 void __iomem *base; 110 struct irq_domain *domain; 111 const struct pruss_intc_match_data *soc_config; 112 struct device *dev; 113 struct mutex lock; /* PRUSS INTC lock */ 114 }; 115 116 /** 117 * struct pruss_host_irq_data - PRUSS host irq data structure 118 * @intc: PRUSS interrupt controller pointer 119 * @host_irq: host irq number 120 */ 121 struct pruss_host_irq_data { 122 struct pruss_intc *intc; 123 u8 host_irq; 124 }; 125 126 static inline u32 pruss_intc_read_reg(struct pruss_intc *intc, unsigned int reg) 127 { 128 return readl_relaxed(intc->base + reg); 129 } 130 131 static inline void pruss_intc_write_reg(struct pruss_intc *intc, 132 unsigned int reg, u32 val) 133 { 134 writel_relaxed(val, intc->base + reg); 135 } 136 137 static void pruss_intc_update_cmr(struct pruss_intc *intc, unsigned int evt, 138 u8 ch) 139 { 140 u32 idx, offset, val; 141 142 idx = evt / CMR_EVT_PER_REG; 143 offset = (evt % CMR_EVT_PER_REG) * CMR_EVT_MAP_BITS; 144 145 val = pruss_intc_read_reg(intc, PRU_INTC_CMR(idx)); 146 val &= ~(CMR_EVT_MAP_MASK << offset); 147 val |= ch << offset; 148 pruss_intc_write_reg(intc, PRU_INTC_CMR(idx), val); 149 150 dev_dbg(intc->dev, "SYSEV%u -> CH%d (CMR%d 0x%08x)\n", evt, ch, 151 idx, pruss_intc_read_reg(intc, PRU_INTC_CMR(idx))); 152 } 153 154 static void pruss_intc_update_hmr(struct pruss_intc *intc, u8 ch, u8 host) 155 { 156 u32 idx, offset, val; 157 158 idx = ch / HMR_CH_PER_REG; 159 offset = (ch % HMR_CH_PER_REG) * HMR_CH_MAP_BITS; 160 161 val = pruss_intc_read_reg(intc, PRU_INTC_HMR(idx)); 162 val &= ~(HMR_CH_MAP_MASK << offset); 163 val |= host << offset; 164 pruss_intc_write_reg(intc, PRU_INTC_HMR(idx), val); 165 166 dev_dbg(intc->dev, "CH%d -> HOST%d (HMR%d 0x%08x)\n", ch, host, idx, 167 pruss_intc_read_reg(intc, PRU_INTC_HMR(idx))); 168 } 169 170 /** 171 * pruss_intc_map() - configure the PRUSS INTC 172 * @intc: PRUSS interrupt controller pointer 173 * @hwirq: the system event number 174 * 175 * Configures the PRUSS INTC with the provided configuration from the one parsed 176 * in the xlate function. 177 */ 178 static void pruss_intc_map(struct pruss_intc *intc, unsigned long hwirq) 179 { 180 struct device *dev = intc->dev; 181 u8 ch, host, reg_idx; 182 u32 val; 183 184 mutex_lock(&intc->lock); 185 186 intc->event_channel[hwirq].ref_count++; 187 188 ch = intc->event_channel[hwirq].value; 189 host = intc->channel_host[ch].value; 190 191 pruss_intc_update_cmr(intc, hwirq, ch); 192 193 reg_idx = hwirq / 32; 194 val = BIT(hwirq % 32); 195 196 /* clear and enable system event */ 197 pruss_intc_write_reg(intc, PRU_INTC_ESR(reg_idx), val); 198 pruss_intc_write_reg(intc, PRU_INTC_SECR(reg_idx), val); 199 200 if (++intc->channel_host[ch].ref_count == 1) { 201 pruss_intc_update_hmr(intc, ch, host); 202 203 /* enable host interrupts */ 204 pruss_intc_write_reg(intc, PRU_INTC_HIEISR, host); 205 } 206 207 dev_dbg(dev, "mapped system_event = %lu channel = %d host = %d", 208 hwirq, ch, host); 209 210 mutex_unlock(&intc->lock); 211 } 212 213 /** 214 * pruss_intc_unmap() - unconfigure the PRUSS INTC 215 * @intc: PRUSS interrupt controller pointer 216 * @hwirq: the system event number 217 * 218 * Undo whatever was done in pruss_intc_map() for a PRU core. 219 * Mappings are reference counted, so resources are only disabled when there 220 * are no longer any users. 221 */ 222 static void pruss_intc_unmap(struct pruss_intc *intc, unsigned long hwirq) 223 { 224 u8 ch, host, reg_idx; 225 u32 val; 226 227 mutex_lock(&intc->lock); 228 229 ch = intc->event_channel[hwirq].value; 230 host = intc->channel_host[ch].value; 231 232 if (--intc->channel_host[ch].ref_count == 0) { 233 /* disable host interrupts */ 234 pruss_intc_write_reg(intc, PRU_INTC_HIDISR, host); 235 236 /* clear the map using reset value 0 */ 237 pruss_intc_update_hmr(intc, ch, 0); 238 } 239 240 intc->event_channel[hwirq].ref_count--; 241 reg_idx = hwirq / 32; 242 val = BIT(hwirq % 32); 243 244 /* disable system events */ 245 pruss_intc_write_reg(intc, PRU_INTC_ECR(reg_idx), val); 246 /* clear any pending status */ 247 pruss_intc_write_reg(intc, PRU_INTC_SECR(reg_idx), val); 248 249 /* clear the map using reset value 0 */ 250 pruss_intc_update_cmr(intc, hwirq, 0); 251 252 dev_dbg(intc->dev, "unmapped system_event = %lu channel = %d host = %d\n", 253 hwirq, ch, host); 254 255 mutex_unlock(&intc->lock); 256 } 257 258 static void pruss_intc_init(struct pruss_intc *intc) 259 { 260 const struct pruss_intc_match_data *soc_config = intc->soc_config; 261 int num_chnl_map_regs, num_host_intr_regs, num_event_type_regs, i; 262 263 num_chnl_map_regs = DIV_ROUND_UP(soc_config->num_system_events, 264 CMR_EVT_PER_REG); 265 num_host_intr_regs = DIV_ROUND_UP(soc_config->num_host_events, 266 HMR_CH_PER_REG); 267 num_event_type_regs = DIV_ROUND_UP(soc_config->num_system_events, 32); 268 269 /* 270 * configure polarity (SIPR register) to active high and 271 * type (SITR register) to level interrupt for all system events 272 */ 273 for (i = 0; i < num_event_type_regs; i++) { 274 pruss_intc_write_reg(intc, PRU_INTC_SIPR(i), 0xffffffff); 275 pruss_intc_write_reg(intc, PRU_INTC_SITR(i), 0); 276 } 277 278 /* clear all interrupt channel map registers, 4 events per register */ 279 for (i = 0; i < num_chnl_map_regs; i++) 280 pruss_intc_write_reg(intc, PRU_INTC_CMR(i), 0); 281 282 /* clear all host interrupt map registers, 4 channels per register */ 283 for (i = 0; i < num_host_intr_regs; i++) 284 pruss_intc_write_reg(intc, PRU_INTC_HMR(i), 0); 285 286 /* global interrupt enable */ 287 pruss_intc_write_reg(intc, PRU_INTC_GER, 1); 288 } 289 290 static void pruss_intc_irq_ack(struct irq_data *data) 291 { 292 struct pruss_intc *intc = irq_data_get_irq_chip_data(data); 293 unsigned int hwirq = data->hwirq; 294 295 pruss_intc_write_reg(intc, PRU_INTC_SICR, hwirq); 296 } 297 298 static void pruss_intc_irq_mask(struct irq_data *data) 299 { 300 struct pruss_intc *intc = irq_data_get_irq_chip_data(data); 301 unsigned int hwirq = data->hwirq; 302 303 pruss_intc_write_reg(intc, PRU_INTC_EICR, hwirq); 304 } 305 306 static void pruss_intc_irq_unmask(struct irq_data *data) 307 { 308 struct pruss_intc *intc = irq_data_get_irq_chip_data(data); 309 unsigned int hwirq = data->hwirq; 310 311 pruss_intc_write_reg(intc, PRU_INTC_EISR, hwirq); 312 } 313 314 static int pruss_intc_irq_reqres(struct irq_data *data) 315 { 316 if (!try_module_get(THIS_MODULE)) 317 return -ENODEV; 318 319 return 0; 320 } 321 322 static void pruss_intc_irq_relres(struct irq_data *data) 323 { 324 module_put(THIS_MODULE); 325 } 326 327 static int pruss_intc_irq_get_irqchip_state(struct irq_data *data, 328 enum irqchip_irq_state which, 329 bool *state) 330 { 331 struct pruss_intc *intc = irq_data_get_irq_chip_data(data); 332 u32 reg, mask, srsr; 333 334 if (which != IRQCHIP_STATE_PENDING) 335 return -EINVAL; 336 337 reg = PRU_INTC_SRSR(data->hwirq / 32); 338 mask = BIT(data->hwirq % 32); 339 340 srsr = pruss_intc_read_reg(intc, reg); 341 342 *state = !!(srsr & mask); 343 344 return 0; 345 } 346 347 static int pruss_intc_irq_set_irqchip_state(struct irq_data *data, 348 enum irqchip_irq_state which, 349 bool state) 350 { 351 struct pruss_intc *intc = irq_data_get_irq_chip_data(data); 352 353 if (which != IRQCHIP_STATE_PENDING) 354 return -EINVAL; 355 356 if (state) 357 pruss_intc_write_reg(intc, PRU_INTC_SISR, data->hwirq); 358 else 359 pruss_intc_write_reg(intc, PRU_INTC_SICR, data->hwirq); 360 361 return 0; 362 } 363 364 static struct irq_chip pruss_irqchip = { 365 .name = "pruss-intc", 366 .irq_ack = pruss_intc_irq_ack, 367 .irq_mask = pruss_intc_irq_mask, 368 .irq_unmask = pruss_intc_irq_unmask, 369 .irq_request_resources = pruss_intc_irq_reqres, 370 .irq_release_resources = pruss_intc_irq_relres, 371 .irq_get_irqchip_state = pruss_intc_irq_get_irqchip_state, 372 .irq_set_irqchip_state = pruss_intc_irq_set_irqchip_state, 373 }; 374 375 static int pruss_intc_validate_mapping(struct pruss_intc *intc, int event, 376 int channel, int host) 377 { 378 struct device *dev = intc->dev; 379 int ret = 0; 380 381 mutex_lock(&intc->lock); 382 383 /* check if sysevent already assigned */ 384 if (intc->event_channel[event].ref_count > 0 && 385 intc->event_channel[event].value != channel) { 386 dev_err(dev, "event %d (req. ch %d) already assigned to channel %d\n", 387 event, channel, intc->event_channel[event].value); 388 ret = -EBUSY; 389 goto unlock; 390 } 391 392 /* check if channel already assigned */ 393 if (intc->channel_host[channel].ref_count > 0 && 394 intc->channel_host[channel].value != host) { 395 dev_err(dev, "channel %d (req. host %d) already assigned to host %d\n", 396 channel, host, intc->channel_host[channel].value); 397 ret = -EBUSY; 398 goto unlock; 399 } 400 401 intc->event_channel[event].value = channel; 402 intc->channel_host[channel].value = host; 403 404 unlock: 405 mutex_unlock(&intc->lock); 406 return ret; 407 } 408 409 static int 410 pruss_intc_irq_domain_xlate(struct irq_domain *d, struct device_node *node, 411 const u32 *intspec, unsigned int intsize, 412 unsigned long *out_hwirq, unsigned int *out_type) 413 { 414 struct pruss_intc *intc = d->host_data; 415 struct device *dev = intc->dev; 416 int ret, sys_event, channel, host; 417 418 if (intsize < 3) 419 return -EINVAL; 420 421 sys_event = intspec[0]; 422 if (sys_event < 0 || sys_event >= intc->soc_config->num_system_events) { 423 dev_err(dev, "%d is not valid event number\n", sys_event); 424 return -EINVAL; 425 } 426 427 channel = intspec[1]; 428 if (channel < 0 || channel >= intc->soc_config->num_host_events) { 429 dev_err(dev, "%d is not valid channel number", channel); 430 return -EINVAL; 431 } 432 433 host = intspec[2]; 434 if (host < 0 || host >= intc->soc_config->num_host_events) { 435 dev_err(dev, "%d is not valid host irq number\n", host); 436 return -EINVAL; 437 } 438 439 /* check if requested sys_event was already mapped, if so validate it */ 440 ret = pruss_intc_validate_mapping(intc, sys_event, channel, host); 441 if (ret) 442 return ret; 443 444 *out_hwirq = sys_event; 445 *out_type = IRQ_TYPE_LEVEL_HIGH; 446 447 return 0; 448 } 449 450 static int pruss_intc_irq_domain_map(struct irq_domain *d, unsigned int virq, 451 irq_hw_number_t hw) 452 { 453 struct pruss_intc *intc = d->host_data; 454 455 pruss_intc_map(intc, hw); 456 457 irq_set_chip_data(virq, intc); 458 irq_set_chip_and_handler(virq, &pruss_irqchip, handle_level_irq); 459 460 return 0; 461 } 462 463 static void pruss_intc_irq_domain_unmap(struct irq_domain *d, unsigned int virq) 464 { 465 struct pruss_intc *intc = d->host_data; 466 unsigned long hwirq = irqd_to_hwirq(irq_get_irq_data(virq)); 467 468 irq_set_chip_and_handler(virq, NULL, NULL); 469 irq_set_chip_data(virq, NULL); 470 pruss_intc_unmap(intc, hwirq); 471 } 472 473 static const struct irq_domain_ops pruss_intc_irq_domain_ops = { 474 .xlate = pruss_intc_irq_domain_xlate, 475 .map = pruss_intc_irq_domain_map, 476 .unmap = pruss_intc_irq_domain_unmap, 477 }; 478 479 static void pruss_intc_irq_handler(struct irq_desc *desc) 480 { 481 unsigned int irq = irq_desc_get_irq(desc); 482 struct irq_chip *chip = irq_desc_get_chip(desc); 483 struct pruss_host_irq_data *host_irq_data = irq_get_handler_data(irq); 484 struct pruss_intc *intc = host_irq_data->intc; 485 u8 host_irq = host_irq_data->host_irq + FIRST_PRU_HOST_INT; 486 487 chained_irq_enter(chip, desc); 488 489 while (true) { 490 u32 hipir; 491 int hwirq, err; 492 493 /* get highest priority pending PRUSS system event */ 494 hipir = pruss_intc_read_reg(intc, PRU_INTC_HIPIR(host_irq)); 495 if (hipir & INTC_HIPIR_NONE_HINT) 496 break; 497 498 hwirq = hipir & GENMASK(9, 0); 499 err = generic_handle_domain_irq(intc->domain, hwirq); 500 501 /* 502 * NOTE: manually ACK any system events that do not have a 503 * handler mapped yet 504 */ 505 if (WARN_ON_ONCE(err)) 506 pruss_intc_write_reg(intc, PRU_INTC_SICR, hwirq); 507 } 508 509 chained_irq_exit(chip, desc); 510 } 511 512 static const char * const irq_names[MAX_NUM_HOST_IRQS] = { 513 "host_intr0", "host_intr1", "host_intr2", "host_intr3", 514 "host_intr4", "host_intr5", "host_intr6", "host_intr7", 515 }; 516 517 static int pruss_intc_probe(struct platform_device *pdev) 518 { 519 const struct pruss_intc_match_data *data; 520 struct device *dev = &pdev->dev; 521 struct pruss_intc *intc; 522 struct pruss_host_irq_data *host_data; 523 int i, irq, ret; 524 u8 max_system_events, irqs_reserved = 0; 525 526 data = of_device_get_match_data(dev); 527 if (!data) 528 return -ENODEV; 529 530 max_system_events = data->num_system_events; 531 532 intc = devm_kzalloc(dev, sizeof(*intc), GFP_KERNEL); 533 if (!intc) 534 return -ENOMEM; 535 536 intc->soc_config = data; 537 intc->dev = dev; 538 platform_set_drvdata(pdev, intc); 539 540 intc->base = devm_platform_ioremap_resource(pdev, 0); 541 if (IS_ERR(intc->base)) 542 return PTR_ERR(intc->base); 543 544 ret = of_property_read_u8(dev->of_node, "ti,irqs-reserved", 545 &irqs_reserved); 546 547 /* 548 * The irqs-reserved is used only for some SoC's therefore not having 549 * this property is still valid 550 */ 551 if (ret < 0 && ret != -EINVAL) 552 return ret; 553 554 pruss_intc_init(intc); 555 556 mutex_init(&intc->lock); 557 558 intc->domain = irq_domain_add_linear(dev->of_node, max_system_events, 559 &pruss_intc_irq_domain_ops, intc); 560 if (!intc->domain) 561 return -ENOMEM; 562 563 for (i = 0; i < MAX_NUM_HOST_IRQS; i++) { 564 if (irqs_reserved & BIT(i)) 565 continue; 566 567 irq = platform_get_irq_byname(pdev, irq_names[i]); 568 if (irq <= 0) { 569 ret = (irq == 0) ? -EINVAL : irq; 570 goto fail_irq; 571 } 572 573 intc->irqs[i] = irq; 574 575 host_data = devm_kzalloc(dev, sizeof(*host_data), GFP_KERNEL); 576 if (!host_data) { 577 ret = -ENOMEM; 578 goto fail_irq; 579 } 580 581 host_data->intc = intc; 582 host_data->host_irq = i; 583 584 irq_set_handler_data(irq, host_data); 585 irq_set_chained_handler(irq, pruss_intc_irq_handler); 586 } 587 588 return 0; 589 590 fail_irq: 591 while (--i >= 0) { 592 if (intc->irqs[i]) 593 irq_set_chained_handler_and_data(intc->irqs[i], NULL, 594 NULL); 595 } 596 597 irq_domain_remove(intc->domain); 598 599 return ret; 600 } 601 602 static int pruss_intc_remove(struct platform_device *pdev) 603 { 604 struct pruss_intc *intc = platform_get_drvdata(pdev); 605 u8 max_system_events = intc->soc_config->num_system_events; 606 unsigned int hwirq; 607 int i; 608 609 for (i = 0; i < MAX_NUM_HOST_IRQS; i++) { 610 if (intc->irqs[i]) 611 irq_set_chained_handler_and_data(intc->irqs[i], NULL, 612 NULL); 613 } 614 615 for (hwirq = 0; hwirq < max_system_events; hwirq++) 616 irq_dispose_mapping(irq_find_mapping(intc->domain, hwirq)); 617 618 irq_domain_remove(intc->domain); 619 620 return 0; 621 } 622 623 static const struct pruss_intc_match_data pruss_intc_data = { 624 .num_system_events = 64, 625 .num_host_events = 10, 626 }; 627 628 static const struct pruss_intc_match_data icssg_intc_data = { 629 .num_system_events = 160, 630 .num_host_events = 20, 631 }; 632 633 static const struct of_device_id pruss_intc_of_match[] = { 634 { 635 .compatible = "ti,pruss-intc", 636 .data = &pruss_intc_data, 637 }, 638 { 639 .compatible = "ti,icssg-intc", 640 .data = &icssg_intc_data, 641 }, 642 { /* sentinel */ }, 643 }; 644 MODULE_DEVICE_TABLE(of, pruss_intc_of_match); 645 646 static struct platform_driver pruss_intc_driver = { 647 .driver = { 648 .name = "pruss-intc", 649 .of_match_table = pruss_intc_of_match, 650 .suppress_bind_attrs = true, 651 }, 652 .probe = pruss_intc_probe, 653 .remove = pruss_intc_remove, 654 }; 655 module_platform_driver(pruss_intc_driver); 656 657 MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>"); 658 MODULE_AUTHOR("Suman Anna <s-anna@ti.com>"); 659 MODULE_AUTHOR("Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>"); 660 MODULE_DESCRIPTION("TI PRU-ICSS INTC Driver"); 661 MODULE_LICENSE("GPL v2"); 662