18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Aic94xx SAS/SATA driver register access.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
68c2ecf20Sopenharmony_ci * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/pci.h>
108c2ecf20Sopenharmony_ci#include "aic94xx_reg.h"
118c2ecf20Sopenharmony_ci#include "aic94xx.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci/* Writing to device address space.
148c2ecf20Sopenharmony_ci * Offset comes before value to remind that the operation of
158c2ecf20Sopenharmony_ci * this function is *offs = val.
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_cistatic void asd_write_byte(struct asd_ha_struct *asd_ha,
188c2ecf20Sopenharmony_ci			   unsigned long offs, u8 val)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	if (unlikely(asd_ha->iospace))
218c2ecf20Sopenharmony_ci		outb(val,
228c2ecf20Sopenharmony_ci		     (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
238c2ecf20Sopenharmony_ci	else
248c2ecf20Sopenharmony_ci		writeb(val, asd_ha->io_handle[0].addr + offs);
258c2ecf20Sopenharmony_ci	wmb();
268c2ecf20Sopenharmony_ci}
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic void asd_write_word(struct asd_ha_struct *asd_ha,
298c2ecf20Sopenharmony_ci			   unsigned long offs, u16 val)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	if (unlikely(asd_ha->iospace))
328c2ecf20Sopenharmony_ci		outw(val,
338c2ecf20Sopenharmony_ci		     (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
348c2ecf20Sopenharmony_ci	else
358c2ecf20Sopenharmony_ci		writew(val, asd_ha->io_handle[0].addr + offs);
368c2ecf20Sopenharmony_ci	wmb();
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic void asd_write_dword(struct asd_ha_struct *asd_ha,
408c2ecf20Sopenharmony_ci			    unsigned long offs, u32 val)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	if (unlikely(asd_ha->iospace))
438c2ecf20Sopenharmony_ci		outl(val,
448c2ecf20Sopenharmony_ci		     (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
458c2ecf20Sopenharmony_ci	else
468c2ecf20Sopenharmony_ci		writel(val, asd_ha->io_handle[0].addr + offs);
478c2ecf20Sopenharmony_ci	wmb();
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/* Reading from device address space.
518c2ecf20Sopenharmony_ci */
528c2ecf20Sopenharmony_cistatic u8 asd_read_byte(struct asd_ha_struct *asd_ha, unsigned long offs)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	u8 val;
558c2ecf20Sopenharmony_ci	if (unlikely(asd_ha->iospace))
568c2ecf20Sopenharmony_ci		val = inb((unsigned long) asd_ha->io_handle[0].addr
578c2ecf20Sopenharmony_ci			  + (offs & 0xFF));
588c2ecf20Sopenharmony_ci	else
598c2ecf20Sopenharmony_ci		val = readb(asd_ha->io_handle[0].addr + offs);
608c2ecf20Sopenharmony_ci	rmb();
618c2ecf20Sopenharmony_ci	return val;
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic u16 asd_read_word(struct asd_ha_struct *asd_ha,
658c2ecf20Sopenharmony_ci			 unsigned long offs)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	u16 val;
688c2ecf20Sopenharmony_ci	if (unlikely(asd_ha->iospace))
698c2ecf20Sopenharmony_ci		val = inw((unsigned long)asd_ha->io_handle[0].addr
708c2ecf20Sopenharmony_ci			  + (offs & 0xFF));
718c2ecf20Sopenharmony_ci	else
728c2ecf20Sopenharmony_ci		val = readw(asd_ha->io_handle[0].addr + offs);
738c2ecf20Sopenharmony_ci	rmb();
748c2ecf20Sopenharmony_ci	return val;
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_cistatic u32 asd_read_dword(struct asd_ha_struct *asd_ha,
788c2ecf20Sopenharmony_ci			  unsigned long offs)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	u32 val;
818c2ecf20Sopenharmony_ci	if (unlikely(asd_ha->iospace))
828c2ecf20Sopenharmony_ci		val = inl((unsigned long) asd_ha->io_handle[0].addr
838c2ecf20Sopenharmony_ci			  + (offs & 0xFF));
848c2ecf20Sopenharmony_ci	else
858c2ecf20Sopenharmony_ci		val = readl(asd_ha->io_handle[0].addr + offs);
868c2ecf20Sopenharmony_ci	rmb();
878c2ecf20Sopenharmony_ci	return val;
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic inline u32 asd_mem_offs_swa(void)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	return 0;
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic inline u32 asd_mem_offs_swc(void)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	return asd_mem_offs_swa() + MBAR0_SWA_SIZE;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic inline u32 asd_mem_offs_swb(void)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	return asd_mem_offs_swc() + MBAR0_SWC_SIZE + 0x20;
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci/* We know that the register wanted is in the range
1068c2ecf20Sopenharmony_ci * of the sliding window.
1078c2ecf20Sopenharmony_ci */
1088c2ecf20Sopenharmony_ci#define ASD_READ_SW(ww, type, ord)					\
1098c2ecf20Sopenharmony_cistatic type asd_read_##ww##_##ord(struct asd_ha_struct *asd_ha,		\
1108c2ecf20Sopenharmony_ci				   u32 reg)				\
1118c2ecf20Sopenharmony_ci{									\
1128c2ecf20Sopenharmony_ci	struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0];	\
1138c2ecf20Sopenharmony_ci	u32 map_offs = (reg - io_handle->ww##_base) + asd_mem_offs_##ww();\
1148c2ecf20Sopenharmony_ci	return asd_read_##ord(asd_ha, (unsigned long)map_offs);	\
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci#define ASD_WRITE_SW(ww, type, ord)					\
1188c2ecf20Sopenharmony_cistatic void asd_write_##ww##_##ord(struct asd_ha_struct *asd_ha,	\
1198c2ecf20Sopenharmony_ci				    u32 reg, type val)			\
1208c2ecf20Sopenharmony_ci{									\
1218c2ecf20Sopenharmony_ci	struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0];	\
1228c2ecf20Sopenharmony_ci	u32 map_offs = (reg - io_handle->ww##_base) + asd_mem_offs_##ww();\
1238c2ecf20Sopenharmony_ci	asd_write_##ord(asd_ha, (unsigned long)map_offs, val);		\
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ciASD_READ_SW(swa, u8,  byte);
1278c2ecf20Sopenharmony_ciASD_READ_SW(swa, u16, word);
1288c2ecf20Sopenharmony_ciASD_READ_SW(swa, u32, dword);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ciASD_READ_SW(swb, u8,  byte);
1318c2ecf20Sopenharmony_ciASD_READ_SW(swb, u16, word);
1328c2ecf20Sopenharmony_ciASD_READ_SW(swb, u32, dword);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ciASD_READ_SW(swc, u8,  byte);
1358c2ecf20Sopenharmony_ciASD_READ_SW(swc, u16, word);
1368c2ecf20Sopenharmony_ciASD_READ_SW(swc, u32, dword);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ciASD_WRITE_SW(swa, u8,  byte);
1398c2ecf20Sopenharmony_ciASD_WRITE_SW(swa, u16, word);
1408c2ecf20Sopenharmony_ciASD_WRITE_SW(swa, u32, dword);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ciASD_WRITE_SW(swb, u8,  byte);
1438c2ecf20Sopenharmony_ciASD_WRITE_SW(swb, u16, word);
1448c2ecf20Sopenharmony_ciASD_WRITE_SW(swb, u32, dword);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ciASD_WRITE_SW(swc, u8,  byte);
1478c2ecf20Sopenharmony_ciASD_WRITE_SW(swc, u16, word);
1488c2ecf20Sopenharmony_ciASD_WRITE_SW(swc, u32, dword);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci/*
1518c2ecf20Sopenharmony_ci * A word about sliding windows:
1528c2ecf20Sopenharmony_ci * MBAR0 is divided into sliding windows A, C and B, in that order.
1538c2ecf20Sopenharmony_ci * SWA starts at offset 0 of MBAR0, up to 0x57, with size 0x58 bytes.
1548c2ecf20Sopenharmony_ci * SWC starts at offset 0x58 of MBAR0, up to 0x60, with size 0x8 bytes.
1558c2ecf20Sopenharmony_ci * From 0x60 to 0x7F, we have a copy of PCI config space 0x60-0x7F.
1568c2ecf20Sopenharmony_ci * SWB starts at offset 0x80 of MBAR0 and extends to the end of MBAR0.
1578c2ecf20Sopenharmony_ci * See asd_init_sw() in aic94xx_hwi.c
1588c2ecf20Sopenharmony_ci *
1598c2ecf20Sopenharmony_ci * We map the most common registers we'd access of the internal 4GB
1608c2ecf20Sopenharmony_ci * host adapter memory space.  If a register/internal memory location
1618c2ecf20Sopenharmony_ci * is wanted which is not mapped, we slide SWB, by paging it,
1628c2ecf20Sopenharmony_ci * see asd_move_swb() in aic94xx_reg.c.
1638c2ecf20Sopenharmony_ci */
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci/**
1668c2ecf20Sopenharmony_ci * asd_move_swb -- move sliding window B
1678c2ecf20Sopenharmony_ci * @asd_ha: pointer to host adapter structure
1688c2ecf20Sopenharmony_ci * @reg: register desired to be within range of the new window
1698c2ecf20Sopenharmony_ci */
1708c2ecf20Sopenharmony_cistatic void asd_move_swb(struct asd_ha_struct *asd_ha, u32 reg)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	u32 base = reg & ~(MBAR0_SWB_SIZE-1);
1738c2ecf20Sopenharmony_ci	pci_write_config_dword(asd_ha->pcidev, PCI_CONF_MBAR0_SWB, base);
1748c2ecf20Sopenharmony_ci	asd_ha->io_handle[0].swb_base = base;
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic void __asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
1808c2ecf20Sopenharmony_ci	BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
1818c2ecf20Sopenharmony_ci	if (io_handle->swa_base <= reg
1828c2ecf20Sopenharmony_ci	    && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
1838c2ecf20Sopenharmony_ci		asd_write_swa_byte (asd_ha, reg,val);
1848c2ecf20Sopenharmony_ci	else if (io_handle->swb_base <= reg
1858c2ecf20Sopenharmony_ci		 && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
1868c2ecf20Sopenharmony_ci		asd_write_swb_byte (asd_ha, reg, val);
1878c2ecf20Sopenharmony_ci	else if (io_handle->swc_base <= reg
1888c2ecf20Sopenharmony_ci		 && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
1898c2ecf20Sopenharmony_ci		asd_write_swc_byte (asd_ha, reg, val);
1908c2ecf20Sopenharmony_ci	else {
1918c2ecf20Sopenharmony_ci		/* Ok, we have to move SWB */
1928c2ecf20Sopenharmony_ci		asd_move_swb(asd_ha, reg);
1938c2ecf20Sopenharmony_ci		asd_write_swb_byte (asd_ha, reg, val);
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci#define ASD_WRITE_REG(type, ord)                                  \
1988c2ecf20Sopenharmony_civoid asd_write_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg, type val)\
1998c2ecf20Sopenharmony_ci{                                                                 \
2008c2ecf20Sopenharmony_ci	struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
2018c2ecf20Sopenharmony_ci	unsigned long flags;                                      \
2028c2ecf20Sopenharmony_ci	BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);         \
2038c2ecf20Sopenharmony_ci	spin_lock_irqsave(&asd_ha->iolock, flags);                \
2048c2ecf20Sopenharmony_ci	if (io_handle->swa_base <= reg                            \
2058c2ecf20Sopenharmony_ci	    && reg < io_handle->swa_base + MBAR0_SWA_SIZE)        \
2068c2ecf20Sopenharmony_ci		asd_write_swa_##ord (asd_ha, reg,val);            \
2078c2ecf20Sopenharmony_ci	else if (io_handle->swb_base <= reg                       \
2088c2ecf20Sopenharmony_ci		 && reg < io_handle->swb_base + MBAR0_SWB_SIZE)   \
2098c2ecf20Sopenharmony_ci		asd_write_swb_##ord (asd_ha, reg, val);           \
2108c2ecf20Sopenharmony_ci	else if (io_handle->swc_base <= reg                       \
2118c2ecf20Sopenharmony_ci		 && reg < io_handle->swc_base + MBAR0_SWC_SIZE)   \
2128c2ecf20Sopenharmony_ci		asd_write_swc_##ord (asd_ha, reg, val);           \
2138c2ecf20Sopenharmony_ci	else {                                                    \
2148c2ecf20Sopenharmony_ci		/* Ok, we have to move SWB */                     \
2158c2ecf20Sopenharmony_ci		asd_move_swb(asd_ha, reg);                        \
2168c2ecf20Sopenharmony_ci		asd_write_swb_##ord (asd_ha, reg, val);           \
2178c2ecf20Sopenharmony_ci	}                                                         \
2188c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&asd_ha->iolock, flags);           \
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ciASD_WRITE_REG(u8, byte);
2228c2ecf20Sopenharmony_ciASD_WRITE_REG(u16,word);
2238c2ecf20Sopenharmony_ciASD_WRITE_REG(u32,dword);
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cistatic u8 __asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg)
2268c2ecf20Sopenharmony_ci{
2278c2ecf20Sopenharmony_ci	struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
2288c2ecf20Sopenharmony_ci	u8 val;
2298c2ecf20Sopenharmony_ci	BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
2308c2ecf20Sopenharmony_ci	if (io_handle->swa_base <= reg
2318c2ecf20Sopenharmony_ci	    && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
2328c2ecf20Sopenharmony_ci		val = asd_read_swa_byte (asd_ha, reg);
2338c2ecf20Sopenharmony_ci	else if (io_handle->swb_base <= reg
2348c2ecf20Sopenharmony_ci		 && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
2358c2ecf20Sopenharmony_ci		val = asd_read_swb_byte (asd_ha, reg);
2368c2ecf20Sopenharmony_ci	else if (io_handle->swc_base <= reg
2378c2ecf20Sopenharmony_ci		 && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
2388c2ecf20Sopenharmony_ci		val = asd_read_swc_byte (asd_ha, reg);
2398c2ecf20Sopenharmony_ci	else {
2408c2ecf20Sopenharmony_ci		/* Ok, we have to move SWB */
2418c2ecf20Sopenharmony_ci		asd_move_swb(asd_ha, reg);
2428c2ecf20Sopenharmony_ci		val = asd_read_swb_byte (asd_ha, reg);
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci	return val;
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci#define ASD_READ_REG(type, ord)                                   \
2488c2ecf20Sopenharmony_citype asd_read_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg)   \
2498c2ecf20Sopenharmony_ci{                                                                 \
2508c2ecf20Sopenharmony_ci	struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
2518c2ecf20Sopenharmony_ci	type val;                                                 \
2528c2ecf20Sopenharmony_ci	unsigned long flags;                                      \
2538c2ecf20Sopenharmony_ci	BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);         \
2548c2ecf20Sopenharmony_ci	spin_lock_irqsave(&asd_ha->iolock, flags);                \
2558c2ecf20Sopenharmony_ci	if (io_handle->swa_base <= reg                            \
2568c2ecf20Sopenharmony_ci	    && reg < io_handle->swa_base + MBAR0_SWA_SIZE)        \
2578c2ecf20Sopenharmony_ci		val = asd_read_swa_##ord (asd_ha, reg);           \
2588c2ecf20Sopenharmony_ci	else if (io_handle->swb_base <= reg                       \
2598c2ecf20Sopenharmony_ci		 && reg < io_handle->swb_base + MBAR0_SWB_SIZE)   \
2608c2ecf20Sopenharmony_ci		val = asd_read_swb_##ord (asd_ha, reg);           \
2618c2ecf20Sopenharmony_ci	else if (io_handle->swc_base <= reg                       \
2628c2ecf20Sopenharmony_ci		 && reg < io_handle->swc_base + MBAR0_SWC_SIZE)   \
2638c2ecf20Sopenharmony_ci		val = asd_read_swc_##ord (asd_ha, reg);           \
2648c2ecf20Sopenharmony_ci	else {                                                    \
2658c2ecf20Sopenharmony_ci		/* Ok, we have to move SWB */                     \
2668c2ecf20Sopenharmony_ci		asd_move_swb(asd_ha, reg);                        \
2678c2ecf20Sopenharmony_ci		val = asd_read_swb_##ord (asd_ha, reg);           \
2688c2ecf20Sopenharmony_ci	}                                                         \
2698c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&asd_ha->iolock, flags);           \
2708c2ecf20Sopenharmony_ci	return val;                                               \
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ciASD_READ_REG(u8, byte);
2748c2ecf20Sopenharmony_ciASD_READ_REG(u16,word);
2758c2ecf20Sopenharmony_ciASD_READ_REG(u32,dword);
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci/**
2788c2ecf20Sopenharmony_ci * asd_read_reg_string -- read a string of bytes from io space memory
2798c2ecf20Sopenharmony_ci * @asd_ha: pointer to host adapter structure
2808c2ecf20Sopenharmony_ci * @dst: pointer to a destination buffer where data will be written to
2818c2ecf20Sopenharmony_ci * @offs: start offset (register) to read from
2828c2ecf20Sopenharmony_ci * @count: number of bytes to read
2838c2ecf20Sopenharmony_ci */
2848c2ecf20Sopenharmony_civoid asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst,
2858c2ecf20Sopenharmony_ci			 u32 offs, int count)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	u8 *p = dst;
2888c2ecf20Sopenharmony_ci	unsigned long flags;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	spin_lock_irqsave(&asd_ha->iolock, flags);
2918c2ecf20Sopenharmony_ci	for ( ; count > 0; count--, offs++, p++)
2928c2ecf20Sopenharmony_ci		*p = __asd_read_reg_byte(asd_ha, offs);
2938c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&asd_ha->iolock, flags);
2948c2ecf20Sopenharmony_ci}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci/**
2978c2ecf20Sopenharmony_ci * asd_write_reg_string -- write a string of bytes to io space memory
2988c2ecf20Sopenharmony_ci * @asd_ha: pointer to host adapter structure
2998c2ecf20Sopenharmony_ci * @src: pointer to source buffer where data will be read from
3008c2ecf20Sopenharmony_ci * @offs: start offset (register) to write to
3018c2ecf20Sopenharmony_ci * @count: number of bytes to write
3028c2ecf20Sopenharmony_ci */
3038c2ecf20Sopenharmony_civoid asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src,
3048c2ecf20Sopenharmony_ci			  u32 offs, int count)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	u8 *p = src;
3078c2ecf20Sopenharmony_ci	unsigned long flags;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	spin_lock_irqsave(&asd_ha->iolock, flags);
3108c2ecf20Sopenharmony_ci	for ( ; count > 0; count--, offs++, p++)
3118c2ecf20Sopenharmony_ci		__asd_write_reg_byte(asd_ha, offs, *p);
3128c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&asd_ha->iolock, flags);
3138c2ecf20Sopenharmony_ci}
314