162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * cobalt driver initialization and card probing 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Derived from cx18-driver.c 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright 2012-2015 Cisco Systems, Inc. and/or its affiliates. 862306a36Sopenharmony_ci * All rights reserved. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/bitfield.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <media/i2c/adv7604.h> 1462306a36Sopenharmony_ci#include <media/i2c/adv7842.h> 1562306a36Sopenharmony_ci#include <media/i2c/adv7511.h> 1662306a36Sopenharmony_ci#include <media/v4l2-event.h> 1762306a36Sopenharmony_ci#include <media/v4l2-ctrls.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "cobalt-driver.h" 2062306a36Sopenharmony_ci#include "cobalt-irq.h" 2162306a36Sopenharmony_ci#include "cobalt-i2c.h" 2262306a36Sopenharmony_ci#include "cobalt-v4l2.h" 2362306a36Sopenharmony_ci#include "cobalt-flash.h" 2462306a36Sopenharmony_ci#include "cobalt-alsa.h" 2562306a36Sopenharmony_ci#include "cobalt-omnitek.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* add your revision and whatnot here */ 2862306a36Sopenharmony_cistatic const struct pci_device_id cobalt_pci_tbl[] = { 2962306a36Sopenharmony_ci {PCI_VENDOR_ID_CISCO, PCI_DEVICE_ID_COBALT, 3062306a36Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, 3162306a36Sopenharmony_ci {0,} 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, cobalt_pci_tbl); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic atomic_t cobalt_instance = ATOMIC_INIT(0); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ciint cobalt_debug; 3962306a36Sopenharmony_cimodule_param_named(debug, cobalt_debug, int, 0644); 4062306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Debug level. Default: 0\n"); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ciint cobalt_ignore_err; 4362306a36Sopenharmony_cimodule_param_named(ignore_err, cobalt_ignore_err, int, 0644); 4462306a36Sopenharmony_ciMODULE_PARM_DESC(ignore_err, 4562306a36Sopenharmony_ci "If set then ignore missing i2c adapters/receivers. Default: 0\n"); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ciMODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com> & Morten Hestnes"); 4862306a36Sopenharmony_ciMODULE_DESCRIPTION("cobalt driver"); 4962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic u8 edid[256] = { 5262306a36Sopenharmony_ci 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 5362306a36Sopenharmony_ci 0x50, 0x21, 0x32, 0x27, 0x00, 0x00, 0x00, 0x00, 5462306a36Sopenharmony_ci 0x22, 0x1a, 0x01, 0x03, 0x80, 0x30, 0x1b, 0x78, 5562306a36Sopenharmony_ci 0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 5662306a36Sopenharmony_ci 0x0f, 0x50, 0x54, 0x2f, 0xcf, 0x00, 0x31, 0x59, 5762306a36Sopenharmony_ci 0x45, 0x59, 0x61, 0x59, 0x81, 0x99, 0x01, 0x01, 5862306a36Sopenharmony_ci 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a, 5962306a36Sopenharmony_ci 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c, 6062306a36Sopenharmony_ci 0x45, 0x00, 0xe0, 0x0e, 0x11, 0x00, 0x00, 0x1e, 6162306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x55, 0x18, 6262306a36Sopenharmony_ci 0x5e, 0x11, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 6362306a36Sopenharmony_ci 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x63, 6462306a36Sopenharmony_ci 0x6f, 0x62, 0x61, 0x6c, 0x74, 0x0a, 0x20, 0x20, 6562306a36Sopenharmony_ci 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x10, 6662306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 6762306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x9d, 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci 0x02, 0x03, 0x1f, 0xf1, 0x4a, 0x10, 0x1f, 0x04, 7062306a36Sopenharmony_ci 0x13, 0x22, 0x21, 0x20, 0x02, 0x11, 0x01, 0x23, 7162306a36Sopenharmony_ci 0x09, 0x07, 0x07, 0x68, 0x03, 0x0c, 0x00, 0x10, 7262306a36Sopenharmony_ci 0x00, 0x00, 0x22, 0x0f, 0xe2, 0x00, 0xca, 0x00, 7362306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 7462306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 7562306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 7662306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 7762306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 7862306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 7962306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 8062306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 8162306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 8262306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 8362306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 8462306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 8562306a36Sopenharmony_ci}; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic void cobalt_set_interrupt(struct cobalt *cobalt, bool enable) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci if (enable) { 9062306a36Sopenharmony_ci unsigned irqs = COBALT_SYSSTAT_VI0_INT1_MSK | 9162306a36Sopenharmony_ci COBALT_SYSSTAT_VI1_INT1_MSK | 9262306a36Sopenharmony_ci COBALT_SYSSTAT_VI2_INT1_MSK | 9362306a36Sopenharmony_ci COBALT_SYSSTAT_VI3_INT1_MSK | 9462306a36Sopenharmony_ci COBALT_SYSSTAT_VI0_INT2_MSK | 9562306a36Sopenharmony_ci COBALT_SYSSTAT_VI1_INT2_MSK | 9662306a36Sopenharmony_ci COBALT_SYSSTAT_VI2_INT2_MSK | 9762306a36Sopenharmony_ci COBALT_SYSSTAT_VI3_INT2_MSK | 9862306a36Sopenharmony_ci COBALT_SYSSTAT_VI0_LOST_DATA_MSK | 9962306a36Sopenharmony_ci COBALT_SYSSTAT_VI1_LOST_DATA_MSK | 10062306a36Sopenharmony_ci COBALT_SYSSTAT_VI2_LOST_DATA_MSK | 10162306a36Sopenharmony_ci COBALT_SYSSTAT_VI3_LOST_DATA_MSK | 10262306a36Sopenharmony_ci COBALT_SYSSTAT_AUD_IN_LOST_DATA_MSK; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (cobalt->have_hsma_rx) 10562306a36Sopenharmony_ci irqs |= COBALT_SYSSTAT_VIHSMA_INT1_MSK | 10662306a36Sopenharmony_ci COBALT_SYSSTAT_VIHSMA_INT2_MSK | 10762306a36Sopenharmony_ci COBALT_SYSSTAT_VIHSMA_LOST_DATA_MSK; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (cobalt->have_hsma_tx) 11062306a36Sopenharmony_ci irqs |= COBALT_SYSSTAT_VOHSMA_INT1_MSK | 11162306a36Sopenharmony_ci COBALT_SYSSTAT_VOHSMA_LOST_DATA_MSK | 11262306a36Sopenharmony_ci COBALT_SYSSTAT_AUD_OUT_LOST_DATA_MSK; 11362306a36Sopenharmony_ci /* Clear any existing interrupts */ 11462306a36Sopenharmony_ci cobalt_write_bar1(cobalt, COBALT_SYS_STAT_EDGE, 0xffffffff); 11562306a36Sopenharmony_ci /* PIO Core interrupt mask register. 11662306a36Sopenharmony_ci Enable ADV7604 INT1 interrupts */ 11762306a36Sopenharmony_ci cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK, irqs); 11862306a36Sopenharmony_ci } else { 11962306a36Sopenharmony_ci /* Disable all ADV7604 interrupts */ 12062306a36Sopenharmony_ci cobalt_write_bar1(cobalt, COBALT_SYS_STAT_MASK, 0); 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic unsigned cobalt_get_sd_nr(struct v4l2_subdev *sd) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct cobalt *cobalt = to_cobalt(sd->v4l2_dev); 12762306a36Sopenharmony_ci unsigned i; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci for (i = 0; i < COBALT_NUM_NODES; i++) 13062306a36Sopenharmony_ci if (sd == cobalt->streams[i].sd) 13162306a36Sopenharmony_ci return i; 13262306a36Sopenharmony_ci cobalt_err("Invalid adv7604 subdev pointer!\n"); 13362306a36Sopenharmony_ci return 0; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic void cobalt_notify(struct v4l2_subdev *sd, 13762306a36Sopenharmony_ci unsigned int notification, void *arg) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct cobalt *cobalt = to_cobalt(sd->v4l2_dev); 14062306a36Sopenharmony_ci unsigned sd_nr = cobalt_get_sd_nr(sd); 14162306a36Sopenharmony_ci struct cobalt_stream *s = &cobalt->streams[sd_nr]; 14262306a36Sopenharmony_ci bool hotplug = arg ? *((int *)arg) : false; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (s->is_output) 14562306a36Sopenharmony_ci return; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci switch (notification) { 14862306a36Sopenharmony_ci case ADV76XX_HOTPLUG: 14962306a36Sopenharmony_ci cobalt_s_bit_sysctrl(cobalt, 15062306a36Sopenharmony_ci COBALT_SYS_CTRL_HPD_TO_CONNECTOR_BIT(sd_nr), hotplug); 15162306a36Sopenharmony_ci cobalt_dbg(1, "Set hotplug for adv %d to %d\n", sd_nr, hotplug); 15262306a36Sopenharmony_ci break; 15362306a36Sopenharmony_ci case V4L2_DEVICE_NOTIFY_EVENT: 15462306a36Sopenharmony_ci cobalt_dbg(1, "Format changed for adv %d\n", sd_nr); 15562306a36Sopenharmony_ci v4l2_event_queue(&s->vdev, arg); 15662306a36Sopenharmony_ci break; 15762306a36Sopenharmony_ci default: 15862306a36Sopenharmony_ci break; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic int get_payload_size(u16 code) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci switch (code) { 16562306a36Sopenharmony_ci case 0: return 128; 16662306a36Sopenharmony_ci case 1: return 256; 16762306a36Sopenharmony_ci case 2: return 512; 16862306a36Sopenharmony_ci case 3: return 1024; 16962306a36Sopenharmony_ci case 4: return 2048; 17062306a36Sopenharmony_ci case 5: return 4096; 17162306a36Sopenharmony_ci default: return 0; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci return 0; 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic const char *get_link_speed(u16 stat) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci switch (stat & PCI_EXP_LNKSTA_CLS) { 17962306a36Sopenharmony_ci case 1: return "2.5 Gbit/s"; 18062306a36Sopenharmony_ci case 2: return "5 Gbit/s"; 18162306a36Sopenharmony_ci case 3: return "10 Gbit/s"; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci return "Unknown speed"; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_civoid cobalt_pcie_status_show(struct cobalt *cobalt) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci struct pci_dev *pci_dev = cobalt->pci_dev; 18962306a36Sopenharmony_ci struct pci_dev *pci_bus_dev = cobalt->pci_dev->bus->self; 19062306a36Sopenharmony_ci u32 capa; 19162306a36Sopenharmony_ci u16 stat, ctrl; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (!pci_is_pcie(pci_dev) || !pci_is_pcie(pci_bus_dev)) 19462306a36Sopenharmony_ci return; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* Device */ 19762306a36Sopenharmony_ci pcie_capability_read_dword(pci_dev, PCI_EXP_DEVCAP, &capa); 19862306a36Sopenharmony_ci pcie_capability_read_word(pci_dev, PCI_EXP_DEVCTL, &ctrl); 19962306a36Sopenharmony_ci pcie_capability_read_word(pci_dev, PCI_EXP_DEVSTA, &stat); 20062306a36Sopenharmony_ci cobalt_info("PCIe device capability 0x%08x: Max payload %d\n", 20162306a36Sopenharmony_ci capa, get_payload_size(capa & PCI_EXP_DEVCAP_PAYLOAD)); 20262306a36Sopenharmony_ci cobalt_info("PCIe device control 0x%04x: Max payload %d. Max read request %d\n", 20362306a36Sopenharmony_ci ctrl, 20462306a36Sopenharmony_ci get_payload_size((ctrl & PCI_EXP_DEVCTL_PAYLOAD) >> 5), 20562306a36Sopenharmony_ci get_payload_size((ctrl & PCI_EXP_DEVCTL_READRQ) >> 12)); 20662306a36Sopenharmony_ci cobalt_info("PCIe device status 0x%04x\n", stat); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* Link */ 20962306a36Sopenharmony_ci pcie_capability_read_dword(pci_dev, PCI_EXP_LNKCAP, &capa); 21062306a36Sopenharmony_ci pcie_capability_read_word(pci_dev, PCI_EXP_LNKCTL, &ctrl); 21162306a36Sopenharmony_ci pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &stat); 21262306a36Sopenharmony_ci cobalt_info("PCIe link capability 0x%08x: %s per lane and %u lanes\n", 21362306a36Sopenharmony_ci capa, get_link_speed(capa), 21462306a36Sopenharmony_ci FIELD_GET(PCI_EXP_LNKCAP_MLW, capa)); 21562306a36Sopenharmony_ci cobalt_info("PCIe link control 0x%04x\n", ctrl); 21662306a36Sopenharmony_ci cobalt_info("PCIe link status 0x%04x: %s per lane and %u lanes\n", 21762306a36Sopenharmony_ci stat, get_link_speed(stat), 21862306a36Sopenharmony_ci FIELD_GET(PCI_EXP_LNKSTA_NLW, stat)); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci /* Bus */ 22162306a36Sopenharmony_ci pcie_capability_read_dword(pci_bus_dev, PCI_EXP_LNKCAP, &capa); 22262306a36Sopenharmony_ci cobalt_info("PCIe bus link capability 0x%08x: %s per lane and %u lanes\n", 22362306a36Sopenharmony_ci capa, get_link_speed(capa), 22462306a36Sopenharmony_ci FIELD_GET(PCI_EXP_LNKCAP_MLW, capa)); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* Slot */ 22762306a36Sopenharmony_ci pcie_capability_read_dword(pci_dev, PCI_EXP_SLTCAP, &capa); 22862306a36Sopenharmony_ci pcie_capability_read_word(pci_dev, PCI_EXP_SLTCTL, &ctrl); 22962306a36Sopenharmony_ci pcie_capability_read_word(pci_dev, PCI_EXP_SLTSTA, &stat); 23062306a36Sopenharmony_ci cobalt_info("PCIe slot capability 0x%08x\n", capa); 23162306a36Sopenharmony_ci cobalt_info("PCIe slot control 0x%04x\n", ctrl); 23262306a36Sopenharmony_ci cobalt_info("PCIe slot status 0x%04x\n", stat); 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic unsigned pcie_link_get_lanes(struct cobalt *cobalt) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci struct pci_dev *pci_dev = cobalt->pci_dev; 23862306a36Sopenharmony_ci u16 link; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (!pci_is_pcie(pci_dev)) 24162306a36Sopenharmony_ci return 0; 24262306a36Sopenharmony_ci pcie_capability_read_word(pci_dev, PCI_EXP_LNKSTA, &link); 24362306a36Sopenharmony_ci return FIELD_GET(PCI_EXP_LNKSTA_NLW, link); 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic unsigned pcie_bus_link_get_lanes(struct cobalt *cobalt) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci struct pci_dev *pci_dev = cobalt->pci_dev->bus->self; 24962306a36Sopenharmony_ci u32 link; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (!pci_is_pcie(pci_dev)) 25262306a36Sopenharmony_ci return 0; 25362306a36Sopenharmony_ci pcie_capability_read_dword(pci_dev, PCI_EXP_LNKCAP, &link); 25462306a36Sopenharmony_ci return FIELD_GET(PCI_EXP_LNKCAP_MLW, link); 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic void msi_config_show(struct cobalt *cobalt, struct pci_dev *pci_dev) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci u16 ctrl, data; 26062306a36Sopenharmony_ci u32 adrs_l, adrs_h; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci pci_read_config_word(pci_dev, 0x52, &ctrl); 26362306a36Sopenharmony_ci cobalt_info("MSI %s\n", ctrl & 1 ? "enable" : "disable"); 26462306a36Sopenharmony_ci cobalt_info("MSI multiple message: Capable %u. Enable %u\n", 26562306a36Sopenharmony_ci (1 << ((ctrl >> 1) & 7)), (1 << ((ctrl >> 4) & 7))); 26662306a36Sopenharmony_ci if (ctrl & 0x80) 26762306a36Sopenharmony_ci cobalt_info("MSI: 64-bit address capable\n"); 26862306a36Sopenharmony_ci pci_read_config_dword(pci_dev, 0x54, &adrs_l); 26962306a36Sopenharmony_ci pci_read_config_dword(pci_dev, 0x58, &adrs_h); 27062306a36Sopenharmony_ci pci_read_config_word(pci_dev, 0x5c, &data); 27162306a36Sopenharmony_ci if (ctrl & 0x80) 27262306a36Sopenharmony_ci cobalt_info("MSI: Address 0x%08x%08x. Data 0x%04x\n", 27362306a36Sopenharmony_ci adrs_h, adrs_l, data); 27462306a36Sopenharmony_ci else 27562306a36Sopenharmony_ci cobalt_info("MSI: Address 0x%08x. Data 0x%04x\n", 27662306a36Sopenharmony_ci adrs_l, data); 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic void cobalt_pci_iounmap(struct cobalt *cobalt, struct pci_dev *pci_dev) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci if (cobalt->bar0) { 28262306a36Sopenharmony_ci pci_iounmap(pci_dev, cobalt->bar0); 28362306a36Sopenharmony_ci cobalt->bar0 = NULL; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci if (cobalt->bar1) { 28662306a36Sopenharmony_ci pci_iounmap(pci_dev, cobalt->bar1); 28762306a36Sopenharmony_ci cobalt->bar1 = NULL; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic void cobalt_free_msi(struct cobalt *cobalt, struct pci_dev *pci_dev) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci free_irq(pci_dev->irq, (void *)cobalt); 29462306a36Sopenharmony_ci pci_free_irq_vectors(pci_dev); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic int cobalt_setup_pci(struct cobalt *cobalt, struct pci_dev *pci_dev, 29862306a36Sopenharmony_ci const struct pci_device_id *pci_id) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci u32 ctrl; 30162306a36Sopenharmony_ci int ret; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci cobalt_dbg(1, "enabling pci device\n"); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci ret = pci_enable_device(pci_dev); 30662306a36Sopenharmony_ci if (ret) { 30762306a36Sopenharmony_ci cobalt_err("can't enable device\n"); 30862306a36Sopenharmony_ci return ret; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci pci_set_master(pci_dev); 31162306a36Sopenharmony_ci pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &cobalt->card_rev); 31262306a36Sopenharmony_ci pci_read_config_word(pci_dev, PCI_DEVICE_ID, &cobalt->device_id); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci switch (cobalt->device_id) { 31562306a36Sopenharmony_ci case PCI_DEVICE_ID_COBALT: 31662306a36Sopenharmony_ci cobalt_info("PCI Express interface from Omnitek\n"); 31762306a36Sopenharmony_ci break; 31862306a36Sopenharmony_ci default: 31962306a36Sopenharmony_ci cobalt_info("PCI Express interface provider is unknown!\n"); 32062306a36Sopenharmony_ci break; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (pcie_link_get_lanes(cobalt) != 8) { 32462306a36Sopenharmony_ci cobalt_warn("PCI Express link width is %d lanes.\n", 32562306a36Sopenharmony_ci pcie_link_get_lanes(cobalt)); 32662306a36Sopenharmony_ci if (pcie_bus_link_get_lanes(cobalt) < 8) 32762306a36Sopenharmony_ci cobalt_warn("The current slot only supports %d lanes, for best performance 8 are needed\n", 32862306a36Sopenharmony_ci pcie_bus_link_get_lanes(cobalt)); 32962306a36Sopenharmony_ci if (pcie_link_get_lanes(cobalt) != pcie_bus_link_get_lanes(cobalt)) { 33062306a36Sopenharmony_ci cobalt_err("The card is most likely not seated correctly in the PCIe slot\n"); 33162306a36Sopenharmony_ci ret = -EIO; 33262306a36Sopenharmony_ci goto err_disable; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(64))) { 33762306a36Sopenharmony_ci ret = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32)); 33862306a36Sopenharmony_ci if (ret) { 33962306a36Sopenharmony_ci cobalt_err("no suitable DMA available\n"); 34062306a36Sopenharmony_ci goto err_disable; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci ret = pci_request_regions(pci_dev, "cobalt"); 34562306a36Sopenharmony_ci if (ret) { 34662306a36Sopenharmony_ci cobalt_err("error requesting regions\n"); 34762306a36Sopenharmony_ci goto err_disable; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci cobalt_pcie_status_show(cobalt); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci cobalt->bar0 = pci_iomap(pci_dev, 0, 0); 35362306a36Sopenharmony_ci cobalt->bar1 = pci_iomap(pci_dev, 1, 0); 35462306a36Sopenharmony_ci if (cobalt->bar1 == NULL) { 35562306a36Sopenharmony_ci cobalt->bar1 = pci_iomap(pci_dev, 2, 0); 35662306a36Sopenharmony_ci cobalt_info("64-bit BAR\n"); 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci if (!cobalt->bar0 || !cobalt->bar1) { 35962306a36Sopenharmony_ci ret = -EIO; 36062306a36Sopenharmony_ci goto err_release; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* Reset the video inputs before enabling any interrupts */ 36462306a36Sopenharmony_ci ctrl = cobalt_read_bar1(cobalt, COBALT_SYS_CTRL_BASE); 36562306a36Sopenharmony_ci cobalt_write_bar1(cobalt, COBALT_SYS_CTRL_BASE, ctrl & ~0xf00); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci /* Disable interrupts to prevent any spurious interrupts 36862306a36Sopenharmony_ci from being generated. */ 36962306a36Sopenharmony_ci cobalt_set_interrupt(cobalt, false); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (pci_alloc_irq_vectors(pci_dev, 1, 1, PCI_IRQ_MSI) < 1) { 37262306a36Sopenharmony_ci cobalt_err("Could not enable MSI\n"); 37362306a36Sopenharmony_ci ret = -EIO; 37462306a36Sopenharmony_ci goto err_release; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci msi_config_show(cobalt, pci_dev); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* Register IRQ */ 37962306a36Sopenharmony_ci if (request_irq(pci_dev->irq, cobalt_irq_handler, IRQF_SHARED, 38062306a36Sopenharmony_ci cobalt->v4l2_dev.name, (void *)cobalt)) { 38162306a36Sopenharmony_ci cobalt_err("Failed to register irq %d\n", pci_dev->irq); 38262306a36Sopenharmony_ci ret = -EIO; 38362306a36Sopenharmony_ci goto err_msi; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci omni_sg_dma_init(cobalt); 38762306a36Sopenharmony_ci return 0; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cierr_msi: 39062306a36Sopenharmony_ci pci_disable_msi(pci_dev); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cierr_release: 39362306a36Sopenharmony_ci cobalt_pci_iounmap(cobalt, pci_dev); 39462306a36Sopenharmony_ci pci_release_regions(pci_dev); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cierr_disable: 39762306a36Sopenharmony_ci pci_disable_device(cobalt->pci_dev); 39862306a36Sopenharmony_ci return ret; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic int cobalt_hdl_info_get(struct cobalt *cobalt) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci int i; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci for (i = 0; i < COBALT_HDL_INFO_SIZE; i++) 40662306a36Sopenharmony_ci cobalt->hdl_info[i] = 40762306a36Sopenharmony_ci ioread8(cobalt->bar1 + COBALT_HDL_INFO_BASE + i); 40862306a36Sopenharmony_ci cobalt->hdl_info[COBALT_HDL_INFO_SIZE - 1] = '\0'; 40962306a36Sopenharmony_ci if (strstr(cobalt->hdl_info, COBALT_HDL_SEARCH_STR)) 41062306a36Sopenharmony_ci return 0; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci return 1; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic void cobalt_stream_struct_init(struct cobalt *cobalt) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci int i; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci for (i = 0; i < COBALT_NUM_STREAMS; i++) { 42062306a36Sopenharmony_ci struct cobalt_stream *s = &cobalt->streams[i]; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci s->cobalt = cobalt; 42362306a36Sopenharmony_ci s->flags = 0; 42462306a36Sopenharmony_ci s->is_audio = false; 42562306a36Sopenharmony_ci s->is_output = false; 42662306a36Sopenharmony_ci s->is_dummy = true; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci /* The Memory DMA channels will always get a lower channel 42962306a36Sopenharmony_ci * number than the FIFO DMA. Video input should map to the 43062306a36Sopenharmony_ci * stream 0-3. The other can use stream struct from 4 and 43162306a36Sopenharmony_ci * higher */ 43262306a36Sopenharmony_ci if (i <= COBALT_HSMA_IN_NODE) { 43362306a36Sopenharmony_ci s->dma_channel = i + cobalt->first_fifo_channel; 43462306a36Sopenharmony_ci s->video_channel = i; 43562306a36Sopenharmony_ci s->dma_fifo_mask = 43662306a36Sopenharmony_ci COBALT_SYSSTAT_VI0_LOST_DATA_MSK << (4 * i); 43762306a36Sopenharmony_ci s->adv_irq_mask = 43862306a36Sopenharmony_ci COBALT_SYSSTAT_VI0_INT1_MSK << (4 * i); 43962306a36Sopenharmony_ci } else if (i >= COBALT_AUDIO_IN_STREAM && 44062306a36Sopenharmony_ci i <= COBALT_AUDIO_IN_STREAM + 4) { 44162306a36Sopenharmony_ci unsigned idx = i - COBALT_AUDIO_IN_STREAM; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci s->dma_channel = 6 + idx; 44462306a36Sopenharmony_ci s->is_audio = true; 44562306a36Sopenharmony_ci s->video_channel = idx; 44662306a36Sopenharmony_ci s->dma_fifo_mask = COBALT_SYSSTAT_AUD_IN_LOST_DATA_MSK; 44762306a36Sopenharmony_ci } else if (i == COBALT_HSMA_OUT_NODE) { 44862306a36Sopenharmony_ci s->dma_channel = 11; 44962306a36Sopenharmony_ci s->is_output = true; 45062306a36Sopenharmony_ci s->video_channel = 5; 45162306a36Sopenharmony_ci s->dma_fifo_mask = COBALT_SYSSTAT_VOHSMA_LOST_DATA_MSK; 45262306a36Sopenharmony_ci s->adv_irq_mask = COBALT_SYSSTAT_VOHSMA_INT1_MSK; 45362306a36Sopenharmony_ci } else if (i == COBALT_AUDIO_OUT_STREAM) { 45462306a36Sopenharmony_ci s->dma_channel = 12; 45562306a36Sopenharmony_ci s->is_audio = true; 45662306a36Sopenharmony_ci s->is_output = true; 45762306a36Sopenharmony_ci s->video_channel = 5; 45862306a36Sopenharmony_ci s->dma_fifo_mask = COBALT_SYSSTAT_AUD_OUT_LOST_DATA_MSK; 45962306a36Sopenharmony_ci } else { 46062306a36Sopenharmony_ci /* FIXME: Memory DMA for debug purpose */ 46162306a36Sopenharmony_ci s->dma_channel = i - COBALT_NUM_NODES; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci cobalt_info("stream #%d -> dma channel #%d <- video channel %d\n", 46462306a36Sopenharmony_ci i, s->dma_channel, s->video_channel); 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic int cobalt_subdevs_init(struct cobalt *cobalt) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci static struct adv76xx_platform_data adv7604_pdata = { 47162306a36Sopenharmony_ci .disable_pwrdnb = 1, 47262306a36Sopenharmony_ci .ain_sel = ADV7604_AIN7_8_9_NC_SYNC_3_1, 47362306a36Sopenharmony_ci .bus_order = ADV7604_BUS_ORDER_BRG, 47462306a36Sopenharmony_ci .blank_data = 1, 47562306a36Sopenharmony_ci .op_format_mode_sel = ADV7604_OP_FORMAT_MODE0, 47662306a36Sopenharmony_ci .int1_config = ADV76XX_INT1_CONFIG_ACTIVE_HIGH, 47762306a36Sopenharmony_ci .dr_str_data = ADV76XX_DR_STR_HIGH, 47862306a36Sopenharmony_ci .dr_str_clk = ADV76XX_DR_STR_HIGH, 47962306a36Sopenharmony_ci .dr_str_sync = ADV76XX_DR_STR_HIGH, 48062306a36Sopenharmony_ci .hdmi_free_run_mode = 1, 48162306a36Sopenharmony_ci .inv_vs_pol = 1, 48262306a36Sopenharmony_ci .inv_hs_pol = 1, 48362306a36Sopenharmony_ci }; 48462306a36Sopenharmony_ci static struct i2c_board_info adv7604_info = { 48562306a36Sopenharmony_ci .type = "adv7604", 48662306a36Sopenharmony_ci .addr = 0x20, 48762306a36Sopenharmony_ci .platform_data = &adv7604_pdata, 48862306a36Sopenharmony_ci }; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci struct cobalt_stream *s = cobalt->streams; 49162306a36Sopenharmony_ci int i; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci for (i = 0; i < COBALT_NUM_INPUTS; i++) { 49462306a36Sopenharmony_ci struct v4l2_subdev_format sd_fmt = { 49562306a36Sopenharmony_ci .pad = ADV7604_PAD_SOURCE, 49662306a36Sopenharmony_ci .which = V4L2_SUBDEV_FORMAT_ACTIVE, 49762306a36Sopenharmony_ci .format.code = MEDIA_BUS_FMT_YUYV8_1X16, 49862306a36Sopenharmony_ci }; 49962306a36Sopenharmony_ci struct v4l2_subdev_edid cobalt_edid = { 50062306a36Sopenharmony_ci .pad = ADV76XX_PAD_HDMI_PORT_A, 50162306a36Sopenharmony_ci .start_block = 0, 50262306a36Sopenharmony_ci .blocks = 2, 50362306a36Sopenharmony_ci .edid = edid, 50462306a36Sopenharmony_ci }; 50562306a36Sopenharmony_ci int err; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci s[i].pad_source = ADV7604_PAD_SOURCE; 50862306a36Sopenharmony_ci s[i].i2c_adap = &cobalt->i2c_adap[i]; 50962306a36Sopenharmony_ci if (s[i].i2c_adap->dev.parent == NULL) 51062306a36Sopenharmony_ci continue; 51162306a36Sopenharmony_ci cobalt_s_bit_sysctrl(cobalt, 51262306a36Sopenharmony_ci COBALT_SYS_CTRL_NRESET_TO_HDMI_BIT(i), 1); 51362306a36Sopenharmony_ci s[i].sd = v4l2_i2c_new_subdev_board(&cobalt->v4l2_dev, 51462306a36Sopenharmony_ci s[i].i2c_adap, &adv7604_info, NULL); 51562306a36Sopenharmony_ci if (!s[i].sd) { 51662306a36Sopenharmony_ci if (cobalt_ignore_err) 51762306a36Sopenharmony_ci continue; 51862306a36Sopenharmony_ci return -ENODEV; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci err = v4l2_subdev_call(s[i].sd, video, s_routing, 52162306a36Sopenharmony_ci ADV76XX_PAD_HDMI_PORT_A, 0, 0); 52262306a36Sopenharmony_ci if (err) 52362306a36Sopenharmony_ci return err; 52462306a36Sopenharmony_ci err = v4l2_subdev_call(s[i].sd, pad, set_edid, 52562306a36Sopenharmony_ci &cobalt_edid); 52662306a36Sopenharmony_ci if (err) 52762306a36Sopenharmony_ci return err; 52862306a36Sopenharmony_ci err = v4l2_subdev_call(s[i].sd, pad, set_fmt, NULL, 52962306a36Sopenharmony_ci &sd_fmt); 53062306a36Sopenharmony_ci if (err) 53162306a36Sopenharmony_ci return err; 53262306a36Sopenharmony_ci /* Reset channel video module */ 53362306a36Sopenharmony_ci cobalt_s_bit_sysctrl(cobalt, 53462306a36Sopenharmony_ci COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(i), 0); 53562306a36Sopenharmony_ci mdelay(2); 53662306a36Sopenharmony_ci cobalt_s_bit_sysctrl(cobalt, 53762306a36Sopenharmony_ci COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(i), 1); 53862306a36Sopenharmony_ci mdelay(1); 53962306a36Sopenharmony_ci s[i].is_dummy = false; 54062306a36Sopenharmony_ci cobalt->streams[i + COBALT_AUDIO_IN_STREAM].is_dummy = false; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci return 0; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cistatic int cobalt_subdevs_hsma_init(struct cobalt *cobalt) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci static struct adv7842_platform_data adv7842_pdata = { 54862306a36Sopenharmony_ci .disable_pwrdnb = 1, 54962306a36Sopenharmony_ci .ain_sel = ADV7842_AIN1_2_3_NC_SYNC_1_2, 55062306a36Sopenharmony_ci .bus_order = ADV7842_BUS_ORDER_RBG, 55162306a36Sopenharmony_ci .op_format_mode_sel = ADV7842_OP_FORMAT_MODE0, 55262306a36Sopenharmony_ci .blank_data = 1, 55362306a36Sopenharmony_ci .dr_str_data = 3, 55462306a36Sopenharmony_ci .dr_str_clk = 3, 55562306a36Sopenharmony_ci .dr_str_sync = 3, 55662306a36Sopenharmony_ci .mode = ADV7842_MODE_HDMI, 55762306a36Sopenharmony_ci .hdmi_free_run_enable = 1, 55862306a36Sopenharmony_ci .vid_std_select = ADV7842_HDMI_COMP_VID_STD_HD_1250P, 55962306a36Sopenharmony_ci .i2c_sdp_io = 0x4a, 56062306a36Sopenharmony_ci .i2c_sdp = 0x48, 56162306a36Sopenharmony_ci .i2c_cp = 0x22, 56262306a36Sopenharmony_ci .i2c_vdp = 0x24, 56362306a36Sopenharmony_ci .i2c_afe = 0x26, 56462306a36Sopenharmony_ci .i2c_hdmi = 0x34, 56562306a36Sopenharmony_ci .i2c_repeater = 0x32, 56662306a36Sopenharmony_ci .i2c_edid = 0x36, 56762306a36Sopenharmony_ci .i2c_infoframe = 0x3e, 56862306a36Sopenharmony_ci .i2c_cec = 0x40, 56962306a36Sopenharmony_ci .i2c_avlink = 0x42, 57062306a36Sopenharmony_ci }; 57162306a36Sopenharmony_ci static struct i2c_board_info adv7842_info = { 57262306a36Sopenharmony_ci .type = "adv7842", 57362306a36Sopenharmony_ci .addr = 0x20, 57462306a36Sopenharmony_ci .platform_data = &adv7842_pdata, 57562306a36Sopenharmony_ci }; 57662306a36Sopenharmony_ci struct v4l2_subdev_format sd_fmt = { 57762306a36Sopenharmony_ci .pad = ADV7842_PAD_SOURCE, 57862306a36Sopenharmony_ci .which = V4L2_SUBDEV_FORMAT_ACTIVE, 57962306a36Sopenharmony_ci .format.code = MEDIA_BUS_FMT_YUYV8_1X16, 58062306a36Sopenharmony_ci }; 58162306a36Sopenharmony_ci static struct adv7511_platform_data adv7511_pdata = { 58262306a36Sopenharmony_ci .i2c_edid = 0x7e >> 1, 58362306a36Sopenharmony_ci .i2c_cec = 0x7c >> 1, 58462306a36Sopenharmony_ci .i2c_pktmem = 0x70 >> 1, 58562306a36Sopenharmony_ci .cec_clk = 12000000, 58662306a36Sopenharmony_ci }; 58762306a36Sopenharmony_ci static struct i2c_board_info adv7511_info = { 58862306a36Sopenharmony_ci .type = "adv7511-v4l2", 58962306a36Sopenharmony_ci .addr = 0x39, /* 0x39 or 0x3d */ 59062306a36Sopenharmony_ci .platform_data = &adv7511_pdata, 59162306a36Sopenharmony_ci }; 59262306a36Sopenharmony_ci struct v4l2_subdev_edid cobalt_edid = { 59362306a36Sopenharmony_ci .pad = ADV7842_EDID_PORT_A, 59462306a36Sopenharmony_ci .start_block = 0, 59562306a36Sopenharmony_ci .blocks = 2, 59662306a36Sopenharmony_ci .edid = edid, 59762306a36Sopenharmony_ci }; 59862306a36Sopenharmony_ci struct cobalt_stream *s = &cobalt->streams[COBALT_HSMA_IN_NODE]; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci s->i2c_adap = &cobalt->i2c_adap[COBALT_NUM_ADAPTERS - 1]; 60162306a36Sopenharmony_ci if (s->i2c_adap->dev.parent == NULL) 60262306a36Sopenharmony_ci return 0; 60362306a36Sopenharmony_ci cobalt_s_bit_sysctrl(cobalt, COBALT_SYS_CTRL_NRESET_TO_HDMI_BIT(4), 1); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci s->sd = v4l2_i2c_new_subdev_board(&cobalt->v4l2_dev, 60662306a36Sopenharmony_ci s->i2c_adap, &adv7842_info, NULL); 60762306a36Sopenharmony_ci if (s->sd) { 60862306a36Sopenharmony_ci int err = v4l2_subdev_call(s->sd, pad, set_edid, &cobalt_edid); 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci if (err) 61162306a36Sopenharmony_ci return err; 61262306a36Sopenharmony_ci err = v4l2_subdev_call(s->sd, pad, set_fmt, NULL, 61362306a36Sopenharmony_ci &sd_fmt); 61462306a36Sopenharmony_ci if (err) 61562306a36Sopenharmony_ci return err; 61662306a36Sopenharmony_ci cobalt->have_hsma_rx = true; 61762306a36Sopenharmony_ci s->pad_source = ADV7842_PAD_SOURCE; 61862306a36Sopenharmony_ci s->is_dummy = false; 61962306a36Sopenharmony_ci cobalt->streams[4 + COBALT_AUDIO_IN_STREAM].is_dummy = false; 62062306a36Sopenharmony_ci /* Reset channel video module */ 62162306a36Sopenharmony_ci cobalt_s_bit_sysctrl(cobalt, 62262306a36Sopenharmony_ci COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(4), 0); 62362306a36Sopenharmony_ci mdelay(2); 62462306a36Sopenharmony_ci cobalt_s_bit_sysctrl(cobalt, 62562306a36Sopenharmony_ci COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(4), 1); 62662306a36Sopenharmony_ci mdelay(1); 62762306a36Sopenharmony_ci return err; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci cobalt_s_bit_sysctrl(cobalt, COBALT_SYS_CTRL_NRESET_TO_HDMI_BIT(4), 0); 63062306a36Sopenharmony_ci cobalt_s_bit_sysctrl(cobalt, COBALT_SYS_CTRL_PWRDN0_TO_HSMA_TX_BIT, 0); 63162306a36Sopenharmony_ci s++; 63262306a36Sopenharmony_ci s->i2c_adap = &cobalt->i2c_adap[COBALT_NUM_ADAPTERS - 1]; 63362306a36Sopenharmony_ci s->sd = v4l2_i2c_new_subdev_board(&cobalt->v4l2_dev, 63462306a36Sopenharmony_ci s->i2c_adap, &adv7511_info, NULL); 63562306a36Sopenharmony_ci if (s->sd) { 63662306a36Sopenharmony_ci /* A transmitter is hooked up, so we can set this bit */ 63762306a36Sopenharmony_ci cobalt_s_bit_sysctrl(cobalt, 63862306a36Sopenharmony_ci COBALT_SYS_CTRL_HSMA_TX_ENABLE_BIT, 1); 63962306a36Sopenharmony_ci cobalt_s_bit_sysctrl(cobalt, 64062306a36Sopenharmony_ci COBALT_SYS_CTRL_VIDEO_RX_RESETN_BIT(4), 0); 64162306a36Sopenharmony_ci cobalt_s_bit_sysctrl(cobalt, 64262306a36Sopenharmony_ci COBALT_SYS_CTRL_VIDEO_TX_RESETN_BIT, 1); 64362306a36Sopenharmony_ci cobalt->have_hsma_tx = true; 64462306a36Sopenharmony_ci v4l2_subdev_call(s->sd, core, s_power, 1); 64562306a36Sopenharmony_ci v4l2_subdev_call(s->sd, video, s_stream, 1); 64662306a36Sopenharmony_ci v4l2_subdev_call(s->sd, audio, s_stream, 1); 64762306a36Sopenharmony_ci v4l2_ctrl_s_ctrl(v4l2_ctrl_find(s->sd->ctrl_handler, 64862306a36Sopenharmony_ci V4L2_CID_DV_TX_MODE), V4L2_DV_TX_MODE_HDMI); 64962306a36Sopenharmony_ci s->is_dummy = false; 65062306a36Sopenharmony_ci cobalt->streams[COBALT_AUDIO_OUT_STREAM].is_dummy = false; 65162306a36Sopenharmony_ci return 0; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci return -ENODEV; 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic int cobalt_probe(struct pci_dev *pci_dev, 65762306a36Sopenharmony_ci const struct pci_device_id *pci_id) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci struct cobalt *cobalt; 66062306a36Sopenharmony_ci int retval = 0; 66162306a36Sopenharmony_ci int i; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* FIXME - module parameter arrays constrain max instances */ 66462306a36Sopenharmony_ci i = atomic_inc_return(&cobalt_instance) - 1; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci cobalt = kzalloc(sizeof(struct cobalt), GFP_KERNEL); 66762306a36Sopenharmony_ci if (cobalt == NULL) 66862306a36Sopenharmony_ci return -ENOMEM; 66962306a36Sopenharmony_ci cobalt->pci_dev = pci_dev; 67062306a36Sopenharmony_ci cobalt->instance = i; 67162306a36Sopenharmony_ci mutex_init(&cobalt->pci_lock); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci retval = v4l2_device_register(&pci_dev->dev, &cobalt->v4l2_dev); 67462306a36Sopenharmony_ci if (retval) { 67562306a36Sopenharmony_ci pr_err("cobalt: v4l2_device_register of card %d failed\n", 67662306a36Sopenharmony_ci cobalt->instance); 67762306a36Sopenharmony_ci kfree(cobalt); 67862306a36Sopenharmony_ci return retval; 67962306a36Sopenharmony_ci } 68062306a36Sopenharmony_ci snprintf(cobalt->v4l2_dev.name, sizeof(cobalt->v4l2_dev.name), 68162306a36Sopenharmony_ci "cobalt-%d", cobalt->instance); 68262306a36Sopenharmony_ci cobalt->v4l2_dev.notify = cobalt_notify; 68362306a36Sopenharmony_ci cobalt_info("Initializing card %d\n", cobalt->instance); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci cobalt->irq_work_queues = 68662306a36Sopenharmony_ci create_singlethread_workqueue(cobalt->v4l2_dev.name); 68762306a36Sopenharmony_ci if (cobalt->irq_work_queues == NULL) { 68862306a36Sopenharmony_ci cobalt_err("Could not create workqueue\n"); 68962306a36Sopenharmony_ci retval = -ENOMEM; 69062306a36Sopenharmony_ci goto err; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci INIT_WORK(&cobalt->irq_work_queue, cobalt_irq_work_handler); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* PCI Device Setup */ 69662306a36Sopenharmony_ci retval = cobalt_setup_pci(cobalt, pci_dev, pci_id); 69762306a36Sopenharmony_ci if (retval != 0) 69862306a36Sopenharmony_ci goto err_wq; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci /* Show HDL version info */ 70162306a36Sopenharmony_ci if (cobalt_hdl_info_get(cobalt)) 70262306a36Sopenharmony_ci cobalt_info("Not able to read the HDL info\n"); 70362306a36Sopenharmony_ci else 70462306a36Sopenharmony_ci cobalt_info("%s", cobalt->hdl_info); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci retval = cobalt_i2c_init(cobalt); 70762306a36Sopenharmony_ci if (retval) 70862306a36Sopenharmony_ci goto err_pci; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci cobalt_stream_struct_init(cobalt); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci retval = cobalt_subdevs_init(cobalt); 71362306a36Sopenharmony_ci if (retval) 71462306a36Sopenharmony_ci goto err_i2c; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci if (!(cobalt_read_bar1(cobalt, COBALT_SYS_STAT_BASE) & 71762306a36Sopenharmony_ci COBALT_SYSSTAT_HSMA_PRSNTN_MSK)) { 71862306a36Sopenharmony_ci retval = cobalt_subdevs_hsma_init(cobalt); 71962306a36Sopenharmony_ci if (retval) 72062306a36Sopenharmony_ci goto err_i2c; 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci retval = cobalt_nodes_register(cobalt); 72462306a36Sopenharmony_ci if (retval) { 72562306a36Sopenharmony_ci cobalt_err("Error %d registering device nodes\n", retval); 72662306a36Sopenharmony_ci goto err_i2c; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci cobalt_set_interrupt(cobalt, true); 72962306a36Sopenharmony_ci v4l2_device_call_all(&cobalt->v4l2_dev, 0, core, 73062306a36Sopenharmony_ci interrupt_service_routine, 0, NULL); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci cobalt_info("Initialized cobalt card\n"); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci cobalt_flash_probe(cobalt); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci return 0; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cierr_i2c: 73962306a36Sopenharmony_ci cobalt_i2c_exit(cobalt); 74062306a36Sopenharmony_ci cobalt_s_bit_sysctrl(cobalt, COBALT_SYS_CTRL_HSMA_TX_ENABLE_BIT, 0); 74162306a36Sopenharmony_cierr_pci: 74262306a36Sopenharmony_ci cobalt_free_msi(cobalt, pci_dev); 74362306a36Sopenharmony_ci cobalt_pci_iounmap(cobalt, pci_dev); 74462306a36Sopenharmony_ci pci_release_regions(cobalt->pci_dev); 74562306a36Sopenharmony_ci pci_disable_device(cobalt->pci_dev); 74662306a36Sopenharmony_cierr_wq: 74762306a36Sopenharmony_ci destroy_workqueue(cobalt->irq_work_queues); 74862306a36Sopenharmony_cierr: 74962306a36Sopenharmony_ci cobalt_err("error %d on initialization\n", retval); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci v4l2_device_unregister(&cobalt->v4l2_dev); 75262306a36Sopenharmony_ci kfree(cobalt); 75362306a36Sopenharmony_ci return retval; 75462306a36Sopenharmony_ci} 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_cistatic void cobalt_remove(struct pci_dev *pci_dev) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); 75962306a36Sopenharmony_ci struct cobalt *cobalt = to_cobalt(v4l2_dev); 76062306a36Sopenharmony_ci int i; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci cobalt_flash_remove(cobalt); 76362306a36Sopenharmony_ci cobalt_set_interrupt(cobalt, false); 76462306a36Sopenharmony_ci flush_workqueue(cobalt->irq_work_queues); 76562306a36Sopenharmony_ci cobalt_nodes_unregister(cobalt); 76662306a36Sopenharmony_ci for (i = 0; i < COBALT_NUM_ADAPTERS; i++) { 76762306a36Sopenharmony_ci struct v4l2_subdev *sd = cobalt->streams[i].sd; 76862306a36Sopenharmony_ci struct i2c_client *client; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci if (sd == NULL) 77162306a36Sopenharmony_ci continue; 77262306a36Sopenharmony_ci client = v4l2_get_subdevdata(sd); 77362306a36Sopenharmony_ci v4l2_device_unregister_subdev(sd); 77462306a36Sopenharmony_ci i2c_unregister_device(client); 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci cobalt_i2c_exit(cobalt); 77762306a36Sopenharmony_ci cobalt_free_msi(cobalt, pci_dev); 77862306a36Sopenharmony_ci cobalt_s_bit_sysctrl(cobalt, COBALT_SYS_CTRL_HSMA_TX_ENABLE_BIT, 0); 77962306a36Sopenharmony_ci cobalt_pci_iounmap(cobalt, pci_dev); 78062306a36Sopenharmony_ci pci_release_regions(cobalt->pci_dev); 78162306a36Sopenharmony_ci pci_disable_device(cobalt->pci_dev); 78262306a36Sopenharmony_ci destroy_workqueue(cobalt->irq_work_queues); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci cobalt_info("removed cobalt card\n"); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci v4l2_device_unregister(v4l2_dev); 78762306a36Sopenharmony_ci kfree(cobalt); 78862306a36Sopenharmony_ci} 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci/* define a pci_driver for card detection */ 79162306a36Sopenharmony_cistatic struct pci_driver cobalt_pci_driver = { 79262306a36Sopenharmony_ci .name = "cobalt", 79362306a36Sopenharmony_ci .id_table = cobalt_pci_tbl, 79462306a36Sopenharmony_ci .probe = cobalt_probe, 79562306a36Sopenharmony_ci .remove = cobalt_remove, 79662306a36Sopenharmony_ci}; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cimodule_pci_driver(cobalt_pci_driver); 799