cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

radio-sf16fmr2.c (8818B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* SF16-FMR2 and SF16-FMD2 radio driver for Linux
      3 * Copyright (c) 2011 Ondrej Zary
      4 *
      5 * Original driver was (c) 2000-2002 Ziglio Frediano, freddy77@angelfire.com
      6 * but almost nothing remained here after conversion to generic TEA575x
      7 * implementation
      8 */
      9
     10#include <linux/delay.h>
     11#include <linux/module.h>	/* Modules			*/
     12#include <linux/init.h>		/* Initdata			*/
     13#include <linux/slab.h>
     14#include <linux/ioport.h>	/* request_region		*/
     15#include <linux/io.h>		/* outb, outb_p			*/
     16#include <linux/isa.h>
     17#include <linux/pnp.h>
     18#include <media/drv-intf/tea575x.h>
     19
     20MODULE_AUTHOR("Ondrej Zary");
     21MODULE_DESCRIPTION("MediaForte SF16-FMR2 and SF16-FMD2 FM radio card driver");
     22MODULE_LICENSE("GPL");
     23
     24/* these cards can only use two different ports (0x384 and 0x284) */
     25#define FMR2_MAX 2
     26
     27static int radio_nr[FMR2_MAX] = { [0 ... (FMR2_MAX - 1)] = -1 };
     28module_param_array(radio_nr, int, NULL, 0444);
     29MODULE_PARM_DESC(radio_nr, "Radio device numbers");
     30
     31struct fmr2 {
     32	int io;
     33	struct v4l2_device v4l2_dev;
     34	struct snd_tea575x tea;
     35	struct v4l2_ctrl *volume;
     36	struct v4l2_ctrl *balance;
     37	bool is_fmd2;
     38};
     39
     40static int num_fmr2_cards;
     41static struct fmr2 *fmr2_cards[FMR2_MAX];
     42static bool isa_registered;
     43static bool pnp_registered;
     44
     45/* the port is hardwired on SF16-FMR2 */
     46#define FMR2_PORT	0x384
     47
     48/* TEA575x tuner pins */
     49#define STR_DATA	(1 << 0)
     50#define STR_CLK		(1 << 1)
     51#define STR_WREN	(1 << 2)
     52#define STR_MOST	(1 << 3)
     53/* PT2254A/TC9154A volume control pins */
     54#define PT_ST		(1 << 4)
     55#define PT_CK		(1 << 5)
     56#define PT_DATA		(1 << 6)
     57/* volume control presence pin */
     58#define FMR2_HASVOL	(1 << 7)
     59
     60static void fmr2_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
     61{
     62	struct fmr2 *fmr2 = tea->private_data;
     63	u8 bits = 0;
     64
     65	bits |= (pins & TEA575X_DATA) ? STR_DATA : 0;
     66	bits |= (pins & TEA575X_CLK)  ? STR_CLK  : 0;
     67	/* WRITE_ENABLE is inverted, DATA must be high during read */
     68	bits |= (pins & TEA575X_WREN) ? 0 : STR_WREN | STR_DATA;
     69
     70	outb(bits, fmr2->io);
     71}
     72
     73static u8 fmr2_tea575x_get_pins(struct snd_tea575x *tea)
     74{
     75	struct fmr2 *fmr2 = tea->private_data;
     76	u8 bits = inb(fmr2->io);
     77
     78	return  ((bits & STR_DATA) ? TEA575X_DATA : 0) |
     79		((bits & STR_MOST) ? TEA575X_MOST : 0);
     80}
     81
     82static void fmr2_tea575x_set_direction(struct snd_tea575x *tea, bool output)
     83{
     84}
     85
     86static const struct snd_tea575x_ops fmr2_tea_ops = {
     87	.set_pins = fmr2_tea575x_set_pins,
     88	.get_pins = fmr2_tea575x_get_pins,
     89	.set_direction = fmr2_tea575x_set_direction,
     90};
     91
     92/* TC9154A/PT2254A volume control */
     93
     94/* 18-bit shift register bit definitions */
     95#define TC9154A_ATT_MAJ_0DB	(1 << 0)
     96#define TC9154A_ATT_MAJ_10DB	(1 << 1)
     97#define TC9154A_ATT_MAJ_20DB	(1 << 2)
     98#define TC9154A_ATT_MAJ_30DB	(1 << 3)
     99#define TC9154A_ATT_MAJ_40DB	(1 << 4)
    100#define TC9154A_ATT_MAJ_50DB	(1 << 5)
    101#define TC9154A_ATT_MAJ_60DB	(1 << 6)
    102
    103#define TC9154A_ATT_MIN_0DB	(1 << 7)
    104#define TC9154A_ATT_MIN_2DB	(1 << 8)
    105#define TC9154A_ATT_MIN_4DB	(1 << 9)
    106#define TC9154A_ATT_MIN_6DB	(1 << 10)
    107#define TC9154A_ATT_MIN_8DB	(1 << 11)
    108/* bit 12 is ignored */
    109#define TC9154A_CHANNEL_LEFT	(1 << 13)
    110#define TC9154A_CHANNEL_RIGHT	(1 << 14)
    111/* bits 15, 16, 17 must be 0 */
    112
    113#define	TC9154A_ATT_MAJ(x)	(1 << x)
    114#define TC9154A_ATT_MIN(x)	(1 << (7 + x))
    115
    116static void tc9154a_set_pins(struct fmr2 *fmr2, u8 pins)
    117{
    118	if (!fmr2->tea.mute)
    119		pins |= STR_WREN;
    120
    121	outb(pins, fmr2->io);
    122}
    123
    124static void tc9154a_set_attenuation(struct fmr2 *fmr2, int att, u32 channel)
    125{
    126	int i;
    127	u32 reg;
    128	u8 bit;
    129
    130	reg = TC9154A_ATT_MAJ(att / 10) | TC9154A_ATT_MIN((att % 10) / 2);
    131	reg |= channel;
    132	/* write 18-bit shift register, LSB first */
    133	for (i = 0; i < 18; i++) {
    134		bit = reg & (1 << i) ? PT_DATA : 0;
    135		tc9154a_set_pins(fmr2, bit);
    136		udelay(5);
    137		tc9154a_set_pins(fmr2, bit | PT_CK);
    138		udelay(5);
    139		tc9154a_set_pins(fmr2, bit);
    140	}
    141
    142	/* latch register data */
    143	udelay(5);
    144	tc9154a_set_pins(fmr2, PT_ST);
    145	udelay(5);
    146	tc9154a_set_pins(fmr2, 0);
    147}
    148
    149static int fmr2_s_ctrl(struct v4l2_ctrl *ctrl)
    150{
    151	struct snd_tea575x *tea = container_of(ctrl->handler, struct snd_tea575x, ctrl_handler);
    152	struct fmr2 *fmr2 = tea->private_data;
    153	int volume, balance, left, right;
    154
    155	switch (ctrl->id) {
    156	case V4L2_CID_AUDIO_VOLUME:
    157		volume = ctrl->val;
    158		balance = fmr2->balance->cur.val;
    159		break;
    160	case V4L2_CID_AUDIO_BALANCE:
    161		balance = ctrl->val;
    162		volume = fmr2->volume->cur.val;
    163		break;
    164	default:
    165		return -EINVAL;
    166	}
    167
    168	left = right = volume;
    169	if (balance < 0)
    170		right = max(0, right + balance);
    171	if (balance > 0)
    172		left = max(0, left - balance);
    173
    174	tc9154a_set_attenuation(fmr2, abs(left - 68), TC9154A_CHANNEL_LEFT);
    175	tc9154a_set_attenuation(fmr2, abs(right - 68), TC9154A_CHANNEL_RIGHT);
    176
    177	return 0;
    178}
    179
    180static const struct v4l2_ctrl_ops fmr2_ctrl_ops = {
    181	.s_ctrl = fmr2_s_ctrl,
    182};
    183
    184static int fmr2_tea_ext_init(struct snd_tea575x *tea)
    185{
    186	struct fmr2 *fmr2 = tea->private_data;
    187
    188	/* FMR2 can have volume control, FMD2 can't (uses SB16 mixer) */
    189	if (!fmr2->is_fmd2 && inb(fmr2->io) & FMR2_HASVOL) {
    190		fmr2->volume = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_VOLUME, 0, 68, 2, 56);
    191		fmr2->balance = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_BALANCE, -68, 68, 2, 0);
    192		if (tea->ctrl_handler.error) {
    193			printk(KERN_ERR "radio-sf16fmr2: can't initialize controls\n");
    194			return tea->ctrl_handler.error;
    195		}
    196	}
    197
    198	return 0;
    199}
    200
    201static const struct pnp_device_id fmr2_pnp_ids[] = {
    202	{ .id = "MFRad13" }, /* tuner subdevice of SF16-FMD2 */
    203	{ .id = "" }
    204};
    205MODULE_DEVICE_TABLE(pnp, fmr2_pnp_ids);
    206
    207static int fmr2_probe(struct fmr2 *fmr2, struct device *pdev, int io)
    208{
    209	int err, i;
    210	char *card_name = fmr2->is_fmd2 ? "SF16-FMD2" : "SF16-FMR2";
    211
    212	/* avoid errors if a card was already registered at given port */
    213	for (i = 0; i < num_fmr2_cards; i++)
    214		if (io == fmr2_cards[i]->io)
    215			return -EBUSY;
    216
    217	strscpy(fmr2->v4l2_dev.name, "radio-sf16fmr2",
    218		sizeof(fmr2->v4l2_dev.name));
    219	fmr2->io = io;
    220
    221	if (!request_region(fmr2->io, 2, fmr2->v4l2_dev.name)) {
    222		printk(KERN_ERR "radio-sf16fmr2: I/O port 0x%x already in use\n", fmr2->io);
    223		return -EBUSY;
    224	}
    225
    226	dev_set_drvdata(pdev, fmr2);
    227	err = v4l2_device_register(pdev, &fmr2->v4l2_dev);
    228	if (err < 0) {
    229		v4l2_err(&fmr2->v4l2_dev, "Could not register v4l2_device\n");
    230		release_region(fmr2->io, 2);
    231		return err;
    232	}
    233	fmr2->tea.v4l2_dev = &fmr2->v4l2_dev;
    234	fmr2->tea.private_data = fmr2;
    235	fmr2->tea.radio_nr = radio_nr[num_fmr2_cards];
    236	fmr2->tea.ops = &fmr2_tea_ops;
    237	fmr2->tea.ext_init = fmr2_tea_ext_init;
    238	strscpy(fmr2->tea.card, card_name, sizeof(fmr2->tea.card));
    239	snprintf(fmr2->tea.bus_info, sizeof(fmr2->tea.bus_info), "%s:%s",
    240			fmr2->is_fmd2 ? "PnP" : "ISA", dev_name(pdev));
    241
    242	if (snd_tea575x_init(&fmr2->tea, THIS_MODULE)) {
    243		printk(KERN_ERR "radio-sf16fmr2: Unable to detect TEA575x tuner\n");
    244		release_region(fmr2->io, 2);
    245		return -ENODEV;
    246	}
    247
    248	printk(KERN_INFO "radio-sf16fmr2: %s radio card at 0x%x.\n",
    249			card_name, fmr2->io);
    250	return 0;
    251}
    252
    253static int fmr2_isa_match(struct device *pdev, unsigned int ndev)
    254{
    255	struct fmr2 *fmr2 = kzalloc(sizeof(*fmr2), GFP_KERNEL);
    256	if (!fmr2)
    257		return 0;
    258
    259	if (fmr2_probe(fmr2, pdev, FMR2_PORT)) {
    260		kfree(fmr2);
    261		return 0;
    262	}
    263	dev_set_drvdata(pdev, fmr2);
    264	fmr2_cards[num_fmr2_cards++] = fmr2;
    265
    266	return 1;
    267}
    268
    269static int fmr2_pnp_probe(struct pnp_dev *pdev, const struct pnp_device_id *id)
    270{
    271	int ret;
    272	struct fmr2 *fmr2 = kzalloc(sizeof(*fmr2), GFP_KERNEL);
    273	if (!fmr2)
    274		return -ENOMEM;
    275
    276	fmr2->is_fmd2 = true;
    277	ret = fmr2_probe(fmr2, &pdev->dev, pnp_port_start(pdev, 0));
    278	if (ret) {
    279		kfree(fmr2);
    280		return ret;
    281	}
    282	pnp_set_drvdata(pdev, fmr2);
    283	fmr2_cards[num_fmr2_cards++] = fmr2;
    284
    285	return 0;
    286}
    287
    288static void fmr2_remove(struct fmr2 *fmr2)
    289{
    290	snd_tea575x_exit(&fmr2->tea);
    291	release_region(fmr2->io, 2);
    292	v4l2_device_unregister(&fmr2->v4l2_dev);
    293	kfree(fmr2);
    294}
    295
    296static void fmr2_isa_remove(struct device *pdev, unsigned int ndev)
    297{
    298	fmr2_remove(dev_get_drvdata(pdev));
    299}
    300
    301static void fmr2_pnp_remove(struct pnp_dev *pdev)
    302{
    303	fmr2_remove(pnp_get_drvdata(pdev));
    304	pnp_set_drvdata(pdev, NULL);
    305}
    306
    307static struct isa_driver fmr2_isa_driver = {
    308	.match		= fmr2_isa_match,
    309	.remove		= fmr2_isa_remove,
    310	.driver		= {
    311		.name	= "radio-sf16fmr2",
    312	},
    313};
    314
    315static struct pnp_driver fmr2_pnp_driver = {
    316	.name		= "radio-sf16fmr2",
    317	.id_table	= fmr2_pnp_ids,
    318	.probe		= fmr2_pnp_probe,
    319	.remove		= fmr2_pnp_remove,
    320};
    321
    322static int __init fmr2_init(void)
    323{
    324	int ret;
    325
    326	ret = pnp_register_driver(&fmr2_pnp_driver);
    327	if (!ret)
    328		pnp_registered = true;
    329	ret = isa_register_driver(&fmr2_isa_driver, 1);
    330	if (!ret)
    331		isa_registered = true;
    332
    333	return (pnp_registered || isa_registered) ? 0 : ret;
    334}
    335
    336static void __exit fmr2_exit(void)
    337{
    338	if (pnp_registered)
    339		pnp_unregister_driver(&fmr2_pnp_driver);
    340	if (isa_registered)
    341		isa_unregister_driver(&fmr2_isa_driver);
    342}
    343
    344module_init(fmr2_init);
    345module_exit(fmr2_exit);