[][Add Proslic SI3218x audio codec driver]
[Description]
Add Proslic SI3218x audio codec driver
[Release-log]
N/A
Change-Id: I30edf714fda413b220b6a0f3e301a7bc3f899c08
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/5396999
diff --git a/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/proslic_sys_spi.c b/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/proslic_sys_spi.c
new file mode 100644
index 0000000..101c486
--- /dev/null
+++ b/target/linux/mediatek/files-5.4/sound/soc/codecs/si3218x/proslic_sys_spi.c
@@ -0,0 +1,698 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/spinlock.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include "proslic_sys.h"
+
+/*****************************************************************************************************/
+
+#define PROSLIC_REG_ID 0
+#define PROSLIC_REG_RAM_WAIT 4
+#define PROSLIC_REG_RAM_HI 5
+#define PROSLIC_REG_RAM_D0 6
+#define PROSLIC_REG_RAM_D1 7
+#define PROSLIC_REG_RAM_D2 8
+#define PROSLIC_REG_RAM_D3 9
+#define PROSLIC_REG_RAM_LO 10
+#define PROSLIC_REG_WRVSLIC 12
+#define PROSLIC_REG_WRVDAA 34
+#define PROSLIC_REG_ISDAA 11
+
+#define PROSLIC_CW_BYTE 0
+#define PROSLIC_REG_BYTE 1
+#define RAM_ADR_HIGH_MASK(ADDR) (((ADDR)>>3)&0xE0)
+
+/* Basic register definitions, regardless of chipset ('4x, '2x, '17x, '26x compatible */
+
+#define PROSLIC_CW_RD 0x60
+#define PROSLIC_CW_WR 0x20
+#define PROSLIC_CW_BCAST 0x80
+#define PROSLIC_BCAST 0xFF
+
+#ifndef PROSLIC_XFER_BUF
+#define PROSLIC_XFER_BUF (SILABS_BITS_PER_WORD/8)
+#endif
+
+/* Now do some sanity checks */
+#if (SILABS_BITS_PER_WORD != 32) && (SILABS_BITS_PER_WORD != 16) && (SILABS_BITS_PER_WORD != 8)
+#error "SILABS_BITS_PER_WORD needs to be either 8, 16 or 32"
+#endif
+
+#if (((SILABS_BITS_PER_WORD == 16) && (PROSLIC_XFER_BUF != 2) ) \
+ || ((SILABS_BITS_PER_WORD == 32) && (PROSLIC_XFER_BUF != 4) ) )
+#error "SILABS_BITS_PER_WORD & PROSLIC_XFER_BUF size mismatch"
+#endif
+
+#if (SILABS_BITS_PER_WORD != 8)
+#define SILABS_CW_BYTE 1
+#define SILABS_REG_BYTE 0
+#else
+#define SILABS_CW_BYTE 0
+#define SILABS_REG_BYTE 1
+#endif
+
+typedef struct
+{
+ proslic_dev_t deviceType[SILABS_MAX_CHANNELS];
+ spinlock_t bus_lock;
+ uInt8 channel_count; /* In most cases this is the channel count as well */
+} proslic_spi_data_t;
+
+typedef struct
+{
+ /* Placeholder for now */
+} proslic_spi_pform_t;
+
+/* Chan address is sent in reverse bit order */
+static uInt8 chanAddr[SILABS_MAX_CHAN] =
+{
+ 0x00, 0x10,
+#if (SILABS_MAX_CHAN > 2)
+ 0x08, 0x18,
+#endif
+#if (SILABS_MAX_CHAN > 4)
+ 0x04, 0x14,
+#endif
+#if (SILABS_MAX_CHAN > 6)
+ 0x0C, 0x1C,
+#endif
+#if (SILABS_MAX_CHAN > 8)
+ 0x02, 0x12,
+#endif
+#if (SILABS_MAX_CHAN > 10)
+ 0x0A, 0x1A,
+#endif
+#if (SILABS_MAX_CHAN > 12)
+ 0x06, 0x16,
+#endif
+#if (SILABS_MAX_CHAN > 14)
+ 0x0E, 0x1E,
+#endif
+#if (SILABS_MAX_CHAN > 16)
+ 0x01, 0x11,
+#endif
+#if (SILABS_MAX_CHAN > 18)
+ 0x09, 0x19,
+#endif
+#if (SILABS_MAX_CHAN > 20)
+ 0x05, 0x15,
+#endif
+#if (SILABS_MAX_CHAN > 22)
+ 0x0D, 0x1D,
+#endif
+#if (SILABS_MAX_CHAN > 24)
+ 0x03, 0x13,
+#endif
+#if (SILABS_MAX_CHAN > 26)
+ 0x0B, 0x1B,
+#endif
+#if (SILABS_MAX_CHAN > 28)
+ 0x07,0x17,
+#endif
+#if (SILABS_MAX_CHAN > 30)
+ 0x0F, 0x1F
+#endif
+};
+
+static proslic_spi_data_t *proslic_data;
+static unsigned int proslic_reset_gpio = SILABS_RESET_GPIO;
+struct spi_driver *proslic_spi;
+struct spi_device *proslic_spidev;
+
+/*****************************************************************************************************/
+uInt8 proslic_read_register_private(void *hCtrl, uInt8 channel, uInt8 regAddr)
+{
+ u_int8_t data_stream[4];
+// proslic_spi_data_t *spi_data = (proslic_spi_data_t *)hCtrl;
+ if (proslic_spidev == NULL)
+ printk ("%s : small spi NULL\n",__FUNCTION__);
+
+ if( unlikely(channel >= SILABS_MAX_CHANNELS) )
+ {
+ return PROSLIC_SPI_NOK;
+ }
+ else
+ {
+ data_stream[PROSLIC_CW_BYTE] = PROSLIC_CW_RD | chanAddr[channel];
+ }
+
+ data_stream[PROSLIC_REG_BYTE] = regAddr;
+
+ data_stream[2] = 0xFF; /* Set the register to a non-zero value, just in case */
+#if (PROSLIC_XFER_BUF == 4) || (PROSLIC_XFER_BUF == 2)
+ spi_write_then_read(proslic_spidev, data_stream, 2, &data_stream[2], 2); /* In essence, 2 16 bit ops: 1 to send the request, 1 to get the data, needs to be 32 bit aligned. */
+ proslic_debug("%s(%d): chan = %u reg = %u data = 0x%02X", __FUNCTION__, __LINE__, channel, regAddr, data_stream[2]);
+#else
+ {
+ int i;
+ for(i = 0; i < 2; i++)
+ {
+ spi_write(proslic_spidev, &data_stream[i], 1);
+ }
+ }
+ spi_read(proslic_spidev, &data_stream[2], 1);
+#endif
+
+ return data_stream[2];
+}
+
+/*****************************************************************************************************/
+
+uInt8 proslic_read_register(void *hCtrl, uInt8 channel, uInt8 regAddr)
+{
+ uInt8 data;
+ //unsigned long irqSettings;
+ //proslic_spi_data_t *spi_data = (proslic_spi_data_t *)hCtrl;
+ //spin_lock_irqsave(&spi_data->bus_lock, irqSettings);
+ data = proslic_read_register_private(hCtrl, channel, regAddr);
+ //spin_unlock_irqrestore(&spi_data->bus_lock, irqSettings);
+ proslic_debug("%s(%d): chan = %u reg = %u data = 0x%02X", __FUNCTION__, __LINE__, channel, regAddr, data);
+ return data;
+}
+EXPORT_SYMBOL(proslic_read_register);
+
+
+/*****************************************************************************************************/
+/* ProSLIC API register write function */
+#if PROSLIC_XFER_BUF == 4
+#define proslic_write_register_private proslic_write_register
+#endif
+
+int proslic_write_register_private(void *hCtrl, uInt8 channel, uInt8 regAddr, uInt8 data)
+{
+ u_int8_t data_stream[4];
+ //struct spi_device *spi_data = (struct spi_device *)hCtrl;
+
+#if PROSLIC_XFER_BUF != 4
+ int i;
+#endif
+
+ if( unlikely(channel == PROSLIC_BCAST) )
+ {
+ data_stream[PROSLIC_CW_BYTE] = PROSLIC_CW_BCAST | PROSLIC_CW_WR;
+ }
+ else if( unlikely(channel >= SILABS_MAX_CHANNELS) )
+ {
+ return PROSLIC_SPI_NOK;
+ }
+ else
+ {
+ data_stream[PROSLIC_CW_BYTE] = PROSLIC_CW_WR | chanAddr[channel];
+ }
+
+ proslic_trace("%s(%d): chan = %u reg = %u data = 0x%02X", __FUNCTION__, __LINE__, channel, regAddr, data);
+
+ data_stream[PROSLIC_REG_BYTE] = regAddr;
+
+ data_stream[2] = data_stream[3] = data;
+
+#if PROSLIC_XFER_BUF == 4
+ spi_write(proslic_spidev, data_stream, PROSLIC_XFER_BUF);
+#else
+#if PROSLIC_XFER_BUF == 2 /* 16 bit mode */
+ for(i = 0; i < 4; i+=2)
+#else /* Byte by byte */
+ for(i = 0; i < 3; i++)
+#endif
+ {
+ spi_write(proslic_spidev, &data_stream[i], PROSLIC_XFER_BUF);
+ }
+#endif
+
+ return PROSLIC_SPI_OK;
+}
+/*****************************************************************************************************/
+#if PROSLIC_XFER_BUF != 4
+int proslic_write_register(void *hCtrl, uInt8 channel, uInt8 regAddr, uInt8 data)
+{
+ unsigned long irqSettings;
+ int rc;
+ //proslic_spi_data_t *spi_data = (proslic_spi_data_t *)hCtrl;
+ //spin_lock_irqsave(&spi_data->bus_lock, irqSettings);
+ rc = proslic_write_register_private(hCtrl, channel, regAddr, data);
+ //spin_unlock_irqrestore(&spi_data->bus_lock, irqSettings);
+ return rc;
+}
+EXPORT_SYMBOL(proslic_write_register);
+#endif
+
+/*****************************************************************************************************/
+
+/*
+ * wait for RAM access
+ *
+ * return code 0 = OK
+ *
+ */
+
+static int wait_ram(void *hCtrl, uInt8 channel)
+{
+ unsigned int count = SILABS_MAX_RAM_WAIT;
+ uInt8 data;
+
+ do
+ {
+ data = proslic_read_register_private(hCtrl, channel, PROSLIC_REG_RAM_WAIT) & 0x1;
+ if(unlikely(data))
+ {
+ mdelay(5);
+ }
+ }while((data) && (count--));
+
+ if(likely(count))
+ {
+ return 0;
+ }
+ return -1; /* Timed out */
+}
+
+/*****************************************************************************************************/
+/* RAM Write wrapper */
+int proslic_write_ram(void *hCtrl, uInt8 channel, uInt16 ramAddr, ramData data )
+{
+
+ ramData myData = data;
+ int rc = 0;
+ //unsigned long irqSettings;
+ //struct spi_device *spi_data = (struct spi_device *)hCtrl;
+ hCtrl = proslic_spidev;
+
+ proslic_trace("%s(%d): chan = %u ram = %u data = 0x%08X", __FUNCTION__, __LINE__, channel, ramAddr, data);
+ //spin_lock_irqsave(&spi_data->bus_lock, irqSettings);
+
+ if(wait_ram(hCtrl,channel) != 0)
+ {
+ return PROSLIC_SPI_NOK;
+ }
+
+
+#ifdef SILABS_RAM_BLOCK_ACCESS
+ {
+ uInt8 ramWriteData[24]; /* This encapsulates the 6 reg writes into 1 block */
+ const uInt8 regAddr[6] = {PROSLIC_REG_RAM_HI, PROSLIC_REG_RAM_D0, PROSLIC_REG_RAM_D1,
+ PROSLIC_REG_RAM_D2, PROSLIC_REG_RAM_D3, PROSLIC_REG_RAM_LO};
+ int i;
+ uInt8 scratch;
+
+ /* Setup control word & registers for ALL the reg access */
+ scratch = chanAddr[channel] | PROSLIC_CW_WR;
+
+ for(i = 0; i < 6; i++)
+ {
+ ramWriteData[(i<<2)] = scratch ;
+ ramWriteData[(i<<2)+1] = regAddr[i];
+ }
+
+ /* For the data, we send the same byte twice to keep things 32 bit aligned */
+ ramWriteData[2] = ramWriteData[3] = RAM_ADR_HIGH_MASK(ramAddr);
+
+ ramWriteData[6] = ramWriteData[7] = (uInt8)(myData<<3);
+ myData = myData >> 5;
+
+ ramWriteData[10] = ramWriteData[11] = (uInt8)(myData & 0xFF);
+ myData = myData >> 8;
+
+ ramWriteData[14] = ramWriteData[15] = (uInt8)(myData & 0xFF);
+ myData = myData >> 8;
+
+ ramWriteData[18] = ramWriteData[19] = (uInt8)(myData & 0xFF);
+
+ ramWriteData[22] = ramWriteData[23] = (uInt8)(ramAddr& 0xFF);
+
+ spi_write(hCtrl, ramWriteData, 24);
+
+ }
+#else
+ proslic_write_register_private(hCtrl, channel, RAM_ADDR_HI, RAM_ADR_HIGH_MASK(ramAddr));
+
+ proslic_write_register_private(hCtrl, channel, RAM_DATA_B0, ((unsigned char)(myData<<3)));
+
+ myData = myData >> 5;
+
+ proslic_write_register_private(hCtrl, channel, RAM_DATA_B1, ((unsigned char)(myData & 0xFF)));
+
+ myData = myData >> 8;
+
+ proslic_write_register_private(hCtrl, channel, RAM_DATA_B2, ((unsigned char)(myData & 0xFF)));
+
+ myData = myData >> 8;
+
+ proslic_write_register_private(hCtrl, channel, RAM_DATA_B3, ((unsigned char)(myData & 0xFF)));
+
+ proslic_write_register_private(hCtrl, channel, RAM_ADDR_LO, (unsigned char)(ramAddr & 0xFF));
+#endif
+ if(wait_ram(hCtrl,channel) != 0)
+ {
+ rc = PROSLIC_SPI_NOK;
+ }
+ else
+ {
+ rc = PROSLIC_SPI_OK;
+ }
+ //spin_unlock_irqrestore(&spi_data->bus_lock, irqSettings);
+
+ return rc;
+
+}
+EXPORT_SYMBOL(proslic_write_ram);
+
+/*****************************************************************************************************/
+ramData proslic_read_ram(void *hCtrl, uInt8 channel, uInt16 ramAddr)
+{
+ ramData data;
+ //unsigned long irqSettings;
+ //proslic_spi_data_t *spi_data = (proslic_spi_data_t *)hCtrl;
+ hCtrl = proslic_spidev;
+
+ if(wait_ram(hCtrl,channel) != 0)
+ {
+ return PROSLIC_SPI_NOK;
+ }
+
+ //spin_lock_irqsave(&spi_data->bus_lock, irqSettings);
+ /* TODO: could combine these 2 writes into 1 spi_write call... */
+ proslic_write_register_private(hCtrl, channel, PROSLIC_REG_RAM_HI, RAM_ADR_HIGH_MASK(ramAddr));
+
+ proslic_write_register_private(hCtrl, channel, PROSLIC_REG_RAM_LO, (unsigned char)(ramAddr&0xFF));
+
+ if(wait_ram(hCtrl,channel) != 0)
+ {
+ return PROSLIC_SPI_NOK;
+ }
+
+ data = proslic_read_register_private(hCtrl, channel, PROSLIC_REG_RAM_D3);
+ data = data << 8;
+ data |= proslic_read_register_private(hCtrl, channel, PROSLIC_REG_RAM_D2);
+ data = data << 8;
+ data |= proslic_read_register_private(hCtrl, channel, PROSLIC_REG_RAM_D1);
+ data = data << 8;
+ data |= proslic_read_register_private(hCtrl, channel, PROSLIC_REG_RAM_D0);
+ //spin_unlock_irqrestore(&spi_data->bus_lock, irqSettings);
+
+ data = data >>3;
+
+ proslic_trace("%s(%d): chan = %u ram = %u data = 0x%08X", __FUNCTION__, __LINE__, channel, ramAddr, data);
+
+ return data;
+
+}
+EXPORT_SYMBOL(proslic_read_ram);
+
+/*****************************************************************************************************/
+int proslic_reset(void *hCtrl, int in_reset)
+{
+ proslic_trace("%s(%d): in_reset = %d", __FUNCTION__, __LINE__, in_reset);
+ gpio_direction_output(proslic_reset_gpio, (in_reset == 0) );
+
+ return PROSLIC_SPI_OK;
+}
+EXPORT_SYMBOL(proslic_reset);
+
+/*****************************************************************************************************/
+
+/*
+ * Do a simple write/verify test on a given register. 0 = OK.
+ */
+static int simple_wrv(void *hCtrl, uInt8 channel, uInt8 regAddr)
+{
+ uInt8 data;
+
+ proslic_write_register(hCtrl, channel, regAddr, 0);
+ data = proslic_read_register(hCtrl, channel, regAddr);
+ if(unlikely(data != 0) )
+ {
+ return -1;
+ }
+
+ proslic_write_register(hCtrl, channel, regAddr, 0x5A);
+ data = proslic_read_register(hCtrl, channel, regAddr);
+ if(unlikely(data != 0x5A) )
+ {
+ return -2;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************************************/
+
+/*
+ * Determine if this a ProSLIC or DAA or unknown type - NOT fully tested against ALL chipsets, may not
+ * properly work with Si3218/9 parts.
+ */
+static proslic_dev_t proslic_detect_type(void *hCtrl, uInt8 channel)
+{
+ /* Guess it's a ProSLIC first */
+ uInt8 data;
+
+ data = proslic_read_register(hCtrl, channel, PROSLIC_REG_ISDAA);
+ proslic_debug("%s(%d): channel = %d data = 0x%0X", __FUNCTION__, __LINE__, channel, data);
+
+ /* For ProSLIC ISDAA = 5, for DAA it is not (it is non-zero and not FF */
+
+ if( unlikely((data != 0xFF) && data ))
+ {
+ /* Likely a ProSLIC, let's confirm it by doing a few register write/verify operations */
+ if( data == 5)
+ {
+ if(unlikely(simple_wrv(hCtrl, channel, PROSLIC_REG_WRVSLIC) == 0))
+ {
+ proslic_debug("%s(%d): channel = %d is_proslic", __FUNCTION__, __LINE__, channel);
+ return PROSLIC_IS_PROSLIC;
+ }
+ }
+ else /* Likely a DAA/Si3050 device */
+ {
+ if(unlikely(simple_wrv(hCtrl, channel, PROSLIC_REG_WRVDAA) == 0))
+ {
+ proslic_debug("%s(%d): channel = %d is_daa", __FUNCTION__, __LINE__, channel);
+ return PROSLIC_IS_DAA;
+ }
+ }
+ }
+
+ proslic_debug("%s(%d): channel = %d is_unknown", __FUNCTION__, __LINE__, channel);
+ return PROSLIC_IS_UNKNOWN;
+}
+
+/*****************************************************************************************************/
+/* Pull in any device tree parameters */
+#ifdef CONFIG_OF
+static void proslic_of_probe(struct spi_device *spi)
+{
+ int len;
+ const __be32 *property;
+ u8 scratch;
+
+ printk(KERN_INFO "proslic_of_probe()\n");
+
+ /* see if the user specified number of channels */
+ property = of_get_property( spi->dev.of_node, "channel_count", &len);
+
+ if(property && (len >= sizeof(__be32)) )
+ {
+ scratch = be32_to_cpup(property);
+
+ if(( scratch <= SILABS_MAX_CHANNELS )
+ && (scratch > 0) )
+ {
+ proslic_channel_count = scratch;
+ }
+ }
+
+ /* See if the user specified a debug setting */
+ property = of_get_property( spi->dev.of_node, "debug_level", &len);
+
+ if(property && (len >= sizeof(__be32)) )
+ {
+ scratch = be32_to_cpup(property);
+
+ if(( scratch <= SILABS_DEFAULT_DBG )
+ && (scratch > 0) )
+ {
+ proslic_debug_setting = scratch;
+ printk(KERN_INFO "debug_level = %d\n", proslic_debug_setting);
+ }
+ }
+
+ printk(KERN_INFO "[previous]reset_gpio = %d\n", proslic_reset_gpio);
+ proslic_reset_gpio =
+ of_get_named_gpio(spi->dev.of_node, "reset_gpio", 0);
+
+ printk(KERN_INFO "reset_gpio = %d\n", proslic_reset_gpio);
+}
+#endif
+
+/*****************************************************************************************************/
+int proslic_spi_probe(struct spi_device *spi, struct spi_driver *spi_drv)
+{
+ proslic_spi_pform_t *pform_data;
+ unsigned int channel;
+ int rc;
+
+ printk(KERN_INFO "PROSLIC module being probed\n");
+
+ proslic_spi = spi_drv;
+ pform_data = (proslic_spi_pform_t *) &(spi->dev.platform_data);
+
+#ifdef CONFIG_OF
+ proslic_of_probe(spi);
+#endif
+
+ rc = gpio_request(proslic_reset_gpio,"proslic_reset");
+ if(rc == 0)
+ {
+ printk(KERN_INFO "PROSLIC GPIO registered OK");
+ gpio_export( proslic_reset_gpio, 0);
+ proslic_reset(NULL, 0);
+ }
+ else
+ {
+ printk(KERN_INFO "PROSLIC GPIO registered FAil!! rc = %d", rc);
+ return -ENODEV;
+ }
+
+ if(unlikely(!pform_data))
+ {
+ return -ENODEV;
+ }
+
+ proslic_data = kzalloc(sizeof(*proslic_data), GFP_KERNEL);
+
+ if(unlikely(!proslic_data))
+ {
+ return -ENOMEM;
+ }
+
+ spin_lock_init(&(proslic_data->bus_lock));
+ proslic_spidev = spi;
+#ifdef CONFIG_OF
+ spi->bits_per_word = SILABS_BITS_PER_WORD;
+ spi->max_speed_hz = SILABS_SPI_RATE;
+ spi->mode = SPI_MODE_3;
+ if( spi_setup(spi) != 0)
+ {
+ printk(KERN_ERR PROSLIC_API_HDR "failed to configure spi mode");
+ kfree(proslic_data);
+ return -EIO;
+ }
+#endif
+ spi_set_drvdata(spi, proslic_data);
+
+ /* Probe to determine the number of DAA's or ProSLIC's present */
+ for(channel = 0; channel < proslic_channel_count; channel++)
+ {
+ proslic_data->deviceType[channel] = proslic_detect_type(proslic_spidev, channel);
+ if( proslic_data->deviceType[channel] != PROSLIC_IS_UNKNOWN)
+ {
+ proslic_data->channel_count++;
+ }
+ }
+
+ if(proslic_data->channel_count)
+ {
+ return 0;
+ }
+ else
+ {
+ return -ENXIO;
+ }
+}
+EXPORT_SYMBOL(proslic_spi_probe);
+
+/*****************************************************************************************************/
+int proslic_spi_remove(struct spi_device *spi)
+{
+ void *ptr;
+
+ printk(KERN_INFO "ProSLIC module being removed");
+ /* Just put the device(s) into reset - assumes 1 reset per SPI device */
+ proslic_reset(NULL, 1);
+
+ ptr = spi_get_drvdata(spi);
+ if(ptr != NULL)
+ {
+ kfree(ptr);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(proslic_spi_remove);
+
+/*****************************************************************************************************/
+int proslic_spi_setup()
+{
+ int rc;
+ printk(KERN_INFO "proslic_spi_setup()\n");
+
+ rc = spi_register_driver(proslic_spi);
+
+ if(rc != 0)
+ {
+ proslic_error("%s(%d): spi_register driver returned = %d", __FUNCTION__, __LINE__, rc);
+ }
+ else
+ {
+ proslic_debug("%s(%d): spi driver registered", __FUNCTION__, __LINE__);
+ }
+
+ proslic_trace("%s(%d): completed", __FUNCTION__, __LINE__);
+ return rc;
+}
+
+
+void proslic_spi_shutdown()
+{
+ spi_unregister_driver(proslic_spi);
+ gpio_unexport( proslic_reset_gpio );
+ gpio_free( proslic_reset_gpio );
+}
+/*****************************************************************************************************/
+int proslic_get_channel_count()
+{
+ return proslic_data->channel_count;
+}
+
+proslic_dev_t proslic_get_device_type(uint8_t channel_number)
+{
+ if(channel_number < proslic_data->channel_count)
+ {
+ return proslic_data->deviceType[channel_number];
+ }
+ else
+ {
+ return PROSLIC_IS_UNKNOWN;
+ }
+}
+
+void *proslic_get_hCtrl(uint8_t channel)
+{
+ if(channel < proslic_data->channel_count)
+ {
+ return proslic_data;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+/*****************************************************************************************************/
+proslic_spi_fptrs_t proslic_spi_if =
+{
+ proslic_reset,
+
+ proslic_write_register,
+ proslic_write_ram,
+
+ proslic_read_register,
+ proslic_read_ram,
+
+ NULL, /* semaphore */
+
+};