AM437x: HDQ/1wire protocol
Subsystems (6)
v2 cover AM437x: HDQ/1wire protocol
This series adds support for HDQ/1w protocol driver for am43x epos evm where it can be used for measuring the temperature of a slave device connected to a particular header.
Tested the patch series on AM437x, hdq master and slave devices are getting registered and interrupts are getting triggered for break and tx conditions.
v1->v2:
cleaned up "hdq_disable_interrupt" api.
Sourav Poddar (5):
drivers: w1: omap_hdq: cleanup and bug fixes.
w1: omap_hdq: Add compatible property for omap hdq driver.
arm: mach-omap2: selective device build from the platform code.
arm: dts: am4372: Add hdq device tree data.
arm: hwmod: am437x: Add hwmod data for hdq1w.
.../devicetree/bindings/hdq1w/omap_hdq.txt | 20 +++++ arch/arm/boot/dts/am4372.dtsi | 10 +++ arch/arm/boot/dts/am43x-epos-evm.dts | 12 +++ arch/arm/mach-omap2/hdq1w.c | 2 + arch/arm/mach-omap2/omap_hwmod_43xx_data.c | 36 ++++++++ arch/arm/mach-omap2/prcm43xx.h | 1 + drivers/w1/masters/omap_hdq.c | 93 ++++++++++++++++---- 7 files changed, 157 insertions(+), 17 deletions(-) create mode 100644 Documentation/devicetree/bindings/hdq1w/omap_hdq.txt
Signature · 1 line
1.7.9.5
PATCH v2 1/5 drivers: w1: omap_hdq: cleanup and bug fixes.
The patch adds the following to the omap hdq driver.
1. HDQ Device reset call in probe.
2. Enabling '1 wire mode' and checking for presence pulse bit.
3. Proper disabling and enabling of interrupts during read path.
4. Add re-initialization code during SKIP ROM command execution.
5. Miscellaneous cleanup(formatting, return error checks).
--- drivers/w1/masters/omap_hdq.c | 84 ++++++++++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 17 deletions(-)
drivers/w1/masters/omap_hdq.c +67 -17
@@ -27,21 +27,22 @@#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_CTRL_STATUS_INTERRUPTMASK (1 << 6) +#define OMAP_HDQ_CTRL_STATUS_CLOCKENABLE (1 << 5) +#define OMAP_HDQ_CTRL_STATUS_PRESENCE (1 << 3) +#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_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_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_SYSSTATUS_RESETDONE (1 << 0)#define OMAP_HDQ_FLAG_CLEAR 0#define OMAP_HDQ_FLAG_SET 1
@@ -115,6 +116,15 @@ static inline u8 hdq_reg_merge(struct hdq_data *hdq_data, u32 offset,return new_val; } +static void hdq_disable_interrupt (struct hdq_data *hdq_data) +{ +u32 ie; + + ie =readl (hdq_data->hdq_base +OMAP_HDQ_CTRL_STATUS ); +writel (ie & ~OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK , + hdq_data->hdq_base +OMAP_HDQ_CTRL_STATUS ); +} +/* * Wait for one or more bits in flag change. * HDQ_FLAG_SET: wait until any bit in the flag is set.
@@ -263,8 +273,7 @@ static int _omap_hdq_reset(struct hdq_data *hdq_data)* interrupt. */ hdq_reg_out (hdq_data,OMAP_HDQ_CTRL_STATUS , -OMAP_HDQ_CTRL_STATUS_CLOCKENABLE | -OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK ); +OMAP_HDQ_CTRL_STATUS_CLOCKENABLE );/* wait for reset to complete */ ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_SYSSTATUS,
@@ -275,7 +284,8 @@ static int _omap_hdq_reset(struct hdq_data *hdq_data)else {hdq_reg_out (hdq_data,OMAP_HDQ_CTRL_STATUS ,OMAP_HDQ_CTRL_STATUS_CLOCKENABLE | -OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK ); +OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK | +OMAP_HDQ_CTRL_STATUS_MODE );hdq_reg_out (hdq_data,OMAP_HDQ_SYSCONFIG ,OMAP_HDQ_SYSCONFIG_AUTOIDLE ); }
@@ -327,6 +337,18 @@ static int omap_hdq_break(struct hdq_data *hdq_data) ret = -ETIMEDOUT ; goto out; } + +/* +* check for the presence detect bit to get +* set to show that the slave is responding +*/ +if (hdq_reg_in (hdq_data,OMAP_HDQ_CTRL_STATUS ) & +OMAP_HDQ_CTRL_STATUS_PRESENCE ) { +dev_dbg (hdq_data->dev,"Presence bit not set\n" ); + ret = -ETIMEDOUT ; + goto out; + } +/* * wait for both INIT and GO bits rerurn to zero. * zero wait time expected for interrupt mode.
@@ -361,6 +383,8 @@ static int hdq_read_byte(struct hdq_data *hdq_data, u8 *val) goto out; } + hdq_data->hdq_irqstatus =0 ; +if (!(hdq_data->hdq_irqstatus &OMAP_HDQ_INT_STATUS_RXCOMPLETE )) { hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS, OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO,
@@ -426,7 +450,8 @@ static int omap_hdq_get(struct hdq_data *hdq_data)/* select HDQ mode & enable clocks */ hdq_reg_out (hdq_data,OMAP_HDQ_CTRL_STATUS ,OMAP_HDQ_CTRL_STATUS_CLOCKENABLE | -OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK ); +OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK | +OMAP_HDQ_CTRL_STATUS_MODE );hdq_reg_out (hdq_data,OMAP_HDQ_SYSCONFIG ,OMAP_HDQ_SYSCONFIG_AUTOIDLE );hdq_reg_in (hdq_data,OMAP_HDQ_INT_STATUS );
@@ -471,6 +496,10 @@ static u8 omap_w1_read_byte(void *_hdq)u8 val =0 ;int ret; +/* First write to initialize the transfer */ +if (hdq_data->init_trans ==0 ) +omap_hdq_get (hdq_data); + ret =hdq_read_byte (hdq_data, &val);if (ret) { ret =mutex_lock_interruptible (&hdq_data->hdq_mutex);
@@ -484,6 +513,9 @@ static u8 omap_w1_read_byte(void *_hdq)return -1 ; } +hdq_disable_interrupt (hdq_data); + hdq_data->hdq_usecount =0 ; +/* Write followed by a read, release the module */ if (hdq_data->init_trans) { ret =mutex_lock_interruptible (&hdq_data->hdq_mutex);
@@ -510,6 +542,14 @@ static void omap_w1_write_byte(void *_hdq, u8 byte)if (hdq_data->init_trans ==0 )omap_hdq_get (hdq_data); +/* +* We need to reset the slave before +* issuing the SKIP ROM command, else +* the slave will not work. +*/ +if (byte ==W1_SKIP_ROM ) +omap_hdq_break (hdq_data); + ret =mutex_lock_interruptible (&hdq_data->hdq_mutex);if (ret <0 ) {dev_dbg (hdq_data->dev,"Could not acquire mutex\n" );
@@ -563,7 +603,17 @@ static int omap_hdq_probe(struct platform_device *pdev)mutex_init (&hdq_data->hdq_mutex);pm_runtime_enable (&pdev->dev); -pm_runtime_get_sync (&pdev->dev); + ret =pm_runtime_get_sync (&pdev->dev); +if (ret <0 ) { +dev_dbg (&pdev->dev,"pm_runtime_get_sync failed\n" ); + goto err_w1; + } + + ret =_omap_hdq_reset (hdq_data); +if (ret) { +dev_dbg (&pdev->dev,"reset failed\n" ); +return -EINVAL ; + } rev =hdq_reg_in (hdq_data,OMAP_HDQ_REVISION ); dev_info(&pdev->dev, "OMAP HDQ Hardware Rev %c.%c. Driver in %s mode\n",
Signature · 1 line
1.7.9.5
PATCH v2 2/5 w1: omap_hdq: Add compatible property for omap hdq driver.
In reply to Sourav PoddarAdd compatible property for omap hdq driver.
--- .../devicetree/bindings/hdq1w/omap_hdq.txt | 20 ++++++++++++++++++++ drivers/w1/masters/omap_hdq.c | 8 ++++++++ 2 files changed, 28 insertions(+) create mode 100644 Documentation/devicetree/bindings/hdq1w/omap_hdq.txt
Documentation/devicetree/bindings/hdq1w/omap_hdq.txt new file +20 -0
@@ -0,0 +1,20 @@ +HDQ/1w for OMAP platforms + +Required properties : +- compatible : Must be "ti,am43xx-hdq". +- ti,hwmods : Must be "hdq1w". +- reg: Should contain register location and length. +- interrupts: Should contain interrupt. +- clock: Clock input to HDQ1w controller. + +Example: + + hdq: hdq at 48347000 { + compatible = "ti,am43xx-hdq"; + reg = <0x48347000 0x1000>; + interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&func_12m_clk>; + clock-names = "fck"; + ti,hwmods = "hdq1w"; + status = "disabled"; + };
drivers/w1/masters/omap_hdq.c +8 -0
@@ -17,6 +17,7 @@#include <linux/io.h> #include <linux/sched.h> #include <linux/pm_runtime.h> +#include <linux/of.h> #include "../w1.h" #include "../w1_int.h"
@@ -73,11 +74,18 @@ struct hdq_data {static int omap_hdq_probe (struct platform_device *pdev);static int omap_hdq_remove (struct platform_device *pdev); +static const struct of_device_id omap_hdq_dt_match[] = { + { .compatible ="ti,am43xx-hdq" }, + {}, +}; +MODULE_DEVICE_TABLE (of, omap_hdq_dt_match); +static struct platform_driver omap_hdq_driver = { .probe = omap_hdq_probe, .remove = omap_hdq_remove, .driver = { .name ="omap_hdq" , + .of_match_table =of_match_ptr (omap_hdq_dt_match), }, };
Signature · 1 line
1.7.9.5
PATCH v2 3/5 arm: omap2: skip device build from platform code for dt.
In reply to Sourav PoddarFor SOCs with dt enabled, device should be build through device tree. Prevent device build call from platform code, if device tree is enabled.
--- arch/arm/mach-omap2/hdq1w.c | 2 ++ 1 file changed, 2 insertions(+)
arch/arm/mach-omap2/hdq1w.c +2 -0
@@ -76,6 +76,7 @@ int omap_hdq1w_reset(struct omap_hwmod *oh)return 0 ; } +#ifndef CONFIG_OF static int __init omap_init_hdq (void ) {int id =-1 ;
@@ -95,3 +96,4 @@ static int __init omap_init_hdq(void) return 0; }omap_arch_initcall (omap_init_hdq); +#endif
Signature · 1 line
1.7.9.5
Tony Lindgren
maintainerPATCH v2 3/5 arm: omap2: skip device build from platform code for dt.
Quoted 3 lines · Sourav Poddar
For SOCs with dt enabled, device should be build through device tree. Prevent device build call from platform code, if device tree is enabled.
Picking this patch into omap-for-v3.16/dt thanks.
Tony
PATCH v2 4/5 arm: dts: am4372: Add hdq device tree data.
In reply to Sourav PoddarAdd device tree nodes and pinmux for hdq/1wire on
am43x epos evm.
--- arch/arm/boot/dts/am4372.dtsi | 10 ++++++++++ arch/arm/boot/dts/am43x-epos-evm.dts | 12 ++++++++++++ 2 files changed, 22 insertions(+)
arch/arm/boot/dts/am4372.dtsi +10 -0
@@ -735,6 +735,16 @@ #size-cells = <1>; status = "disabled"; }; + + hdq: hdq at 48347000 { + compatible = "ti,am43xx-hdq"; + reg = <0x48347000 0x1000>; + interrupts = <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&func_12m_clk>; + clock-names = "fck"; + ti,hwmods = "hdq1w"; + status = "disabled"; + }; }; };
arch/arm/boot/dts/am43x-epos-evm.dts +12 -0
@@ -138,6 +138,12 @@ 0x160 (PIN_INPUT | MUX_MODE7) /* spi0_cs1.gpio0_6 */ >; }; + + hdq_pins: pinmux_hdq_pins { + pinctrl-single,pins = < + 0x234 (PIN_INPUT_PULLUP | MUX_MODE1) /* cam1_wen.hdq_gpio */ + >; + }; }; matrix_keypad: matrix_keypad at 0 {
@@ -367,3 +373,9 @@ pinctrl-0 = <&spi1_pins>; status = "okay"; }; + +&hdq { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&hdq_pins>; +};
Signature · 1 line
1.7.9.5
Tony Lindgren
maintainerPATCH v2 4/5 arm: dts: am4372: Add hdq device tree data.
Quoted 2 lines · Sourav Poddar
Add device tree nodes and pinmux for hdq/1wire on
am43x epos evm.
Picking this too. The hwmod changes should go through Paul, and the driver changes through the driver list.
Regards,
Tony
PATCH v2 5/5 arm: hwmod: am437x: Add hwmod data for hdq1w.
In reply to Sourav PoddarThese adds hwmod data for hdq/1w driver.
--- arch/arm/mach-omap2/omap_hwmod_43xx_data.c | 36 ++++++++++++++++++++++++++++ arch/arm/mach-omap2/prcm43xx.h | 1 + 2 files changed, 37 insertions(+)
arch/arm/mach-omap2/omap_hwmod_43xx_data.c +36 -0
@@ -19,6 +19,7 @@#include "omap_hwmod.h" #include "omap_hwmod_33xx_43xx_common_data.h" #include "prcm43xx.h" +#include "hdq1w.h" /* IP blocks */ static struct omap_hwmod am43xx_l4_hs_hwmod = {
@@ -415,6 +416,32 @@ static struct omap_hwmod am43xx_qspi_hwmod = { }, }; +static struct omap_hwmod_class_sysconfig am43xx_hdq1w_sysc = { + .rev_offs =0x0000 , + .sysc_offs =0x0014 , + .syss_offs =0x0018 , + .sysc_flags = (SYSC_HAS_SOFTRESET ), + .sysc_fields = &omap_hwmod_sysc_type1, +}; + +static struct omap_hwmod_class am43xx_hdq1w_hwmod_class = { + .name ="hdq1w" , + .sysc = &am43xx_hdq1w_sysc, + .reset = &omap_hdq1w_reset, +}; + +static struct omap_hwmod am43xx_hdq1w_hwmod = { + .name ="hdq1w" , + .class = &am43xx_hdq1w_hwmod_class, + .clkdm_name ="l4ls_clkdm" , + .prcm = { + .omap4 = { + .clkctrl_offs =AM43XX_CM_PER_HDQ1W_CLKCTRL_OFFSET , + .modulemode =MODULEMODE_SWCTRL , + }, + }, +}; +/* Interfaces */ static struct omap_hwmod_ocp_if am43xx_l3_main__l4_hs = { .master = &am33xx_l3_main_hwmod,
@@ -654,6 +681,14 @@ static struct omap_hwmod_ocp_if am43xx_l3_s__qspi = { .user = OCP_USER_MPU | OCP_USER_SDMA, }; +/* l4_per -> hdq1w */ +static struct omap_hwmod_ocp_if am43xx_l4_ls__hdq1w = { + .master = &am33xx_l4_ls_hwmod, + .slave = &am43xx_hdq1w_hwmod, + .clk ="l4ls_gclk" , + .user =OCP_USER_MPU |OCP_USER_SDMA , +}; +static struct omap_hwmod_ocp_if *am43xx_hwmod_ocp_ifs[]__initdata = { &am33xx_l4_wkup__synctimer, &am43xx_l4_ls__timer8,
@@ -748,6 +783,7 @@ static struct omap_hwmod_ocp_if *am43xx_hwmod_ocp_ifs[] __initdata = { &am43xx_l4_ls__ocp2scp1, &am43xx_l3_s__usbotgss0, &am43xx_l3_s__usbotgss1, + &am43xx_l4_ls__hdq1w, NULL, };
arch/arm/mach-omap2/prcm43xx.h +1 -0
@@ -142,5 +142,6 @@#define AM43XX_CM_PER_USBPHYOCP2SCP0_CLKCTRL_OFFSET 0x05B8#define AM43XX_CM_PER_USB_OTG_SS1_CLKCTRL_OFFSET 0x0268#define AM43XX_CM_PER_USBPHYOCP2SCP1_CLKCTRL_OFFSET 0x05C0 +#define AM43XX_CM_PER_HDQ1W_CLKCTRL_OFFSET 0x04a0#endif
Signature · 1 line
1.7.9.5