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 */ 23 int 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 */ 103 const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev, 104 u8 index) 105 { 106 return &zldev->out[index]; 107 } 108 109 int 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 } 158