📄 kernel-2.6.19_mx-modular_rel1_1-5_update.patch
字号:
+ 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, ®, 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 + -