File Index
Files and directories
Sign in
FILE

out.c

File preview with syntax highlighting.

linux-6.19.14/drivers/dpll/zl3073x/out.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2
  3#include <linux/bitfield.h>
  4#include <linux/cleanup.h>
  5#include <linux/dev_printk.h>
  6#include <linux/string.h>
  7#include <linux/string_choices.h>
  8#include <linux/types.h>
  9
 10#include "core.h"
 11#include "out.h"
 12
 13/**
 14 * zl3073x_out_state_fetch - fetch output state from hardware
 15 * @zldev: pointer to zl3073x_dev structure
 16 * @index: output index to fetch state for
 17 *
 18 * Function fetches state of the given output from hardware and stores it
 19 * for later use.
 20 *
 21 * Return: 0 on success, <0 on error
 22 */
 23int zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index)
 24{
 25	struct zl3073x_out *out = &zldev->out[index];
 26	int rc;
 27
 28	/* Read output configuration */
 29	rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_CTRL(index), &out->ctrl);
 30	if (rc)
 31		return rc;
 32
 33	dev_dbg(zldev->dev, "OUT%u is %s and connected to SYNTH%u\n", index,
 34		str_enabled_disabled(zl3073x_out_is_enabled(out)),
 35		zl3073x_out_synth_get(out));
 36
 37	guard(mutex)(&zldev->multiop_lock);
 38
 39	/* Read output configuration */
 40	rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
 41			   ZL_REG_OUTPUT_MB_MASK, BIT(index));
 42	if (rc)
 43		return rc;
 44
 45	/* Read output mode */
 46	rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &out->mode);
 47	if (rc)
 48		return rc;
 49
 50	dev_dbg(zldev->dev, "OUT%u has signal format 0x%02x\n", index,
 51		zl3073x_out_signal_format_get(out));
 52
 53	/* Read output divisor */
 54	rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &out->div);
 55	if (rc)
 56		return rc;
 57
 58	if (!out->div) {
 59		dev_err(zldev->dev, "Zero divisor for OUT%u got from device\n",
 60			index);
 61		return -EINVAL;
 62	}
 63
 64	dev_dbg(zldev->dev, "OUT%u divisor: %u\n", index, out->div);
 65
 66	/* Read output width */
 67	rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_WIDTH, &out->width);
 68	if (rc)
 69		return rc;
 70
 71	rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD,
 72			      &out->esync_n_period);
 73	if (rc)
 74		return rc;
 75
 76	if (!out->esync_n_period) {
 77		dev_err(zldev->dev,
 78			"Zero esync divisor for OUT%u got from device\n",
 79			index);
 80		return -EINVAL;
 81	}
 82
 83	rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH,
 84			      &out->esync_n_width);
 85	if (rc)
 86		return rc;
 87
 88	rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP,
 89			      &out->phase_comp);
 90	if (rc)
 91		return rc;
 92
 93	return rc;
 94}
 95
 96/**
 97 * zl3073x_out_state_get - get current output state
 98 * @zldev: pointer to zl3073x_dev structure
 99 * @index: output index to get state for
100 *
101 * Return: pointer to given output state
102 */
103const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev,
104						u8 index)
105{
106	return &zldev->out[index];
107}
108
109int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index,
110			  const struct zl3073x_out *out)
111{
112	struct zl3073x_out *dout = &zldev->out[index];
113	int rc;
114
115	guard(mutex)(&zldev->multiop_lock);
116
117	/* Read output configuration into mailbox */
118	rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD,
119			   ZL_REG_OUTPUT_MB_MASK, BIT(index));
120	if (rc)
121		return rc;
122
123	/* Update mailbox with changed values */
124	if (dout->div != out->div)
125		rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_DIV, out->div);
126	if (!rc && dout->width != out->width)
127		rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_WIDTH, out->width);
128	if (!rc && dout->esync_n_period != out->esync_n_period)
129		rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD,
130				       out->esync_n_period);
131	if (!rc && dout->esync_n_width != out->esync_n_width)
132		rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH,
133				       out->esync_n_width);
134	if (!rc && dout->mode != out->mode)
135		rc = zl3073x_write_u8(zldev, ZL_REG_OUTPUT_MODE, out->mode);
136	if (!rc && dout->phase_comp != out->phase_comp)
137		rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP,
138				       out->phase_comp);
139	if (rc)
140		return rc;
141
142	/* Commit output configuration */
143	rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR,
144			   ZL_REG_OUTPUT_MB_MASK, BIT(index));
145	if (rc)
146		return rc;
147
148	/* After successful commit store new state */
149	dout->div = out->div;
150	dout->width = out->width;
151	dout->esync_n_period = out->esync_n_period;
152	dout->esync_n_width = out->esync_n_width;
153	dout->mode = out->mode;
154	dout->phase_comp = out->phase_comp;
155
156	return 0;
157}
~/ Read-only file preview.