^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);