1607f2c00SIvan Vecera // SPDX-License-Identifier: GPL-2.0-only 2607f2c00SIvan Vecera 3607f2c00SIvan Vecera #include <linux/bitfield.h> 4607f2c00SIvan Vecera #include <linux/cleanup.h> 5607f2c00SIvan Vecera #include <linux/dev_printk.h> 6607f2c00SIvan Vecera #include <linux/string.h> 7607f2c00SIvan Vecera #include <linux/string_choices.h> 8607f2c00SIvan Vecera #include <linux/types.h> 9607f2c00SIvan Vecera 10607f2c00SIvan Vecera #include "core.h" 11607f2c00SIvan Vecera #include "out.h" 12607f2c00SIvan Vecera 13607f2c00SIvan Vecera /** 14607f2c00SIvan Vecera * zl3073x_out_state_fetch - fetch output state from hardware 15607f2c00SIvan Vecera * @zldev: pointer to zl3073x_dev structure 16607f2c00SIvan Vecera * @index: output index to fetch state for 17607f2c00SIvan Vecera * 18607f2c00SIvan Vecera * Function fetches state of the given output from hardware and stores it 19607f2c00SIvan Vecera * for later use. 20607f2c00SIvan Vecera * 21607f2c00SIvan Vecera * Return: 0 on success, <0 on error 22607f2c00SIvan Vecera */ 23607f2c00SIvan Vecera int zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index) 24607f2c00SIvan Vecera { 25607f2c00SIvan Vecera struct zl3073x_out *out = &zldev->out[index]; 26607f2c00SIvan Vecera int rc; 27607f2c00SIvan Vecera 28607f2c00SIvan Vecera /* Read output configuration */ 29607f2c00SIvan Vecera rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_CTRL(index), &out->ctrl); 30607f2c00SIvan Vecera if (rc) 31607f2c00SIvan Vecera return rc; 32607f2c00SIvan Vecera 33607f2c00SIvan Vecera dev_dbg(zldev->dev, "OUT%u is %s and connected to SYNTH%u\n", index, 34607f2c00SIvan Vecera str_enabled_disabled(zl3073x_out_is_enabled(out)), 35607f2c00SIvan Vecera zl3073x_out_synth_get(out)); 36607f2c00SIvan Vecera 37607f2c00SIvan Vecera guard(mutex)(&zldev->multiop_lock); 38607f2c00SIvan Vecera 39607f2c00SIvan Vecera /* Read output configuration */ 40607f2c00SIvan Vecera rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, 41607f2c00SIvan Vecera ZL_REG_OUTPUT_MB_MASK, BIT(index)); 42607f2c00SIvan Vecera if (rc) 43607f2c00SIvan Vecera return rc; 44607f2c00SIvan Vecera 45607f2c00SIvan Vecera /* Read output mode */ 46607f2c00SIvan Vecera rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &out->mode); 47607f2c00SIvan Vecera if (rc) 48607f2c00SIvan Vecera return rc; 49607f2c00SIvan Vecera 50607f2c00SIvan Vecera dev_dbg(zldev->dev, "OUT%u has signal format 0x%02x\n", index, 51607f2c00SIvan Vecera zl3073x_out_signal_format_get(out)); 52607f2c00SIvan Vecera 53*5fb9b0d4SIvan Vecera /* Read output divisor */ 54*5fb9b0d4SIvan Vecera rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &out->div); 55*5fb9b0d4SIvan Vecera if (rc) 56*5fb9b0d4SIvan Vecera return rc; 57*5fb9b0d4SIvan Vecera 58*5fb9b0d4SIvan Vecera if (!out->div) { 59*5fb9b0d4SIvan Vecera dev_err(zldev->dev, "Zero divisor for OUT%u got from device\n", 60*5fb9b0d4SIvan Vecera index); 61*5fb9b0d4SIvan Vecera return -EINVAL; 62*5fb9b0d4SIvan Vecera } 63*5fb9b0d4SIvan Vecera 64*5fb9b0d4SIvan Vecera dev_dbg(zldev->dev, "OUT%u divisor: %u\n", index, out->div); 65*5fb9b0d4SIvan Vecera 66*5fb9b0d4SIvan Vecera /* Read output width */ 67*5fb9b0d4SIvan Vecera rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_WIDTH, &out->width); 68*5fb9b0d4SIvan Vecera if (rc) 69*5fb9b0d4SIvan Vecera return rc; 70*5fb9b0d4SIvan Vecera 71*5fb9b0d4SIvan Vecera rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, 72*5fb9b0d4SIvan Vecera &out->esync_n_period); 73*5fb9b0d4SIvan Vecera if (rc) 74*5fb9b0d4SIvan Vecera return rc; 75*5fb9b0d4SIvan Vecera 76*5fb9b0d4SIvan Vecera if (!out->esync_n_period) { 77*5fb9b0d4SIvan Vecera dev_err(zldev->dev, 78*5fb9b0d4SIvan Vecera "Zero esync divisor for OUT%u got from device\n", 79*5fb9b0d4SIvan Vecera index); 80*5fb9b0d4SIvan Vecera return -EINVAL; 81*5fb9b0d4SIvan Vecera } 82*5fb9b0d4SIvan Vecera 83*5fb9b0d4SIvan Vecera rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, 84*5fb9b0d4SIvan Vecera &out->esync_n_width); 85*5fb9b0d4SIvan Vecera if (rc) 86*5fb9b0d4SIvan Vecera return rc; 87*5fb9b0d4SIvan Vecera 88*5fb9b0d4SIvan Vecera rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP, 89*5fb9b0d4SIvan Vecera &out->phase_comp); 90*5fb9b0d4SIvan Vecera if (rc) 91*5fb9b0d4SIvan Vecera return rc; 92*5fb9b0d4SIvan Vecera 93607f2c00SIvan Vecera return rc; 94607f2c00SIvan Vecera } 95607f2c00SIvan Vecera 96607f2c00SIvan Vecera /** 97607f2c00SIvan Vecera * zl3073x_out_state_get - get current output state 98607f2c00SIvan Vecera * @zldev: pointer to zl3073x_dev structure 99607f2c00SIvan Vecera * @index: output index to get state for 100607f2c00SIvan Vecera * 101607f2c00SIvan Vecera * Return: pointer to given output state 102607f2c00SIvan Vecera */ 103607f2c00SIvan Vecera const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev, 104607f2c00SIvan Vecera u8 index) 105607f2c00SIvan Vecera { 106607f2c00SIvan Vecera return &zldev->out[index]; 107607f2c00SIvan Vecera } 108*5fb9b0d4SIvan Vecera 109*5fb9b0d4SIvan Vecera int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index, 110*5fb9b0d4SIvan Vecera const struct zl3073x_out *out) 111*5fb9b0d4SIvan Vecera { 112*5fb9b0d4SIvan Vecera struct zl3073x_out *dout = &zldev->out[index]; 113*5fb9b0d4SIvan Vecera int rc; 114*5fb9b0d4SIvan Vecera 115*5fb9b0d4SIvan Vecera guard(mutex)(&zldev->multiop_lock); 116*5fb9b0d4SIvan Vecera 117*5fb9b0d4SIvan Vecera /* Read output configuration into mailbox */ 118*5fb9b0d4SIvan Vecera rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, 119*5fb9b0d4SIvan Vecera ZL_REG_OUTPUT_MB_MASK, BIT(index)); 120*5fb9b0d4SIvan Vecera if (rc) 121*5fb9b0d4SIvan Vecera return rc; 122*5fb9b0d4SIvan Vecera 123*5fb9b0d4SIvan Vecera /* Update mailbox with changed values */ 124*5fb9b0d4SIvan Vecera if (dout->div != out->div) 125*5fb9b0d4SIvan Vecera rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_DIV, out->div); 126*5fb9b0d4SIvan Vecera if (!rc && dout->width != out->width) 127*5fb9b0d4SIvan Vecera rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_WIDTH, out->width); 128*5fb9b0d4SIvan Vecera if (!rc && dout->esync_n_period != out->esync_n_period) 129*5fb9b0d4SIvan Vecera rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, 130*5fb9b0d4SIvan Vecera out->esync_n_period); 131*5fb9b0d4SIvan Vecera if (!rc && dout->esync_n_width != out->esync_n_width) 132*5fb9b0d4SIvan Vecera rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, 133*5fb9b0d4SIvan Vecera out->esync_n_width); 134*5fb9b0d4SIvan Vecera if (!rc && dout->mode != out->mode) 135*5fb9b0d4SIvan Vecera rc = zl3073x_write_u8(zldev, ZL_REG_OUTPUT_MODE, out->mode); 136*5fb9b0d4SIvan Vecera if (!rc && dout->phase_comp != out->phase_comp) 137*5fb9b0d4SIvan Vecera rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP, 138*5fb9b0d4SIvan Vecera out->phase_comp); 139*5fb9b0d4SIvan Vecera if (rc) 140*5fb9b0d4SIvan Vecera return rc; 141*5fb9b0d4SIvan Vecera 142*5fb9b0d4SIvan Vecera /* Commit output configuration */ 143*5fb9b0d4SIvan Vecera rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR, 144*5fb9b0d4SIvan Vecera ZL_REG_OUTPUT_MB_MASK, BIT(index)); 145*5fb9b0d4SIvan Vecera if (rc) 146*5fb9b0d4SIvan Vecera return rc; 147*5fb9b0d4SIvan Vecera 148*5fb9b0d4SIvan Vecera /* After successful commit store new state */ 149*5fb9b0d4SIvan Vecera dout->div = out->div; 150*5fb9b0d4SIvan Vecera dout->width = out->width; 151*5fb9b0d4SIvan Vecera dout->esync_n_period = out->esync_n_period; 152*5fb9b0d4SIvan Vecera dout->esync_n_width = out->esync_n_width; 153*5fb9b0d4SIvan Vecera dout->mode = out->mode; 154*5fb9b0d4SIvan Vecera dout->phase_comp = out->phase_comp; 155*5fb9b0d4SIvan Vecera 156*5fb9b0d4SIvan Vecera return 0; 157*5fb9b0d4SIvan Vecera } 158