Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Guillemot Maxi Radio FM 2000 PCI radio card driver for Linux
0004  * (C) 2001 Dimitromanolakis Apostolos <apdim@grecian.net>
0005  *
0006  * Based in the radio Maestro PCI driver. Actually it uses the same chip
0007  * for radio but different pci controller.
0008  *
0009  * I didn't have any specs I reversed engineered the protocol from
0010  * the windows driver (radio.dll).
0011  *
0012  * The card uses the TEA5757 chip that includes a search function but it
0013  * is useless as I haven't found any way to read back the frequency. If
0014  * anybody does please mail me.
0015  *
0016  * For the pdf file see:
0017  * http://www.nxp.com/acrobat_download2/expired_datasheets/TEA5757_5759_3.pdf
0018  *
0019  *
0020  * CHANGES:
0021  *   0.75b
0022  *     - better pci interface thanks to Francois Romieu <romieu@cogenit.fr>
0023  *
0024  *   0.75      Sun Feb  4 22:51:27 EET 2001
0025  *     - tiding up
0026  *     - removed support for multiple devices as it didn't work anyway
0027  *
0028  * BUGS:
0029  *   - card unmutes if you change frequency
0030  *
0031  * (c) 2006, 2007 by Mauro Carvalho Chehab <mchehab@kernel.org>:
0032  *  - Conversion to V4L2 API
0033  *      - Uses video_ioctl2 for parsing and to add debug support
0034  */
0035 
0036 
0037 #include <linux/module.h>
0038 #include <linux/init.h>
0039 #include <linux/ioport.h>
0040 #include <linux/delay.h>
0041 #include <linux/mutex.h>
0042 #include <linux/pci.h>
0043 #include <linux/videodev2.h>
0044 #include <linux/io.h>
0045 #include <linux/slab.h>
0046 #include <media/drv-intf/tea575x.h>
0047 #include <media/v4l2-device.h>
0048 #include <media/v4l2-ioctl.h>
0049 #include <media/v4l2-fh.h>
0050 #include <media/v4l2-ctrls.h>
0051 #include <media/v4l2-event.h>
0052 
0053 MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
0054 MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000.");
0055 MODULE_LICENSE("GPL");
0056 MODULE_VERSION("1.0.0");
0057 
0058 static int radio_nr = -1;
0059 module_param(radio_nr, int, 0644);
0060 MODULE_PARM_DESC(radio_nr, "Radio device number");
0061 
0062 /* TEA5757 pin mappings */
0063 static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16;
0064 
0065 static atomic_t maxiradio_instance = ATOMIC_INIT(0);
0066 
0067 #define PCI_VENDOR_ID_GUILLEMOT 0x5046
0068 #define PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO 0x1001
0069 
0070 struct maxiradio
0071 {
0072     struct snd_tea575x tea;
0073     struct v4l2_device v4l2_dev;
0074     struct pci_dev *pdev;
0075 
0076     u16 io; /* base of radio io */
0077 };
0078 
0079 static inline struct maxiradio *to_maxiradio(struct v4l2_device *v4l2_dev)
0080 {
0081     return container_of(v4l2_dev, struct maxiradio, v4l2_dev);
0082 }
0083 
0084 static void maxiradio_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
0085 {
0086     struct maxiradio *dev = tea->private_data;
0087     u8 bits = 0;
0088 
0089     bits |= (pins & TEA575X_DATA) ? data : 0;
0090     bits |= (pins & TEA575X_CLK)  ? clk  : 0;
0091     bits |= (pins & TEA575X_WREN) ? wren : 0;
0092     bits |= power;
0093 
0094     outb(bits, dev->io);
0095 }
0096 
0097 /* Note: this card cannot read out the data of the shift registers,
0098    only the mono/stereo pin works. */
0099 static u8 maxiradio_tea575x_get_pins(struct snd_tea575x *tea)
0100 {
0101     struct maxiradio *dev = tea->private_data;
0102     u8 bits = inb(dev->io);
0103 
0104     return  ((bits & data) ? TEA575X_DATA : 0) |
0105         ((bits & mo_st) ? TEA575X_MOST : 0);
0106 }
0107 
0108 static void maxiradio_tea575x_set_direction(struct snd_tea575x *tea, bool output)
0109 {
0110 }
0111 
0112 static const struct snd_tea575x_ops maxiradio_tea_ops = {
0113     .set_pins = maxiradio_tea575x_set_pins,
0114     .get_pins = maxiradio_tea575x_get_pins,
0115     .set_direction = maxiradio_tea575x_set_direction,
0116 };
0117 
0118 static int maxiradio_probe(struct pci_dev *pdev,
0119                const struct pci_device_id *ent)
0120 {
0121     struct maxiradio *dev;
0122     struct v4l2_device *v4l2_dev;
0123     int retval = -ENOMEM;
0124 
0125     dev = kzalloc(sizeof(*dev), GFP_KERNEL);
0126     if (dev == NULL) {
0127         dev_err(&pdev->dev, "not enough memory\n");
0128         return -ENOMEM;
0129     }
0130 
0131     v4l2_dev = &dev->v4l2_dev;
0132     v4l2_device_set_name(v4l2_dev, "maxiradio", &maxiradio_instance);
0133 
0134     retval = v4l2_device_register(&pdev->dev, v4l2_dev);
0135     if (retval < 0) {
0136         v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
0137         goto errfr;
0138     }
0139     dev->tea.private_data = dev;
0140     dev->tea.ops = &maxiradio_tea_ops;
0141     /* The data pin cannot be read. This may be a hardware limitation, or
0142        we just don't know how to read it. */
0143     dev->tea.cannot_read_data = true;
0144     dev->tea.v4l2_dev = v4l2_dev;
0145     dev->tea.radio_nr = radio_nr;
0146     strscpy(dev->tea.card, "Maxi Radio FM2000", sizeof(dev->tea.card));
0147 
0148     retval = -ENODEV;
0149 
0150     if (!request_region(pci_resource_start(pdev, 0),
0151                pci_resource_len(pdev, 0), v4l2_dev->name)) {
0152         dev_err(&pdev->dev, "can't reserve I/O ports\n");
0153         goto err_hdl;
0154     }
0155 
0156     if (pci_enable_device(pdev))
0157         goto err_out_free_region;
0158 
0159     dev->io = pci_resource_start(pdev, 0);
0160     if (snd_tea575x_init(&dev->tea, THIS_MODULE)) {
0161         printk(KERN_ERR "radio-maxiradio: Unable to detect TEA575x tuner\n");
0162         goto err_out_free_region;
0163     }
0164     return 0;
0165 
0166 err_out_free_region:
0167     release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
0168 err_hdl:
0169     v4l2_device_unregister(v4l2_dev);
0170 errfr:
0171     kfree(dev);
0172     return retval;
0173 }
0174 
0175 static void maxiradio_remove(struct pci_dev *pdev)
0176 {
0177     struct v4l2_device *v4l2_dev = pci_get_drvdata(pdev);
0178     struct maxiradio *dev = to_maxiradio(v4l2_dev);
0179 
0180     snd_tea575x_exit(&dev->tea);
0181     /* Turn off power */
0182     outb(0, dev->io);
0183     v4l2_device_unregister(v4l2_dev);
0184     release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
0185     kfree(dev);
0186 }
0187 
0188 static const struct pci_device_id maxiradio_pci_tbl[] = {
0189     { PCI_VENDOR_ID_GUILLEMOT, PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO,
0190         PCI_ANY_ID, PCI_ANY_ID, },
0191     { 0 }
0192 };
0193 
0194 MODULE_DEVICE_TABLE(pci, maxiradio_pci_tbl);
0195 
0196 static struct pci_driver maxiradio_driver = {
0197     .name       = "radio-maxiradio",
0198     .id_table   = maxiradio_pci_tbl,
0199     .probe      = maxiradio_probe,
0200     .remove     = maxiradio_remove,
0201 };
0202 
0203 module_pci_driver(maxiradio_driver);