⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kernel-2.6.19_mx-modular_rel1_1-5_update.patch

📁 si4702 linux patch,this is FM chip si4702 driver,based on iMX31 platform
💻 PATCH
📖 第 1 页 / 共 3 页
字号:
+		return -1;	
+	}
+
+	if (seek_error == 0) {
+		channel = si4702_reg_data & 0x03ff;
+		seek_error = channel * SPACING + BAND;
+		DPRINTK("seek finish: channel(%d), freq(%dKHz)\n", channel, seek_error);
+	}
+	
+	return seek_error;
+}
+
+extern void pmic_fm_output_enable(bool);
+/*!
+  * open routing, initial the si4702
+  */
+static int si4702_open(struct inode *inode, struct file *file)
+{
+
+	spin_lock(&count_lock);
+	if (count != 0) {
+		DPRINTK("device has been open already\n");
+		spin_unlock(&count_lock);
+		return -EBUSY;
+	}
+	count ++;
+	spin_unlock(&count_lock);
+
+	/* detect headphone as RF */
+	if (!1) { //gpio_find_headphone()) {
+		printk(KERN_WARNING "Headphone has not been inserted\n");
+		spin_lock(&count_lock);
+		count --;
+		spin_unlock(&count_lock);
+		return -ENODEV;
+	}
+
+	/* request and active GPIO */
+	si4702_gpio_active();
+	/* reset the si4702 from it's reset pin */
+	si4702_gpio_reset();
+
+	/* startup si4702 */
+	if (si4702_startup()) {
+		spin_lock(&count_lock);
+		count--;
+		spin_unlock(&count_lock);
+		return -ENODEV;
+	}
+
+	pmic_fm_output_enable(1);
+	/* reset the device info struct */
+	si4702_dev.volume = 0x07;
+	si4702_dev.channel = 0;
+	si4702_dev.mute = 0;
+
+	return 0;
+}
+
+/*!
+  * release routing, shutdown si4702
+  */
+static int si4702_release(struct inode *inode, struct file *file)
+{
+	DPRINTK("release\n");
+	/* software shutdown */
+	si4702_shutdown();
+	/* inactive, free GPIO, cut power */
+	si4702_gpio_inactive();
+
+	pmic_fm_output_enable(0);
+
+	spin_lock(&count_lock);
+	count --;
+	spin_unlock(&count_lock);
+
+	return 0;
+}
+
+static int si4702_ioctl(struct inode *inode, struct file *file,
+		    unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int mute = 0;
+	u16 data;
+	int error;
+
+	DPRINTK("ioctl, cmd: 0x%x, arg: 0x%lx\n", cmd, arg);
+
+	switch (cmd) {
+		case SI4702_SETVOLUME:
+		{
+			u8 volume;
+			int error;
+			
+			/* get volume from user */
+			if (copy_from_user(&volume, argp, sizeof(u8))) {
+
+				DPRINTK("ioctl, copy volume value from user failed\n");
+				return -EFAULT;
+			}
+			DPRINTK("volume %d\n", volume);
+			/* refill the register value */
+			volume &= 0x0f;
+			if (si4702_dev.mute)
+				error = si4702_write_reg(SI4702_POWERCFG, 0x0001); 
+			else
+				error = si4702_write_reg(SI4702_POWERCFG, 0x4001); 
+
+			error = si4702_write_reg(SI4702_CHANNEL, 0); 
+			error = si4702_write_reg(SI4702_SYSCONFIG1, 0); 
+			error = si4702_write_reg(SI4702_SYSCONFIG2, 0x0f10 | volume); 
+			if (error) {
+				DPRINTK("ioctl, set volume failed\n");
+				return -EFAULT;
+			}
+			/* renew the device info */
+			si4702_dev.volume = volume;
+
+			break;
+		}
+		case SI4702_GETVOLUME:
+			/* just copy volume value to user */
+			if (copy_to_user(argp, &si4702_dev.volume, 
+						sizeof(unsigned int))) {
+				DPRINTK("ioctl, copy to user failed\n");
+				return -EFAULT;
+			}
+			break;
+		case SI4702_MUTEON:
+			mute = 1;
+		case SI4702_MUTEOFF:
+			if (mute) {
+				/* enable mute */
+				//reg = 0x00;
+				//error = si4702_operation(SD_WRITE, &reg, 1);
+				si4702_read_reg(SI4702_POWERCFG, &data);
+				data &= 0x00FF;
+				error = si4702_write_reg(SI4702_POWERCFG, data); 
+			} else {
+				//data = 0x40;
+				//error = si4702_operation(SD_WRITE, &data, 1);
+				si4702_read_reg(SI4702_POWERCFG, &data);
+				data &= 0x00FF;
+				data |= 0x4000;
+				error = si4702_write_reg(SI4702_POWERCFG, data); 
+			}
+			if (error) {
+				DPRINTK("ioctl, set mute failed\n");
+				return -EFAULT;
+			}
+			break;
+		case SI4702_SELECT:
+		{
+			unsigned int freq;
+			if (copy_from_user(&freq, argp, sizeof(unsigned int))) {
+
+				DPRINTK("ioctl, copy frequence from user failed\n");
+				return -EFAULT;
+			}
+			/* check frequence */
+			if (freq > MAX_BAND || freq < BAND) {
+				printk(KERN_WARNING "si4702: the frequence select is out of band\n");
+				return -EINVAL;
+			}
+			if (si4702_channel_select(freq)) {
+				DPRINTK("ioctl, failed to select channel\n");
+				return -EFAULT;
+			}
+			break;
+		}
+		case SI4702_SEEK:
+		{
+			int dir;
+			if (copy_from_user(&dir, argp, sizeof(int))) {
+
+				DPRINTK("ioctl, copy from user failed\n");
+				return -EFAULT;
+			}
+			/* get seeked channel */
+			dir = si4702_channel_seek(dir);
+			if (dir == -1) {
+				return -EAGAIN;
+			} else if (dir == -2) {
+				return -EFAULT;
+			}
+			if (copy_to_user(argp, &dir, sizeof(int))) {
+				
+				DPRINTK("ioctl, copy seek frequnce to user failed\n");
+				return -EFAULT;
+			}
+			break;
+		}
+		default:
+			printk(KERN_WARNING "SI4702: Invalid ioctl command\n");
+			return -EINVAL;
+
+	}
+	return 0;
+}
+
+static struct file_operations si4702_fops = {
+	.owner		= THIS_MODULE,
+	.ioctl		= si4702_ioctl,
+	.open		= si4702_open,
+	.release	= si4702_release,
+};
+
+
+/////////////////////////////////////I2C operations
+static struct i2c_client *si4702_client = 0;
+
+static int i2c_si4702_attach(struct i2c_adapter *adap);
+static int i2c_si4702_detach(struct i2c_client *client);
+
+static struct i2c_driver si4702_i2c_driver = {
+	.driver = {
+		   .owner = THIS_MODULE,
+		   .name = "si4702 driver",
+		   },
+	.attach_adapter = &i2c_si4702_attach,
+	.detach_client = &i2c_si4702_detach,
+};
+
+static int si4702_access_reg(char *buf, u16 num, u16 tran_flag)
+{
+	struct i2c_msg msg[1];
+	int ret;
+	if(si4702_client == 0)
+	{
+		DPRINTK("si4702_client = 0\n");
+		return -1;
+	}
+	msg[0].addr = SI4702_I2C_ADDR;
+	msg[0].len = num;
+	msg[0].buf = buf;
+	msg[0].flags = tran_flag | MXC_I2C_FLAG_POLLING;
+
+	if (tran_flag & MXC_I2C_FLAG_READ) {
+		msg[0].flags |= I2C_M_RD;
+		memset(si4702_reg_buf, 0, SI4702_REG_BYTE);
+	} else {
+		msg[0].flags &= ~I2C_M_RD;
+	}
+
+	ret = i2c_transfer(si4702_client->adapter, msg, 1);
+
+	if(ret < 0)
+		DPRINTK("register access failed.\n");
+
+	return ret;
+}
+
+static int si4702_read_reg(u8 reg, u16 * word)
+{
+	int ret;
+	u8 register1 = reg;
+	
+	if(register1 >= SI4702_STATUSRSSI && register1 < SI4702_REG_NUM)
+		register1 -= SI4702_STATUSRSSI;
+	else if(reg < SI4702_STATUSRSSI)
+		register1 += SI4702_REG_NUM - SI4702_STATUSRSSI;
+	else
+	{
+		DPRINTK("Wrong register number.\n");
+		return -1;
+	}
+	
+	ret = si4702_access_reg(&si4702_reg_buf[0], SI4702_REG_BYTE, MXC_I2C_FLAG_READ);
+
+	if(ret < 0)
+		return ret;
+	
+	*word = (si4702_reg_buf[register1 * 2] << 8 )& 0xFF00;
+	*word |= si4702_reg_buf[register1 * 2 + 1] & 0x00FF;
+	DPRINTK("read register %d = 0x%x \n", reg, *word);
+
+	return ret;
+}
+
+static int si4702_write_reg(u8 reg, u16 word)
+{
+	int ret;
+	u8 register1 = reg;
+	
+	if(register1 >= SI4702_POWERCFG && register1 < SI4702_STATUSRSSI)
+		register1 -= SI4702_POWERCFG;
+	else
+	{
+		DPRINTK("Wrong register number.\n");
+		return -1;
+	}
+
+	si4702_reg_buf[SI4702_RW_OFFSET * 2 + register1 * 2] = (word & 0xFF00) >> 8;
+	si4702_reg_buf[SI4702_RW_OFFSET * 2 + register1 * 2 + 1] = word & 0x00FF;
+
+	DPRINTK("write register %d = 0x%x \n", reg, word);
+	ret = si4702_access_reg(&si4702_reg_buf[SI4702_RW_OFFSET * 2],
+		SI4702_RW_REG_NUM * 2, MXC_I2C_FLAG_POLLING);
+
+	return ret;
+}
+
+static void dump_reg(void)
+{
+	u16 i;
+	
+	si4702_read_reg(0, &i);
+
+
+	DPRINTK("SI4702_DEVICEID		= 0x%x\n", BYTE_TO_WORD(si4702_reg_buf[12], si4702_reg_buf[13]));
+	DPRINTK("SI4702_CHIPID		= 0x%x\n", BYTE_TO_WORD(si4702_reg_buf[14], si4702_reg_buf[15]));
+	DPRINTK("SI4702_POWERCFG 	= 0x%x\n", BYTE_TO_WORD(si4702_reg_buf[16], si4702_reg_buf[17]));
+	DPRINTK("SI4702_CHANNEL 		= 0x%x\n", BYTE_TO_WORD(si4702_reg_buf[18], si4702_reg_buf[19]));
+	DPRINTK("SI4702_SYSCONFIG1 	= 0x%x\n", BYTE_TO_WORD(si4702_reg_buf[20], si4702_reg_buf[21]));
+	DPRINTK("SI4702_SYSCONFIG2 	= 0x%x\n", BYTE_TO_WORD(si4702_reg_buf[22], si4702_reg_buf[23]));
+	DPRINTK("SI4702_SYSCONFIG3 	= 0x%x\n", BYTE_TO_WORD(si4702_reg_buf[24], si4702_reg_buf[25]));
+	DPRINTK("SI4702_TEST1 		= 0x%x\n", BYTE_TO_WORD(si4702_reg_buf[26], si4702_reg_buf[27]));
+	DPRINTK("SI4702_TEST2 		= 0x%x\n", BYTE_TO_WORD(si4702_reg_buf[28], si4702_reg_buf[29]));
+	DPRINTK("SI4702_B00TCONFIG 	= 0x%x\n", BYTE_TO_WORD(si4702_reg_buf[30], si4702_reg_buf[31]));
+	DPRINTK("SI4702_STATUSRSSI 	= 0x%x\n", BYTE_TO_WORD(si4702_reg_buf[0], si4702_reg_buf[1]));
+	DPRINTK("SI4702_READCHAN		= 0x%x\n", BYTE_TO_WORD(si4702_reg_buf[2], si4702_reg_buf[3]));
+	
+}
+
+static int i2c_si4702_detect_client(struct i2c_adapter *adapter, int address,
+				   int kind)
+{
+	int ret;	
+	struct i2c_client *client;
+	u16 id;
+	const char *client_name = "si4702 I2C dev";
+
+	pr_debug("si4702: i2c-bus: %s; address: 0x%x\n", adapter->name, address);
+
+	client =
+	    kmalloc(sizeof(struct i2c_client) + sizeof(int),
+		    GFP_KERNEL);
+	if (!client)
+	{
+		DPRINTK("client mem allocate failed\n");
+		return -ENOMEM;
+	}
+	memset(client, 0, sizeof(struct i2c_client) + sizeof(int));
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &si4702_i2c_driver;
+	client->flags = 0;
+
+	strcpy(client->name, client_name);
+	printk(KERN_ERR "si4702: before i2c_attach_client %x, adapter = %x, address = %x\n", 
+		(unsigned int)client->dev.driver_data, (unsigned int)adapter, (unsigned int)address);
+	i2c_set_clientdata(client, (client + 1));
+	
+	if (i2c_attach_client(client)) {
+		printk(KERN_ERR "si4702: i2c_attach_client() failed.\n");
+		kfree(client);
+	} else if (si4702_client == 0)
+		si4702_client = client;
+
+	/* request and active GPIO */
+	si4702_gpio_active();
+	/* reset the si4702 from it's reset pin */
+	si4702_gpio_reset();
+
+	/*TODO client detection*/
+	ret = si4702_read_reg(SI4702_DEVICEID, &id);
+
+	si4702_gpio_inactive();
+	if (ret < 0 || id != SI4702_DEVICE_ID) {
+		printk(KERN_ERR "si4702: DEVICEID: 0x%x, but it should be 0x%x\n", id, SI4702_DEVICE_ID);
+		return 0;
+	}
+	printk(KERN_ERR "si4702: DEVICEID: 0x%x\n", id);
+
+	return 0;
+}
+
+
+static unsigned short normal_i2c[] = { SI4702_I2C_ADDR, I2C_CLIENT_END };
+
+/* Magic definition of all other variables and things */
+I2C_CLIENT_INSMOD;
+
+static int i2c_si4702_attach(struct i2c_adapter *adap)
+{
+	DPRINTK("i2c_si4702_attach\n");
+	return i2c_probe(adap, &addr_data, &i2c_si4702_detect_client);
+}
+
+static int i2c_si4702_detach(struct i2c_client *client)
+{
+	int err;
+
+	DPRINTK("i2c_si4702_detach\n");
+	if ((err = i2c_detach_client(client))) {
+		pr_debug("si4702: i2c_detach_client() failed\n");
+		return err;
+	}
+
+	if (si4702_client == client)
+		si4702_client = 0;
+
+	kfree(client);
+	return 0;
+}
+
+static int __init si4702_init(void)
+{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -