Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
meta-elphel393
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
Elphel
meta-elphel393
Commits
fc7bccdc
Commit
fc7bccdc
authored
Nov 26, 2013
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
added driver for vscw330x cross point switches
parent
37ef9732
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
1033 additions
and
1 deletion
+1033
-1
elphel393_defconfig_3.10.cfg
conf/machine/boards/common/elphel393_defconfig_3.10.cfg
+3
-1
elphel393.dts
conf/machine/boards/elphel393/elphel393.dts
+5
-0
linux-xlnx.inc
recipes-kernel/linux/linux-xlnx.inc
+1
-0
vsc330x.c
recipes-kernel/linux/linux-xlnx/drivers/misc/vsc330x.c
+201
-0
vsc3304.patch
recipes-kernel/linux/linux-xlnx/vsc3304.patch
+823
-0
No files found.
conf/machine/boards/common/elphel393_defconfig_3.10.cfg
View file @
fc7bccdc
...
...
@@ -874,6 +874,8 @@ CONFIG_SI570=y
# CONFIG_LATTICE_ECP3_CONFIG is not set
CONFIG_SRAM=y
# CONFIG_C2PORT is not set
##
CONFIG_VSC330X=y
#
# EEPROM support
...
...
conf/machine/boards/elphel393/elphel393.dts
View file @
fc7bccdc
...
...
@@ -142,6 +142,11 @@
compatible
=
"stm,m41t80"
;
reg
=
<
0x68
>;
};
vsc330x
@
1
{
compatible
=
"vsc,vsc3304"
;
reg
=
<
0x01
>;
};
}
;
ps7_gpio_0
:
ps7
-
gpio
@
e000a000
{
...
...
recipes-kernel/linux/linux-xlnx.inc
View file @
fc7bccdc
...
...
@@ -17,6 +17,7 @@ S = "${WORKDIR}/git"
FILESEXTRAPATHS_append
:=
"${THISDIR}/linux-xlnx:"
SRC_URI_append
+=
" file://xilinx_nandps_elphel393.patch"
SRC_URI_append
+=
" file://xilinx_emacps.c.patch"
SRC_URI_append
+=
" file://vsc3304.patch"
inherit
kernel
require
linux
-
dtb
.
inc
...
...
recipes-kernel/linux/linux-xlnx/drivers/misc/vsc330x.c
0 → 100644
View file @
fc7bccdc
/*!***************************************************************************
*! FILE NAME : vsc330x.c
*! DESCRIPTION: control of the VSC3304 4x4 crosspoint switch
*! Copyright (C) 2013 Elphel, Inc.
*! -----------------------------------------------------------------------------**
*!
*! This program is free software: you can redistribute it and/or modify
*! it under the terms of the GNU General Public License as published by
*! the Free Software Foundation, either version 3 of the License, or
*! (at your option) any later version.
*!
*! This program is distributed in the hope that it will be useful,
*! but WITHOUT ANY WARRANTY; without even the implied warranty of
*! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*! GNU General Public License for more details.
*!
*! You should have received a copy of the GNU General Public License
*! along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/string.h>
#define DRV_VERSION "1.0"
/* TODO: Descriptions from vsc3312 - check differences */
#define I2C_PAGE_CONNECTION 0x00
/* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding output (0..0xf) source
(input number) bit 4 (+0x10) - turn output off, bits 3:0 - source */
#define I2C_PAGE_INPUT_ISE 0x10
/* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding input (0..0xf)
ISE (equalization): Bits 5:4 ISE short: 0 - off, 1 - minimal, 2 - moderate, 3 - maximal;
bits 3:2 ISE medium, bits 1:0 ISE Long time constant */
#define I2C_PAGE_INPUT_STATE 0x11
/* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding input (0..0xf) enable,
polarity and termination (default 6)
Bit 2 (+4) Terminate to VDD ( 0 - connect, 1 - do not connect) - dedicated (0..7) inputs only
Bit 1 (+2) Input power (0 - on, 1 - off)
Bit 0 (+1) Invert signal at input */
#define I2C_INPUT_STATE_DATA 0x04
/* terminated,enabled, not inverted */
#define I2C_PAGE_INPUTLOS 0x12
/* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding input (0..0xf)
LOS (loss of signal) threshold
Bits 2:0 - level in mV for dedicated(bidirectional) inputs: 0,1,6,7 - unused, 2 - 150(170),
3 - 200(230), 4 - 250(280), 5 - 300(330) */
#define I2C_PAGE_OUTPUT_PRE_LONG 0x20
/* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding output (0..0xf)
long time constant pre-emphasis
Bits 6:3 Pre-Emphasis level (0x0 - off, 0x1 - min, 0xf - max - 0..6dB), bits 2:0 - Pre-emphasis
decay (0x0 - fastest, 0x7 - slowest) in 500..1500 ps range */
#define I2C_PAGE_OUTPUT_PRE_SHORT 0x21
/* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding output (0..0xf)
short time constant pre-emphasis
Bits 6:3 Pre-Emphasis level (0x0 - off, 0x1 - min, 0xf - max - 0..6dB),
bits 2:0 - Pre-emphasis decay (0x0 - fastest, 0x7 - slowest) in 30..500 ps range */
#define I2C_PAGE_OUTPUT_LEVEL 0x22
/* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding output (0..0xf)
short time constant pre-emphasis
Bits 3:0 - peak-to-peak 0,1,0xe,0xf - unused, 0x2-405mV,0x3-425V,0x4-455mV,0x5-485mV,0x6-520mV,
0x7-555mV,0x8-605mV,0x9-655mV,0xa-720mV,0xb-790mV,0xc-890mV,0xd-990mV (+3.3VDC required)
bit 4 (+0x10) - for 8-15 used as inputs only: terminate inputs 8..15 to VDDIO-0.7V */
#define I2C_PAGE_OUTPUT_STATE 0x23
/* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding output (0..0xf)
OOB signaling and output polarity
bits 4:1 - operation mode: 0xa - inverted, 0x5 - normal, 0x0 - suppressed
bit 0 - OOB control: 1 - enable LOS forwarding, 0 - ignore LOS */
#define I2C_PAGE_CHANNEL_STATUS 0xf0
/* When written to I2C_CURRENT_PAGE, makes registers 0..0xf monitor corresponding input (0..0xf) LOS status
bit 0 - LOS status: 1 - LOS detected (loss of signal), 0 - signal present (input has to be enabled,
otherwise 0 is read)when reading from address 0x10 of this page:
bit 0 - value of STAT0
bit 1 - value of STAT1 */
#define I2C_PAGE_STATUS0_CONFIGURE 0x80
/* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control selected input LOS to be OR-ed
to STAT0 output pin (and bit)
bit 0 : 1 - OR this input channel LOS status to STAT0 */
#define I2C_PAGE_STATUS1_CONFIGURE 0x81
/* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control selected input LOS to be OR-ed
to STAT1 output pin (and bit)
bit 0 : 1 - OR this input channel LOS status to STAT1 */
#define I2C_GLOBAL_CONNECTION 0x50
/* Bit 4 (+0x10) - disable all outputs, bits 3:0 - input number to connect to all outputs */
#define I2C_GLOBAL_INPUT_ISE 0x51
/* Bits 5:4 ISE short: 0 - off, 1 - minimal, 2 - moderate, 3 - maximal; bits 3:2 ISE medium,
bits 1:0 ISE Long time constant */
#define I2C_GLOBAL_INPUT_STATE 0x52
/* Bit 2 (+4) - terminate input to VDD (0..7 only) 0-connect, 1 Normal;
Bit 1 (+2) Input power off (0 - On, 1 - Off) bit0 (+1): Input polarity: 1 - inverted, 0 - normal */
#define I2C_GLOBAL_INPUT_LOS 0x53
/* Bits 2:0 - level in mV for dedicated(bidirectional) inputs: 0,1,6,7 - unused, 2 - 150(170),
3 - 200(230), 4 - 250(280), 5 - 300(330) */
#define I2C_GLOBAL_OUTPUT_PRE_LONG 0x54
/* Bits 6:3 Pre-Emphasis level (0x0 - off, 0x1 - min, 0xf - max - 0..6dB),
bits 2:0 - Pre-emphasis decay (0x0 - fastest, 0x7 - slowest) in 500..1500 ps range */
#define I2C_GLOBAL_OUTPUT_PRE_SHORT 0x55
/* Bits 6:3 Pre-Emphasis level (0x0 - off, 0x1 - min, 0xf - max - 0..6dB),
bits 2:0 - Pre-emphasis decay (0x0 - fastest, 0x7 - slowest) in 30..500 ps range */
#define I2C_GLOBAL_OUTPUT_LEVELl 0x56
/* Bits 3:0 - peak-to-peak 0,1,0xe,0xf - unused,0x2-405mV,0x3-425V,0x4-455mV,0x5-485mV,
0x6-520mV,0x7-555mV,0x8-605mV,0x9-655mV,0xa-720mV,0xb-790mV,0xc-890mV,0xd-990mV (+3.3VDC required)
bit 4 (+0x10) terminate inputs 8..15 to VDDIO-0.7V */
#define I2C_GLOBAL_OUTPUT_STATE 0x57
/* +1 (bit 0) - LOS, +0x15 - inverted, 0xa0 - normal, +0 - "Common mode" ? */
#define I2C_GLOBAL_OUTPUT_STATE_DATA 0x0b
/* No inversion, enable OOB forwarding on all channels */
#define I2C_STATUS0 0x58
/* Bit 0 - selected for Status0 chanel LOS on */
#define I2C_STATUS1 0x59
/* Bit 0 - selected for Status1 chanel LOS on // Which channel LOS to show on Status1 output/bit */
#define I2C_CORE_CONFIGURATION 0x75
#define I2C_CORE_CONFIGURATION_DATA 0x18
/* default 0x18 - 0x10 - leftEn, 0x8 - rightEn, 0x4 - DNU, 0x2 - BufferForceOn, 0x1 - Config polarity */
#define I2C_CORE_CONFIGURATION_DATAF 0x19
/* default with inverted Config polarity (freeze update) */
#if 0
#define I2C_SLAVE_ADDRESS 0x78 /* programmed only, not hardwired */
#endif
#define I2C_INTERFACE_MODE 0x79
#define I2C_INTERFACE_MODE_DATA 0x02
/* i2c (1 - 4-wire) */
#define I2C_SOFTWARE_RESET 0x7a
#define I2C_SOFTWARE_RESET_DATA 0x10
/* to reset, 0 - normal */
#define I2C_CURRENT_PAGE 0x7f
static
DEFINE_MUTEX
(
vsc3304_mutex
);
static
const
struct
i2c_device_id
vsc3304_id
[]
=
{
{
"vsc3304"
,
0
},
{
"vsc3308"
,
1
},
{
}
};
MODULE_DEVICE_TABLE
(
i2c
,
vsc3304_id
);
/*
struct m41t80_data {
u8 features;
struct rtc_device *rtc;
};
*/
/* I2C bus functions */
static
int
write_d8
(
void
*
client
,
u8
val
)
{
return
i2c_smbus_write_byte
(
client
,
val
);
}
static
int
write_r8d8
(
void
*
client
,
u8
reg
,
u8
val
)
{
return
i2c_smbus_write_byte_data
(
client
,
reg
,
val
);
}
static
int
write_r8d16
(
void
*
client
,
u8
reg
,
u16
val
)
{
return
i2c_smbus_write_word_data
(
client
,
reg
,
val
);
}
static
int
read_d8
(
void
*
client
)
{
return
i2c_smbus_read_byte
(
client
);
}
static
int
read_r8d8
(
void
*
client
,
u8
reg
)
{
return
i2c_smbus_read_byte_data
(
client
,
reg
);
}
static
int
read_r8d16
(
void
*
client
,
u8
reg
)
{
return
i2c_smbus_read_word_data
(
client
,
reg
);
}
static
const
struct
vsc_bus_ops
bops
=
{
.
read_d8
=
read_d8
,
.
read_r8d8
=
read_r8d8
,
.
read_r8d16
=
read_r8d16
,
.
write_d8
=
write_d8
,
.
write_r8d8
=
write_r8d8
,
.
write_r8d16
=
write_r8d16
,
};
static
int
vsc330x_i2c_probe
(
struct
i2c_client
*
client
,
const
struct
i2c_device_id
*
id
)
{
struct
ad_dpot_bus_data
bdata
=
{
.
client
=
client
,
.
bops
=
&
bops
,
};
if
(
!
i2c_check_functionality
(
client
->
adapter
,
I2C_FUNC_SMBUS_WORD_DATA
))
{
dev_err
(
&
client
->
dev
,
"SMBUS Word Data not Supported
\n
"
);
return
-
EIO
;
}
return
1
/* found*/
// return vsc330x_probe(&client->dev, &bdata, id->driver_data, id->name);
}
static
int
vsc330x_i2c_remove
(
struct
i2c_client
*
client
)
{
return
vsc330x_remove
(
&
client
->
dev
);
}
static
struct
i2c_driver
vsc330x_i2c_driver
=
{
.
driver
=
{
.
name
=
"vsc330x"
,
.
owner
=
THIS_MODULE
,
},
.
probe
=
vsc330x_i2c_probe
,
.
remove
=
vsc330x_i2c_remove
,
.
id_table
=
vsc330x_id
,
};
module_i2c_driver
(
vsc330x_i2c_driver
);
MODULE_AUTHOR
(
"Andrey Filippov <andrey@elphel.com>"
);
MODULE_DESCRIPTION
(
"VSC330x I2C bus driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS
(
"i2c:vsc330x"
);
recipes-kernel/linux/linux-xlnx/vsc3304.patch
0 → 100644
View file @
fc7bccdc
Index: git/drivers/misc/Kconfig
===================================================================
--- git.orig/drivers/misc/Kconfig 2013-11-26 00:53:11.204122076 -0700
+++ git/drivers/misc/Kconfig 2013-11-26 00:53:14.044122105 -0700
@@ -549,6 +549,13 @@
their requirements.
If unsure, say N
+config VSC330X
+ tristate "Support VSC330X crosspoint switch"
+ help
+ Say Y here if you have a VSC30X crosspoint switch IC on the I2C bus.
+ To compile this driver as a module, choose M here: the
+ module will be called vsc330x.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
Index: git/drivers/misc/Makefile
===================================================================
--- git.orig/drivers/misc/Makefile 2013-11-26 00:53:11.204122076 -0700
+++ git/drivers/misc/Makefile 2013-11-26 00:53:14.044122105 -0700
@@ -55,3 +55,4 @@
obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o
obj-$(CONFIG_SRAM) += sram.o
obj-$(CONFIG_XILINX_TRAFGEN) += xilinx_trafgen.o
+obj-$(CONFIG_VSC330X) += vsc330x.o
Index: git/drivers/misc/vsc330x.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ git/drivers/misc/vsc330x.c 2013-11-26 00:58:21.924125299 -0700
@@ -0,0 +1,791 @@
+/*!***************************************************************************
+ *! FILE NAME : vsc330x.c
+ *! DESCRIPTION: control of the VSC3304 4x4 crosspoint switch
+ *! Copyright (C) 2013 Elphel, Inc.
+ *! -----------------------------------------------------------------------------**
+ *!
+ *! This program is free software: you can redistribute it and/or modify
+ *! it under the terms of the GNU General Public License as published by
+ *! the Free Software Foundation, either version 3 of the License, or
+ *! (at your option) any later version.
+ *!
+ *! This program is distributed in the hope that it will be useful,
+ *! but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *! GNU General Public License for more details.
+ *!
+ *! You should have received a copy of the GNU General Public License
+ *! along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+
+#define DRV_VERSION "1.0"
+/* TODO: Descriptions from vsc3312 - check differences */
+#define I2C_PAGE_CONNECTION 0x00 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding output (0..0xf) source
+ (input number) bit 4 (+0x10) - turn output off, bits 3:0 - source */
+#define I2C_PAGE_INPUT_ISE 0x10 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding input (0..0xf)
+ ISE (equalization): Bits 5:4 ISE short: 0 - off, 1 - minimal, 2 - moderate, 3 - maximal;
+ bits 3:2 ISE medium, bits 1:0 ISE Long time constant */
+#define I2C_PAGE_INPUT_STATE 0x11 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding input (0..0xf) enable,
+ polarity and termination (default 6)
+ Bit 2 (+4) Terminate to VDD ( 0 - connect, 1 - do not connect) - dedicated (0..7) inputs only
+ Bit 1 (+2) Input power (0 - on, 1 - off)
+ Bit 0 (+1) Invert signal at input */
+#define I2C_INPUT_STATE_DATA 0x04 /* terminated,enabled, not inverted */
+#define I2C_PAGE_INPUT_LOS 0x12 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding input (0..0xf)
+ LOS (loss of signal) threshold
+ Bits 2:0 - level in mV for dedicated(bidirectional) inputs: 0,1,6,7 - unused, 2 - 150(170),
+ 3 - 200(230), 4 - 250(280), 5 - 300(330) */
+#define I2C_PAGE_OUTPUT_PRE_LONG 0x20 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding output (0..0xf)
+ long time constant pre-emphasis
+ Bits 6:3 Pre-Emphasis level (0x0 - off, 0x1 - min, 0xf - max - 0..6dB), bits 2:0 - Pre-emphasis
+ decay (0x0 - fastest, 0x7 - slowest) in 500..1500 ps range */
+#define I2C_PAGE_OUTPUT_PRE_SHORT 0x21 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding output (0..0xf)
+ short time constant pre-emphasis
+ Bits 6:3 Pre-Emphasis level (0x0 - off, 0x1 - min, 0xf - max - 0..6dB),
+ bits 2:0 - Pre-emphasis decay (0x0 - fastest, 0x7 - slowest) in 30..500 ps range */
+#define I2C_PAGE_OUTPUT_LEVEL 0x22 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding output (0..0xf)
+ short time constant pre-emphasis
+ Bits 3:0 - peak-to-peak 0,1,0xe,0xf - unused, 0x2-405mV,0x3-425V,0x4-455mV,0x5-485mV,0x6-520mV,
+ 0x7-555mV,0x8-605mV,0x9-655mV,0xa-720mV,0xb-790mV,0xc-890mV,0xd-990mV (+3.3VDC required)
+ bit 4 (+0x10) - for 8-15 used as inputs only: terminate inputs 8..15 to VDDIO-0.7V */
+#define I2C_PAGE_OUTPUT_STATE 0x23 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control corresponding output (0..0xf)
+ OOB signaling and output polarity
+ bits 4:1 - operation mode: 0xa - inverted, 0x5 - normal, 0x0 - suppressed
+ bit 0 - OOB control: 1 - enable LOS forwarding, 0 - ignore LOS */
+#define I2C_PAGE_CHANNEL_STATUS 0xf0 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf monitor corresponding input (0..0xf) LOS status
+ bit 0 - LOS status: 1 - LOS detected (loss of signal), 0 - signal present (input has to be enabled,
+ otherwise 0 is read)when reading from address 0x10 of this page:
+ bit 0 - value of STAT0
+ bit 1 - value of STAT1 */
+#define I2C_PAGE_STATUS0_CONFIGURE 0x80 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control selected input LOS to be OR-ed
+ to STAT0 output pin (and bit)
+ bit 0 : 1 - OR this input channel LOS status to STAT0 */
+#define I2C_PAGE_STATUS1_CONFIGURE 0x81 /* When written to I2C_CURRENT_PAGE, makes registers 0..0xf control selected input LOS to be OR-ed
+ to STAT1 output pin (and bit)
+ bit 0 : 1 - OR this input channel LOS status to STAT1 */
+#define I2C_PAGE_STATUS_READ 0xf0 /* Read only from reg=0x10: bit 0 - status0, bit 1 - status 1 */
+
+#define I2C_GLOBAL_CONNECTION 0x50 /* Bit 4 (+0x10) - disable all outputs, bits 3:0 - input number to connect to all outputs */
+#define I2C_GLOBAL_INPUT_ISE 0x51 /* Bits 5:4 ISE short: 0 - off, 1 - minimal, 2 - moderate, 3 - maximal; bits 3:2 ISE medium,
+ bits 1:0 ISE Long time constant */
+#define I2C_GLOBAL_INPUT_STATE 0x52 /* Bit 2 (+4) - terminate input to VDD (0..7 only) 0-connect, 1 Normal;
+ Bit 1 (+2) Input power off (0 - On, 1 - Off) bit0 (+1): Input polarity: 1 - inverted, 0 - normal */
+#define I2C_GLOBAL_INPUT_LOS 0x53 /* Bits 2:0 - level in mV for dedicated(bidirectional) inputs: 0,1,6,7 - unused, 2 - 150(170),
+ 3 - 200(230), 4 - 250(280), 5 - 300(330) */
+#define I2C_GLOBAL_OUTPUT_PRE_LONG 0x54 /* Bits 6:3 Pre-Emphasis level (0x0 - off, 0x1 - min, 0xf - max - 0..6dB),
+ bits 2:0 - Pre-emphasis decay (0x0 - fastest, 0x7 - slowest) in 500..1500 ps range */
+#define I2C_GLOBAL_OUTPUT_PRE_SHORT 0x55 /* Bits 6:3 Pre-Emphasis level (0x0 - off, 0x1 - min, 0xf - max - 0..6dB),
+ bits 2:0 - Pre-emphasis decay (0x0 - fastest, 0x7 - slowest) in 30..500 ps range */
+#define I2C_GLOBAL_OUTPUT_LEVEL 0x56 /* Bits 3:0 - peak-to-peak 0,1,0xe,0xf - unused,0x2-405mV,0x3-425V,0x4-455mV,0x5-485mV,
+ 0x6-520mV,0x7-555mV,0x8-605mV,0x9-655mV,0xa-720mV,0xb-790mV,0xc-890mV,0xd-990mV (+3.3VDC required)
+ bit 4 (+0x10) terminate inputs 8..15 to VDDIO-0.7V */
+#define I2C_GLOBAL_OUTPUT_STATE 0x57 /* +1 (bit 0) - LOS, +0x15 - inverted, 0xa0 - normal, +0 - "Common mode" ? */
+#define I2C_GLOBAL_OUTPUT_STATE_DATA 0x0b /* No inversion, enable OOB forwarding on all channels */
+#define I2C_GLOBAL_STATUS0 0x58 /* Bit 0 - selected for Status0 chanel LOS on from all channels */
+#define I2C_GLOBAL_STATUS1 0x59 /* Bit 0 - selected for Status1 chanel LOS on from all channels */
+#define I2C_CORE_CONFIGURATION 0x75
+#define I2C_CORE_CONFIGURATION_DATA 0x18 /* default 0x18 - 0x10 - leftEn, 0x8 - rightEn, 0x4 - DNU, 0x2 - BufferForceOn, 0x1 - Config polarity */
+#define I2C_CORE_CONFIGURATION_DATAF 0x19 /* default with inverted Config polarity (freeze update) */
+#define I2C_SLAVE_ADDRESS 0x78 /* programmed only, not hardwired */
+#define I2C_INTERFACE_MODE 0x79
+#define I2C_INTERFACE_MODE_DATA 0x02 /* i2c (1 - 4-wire) */
+#define I2C_SOFTWARE_RESET 0x7a
+#define I2C_SOFTWARE_RESET_DATA 0x10 /* to reset, 0 - normal */
+#define I2C_CURRENT_PAGE 0x7f
+#define VSC330X_FEATURE_FREEZE_UPDATES 0x01
+#define PORT_PEFIX "port_"
+#define ALL_PORTS "all"
+#define MAX_PORTS 16
+#define I2C_PAGE_GLOBAL -1 /* does not use paging access */
+
+#define SYSFS_PERMISSIONS 0644 /* default permissions for sysfs files */
+#define SYSFS_READONLY 0444
+#define SYSFS_WRITEONLY 0222
+
+static const char port_names[][8]={
+ PORT_PEFIX "00",PORT_PEFIX "01",PORT_PEFIX "02",PORT_PEFIX "03",PORT_PEFIX "04",
+ PORT_PEFIX "05",PORT_PEFIX "06",PORT_PEFIX "07",PORT_PEFIX "08",PORT_PEFIX "09",
+ PORT_PEFIX "10",PORT_PEFIX "11",PORT_PEFIX "12",PORT_PEFIX "13",PORT_PEFIX "14",
+ PORT_PEFIX "15",PORT_PEFIX "16",PORT_PEFIX "17",PORT_PEFIX "18",PORT_PEFIX "19",
+ PORT_PEFIX "20",PORT_PEFIX "21",PORT_PEFIX "22",PORT_PEFIX "23",PORT_PEFIX "24",
+ PORT_PEFIX "25",PORT_PEFIX "26",PORT_PEFIX "27",PORT_PEFIX "28",PORT_PEFIX "29",
+ PORT_PEFIX "30",PORT_PEFIX "31"};
+
+static const struct i2c_device_id vsc330x_id[] = {
+ { "vsc3304", 0 },
+ { "vsc3308", 1 },
+ { "vsc3312", 2 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, vsc3304_id);
+
+struct vsc330x_data_t {
+ u8 features;
+ u8 last_page;
+ u32 in_ports;
+ u32 out_ports;
+};
+
+static const struct vsc330x_data_t vsc330x_data[] = {
+ {.features=0,
+// .in_ports=0xff00, .out_ports=0xff00}, /* 3304 - all ports I/O shared*/
+/* for testing only enabling all ports */
+ .in_ports=0xffff, .out_ports=0xffff}, /* 3304 - all ports I/O shared*/
+ {.features=0,
+ .in_ports=0x00ff, .out_ports=0x00ff}, /* 3308 - no ports I/O shared */
+ {.features=VSC330X_FEATURE_FREEZE_UPDATES ,
+ .in_ports=0xffff, .out_ports=0xffff} /* 3312 - some ports I/O shared*/
+};
+
+static int read_reg(struct i2c_client *client, u8 reg);
+static int write_reg(struct i2c_client *client, u8 reg, u8 val);
+static int read_page_reg(struct i2c_client *client, int page, u8 reg);
+static int write_page_reg(struct i2c_client *client, int page, u8 reg, u8 val);
+static int read_field(struct i2c_client *client, u8 reg, int ls_bit_num, int width);
+static int read_page_field(struct i2c_client *client, int page, u8 reg, int ls_bit_num, int width);
+static int write_field(struct i2c_client *client, u8 reg, u8 val, int ls_bit_num, int width);
+static int write_page_field(struct i2c_client *client, int page, u8 reg, u8 val, int ls_bit_num, int width);
+static int freeze(struct device *dev, int lock);
+static ssize_t field_show(struct device *dev, struct device_attribute *attr, char *buf,
+ int page, int ls_bit_num, int width);
+static ssize_t field_show_reg(struct device *dev, char *buf, int page, int reg, int ls_bit_num, int width);
+static ssize_t field_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count,
+ int page, int ls_bit_num, int width);
+static ssize_t field_store_reg(struct device *dev, const char *buf, size_t count,
+ int page, int reg, int ls_bit_num, int width);
+static ssize_t connection_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t connection_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t input_ISE_short_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t input_ISE_short_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t input_ISE_medium_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t input_ISE_medium_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t input_ISE_long_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t input_ISE_long_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t input_state_off_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t input_state_off_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t input_state_invert_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t input_state_invert_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t input_LOS_threshold_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t input_LOS_threshold_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t output_PRE_long_level_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t output_PRE_long_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t output_PRE_long_decay_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t output_PRE_long_decay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t output_PRE_short_level_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t output_PRE_short_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t output_PRE_short_decay_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t output_PRE_short_decay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+/* TODO - fix for vsc3312*/
+static ssize_t input_terminate_low_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t input_terminate_low_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t input_terminate_high_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t input_terminate_high_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t output_level_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t output_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t output_mode_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t output_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t forward_OOB_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t forward_OOB_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t status_0_on_LOS_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t status_0_on_LOS_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t status_1_on_LOS_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t status_1_on_LOS_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t status_show (struct device *dev, struct device_attribute *attr, char *buf);
+/* global */
+static ssize_t global_connection_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t global_connection_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t global_ISE_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t global_ISE_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t global_input_state_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t global_input_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t global_input_LOS_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t global_input_LOS_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t global_output_PRE_long_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t global_output_PRE_long_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t global_output_PRE_short_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t global_output_PRE_short_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t global_output_level_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t global_output_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t global_output_state_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t global_output_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t global_status_0_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t global_status_0_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t global_status_1_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t global_status_1_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t core_config_word_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t core_config_word_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t core_left_bias_en_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t core_left_bias_en_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t core_right_bias_en_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t core_right_bias_en_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t core_buffer_on_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t core_buffer_on_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t core_config_pin_invert_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t core_config_pin_invert_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t soft_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+static ssize_t address_range_show (struct device *dev, struct device_attribute *attr, char *buf);
+static ssize_t address_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
+
+static DEVICE_ATTR(connection, SYSFS_PERMISSIONS, global_connection_show, global_connection_store);
+static DEVICE_ATTR(ISE, SYSFS_PERMISSIONS, global_ISE_show, global_ISE_store);
+static DEVICE_ATTR(input_state, SYSFS_PERMISSIONS, global_input_state_show, global_input_state_store);
+static DEVICE_ATTR(input_LOS, SYSFS_PERMISSIONS, global_input_LOS_show, global_input_LOS_store);
+static DEVICE_ATTR(output_PRE_long, SYSFS_PERMISSIONS, global_output_PRE_long_show, global_output_PRE_long_store);
+static DEVICE_ATTR(output_PRE_short, SYSFS_PERMISSIONS, global_output_PRE_short_show, global_output_PRE_short_store);
+static DEVICE_ATTR(output_level, SYSFS_PERMISSIONS, global_output_level_show, global_output_level_store);
+static DEVICE_ATTR(output_state, SYSFS_PERMISSIONS, global_output_state_show, global_output_state_store);
+static DEVICE_ATTR(status_0, SYSFS_PERMISSIONS, global_status_0_show, global_status_0_store);
+static DEVICE_ATTR(status_1, SYSFS_PERMISSIONS, global_status_1_show, global_status_1_store);
+static DEVICE_ATTR(core_config_word, SYSFS_PERMISSIONS, core_config_word_show, core_config_word_store);
+static DEVICE_ATTR(core_left_bias_en, SYSFS_PERMISSIONS, core_left_bias_en_show, core_left_bias_en_store);
+static DEVICE_ATTR(core_right_bias_en,SYSFS_PERMISSIONS, core_right_bias_en_show, core_right_bias_en_store);
+static DEVICE_ATTR(core_buffer_on, SYSFS_PERMISSIONS, core_buffer_on_show, core_buffer_on_store);
+static DEVICE_ATTR(core_config_pin_invert,SYSFS_PERMISSIONS, core_config_pin_invert_show, core_config_pin_invert_store);
+static DEVICE_ATTR(soft_reset, SYSFS_PERMISSIONS & SYSFS_WRITEONLY, NULL, soft_reset_store);
+static DEVICE_ATTR(address_range, SYSFS_PERMISSIONS, address_range_show, address_range_store);
+static DEVICE_ATTR(status, SYSFS_PERMISSIONS & SYSFS_READONLY, status_show, NULL);
+
+static struct attribute *globals_dev_attrs[] = {
+ &dev_attr_connection.attr,
+ &dev_attr_ISE.attr,
+ &dev_attr_input_state.attr,
+ &dev_attr_input_LOS.attr,
+ &dev_attr_output_PRE_long.attr,
+ &dev_attr_output_PRE_short.attr,
+ &dev_attr_output_level.attr,
+ &dev_attr_output_state.attr,
+ &dev_attr_status_0.attr,
+ &dev_attr_status_1.attr,
+ &dev_attr_core_config_word.attr,
+ &dev_attr_core_left_bias_en.attr,
+ &dev_attr_core_right_bias_en.attr,
+ &dev_attr_core_buffer_on.attr,
+ &dev_attr_core_config_pin_invert.attr,
+ &dev_attr_soft_reset.attr,
+ &dev_attr_address_range.attr,
+ &dev_attr_status.attr,
+ NULL
+};
+
+static const struct attribute_group dev_attr_globals_group = {
+ .attrs = globals_dev_attrs,
+ .name = "globals",
+};
+
+
+/* seems we need to INITIALIZE all structures to zero - examples use static */
+static int make_group (struct device *dev, const char * name, int port_mask, mode_t mode,
+ ssize_t (*show)(struct device *dev, struct device_attribute *attr,
+ char *buf),
+ ssize_t (*store)(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+){
+ int retval=-1;
+ int port,index=0,num_regs;
+ struct attribute **pattrs; /* array of pointers to attibutes */
+ struct device_attribute *dev_attrs;
+ struct attribute_group *attr_group;
+ for (port=0,num_regs=1;port<MAX_PORTS;port++) if (port_mask & (1<<port)) num_regs++; /* 1 extra - used for all ports */
+
+ pattrs = devm_kzalloc(dev, (num_regs+1)*sizeof(pattrs[0]), GFP_KERNEL);
+ if (!pattrs) return -ENOMEM;
+ dev_attrs = devm_kzalloc(dev, num_regs*sizeof(dev_attrs[0]), GFP_KERNEL);
+ if (!dev_attrs) return -ENOMEM;
+ attr_group = devm_kzalloc(dev, sizeof(*attr_group), GFP_KERNEL);
+ if (!attr_group) return -ENOMEM;
+ memset(dev_attrs, 0, num_regs*sizeof(dev_attrs[0]));
+ memset(attr_group, 0, sizeof(*attr_group));
+ for (port=0,index=0;port<MAX_PORTS;port++) if (port_mask & (1<<port)){
+ dev_attrs[index].attr.name=port_names[port];
+ dev_attrs[index].attr.mode=mode;
+ dev_attrs[index].show= show;
+ dev_attrs[index].store=store;
+ pattrs[index]=&(dev_attrs[index].attr);
+ index++;
+ }
+ /* add all ports */
+ dev_attrs[index].attr.name=ALL_PORTS;
+ dev_attrs[index].attr.mode=mode; /* & 0222; */ /* write only */
+ dev_attrs[index].show= show;
+ dev_attrs[index].store=store;
+ pattrs[index]=&(dev_attrs[index].attr);
+ index++;
+ pattrs[index]=NULL;
+
+ attr_group->name = name;
+ attr_group->attrs =pattrs;
+ dev_dbg(dev,"name=%s, &dev->kobj=0x%08x\n",attr_group->name, (int) (&dev->kobj));
+ index=0;
+ while ((*attr_group).attrs[index]){
+ dev_dbg(dev,"attr=%s\n",attr_group->attrs[index]->name);
+ index++;
+ }
+ if (&dev->kobj) {
+ retval = sysfs_create_group(&dev->kobj, attr_group);
+ }
+ return retval;
+}
+
+static int vsc330x_sysfs_register(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct vsc330x_data_t *clientdata = i2c_get_clientdata(client);
+ int ports=clientdata->out_ports;
+ int retval=0;
+ if ((retval=make_group (dev, "connections", ports, SYSFS_PERMISSIONS, connection_show, connection_store))) return retval;
+ if ((retval=make_group (dev, "input_ISE_short", ports, SYSFS_PERMISSIONS, input_ISE_short_show, input_ISE_short_store))) return retval;
+ if ((retval=make_group (dev, "input_ISE_medium", ports, SYSFS_PERMISSIONS, input_ISE_medium_show, input_ISE_medium_store))) return retval;
+ if ((retval=make_group (dev, "input_ISE_long", ports, SYSFS_PERMISSIONS, input_ISE_long_show, input_ISE_long_store))) return retval;
+ if ((retval=make_group (dev, "input_state_off", ports, SYSFS_PERMISSIONS, input_state_off_show, input_state_off_store))) return retval;
+ if ((retval=make_group (dev, "input_state_invert", ports, SYSFS_PERMISSIONS, input_state_invert_show, input_state_invert_store))) return retval;
+ if ((retval=make_group (dev, "input_LOS_threshold", ports, SYSFS_PERMISSIONS, input_LOS_threshold_show, input_LOS_threshold_store))) return retval;
+ if ((retval=make_group (dev, "output_PRE_long_level", ports, SYSFS_PERMISSIONS, output_PRE_long_level_show, output_PRE_long_level_store))) return retval;
+ if ((retval=make_group (dev, "output_PRE_long_decay", ports, SYSFS_PERMISSIONS, output_PRE_long_decay_show, output_PRE_long_decay_store))) return retval;
+ if ((retval=make_group (dev, "output_PRE_short_level",ports, SYSFS_PERMISSIONS, output_PRE_short_level_show, output_PRE_short_level_store))) return retval;
+ if ((retval=make_group (dev, "output_PRE_short_decay",ports, SYSFS_PERMISSIONS, output_PRE_short_decay_show, output_PRE_short_decay_store))) return retval;
+ if ((retval=make_group (dev, "input_terminate_low", ports, SYSFS_PERMISSIONS, input_terminate_low_show, input_terminate_low_store))) return retval;
+ if ((retval=make_group (dev, "input_terminate_high", ports, SYSFS_PERMISSIONS, input_terminate_high_show, input_terminate_high_store))) return retval;
+ if ((retval=make_group (dev, "output_level", ports, SYSFS_PERMISSIONS, output_level_show, output_level_store))) return retval;
+ if ((retval=make_group (dev, "output_mode", ports, SYSFS_PERMISSIONS, output_mode_show, output_mode_store))) return retval;
+ if ((retval=make_group (dev, "forward_OOB", ports, SYSFS_PERMISSIONS, forward_OOB_show, forward_OOB_store))) return retval;
+ if ((retval=make_group (dev, "status_0_on_LOS", ports, SYSFS_PERMISSIONS, status_0_on_LOS_show, status_0_on_LOS_store))) return retval;
+ if ((retval=make_group (dev, "status_1_on_LOS", ports, SYSFS_PERMISSIONS, status_1_on_LOS_show, status_1_on_LOS_store))) return retval;
+ if (&dev->kobj) {
+ retval = sysfs_create_group(&dev->kobj, &dev_attr_globals_group);
+ }
+ return retval;
+}
+
+
+static ssize_t field_show(struct device *dev, struct device_attribute *attr, char *buf,
+ int page, int ls_bit_num, int width)
+{
+ int reg, port_mask, rc=0, len=0, count=PAGE_SIZE;
+ struct i2c_client *client = to_i2c_client(dev);
+ /* do for all ports - not used. TODO: we can try to output all of them in a row, but not sure if count will permit*/
+ if (strcmp(attr->attr.name,ALL_PORTS) == 0) {
+ port_mask=((struct vsc330x_data_t *) i2c_get_clientdata(to_i2c_client(dev)))->out_ports;
+ for (reg=0;reg<MAX_PORTS;reg++) if ((port_mask & (1<<reg)) && (count>5)) {
+ dev_dbg(dev, "name='%s' reg=0x%x, page=0x%x, ls_bit_num=0x%x, width=0x%x\n",
+ attr->attr.name, reg, page, ls_bit_num, width);
+ rc = read_page_field(client, page, reg, ls_bit_num, width);
+// rc=field_show_reg(dev, buf, page, reg, ls_bit_num, width);
+ if (rc<0) return rc;
+ rc=sprintf(buf, "%d ", rc);
+ buf+=rc;
+ len+=rc;
+ count-=rc;
+
+ }
+ if (len>0) {
+ len--;
+ count++;
+ buf--;
+ }
+ rc=sprintf(buf, "\n");
+ buf+=rc;
+ len+=rc;
+ count-=rc;
+ return len;
+ }
+ /* process single port */
+ sscanf(attr->attr.name+strlen(PORT_PEFIX), "%du", ®);
+ dev_dbg(dev, "name='%s' name+%d='%s' reg=0x%x, page=0x%x, ls_bit_num=0x%x, width=0x%x\n",
+ attr->attr.name, strlen(PORT_PEFIX), ( attr->attr.name+strlen(PORT_PEFIX)), reg, page, ls_bit_num, width);
+ return field_show_reg(dev, buf, page, reg, ls_bit_num, width);
+}
+
+static ssize_t field_show_reg(struct device *dev, char *buf, int page, int reg, int ls_bit_num, int width)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int data=read_page_field(client, page, reg, ls_bit_num, width);
+ return sprintf(buf, "%d\n", data);
+}
+
+static ssize_t field_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count,
+ int page, int ls_bit_num, int width)
+{
+ int reg, port_mask, rc;
+ /* do for all ports */
+ if (strcmp(attr->attr.name,ALL_PORTS) == 0) {
+ port_mask=((struct vsc330x_data_t *) i2c_get_clientdata(to_i2c_client(dev)))->out_ports;
+ for (reg=0;reg<MAX_PORTS;reg++) if (port_mask & (1<<reg)) {
+ dev_dbg(dev, "name='%s' reg=0x%x, page=0x%x, ls_bit_num=0x%x, width=0x%x\n",
+ attr->attr.name, reg, page, ls_bit_num, width);
+ rc= field_store_reg(dev, buf, count, page, reg, ls_bit_num, width);
+ if (rc<0) return rc;
+ }
+ return count;
+ }
+ /* process single port */
+ sscanf(attr->attr.name+strlen(PORT_PEFIX), "%du", ®);
+ dev_dbg(dev, "name='%s' name+%d='%s' reg=0x%x, page=0x%x, ls_bit_num=0x%x, width=0x%x\n",
+ attr->attr.name, strlen(PORT_PEFIX), ( attr->attr.name+strlen(PORT_PEFIX)), reg, page, ls_bit_num, width);
+
+ return field_store_reg(dev, buf, count, page, reg, ls_bit_num, width);
+}
+static ssize_t field_store_reg(struct device *dev, const char *buf, size_t count,
+ int page, int reg, int ls_bit_num, int width)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int val,rc;
+ sscanf(buf, "%du", &val);
+ rc=write_page_field(client, page, reg, val, ls_bit_num, width);
+ return count;
+}
+
+
+static ssize_t connection_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show(dev, attr, buf, I2C_PAGE_CONNECTION, 0, 5);}
+static ssize_t connection_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store(dev, attr, buf, count, I2C_PAGE_CONNECTION, 0, 5);}
+
+static ssize_t input_ISE_short_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show(dev, attr, buf, I2C_PAGE_INPUT_ISE, 4, 2);}
+static ssize_t input_ISE_short_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_ISE, 4, 2);}
+
+static ssize_t input_ISE_medium_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show(dev, attr, buf, I2C_PAGE_INPUT_ISE, 2, 2);}
+static ssize_t input_ISE_medium_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_ISE, 2, 2);}
+
+static ssize_t input_ISE_long_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show(dev, attr, buf, I2C_PAGE_INPUT_ISE, 0, 2);}
+static ssize_t input_ISE_long_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_ISE, 0, 2);}
+
+static ssize_t input_state_off_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show(dev, attr, buf, I2C_PAGE_INPUT_STATE, 1, 1);}
+static ssize_t input_state_off_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_STATE, 1, 1);}
+
+static ssize_t input_state_invert_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show(dev, attr, buf, I2C_PAGE_INPUT_STATE, 0, 1);}
+static ssize_t input_state_invert_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_STATE, 0, 1);}
+
+static ssize_t input_LOS_threshold_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show(dev, attr, buf, I2C_PAGE_INPUT_LOS, 0, 3);}
+static ssize_t input_LOS_threshold_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_LOS, 0, 3);}
+
+static ssize_t output_PRE_long_level_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_PRE_LONG, 3, 4);}
+static ssize_t output_PRE_long_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_PRE_LONG, 3, 4);}
+
+static ssize_t output_PRE_long_decay_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_PRE_LONG, 0, 3);}
+static ssize_t output_PRE_long_decay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_PRE_LONG, 0, 3);}
+
+static ssize_t output_PRE_short_level_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_PRE_SHORT, 3, 4);}
+static ssize_t output_PRE_short_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_PRE_SHORT, 3, 4);}
+
+static ssize_t output_PRE_short_decay_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_PRE_SHORT, 0, 3);}
+static ssize_t output_PRE_short_decay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_PRE_SHORT, 0, 3);}
+/* TODO - fix for vsc3312*/
+static ssize_t input_terminate_low_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show(dev, attr, buf, I2C_PAGE_INPUT_STATE, 2, 1);}
+static ssize_t input_terminate_low_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store(dev, attr, buf, count, I2C_PAGE_INPUT_STATE, 2, 1);}
+static ssize_t input_terminate_high_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_LEVEL, 4, 1);}
+static ssize_t input_terminate_high_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_LEVEL, 4, 1);}
+
+static ssize_t output_level_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_LEVEL, 0, 4);}
+static ssize_t output_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_LEVEL, 0, 4);}
+
+static ssize_t output_mode_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_STATE, 1, 4);}
+static ssize_t output_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_STATE, 1, 4);}
+
+static ssize_t forward_OOB_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show(dev, attr, buf, I2C_PAGE_OUTPUT_STATE, 0, 1);}
+static ssize_t forward_OOB_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store(dev, attr, buf, count, I2C_PAGE_OUTPUT_STATE, 0, 1);}
+
+static ssize_t status_0_on_LOS_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show(dev, attr, buf, I2C_PAGE_STATUS0_CONFIGURE, 0, 1);}
+static ssize_t status_0_on_LOS_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store(dev, attr, buf, count, I2C_PAGE_STATUS0_CONFIGURE, 0, 1);}
+
+static ssize_t status_1_on_LOS_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show(dev, attr, buf, I2C_PAGE_STATUS1_CONFIGURE, 0, 1);}
+static ssize_t status_1_on_LOS_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store(dev, attr, buf, count, I2C_PAGE_STATUS1_CONFIGURE, 0, 1);}
+
+static ssize_t status_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show_reg(dev, buf, I2C_PAGE_STATUS_READ, 0x10, 0, 2);}
+
+
+/* Global registers use all 8 bits (and control multiple features at once, because it is not possible to read-modify-write them */
+static ssize_t global_connection_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_CONNECTION, 0, 8);}
+static ssize_t global_connection_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_CONNECTION, 0, 8);}
+
+
+static ssize_t global_ISE_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_INPUT_ISE, 0, 8);}
+static ssize_t global_ISE_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_INPUT_ISE, 0, 8);}
+
+static ssize_t global_input_state_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_INPUT_STATE, 0, 8);}
+static ssize_t global_input_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_INPUT_STATE, 0, 8);}
+
+static ssize_t global_input_LOS_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_INPUT_LOS, 0, 8);}
+static ssize_t global_input_LOS_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_INPUT_LOS, 0, 8);}
+
+static ssize_t global_output_PRE_long_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_PRE_LONG, 0, 8);}
+static ssize_t global_output_PRE_long_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_PRE_LONG, 0, 8);}
+
+static ssize_t global_output_PRE_short_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_PRE_SHORT, 0, 8);}
+static ssize_t global_output_PRE_short_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_PRE_SHORT, 0, 8);}
+
+static ssize_t global_output_level_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_LEVEL, 0, 8);}
+static ssize_t global_output_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_LEVEL, 0, 8);}
+
+static ssize_t global_output_state_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_STATE, 0, 8);}
+static ssize_t global_output_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_OUTPUT_STATE, 0, 8);}
+
+static ssize_t global_status_0_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_STATUS0, 0, 8);}
+static ssize_t global_status_0_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_STATUS0, 0, 8);}
+
+static ssize_t global_status_1_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_GLOBAL_STATUS1, 0, 8);}
+static ssize_t global_status_1_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_GLOBAL_STATUS1, 0, 8);}
+
+static ssize_t core_config_word_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 0, 8);}
+static ssize_t core_config_word_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 0, 8);} /* 0x18/ 0x19 for 3312 */
+
+static ssize_t core_left_bias_en_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 4, 1);}
+static ssize_t core_left_bias_en_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 4, 1);}
+
+static ssize_t core_right_bias_en_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 3, 1);}
+static ssize_t core_right_bias_en_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 3, 1);}
+
+static ssize_t core_buffer_on_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 1, 1);}
+static ssize_t core_buffer_on_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 1, 1);}
+
+static ssize_t core_config_pin_invert_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 0, 1);}
+static ssize_t core_config_pin_invert_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_CORE_CONFIGURATION, 0, 1);}
+
+static ssize_t soft_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_SOFTWARE_RESET, 4, 1);}
+
+static ssize_t address_range_show (struct device *dev, struct device_attribute *attr, char *buf)
+ {return field_show_reg (dev, buf, I2C_PAGE_GLOBAL, I2C_SOFTWARE_RESET, 0, 4);}
+static ssize_t address_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+ {return field_store_reg(dev, buf, count, I2C_PAGE_GLOBAL, I2C_SOFTWARE_RESET, 0, 4);}
+
+
+static int bitmask(int ls_bit_num, int width)
+{
+ return ((1 << width) -1) << ls_bit_num;
+}
+
+static int read_reg(struct i2c_client *client, u8 reg)
+{
+ int val;
+ val= i2c_smbus_read_byte_data(client, reg);
+ dev_dbg(&client->dev,"reading i2c device : slave=0x%x, reg=0x%x -> 0x%x\n",(int) (client->addr),reg,val);
+ return val;
+}
+
+static int write_reg(struct i2c_client *client, u8 reg, u8 val)
+{
+ dev_dbg(&client->dev,"device write: slave=0x%x, reg=0x%x, val=0x%x\n", (int) (client->addr),reg,val);
+ return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+static int read_page_reg(struct i2c_client *client, int page, u8 reg)
+{
+ int rc;
+ struct vsc330x_data_t *clientdata = i2c_get_clientdata(client);
+ if ((page>=0) && (clientdata->last_page!=page)) {
+ if (((rc=write_reg(client, I2C_CURRENT_PAGE, page)))<0) return rc;
+ clientdata->last_page=page;
+ }
+ return read_reg(client, reg);
+}
+
+static int write_page_reg(struct i2c_client *client, int page, u8 reg, u8 val)
+{
+ int rc;
+ struct vsc330x_data_t *clientdata = i2c_get_clientdata(client);
+ if ((page>=0) && (clientdata->last_page!=page)) {
+ if (((rc=write_reg(client, I2C_CURRENT_PAGE, page)))<0) return rc;
+ clientdata->last_page=page;
+ }
+ return write_reg(client, reg, val);
+}
+
+static int read_field(struct i2c_client *client, u8 reg, int ls_bit_num, int width)
+{
+ int rc;
+ if (((rc=read_reg(client, reg)))<0) return rc;
+ rc= (rc >> ls_bit_num) & bitmask(0, width);
+ dev_dbg(&client->dev,"reg=0x%x, ls_bit_num=%d, width=%d -> 0x%x\n", (int) reg, ls_bit_num,width,rc);
+ return rc;
+}
+static int read_page_field(struct i2c_client *client, int page, u8 reg, int ls_bit_num, int width)
+{
+ int rc;
+ struct vsc330x_data_t *clientdata = i2c_get_clientdata(client);
+ dev_dbg(&client->dev,"page=0x%x (last was 0x%x) reg=0x%x, ls_bit_num=%d, width=%d:\n",
+ page, (clientdata->last_page!=page), (int) reg, ls_bit_num, width);
+ if ((page>=0) && (clientdata->last_page!=page)) {
+ if (((rc=write_reg(client, I2C_CURRENT_PAGE, page)))<0) return rc;
+ clientdata->last_page=page;
+ }
+ rc= read_field(client, reg, ls_bit_num, width);
+ dev_dbg(&client->dev,"page=0x%x (last was 0x%x) reg=0x%x, ls_bit_num=%d, width=%d -> 0x%x\n",
+ page, (clientdata->last_page!=page), (int) reg, ls_bit_num, width,rc);
+ return rc;
+}
+static int write_field(struct i2c_client *client, u8 reg, u8 val, int ls_bit_num, int width)
+{
+ int rc;
+ dev_dbg(&client->dev,"reg=0x%x, val=0x%x, ls_bit_num=%d, width=%d \n", (int) reg, (int) val,ls_bit_num,width);
+ if (((rc=read_reg(client, reg)))<0) return rc;
+ val<<=ls_bit_num;
+ return write_reg(client, reg, ((rc ^ val) & bitmask(ls_bit_num, width))^ rc);
+}
+
+static int write_page_field(struct i2c_client *client, int page, u8 reg, u8 val, int ls_bit_num, int width)
+{
+ int rc;
+ struct vsc330x_data_t *clientdata = i2c_get_clientdata(client);
+ dev_dbg(&client->dev,"page=0x%x (last was 0x%x), reg=0x%x, val=0x%x, ls_bit_num=%d, width=%d \n",
+ page,clientdata->last_page, (int) reg, (int) val,ls_bit_num,width);
+ if ((page>=0) && (clientdata->last_page!=page)) {
+ if (((rc=write_reg(client, I2C_CURRENT_PAGE, page)))<0) return rc;
+ clientdata->last_page=page;
+ }
+ return write_field(client, reg, val, ls_bit_num, width);
+}
+
+static int freeze(struct device *dev, int lock)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct vsc330x_data_t *clientdata = i2c_get_clientdata(client);
+ if (clientdata->features & VSC330X_FEATURE_FREEZE_UPDATES ){
+ /*Assumes config pin grounded, otherwise swap freeze/unfreeze*/
+ return write_reg(client, I2C_CORE_CONFIGURATION, lock? I2C_CORE_CONFIGURATION_DATAF: I2C_CORE_CONFIGURATION_DATA);
+ } else {
+ dev_dbg(dev, "Update freeze is not implemented in %s\n",client->name);
+ return 0; /* just do nothing */
+ }
+
+}
+
+static int vsc330x_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int rc=0;
+ struct vsc330x_data_t *clientdata = NULL;
+
+/* initialize i2c mode */
+ rc=write_reg(client, I2C_INTERFACE_MODE, I2C_INTERFACE_MODE_DATA);
+ if (rc<0) goto wr_err;
+ rc=write_reg(client, I2C_CURRENT_PAGE, 0); // initialize to page 0
+ if (rc<0) goto wr_err;
+
+ dev_info(&client->dev,
+ "Chip %s found, driver version %s\n", id->name, DRV_VERSION);
+ clientdata = devm_kzalloc(&client->dev, sizeof(*clientdata), GFP_KERNEL);
+ if (!clientdata) {
+ rc = -ENOMEM;
+ goto exit;
+ }
+ clientdata->last_page = 0;
+ clientdata->features = vsc330x_data[id->driver_data].features;
+ clientdata->in_ports = vsc330x_data[id->driver_data].in_ports;
+ clientdata->out_ports = vsc330x_data[id->driver_data].out_ports;
+ i2c_set_clientdata(client, clientdata);
+ rc = vsc330x_sysfs_register(&client->dev);
+ if (rc)
+ goto exit;
+ return 0; /* found OK*/
+wr_err:
+ rc = -EIO;
+ dev_err(&client->dev, "%s:%d error writing\n",__func__,__LINE__);
+ goto exit;
+#if 0
+rd_err:
+ rc = -EIO;
+ dev_err(&client->dev, "%s:%d error reading\n",__func__,__LINE__);
+ goto exit;
+#endif
+exit:
+ return rc;
+
+}
+
+static int vsc330x_i2c_remove(struct i2c_client *client)
+{
+ return 0;
+}
+
+static struct i2c_driver vsc330x_i2c_driver = {
+ .driver = {
+ .name = "vsc330x",
+ .owner = THIS_MODULE,
+ },
+ .probe = vsc330x_i2c_probe,
+ .remove = vsc330x_i2c_remove,
+ .id_table = vsc330x_id,
+};
+
+module_i2c_driver(vsc330x_i2c_driver);
+
+MODULE_AUTHOR("Andrey Filippov <andrey@elphel.com>");
+MODULE_DESCRIPTION("VSC330x I2C bus driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("i2c:vsc330x");
+
+
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment