HDQ/1-wire support for OMAP2430/3430
PATCH 2/5 HDQ/1-wire support for OMAP2430/3430
This patch adds OMAP2430/3430 HDQ/1-Wire driver support.
--- drivers/w1/masters/Kconfig | 8 drivers/w1/masters/Makefile | 1 drivers/w1/masters/omap_hdq.c | 653 ++++++++++++++++++++++++++++++++++++++++ include/asm-arm/arch-omap/hdq.h | 23 + 4 files changed, 685 insertions(+)
drivers/w1/masters/omap_hdq.c new file +653 -0
@@ -0,0 +1,653 @@ +/* +* drivers/w1/masters/omap_hdq.c +* +* Copyright (C) 2007 Texas Instruments, Inc. +* +* This file is licensed under the terms of the GNU General Public License +* version 2. This program is licensed "as is" without any warranty of any +* kind, whether express or implied. +* +*/ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <asm/irq.h> +#include <asm/hardware.h> +#include <asm/arch/hdq.h> + +#include "../w1.h" +#include "../w1_int.h" + +#define MOD_NAME "OMAP_HDQ:" + +#define OMAP_HDQ_REVISION 0x00 +#define OMAP_HDQ_TX_DATA 0x04 +#define OMAP_HDQ_RX_DATA 0x08 +#define OMAP_HDQ_CTRL_STATUS 0x0c +#define OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK (1<<6) +#define OMAP_HDQ_CTRL_STATUS_CLOCKENABLE (1<<5) +#define OMAP_HDQ_CTRL_STATUS_GO (1<<4) +#define OMAP_HDQ_CTRL_STATUS_INITIALIZATION (1<<2) +#define OMAP_HDQ_CTRL_STATUS_DIR (1<<1) +#define OMAP_HDQ_CTRL_STATUS_MODE (1<<0) +#define OMAP_HDQ_INT_STATUS 0x10 +#define OMAP_HDQ_INT_STATUS_TXCOMPLETE (1<<2) +#define OMAP_HDQ_INT_STATUS_RXCOMPLETE (1<<1) +#define OMAP_HDQ_INT_STATUS_TIMEOUT (1<<0) +#define OMAP_HDQ_SYSCONFIG 0x14 +#define OMAP_HDQ_SYSCONFIG_SOFTRESET (1<<1) +#define OMAP_HDQ_SYSCONFIG_AUTOIDLE (1<<0) +#define OMAP_HDQ_SYSSTATUS 0x18 +#define OMAP_HDQ_SYSSTATUS_RESETDONE (1<<0) + +#define OMAP_HDQ_FLAG_CLEAR 0 +#define OMAP_HDQ_FLAG_SET 1 +#define OMAP_HDQ_TIMEOUT (HZ/5) + +#define OMAP_HDQ_MAX_USER 4 + +DECLARE_WAIT_QUEUE_HEAD (hdq_wait_queue); +int W1_ID ; + +struct hdq_data { +resource_size_t hdq_base; +struct semaphore hdq_semlock; +int hdq_usecount; +struct clk *hdq_ick; +struct clk *hdq_fck; +u8 hdq_irqstatus; +spinlock_t hdq_spinlock; +}; + +static struct hdq_data *hdq_data; + +static int __init omap_hdq_probe (struct platform_device *pdev); +static int omap_hdq_remove (struct platform_device *pdev); + +static struct platform_driver omap_hdq_driver = { + .probe = omap_hdq_probe, + .remove = omap_hdq_remove, + .suspend =NULL , + .resume =NULL , + .driver = { + .name ="omap_hdq" , + }, +}; + +static u8 omap_w1_read_byte (void *data); +static void omap_w1_write_byte (void *data,u8 byte); +static u8 omap_w1_reset_bus (void *data); +static void omap_w1_search_bus (void *data,u8 search_type, +w1_slave_found_callback slave_found); + +static struct w1_bus_master omap_w1_master = { + .read_byte = omap_w1_read_byte, + .write_byte = omap_w1_write_byte, + .reset_bus = omap_w1_reset_bus, + .search = omap_w1_search_bus, +}; + +/* +* HDQ register I/O routines +*/ +static inline u8 +hdq_reg_in (u32 offset) +{ +return omap_readb (hdq_data->hdq_base + offset); +} + +static inline u8 +hdq_reg_out (u32 offset,u8 val) +{ +omap_writeb (val, hdq_data->hdq_base + offset); +return val; +} + +static inline u8 +hdq_reg_merge (u32 offset,u8 val,u8 mask) +{ +u8 new_val = (omap_readb (hdq_data->hdq_base + offset) & ~mask) + | (val & mask); +omap_writeb (new_val, hdq_data->hdq_base + offset); +return new_val; +} + +/* +* Wait for one or more bits in flag change. +* HDQ_FLAG_SET: wait until any bit in the flag is set. +* HDQ_FLAG_CLEAR: wait until all bits in the flag are cleared. +* return 0 on success and -ETIMEOUT in the case of timeout. +*/ +static int +hdq_wait_for_flag (u32 offset,u8 flag,u8 flag_set,u8 *status) +{ +int ret =0 ; +unsigned long timeout = jiffies +OMAP_HDQ_TIMEOUT ; + +if (flag_set ==OMAP_HDQ_FLAG_CLEAR ) { +/* wait for the flag clear */ +while (((*status =hdq_reg_in (offset)) & flag) + &&time_before (jiffies, timeout)) { +set_current_state (TASK_UNINTERRUPTIBLE ); +schedule_timeout (1 ); + } +if (unlikely (*status & flag)) + ret = -ETIMEDOUT ; + }else if (flag_set ==OMAP_HDQ_FLAG_SET ) { +/* wait for the flag set */ +while (!((*status =hdq_reg_in (offset)) & flag) + &&time_before (jiffies, timeout)) { +set_current_state (TASK_UNINTERRUPTIBLE ); +schedule_timeout (1 ); + } +if (unlikely (!(*status & flag))) + ret = -ETIMEDOUT ; + }else +return -EINVAL ; + +return ret; +} + +/* +* write out a byte and fill *status with HDQ_INT_STATUS +*/ +static int +hdq_write_byte (u8 val,u8 *status) +{ +int ret; +u8 tmp_status; +unsigned long irqflags; + + *status =0 ; + +spin_lock_irqsave (&hdq_data->hdq_spinlock, irqflags); +/* clear interrupt flags via a dummy read */ +hdq_reg_in (OMAP_HDQ_INT_STATUS ); +/* ISR loads it with new INT_STATUS */ + hdq_data->hdq_irqstatus =0 ; +spin_unlock_irqrestore (&hdq_data->hdq_spinlock, irqflags); + +hdq_reg_out (OMAP_HDQ_TX_DATA , val); + +/* set the GO bit */ +hdq_reg_merge (OMAP_HDQ_CTRL_STATUS ,OMAP_HDQ_CTRL_STATUS_GO , +OMAP_HDQ_CTRL_STATUS_DIR |OMAP_HDQ_CTRL_STATUS_GO ); +/* wait for the TXCOMPLETE bit */ + ret =wait_event_interruptible_timeout (hdq_wait_queue, + hdq_data->hdq_irqstatus,OMAP_HDQ_TIMEOUT ); +if (unlikely (ret <0 )) { +pr_debug ("wait interrupted" ); +return -EINTR ; + } + +spin_lock_irqsave (&hdq_data->hdq_spinlock, irqflags); + *status = hdq_data->hdq_irqstatus; +spin_unlock_irqrestore (&hdq_data->hdq_spinlock, irqflags); +/* check irqstatus */ +if (!(*status &OMAP_HDQ_INT_STATUS_TXCOMPLETE )) { +pr_debug ("timeout waiting for TXCOMPLETE/RXCOMPLETE, %x" , + *status); +return -ETIMEDOUT ; + } + +/* wait for the GO bit return to zero */ + ret =hdq_wait_for_flag (OMAP_HDQ_CTRL_STATUS ,OMAP_HDQ_CTRL_STATUS_GO , +OMAP_HDQ_FLAG_CLEAR , &tmp_status); +if (ret) { +pr_debug ("timeout waiting GO bit return to zero, %x" , + tmp_status); +return ret; + } + +return ret; +} + +static irqreturn_t +hdq_isr (int irq,void *arg) +{ +unsigned long irqflags; + +spin_lock_irqsave (&hdq_data->hdq_spinlock, irqflags); + hdq_data->hdq_irqstatus =hdq_reg_in (OMAP_HDQ_INT_STATUS ); +spin_unlock_irqrestore (&hdq_data->hdq_spinlock, irqflags); +pr_debug ("hdq_isr: %x" , hdq_data->hdq_irqstatus); + +if (hdq_data->hdq_irqstatus & + (OMAP_HDQ_INT_STATUS_TXCOMPLETE |OMAP_HDQ_INT_STATUS_RXCOMPLETE + |OMAP_HDQ_INT_STATUS_TIMEOUT )) { +/* wake up sleeping process */ +wake_up_interruptible (&hdq_wait_queue); + } + +return IRQ_HANDLED ; +} + +static u8 omap_w1_reset_bus (void *data) +{ +return 0 ; +} + +static void omap_w1_search_bus (void *data,u8 search_type, +w1_slave_found_callback slave_found) +{ +u64 module_id, rn_le, cs, id; + +if (W1_ID ) + module_id =W1_ID ; +else + module_id =0x1 ; + + rn_le =cpu_to_le64 (module_id); +/* HDQ might not obely truly the 1-wire spec. +* So calculate CRC based on module parameter. +*/ + cs =w1_calc_crc8 ((u8 *)&rn_le,7 ); + id = (cs <<56 ) | module_id; + +slave_found (data, id); +} + +static int +_omap_hdq_reset (void ) +{ +int ret; +u8 tmp_status; + +hdq_reg_out (OMAP_HDQ_SYSCONFIG ,OMAP_HDQ_SYSCONFIG_SOFTRESET ); +/* +* Select HDQ mode & enable clocks. +* It is observed that INT flags can't be cleared via a read and GO/INIT +* won't return to zero if interrupt is disabled. So we always enable +* interrupt. +*/ +hdq_reg_out (OMAP_HDQ_CTRL_STATUS , +OMAP_HDQ_CTRL_STATUS_CLOCKENABLE | +OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK ); + +/* wait for reset to complete */ + ret =hdq_wait_for_flag (OMAP_HDQ_SYSSTATUS , +OMAP_HDQ_SYSSTATUS_RESETDONE ,OMAP_HDQ_FLAG_SET , &tmp_status); +if (ret) +pr_debug ("timeout waiting HDQ reset, %x" , tmp_status); +else { +hdq_reg_out (OMAP_HDQ_CTRL_STATUS , +OMAP_HDQ_CTRL_STATUS_CLOCKENABLE | +OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK ); +hdq_reg_out (OMAP_HDQ_SYSCONFIG ,OMAP_HDQ_SYSCONFIG_AUTOIDLE ); + } + +return ret; +} + +int +omap_hdq_reset (void ) +{ +int ret; + + ret =down_interruptible (&hdq_data->hdq_semlock); +if (ret <0 ) +return -EINTR ; + +if (!hdq_data->hdq_usecount) { +up (&hdq_data->hdq_semlock); +return -EINVAL ; + } + ret =_omap_hdq_reset (); +up (&hdq_data->hdq_semlock); +return ret; +} + +int +omap_hdq_break () +{ +int ret; +u8 tmp_status; +unsigned long irqflags; + + ret =down_interruptible (&hdq_data->hdq_semlock); +if (ret <0 ) +return -EINTR ; + +if (!hdq_data->hdq_usecount) { +up (&hdq_data->hdq_semlock); +return -EINVAL ; + } + +spin_lock_irqsave (&hdq_data->hdq_spinlock, irqflags); +/* clear interrupt flags via a dummy read */ +hdq_reg_in (OMAP_HDQ_INT_STATUS ); +/* ISR loads it with new INT_STATUS */ + hdq_data->hdq_irqstatus =0 ; +spin_unlock_irqrestore (&hdq_data->hdq_spinlock, irqflags); + +/* set the INIT and GO bit */ +hdq_reg_merge (OMAP_HDQ_CTRL_STATUS , +OMAP_HDQ_CTRL_STATUS_INITIALIZATION |OMAP_HDQ_CTRL_STATUS_GO , +OMAP_HDQ_CTRL_STATUS_DIR |OMAP_HDQ_CTRL_STATUS_INITIALIZATION | +OMAP_HDQ_CTRL_STATUS_GO ); + +/* wait for the TIMEOUT bit */ + ret =wait_event_interruptible_timeout (hdq_wait_queue, + hdq_data->hdq_irqstatus,OMAP_HDQ_TIMEOUT ); +if (unlikely (ret <0 )) { +pr_debug ("wait interrupted" ); +up (&hdq_data->hdq_semlock); +return -EINTR ; + } + +spin_lock_irqsave (&hdq_data->hdq_spinlock, irqflags); + tmp_status = hdq_data->hdq_irqstatus; +spin_unlock_irqrestore (&hdq_data->hdq_spinlock, irqflags); +/* check irqstatus */ +if (!(tmp_status &OMAP_HDQ_INT_STATUS_TIMEOUT )) { +pr_debug ("timeout waiting for TIMEOUT, %x" , tmp_status); +up (&hdq_data->hdq_semlock); +return -ETIMEDOUT ; + } +/* +* wait for both INIT and GO bits rerurn to zero. +* zero wait time expected for interrupt mode. +*/ + ret =hdq_wait_for_flag (OMAP_HDQ_CTRL_STATUS , +OMAP_HDQ_CTRL_STATUS_INITIALIZATION | +OMAP_HDQ_CTRL_STATUS_GO ,OMAP_HDQ_FLAG_CLEAR , + &tmp_status); +if (ret) +pr_debug ("timeout waiting INIT&GO bits return to zero, %x" , + tmp_status); + +up (&hdq_data->hdq_semlock); +return ret; +} +EXPORT_SYMBOL (omap_hdq_break); + +int hdq_read_byte (u8 *val) +{ +int ret; +u8 status; +unsigned long irqflags; + + ret =down_interruptible (&hdq_data->hdq_semlock); +if (ret <0 ) +return -EINTR ; + +if (!hdq_data->hdq_usecount) { +up (&hdq_data->hdq_semlock); +return -EINVAL ; + } + +if (!(hdq_data->hdq_irqstatus &OMAP_HDQ_INT_STATUS_RXCOMPLETE )) { +hdq_reg_merge (OMAP_HDQ_CTRL_STATUS , +OMAP_HDQ_CTRL_STATUS_DIR |OMAP_HDQ_CTRL_STATUS_GO , +OMAP_HDQ_CTRL_STATUS_DIR |OMAP_HDQ_CTRL_STATUS_GO ); +/* +* The RX comes immediately after TX. It +* triggers another interrupt before we +* sleep. So we have to wait for RXCOMPLETE bit. +*/ + { +unsigned long timeout = jiffies +OMAP_HDQ_TIMEOUT ; +while (!(hdq_data->hdq_irqstatus + &OMAP_HDQ_INT_STATUS_RXCOMPLETE ) + &&time_before (jiffies, timeout)) { +set_current_state (TASK_UNINTERRUPTIBLE ); +schedule_timeout (1 ); + } + } +hdq_reg_merge (OMAP_HDQ_CTRL_STATUS ,0 , +OMAP_HDQ_CTRL_STATUS_DIR ); +spin_lock_irqsave (&hdq_data->hdq_spinlock, irqflags); + status = hdq_data->hdq_irqstatus; +spin_unlock_irqrestore (&hdq_data->hdq_spinlock, irqflags); +/* check irqstatus */ +if (!(status &OMAP_HDQ_INT_STATUS_RXCOMPLETE )) { +pr_debug ("timeout waiting for RXCOMPLETE, %x" , status); +up (&hdq_data->hdq_semlock); +return -ETIMEDOUT ; + } + } +/* the data is ready. Read it in! */ + *val =hdq_reg_in (OMAP_HDQ_RX_DATA ); +up (&hdq_data->hdq_semlock); + +return 0 ; + +} + +int +omap_hdq_get () +{ +int ret =0 ; + + ret =down_interruptible (&hdq_data->hdq_semlock); +if (ret <0 ) +return -EINTR ; + +if (OMAP_HDQ_MAX_USER == hdq_data->hdq_usecount) { +pr_debug ("attempt to exceed the max use count" ); +up (&hdq_data->hdq_semlock); + ret = -EINVAL ; + }else { + hdq_data->hdq_usecount++; +try_module_get (THIS_MODULE ); +if (1 == hdq_data->hdq_usecount) { +if (clk_enable (hdq_data->hdq_ick)) { +pr_debug ("Can not enable ick\n" ); +clk_put (hdq_data->hdq_ick); +clk_put (hdq_data->hdq_fck); +up (&hdq_data->hdq_semlock); +return -ENODEV ; + } +if (clk_enable (hdq_data->hdq_fck)) { +pr_debug ("Can not enable fck\n" ); +clk_put (hdq_data->hdq_ick); +clk_put (hdq_data->hdq_fck); +up (&hdq_data->hdq_semlock); +return -ENODEV ; + } + +/* make sure HDQ is out of reset */ +if (!(hdq_reg_in (OMAP_HDQ_SYSSTATUS ) & +OMAP_HDQ_SYSSTATUS_RESETDONE )) { + ret =_omap_hdq_reset (); +if (ret) +/* back up the count */ + hdq_data->hdq_usecount--; + }else { +/* select HDQ mode & enable clocks */ +hdq_reg_out (OMAP_HDQ_CTRL_STATUS , +OMAP_HDQ_CTRL_STATUS_CLOCKENABLE | +OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK ); +hdq_reg_out (OMAP_HDQ_SYSCONFIG , +OMAP_HDQ_SYSCONFIG_AUTOIDLE ); +hdq_reg_in (OMAP_HDQ_INT_STATUS ); + } + } + } +up (&hdq_data->hdq_semlock); +return ret; +} +EXPORT_SYMBOL (omap_hdq_get); + +int +omap_hdq_put () +{ +int ret =0 ; + + ret =down_interruptible (&hdq_data->hdq_semlock); +if (ret <0 ) +return -EINTR ; + +if (0 == hdq_data->hdq_usecount) { +pr_debug ("attempt to decrement use count when it is zero" ); + ret = -EINVAL ; + }else { + hdq_data->hdq_usecount--; +module_put (THIS_MODULE ); +if (0 == hdq_data->hdq_usecount) { +clk_disable (hdq_data->hdq_ick); +clk_disable (hdq_data->hdq_fck); + } + } +up (&hdq_data->hdq_semlock); +return ret; +} +EXPORT_SYMBOL (omap_hdq_put); + +static u8 omap_w1_read_byte (void *data) +{ +u8 val; +int ret; + + ret =hdq_read_byte (&val); +if (ret) +return -1 ; +return val; +} + +static void omap_w1_write_byte (void *data,u8 byte) +{ +u8 status; + +hdq_write_byte (byte, &status); +pr_debug ("Ctrl status %x\n" , status); +return ; +} + +static int __init omap_hdq_probe (struct platform_device *pdev) +{ +struct resource *res; +int ret, irq; +u8 rev; + +if (!pdev) +return -ENODEV ; + + hdq_data =kmalloc (sizeof (*hdq_data),GFP_KERNEL ); +if (!hdq_data) +return -ENODEV ; + +platform_set_drvdata (pdev, hdq_data); + + res =platform_get_resource (pdev,IORESOURCE_MEM ,0 ); +if (res ==NULL ) { +platform_set_drvdata (pdev,NULL ); +kfree (hdq_data); +return -ENXIO ; + } + + hdq_data->hdq_base = res->start; + +/* get interface & functional clock objects */ + hdq_data->hdq_ick =clk_get (&pdev->dev,"hdq_ick" ); + hdq_data->hdq_fck =clk_get (&pdev->dev,"hdq_fck" ); + +if (IS_ERR (hdq_data->hdq_ick) ||IS_ERR (hdq_data->hdq_fck)) { +pr_debug ("Can't get HDQ clock objects\n" ); +if (IS_ERR (hdq_data->hdq_ick)) { + ret =PTR_ERR (hdq_data->hdq_ick); +platform_set_drvdata (pdev,NULL ); +kfree (hdq_data); +return ret; + } +if (IS_ERR (hdq_data->hdq_fck)) { + ret =PTR_ERR (hdq_data->hdq_fck); +platform_set_drvdata (pdev,NULL ); +kfree (hdq_data); +return ret; + } + } + + hdq_data->hdq_usecount =0 ; +sema_init (&hdq_data->hdq_semlock,1 ); + +if (clk_enable (hdq_data->hdq_ick)) { +pr_debug ("Can not enable ick\n" ); +clk_put (hdq_data->hdq_ick); +clk_put (hdq_data->hdq_fck); +platform_set_drvdata (pdev,NULL ); +kfree (hdq_data); +return -ENODEV ; + } + + rev =hdq_reg_in (OMAP_HDQ_REVISION ); +pr_info ("OMAP HDQ Hardware Revision %c.%c. Driver in %s mode.\n" , + (rev >>4 ) +'0' , (rev &0x0f ) +'0' ,"Interrupt" ); + + irq =platform_get_irq (pdev,0 ); +if (irq <0 ) { +platform_set_drvdata (pdev,NULL ); +kfree (hdq_data); +return -ENXIO ; + } + +if (request_irq (irq, hdq_isr,IRQF_DISABLED ,"OMAP HDQ" , + &hdq_data->hdq_semlock)) { +pr_debug ("request_irq failed\n" ); +clk_disable (hdq_data->hdq_ick); +clk_put (hdq_data->hdq_ick); +clk_put (hdq_data->hdq_fck); +platform_set_drvdata (pdev,NULL ); +kfree (hdq_data); +return -ENODEV ; + } +spin_lock_init (&hdq_data->hdq_spinlock); +/* don't clock the HDQ until it is needed */ +clk_disable (hdq_data->hdq_ick); + + ret =w1_add_master_device (&omap_w1_master); +if (ret) { +pr_debug ("Failure in registering w1 master\n" ); +clk_put (hdq_data->hdq_ick); +clk_put (hdq_data->hdq_fck); +platform_set_drvdata (pdev,NULL ); +kfree (hdq_data); +return ret; + } + +return 0 ; +} + +static int omap_hdq_remove (struct platform_device *pdev) +{ +down_interruptible (&hdq_data->hdq_semlock); +if (0 != hdq_data->hdq_usecount) { +pr_debug ("removed when use count is not zero\n" ); +return -EBUSY ; + } +up (&hdq_data->hdq_semlock); + +/* remove module dependency */ +clk_put (hdq_data->hdq_ick); +clk_put (hdq_data->hdq_fck); +free_irq (INT_24XX_HDQ_IRQ , &hdq_data->hdq_semlock); +platform_set_drvdata (pdev,NULL ); +kfree (hdq_data); + +return 0 ; +} + +static int __init +omap_hdq_init (void ) +{ +return platform_driver_register (&omap_hdq_driver); +} + +static void __exit +omap_hdq_exit (void ) +{ +platform_driver_unregister (&omap_hdq_driver); +} + +module_init (omap_hdq_init); +module_exit (omap_hdq_exit); + +module_param (W1_ID , int,S_IRUSR ); + +MODULE_AUTHOR ("Texas Instruments" ); +MODULE_DESCRIPTION ("HDQ driver Library" ); +MODULE_LICENSE ("GPL" );
drivers/w1/masters/Kconfig +8 -0
@@ -42,5 +42,13 @@ in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like hx4700. +config HDQ_MASTER_OMAP + tristate "OMAP HDQ driver" + depends on ARCH_OMAP2430 || ARCH_OMAP34XX + help + Say Y here if you want support for the 1-wire or HDQ Interface + on an OMAP processor. + + endmenu
drivers/w1/masters/Makefile +1 -0
@@ -6,3 +6,4 @@ obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o obj-$(CONFIG_W1_MASTER_DS1WM) += ds1wm.o +obj-$(CONFIG_HDQ_MASTER_OMAP) += omap_hdq.o
include/asm-arm/arch-omap/hdq.h new file +23 -0
@@ -0,0 +1,23 @@ +/* +* include/asm-arm/arch-omap2/hdq.h +* +* Copyright (C) 2006-2007 Texas Instruments, Inc. +* +* This file is licensed under the terms of the GNU General Public License +* version 2. This program is licensed "as is" without any warranty of any +* kind, whether express or implied. +* +*/ + +#ifndef __ASM_OMAP2_HDQ_H__ +#define __ASM_OMAP2_HDQ_H__ + +/* Note the following API has to be called in a process context */ + +int omap_hdq_get (void );/* request the HDQ block */ +int omap_hdq_put (void );/* release the HDQ block */ + +int omap_hdq_reset (void );/* reset the HDQ block */ +int omap_hdq_break (void );/* reset the slave by sending it a break pulse */ + +#endif
Hi Madhu,
Quoted 130 lines · Madhusudhan Chikkature Rajashekar
This patch adds OMAP2430/3430 HDQ/1-Wire driver support.
Signed-off-by Madhusudhan Chikkature<[email protected]>--- drivers/w1/masters/Kconfig | 8 drivers/w1/masters/Makefile | 1 drivers/w1/masters/omap_hdq.c | 653 ++++++++++++++++++++++++++++++++++++++++ include/asm-arm/arch-omap/hdq.h | 23 + 4 files changed, 685 insertions(+)Index:
linux-omap-hdq-new/drivers/w1/masters/omap_hdq.c
===================================================================drivers/w1/masters/omap_hdq.c 2007-12-06 17:14:30.189291891 +0530 renamed from dev/null 1970-01-01 00:00:00.000000000 +0000 +114
-0@@ -0,0 +1,653 @@ +/* + * drivers/w1/masters/omap_hdq.c + * + * Copyright (C) 2007 Texas Instruments, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + * + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <asm/irq.h> +#include <asm/hardware.h> +#include <asm/arch/hdq.h> + +#include "../w1.h" +#include "../w1_int.h" + +#define MOD_NAME "OMAP_HDQ:" + +#define OMAP_HDQ_REVISION 0x00 +#define OMAP_HDQ_TX_DATA 0x04 +#define OMAP_HDQ_RX_DATA 0x08 +#define OMAP_HDQ_CTRL_STATUS 0x0c +#define OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK (1<<6) +#define OMAP_HDQ_CTRL_STATUS_CLOCKENABLE (1<<5) +#define OMAP_HDQ_CTRL_STATUS_GO (1<<4) +#define OMAP_HDQ_CTRL_STATUS_INITIALIZATION (1<<2) +#define OMAP_HDQ_CTRL_STATUS_DIR (1<<1) +#define OMAP_HDQ_CTRL_STATUS_MODE (1<<0) +#define OMAP_HDQ_INT_STATUS 0x10 +#define OMAP_HDQ_INT_STATUS_TXCOMPLETE (1<<2) +#define OMAP_HDQ_INT_STATUS_RXCOMPLETE (1<<1) +#define OMAP_HDQ_INT_STATUS_TIMEOUT (1<<0) +#define OMAP_HDQ_SYSCONFIG 0x14 +#define OMAP_HDQ_SYSCONFIG_SOFTRESET (1<<1) +#define OMAP_HDQ_SYSCONFIG_AUTOIDLE (1<<0) +#define OMAP_HDQ_SYSSTATUS 0x18 +#define OMAP_HDQ_SYSSTATUS_RESETDONE (1<<0) + +#define OMAP_HDQ_FLAG_CLEAR 0 +#define OMAP_HDQ_FLAG_SET 1 +#define OMAP_HDQ_TIMEOUT (HZ/5) + +#define OMAP_HDQ_MAX_USER 4 + +DECLARE_WAIT_QUEUE_HEAD(hdq_wait_queue); +int W1_ID; + +struct hdq_data { + resource_size_t hdq_base; + struct semaphore hdq_semlock; + int hdq_usecount; + struct clk *hdq_ick; + struct clk *hdq_fck; + u8 hdq_irqstatus; + spinlock_t hdq_spinlock; +}; + +static struct hdq_data *hdq_data; + +static int __init omap_hdq_probe(struct platform_device *pdev); +static int omap_hdq_remove(struct platform_device *pdev); + +static struct platform_driver omap_hdq_driver = { + .probe = omap_hdq_probe, + .remove = omap_hdq_remove, + .suspend = NULL, + .resume = NULL, + .driver = { + .name = "omap_hdq", + }, +}; + +static u8 omap_w1_read_byte(void *data); +static void omap_w1_write_byte(void *data, u8 byte); +static u8 omap_w1_reset_bus(void *data); +static void omap_w1_search_bus(void *data, u8 search_type, + w1_slave_found_callback slave_found); + +static struct w1_bus_master omap_w1_master = { + .read_byte = omap_w1_read_byte, + .write_byte = omap_w1_write_byte, + .reset_bus = omap_w1_reset_bus, + .search = omap_w1_search_bus, +}; + +/* + * HDQ register I/O routines + */ +static inline u8 +hdq_reg_in(u32 offset) +{ + return omap_readb(hdq_data->hdq_base + offset); +} + +static inline u8 +hdq_reg_out(u32 offset, u8 val) +{ + omap_writeb(val, hdq_data->hdq_base + offset); + return val; +} + +static inline u8 +hdq_reg_merge(u32 offset, u8 val, u8 mask) +{ + u8 new_val = (omap_readb(hdq_data->hdq_base + offset) & ~mask) + | (val & mask);
drivers/w1/masters/omap_hdq.c 2007-12-06 17:14:30.189291891 +0530 line 124
Quoted 10 lines
drivers/w1/masters/omap_hdq.c 2007-12-06 17:14:30.189291891 +0530 renamed from dev/null 1970-01-01 00:00:00.000000000 +0000 +10
-0+ omap_writeb(new_val, hdq_data->hdq_base + offset); + return new_val; +} + +/* + * Wait for one or more bits in flag change. + * HDQ_FLAG_SET: wait until any bit in the flag is set. + * HDQ_FLAG_CLEAR: wait until all bits in the flag are cleared. + * return 0 on success and -ETIMEOUT in the case of timeout. + */
s/-ETIMEOUT/-ETIMEDOUT
Quoted 561 lines
drivers/w1/masters/omap_hdq.c 2007-12-06 17:14:30.189291891 +0530 renamed from dev/null 1970-01-01 00:00:00.000000000 +0000 +529
-0+static int +hdq_wait_for_flag(u32 offset, u8 flag, u8 flag_set, u8 *status) +{ + int ret = 0; + unsigned long timeout = jiffies + OMAP_HDQ_TIMEOUT; + + if (flag_set == OMAP_HDQ_FLAG_CLEAR) { + /* wait for the flag clear */ + while (((*status = hdq_reg_in(offset)) & flag) + && time_before(jiffies, timeout)) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + if (unlikely(*status & flag)) + ret = -ETIMEDOUT; + } else if (flag_set == OMAP_HDQ_FLAG_SET) { + /* wait for the flag set */ + while (!((*status = hdq_reg_in(offset)) & flag) + && time_before(jiffies, timeout)) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + if (unlikely(!(*status & flag))) + ret = -ETIMEDOUT; + } else + return -EINVAL; + + return ret; +} + +/* + * write out a byte and fill *status with HDQ_INT_STATUS + */ +static int +hdq_write_byte(u8 val, u8 *status) +{ + int ret; + u8 tmp_status; + unsigned long irqflags; + + *status = 0; + + spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags); + /* clear interrupt flags via a dummy read */ + hdq_reg_in(OMAP_HDQ_INT_STATUS); + /* ISR loads it with new INT_STATUS */ + hdq_data->hdq_irqstatus = 0; + spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags); + + hdq_reg_out(OMAP_HDQ_TX_DATA, val); + + /* set the GO bit */ + hdq_reg_merge(OMAP_HDQ_CTRL_STATUS, OMAP_HDQ_CTRL_STATUS_GO, + OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO); + /* wait for the TXCOMPLETE bit */ + ret = wait_event_interruptible_timeout(hdq_wait_queue, + hdq_data->hdq_irqstatus, OMAP_HDQ_TIMEOUT); + if (unlikely(ret < 0)) { + pr_debug("wait interrupted"); + return -EINTR; + } + + spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags); + *status = hdq_data->hdq_irqstatus; + spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags); + /* check irqstatus */ + if (!(*status & OMAP_HDQ_INT_STATUS_TXCOMPLETE)) { + pr_debug("timeout waiting for TXCOMPLETE/RXCOMPLETE, %x", + *status); + return -ETIMEDOUT; + } + + /* wait for the GO bit return to zero */ + ret = hdq_wait_for_flag(OMAP_HDQ_CTRL_STATUS, OMAP_HDQ_CTRL_STATUS_GO, + OMAP_HDQ_FLAG_CLEAR, &tmp_status); + if (ret) { + pr_debug("timeout waiting GO bit return to zero, %x", + tmp_status); + return ret; + } + + return ret; +} + +static irqreturn_t +hdq_isr(int irq, void *arg) +{ + unsigned long irqflags; + + spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags); + hdq_data->hdq_irqstatus = hdq_reg_in(OMAP_HDQ_INT_STATUS); + spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags); + pr_debug("hdq_isr: %x", hdq_data->hdq_irqstatus); + + if (hdq_data->hdq_irqstatus & + (OMAP_HDQ_INT_STATUS_TXCOMPLETE | OMAP_HDQ_INT_STATUS_RXCOMPLETE + | OMAP_HDQ_INT_STATUS_TIMEOUT)) { + /* wake up sleeping process */ + wake_up_interruptible(&hdq_wait_queue); + } + + return IRQ_HANDLED; +} + +static u8 omap_w1_reset_bus(void *data) +{ + return 0; +} + +static void omap_w1_search_bus(void *data, u8 search_type, + w1_slave_found_callback slave_found) +{ + u64 module_id, rn_le, cs, id; + + if (W1_ID) + module_id = W1_ID; + else + module_id = 0x1; + + rn_le = cpu_to_le64(module_id); + /* HDQ might not obely truly the 1-wire spec. + * So calculate CRC based on module parameter. + */ + cs = w1_calc_crc8((u8 *)&rn_le, 7); + id = (cs << 56) | module_id; + + slave_found(data, id); +} + +static int +_omap_hdq_reset(void) +{ + int ret; + u8 tmp_status; + + hdq_reg_out(OMAP_HDQ_SYSCONFIG, OMAP_HDQ_SYSCONFIG_SOFTRESET); + /* + * Select HDQ mode & enable clocks. + * It is observed that INT flags can't be cleared via a read and GO/INIT + * won't return to zero if interrupt is disabled. So we always enable + * interrupt. + */ + hdq_reg_out(OMAP_HDQ_CTRL_STATUS, + OMAP_HDQ_CTRL_STATUS_CLOCKENABLE | + OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK); + + /* wait for reset to complete */ + ret = hdq_wait_for_flag(OMAP_HDQ_SYSSTATUS, + OMAP_HDQ_SYSSTATUS_RESETDONE, OMAP_HDQ_FLAG_SET, &tmp_status); + if (ret) + pr_debug("timeout waiting HDQ reset, %x", tmp_status); + else { + hdq_reg_out(OMAP_HDQ_CTRL_STATUS, + OMAP_HDQ_CTRL_STATUS_CLOCKENABLE | + OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK); + hdq_reg_out(OMAP_HDQ_SYSCONFIG, OMAP_HDQ_SYSCONFIG_AUTOIDLE); + } + + return ret; +} + +int +omap_hdq_reset(void) +{ + int ret; + + ret = down_interruptible(&hdq_data->hdq_semlock); + if (ret < 0) + return -EINTR; + + if (!hdq_data->hdq_usecount) { + up(&hdq_data->hdq_semlock); + return -EINVAL; + } + ret = _omap_hdq_reset(); + up(&hdq_data->hdq_semlock); + return ret; +} + +int +omap_hdq_break() +{ + int ret; + u8 tmp_status; + unsigned long irqflags; + + ret = down_interruptible(&hdq_data->hdq_semlock); + if (ret < 0) + return -EINTR; + + if (!hdq_data->hdq_usecount) { + up(&hdq_data->hdq_semlock); + return -EINVAL; + } + + spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags); + /* clear interrupt flags via a dummy read */ + hdq_reg_in(OMAP_HDQ_INT_STATUS); + /* ISR loads it with new INT_STATUS */ + hdq_data->hdq_irqstatus = 0; + spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags); + + /* set the INIT and GO bit */ + hdq_reg_merge(OMAP_HDQ_CTRL_STATUS, + OMAP_HDQ_CTRL_STATUS_INITIALIZATION | OMAP_HDQ_CTRL_STATUS_GO, + OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_INITIALIZATION | + OMAP_HDQ_CTRL_STATUS_GO); + + /* wait for the TIMEOUT bit */ + ret = wait_event_interruptible_timeout(hdq_wait_queue, + hdq_data->hdq_irqstatus, OMAP_HDQ_TIMEOUT); + if (unlikely(ret < 0)) { + pr_debug("wait interrupted"); + up(&hdq_data->hdq_semlock); + return -EINTR; + } + + spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags); + tmp_status = hdq_data->hdq_irqstatus; + spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags); + /* check irqstatus */ + if (!(tmp_status & OMAP_HDQ_INT_STATUS_TIMEOUT)) { + pr_debug("timeout waiting for TIMEOUT, %x", tmp_status); + up(&hdq_data->hdq_semlock); + return -ETIMEDOUT; + } + /* + * wait for both INIT and GO bits rerurn to zero. + * zero wait time expected for interrupt mode. + */ + ret = hdq_wait_for_flag(OMAP_HDQ_CTRL_STATUS, + OMAP_HDQ_CTRL_STATUS_INITIALIZATION | + OMAP_HDQ_CTRL_STATUS_GO, OMAP_HDQ_FLAG_CLEAR, + &tmp_status); + if (ret) + pr_debug("timeout waiting INIT&GO bits return to zero, %x", + tmp_status); + + up(&hdq_data->hdq_semlock); + return ret; +} +EXPORT_SYMBOL(omap_hdq_break); + +int hdq_read_byte(u8 *val) +{ + int ret; + u8 status; + unsigned long irqflags; + + ret = down_interruptible(&hdq_data->hdq_semlock); + if (ret < 0) + return -EINTR; + + if (!hdq_data->hdq_usecount) { + up(&hdq_data->hdq_semlock); + return -EINVAL; + } + + if (!(hdq_data->hdq_irqstatus & OMAP_HDQ_INT_STATUS_RXCOMPLETE)) { + hdq_reg_merge(OMAP_HDQ_CTRL_STATUS, + OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO, + OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO); + /* + * The RX comes immediately after TX. It + * triggers another interrupt before we + * sleep. So we have to wait for RXCOMPLETE bit. + */ + { + unsigned long timeout = jiffies + OMAP_HDQ_TIMEOUT; + while (!(hdq_data->hdq_irqstatus + & OMAP_HDQ_INT_STATUS_RXCOMPLETE) + && time_before(jiffies, timeout)) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } + } + hdq_reg_merge(OMAP_HDQ_CTRL_STATUS, 0, + OMAP_HDQ_CTRL_STATUS_DIR); + spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags); + status = hdq_data->hdq_irqstatus; + spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags); + /* check irqstatus */ + if (!(status & OMAP_HDQ_INT_STATUS_RXCOMPLETE)) { + pr_debug("timeout waiting for RXCOMPLETE, %x", status); + up(&hdq_data->hdq_semlock); + return -ETIMEDOUT; + } + } + /* the data is ready. Read it in! */ + *val = hdq_reg_in(OMAP_HDQ_RX_DATA); + up(&hdq_data->hdq_semlock); + + return 0; + +} + +int +omap_hdq_get() +{ + int ret = 0; + + ret = down_interruptible(&hdq_data->hdq_semlock); + if (ret < 0) + return -EINTR; + + if (OMAP_HDQ_MAX_USER == hdq_data->hdq_usecount) { + pr_debug("attempt to exceed the max use count"); + up(&hdq_data->hdq_semlock); + ret = -EINVAL; + } else { + hdq_data->hdq_usecount++; + try_module_get(THIS_MODULE); + if (1 == hdq_data->hdq_usecount) { + if (clk_enable(hdq_data->hdq_ick)) { + pr_debug("Can not enable ick\n"); + clk_put(hdq_data->hdq_ick); + clk_put(hdq_data->hdq_fck); + up(&hdq_data->hdq_semlock); + return -ENODEV; + } + if (clk_enable(hdq_data->hdq_fck)) { + pr_debug("Can not enable fck\n"); + clk_put(hdq_data->hdq_ick); + clk_put(hdq_data->hdq_fck); + up(&hdq_data->hdq_semlock); + return -ENODEV; + } + + /* make sure HDQ is out of reset */ + if (!(hdq_reg_in(OMAP_HDQ_SYSSTATUS) & + OMAP_HDQ_SYSSTATUS_RESETDONE)) { + ret = _omap_hdq_reset(); + if (ret) + /* back up the count */ + hdq_data->hdq_usecount--; + } else { + /* select HDQ mode & enable clocks */ + hdq_reg_out(OMAP_HDQ_CTRL_STATUS, + OMAP_HDQ_CTRL_STATUS_CLOCKENABLE | + OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK); + hdq_reg_out(OMAP_HDQ_SYSCONFIG, + OMAP_HDQ_SYSCONFIG_AUTOIDLE); + hdq_reg_in(OMAP_HDQ_INT_STATUS); + } + } + } + up(&hdq_data->hdq_semlock); + return ret; +} +EXPORT_SYMBOL(omap_hdq_get); + +int +omap_hdq_put() +{ + int ret = 0; + + ret = down_interruptible(&hdq_data->hdq_semlock); + if (ret < 0) + return -EINTR; + + if (0 == hdq_data->hdq_usecount) { + pr_debug("attempt to decrement use count when it is zero"); + ret = -EINVAL; + } else { + hdq_data->hdq_usecount--; + module_put(THIS_MODULE); + if (0 == hdq_data->hdq_usecount) { + clk_disable(hdq_data->hdq_ick); + clk_disable(hdq_data->hdq_fck); + } + } + up(&hdq_data->hdq_semlock); + return ret; +} +EXPORT_SYMBOL(omap_hdq_put); + +static u8 omap_w1_read_byte(void *data) +{ + u8 val; + int ret; + + ret = hdq_read_byte(&val); + if (ret) + return -1; + return val; +} + +static void omap_w1_write_byte(void *data, u8 byte) +{ + u8 status; + + hdq_write_byte(byte, &status); + pr_debug("Ctrl status %x\n", status); + return; +} + +static int __init omap_hdq_probe(struct platform_device *pdev) +{ + struct resource *res; + int ret, irq; + u8 rev; + + if (!pdev) + return -ENODEV; + + hdq_data = kmalloc(sizeof(*hdq_data), GFP_KERNEL); + if (!hdq_data) + return -ENODEV; + + platform_set_drvdata(pdev, hdq_data); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + platform_set_drvdata(pdev, NULL); + kfree(hdq_data); + return -ENXIO; + } + + hdq_data->hdq_base = res->start; + + /* get interface & functional clock objects */ + hdq_data->hdq_ick = clk_get(&pdev->dev, "hdq_ick"); + hdq_data->hdq_fck = clk_get(&pdev->dev, "hdq_fck"); + + if (IS_ERR(hdq_data->hdq_ick) || IS_ERR(hdq_data->hdq_fck)) { + pr_debug("Can't get HDQ clock objects\n"); + if (IS_ERR(hdq_data->hdq_ick)) { + ret = PTR_ERR(hdq_data->hdq_ick); + platform_set_drvdata(pdev, NULL); + kfree(hdq_data); + return ret; + } + if (IS_ERR(hdq_data->hdq_fck)) { + ret = PTR_ERR(hdq_data->hdq_fck); + platform_set_drvdata(pdev, NULL); + kfree(hdq_data); + return ret; + } + } + + hdq_data->hdq_usecount = 0; + sema_init(&hdq_data->hdq_semlock, 1); + + if (clk_enable(hdq_data->hdq_ick)) { + pr_debug("Can not enable ick\n"); + clk_put(hdq_data->hdq_ick); + clk_put(hdq_data->hdq_fck); + platform_set_drvdata(pdev, NULL); + kfree(hdq_data); + return -ENODEV; + } + + rev = hdq_reg_in(OMAP_HDQ_REVISION); + pr_info("OMAP HDQ Hardware Revision %c.%c. Driver in %s mode.\n", + (rev >> 4) + '0', (rev & 0x0f) + '0', "Interrupt"); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + platform_set_drvdata(pdev, NULL); + kfree(hdq_data); + return -ENXIO; + } + + if (request_irq(irq, hdq_isr, IRQF_DISABLED, "OMAP HDQ", + &hdq_data->hdq_semlock)) { + pr_debug("request_irq failed\n"); + clk_disable(hdq_data->hdq_ick); + clk_put(hdq_data->hdq_ick); + clk_put(hdq_data->hdq_fck); + platform_set_drvdata(pdev, NULL); + kfree(hdq_data); + return -ENODEV; + } + spin_lock_init(&hdq_data->hdq_spinlock); + /* don't clock the HDQ until it is needed */ + clk_disable(hdq_data->hdq_ick); + + ret = w1_add_master_device(&omap_w1_master); + if (ret) { + pr_debug("Failure in registering w1 master\n"); + clk_put(hdq_data->hdq_ick); + clk_put(hdq_data->hdq_fck); + platform_set_drvdata(pdev, NULL); + kfree(hdq_data); + return ret; + } + + return 0; +} + +static int omap_hdq_remove(struct platform_device *pdev) +{ + down_interruptible(&hdq_data->hdq_semlock); + if (0 != hdq_data->hdq_usecount) { + pr_debug("removed when use count is not zero\n"); + return -EBUSY; + } + up(&hdq_data->hdq_semlock); + + /* remove module dependency */ + clk_put(hdq_data->hdq_ick); + clk_put(hdq_data->hdq_fck); + free_irq(INT_24XX_HDQ_IRQ, &hdq_data->hdq_semlock); + platform_set_drvdata(pdev, NULL); + kfree(hdq_data); + + return 0; +} + +static int __init +omap_hdq_init(void) +{ + return platform_driver_register(&omap_hdq_driver); +} + +static void __exit +omap_hdq_exit(void) +{ + platform_driver_unregister(&omap_hdq_driver); +} + +module_init(omap_hdq_init); +module_exit(omap_hdq_exit); + +module_param(W1_ID, int, S_IRUSR); + +MODULE_AUTHOR("Texas Instruments"); +MODULE_DESCRIPTION("HDQ driver Library"); +MODULE_LICENSE("GPL");Index: linux-omap-hdq-new/drivers/w1/masters/Kconfig
===================================================================drivers/w1/masters/Kconfig 2007-12-04 17:58:44.000000000 +0530 renamed from drivers/w1/masters/Kconfig 2007-11-27 20:04:44.000000000 +0530 +8
-0@@ -42,5 +42,13 @@ in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like hx4700. +config HDQ_MASTER_OMAP + tristate "OMAP HDQ driver" + depends on ARCH_OMAP2430 || ARCH_OMAP34XX + help + Say Y here if you want support for the 1-wire or HDQ Interface + on an OMAP processor. + + endmenuIndex: linux-omap-hdq-new/drivers/w1/masters/Makefile
===================================================================drivers/w1/masters/Makefile 2007-12-04 08:55:21.000000000 +0530 renamed from drivers/w1/masters/Makefile 2007-11-27 20:04:44.000000000 +0530 +1
-0@@ -6,3 +6,4 @@ obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o obj-$(CONFIG_W1_MASTER_DS1WM) += ds1wm.o +obj-$(CONFIG_HDQ_MASTER_OMAP) += omap_hdq.oIndex:
linux-omap-hdq-new/include/asm-arm/arch-omap/hdq.h
===================================================================
include/asm-arm/arch-omap/hdq.h 2007-12-04 08:55:21.000000000 +0530 line 2
Quoted 2 lines
include/asm-arm/arch-omap/hdq.h 2007-12-04 08:55:21.000000000 +0530 renamed from dev/null 1970-01-01 00:00:00.000000000 +0000 +2
-0@@ -0,0 +1,23 @@ +/* + * include/asm-arm/arch-omap2/hdq.h
OMAP GIT tree doesn't have arch-omap2 directory.
Quoted 28 lines
include/asm-arm/arch-omap/hdq.h 2007-12-04 08:55:21.000000000 +0530 renamed from dev/null 1970-01-01 00:00:00.000000000 +0000 +21
-0+ * + * Copyright (C) 2006-2007 Texas Instruments, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + * + */ + +#ifndef __ASM_OMAP2_HDQ_H__ +#define __ASM_OMAP2_HDQ_H__ + +/* Note the following API has to be called in a process context */ + +int omap_hdq_get(void); /* request the HDQ block */ +int omap_hdq_put(void); /* release the HDQ block */ + +int omap_hdq_reset(void); /* reset the HDQ block */ +int omap_hdq_break(void); /* reset the slave by sending it a break pulse */ + +#endif_______________________________________________
Linux-omap-open-source mailing list
[email protected]
http://linux.omap.com/mailman/listinfo/linux-omap-open-source
Signature · 1 line
--Trilok Soni