// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fcntl.h>
#include <zircon/device/i2c.h>
#include <zircon/syscalls.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include "hifi-berry.h"
#include "pcm5122.h"

/*
    HiFiBerry DAC+ - i2s slave, i2c control mode, using BCLK as the reference

    To keep things simple/manageable, always assume a i2s interface with
     64bclk per audio frame

*/

#define HIFIBERRY_I2C_ADDRESS 0x4d
#define DEVNAME "/dev/soc/bcm-i2c/i2c1"

typedef struct {
    int i2c_fd;
    uint32_t state;
} hifiberry_t;

static hifiberry_t* hfb = NULL;

static zx_status_t hifiberry_LED_ctl(bool state) {

    if (!hfb)
        return ZX_ERR_BAD_STATE;
    if (hfb->i2c_fd < 0)
        return ZX_ERR_BAD_STATE;
    if (hfb->state == HIFIBERRY_STATE_SHUTDOWN)
        return ZX_ERR_BAD_STATE;
    // Not using any other GPIO pins, so don't worry about state of other
    //  pins.
    pcm5122_write_reg(hfb->i2c_fd, PCM5122_REG_GPIO_CONTROL,
                     (state) ? (PCM5122_GPIO_HIGH << PCM5122_GPIO4) :
                               (PCM5122_GPIO_LOW  << PCM5122_GPIO4));

    return ZX_OK;
}

zx_status_t hifiberry_release(void) {

    if (!hfb)
        return ZX_OK;
    hifiberry_LED_ctl(false);

    if (hfb->i2c_fd >= 0) {
        close(hfb->i2c_fd);
    }

    free(hfb);
    hfb = NULL;

    return ZX_OK;
}

zx_status_t hifiberry_start(void) {
    return hifiberry_LED_ctl(true);
}

zx_status_t hifiberry_stop(void) {
    return hifiberry_LED_ctl(false);
}

zx_status_t hifiberry_init(void) {

    // Check to see if already initialized
    if ((hfb) && (hfb->state != HIFIBERRY_STATE_SHUTDOWN))
        return ZX_ERR_BAD_STATE;

    if (hfb == NULL) {
        hfb = calloc(1, sizeof(hifiberry_t));
        if (!hfb)
            return ZX_ERR_NO_MEMORY;
    }

    hfb->i2c_fd = open(DEVNAME, O_RDWR);
    if (hfb->i2c_fd < 0) {
        printf("HIFIBERRY: Control channel not found\n");
        return ZX_ERR_NOT_FOUND;
    }

    i2c_ioctl_add_slave_args_t add_slave_args = {
        .chip_address_width = I2C_7BIT_ADDRESS,
        .chip_address = HIFIBERRY_I2C_ADDRESS,
    };

    ssize_t ret = ioctl_i2c_bus_add_slave(hfb->i2c_fd, &add_slave_args);
    if (ret < 0) {
        return ZX_ERR_INTERNAL;
    }
    // configure LED GPIO
    pcm5122_write_reg(hfb->i2c_fd, PCM5122_REG_GPIO_ENABLE,
                                   PCM5122_GPIO_OUTPUT << PCM5122_GPIO4);

    pcm5122_write_reg(hfb->i2c_fd, PCM5122_REG_GPIO4_OUTPUT_SELECTION,
                                   PCM5122_GPIO_SELECT_REG_OUT );
    hifiberry_LED_ctl(false);

    // Clock source for pll = 1 (bclk)
    pcm5122_write_reg(hfb->i2c_fd, PCM5122_REG_PLL_CLK_SOURCE,
                                   PCM5122_PLL_CLK_SOURCE_BCK);

    pcm5122_write_reg(hfb->i2c_fd, PCM5122_REG_ERROR_MASK, (1 << 4) | // Ignore sck detection
                                                           (1 << 3) | // Ignore sck halt detection
                                                           (1 << 2)); // Disable clock autoset

    // Most of the below are mode specific, should defer to some mode set routine...

    // DDSP divider 1 (=/2)
    pcm5122_write_reg(hfb->i2c_fd, PCM5122_REG_DSP_CLK_DIVIDER, 1);
    // DAC Divider = /16
    pcm5122_write_reg(hfb->i2c_fd, PCM5122_REG_DAC_CLK_DIVIDER, 15);
    // NCP Divider = /4
    pcm5122_write_reg(hfb->i2c_fd, PCM5122_REG_NCP_CLK_DIVIDER, 3);
    // OSR Divider = /8
    pcm5122_write_reg(hfb->i2c_fd, PCM5122_REG_OSR_CLK_DIVIDER, 7);
    // DAC CLK Mux = PLL
    pcm5122_write_reg(hfb->i2c_fd, PCM5122_REG_DAC_CLK_SOURCE, 0x10);
    // Enable the PLL
    pcm5122_write_reg(hfb->i2c_fd, PCM5122_REG_PLL_ENABLE, (1 << 0));

    pcm5122_write_reg(hfb->i2c_fd, PCM5122_REG_PLL_P, 0);   // P = 0
    pcm5122_write_reg(hfb->i2c_fd, PCM5122_REG_PLL_J, 16);  // J = 16
    pcm5122_write_reg(hfb->i2c_fd, PCM5122_REG_PLL_D_HI, 0);// D = 0
    pcm5122_write_reg(hfb->i2c_fd, PCM5122_REG_PLL_D_LO, 0);// (D uses two registers)
    pcm5122_write_reg(hfb->i2c_fd, PCM5122_REG_PLL_R, 1);   // R = 2

    hfb->state |= HIFIBERRY_STATE_INITIALIZED;

    return ZX_OK;
}

bool hifiberry_is_valid_mode(audio_stream_cmd_set_format_req_t req) {

    uint32_t mode = req.sample_format & (AUDIO_SAMPLE_FORMAT_16BIT);
    if (!mode)
        return false;

    if (req.channels != 2)
        return false;
    if ((req.frames_per_second != 48000) && (req.frames_per_second != 44100))
        return false;

    return true;
}
