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

📄 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 页
字号:
+	int err;
+	/* initial spin lock */
+	spin_lock_init(&count_lock);	
+
+	/* register character device */
+	major = register_chrdev(0, SI4702_DEV_NAME, &si4702_fops);
+	if (major <= 0) {
+		printk(KERN_ERR "SI4702: unable to get major\n");
+		return -EIO;
+	}
+
+	/* create simple class */
+	radio_class = class_create(THIS_MODULE, "radio");
+	if (IS_ERR(radio_class)) {
+		printk(KERN_ERR "SI4702: failed to create radio class\n");
+		goto err1;
+	}
+
+	/* add device to this radio class */
+	class_device_create(radio_class, NULL, MKDEV(major, 0), NULL,
+			"si4702");
+
+	printk("Freescale SI4702 FM driver, (c) 2005 Freescale Semiconductor, Inc.\n");
+
+	if ((err = i2c_add_driver(&si4702_i2c_driver))) {
+		printk("SI4702: driver registration failed\n");
+		pr_info("SI4702: driver registration failed\n");
+		goto err2;
+	}
+	
+	fm_sys_init();
+#if 0
+	/* call devfs to create device file in user space */
+	if (devfs_mk_cdev(MKDEV(major, 0), S_IFCHR | S_IRUGO | S_IWUGO,
+			SI4702_DEV_NAME)) {
+		printk(KERN_DEBUG "SI4702: failed to create devfs\n");
+		goto err2;
+	}
+#endif
+
+	return 0;
+err2:
+	class_destroy(radio_class);
+err1:
+	unregister_chrdev(major, SI4702_DEV_NAME);
+	return -EIO;
+}
+
+static void __exit si4702_exit(void)
+{
+	unregister_chrdev(major, SI4702_DEV_NAME);
+#if 0
+	devfs_remove(SI4702_DEV_NAME);
+#endif
+	class_device_destroy(radio_class, MKDEV(major, 0));
+	class_destroy(radio_class);
+
+	i2c_del_driver(&si4702_i2c_driver);
+	fm_sys_exit();
+}
+
+/////////////////////sys system
+enum
+{
+	FM_SHUTDOWN 	= 0,
+	FM_STARTUP		= 1,
+	FM_OPEN			= 2,
+	FM_RESET		= 3,
+	FM_SELECT		= 4,
+	FM_REG			= 5,
+	FM_READ			= 6,
+	FM_WRITE		= 7,
+	FM_VOLUP		= 8,
+	FM_VOLDOWN		= 9,
+	FM_SEEK			= 10,
+	FM_SEEK_UP		= 11,
+	FM_MUTEON		= 12,
+	FM_MUTEDIS		= 13,
+	FM_101			= 14,
+	FM_103			= 15,
+	FM_105			= 16,
+	FM_107			= 17,
+	FM_CONTROL_MAX
+};
+
+static const char * const fm_control[FM_CONTROL_MAX] = {
+	[FM_SHUTDOWN]	= "halt",
+	[FM_STARTUP]		= "start",
+	[FM_OPEN]		= "open",
+	[FM_RESET]		= "reset",
+	[FM_SELECT]		= "select",
+	[FM_REG]			= "reg",
+	[FM_READ]		= "read",
+	[FM_WRITE]		= "write",
+	[FM_VOLUP]		= "vu",
+	[FM_VOLDOWN]	= "vd",
+	[FM_SEEK]		= "seek",
+	[FM_SEEK_UP]		= "seekup",
+	[FM_MUTEON]		= "muteon",
+	[FM_MUTEDIS]		= "mutedis",
+	[FM_101]			= "101",
+	[FM_103]			= "103",
+	[FM_105]			= "105",
+	[FM_107]			= "107"
+};
+
+decl_subsys(fm,NULL,NULL);
+
+#define F97_7MHz 		97700
+#define F101_7MHz 	101700
+#define F103_7MHz 	103700
+#define F105_7MHz 	105700
+#define F107_7MHz	107700
+
+PMIC_AUDIO_HANDLE handle;
+
+static int fm_state(unsigned int state)
+{
+	u16 reg, mute = 0;
+	
+	switch(state)
+	{
+	case FM_SHUTDOWN:
+		DPRINTK("FM_SHUTDOWN\n");
+		si4702_shutdown();
+		pmic_fm_output_enable(0);
+		break;
+	case FM_STARTUP:
+		DPRINTK("FM_STARTUP\n");
+		pmic_fm_output_enable(1);
+		si4702_startup();
+		break;
+	case FM_OPEN:
+		DPRINTK("FM_OPEN\n");
+		si4702_open(0, 0);
+		break;		
+	case FM_RESET:
+		DPRINTK("FM_RESET\n");
+		si4702_gpio_reset();
+		break;
+	case FM_SELECT:
+		DPRINTK("FM_SELECT\n");
+		si4702_channel_select(F97_7MHz);
+		break;
+	case FM_101:
+		si4702_channel_select(F101_7MHz);
+		break;
+	case FM_103:
+		si4702_channel_select(F103_7MHz);
+		break;
+	case FM_105:
+		si4702_channel_select(F105_7MHz);
+		break;
+	case FM_107:
+		si4702_channel_select(87900);
+		break;
+	case FM_REG:
+		DPRINTK("FM_REG\n");		
+		dump_reg();		
+		break;
+	case FM_READ:
+		dump_reg();
+		break;
+	case FM_WRITE:
+		si4702_write_reg(SI4702_POWERCFG, 0x4001);
+		break;	
+	case FM_VOLUP:
+		si4702_dev.volume += 2;
+	case FM_VOLDOWN:
+		si4702_dev.volume -= 1;
+		si4702_dev.volume &= 0xF;
+		DPRINTK("volume to 0x%x\n", si4702_dev.volume);
+		reg = 0x0f10 | si4702_dev.volume;
+		si4702_write_reg(SI4702_SYSCONFIG2, reg);
+		break;
+	case FM_SEEK:
+		si4702_channel_seek(0);
+		break;
+	case FM_SEEK_UP:
+		si4702_channel_seek(1);
+		break;
+	case FM_MUTEON:
+		mute = 1;
+	case FM_MUTEDIS:
+		if (mute) {
+			/* enable mute */
+			//reg = 0x00;
+			//error = si4702_operation(SD_WRITE, &reg, 1);
+			si4702_read_reg(SI4702_POWERCFG, &reg);
+			reg &= 0x00FF;
+			si4702_write_reg(SI4702_POWERCFG, reg); 
+		} else {
+			//reg = 0x40;
+			//error = si4702_operation(SD_WRITE, &reg, 1);
+			si4702_read_reg(SI4702_POWERCFG, &reg);
+			reg &= 0x00FF;
+			reg |= 0x4000;
+			si4702_write_reg(SI4702_POWERCFG, reg); 
+		}
+		
+		break;
+	default:
+		DPRINTK("default\n");
+		break;
+	}
+	return 0;
+}
+
+static ssize_t fm_show(struct subsystem * subsys, char * buf)
+{
+	return 0;
+}
+
+static ssize_t fm_store(struct subsystem * subsys, const char * buf, size_t n)
+{
+	suspend_state_t state = 0;
+	const char * const *s;
+	char *p;
+	int error;
+	int len;
+
+	p = memchr(buf, '\n', n);
+	len = p ? p - buf : n;
+
+	for (s = &fm_control[state]; state < FM_CONTROL_MAX; s++, state++) {
+		if (*s && !strncmp(buf, *s, len))
+			break;
+	}
+	if (state < FM_CONTROL_MAX && *s)
+		error = fm_state(state);
+	else
+		error = -EINVAL;
+	return error ? error : n;
+}
+
+si4702_attr(fm);
+
+static struct attribute * g[] = {
+	&fm_attr.attr,
+	NULL,
+};
+
+static struct attribute_group attr_group = {
+	.attrs = g,
+};
+
+static int fm_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	return 0;
+}
+
+/*!
+ * This function is called to correct the system time based on the
+ * current MXC RTC time relative to the time delta saved during
+ * suspend.
+ *
+ * @param   pdev  not used
+ *
+ * @return  The function always returns 0.
+ */
+static int fm_resume(struct platform_device *pdev)
+{
+	return 0;
+}
+
+/*!
+ * Contains pointers to the power management callback functions.
+ */
+static struct platform_driver fm_driver = {
+	.driver = {
+		   .name = "mxc_rtc",
+		   .bus = &platform_bus_type,
+		   },
+	.suspend = fm_suspend,
+	.resume = fm_resume,
+};
+
+static int fm_sys_init(void)
+{	
+	int error; 
+
+	DPRINTK("fm sys init\n");
+	platform_driver_register(&fm_driver);
+		
+	error = subsystem_register(&fm_subsys);
+	if (!error)
+		error = sysfs_create_group(&fm_subsys.kset.kobj,&attr_group);
+
+	memset(si4702_reg_buf, 0, SI4702_REG_BYTE);
+	return error;
+}
+
+static int fm_sys_exit(void)
+{
+	DPRINTK("fm sys exit\n");
+	sysfs_remove_group(&fm_subsys.kset.kobj,&attr_group);
+	subsystem_unregister(&fm_subsys);
+	platform_driver_unregister(&fm_driver);
+		
+	return 0;
+}
+
+module_init(si4702_init);
+module_exit(si4702_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("SI4702 FM Radio driver");
+MODULE_LICENSE("GPL");
diff --exclude CVS -uNr linux-2.6.19.2/drivers/char/si4702.h linux-2.6.19.2.modified/drivers/char/si4702.h
--- linux-2.6.19.2/drivers/char/si4702.h	1970-01-01 07:00:00.000000000 +0700
+++ linux-2.6.19.2.modified/drivers/char/si4702.h	2007-10-26 13:10:09.000000000 +0800
@@ -0,0 +1,95 @@
+#ifndef _SI4702_FM_H
+#define _SI4702_FM_H
+/*
+ * linux/drivers/char/si4702.h
+ *
+ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @defgroup Character device driver for SI4702 FM radio
+ */
+
+/*
+ * @file si4702.h
+ *
+ * @brief SI4702 Radio FM driver
+ *
+ * @ingroup Character
+ */
+
+#ifdef __KERNEL__
+
+#include <asm/arch-mxc/gpio.h>
+#include "../arch/arm/mach-mx3/iomux.h"
+
+#define SI4702_DEV_NAME		"si4702"
+
+//I2C operations
+#define SI4702_I2C_ADDR	0x10 /* 7bits I2C address */
+
+#define BAND		87500	/* 87.5 MHz */
+#define MAX_BAND	108000	
+#define SPACING		100	/* 100 KHz */
+
+#define DELAY_WAIT	8 /* loop_counter max value */
+
+//register
+#define SI4702_DEVICEID		0x00
+#define SI4702_CHIPID			0x01
+#define SI4702_POWERCFG		0x02
+#define SI4702_CHANNEL		0x03
+#define SI4702_SYSCONFIG1		0x04
+#define SI4702_SYSCONFIG2		0x05
+#define SI4702_SYSCONFIG3		0x06
+#define SI4702_TEST1			0x07
+#define SI4702_TEST2			0x08
+#define SI4702_B00TCONFIG		0x09
+#define SI4702_STATUSRSSI		0x0A
+#define SI4702_READCHAN		0x0B
+
+#define SI4702_REG_NUM		0x10
+#define SI4702_REG_BYTE		(SI4702_REG_NUM * 2)
+#define SI4702_DEVICE_ID		0x1242
+
+#define SI4702_RW_REG_NUM	(SI4702_STATUSRSSI - SI4702_POWERCFG)
+#define SI4702_RW_OFFSET		(SI4702_REG_NUM - SI4702_STATUSRSSI + SI4702_POWERCFG)
+
+#define BYTE_TO_WORD(hi, lo)	(((hi) << 8) & 0xFF00) | ((lo) & 0x00FF)
+
+struct si4702_device {
+	unsigned int volume;
+	unsigned int channel;
+	unsigned int mute:1;
+};
+
+#endif /* __KERNEL__ */
+
+/* define IOCTL command */
+#define SI4702_GETVOLUME	_IOR('S', 0x10, unsigned int)
+#define SI4702_SETVOLUME	_IOW('S', 0x11, unsigned int)
+#define SI4702_MUTEON		_IO('S', 0x12)
+#define SI4702_MUTEOFF		_IO('S', 0x13)
+#define SI4702_SELECT		_IOW('S', 0x14, unsigned int)
+#define SI4702_SEEK		_IOWR('S', 0x15, unsigned int)
+
+#define si4702_attr(_name) \
+static struct subsys_attribute _name##_attr = {	\
+	.attr	= {				\
+		.name = __stringify(_name),	\
+		.mode = 0644,			\
+	},					\
+	.show	= _name##_show,			\
+	.store	= _name##_store,		\
+}
+
+#endif /* _SI4702_FM_H */

⌨️ 快捷键说明

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