1 /* SF16-FMR2 radio driver for Linux 2 * Copyright (c) 2011 Ondrej Zary 3 * 4 * Original driver was (c) 2000-2002 Ziglio Frediano, freddy77@angelfire.com 5 * but almost nothing remained here after conversion to generic TEA575x 6 * implementation 7 */ 8 9 #include <linux/delay.h> 10 #include <linux/module.h> /* Modules */ 11 #include <linux/init.h> /* Initdata */ 12 #include <linux/ioport.h> /* request_region */ 13 #include <linux/io.h> /* outb, outb_p */ 14 #include <sound/tea575x-tuner.h> 15 16 MODULE_AUTHOR("Ondrej Zary"); 17 MODULE_DESCRIPTION("MediaForte SF16-FMR2 FM radio card driver"); 18 MODULE_LICENSE("GPL"); 19 20 struct fmr2 { 21 int io; 22 struct snd_tea575x tea; 23 struct v4l2_ctrl *volume; 24 struct v4l2_ctrl *balance; 25 }; 26 27 /* the port is hardwired so no need to support multiple cards */ 28 #define FMR2_PORT 0x384 29 static struct fmr2 fmr2_card; 30 31 /* TEA575x tuner pins */ 32 #define STR_DATA (1 << 0) 33 #define STR_CLK (1 << 1) 34 #define STR_WREN (1 << 2) 35 #define STR_MOST (1 << 3) 36 /* PT2254A/TC9154A volume control pins */ 37 #define PT_ST (1 << 4) 38 #define PT_CK (1 << 5) 39 #define PT_DATA (1 << 6) 40 /* volume control presence pin */ 41 #define FMR2_HASVOL (1 << 7) 42 43 static void fmr2_tea575x_set_pins(struct snd_tea575x *tea, u8 pins) 44 { 45 struct fmr2 *fmr2 = tea->private_data; 46 u8 bits = 0; 47 48 bits |= (pins & TEA575X_DATA) ? STR_DATA : 0; 49 bits |= (pins & TEA575X_CLK) ? STR_CLK : 0; 50 /* WRITE_ENABLE is inverted, DATA must be high during read */ 51 bits |= (pins & TEA575X_WREN) ? 0 : STR_WREN | STR_DATA; 52 53 outb(bits, fmr2->io); 54 } 55 56 static u8 fmr2_tea575x_get_pins(struct snd_tea575x *tea) 57 { 58 struct fmr2 *fmr2 = tea->private_data; 59 u8 bits = inb(fmr2->io); 60 61 return (bits & STR_DATA) ? TEA575X_DATA : 0 | 62 (bits & STR_MOST) ? TEA575X_MOST : 0; 63 } 64 65 static void fmr2_tea575x_set_direction(struct snd_tea575x *tea, bool output) 66 { 67 } 68 69 static struct snd_tea575x_ops fmr2_tea_ops = { 70 .set_pins = fmr2_tea575x_set_pins, 71 .get_pins = fmr2_tea575x_get_pins, 72 .set_direction = fmr2_tea575x_set_direction, 73 }; 74 75 /* TC9154A/PT2254A volume control */ 76 77 /* 18-bit shift register bit definitions */ 78 #define TC9154A_ATT_MAJ_0DB (1 << 0) 79 #define TC9154A_ATT_MAJ_10DB (1 << 1) 80 #define TC9154A_ATT_MAJ_20DB (1 << 2) 81 #define TC9154A_ATT_MAJ_30DB (1 << 3) 82 #define TC9154A_ATT_MAJ_40DB (1 << 4) 83 #define TC9154A_ATT_MAJ_50DB (1 << 5) 84 #define TC9154A_ATT_MAJ_60DB (1 << 6) 85 86 #define TC9154A_ATT_MIN_0DB (1 << 7) 87 #define TC9154A_ATT_MIN_2DB (1 << 8) 88 #define TC9154A_ATT_MIN_4DB (1 << 9) 89 #define TC9154A_ATT_MIN_6DB (1 << 10) 90 #define TC9154A_ATT_MIN_8DB (1 << 11) 91 /* bit 12 is ignored */ 92 #define TC9154A_CHANNEL_LEFT (1 << 13) 93 #define TC9154A_CHANNEL_RIGHT (1 << 14) 94 /* bits 15, 16, 17 must be 0 */ 95 96 #define TC9154A_ATT_MAJ(x) (1 << x) 97 #define TC9154A_ATT_MIN(x) (1 << (7 + x)) 98 99 static void tc9154a_set_pins(struct fmr2 *fmr2, u8 pins) 100 { 101 if (!fmr2->tea.mute) 102 pins |= STR_WREN; 103 104 outb(pins, fmr2->io); 105 } 106 107 static void tc9154a_set_attenuation(struct fmr2 *fmr2, int att, u32 channel) 108 { 109 int i; 110 u32 reg; 111 u8 bit; 112 113 reg = TC9154A_ATT_MAJ(att / 10) | TC9154A_ATT_MIN((att % 10) / 2); 114 reg |= channel; 115 /* write 18-bit shift register, LSB first */ 116 for (i = 0; i < 18; i++) { 117 bit = reg & (1 << i) ? PT_DATA : 0; 118 tc9154a_set_pins(fmr2, bit); 119 udelay(5); 120 tc9154a_set_pins(fmr2, bit | PT_CK); 121 udelay(5); 122 tc9154a_set_pins(fmr2, bit); 123 } 124 125 /* latch register data */ 126 udelay(5); 127 tc9154a_set_pins(fmr2, PT_ST); 128 udelay(5); 129 tc9154a_set_pins(fmr2, 0); 130 } 131 132 static int fmr2_s_ctrl(struct v4l2_ctrl *ctrl) 133 { 134 struct snd_tea575x *tea = container_of(ctrl->handler, struct snd_tea575x, ctrl_handler); 135 struct fmr2 *fmr2 = tea->private_data; 136 int volume, balance, left, right; 137 138 switch (ctrl->id) { 139 case V4L2_CID_AUDIO_VOLUME: 140 volume = ctrl->val; 141 balance = fmr2->balance->cur.val; 142 break; 143 case V4L2_CID_AUDIO_BALANCE: 144 balance = ctrl->val; 145 volume = fmr2->volume->cur.val; 146 break; 147 default: 148 return -EINVAL; 149 } 150 151 left = right = volume; 152 if (balance < 0) 153 right = max(0, right + balance); 154 if (balance > 0) 155 left = max(0, left - balance); 156 157 tc9154a_set_attenuation(fmr2, abs(left - 68), TC9154A_CHANNEL_LEFT); 158 tc9154a_set_attenuation(fmr2, abs(right - 68), TC9154A_CHANNEL_RIGHT); 159 160 return 0; 161 } 162 163 static const struct v4l2_ctrl_ops fmr2_ctrl_ops = { 164 .s_ctrl = fmr2_s_ctrl, 165 }; 166 167 static int fmr2_tea_ext_init(struct snd_tea575x *tea) 168 { 169 struct fmr2 *fmr2 = tea->private_data; 170 171 if (inb(fmr2->io) & FMR2_HASVOL) { 172 fmr2->volume = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_VOLUME, 0, 68, 2, 56); 173 fmr2->balance = v4l2_ctrl_new_std(&tea->ctrl_handler, &fmr2_ctrl_ops, V4L2_CID_AUDIO_BALANCE, -68, 68, 2, 0); 174 if (tea->ctrl_handler.error) { 175 printk(KERN_ERR "radio-sf16fmr2: can't initialize contrls\n"); 176 return tea->ctrl_handler.error; 177 } 178 } 179 180 return 0; 181 } 182 183 static int __init fmr2_init(void) 184 { 185 struct fmr2 *fmr2 = &fmr2_card; 186 187 fmr2->io = FMR2_PORT; 188 189 if (!request_region(fmr2->io, 2, "SF16-FMR2")) { 190 printk(KERN_ERR "radio-sf16fmr2: I/O port 0x%x already in use\n", fmr2->io); 191 return -EBUSY; 192 } 193 194 fmr2->tea.private_data = fmr2; 195 fmr2->tea.ops = &fmr2_tea_ops; 196 fmr2->tea.ext_init = fmr2_tea_ext_init; 197 strlcpy(fmr2->tea.card, "SF16-FMR2", sizeof(fmr2->tea.card)); 198 strcpy(fmr2->tea.bus_info, "ISA"); 199 200 if (snd_tea575x_init(&fmr2->tea)) { 201 printk(KERN_ERR "radio-sf16fmr2: Unable to detect TEA575x tuner\n"); 202 release_region(fmr2->io, 2); 203 return -ENODEV; 204 } 205 206 printk(KERN_INFO "radio-sf16fmr2: SF16-FMR2 radio card at 0x%x.\n", fmr2->io); 207 return 0; 208 } 209 210 static void __exit fmr2_exit(void) 211 { 212 struct fmr2 *fmr2 = &fmr2_card; 213 214 snd_tea575x_exit(&fmr2->tea); 215 release_region(fmr2->io, 2); 216 } 217 218 module_init(fmr2_init); 219 module_exit(fmr2_exit); 220