📄 kernel-2.6.19_mx-modular_rel1_1-5_update.patch
字号:
+ 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, ®, 1);
+ si4702_read_reg(SI4702_POWERCFG, ®);
+ reg &= 0x00FF;
+ si4702_write_reg(SI4702_POWERCFG, reg);
+ } else {
+ //reg = 0x40;
+ //error = si4702_operation(SD_WRITE, ®, 1);
+ si4702_read_reg(SI4702_POWERCFG, ®);
+ 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 + -