Skip to content

Commit 1129947

Browse files
committed
dpll: zl3073x: Add functions to access hardware registers
JIRA: https://issues.redhat.com/browse/RHEL-115367 commit 259ede9 Author: Ivan Vecera <ivecera@redhat.com> Date: Tue Sep 9 11:15:28 2025 +0200 dpll: zl3073x: Add functions to access hardware registers Besides the device host registers that are directly accessible, there are also hardware registers that can be accessed indirectly via specific host registers. Add register definitions for accessing hardware registers and provide helper functions for working with them. Additionally, extend the number of pages in the regmap configuration to 256, as the host registers used for accessing hardware registers are located on page 255. Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com> Signed-off-by: Ivan Vecera <ivecera@redhat.com> Link: https://patch.msgid.link/20250909091532.11790-2-ivecera@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Ivan Vecera <ivecera@redhat.com>
1 parent e3a7126 commit 1129947

File tree

3 files changed

+193
-4
lines changed

3 files changed

+193
-4
lines changed

drivers/dpll/zl3073x/core.c

Lines changed: 151 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,9 +95,9 @@ EXPORT_SYMBOL_NS_GPL(zl30735_chip_info, "ZL3073X");
9595

9696
#define ZL_RANGE_OFFSET 0x80
9797
#define ZL_PAGE_SIZE 0x80
98-
#define ZL_NUM_PAGES 15
98+
#define ZL_NUM_PAGES 256
9999
#define ZL_PAGE_SEL 0x7F
100-
#define ZL_PAGE_SEL_MASK GENMASK(3, 0)
100+
#define ZL_PAGE_SEL_MASK GENMASK(7, 0)
101101
#define ZL_NUM_REGS (ZL_NUM_PAGES * ZL_PAGE_SIZE)
102102

