Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.17 213 lines 4.8 kB view raw
1/* 2 * Driver for Philips SAB3036 "CITAC" tuner control chip. 3 * 4 * Author: Phil Blundell <philb@gnu.org> 5 * 6 * The SAB3036 is just about different enough from the chips that 7 * tuner.c copes with to make it not worth the effort to crowbar 8 * the support into that file. So instead we have a separate driver. 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License 12 * as published by the Free Software Foundation; either version 13 * 2 of the License, or (at your option) any later version. 14 */ 15 16#include <linux/module.h> 17#include <linux/kernel.h> 18#include <linux/sched.h> 19#include <linux/string.h> 20#include <linux/timer.h> 21#include <linux/delay.h> 22#include <linux/errno.h> 23#include <linux/slab.h> 24#include <linux/init.h> 25 26#include <linux/i2c.h> 27#include <linux/videodev.h> 28 29#include <media/tuner.h> 30 31static int debug; /* insmod parameter */ 32static int this_adap; 33 34static struct i2c_client client_template; 35 36/* Addresses to scan */ 37static unsigned short normal_i2c[] = { 0x60, 0x61, I2C_CLIENT_END }; 38static unsigned short ignore = I2C_CLIENT_END; 39 40static struct i2c_client_address_data addr_data = { 41 .normal_i2c = normal_i2c, 42 .probe = &ignore, 43 .ignore = &ignore, 44}; 45 46/* ---------------------------------------------------------------------- */ 47 48static unsigned char 49tuner_getstatus (struct i2c_client *c) 50{ 51 unsigned char byte; 52 if (i2c_master_recv(c, &byte, 1) != 1) 53 printk(KERN_ERR "tuner-3036: I/O error.\n"); 54 return byte; 55} 56 57#define TUNER_FL 0x80 58 59static int 60tuner_islocked (struct i2c_client *c) 61{ 62 return (tuner_getstatus(c) & TUNER_FL); 63} 64 65/* ---------------------------------------------------------------------- */ 66 67static void 68set_tv_freq(struct i2c_client *c, int freq) 69{ 70 u16 div = ((freq * 20) / 16); 71 unsigned long give_up = jiffies + HZ; 72 unsigned char buffer[2]; 73 74 if (debug) 75 printk(KERN_DEBUG "tuner: setting frequency %dMHz, divisor %x\n", freq / 16, div); 76 77 /* Select high tuning current */ 78 buffer[0] = 0x29; 79 buffer[1] = 0x3e; 80 81 if (i2c_master_send(c, buffer, 2) != 2) 82 printk("tuner: i2c i/o error 1\n"); 83 84 buffer[0] = 0x80 | ((div>>8) & 0x7f); 85 buffer[1] = div & 0xff; 86 87 if (i2c_master_send(c, buffer, 2) != 2) 88 printk("tuner: i2c i/o error 2\n"); 89 90 while (!tuner_islocked(c) && time_before(jiffies, give_up)) 91 schedule(); 92 93 if (!tuner_islocked(c)) 94 printk(KERN_WARNING "tuner: failed to achieve PLL lock\n"); 95 96 /* Select low tuning current and engage AFC */ 97 buffer[0] = 0x29; 98 buffer[1] = 0xb2; 99 100 if (i2c_master_send(c, buffer, 2) != 2) 101 printk("tuner: i2c i/o error 3\n"); 102 103 if (debug) 104 printk(KERN_DEBUG "tuner: status %02x\n", tuner_getstatus(c)); 105} 106 107/* ---------------------------------------------------------------------- */ 108 109static int 110tuner_attach(struct i2c_adapter *adap, int addr, int kind) 111{ 112 static unsigned char buffer[] = { 0x29, 0x32, 0x2a, 0, 0x2b, 0 }; 113 114 struct i2c_client *client; 115 116 if (this_adap > 0) 117 return -1; 118 this_adap++; 119 120 client_template.adapter = adap; 121 client_template.addr = addr; 122 123 client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); 124 if (client == NULL) 125 return -ENOMEM; 126 memcpy(client, &client_template, sizeof(struct i2c_client)); 127 128 printk("tuner: SAB3036 found, status %02x\n", tuner_getstatus(client)); 129 130 i2c_attach_client(client); 131 132 if (i2c_master_send(client, buffer, 2) != 2) 133 printk("tuner: i2c i/o error 1\n"); 134 if (i2c_master_send(client, buffer+2, 2) != 2) 135 printk("tuner: i2c i/o error 2\n"); 136 if (i2c_master_send(client, buffer+4, 2) != 2) 137 printk("tuner: i2c i/o error 3\n"); 138 return 0; 139} 140 141static int 142tuner_detach(struct i2c_client *c) 143{ 144 return 0; 145} 146 147static int 148tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) 149{ 150 int *iarg = (int*)arg; 151 152 switch (cmd) 153 { 154 case VIDIOCSFREQ: 155 set_tv_freq(client, *iarg); 156 break; 157 158 default: 159 return -EINVAL; 160 } 161 return 0; 162} 163 164static int 165tuner_probe(struct i2c_adapter *adap) 166{ 167 this_adap = 0; 168 if (adap->id == I2C_HW_B_LP) 169 return i2c_probe(adap, &addr_data, tuner_attach); 170 return 0; 171} 172 173/* ----------------------------------------------------------------------- */ 174 175static struct i2c_driver 176i2c_driver_tuner = 177{ 178 .driver = { 179 .name = "sab3036", 180 }, 181 .id = I2C_DRIVERID_SAB3036, 182 .attach_adapter = tuner_probe, 183 .detach_client = tuner_detach, 184 .command = tuner_command 185}; 186 187static struct i2c_client client_template = 188{ 189 .driver = &i2c_driver_tuner, 190 .name = "SAB3036", 191}; 192 193static int __init 194tuner3036_init(void) 195{ 196 return i2c_add_driver(&i2c_driver_tuner); 197} 198 199static void __exit 200tuner3036_exit(void) 201{ 202 i2c_del_driver(&i2c_driver_tuner); 203} 204 205MODULE_DESCRIPTION("SAB3036 tuner driver"); 206MODULE_AUTHOR("Philip Blundell <philb@gnu.org>"); 207MODULE_LICENSE("GPL"); 208 209module_param(debug, int, 0); 210MODULE_PARM_DESC(debug,"Enable debugging output"); 211 212module_init(tuner3036_init); 213module_exit(tuner3036_exit);