1/* 2 * Copyright (C) 2010 Bluecherry, LLC www.bluecherrydvr.com 3 * Copyright (C) 2010 Ben Collins <bcollins@bluecherry.net> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 */ 19 20#include <linux/kernel.h> 21#include <linux/module.h> 22#include <linux/pci.h> 23#include <linux/interrupt.h> 24#include <linux/videodev2.h> 25 26#include "solo6010.h" 27#include "solo6010-tw28.h" 28 29MODULE_DESCRIPTION("Softlogic 6010 MP4 Encoder/Decoder V4L2/ALSA Driver"); 30MODULE_AUTHOR("Ben Collins <bcollins@bluecherry.net>"); 31MODULE_VERSION(SOLO6010_VERSION); 32MODULE_LICENSE("GPL"); 33 34void solo6010_irq_on(struct solo6010_dev *solo_dev, u32 mask) 35{ 36 solo_dev->irq_mask |= mask; 37 solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask); 38} 39 40void solo6010_irq_off(struct solo6010_dev *solo_dev, u32 mask) 41{ 42 solo_dev->irq_mask &= ~mask; 43 solo_reg_write(solo_dev, SOLO_IRQ_ENABLE, solo_dev->irq_mask); 44} 45 46static irqreturn_t solo6010_isr(int irq, void *data) 47{ 48 struct solo6010_dev *solo_dev = data; 49 u32 status; 50 int i; 51 52 status = solo_reg_read(solo_dev, SOLO_IRQ_STAT); 53 if (!status) 54 return IRQ_NONE; 55 56 if (status & ~solo_dev->irq_mask) { 57 solo_reg_write(solo_dev, SOLO_IRQ_STAT, 58 status & ~solo_dev->irq_mask); 59 status &= solo_dev->irq_mask; 60 } 61 62 if (status & SOLO_IRQ_PCI_ERR) { 63 u32 err = solo_reg_read(solo_dev, SOLO_PCI_ERR); 64 solo_p2m_error_isr(solo_dev, err); 65 solo_reg_write(solo_dev, SOLO_IRQ_STAT, SOLO_IRQ_PCI_ERR); 66 } 67 68 for (i = 0; i < SOLO_NR_P2M; i++) 69 if (status & SOLO_IRQ_P2M(i)) 70 solo_p2m_isr(solo_dev, i); 71 72 if (status & SOLO_IRQ_IIC) 73 solo_i2c_isr(solo_dev); 74 75 if (status & SOLO_IRQ_VIDEO_IN) 76 solo_video_in_isr(solo_dev); 77 78 /* Call this first so enc gets detected flag set */ 79 if (status & SOLO_IRQ_MOTION) 80 solo_motion_isr(solo_dev); 81 82 if (status & SOLO_IRQ_ENCODER) 83 solo_enc_v4l2_isr(solo_dev); 84 85 if (status & SOLO_IRQ_G723) 86 solo_g723_isr(solo_dev); 87 88 return IRQ_HANDLED; 89} 90 91static void free_solo_dev(struct solo6010_dev *solo_dev) 92{ 93 struct pci_dev *pdev; 94 95 if (!solo_dev) 96 return; 97 98 pdev = solo_dev->pdev; 99 100 /* If we never initialized the PCI device, then nothing else 101 * below here needs cleanup */ 102 if (!pdev) { 103 kfree(solo_dev); 104 return; 105 } 106 107 /* Bring down the sub-devices first */ 108 solo_g723_exit(solo_dev); 109 solo_enc_v4l2_exit(solo_dev); 110 solo_enc_exit(solo_dev); 111 solo_v4l2_exit(solo_dev); 112 solo_disp_exit(solo_dev); 113 solo_gpio_exit(solo_dev); 114 solo_p2m_exit(solo_dev); 115 solo_i2c_exit(solo_dev); 116 117 /* Now cleanup the PCI device */ 118 if (solo_dev->reg_base) { 119 solo6010_irq_off(solo_dev, ~0); 120 pci_iounmap(pdev, solo_dev->reg_base); 121 free_irq(pdev->irq, solo_dev); 122 } 123 124 pci_release_regions(pdev); 125 pci_disable_device(pdev); 126 pci_set_drvdata(pdev, NULL); 127 128 kfree(solo_dev); 129} 130 131static int __devinit solo6010_pci_probe(struct pci_dev *pdev, 132 const struct pci_device_id *id) 133{ 134 struct solo6010_dev *solo_dev; 135 int ret; 136 int sdram; 137 u8 chip_id; 138 139 if ((solo_dev = kzalloc(sizeof(*solo_dev), GFP_KERNEL)) == NULL) 140 return -ENOMEM; 141 142 solo_dev->pdev = pdev; 143 spin_lock_init(&solo_dev->reg_io_lock); 144 pci_set_drvdata(pdev, solo_dev); 145 146 if ((ret = pci_enable_device(pdev))) 147 goto fail_probe; 148 149 pci_set_master(pdev); 150 151 if ((ret = pci_request_regions(pdev, SOLO6010_NAME))) 152 goto fail_probe; 153 154 if ((solo_dev->reg_base = pci_ioremap_bar(pdev, 0)) == NULL) { 155 ret = -ENOMEM; 156 goto fail_probe; 157 } 158 159 chip_id = solo_reg_read(solo_dev, SOLO_CHIP_OPTION) & 160 SOLO_CHIP_ID_MASK; 161 switch (chip_id) { 162 case 7: 163 solo_dev->nr_chans = 16; 164 solo_dev->nr_ext = 5; 165 break; 166 case 6: 167 solo_dev->nr_chans = 8; 168 solo_dev->nr_ext = 2; 169 break; 170 default: 171 dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, " 172 "defaulting to 4 channels\n", 173 chip_id); 174 case 5: 175 solo_dev->nr_chans = 4; 176 solo_dev->nr_ext = 1; 177 } 178 179 /* Disable all interrupts to start */ 180 solo6010_irq_off(solo_dev, ~0); 181 182 /* Initial global settings */ 183 solo_reg_write(solo_dev, SOLO_SYS_CFG, SOLO_SYS_CFG_SDRAM64BIT | 184 SOLO_SYS_CFG_INPUTDIV(25) | 185 SOLO_SYS_CFG_FEEDBACKDIV((SOLO_CLOCK_MHZ * 2) - 2) | 186 SOLO_SYS_CFG_OUTDIV(3)); 187 solo_reg_write(solo_dev, SOLO_TIMER_CLOCK_NUM, SOLO_CLOCK_MHZ - 1); 188 189 /* PLL locking time of 1ms */ 190 mdelay(1); 191 192 ret = request_irq(pdev->irq, solo6010_isr, IRQF_SHARED, SOLO6010_NAME, 193 solo_dev); 194 if (ret) 195 goto fail_probe; 196 197 /* Handle this from the start */ 198 solo6010_irq_on(solo_dev, SOLO_IRQ_PCI_ERR); 199 200 if ((ret = solo_i2c_init(solo_dev))) 201 goto fail_probe; 202 203 /* Setup the DMA engine */ 204 sdram = (solo_dev->nr_chans >= 8) ? 2 : 1; 205 solo_reg_write(solo_dev, SOLO_DMA_CTRL, 206 SOLO_DMA_CTRL_REFRESH_CYCLE(1) | 207 SOLO_DMA_CTRL_SDRAM_SIZE(sdram) | 208 SOLO_DMA_CTRL_SDRAM_CLK_INVERT | 209 SOLO_DMA_CTRL_READ_CLK_SELECT | 210 SOLO_DMA_CTRL_LATENCY(1)); 211 212 if ((ret = solo_p2m_init(solo_dev))) 213 goto fail_probe; 214 215 if ((ret = solo_disp_init(solo_dev))) 216 goto fail_probe; 217 218 if ((ret = solo_gpio_init(solo_dev))) 219 goto fail_probe; 220 221 if ((ret = solo_tw28_init(solo_dev))) 222 goto fail_probe; 223 224 if ((ret = solo_v4l2_init(solo_dev))) 225 goto fail_probe; 226 227 if ((ret = solo_enc_init(solo_dev))) 228 goto fail_probe; 229 230 if ((ret = solo_enc_v4l2_init(solo_dev))) 231 goto fail_probe; 232 233 if ((ret = solo_g723_init(solo_dev))) 234 goto fail_probe; 235 236 return 0; 237 238fail_probe: 239 free_solo_dev(solo_dev); 240 return ret; 241} 242 243static void __devexit solo6010_pci_remove(struct pci_dev *pdev) 244{ 245 struct solo6010_dev *solo_dev = pci_get_drvdata(pdev); 246 247 free_solo_dev(solo_dev); 248} 249 250static struct pci_device_id solo6010_id_table[] = { 251 {PCI_DEVICE(PCI_VENDOR_ID_SOFTLOGIC, PCI_DEVICE_ID_SOLO6010)}, 252 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_4)}, 253 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_9)}, 254 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_NEUSOLO_16)}, 255 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_COMMSOLO_4)}, 256 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_COMMSOLO_9)}, 257 {PCI_DEVICE(PCI_VENDOR_ID_BLUECHERRY, PCI_DEVICE_ID_COMMSOLO_16)}, 258 {0,} 259}; 260 261MODULE_DEVICE_TABLE(pci, solo6010_id_table); 262 263static struct pci_driver solo6010_pci_driver = { 264 .name = SOLO6010_NAME, 265 .id_table = solo6010_id_table, 266 .probe = solo6010_pci_probe, 267 .remove = solo6010_pci_remove, 268}; 269 270static int __init solo6010_module_init(void) 271{ 272 return pci_register_driver(&solo6010_pci_driver); 273} 274 275static void __exit solo6010_module_exit(void) 276{ 277 pci_unregister_driver(&solo6010_pci_driver); 278} 279 280module_init(solo6010_module_init); 281module_exit(solo6010_module_exit); 282