162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * SMI PCIe driver for DVBSky cards. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2014 Max nibble <nibble.max@gmail.com> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "smipcie.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define SMI_SAMPLE_PERIOD 83 1162306a36Sopenharmony_ci#define SMI_SAMPLE_IDLEMIN (10000 / SMI_SAMPLE_PERIOD) 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_cistatic void smi_ir_enableInterrupt(struct smi_rc *ir) 1462306a36Sopenharmony_ci{ 1562306a36Sopenharmony_ci struct smi_dev *dev = ir->dev; 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci smi_write(MSI_INT_ENA_SET, IR_X_INT); 1862306a36Sopenharmony_ci} 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic void smi_ir_disableInterrupt(struct smi_rc *ir) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci struct smi_dev *dev = ir->dev; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci smi_write(MSI_INT_ENA_CLR, IR_X_INT); 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic void smi_ir_clearInterrupt(struct smi_rc *ir) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci struct smi_dev *dev = ir->dev; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci smi_write(MSI_INT_STATUS_CLR, IR_X_INT); 3262306a36Sopenharmony_ci} 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic void smi_ir_stop(struct smi_rc *ir) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci struct smi_dev *dev = ir->dev; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci smi_ir_disableInterrupt(ir); 3962306a36Sopenharmony_ci smi_clear(IR_Init_Reg, rbIRen); 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic void smi_raw_process(struct rc_dev *rc_dev, const u8 *buffer, 4362306a36Sopenharmony_ci const u8 length) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci struct ir_raw_event rawir = {}; 4662306a36Sopenharmony_ci int cnt; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci for (cnt = 0; cnt < length; cnt++) { 4962306a36Sopenharmony_ci if (buffer[cnt] & 0x7f) { 5062306a36Sopenharmony_ci rawir.pulse = (buffer[cnt] & 0x80) == 0; 5162306a36Sopenharmony_ci rawir.duration = ((buffer[cnt] & 0x7f) + 5262306a36Sopenharmony_ci (rawir.pulse ? 0 : -1)) * 5362306a36Sopenharmony_ci rc_dev->rx_resolution; 5462306a36Sopenharmony_ci ir_raw_event_store_with_filter(rc_dev, &rawir); 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic void smi_ir_decode(struct smi_rc *ir) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct smi_dev *dev = ir->dev; 6262306a36Sopenharmony_ci struct rc_dev *rc_dev = ir->rc_dev; 6362306a36Sopenharmony_ci u32 control, data; 6462306a36Sopenharmony_ci u8 index, ir_count, read_loop; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci control = smi_read(IR_Init_Reg); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci dev_dbg(&rc_dev->dev, "ircontrol: 0x%08x\n", control); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (control & rbIRVld) { 7162306a36Sopenharmony_ci ir_count = (u8)smi_read(IR_Data_Cnt); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci dev_dbg(&rc_dev->dev, "ircount %d\n", ir_count); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci read_loop = ir_count / 4; 7662306a36Sopenharmony_ci if (ir_count % 4) 7762306a36Sopenharmony_ci read_loop += 1; 7862306a36Sopenharmony_ci for (index = 0; index < read_loop; index++) { 7962306a36Sopenharmony_ci data = smi_read(IR_DATA_BUFFER_BASE + (index * 4)); 8062306a36Sopenharmony_ci dev_dbg(&rc_dev->dev, "IRData 0x%08x\n", data); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci ir->irData[index * 4 + 0] = (u8)(data); 8362306a36Sopenharmony_ci ir->irData[index * 4 + 1] = (u8)(data >> 8); 8462306a36Sopenharmony_ci ir->irData[index * 4 + 2] = (u8)(data >> 16); 8562306a36Sopenharmony_ci ir->irData[index * 4 + 3] = (u8)(data >> 24); 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci smi_raw_process(rc_dev, ir->irData, ir_count); 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (control & rbIRhighidle) { 9162306a36Sopenharmony_ci struct ir_raw_event rawir = {}; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci dev_dbg(&rc_dev->dev, "high idle\n"); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci rawir.pulse = 0; 9662306a36Sopenharmony_ci rawir.duration = SMI_SAMPLE_PERIOD * SMI_SAMPLE_IDLEMIN; 9762306a36Sopenharmony_ci ir_raw_event_store_with_filter(rc_dev, &rawir); 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci smi_set(IR_Init_Reg, rbIRVld); 10162306a36Sopenharmony_ci ir_raw_event_handle(rc_dev); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* ir functions call by main driver.*/ 10562306a36Sopenharmony_ciint smi_ir_irq(struct smi_rc *ir, u32 int_status) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci int handled = 0; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (int_status & IR_X_INT) { 11062306a36Sopenharmony_ci smi_ir_disableInterrupt(ir); 11162306a36Sopenharmony_ci smi_ir_clearInterrupt(ir); 11262306a36Sopenharmony_ci smi_ir_decode(ir); 11362306a36Sopenharmony_ci smi_ir_enableInterrupt(ir); 11462306a36Sopenharmony_ci handled = 1; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci return handled; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_civoid smi_ir_start(struct smi_rc *ir) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci struct smi_dev *dev = ir->dev; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci smi_write(IR_Idle_Cnt_Low, 12462306a36Sopenharmony_ci (((SMI_SAMPLE_PERIOD - 1) & 0xFFFF) << 16) | 12562306a36Sopenharmony_ci (SMI_SAMPLE_IDLEMIN & 0xFFFF)); 12662306a36Sopenharmony_ci msleep(20); 12762306a36Sopenharmony_ci smi_set(IR_Init_Reg, rbIRen | rbIRhighidle); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci smi_ir_enableInterrupt(ir); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ciint smi_ir_init(struct smi_dev *dev) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci int ret; 13562306a36Sopenharmony_ci struct rc_dev *rc_dev; 13662306a36Sopenharmony_ci struct smi_rc *ir = &dev->ir; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci rc_dev = rc_allocate_device(RC_DRIVER_IR_RAW); 13962306a36Sopenharmony_ci if (!rc_dev) 14062306a36Sopenharmony_ci return -ENOMEM; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* init input device */ 14362306a36Sopenharmony_ci snprintf(ir->device_name, sizeof(ir->device_name), "IR (%s)", 14462306a36Sopenharmony_ci dev->info->name); 14562306a36Sopenharmony_ci snprintf(ir->input_phys, sizeof(ir->input_phys), "pci-%s/ir0", 14662306a36Sopenharmony_ci pci_name(dev->pci_dev)); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci rc_dev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER; 14962306a36Sopenharmony_ci rc_dev->driver_name = "SMI_PCIe"; 15062306a36Sopenharmony_ci rc_dev->input_phys = ir->input_phys; 15162306a36Sopenharmony_ci rc_dev->device_name = ir->device_name; 15262306a36Sopenharmony_ci rc_dev->input_id.bustype = BUS_PCI; 15362306a36Sopenharmony_ci rc_dev->input_id.version = 1; 15462306a36Sopenharmony_ci rc_dev->input_id.vendor = dev->pci_dev->subsystem_vendor; 15562306a36Sopenharmony_ci rc_dev->input_id.product = dev->pci_dev->subsystem_device; 15662306a36Sopenharmony_ci rc_dev->dev.parent = &dev->pci_dev->dev; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci rc_dev->map_name = dev->info->rc_map; 15962306a36Sopenharmony_ci rc_dev->timeout = SMI_SAMPLE_PERIOD * SMI_SAMPLE_IDLEMIN; 16062306a36Sopenharmony_ci rc_dev->rx_resolution = SMI_SAMPLE_PERIOD; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci ir->rc_dev = rc_dev; 16362306a36Sopenharmony_ci ir->dev = dev; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci smi_ir_disableInterrupt(ir); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci ret = rc_register_device(rc_dev); 16862306a36Sopenharmony_ci if (ret) 16962306a36Sopenharmony_ci goto ir_err; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci return 0; 17262306a36Sopenharmony_ciir_err: 17362306a36Sopenharmony_ci rc_free_device(rc_dev); 17462306a36Sopenharmony_ci return ret; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_civoid smi_ir_exit(struct smi_dev *dev) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci struct smi_rc *ir = &dev->ir; 18062306a36Sopenharmony_ci struct rc_dev *rc_dev = ir->rc_dev; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci rc_unregister_device(rc_dev); 18362306a36Sopenharmony_ci smi_ir_stop(ir); 18462306a36Sopenharmony_ci ir->rc_dev = NULL; 18562306a36Sopenharmony_ci} 186