18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * drivers/w1/masters/omap_hdq.c
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2007,2012 Texas Instruments, Inc.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public License
78c2ecf20Sopenharmony_ci * version 2. This program is licensed "as is" without any warranty of any
88c2ecf20Sopenharmony_ci * kind, whether express or implied.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
148c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci#include <linux/err.h>
178c2ecf20Sopenharmony_ci#include <linux/io.h>
188c2ecf20Sopenharmony_ci#include <linux/sched.h>
198c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
208c2ecf20Sopenharmony_ci#include <linux/of.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <linux/w1.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define	MOD_NAME	"OMAP_HDQ:"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define OMAP_HDQ_REVISION			0x00
278c2ecf20Sopenharmony_ci#define OMAP_HDQ_TX_DATA			0x04
288c2ecf20Sopenharmony_ci#define OMAP_HDQ_RX_DATA			0x08
298c2ecf20Sopenharmony_ci#define OMAP_HDQ_CTRL_STATUS			0x0c
308c2ecf20Sopenharmony_ci#define OMAP_HDQ_CTRL_STATUS_SINGLE		BIT(7)
318c2ecf20Sopenharmony_ci#define OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK	BIT(6)
328c2ecf20Sopenharmony_ci#define OMAP_HDQ_CTRL_STATUS_CLOCKENABLE	BIT(5)
338c2ecf20Sopenharmony_ci#define OMAP_HDQ_CTRL_STATUS_GO                 BIT(4)
348c2ecf20Sopenharmony_ci#define OMAP_HDQ_CTRL_STATUS_PRESENCE		BIT(3)
358c2ecf20Sopenharmony_ci#define OMAP_HDQ_CTRL_STATUS_INITIALIZATION	BIT(2)
368c2ecf20Sopenharmony_ci#define OMAP_HDQ_CTRL_STATUS_DIR		BIT(1)
378c2ecf20Sopenharmony_ci#define OMAP_HDQ_INT_STATUS			0x10
388c2ecf20Sopenharmony_ci#define OMAP_HDQ_INT_STATUS_TXCOMPLETE		BIT(2)
398c2ecf20Sopenharmony_ci#define OMAP_HDQ_INT_STATUS_RXCOMPLETE		BIT(1)
408c2ecf20Sopenharmony_ci#define OMAP_HDQ_INT_STATUS_TIMEOUT		BIT(0)
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#define OMAP_HDQ_FLAG_CLEAR			0
438c2ecf20Sopenharmony_ci#define OMAP_HDQ_FLAG_SET			1
448c2ecf20Sopenharmony_ci#define OMAP_HDQ_TIMEOUT			(HZ/5)
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#define OMAP_HDQ_MAX_USER			4
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(hdq_wait_queue);
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic int w1_id;
518c2ecf20Sopenharmony_cimodule_param(w1_id, int, S_IRUSR);
528c2ecf20Sopenharmony_ciMODULE_PARM_DESC(w1_id, "1-wire id for the slave detection in HDQ mode");
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistruct hdq_data {
558c2ecf20Sopenharmony_ci	struct device		*dev;
568c2ecf20Sopenharmony_ci	void __iomem		*hdq_base;
578c2ecf20Sopenharmony_ci	/* lock read/write/break operations */
588c2ecf20Sopenharmony_ci	struct  mutex		hdq_mutex;
598c2ecf20Sopenharmony_ci	/* interrupt status and a lock for it */
608c2ecf20Sopenharmony_ci	u8			hdq_irqstatus;
618c2ecf20Sopenharmony_ci	spinlock_t		hdq_spinlock;
628c2ecf20Sopenharmony_ci	/* mode: 0-HDQ 1-W1 */
638c2ecf20Sopenharmony_ci	int                     mode;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci};
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci/* HDQ register I/O routines */
688c2ecf20Sopenharmony_cistatic inline u8 hdq_reg_in(struct hdq_data *hdq_data, u32 offset)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	return __raw_readl(hdq_data->hdq_base + offset);
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic inline void hdq_reg_out(struct hdq_data *hdq_data, u32 offset, u8 val)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	__raw_writel(val, hdq_data->hdq_base + offset);
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic inline u8 hdq_reg_merge(struct hdq_data *hdq_data, u32 offset,
798c2ecf20Sopenharmony_ci			u8 val, u8 mask)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	u8 new_val = (__raw_readl(hdq_data->hdq_base + offset) & ~mask)
828c2ecf20Sopenharmony_ci			| (val & mask);
838c2ecf20Sopenharmony_ci	__raw_writel(new_val, hdq_data->hdq_base + offset);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	return new_val;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci/*
898c2ecf20Sopenharmony_ci * Wait for one or more bits in flag change.
908c2ecf20Sopenharmony_ci * HDQ_FLAG_SET: wait until any bit in the flag is set.
918c2ecf20Sopenharmony_ci * HDQ_FLAG_CLEAR: wait until all bits in the flag are cleared.
928c2ecf20Sopenharmony_ci * return 0 on success and -ETIMEDOUT in the case of timeout.
938c2ecf20Sopenharmony_ci */
948c2ecf20Sopenharmony_cistatic int hdq_wait_for_flag(struct hdq_data *hdq_data, u32 offset,
958c2ecf20Sopenharmony_ci		u8 flag, u8 flag_set, u8 *status)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	int ret = 0;
988c2ecf20Sopenharmony_ci	unsigned long timeout = jiffies + OMAP_HDQ_TIMEOUT;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	if (flag_set == OMAP_HDQ_FLAG_CLEAR) {
1018c2ecf20Sopenharmony_ci		/* wait for the flag clear */
1028c2ecf20Sopenharmony_ci		while (((*status = hdq_reg_in(hdq_data, offset)) & flag)
1038c2ecf20Sopenharmony_ci			&& time_before(jiffies, timeout)) {
1048c2ecf20Sopenharmony_ci			schedule_timeout_uninterruptible(1);
1058c2ecf20Sopenharmony_ci		}
1068c2ecf20Sopenharmony_ci		if (*status & flag)
1078c2ecf20Sopenharmony_ci			ret = -ETIMEDOUT;
1088c2ecf20Sopenharmony_ci	} else if (flag_set == OMAP_HDQ_FLAG_SET) {
1098c2ecf20Sopenharmony_ci		/* wait for the flag set */
1108c2ecf20Sopenharmony_ci		while (!((*status = hdq_reg_in(hdq_data, offset)) & flag)
1118c2ecf20Sopenharmony_ci			&& time_before(jiffies, timeout)) {
1128c2ecf20Sopenharmony_ci			schedule_timeout_uninterruptible(1);
1138c2ecf20Sopenharmony_ci		}
1148c2ecf20Sopenharmony_ci		if (!(*status & flag))
1158c2ecf20Sopenharmony_ci			ret = -ETIMEDOUT;
1168c2ecf20Sopenharmony_ci	} else
1178c2ecf20Sopenharmony_ci		return -EINVAL;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	return ret;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci/* Clear saved irqstatus after using an interrupt */
1238c2ecf20Sopenharmony_cistatic u8 hdq_reset_irqstatus(struct hdq_data *hdq_data, u8 bits)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	unsigned long irqflags;
1268c2ecf20Sopenharmony_ci	u8 status;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
1298c2ecf20Sopenharmony_ci	status = hdq_data->hdq_irqstatus;
1308c2ecf20Sopenharmony_ci	/* this is a read-modify-write */
1318c2ecf20Sopenharmony_ci	hdq_data->hdq_irqstatus &= ~bits;
1328c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	return status;
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci/* write out a byte and fill *status with HDQ_INT_STATUS */
1388c2ecf20Sopenharmony_cistatic int hdq_write_byte(struct hdq_data *hdq_data, u8 val, u8 *status)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	int ret;
1418c2ecf20Sopenharmony_ci	u8 tmp_status;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
1448c2ecf20Sopenharmony_ci	if (ret < 0) {
1458c2ecf20Sopenharmony_ci		ret = -EINTR;
1468c2ecf20Sopenharmony_ci		goto rtn;
1478c2ecf20Sopenharmony_ci	}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	if (hdq_data->hdq_irqstatus)
1508c2ecf20Sopenharmony_ci		dev_err(hdq_data->dev, "TX irqstatus not cleared (%02x)\n",
1518c2ecf20Sopenharmony_ci			hdq_data->hdq_irqstatus);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	*status = 0;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	hdq_reg_out(hdq_data, OMAP_HDQ_TX_DATA, val);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	/* set the GO bit */
1588c2ecf20Sopenharmony_ci	hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS, OMAP_HDQ_CTRL_STATUS_GO,
1598c2ecf20Sopenharmony_ci		OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO);
1608c2ecf20Sopenharmony_ci	/* wait for the TXCOMPLETE bit */
1618c2ecf20Sopenharmony_ci	ret = wait_event_timeout(hdq_wait_queue,
1628c2ecf20Sopenharmony_ci		(hdq_data->hdq_irqstatus & OMAP_HDQ_INT_STATUS_TXCOMPLETE),
1638c2ecf20Sopenharmony_ci		OMAP_HDQ_TIMEOUT);
1648c2ecf20Sopenharmony_ci	*status = hdq_reset_irqstatus(hdq_data, OMAP_HDQ_INT_STATUS_TXCOMPLETE);
1658c2ecf20Sopenharmony_ci	if (ret == 0) {
1668c2ecf20Sopenharmony_ci		dev_dbg(hdq_data->dev, "TX wait elapsed\n");
1678c2ecf20Sopenharmony_ci		ret = -ETIMEDOUT;
1688c2ecf20Sopenharmony_ci		goto out;
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	/* check irqstatus */
1728c2ecf20Sopenharmony_ci	if (!(*status & OMAP_HDQ_INT_STATUS_TXCOMPLETE)) {
1738c2ecf20Sopenharmony_ci		dev_dbg(hdq_data->dev, "timeout waiting for"
1748c2ecf20Sopenharmony_ci			" TXCOMPLETE/RXCOMPLETE, %x\n", *status);
1758c2ecf20Sopenharmony_ci		ret = -ETIMEDOUT;
1768c2ecf20Sopenharmony_ci		goto out;
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	/* wait for the GO bit return to zero */
1808c2ecf20Sopenharmony_ci	ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_CTRL_STATUS,
1818c2ecf20Sopenharmony_ci			OMAP_HDQ_CTRL_STATUS_GO,
1828c2ecf20Sopenharmony_ci			OMAP_HDQ_FLAG_CLEAR, &tmp_status);
1838c2ecf20Sopenharmony_ci	if (ret) {
1848c2ecf20Sopenharmony_ci		dev_dbg(hdq_data->dev, "timeout waiting GO bit"
1858c2ecf20Sopenharmony_ci			" return to zero, %x\n", tmp_status);
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ciout:
1898c2ecf20Sopenharmony_ci	mutex_unlock(&hdq_data->hdq_mutex);
1908c2ecf20Sopenharmony_cirtn:
1918c2ecf20Sopenharmony_ci	return ret;
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci/* HDQ Interrupt service routine */
1958c2ecf20Sopenharmony_cistatic irqreturn_t hdq_isr(int irq, void *_hdq)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	struct hdq_data *hdq_data = _hdq;
1988c2ecf20Sopenharmony_ci	unsigned long irqflags;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
2018c2ecf20Sopenharmony_ci	hdq_data->hdq_irqstatus |= hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
2028c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&hdq_data->hdq_spinlock, irqflags);
2038c2ecf20Sopenharmony_ci	dev_dbg(hdq_data->dev, "hdq_isr: %x\n", hdq_data->hdq_irqstatus);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	if (hdq_data->hdq_irqstatus &
2068c2ecf20Sopenharmony_ci		(OMAP_HDQ_INT_STATUS_TXCOMPLETE | OMAP_HDQ_INT_STATUS_RXCOMPLETE
2078c2ecf20Sopenharmony_ci		| OMAP_HDQ_INT_STATUS_TIMEOUT)) {
2088c2ecf20Sopenharmony_ci		/* wake up sleeping process */
2098c2ecf20Sopenharmony_ci		wake_up(&hdq_wait_queue);
2108c2ecf20Sopenharmony_ci	}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci/* W1 search callback function  in HDQ mode */
2168c2ecf20Sopenharmony_cistatic void omap_w1_search_bus(void *_hdq, struct w1_master *master_dev,
2178c2ecf20Sopenharmony_ci		u8 search_type, w1_slave_found_callback slave_found)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	u64 module_id, rn_le, cs, id;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	if (w1_id)
2228c2ecf20Sopenharmony_ci		module_id = w1_id;
2238c2ecf20Sopenharmony_ci	else
2248c2ecf20Sopenharmony_ci		module_id = 0x1;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	rn_le = cpu_to_le64(module_id);
2278c2ecf20Sopenharmony_ci	/*
2288c2ecf20Sopenharmony_ci	 * HDQ might not obey truly the 1-wire spec.
2298c2ecf20Sopenharmony_ci	 * So calculate CRC based on module parameter.
2308c2ecf20Sopenharmony_ci	 */
2318c2ecf20Sopenharmony_ci	cs = w1_calc_crc8((u8 *)&rn_le, 7);
2328c2ecf20Sopenharmony_ci	id = (cs << 56) | module_id;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	slave_found(master_dev, id);
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci/* Issue break pulse to the device */
2388c2ecf20Sopenharmony_cistatic int omap_hdq_break(struct hdq_data *hdq_data)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	int ret = 0;
2418c2ecf20Sopenharmony_ci	u8 tmp_status;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
2448c2ecf20Sopenharmony_ci	if (ret < 0) {
2458c2ecf20Sopenharmony_ci		dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
2468c2ecf20Sopenharmony_ci		ret = -EINTR;
2478c2ecf20Sopenharmony_ci		goto rtn;
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	if (hdq_data->hdq_irqstatus)
2518c2ecf20Sopenharmony_ci		dev_err(hdq_data->dev, "break irqstatus not cleared (%02x)\n",
2528c2ecf20Sopenharmony_ci			hdq_data->hdq_irqstatus);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	/* set the INIT and GO bit */
2558c2ecf20Sopenharmony_ci	hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS,
2568c2ecf20Sopenharmony_ci		OMAP_HDQ_CTRL_STATUS_INITIALIZATION | OMAP_HDQ_CTRL_STATUS_GO,
2578c2ecf20Sopenharmony_ci		OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_INITIALIZATION |
2588c2ecf20Sopenharmony_ci		OMAP_HDQ_CTRL_STATUS_GO);
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	/* wait for the TIMEOUT bit */
2618c2ecf20Sopenharmony_ci	ret = wait_event_timeout(hdq_wait_queue,
2628c2ecf20Sopenharmony_ci		(hdq_data->hdq_irqstatus & OMAP_HDQ_INT_STATUS_TIMEOUT),
2638c2ecf20Sopenharmony_ci		OMAP_HDQ_TIMEOUT);
2648c2ecf20Sopenharmony_ci	tmp_status = hdq_reset_irqstatus(hdq_data, OMAP_HDQ_INT_STATUS_TIMEOUT);
2658c2ecf20Sopenharmony_ci	if (ret == 0) {
2668c2ecf20Sopenharmony_ci		dev_dbg(hdq_data->dev, "break wait elapsed\n");
2678c2ecf20Sopenharmony_ci		ret = -EINTR;
2688c2ecf20Sopenharmony_ci		goto out;
2698c2ecf20Sopenharmony_ci	}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	/* check irqstatus */
2728c2ecf20Sopenharmony_ci	if (!(tmp_status & OMAP_HDQ_INT_STATUS_TIMEOUT)) {
2738c2ecf20Sopenharmony_ci		dev_dbg(hdq_data->dev, "timeout waiting for TIMEOUT, %x\n",
2748c2ecf20Sopenharmony_ci			tmp_status);
2758c2ecf20Sopenharmony_ci		ret = -ETIMEDOUT;
2768c2ecf20Sopenharmony_ci		goto out;
2778c2ecf20Sopenharmony_ci	}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	/*
2808c2ecf20Sopenharmony_ci	 * check for the presence detect bit to get
2818c2ecf20Sopenharmony_ci	 * set to show that the slave is responding
2828c2ecf20Sopenharmony_ci	 */
2838c2ecf20Sopenharmony_ci	if (!(hdq_reg_in(hdq_data, OMAP_HDQ_CTRL_STATUS) &
2848c2ecf20Sopenharmony_ci			OMAP_HDQ_CTRL_STATUS_PRESENCE)) {
2858c2ecf20Sopenharmony_ci		dev_dbg(hdq_data->dev, "Presence bit not set\n");
2868c2ecf20Sopenharmony_ci		ret = -ETIMEDOUT;
2878c2ecf20Sopenharmony_ci		goto out;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	/*
2918c2ecf20Sopenharmony_ci	 * wait for both INIT and GO bits rerurn to zero.
2928c2ecf20Sopenharmony_ci	 * zero wait time expected for interrupt mode.
2938c2ecf20Sopenharmony_ci	 */
2948c2ecf20Sopenharmony_ci	ret = hdq_wait_for_flag(hdq_data, OMAP_HDQ_CTRL_STATUS,
2958c2ecf20Sopenharmony_ci			OMAP_HDQ_CTRL_STATUS_INITIALIZATION |
2968c2ecf20Sopenharmony_ci			OMAP_HDQ_CTRL_STATUS_GO, OMAP_HDQ_FLAG_CLEAR,
2978c2ecf20Sopenharmony_ci			&tmp_status);
2988c2ecf20Sopenharmony_ci	if (ret)
2998c2ecf20Sopenharmony_ci		dev_dbg(hdq_data->dev, "timeout waiting INIT&GO bits"
3008c2ecf20Sopenharmony_ci			" return to zero, %x\n", tmp_status);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ciout:
3038c2ecf20Sopenharmony_ci	mutex_unlock(&hdq_data->hdq_mutex);
3048c2ecf20Sopenharmony_cirtn:
3058c2ecf20Sopenharmony_ci	return ret;
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic int hdq_read_byte(struct hdq_data *hdq_data, u8 *val)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	int ret = 0;
3118c2ecf20Sopenharmony_ci	u8 status;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
3148c2ecf20Sopenharmony_ci	if (ret < 0) {
3158c2ecf20Sopenharmony_ci		ret = -EINTR;
3168c2ecf20Sopenharmony_ci		goto rtn;
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	if (pm_runtime_suspended(hdq_data->dev)) {
3208c2ecf20Sopenharmony_ci		ret = -EINVAL;
3218c2ecf20Sopenharmony_ci		goto out;
3228c2ecf20Sopenharmony_ci	}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	if (!(hdq_data->hdq_irqstatus & OMAP_HDQ_INT_STATUS_RXCOMPLETE)) {
3258c2ecf20Sopenharmony_ci		hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS,
3268c2ecf20Sopenharmony_ci			OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO,
3278c2ecf20Sopenharmony_ci			OMAP_HDQ_CTRL_STATUS_DIR | OMAP_HDQ_CTRL_STATUS_GO);
3288c2ecf20Sopenharmony_ci		/*
3298c2ecf20Sopenharmony_ci		 * The RX comes immediately after TX.
3308c2ecf20Sopenharmony_ci		 */
3318c2ecf20Sopenharmony_ci		wait_event_timeout(hdq_wait_queue,
3328c2ecf20Sopenharmony_ci				   (hdq_data->hdq_irqstatus
3338c2ecf20Sopenharmony_ci				    & (OMAP_HDQ_INT_STATUS_RXCOMPLETE |
3348c2ecf20Sopenharmony_ci				       OMAP_HDQ_INT_STATUS_TIMEOUT)),
3358c2ecf20Sopenharmony_ci				   OMAP_HDQ_TIMEOUT);
3368c2ecf20Sopenharmony_ci		status = hdq_reset_irqstatus(hdq_data,
3378c2ecf20Sopenharmony_ci					     OMAP_HDQ_INT_STATUS_RXCOMPLETE |
3388c2ecf20Sopenharmony_ci					     OMAP_HDQ_INT_STATUS_TIMEOUT);
3398c2ecf20Sopenharmony_ci		hdq_reg_merge(hdq_data, OMAP_HDQ_CTRL_STATUS, 0,
3408c2ecf20Sopenharmony_ci			OMAP_HDQ_CTRL_STATUS_DIR);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci		/* check irqstatus */
3438c2ecf20Sopenharmony_ci		if (!(status & OMAP_HDQ_INT_STATUS_RXCOMPLETE)) {
3448c2ecf20Sopenharmony_ci			dev_dbg(hdq_data->dev, "timeout waiting for"
3458c2ecf20Sopenharmony_ci				" RXCOMPLETE, %x", status);
3468c2ecf20Sopenharmony_ci			ret = -ETIMEDOUT;
3478c2ecf20Sopenharmony_ci			goto out;
3488c2ecf20Sopenharmony_ci		}
3498c2ecf20Sopenharmony_ci	} else { /* interrupt had occurred before hdq_read_byte was called */
3508c2ecf20Sopenharmony_ci		hdq_reset_irqstatus(hdq_data, OMAP_HDQ_INT_STATUS_RXCOMPLETE);
3518c2ecf20Sopenharmony_ci	}
3528c2ecf20Sopenharmony_ci	/* the data is ready. Read it in! */
3538c2ecf20Sopenharmony_ci	*val = hdq_reg_in(hdq_data, OMAP_HDQ_RX_DATA);
3548c2ecf20Sopenharmony_ciout:
3558c2ecf20Sopenharmony_ci	mutex_unlock(&hdq_data->hdq_mutex);
3568c2ecf20Sopenharmony_cirtn:
3578c2ecf20Sopenharmony_ci	return ret;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci/*
3628c2ecf20Sopenharmony_ci * W1 triplet callback function - used for searching ROM addresses.
3638c2ecf20Sopenharmony_ci * Registered only when controller is in 1-wire mode.
3648c2ecf20Sopenharmony_ci */
3658c2ecf20Sopenharmony_cistatic u8 omap_w1_triplet(void *_hdq, u8 bdir)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	u8 id_bit, comp_bit;
3688c2ecf20Sopenharmony_ci	int err;
3698c2ecf20Sopenharmony_ci	u8 ret = 0x3; /* no slaves responded */
3708c2ecf20Sopenharmony_ci	struct hdq_data *hdq_data = _hdq;
3718c2ecf20Sopenharmony_ci	u8 ctrl = OMAP_HDQ_CTRL_STATUS_SINGLE | OMAP_HDQ_CTRL_STATUS_GO |
3728c2ecf20Sopenharmony_ci		  OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK;
3738c2ecf20Sopenharmony_ci	u8 mask = ctrl | OMAP_HDQ_CTRL_STATUS_DIR;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	err = pm_runtime_get_sync(hdq_data->dev);
3768c2ecf20Sopenharmony_ci	if (err < 0) {
3778c2ecf20Sopenharmony_ci		pm_runtime_put_noidle(hdq_data->dev);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci		return err;
3808c2ecf20Sopenharmony_ci	}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	err = mutex_lock_interruptible(&hdq_data->hdq_mutex);
3838c2ecf20Sopenharmony_ci	if (err < 0) {
3848c2ecf20Sopenharmony_ci		dev_dbg(hdq_data->dev, "Could not acquire mutex\n");
3858c2ecf20Sopenharmony_ci		goto rtn;
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	/* read id_bit */
3898c2ecf20Sopenharmony_ci	hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS,
3908c2ecf20Sopenharmony_ci		      ctrl | OMAP_HDQ_CTRL_STATUS_DIR, mask);
3918c2ecf20Sopenharmony_ci	err = wait_event_timeout(hdq_wait_queue,
3928c2ecf20Sopenharmony_ci				 (hdq_data->hdq_irqstatus
3938c2ecf20Sopenharmony_ci				  & OMAP_HDQ_INT_STATUS_RXCOMPLETE),
3948c2ecf20Sopenharmony_ci				 OMAP_HDQ_TIMEOUT);
3958c2ecf20Sopenharmony_ci	/* Must clear irqstatus for another RXCOMPLETE interrupt */
3968c2ecf20Sopenharmony_ci	hdq_reset_irqstatus(hdq_data, OMAP_HDQ_INT_STATUS_RXCOMPLETE);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	if (err == 0) {
3998c2ecf20Sopenharmony_ci		dev_dbg(hdq_data->dev, "RX wait elapsed\n");
4008c2ecf20Sopenharmony_ci		goto out;
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci	id_bit = (hdq_reg_in(_hdq, OMAP_HDQ_RX_DATA) & 0x01);
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	/* read comp_bit */
4058c2ecf20Sopenharmony_ci	hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS,
4068c2ecf20Sopenharmony_ci		      ctrl | OMAP_HDQ_CTRL_STATUS_DIR, mask);
4078c2ecf20Sopenharmony_ci	err = wait_event_timeout(hdq_wait_queue,
4088c2ecf20Sopenharmony_ci				 (hdq_data->hdq_irqstatus
4098c2ecf20Sopenharmony_ci				  & OMAP_HDQ_INT_STATUS_RXCOMPLETE),
4108c2ecf20Sopenharmony_ci				 OMAP_HDQ_TIMEOUT);
4118c2ecf20Sopenharmony_ci	/* Must clear irqstatus for another RXCOMPLETE interrupt */
4128c2ecf20Sopenharmony_ci	hdq_reset_irqstatus(hdq_data, OMAP_HDQ_INT_STATUS_RXCOMPLETE);
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	if (err == 0) {
4158c2ecf20Sopenharmony_ci		dev_dbg(hdq_data->dev, "RX wait elapsed\n");
4168c2ecf20Sopenharmony_ci		goto out;
4178c2ecf20Sopenharmony_ci	}
4188c2ecf20Sopenharmony_ci	comp_bit = (hdq_reg_in(_hdq, OMAP_HDQ_RX_DATA) & 0x01);
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	if (id_bit && comp_bit) {
4218c2ecf20Sopenharmony_ci		ret = 0x03;  /* no slaves responded */
4228c2ecf20Sopenharmony_ci		goto out;
4238c2ecf20Sopenharmony_ci	}
4248c2ecf20Sopenharmony_ci	if (!id_bit && !comp_bit) {
4258c2ecf20Sopenharmony_ci		/* Both bits are valid, take the direction given */
4268c2ecf20Sopenharmony_ci		ret = bdir ? 0x04 : 0;
4278c2ecf20Sopenharmony_ci	} else {
4288c2ecf20Sopenharmony_ci		/* Only one bit is valid, take that direction */
4298c2ecf20Sopenharmony_ci		bdir = id_bit;
4308c2ecf20Sopenharmony_ci		ret = id_bit ? 0x05 : 0x02;
4318c2ecf20Sopenharmony_ci	}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	/* write bdir bit */
4348c2ecf20Sopenharmony_ci	hdq_reg_out(_hdq, OMAP_HDQ_TX_DATA, bdir);
4358c2ecf20Sopenharmony_ci	hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS, ctrl, mask);
4368c2ecf20Sopenharmony_ci	err = wait_event_timeout(hdq_wait_queue,
4378c2ecf20Sopenharmony_ci				 (hdq_data->hdq_irqstatus
4388c2ecf20Sopenharmony_ci				  & OMAP_HDQ_INT_STATUS_TXCOMPLETE),
4398c2ecf20Sopenharmony_ci				 OMAP_HDQ_TIMEOUT);
4408c2ecf20Sopenharmony_ci	/* Must clear irqstatus for another TXCOMPLETE interrupt */
4418c2ecf20Sopenharmony_ci	hdq_reset_irqstatus(hdq_data, OMAP_HDQ_INT_STATUS_TXCOMPLETE);
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	if (err == 0) {
4448c2ecf20Sopenharmony_ci		dev_dbg(hdq_data->dev, "TX wait elapsed\n");
4458c2ecf20Sopenharmony_ci		goto out;
4468c2ecf20Sopenharmony_ci	}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	hdq_reg_merge(_hdq, OMAP_HDQ_CTRL_STATUS, 0,
4498c2ecf20Sopenharmony_ci		      OMAP_HDQ_CTRL_STATUS_SINGLE);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ciout:
4528c2ecf20Sopenharmony_ci	mutex_unlock(&hdq_data->hdq_mutex);
4538c2ecf20Sopenharmony_cirtn:
4548c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(hdq_data->dev);
4558c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(hdq_data->dev);
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	return ret;
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci/* reset callback */
4618c2ecf20Sopenharmony_cistatic u8 omap_w1_reset_bus(void *_hdq)
4628c2ecf20Sopenharmony_ci{
4638c2ecf20Sopenharmony_ci	struct hdq_data *hdq_data = _hdq;
4648c2ecf20Sopenharmony_ci	int err;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	err = pm_runtime_get_sync(hdq_data->dev);
4678c2ecf20Sopenharmony_ci	if (err < 0) {
4688c2ecf20Sopenharmony_ci		pm_runtime_put_noidle(hdq_data->dev);
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci		return err;
4718c2ecf20Sopenharmony_ci	}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	omap_hdq_break(hdq_data);
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(hdq_data->dev);
4768c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(hdq_data->dev);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	return 0;
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci/* Read a byte of data from the device */
4828c2ecf20Sopenharmony_cistatic u8 omap_w1_read_byte(void *_hdq)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	struct hdq_data *hdq_data = _hdq;
4858c2ecf20Sopenharmony_ci	u8 val = 0;
4868c2ecf20Sopenharmony_ci	int ret;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	ret = pm_runtime_get_sync(hdq_data->dev);
4898c2ecf20Sopenharmony_ci	if (ret < 0) {
4908c2ecf20Sopenharmony_ci		pm_runtime_put_noidle(hdq_data->dev);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci		return -1;
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	ret = hdq_read_byte(hdq_data, &val);
4968c2ecf20Sopenharmony_ci	if (ret)
4978c2ecf20Sopenharmony_ci		val = -1;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(hdq_data->dev);
5008c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(hdq_data->dev);
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	return val;
5038c2ecf20Sopenharmony_ci}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci/* Write a byte of data to the device */
5068c2ecf20Sopenharmony_cistatic void omap_w1_write_byte(void *_hdq, u8 byte)
5078c2ecf20Sopenharmony_ci{
5088c2ecf20Sopenharmony_ci	struct hdq_data *hdq_data = _hdq;
5098c2ecf20Sopenharmony_ci	int ret;
5108c2ecf20Sopenharmony_ci	u8 status;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	ret = pm_runtime_get_sync(hdq_data->dev);
5138c2ecf20Sopenharmony_ci	if (ret < 0) {
5148c2ecf20Sopenharmony_ci		pm_runtime_put_noidle(hdq_data->dev);
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci		return;
5178c2ecf20Sopenharmony_ci	}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	/*
5208c2ecf20Sopenharmony_ci	 * We need to reset the slave before
5218c2ecf20Sopenharmony_ci	 * issuing the SKIP ROM command, else
5228c2ecf20Sopenharmony_ci	 * the slave will not work.
5238c2ecf20Sopenharmony_ci	 */
5248c2ecf20Sopenharmony_ci	if (byte == W1_SKIP_ROM)
5258c2ecf20Sopenharmony_ci		omap_hdq_break(hdq_data);
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	ret = hdq_write_byte(hdq_data, byte, &status);
5288c2ecf20Sopenharmony_ci	if (ret < 0) {
5298c2ecf20Sopenharmony_ci		dev_dbg(hdq_data->dev, "TX failure:Ctrl status %x\n", status);
5308c2ecf20Sopenharmony_ci		goto out_err;
5318c2ecf20Sopenharmony_ci	}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ciout_err:
5348c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(hdq_data->dev);
5358c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(hdq_data->dev);
5368c2ecf20Sopenharmony_ci}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_cistatic struct w1_bus_master omap_w1_master = {
5398c2ecf20Sopenharmony_ci	.read_byte	= omap_w1_read_byte,
5408c2ecf20Sopenharmony_ci	.write_byte	= omap_w1_write_byte,
5418c2ecf20Sopenharmony_ci	.reset_bus	= omap_w1_reset_bus,
5428c2ecf20Sopenharmony_ci};
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_cistatic int __maybe_unused omap_hdq_runtime_suspend(struct device *dev)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	struct hdq_data *hdq_data = dev_get_drvdata(dev);
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	hdq_reg_out(hdq_data, 0, hdq_data->mode);
5498c2ecf20Sopenharmony_ci	hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	return 0;
5528c2ecf20Sopenharmony_ci}
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_cistatic int __maybe_unused omap_hdq_runtime_resume(struct device *dev)
5558c2ecf20Sopenharmony_ci{
5568c2ecf20Sopenharmony_ci	struct hdq_data *hdq_data = dev_get_drvdata(dev);
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	/* select HDQ/1W mode & enable clocks */
5598c2ecf20Sopenharmony_ci	hdq_reg_out(hdq_data, OMAP_HDQ_CTRL_STATUS,
5608c2ecf20Sopenharmony_ci		    OMAP_HDQ_CTRL_STATUS_CLOCKENABLE |
5618c2ecf20Sopenharmony_ci		    OMAP_HDQ_CTRL_STATUS_INTERRUPTMASK |
5628c2ecf20Sopenharmony_ci		    hdq_data->mode);
5638c2ecf20Sopenharmony_ci	hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	return 0;
5668c2ecf20Sopenharmony_ci}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_cistatic const struct dev_pm_ops omap_hdq_pm_ops = {
5698c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(omap_hdq_runtime_suspend,
5708c2ecf20Sopenharmony_ci			   omap_hdq_runtime_resume, NULL)
5718c2ecf20Sopenharmony_ci};
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_cistatic int omap_hdq_probe(struct platform_device *pdev)
5748c2ecf20Sopenharmony_ci{
5758c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
5768c2ecf20Sopenharmony_ci	struct hdq_data *hdq_data;
5778c2ecf20Sopenharmony_ci	int ret, irq;
5788c2ecf20Sopenharmony_ci	u8 rev;
5798c2ecf20Sopenharmony_ci	const char *mode;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	hdq_data = devm_kzalloc(dev, sizeof(*hdq_data), GFP_KERNEL);
5828c2ecf20Sopenharmony_ci	if (!hdq_data) {
5838c2ecf20Sopenharmony_ci		dev_dbg(&pdev->dev, "unable to allocate memory\n");
5848c2ecf20Sopenharmony_ci		return -ENOMEM;
5858c2ecf20Sopenharmony_ci	}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	hdq_data->dev = dev;
5888c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, hdq_data);
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	hdq_data->hdq_base = devm_platform_ioremap_resource(pdev, 0);
5918c2ecf20Sopenharmony_ci	if (IS_ERR(hdq_data->hdq_base))
5928c2ecf20Sopenharmony_ci		return PTR_ERR(hdq_data->hdq_base);
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	mutex_init(&hdq_data->hdq_mutex);
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	ret = of_property_read_string(pdev->dev.of_node, "ti,mode", &mode);
5978c2ecf20Sopenharmony_ci	if (ret < 0 || !strcmp(mode, "hdq")) {
5988c2ecf20Sopenharmony_ci		hdq_data->mode = 0;
5998c2ecf20Sopenharmony_ci		omap_w1_master.search = omap_w1_search_bus;
6008c2ecf20Sopenharmony_ci	} else {
6018c2ecf20Sopenharmony_ci		hdq_data->mode = 1;
6028c2ecf20Sopenharmony_ci		omap_w1_master.triplet = omap_w1_triplet;
6038c2ecf20Sopenharmony_ci	}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
6068c2ecf20Sopenharmony_ci	pm_runtime_use_autosuspend(&pdev->dev);
6078c2ecf20Sopenharmony_ci	pm_runtime_set_autosuspend_delay(&pdev->dev, 300);
6088c2ecf20Sopenharmony_ci	ret = pm_runtime_get_sync(&pdev->dev);
6098c2ecf20Sopenharmony_ci	if (ret < 0) {
6108c2ecf20Sopenharmony_ci		pm_runtime_put_noidle(&pdev->dev);
6118c2ecf20Sopenharmony_ci		dev_dbg(&pdev->dev, "pm_runtime_get_sync failed\n");
6128c2ecf20Sopenharmony_ci		goto err_w1;
6138c2ecf20Sopenharmony_ci	}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	rev = hdq_reg_in(hdq_data, OMAP_HDQ_REVISION);
6168c2ecf20Sopenharmony_ci	dev_info(&pdev->dev, "OMAP HDQ Hardware Rev %c.%c. Driver in %s mode\n",
6178c2ecf20Sopenharmony_ci		(rev >> 4) + '0', (rev & 0x0f) + '0', "Interrupt");
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	spin_lock_init(&hdq_data->hdq_spinlock);
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
6228c2ecf20Sopenharmony_ci	if (irq	< 0) {
6238c2ecf20Sopenharmony_ci		dev_dbg(&pdev->dev, "Failed to get IRQ: %d\n", irq);
6248c2ecf20Sopenharmony_ci		ret = irq;
6258c2ecf20Sopenharmony_ci		goto err_irq;
6268c2ecf20Sopenharmony_ci	}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	ret = devm_request_irq(dev, irq, hdq_isr, 0, "omap_hdq", hdq_data);
6298c2ecf20Sopenharmony_ci	if (ret < 0) {
6308c2ecf20Sopenharmony_ci		dev_dbg(&pdev->dev, "could not request irq\n");
6318c2ecf20Sopenharmony_ci		goto err_irq;
6328c2ecf20Sopenharmony_ci	}
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	omap_hdq_break(hdq_data);
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	pm_runtime_mark_last_busy(&pdev->dev);
6378c2ecf20Sopenharmony_ci	pm_runtime_put_autosuspend(&pdev->dev);
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	omap_w1_master.data = hdq_data;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	ret = w1_add_master_device(&omap_w1_master);
6428c2ecf20Sopenharmony_ci	if (ret) {
6438c2ecf20Sopenharmony_ci		dev_dbg(&pdev->dev, "Failure in registering w1 master\n");
6448c2ecf20Sopenharmony_ci		goto err_w1;
6458c2ecf20Sopenharmony_ci	}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	return 0;
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_cierr_irq:
6508c2ecf20Sopenharmony_ci	pm_runtime_put_sync(&pdev->dev);
6518c2ecf20Sopenharmony_cierr_w1:
6528c2ecf20Sopenharmony_ci	pm_runtime_dont_use_autosuspend(&pdev->dev);
6538c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ci	return ret;
6568c2ecf20Sopenharmony_ci}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_cistatic int omap_hdq_remove(struct platform_device *pdev)
6598c2ecf20Sopenharmony_ci{
6608c2ecf20Sopenharmony_ci	int active;
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	active = pm_runtime_get_sync(&pdev->dev);
6638c2ecf20Sopenharmony_ci	if (active < 0)
6648c2ecf20Sopenharmony_ci		pm_runtime_put_noidle(&pdev->dev);
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	w1_remove_master_device(&omap_w1_master);
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	pm_runtime_dont_use_autosuspend(&pdev->dev);
6698c2ecf20Sopenharmony_ci	if (active >= 0)
6708c2ecf20Sopenharmony_ci		pm_runtime_put_sync(&pdev->dev);
6718c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	return 0;
6748c2ecf20Sopenharmony_ci}
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_cistatic const struct of_device_id omap_hdq_dt_ids[] = {
6778c2ecf20Sopenharmony_ci	{ .compatible = "ti,omap3-1w" },
6788c2ecf20Sopenharmony_ci	{ .compatible = "ti,am4372-hdq" },
6798c2ecf20Sopenharmony_ci	{}
6808c2ecf20Sopenharmony_ci};
6818c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, omap_hdq_dt_ids);
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_cistatic struct platform_driver omap_hdq_driver = {
6848c2ecf20Sopenharmony_ci	.probe = omap_hdq_probe,
6858c2ecf20Sopenharmony_ci	.remove = omap_hdq_remove,
6868c2ecf20Sopenharmony_ci	.driver = {
6878c2ecf20Sopenharmony_ci		.name =	"omap_hdq",
6888c2ecf20Sopenharmony_ci		.of_match_table = omap_hdq_dt_ids,
6898c2ecf20Sopenharmony_ci		.pm = &omap_hdq_pm_ops,
6908c2ecf20Sopenharmony_ci	},
6918c2ecf20Sopenharmony_ci};
6928c2ecf20Sopenharmony_cimodule_platform_driver(omap_hdq_driver);
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ciMODULE_AUTHOR("Texas Instruments");
6958c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("HDQ-1W driver Library");
6968c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
697