103103
/* Regmap range configuration */
@@ -174,9 +174,10 @@ static bool
174174
zl3073x_check_reg(struct zl3073x_dev *zldev, unsigned int reg, size_t size)
175175
{
176176
/* Check that multiop lock is held when accessing registers
177-
* from page 10 and above.
177+
* from page 10 and above except the page 255 that does not
178+
* need this protection.
178179
*/
179-
if (ZL_REG_PAGE(reg) >= 10)
180+
if (ZL_REG_PAGE(reg) >= 10 && ZL_REG_PAGE(reg) < 255)
180181
lockdep_assert_held(&zldev->multiop_lock);
181182

182183
/* Check the index is in valid range for indexed register */
@@ -446,6 +447,152 @@ int zl3073x_mb_op(struct zl3073x_dev *zldev, unsigned int op_reg, u8 op_val,
446447
return zl3073x_poll_zero_u8(zldev, op_reg, op_val);
447448
}
448449

450+
/**
451+
* zl3073x_do_hwreg_op - Perform HW register read/write operation
452+
* @zldev: zl3073x device pointer
453+
* @op: operation to perform
454+
*
455+
* Performs requested operation and waits for its completion.
456+
*
457+
* Return: 0 on success, <0 on error
458+
*/
459+
static int
460+
zl3073x_do_hwreg_op(struct zl3073x_dev *zldev, u8 op)
461+
{
462+
int rc;
463+
464+
/* Set requested operation and set pending bit */
465+
rc = zl3073x_write_u8(zldev, ZL_REG_HWREG_OP, op | ZL_HWREG_OP_PENDING);
466+
if (rc)
467+
return rc;
468+
469+
/* Poll for completion - pending bit cleared */
470+
return zl3073x_poll_zero_u8(zldev, ZL_REG_HWREG_OP,
471+
ZL_HWREG_OP_PENDING);
472+
}
473+
474+
/**
475+
* zl3073x_read_hwreg - Read HW register
476+
* @zldev: zl3073x device pointer
477+
* @addr: HW register address
478+
* @value: Value of the HW register
479+
*
480+
* Reads HW register value and stores it into @value.
481+
*
482+
* Return: 0 on success, <0 on error
483+
*/
484+
int zl3073x_read_hwreg(struct zl3073x_dev *zldev, u32 addr, u32 *value)
485+
{
486+
int rc;
487+
488+
/* Set address to read data from */
489+
rc = zl3073x_write_u32(zldev, ZL_REG_HWREG_ADDR, addr);
490+
if (rc)
491+
return rc;
492+
493+
/* Perform the read operation */
494+
rc = zl3073x_do_hwreg_op(zldev, ZL_HWREG_OP_READ);
495+
if (rc)
496+
return rc;
497+
498+
/* Read the received data */
499+
return zl3073x_read_u32(zldev, ZL_REG_HWREG_READ_DATA, value);
500+
}
501+
502+
/**
503+
* zl3073x_write_hwreg - Write value to HW register
504+
* @zldev: zl3073x device pointer
505+
* @addr: HW registers address
506+
* @value: Value to be written to HW register
507+
*
508+
* Stores the requested value into HW register.
509+
*
510+
* Return: 0 on success, <0 on error
511+
*/
512+
int zl3073x_write_hwreg(struct zl3073x_dev *zldev, u32 addr, u32 value)
513+
{
514+
int rc;
515+
516+
/* Set address to write data to */
517+
rc = zl3073x_write_u32(zldev, ZL_REG_HWREG_ADDR, addr);
518+
if (rc)
519+
return rc;
520+
521+
/* Set data to be written */
522+
rc = zl3073x_write_u32(zldev, ZL_REG_HWREG_WRITE_DATA, value);
523+
if (rc)
524+
return rc;
525+
526+
/* Perform the write operation */
527+
return zl3073x_do_hwreg_op(zldev, ZL_HWREG_OP_WRITE);
528+
}
529+
530+
/**
531+
* zl3073x_update_hwreg - Update certain bits in HW register
532+
* @zldev: zl3073x device pointer
533+
* @addr: HW register address
534+
* @value: Value to be written into HW register
535+
* @mask: Bitmask indicating bits to be updated
536+
*
537+
* Reads given HW register, updates requested bits specified by value and
538+
* mask and writes result back to HW register.
539+
*
540+
* Return: 0 on success, <0 on error
541+
*/
542+
int zl3073x_update_hwreg(struct zl3073x_dev *zldev, u32 addr, u32 value,
543+
u32 mask)
544+
{
545+
u32 tmp;
546+
int rc;
547+
548+
rc = zl3073x_read_hwreg(zldev, addr, &tmp);
549+
if (rc)
550+
return rc;
551+
552+
tmp &= ~mask;
553+
tmp |= value & mask;
554+
555+
return zl3073x_write_hwreg(zldev, addr, tmp);
556+
}
557+
558+
/**
559+
* zl3073x_write_hwreg_seq - Write HW registers sequence
560+
* @zldev: pointer to device structure
561+
* @seq: pointer to first sequence item
562+
* @num_items: number of items in sequence
563+
*
564+
* Writes given HW registers sequence.
565+
*
566+
* Return: 0 on success, <0 on error
567+
*/
568+
int zl3073x_write_hwreg_seq(struct zl3073x_dev *zldev,
569+
const struct zl3073x_hwreg_seq_item *seq,
570+
size_t num_items)
571+
{
572+
int i, rc = 0;
573+
574+
for (i = 0; i < num_items; i++) {
575+
dev_dbg(zldev->dev, "Write 0x%0x [0x%0x] to 0x%0x",
576+
seq[i].value, seq[i].mask, seq[i].addr);
577+
578+
if (seq[i].mask == U32_MAX)
579+
/* Write value directly */
580+
rc = zl3073x_write_hwreg(zldev, seq[i].addr,
581+
seq[i].value);
582+
else
583+
/* Update only bits specified by the mask */
584+
rc = zl3073x_update_hwreg(zldev, seq[i].addr,
585+
seq[i].value, seq[i].mask);
586+
if (rc)
587+
return rc;
588+
589+
if (seq->wait)
590+
msleep(seq->wait);
591+
}
592+
593+
return rc;
594+
}
595+
449596
/**
450597
* zl3073x_ref_state_fetch - get input reference state
451598
* @zldev: pointer to zl3073x_dev structure

drivers/dpll/zl3073x/core.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#ifndef _ZL3073X_CORE_H
44
#define _ZL3073X_CORE_H
55

6+
#include <linux/bitfield.h>
67
#include <linux/kthread.h>
78
#include <linux/list.h>
89
#include <linux/mutex.h>
@@ -115,6 +116,28 @@ int zl3073x_dev_probe(struct zl3073x_dev *zldev,
115116
* Registers operations
116117
**********************/
117118

119+
/**
120+
* struct zl3073x_hwreg_seq_item - HW register write sequence item
121+
* @addr: HW register to be written
122+
* @value: value to be written to HW register
123+
* @mask: bitmask indicating bits to be updated
124+
* @wait: number of ms to wait after register write
125+
*/
126+
struct zl3073x_hwreg_seq_item {
127+
u32 addr;
128+
u32 value;
129+
u32 mask;
130+
u32 wait;
131+
};
132+
133+
#define HWREG_SEQ_ITEM(_addr, _value, _mask, _wait) \
134+
{ \
135+
.addr = _addr, \
136+
.value = FIELD_PREP_CONST(_mask, _value), \
137+
.mask = _mask, \
138+
.wait = _wait, \
139+
}
140+
118141
int zl3073x_mb_op(struct zl3073x_dev *zldev, unsigned int op_reg, u8 op_val,
119142
unsigned int mask_reg, u16 mask_val);
120143
int zl3073x_poll_zero_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 mask);
@@ -126,6 +149,13 @@ int zl3073x_write_u8(struct zl3073x_dev *zldev, unsigned int reg, u8 val);
126149
int zl3073x_write_u16(struct zl3073x_dev *zldev, unsigned int reg, u16 val);
127150
int zl3073x_write_u32(struct zl3073x_dev *zldev, unsigned int reg, u32 val);
128151
int zl3073x_write_u48(struct zl3073x_dev *zldev, unsigned int reg, u64 val);
152+
int zl3073x_read_hwreg(struct zl3073x_dev *zldev, u32 addr, u32 *value);
153+
int zl3073x_write_hwreg(struct zl3073x_dev *zldev, u32 addr, u32 value);
154+
int zl3073x_update_hwreg(struct zl3073x_dev *zldev, u32 addr, u32 value,
155+
u32 mask);
156+
int zl3073x_write_hwreg_seq(struct zl3073x_dev *zldev,
157+
const struct zl3073x_hwreg_seq_item *seq,
158+
size_t num_items);
129159

130160
/*****************
131161
* Misc operations

drivers/dpll/zl3073x/regs.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,4 +260,16 @@
260260
#define ZL_REG_OUTPUT_ESYNC_WIDTH ZL_REG(14, 0x18, 4)
261261
#define ZL_REG_OUTPUT_PHASE_COMP ZL_REG(14, 0x20, 4)
262262

263+
/*
264+
* Register Page 255 - HW registers access
265+
*/
266+
#define ZL_REG_HWREG_OP ZL_REG(0xff, 0x00, 1)
267+
#define ZL_HWREG_OP_WRITE 0x28
268+
#define ZL_HWREG_OP_READ 0x29
269+
#define ZL_HWREG_OP_PENDING BIT(1)
270+
271+
#define ZL_REG_HWREG_ADDR ZL_REG(0xff, 0x04, 4)
272+
#define ZL_REG_HWREG_WRITE_DATA ZL_REG(0xff, 0x08, 4)
273+
#define ZL_REG_HWREG_READ_DATA ZL_REG(0xff, 0x0c, 4)
274+
263275
#endif /* _ZL3073X_REGS_H */

0 commit comments

Comments
 (0)