Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

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