📄 menelaus.c
字号:
/* * drivers/i2c/chips/menelaus.c * * Copyright (C) 2004 Texas Instruments, Inc. * * Based on tlv320aic23.c: * Copyright (c) by Kai Svahn <kai.svahn@nokia.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/i2c.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/mach/irq.h>#include <asm/arch/mux.h>#include <asm/arch/menelaus.h>#include <asm/arch/sys_info.h>/* Local BCD/BIN conversion macros: */#ifdef BCD_TO_BIN#undef BCD_TO_BIN#endif#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10) #ifdef BIN_TO_BCD#undef BIN_TO_BCD#endif#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)//#define MENELAUSID1 0xE4//#define MENELAUSID2 0xE5/* I2C Addresses to scan *///static unsigned short normal_i2c[] = { MENELAUSID1, MENELAUSID2, I2C_CLIENT_END };static unsigned short normal_i2c[] = { 0x72, I2C_CLIENT_END };static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };/* This makes all addr_data:s */I2C_CLIENT_INSMOD;static int menelaus_id = 0;static const int menelaus_irq = INT_SYS;static struct i2c_driver menelaus_driver; static struct i2c_client *client;s32 menelaus_write(u8 value, u8 reg){ return i2c_smbus_write_byte_data(client, reg, value);}s32 menelaus_read(u8 reg){ return i2c_smbus_read_byte_data(client, reg);}static void menelaus_mask_ack_irq(unsigned int irq){ unsigned int menelaus = irq - IH_MENELAUS_BASE; if (menelaus > 7) { /* INT_MASK2 */ menelaus_write(menelaus_read(MENELAUS_INT_MASK2) | (1<<(menelaus-8)), MENELAUS_INT_MASK2); menelaus_write(1<<(menelaus-8), MENELAUS_INT_ACK2); } else { /* INT_MASK1 */ menelaus_write(menelaus_read(MENELAUS_INT_MASK1) | (1<<menelaus), MENELAUS_INT_MASK1); menelaus_write(1<<menelaus, MENELAUS_INT_ACK1); }}static void menelaus_mask_irq(unsigned int irq){ unsigned int menelaus = irq - IH_MENELAUS_BASE; if (menelaus > 7) { /* INT_MASK2 */ menelaus_write(menelaus_read(MENELAUS_INT_MASK2) | (1<<(menelaus-8)), MENELAUS_INT_MASK2); } else { /* INT_MASK1 */ menelaus_write(menelaus_read(MENELAUS_INT_MASK1) | (1<<menelaus), MENELAUS_INT_MASK1); }}void menelaus_unmask_irq(unsigned int irq){ unsigned int menelaus = irq - IH_MENELAUS_BASE; if (menelaus > 7) { /* INT_MASK2 */ menelaus_write(menelaus_read(MENELAUS_INT_MASK2) & ~(1<<(menelaus-8)), MENELAUS_INT_MASK2); } else { /* INT_MASK1 */ menelaus_write(menelaus_read(MENELAUS_INT_MASK1) & ~(1<<menelaus), MENELAUS_INT_MASK1); }}static struct irqchip menelaus_irq_chip = { .ack = menelaus_mask_ack_irq, .mask = menelaus_mask_irq, .unmask = menelaus_unmask_irq,};struct menelaus_irq_info { struct irqdesc *desc; unsigned int irq; struct work_struct *work; struct pt_regs *regs;};static void menelaus_work(void *data){ struct menelaus_irq_info *i = (struct menelaus_irq_info *)data; int menelaus; s32 isr1 = menelaus_read(MENELAUS_INT_STATUS1); s32 isr2 = menelaus_read(MENELAUS_INT_STATUS2); for (menelaus = IH_MENELAUS_BASE; menelaus < IH_MENELAUS_BASE + 8; menelaus++) { int m = menelaus - IH_MENELAUS_BASE; if (isr1 & (1<<m)) { struct irqdesc *d = irq_desc + menelaus; d->handle(menelaus, d, i->regs); } } for (menelaus = IH_MENELAUS_BASE + 8; menelaus < IH_MENELAUS_END; menelaus++) { int m = menelaus - IH_MENELAUS_BASE - 8; if (isr2 & (1<<m)) { struct irqdesc *d = irq_desc + menelaus; d->handle(menelaus, d, i->regs); } } i->desc->chip->unmask(i->irq); kfree(i->work); kfree(i); return;}static void do_menelaus_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs){ struct menelaus_irq_info *e; struct work_struct *work; desc->chip->ack(irq); // ack mask parent pic if (!(e = kmalloc(sizeof(struct menelaus_irq_info), GFP_KERNEL))) { printk(KERN_CRIT "Couldn't allocate memory for irq (%d) to be run in keventd context\n", irq); return; } if (!(work = kmalloc(sizeof(struct work_struct), GFP_KERNEL))) { printk(KERN_CRIT "Couldn't allocate memory for irq (%d) to be run in keventd context\n", irq); kfree(e); return; } e->work = work; e->irq = irq; e->desc = desc; e->regs = regs; INIT_WORK(work, menelaus_work, e); schedule_work(work);}static int menelaus_detect_client(struct i2c_adapter *adapter, int address, int kind){ int err = 0, i; const char *client_name = "Menelaus"; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_WRITE_BYTE)) { printk(KERN_WARNING "%s functinality check failed\n", client_name); return err; } if (!(client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) { err = -ENOMEM; printk(KERN_WARNING "Couldn't allocate memory for %s\n", client_name); return err; } memset(client, 0x00, sizeof(struct i2c_client)); client->addr = address; client->adapter = adapter; client->driver = &menelaus_driver; client->flags = 0; strlcpy(client->name, client_name, I2C_NAME_SIZE); client->id = menelaus_id++; if (kind < 0) if ((err = menelaus_read(MENELAUS_REV)) == -1) goto fail1; if ((err = i2c_attach_client(client))) { printk(KERN_WARNING "Couldn't attach %s\n", client_name); goto fail1; } for (i = IH_MENELAUS_BASE; i < IH_MENELAUS_END; i++) { set_irq_chip(i, &menelaus_irq_chip); set_irq_handler(i, do_level_IRQ); set_irq_flags(i, IRQF_VALID); } set_irq_chained_handler(menelaus_irq, do_menelaus_irq); omap2_cfg_reg(W19_2420_SYS_NIRQ); return 0;fail1: kfree(client); return err;} static int menelaus_detach_client(struct i2c_client *client){ int err; flush_scheduled_work(); if ((err = i2c_detach_client(client))) { printk("menelaus.o: Client deregistration failed, client not detached.\n"); return err; } kfree(client); return 0;}static int menelaus_attach_adapter(struct i2c_adapter *adapter){ if (!client) return menelaus_detect_client(adapter, addr_data.normal_i2c[0], -1); return -ENODEV;}/*-----------------------------------------------------------------------*/static struct i2c_driver menelaus_driver = { .owner = THIS_MODULE, .name = "Menelaus", .id = I2C_DRIVERID_EXP0, /* Experimental ID */ .flags = I2C_DF_NOTIFY, .attach_adapter = menelaus_attach_adapter, .detach_client = menelaus_detach_client,};static int __init menelaus_init(void){ int res; struct i2c_client *client = client; u32 board = get_board_type(); if(board == BOARD_H4_MENELAUS){ if ((res = i2c_add_driver(&menelaus_driver))) { printk("menelaus i2c: Driver registration failed, module not inserted.\n"); return res; } }else return -ENODEV; return 0;}static void __exit menelaus_exit(void){ int res; u32 board = get_board_type(); if(board == BOARD_H4_MENELAUS){ if ((res = i2c_del_driver(&menelaus_driver))) printk("menelaus i2c: Driver remove failed, module not removed.\n"); }}MODULE_AUTHOR("Texas Instruments, Inc.");MODULE_DESCRIPTION("I2C interface for Menelaus.");MODULE_LICENSE("GPL");module_init(menelaus_init)module_exit(menelaus_exit)EXPORT_SYMBOL(menelaus_write);EXPORT_SYMBOL(menelaus_read);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -