📄 omap-tsc2101.c
字号:
/* * linux/drivers/ssi/omap-tsc2101.c * * TSC2101 codec interface driver for the OMAP platform * * Copyright (C) 2004 Texas Instruments, Inc. * * This package is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * History: * * 2004/11/01 Srinath - Ported to 2420. * 2004/11/07 Nishanth Menon - Modified for common hooks for Audio and Touchscreen */#include <linux/module.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/errno.h>#include <linux/delay.h>#include <asm/system.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/mach-types.h>#include <asm/hardware.h>#include <asm/arch/mux.h>#include <asm/arch/io.h>#include <asm/arch/hardware.h>#include <asm/hardware/tsc2101.h>#include "omap-tsc2101.h"#if CONFIG_ARCH_OMAP16XX#include <asm/arch/clocks.h>#include <../drivers/ssi/omap-uwire.h>#elif CONFIG_ARCH_OMAP24XX#include <../drivers/ssi/omap-mcspi.h>#endif#define LEAVE_CS 0x80#define SPIO 1#ifdef CONFIG_ARCH_OMAP24XX#define STARTADDRESS(n) ((n)<<5)#define SYSTEM_CONTROL_BASE OMAP24XX_VA_SYSTEM_CONTROL_BASE/* Offsets */#define PRCM_CLKOUT_CTRL 0x8070#define CONTROL_PADCONF_sys_clkout 0x0137#define CONTROL_PADCONF_spi1_clk 0x00FF#define CONTROL_PADCONF_spi1_simo 0x0100#define CONTROL_PADCONF_spi1_somi 0x0101#define CONTROL_PADCONF_spi1_ncs0 0x0102#define CONTROL_PADCONF_spi1_ncs1 0x0103#endif /* End of #ifdef CONFIG_ARCH_OMAP24XX */static int count;static spinlock_t tsc2101_lock = SPIN_LOCK_UNLOCKED;static int omap_tsc2101_configure(void);#if CONFIG_MACH_OMAP_H3/* The GPIO Functions. These should be defined else where */extern int write_gpio_expa(u8 val, int addr);extern int read_gpio_expa(u8 * val, int addr);#endif#ifdef CONFIG_ARCH_OMAP24XX/********************************************************************************* * * PRCM Register access functions * ********************************************************************************/static __inline__ u32 tsc2101_prcm_write(u32 offset, u32 val){ return writel(val, SYSTEM_CONTROL_BASE + offset);}static __inline__ u32 tsc2101_prcm_read(u32 offset){ return readl(SYSTEM_CONTROL_BASE + offset);}static __inline__ u8 tsc2101_ctrl_out(u32 offset, u32 val){ return writeb(val, SYSTEM_CONTROL_BASE + offset);}#endif /* End of #ifdef CONFIG_ARCH_OMAP24XX *//* FIXME: add driver model usage to powerdown the tsc2101 on suspend */int omap_tsc2101_enable(void){ int ret = 0; spin_lock(&tsc2101_lock); if (count++ == 0) {#if CONFIG_ARCH_OMAP16XX int ret = 0; unsigned int reg_val = 0; /* Clock -Hard coding for the time being */#define CLK_SOFT_REQ_REG_BASE (0xFFFE0800+0x34)#define SOFT_COM_MCK0_REQ_MASK (0x1<<6) if (machine_is_omap_h3()) { ret = omap_cfg_reg(V5_1710_MCLK_ON); } else { if (machine_is_omap_h2()) { ret = omap_cfg_reg(R10_1610_MCLK_ON); } } reg_val = omap_readw(CLK_SOFT_REQ_REG_BASE); reg_val = reg_val | (SOFT_COM_MCK0_REQ_MASK); omap_writew(reg_val, CLK_SOFT_REQ_REG_BASE);#endif /* CONFIG_ARCH_OMAP1710|| CONFIG_ARCH_OMAP1610 */ ret = omap_tsc2101_configure(); } spin_unlock(&tsc2101_lock); return ret;}void omap_tsc2101_disable(void){ spin_lock(&tsc2101_lock); if (--count == 0) {#if CONFIG_ARCH_OMAP16XX int ret = 0; unsigned int reg_val = 0; if (machine_is_omap_h3()) { ret = omap_cfg_reg(V5_1710_MCLK_OFF); } else { if (machine_is_omap_h2()) { ret = omap_cfg_reg(R10_1610_MCLK_OFF); } } reg_val = omap_readw(CLK_SOFT_REQ_REG_BASE); reg_val = reg_val & (~SOFT_COM_MCK0_REQ_MASK); omap_writew(reg_val, CLK_SOFT_REQ_REG_BASE); #endif /* CONFIG_ARCH_OMAP1710|| CONFIG_ARCH_OMAP1610 */#ifdef CONFIG_ARCH_OMAP24XX omap24xx_spi1_exit();#endif } spin_unlock(&tsc2101_lock);}void omap_tsc2101_write(int page, u8 address, u16 data){#if CONFIG_ARCH_OMAP16XX int ret = 0; if (machine_is_omap_h2()) { ret = omap_uwire_data_transfer(LEAVE_CS | 1, (((page) << 11) | (address << 5)), 16, 0, NULL); if (ret) { printk(KERN_ERR "uwire-write returned error for address %x\n", address); return; } ret = omap_uwire_data_transfer(1, data, 16, 0, NULL); if (ret) { printk(KERN_ERR "uwire-write returned error for address %x\n", address); return; } } if (machine_is_omap_h3()) { ret = omap_uwire_data_transfer(LEAVE_CS | 0, ((page << 11) | (address << 5)), 16, 0, NULL); if (ret) { printk(KERN_ERR "uwire-write returned error for address %x\n", address); return; } ret = omap_uwire_data_transfer(0, data, 16, 0, NULL); if (ret) { printk(KERN_ERR "uwire-write returned error for address %x\n", address); return; } }#endif#if CONFIG_ARCH_OMAP24XX u32 tmp; tmp = (page << 11) | (address << 5); tmp <<= 16; tmp |= data; omap24xx_spi_enablechannel(SPI0); omap24xx_spi_writetochannel(SPI0, tmp); omap24xx_spi_disablechannel(SPI0);#endif}void omap_tsc2101_reads(int page, u8 startaddress, u16 * data, int numregs){#if CONFIG_ARCH_OMAP16XX int cs = 0, i; if (machine_is_omap_h2()) { cs = 1; } if (machine_is_omap_h3()) { cs = 0; } (void)omap_uwire_data_transfer(LEAVE_CS | cs, (0x8000 | (page << 11) | (startaddress << 5)), 16, 0, NULL); for (i = 0; i < (numregs - 1); i++, data++) { omap_uwire_data_transfer(LEAVE_CS | cs, 0, 0, 16, data); } omap_uwire_data_transfer(cs, 0, 0, 16, data);#endif#if CONFIG_ARCH_OMAP24XX int i; u32 tmp; tmp = (page << 11); omap24xx_spi_enablechannel(SPI0); /* write command word */ for (i = 0; i < numregs; i++) { tmp = tmp | (STARTADDRESS(startaddress + i)); tmp = tmp << 16; tmp |= 0x80000000; omap24xx_spi_writetochannel(SPI0, tmp); (*data) = omap24xx_spi_readfromchannel(SPI0) & 0x0000FFFF; data++; } omap24xx_spi_disablechannel(SPI0);#endif}u16 omap_tsc2101_read(int page, u8 address){ u16 ret; omap_tsc2101_reads(page, address, &ret, 1); return ret;}static int omap_tsc2101_configure(void){ /* FIXME: adapt clock divisors for uwire to current ARM xor clock rate */#if CONFIG_MACH_OMAP_H3 int err = 0; u8 ioExpanderVal = 0; if ((err = read_gpio_expa(&ioExpanderVal, 0x24))) { printk(" Error reading from I/O EXPANDER \n"); return err; } ioExpanderVal |= 0x8; if ((err = write_gpio_expa(ioExpanderVal, 0x24))) { printk(KERN_ERR ": Error writing to I/O EXPANDER \n"); return err; }#endif#if CONFIG_ARCH_OMAP16XX if (machine_is_omap_h2()) { omap_cfg_reg(N15_1610_UWIRE_CS1); //omap_uwire_configure_mode(1, 1, 1, 0, 0, 0); omap_uwire_configure_mode(1, 1, 1, 0, 2, 0); } if (machine_is_omap_h3()) { omap_cfg_reg(N14_1610_UWIRE_CS0); //omap_uwire_configure_mode(0, 1, 1, 0, 0, 0); omap_uwire_configure_mode(0, 1, 1, 0, 2, 0); } omap_writel(omap_readl(PU_PD_SEL_2) | (1 << 22), PU_PD_SEL_2); /*Configure MCLK enable */#endif#if CONFIG_ARCH_OMAP24XX struct spi_channel_config ch0_config; u32 reg_val; /* PRCM settings... */ reg_val = tsc2101_prcm_read(PRCM_CLKOUT_CTRL); reg_val &= ~0x03; reg_val |= 0x01; reg_val |= 0x80; tsc2101_prcm_write(PRCM_CLKOUT_CTRL, reg_val); /* TODO: * MUX - write to move it out of safe mode state * Move same out to spi code. */ tsc2101_ctrl_out(CONTROL_PADCONF_sys_clkout, 0x18); tsc2101_ctrl_out(CONTROL_PADCONF_spi1_clk, 0); tsc2101_ctrl_out(CONTROL_PADCONF_spi1_simo, 0); tsc2101_ctrl_out(CONTROL_PADCONF_spi1_somi, 0); tsc2101_ctrl_out(CONTROL_PADCONF_spi1_ncs0, 0); tsc2101_ctrl_out(CONTROL_PADCONF_spi1_ncs1, 0); omap24xx_spi1_init(); ch0_config.mode = MASTER; ch0_config.endianess = MCSPI_MODULCTRL_LITTLEEND; /* little endian */ ch0_config.transmitreceive = MCSPI_CHCONF_TRANSRECEIVE; ch0_config.wordlength = MCSPI_CHCONF_WL32; ch0_config.spipolarity = MCSPI_CHCONF_EPOL_LOW; ch0_config.clkphase = MCSPI_CHCONF_PHA_EVEN; ch0_config.clkpolarity = MCSPI_CHCONF_POL_HIGH; ch0_config.clkdivisor = MCSPI_CHCONF_CLKD_8; omap24xx_spi_channelconfig(SPI0, &ch0_config);#endif return 0;}EXPORT_SYMBOL(omap_tsc2101_enable);EXPORT_SYMBOL(omap_tsc2101_read);EXPORT_SYMBOL(omap_tsc2101_reads);EXPORT_SYMBOL(omap_tsc2101_write);EXPORT_SYMBOL(omap_tsc2101_disable);MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -