Merge pull request #514 from brandonchuang/as4610_54t_b

[as4610] Modify oom related part to support kernel 4.14
This commit is contained in:
Jeffrey Townsend
2019-01-07 09:51:52 -08:00
committed by GitHub
13 changed files with 800 additions and 1765 deletions

View File

@@ -8,11 +8,18 @@ class OnlPlatform_arm_accton_as4610_30_r0(OnlPlatformAccton,
SYS_OBJECT_ID=".4610.30"
def baseconfig(self):
self.insmod("accton_i2c_cpld")
self.new_i2c_device("as4610_30_cpld", 0x30, 0)
self.insmod("accton_as4610_sfp")
self.insmod("accton_as4610_cpld")
self.insmod("accton_as4610_psu")
self.insmod("accton_as4610_fan")
self.insmod("accton_as4610_leds")
self.insmod("ym2651y")
self.insmod("optoe")
subprocess.call('echo port25 > /sys/bus/i2c/devices/2-0050/port_name', shell=True)
subprocess.call('echo port26 > /sys/bus/i2c/devices/3-0050/port_name', shell=True)
subprocess.call('echo port27 > /sys/bus/i2c/devices/4-0050/port_name', shell=True)
subprocess.call('echo port28 > /sys/bus/i2c/devices/5-0050/port_name', shell=True)
subprocess.call('echo port29 > /sys/bus/i2c/devices/6-0050/port_name', shell=True)
subprocess.call('echo port30 > /sys/bus/i2c/devices/7-0050/port_name', shell=True)
return True

View File

@@ -8,13 +8,20 @@ class OnlPlatform_arm_accton_as4610_54_r0(OnlPlatformAccton,
SYS_OBJECT_ID=".4610.54"
def baseconfig(self):
self.insmod("accton_i2c_cpld")
self.new_i2c_device("as4610_54_cpld", 0x30, 0)
self.insmod("accton_as4610_sfp")
self.insmod("accton_as4610_cpld")
self.insmod("accton_as4610_psu")
self.insmod("accton_as4610_fan")
self.insmod("accton_as4610_leds")
self.insmod("ym2651y")
self.insmod("optoe")
subprocess.call('echo port49 > /sys/bus/i2c/devices/2-0050/port_name', shell=True)
subprocess.call('echo port50 > /sys/bus/i2c/devices/3-0050/port_name', shell=True)
subprocess.call('echo port51 > /sys/bus/i2c/devices/4-0050/port_name', shell=True)
subprocess.call('echo port52 > /sys/bus/i2c/devices/5-0050/port_name', shell=True)
subprocess.call('echo port53 > /sys/bus/i2c/devices/6-0050/port_name', shell=True)
subprocess.call('echo port54 > /sys/bus/i2c/devices/7-0050/port_name', shell=True)
# self.new_i2c_devices(
# [
# ("pca9548", 0x70, 1),

View File

@@ -8,11 +8,18 @@ class OnlPlatform_arm_accton_as4610_30_r0(OnlPlatformAccton,
SYS_OBJECT_ID=".4610.30"
def baseconfig(self):
self.insmod("accton_i2c_cpld")
self.new_i2c_device("as4610_30_cpld", 0x30, 0)
self.insmod("accton_as4610_sfp")
self.insmod("accton_as4610_cpld")
self.insmod("accton_as4610_psu")
self.insmod("accton_as4610_fan")
self.insmod("accton_as4610_leds")
self.insmod("ym2651y")
self.insmod("optoe")
subprocess.call('echo port25 > /sys/bus/i2c/devices/2-0050/port_name', shell=True)
subprocess.call('echo port26 > /sys/bus/i2c/devices/3-0050/port_name', shell=True)
subprocess.call('echo port27 > /sys/bus/i2c/devices/4-0050/port_name', shell=True)
subprocess.call('echo port28 > /sys/bus/i2c/devices/5-0050/port_name', shell=True)
subprocess.call('echo port29 > /sys/bus/i2c/devices/6-0050/port_name', shell=True)
subprocess.call('echo port30 > /sys/bus/i2c/devices/7-0050/port_name', shell=True)
return True

View File

@@ -8,13 +8,20 @@ class OnlPlatform_arm_accton_as4610_54_r0(OnlPlatformAccton,
SYS_OBJECT_ID=".4610.54"
def baseconfig(self):
self.insmod("accton_i2c_cpld")
self.new_i2c_device("as4610_54_cpld", 0x30, 0)
self.insmod("accton_as4610_sfp")
self.insmod("accton_as4610_cpld")
self.insmod("accton_as4610_psu")
self.insmod("accton_as4610_fan")
self.insmod("accton_as4610_leds")
self.insmod("ym2651y")
self.insmod("optoe")
subprocess.call('echo port49 > /sys/bus/i2c/devices/2-0050/port_name', shell=True)
subprocess.call('echo port50 > /sys/bus/i2c/devices/3-0050/port_name', shell=True)
subprocess.call('echo port51 > /sys/bus/i2c/devices/4-0050/port_name', shell=True)
subprocess.call('echo port52 > /sys/bus/i2c/devices/5-0050/port_name', shell=True)
subprocess.call('echo port53 > /sys/bus/i2c/devices/6-0050/port_name', shell=True)
subprocess.call('echo port54 > /sys/bus/i2c/devices/7-0050/port_name', shell=True)
# self.new_i2c_devices(
# [
# ("pca9548", 0x70, 1),

View File

@@ -87,8 +87,8 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
sfp_eeprom@50 {
compatible = "accton,as4610_sfp1";
optoe@50 {
compatible = "optoe2";
reg = <0x50>;
label = "port49";
};
@@ -99,8 +99,8 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
sfp_eeprom@50 {
compatible = "accton,as4610_sfp2";
optoe@50 {
compatible = "optoe2";
reg = <0x50>;
label = "port50";
};
@@ -111,8 +111,8 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <2>;
sfp_eeprom@50 {
compatible = "accton,as4610_sfp3";
optoe@50 {
compatible = "optoe2";
reg = <0x50>;
label = "port51";
};
@@ -123,8 +123,8 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <3>;
sfp_eeprom@50 {
compatible = "accton,as4610_sfp4";
optoe@50 {
compatible = "optoe2";
reg = <0x50>;
label = "port52";
};
@@ -135,9 +135,10 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <4>;
sfp_eeprom@50 {
compatible = "accton,as4610_sfp5";
optoe@50 {
compatible = "optoe1";
reg = <0x50>;
label = "port53";
};
};
@@ -146,9 +147,10 @@
#address-cells = <1>;
#size-cells = <0>;
reg = <5>;
sfp_eeprom@50 {
compatible = "accton,as4610_sfp6";
optoe@50 {
compatible = "optoe1";
reg = <0x50>;
label = "port54";
};
};

View File

@@ -24,50 +24,31 @@
*
***********************************************************/
#include <onlp/platformi/sfpi.h>
#include <onlplib/file.h>
#include "platform_lib.h"
#include <arm_accton_as4610/arm_accton_as4610_config.h>
#include "arm_accton_as4610_log.h"
#define MAX_SFP_PATH 64
static char sfp_node_path[MAX_SFP_PATH] = {0};
#define FRONT_PORT_MUX_INDEX(port) (port-46)
#define PORT_EEPROM_FORMAT "/sys/bus/i2c/devices/%d-0050/eeprom"
#define MODULE_PRESENT_FORMAT "/sys/bus/i2c/devices/0-0030/module_present_%d"
#define MODULE_RXLOS_FORMAT "/sys/bus/i2c/devices/0-0030/module_rx_los_%d"
#define MODULE_TXFAULT_FORMAT "/sys/bus/i2c/devices/0-0030/module_tx_fault_%d"
#define MODULE_PRESENT_ALL_ATTR_CPLD "/sys/bus/i2c/devices/0-0030/module_present_all"
#define MODULE_RXLOS_ALL_ATTR_CPLD "/sys/bus/i2c/devices/0-0030/module_rx_los_all"
static int
sfp_node_read_int(char *node_path, int *value, int data_len)
static int front_port_bus_index(int port)
{
int ret = 0;
char buf[8];
*value = 0;
ret = deviceNodeReadString(node_path, buf, sizeof(buf), data_len);
if (ret == 0) {
*value = atoi(buf);
}
return ret;
return (platform_id == PLATFORM_ID_POWERPC_ACCTON_AS4610_30_R0) ?
(port - 22) : /* PLATFORM_ID_POWERPC_ACCTON_AS4610_30_R0 */
(port - 46) ; /* PLATFORM_ID_POWERPC_ACCTON_AS4610_54_R0 */
}
static char*
sfp_get_port_path_addr(int port, int addr, char *node_name)
static int front_port_to_cpld_port(int port)
{
int front_port_mux_id;
if(platform_id == PLATFORM_ID_POWERPC_ACCTON_AS4610_30_R0)
front_port_mux_id = port - 22;
else /*PLATFORM_ID_POWERPC_ACCTON_AS4610_54_R0*/
front_port_mux_id = port - 46;
sprintf(sfp_node_path, "/sys/bus/i2c/devices/%d-00%d/%s",
front_port_mux_id, addr, node_name);
return sfp_node_path;
}
static char*
sfp_get_port_path(int port, char *node_name)
{
return sfp_get_port_path_addr(port, 50, node_name);
return (platform_id == PLATFORM_ID_POWERPC_ACCTON_AS4610_30_R0) ?
(port - 23) : /* PLATFORM_ID_POWERPC_ACCTON_AS4610_30_R0 */
(port - 47) ; /* PLATFORM_ID_POWERPC_ACCTON_AS4610_54_R0 */
}
/************************************************************
@@ -115,9 +96,9 @@ onlp_sfpi_is_present(int port)
* Return < 0 if error.
*/
int present;
char* path = sfp_get_port_path(port, "sfp_is_present");
if (sfp_node_read_int(path, &present, 0) != 0) {
int cpld_port = front_port_to_cpld_port(port);
if (onlp_file_read_int(&present, MODULE_PRESENT_FORMAT, cpld_port) < 0) {
AIM_LOG_ERROR("Unable to read present status from port(%d)\r\n", port);
return ONLP_STATUS_E_INTERNAL;
}
@@ -129,7 +110,6 @@ int
onlp_sfpi_presence_bitmap_get(onlp_sfp_bitmap_t* dst)
{
uint32_t byte;
char* path;
FILE* fp;
int port;
@@ -140,18 +120,18 @@ onlp_sfpi_presence_bitmap_get(onlp_sfp_bitmap_t* dst)
else /*PLATFORM_ID_POWERPC_ACCTON_AS4610_54_R0*/
port = 48;
path = sfp_get_port_path(port, "sfp_is_present_all");
fp = fopen(path, "r");
/* Read present status of each port */
fp = fopen(MODULE_PRESENT_ALL_ATTR_CPLD, "r");
if(fp == NULL) {
AIM_LOG_ERROR("Unable to open the sfp_is_present_all device file.");
AIM_LOG_ERROR("Unable to open the module_present_all device file of CPLD.");
return ONLP_STATUS_E_INTERNAL;
}
int count = fscanf(fp, "%x", &byte);
fclose(fp);
if(count != 1) {
/* Likely a CPLD read timeout. */
AIM_LOG_ERROR("Unable to read all fields from the sfp_is_present_all device file.");
AIM_LOG_ERROR("Unable to read all fields the module_present_all device file of CPLD.");
return ONLP_STATUS_E_INTERNAL;
}
@@ -173,7 +153,6 @@ int
onlp_sfpi_rx_los_bitmap_get(onlp_sfp_bitmap_t* dst)
{
uint32_t byte;
char* path;
FILE* fp;
int port;
@@ -182,16 +161,18 @@ onlp_sfpi_rx_los_bitmap_get(onlp_sfp_bitmap_t* dst)
else /*PLATFORM_ID_POWERPC_ACCTON_AS4610_54_R0*/
port = 48;
path = sfp_get_port_path(port, "sfp_rx_los_all");
fp = fopen(path, "r");
/* Read present status of each port */
fp = fopen(MODULE_RXLOS_ALL_ATTR_CPLD, "r");
if(fp == NULL) {
AIM_LOG_ERROR("Unable to open the sfp_rx_los_all device file.");
AIM_LOG_ERROR("Unable to open the module_rx_los_all device file of CPLD.");
return ONLP_STATUS_E_INTERNAL;
}
int count = fscanf(fp, "%x", &byte);
fclose(fp);
if(count != 1) {
AIM_LOG_ERROR("Unable to read all fields from the sfp_rx_los_all device file.");
/* Likely a CPLD read timeout. */
AIM_LOG_ERROR("Unable to read all fields the module_rx_los_all device file of CPLD.");
return ONLP_STATUS_E_INTERNAL;
}
@@ -212,32 +193,51 @@ onlp_sfpi_rx_los_bitmap_get(onlp_sfp_bitmap_t* dst)
int
onlp_sfpi_eeprom_read(int port, uint8_t data[256])
{
char* path = sfp_get_port_path(port, "sfp_eeprom");
/*
* Read the SFP eeprom into data[]
*
* Return MISSING if SFP is missing.
* Return OK if eeprom is read
*/
int size = 0;
memset(data, 0, 256);
if (deviceNodeReadBinary(path, (char*)data, 256, 256) != 0) {
if(onlp_file_read(data, 256, &size, PORT_EEPROM_FORMAT, front_port_bus_index(port)) != ONLP_STATUS_OK) {
AIM_LOG_ERROR("Unable to read eeprom from port(%d)\r\n", port);
return ONLP_STATUS_E_INTERNAL;
}
if (size != 256) {
AIM_LOG_ERROR("Unable to read eeprom from port(%d), size is different!\r\n", port);
return ONLP_STATUS_E_INTERNAL;
}
return ONLP_STATUS_OK;
}
int
onlp_sfpi_dom_read(int port, uint8_t data[256])
{
char* path = sfp_get_port_path_addr(port, 51, "sfp_eeprom");
memset(data, 0, 256);
FILE* fp;
char file[64] = {0};
sprintf(file, PORT_EEPROM_FORMAT, front_port_bus_index(port));
fp = fopen(file, "r");
if(fp == NULL) {
AIM_LOG_ERROR("Unable to open the eeprom device file of port(%d)", port);
return ONLP_STATUS_E_INTERNAL;
}
if (deviceNodeReadBinary(path, (char*)data, 256, 256) != 0) {
AIM_LOG_INFO("Unable to read eeprom from port(%d)\r\n", port);
if (fseek(fp, 256, SEEK_CUR) != 0) {
fclose(fp);
AIM_LOG_ERROR("Unable to set the file position indicator of port(%d)", port);
return ONLP_STATUS_E_INTERNAL;
}
int ret = fread(data, 1, 256, fp);
fclose(fp);
if (ret != 256) {
AIM_LOG_ERROR("Unable to read the module_eeprom device file of port(%d)", port);
return ONLP_STATUS_E_INTERNAL;
}
@@ -247,45 +247,24 @@ onlp_sfpi_dom_read(int port, uint8_t data[256])
int
onlp_sfpi_control_set(int port, onlp_sfp_control_t control, int value)
{
int rv;
switch(control)
{
case ONLP_SFP_CONTROL_TX_DISABLE:
{
char* path = sfp_get_port_path(port, "sfp_tx_disable");
if (deviceNodeWriteInt(path, value, 0) != 0) {
AIM_LOG_ERROR("Unable to set tx_disable status to port(%d)\r\n", port);
rv = ONLP_STATUS_E_INTERNAL;
}
else {
rv = ONLP_STATUS_OK;
}
break;
}
default:
rv = ONLP_STATUS_E_UNSUPPORTED;
break;
}
return rv;
return ONLP_STATUS_E_UNSUPPORTED;
}
int
onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value)
{
int rv;
char* path = NULL;
int cpld_port = front_port_to_cpld_port(port);
if (cpld_port > 4) {
return ONLP_STATUS_E_UNSUPPORTED;
}
switch(control)
{
case ONLP_SFP_CONTROL_RX_LOS:
{
path = sfp_get_port_path(port, "sfp_rx_los");
if (sfp_node_read_int(path, value, 0) != 0) {
if (onlp_file_read_int(value, MODULE_RXLOS_FORMAT, cpld_port) < 0) {
AIM_LOG_ERROR("Unable to read rx_los status from port(%d)\r\n", port);
rv = ONLP_STATUS_E_INTERNAL;
}
@@ -297,9 +276,7 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value)
case ONLP_SFP_CONTROL_TX_FAULT:
{
path = sfp_get_port_path(port, "sfp_tx_fault");
if (sfp_node_read_int(path, value, 0) != 0) {
if (onlp_file_read_int(value, MODULE_TXFAULT_FORMAT, cpld_port) < 0) {
AIM_LOG_ERROR("Unable to read tx_fault status from port(%d)\r\n", port);
rv = ONLP_STATUS_E_INTERNAL;
}
@@ -309,20 +286,6 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value)
break;
}
case ONLP_SFP_CONTROL_TX_DISABLE:
{
path = sfp_get_port_path(port, "sfp_tx_disable");
if (sfp_node_read_int(path, value, 0) != 0) {
AIM_LOG_ERROR("Unable to read tx_disabled status from port(%d)\r\n", port);
rv = ONLP_STATUS_E_INTERNAL;
}
else {
rv = ONLP_STATUS_OK;
}
break;
}
default:
rv = ONLP_STATUS_E_UNSUPPORTED;
}
@@ -330,9 +293,9 @@ onlp_sfpi_control_get(int port, onlp_sfp_control_t control, int* value)
return rv;
}
int
onlp_sfpi_denit(void)
{
return ONLP_STATUS_OK;
}

View File

@@ -0,0 +1,627 @@
/*
* Copyright (C) Brandon Chuang <brandon_chuang@accton.com.tw>
*
* This module supports the accton cpld that hold the channel select
* mechanism for other i2c slave devices, such as SFP.
* This includes the:
* Accton as4610_54 CPLD
*
* Based on:
* pca954x.c from Kumar Gala <galak@kernel.crashing.org>
* Copyright (C) 2006
*
* Based on:
* pca954x.c from Ken Harrenstien
* Copyright (C) 2004 Google, Inc. (Ken Harrenstien)
*
* Based on:
* i2c-virtual_cb.c from Brian Kuschak <bkuschak@yahoo.com>
* and
* pca9540.c from Jean Delvare <khali@linux-fr.org>.
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/version.h>
#include <linux/stat.h>
#include <linux/hwmon-sysfs.h>
#include <linux/delay.h>
#define I2C_RW_RETRY_COUNT 10
#define I2C_RW_RETRY_INTERVAL 60 /* ms */
#define AS4610_CPLD_SLAVE_ADDR 0x30
#define AS4610_CPLD_PID_OFFSET 0x01 /* Product ID offset */
static LIST_HEAD(cpld_client_list);
static struct mutex list_lock;
struct cpld_client_node {
struct i2c_client *client;
struct list_head list;
};
enum cpld_type {
as4610_54_cpld
};
enum as4610_product_id_e {
PID_AS4610_30T,
PID_AS4610_30P,
PID_AS4610_54T,
PID_AS4610_54P,
PID_RESERVED,
PID_AS4610_54T_B,
PID_UNKNOWN
};
struct as4610_54_cpld_data {
enum cpld_type type;
struct device *hwmon_dev;
struct mutex update_lock;
};
static const struct i2c_device_id as4610_54_cpld_id[] = {
{ "as4610_54_cpld", as4610_54_cpld },
{ }
};
MODULE_DEVICE_TABLE(i2c, as4610_54_cpld_id);
#define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index
#define TRANSCEIVER_TXDISABLE_ATTR_ID(index) MODULE_TXDISABLE_##index
#define TRANSCEIVER_RXLOS_ATTR_ID(index) MODULE_RXLOS_##index
#define TRANSCEIVER_TXFAULT_ATTR_ID(index) MODULE_TXFAULT_##index
enum as4610_54_cpld1_sysfs_attributes {
CPLD_VERSION,
PRODUCT_ID,
ACCESS,
MODULE_PRESENT_ALL,
MODULE_RXLOS_ALL,
/* transceiver attributes */
TRANSCEIVER_PRESENT_ATTR_ID(1),
TRANSCEIVER_PRESENT_ATTR_ID(2),
TRANSCEIVER_PRESENT_ATTR_ID(3),
TRANSCEIVER_PRESENT_ATTR_ID(4),
TRANSCEIVER_PRESENT_ATTR_ID(5),
TRANSCEIVER_PRESENT_ATTR_ID(6),
TRANSCEIVER_TXDISABLE_ATTR_ID(1),
TRANSCEIVER_TXDISABLE_ATTR_ID(2),
TRANSCEIVER_TXDISABLE_ATTR_ID(3),
TRANSCEIVER_TXDISABLE_ATTR_ID(4),
TRANSCEIVER_RXLOS_ATTR_ID(1),
TRANSCEIVER_RXLOS_ATTR_ID(2),
TRANSCEIVER_RXLOS_ATTR_ID(3),
TRANSCEIVER_RXLOS_ATTR_ID(4),
TRANSCEIVER_TXFAULT_ATTR_ID(1),
TRANSCEIVER_TXFAULT_ATTR_ID(2),
TRANSCEIVER_TXFAULT_ATTR_ID(3),
TRANSCEIVER_TXFAULT_ATTR_ID(4),
};
/* sysfs attributes for hwmon
*/
static ssize_t show_status(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t show_present_all(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t access(struct device *dev, struct device_attribute *da,
const char *buf, size_t count);
static ssize_t show_version(struct device *dev, struct device_attribute *da,
char *buf);
static ssize_t show_product_id(struct device *dev, struct device_attribute *attr,
char *buf);
static int as4610_54_cpld_read_internal(struct i2c_client *client, u8 reg);
static int as4610_54_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value);
/* transceiver attributes */
#define DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(index) \
static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index)
#define DECLARE_TRANSCEIVER_PRESENT_ATTR(index) &sensor_dev_attr_module_present_##index.dev_attr.attr
#define DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \
static SENSOR_DEVICE_ATTR(module_rx_los_##index, S_IRUGO, show_status, NULL, MODULE_RXLOS_##index); \
static SENSOR_DEVICE_ATTR(module_tx_fault_##index, S_IRUGO, show_status, NULL, MODULE_TXFAULT_##index)
#define DECLARE_SFP_TRANSCEIVER_ATTR(index) \
&sensor_dev_attr_module_rx_los_##index.dev_attr.attr, \
&sensor_dev_attr_module_tx_fault_##index.dev_attr.attr
static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION);
static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS);
static SENSOR_DEVICE_ATTR(product_id, S_IRUGO, show_product_id, NULL, PRODUCT_ID);
/* transceiver attributes */
static SENSOR_DEVICE_ATTR(module_present_all, S_IRUGO, show_present_all, NULL, MODULE_PRESENT_ALL);
static SENSOR_DEVICE_ATTR(module_rx_los_all, S_IRUGO, show_rxlos_all, NULL, MODULE_RXLOS_ALL);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(1);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(2);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(3);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(4);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(5);
DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(6);
DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(1);
DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(2);
DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(3);
DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(4);
static struct attribute *as4610_54_cpld_attributes[] = {
&sensor_dev_attr_version.dev_attr.attr,
&sensor_dev_attr_access.dev_attr.attr,
&sensor_dev_attr_product_id.dev_attr.attr,
/* transceiver attributes */
&sensor_dev_attr_module_present_all.dev_attr.attr,
&sensor_dev_attr_module_rx_los_all.dev_attr.attr,
DECLARE_TRANSCEIVER_PRESENT_ATTR(1),
DECLARE_TRANSCEIVER_PRESENT_ATTR(2),
DECLARE_TRANSCEIVER_PRESENT_ATTR(3),
DECLARE_TRANSCEIVER_PRESENT_ATTR(4),
DECLARE_TRANSCEIVER_PRESENT_ATTR(5),
DECLARE_TRANSCEIVER_PRESENT_ATTR(6),
DECLARE_SFP_TRANSCEIVER_ATTR(1),
DECLARE_SFP_TRANSCEIVER_ATTR(2),
DECLARE_SFP_TRANSCEIVER_ATTR(3),
DECLARE_SFP_TRANSCEIVER_ATTR(4),
NULL
};
static const struct attribute_group as4610_54_cpld_group = {
.attrs = as4610_54_cpld_attributes,
};
static ssize_t show_present_all(struct device *dev, struct device_attribute *da,
char *buf)
{
int i, status, present = 0;
u8 regs[] = {0x2, 0x3, 0x21};
struct i2c_client *client = to_i2c_client(dev);
struct as4610_54_cpld_data *data = i2c_get_clientdata(client);
mutex_lock(&data->update_lock);
for (i = 0; i < ARRAY_SIZE(regs); i++) {
status = as4610_54_cpld_read_internal(client, regs[i]);
if (status < 0) {
goto exit;
}
switch (i) {
case 0:
present |= (status & BIT(6)) >> 6; /* port 25/49 */
present |= (status & BIT(2)) >> 1; /* port 26/50 */
break;
case 1:
present |= (status & BIT(6)) >> 4; /* port 27/51 */
present |= (status & BIT(2)) << 1; /* port 28/52 */
break;
case 2:
present |= (status & BIT(0)) << 4; /* port 29/53 */
present |= (status & BIT(4)) << 1; /* port 30/54 */
break;
default:
break;
}
}
mutex_unlock(&data->update_lock);
return sprintf(buf, "%.2x\n", present);
exit:
mutex_unlock(&data->update_lock);
return status;
}
static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da,
char *buf)
{
int i, status, rx_los = 0;
u8 regs[] = {0x2, 0x3};
struct i2c_client *client = to_i2c_client(dev);
struct as4610_54_cpld_data *data = i2c_get_clientdata(client);
mutex_lock(&data->update_lock);
for (i = 0; i < ARRAY_SIZE(regs); i++) {
status = as4610_54_cpld_read_internal(client, regs[i]);
if (status < 0) {
goto exit;
}
switch (i) {
case 0:
rx_los |= (status & BIT(4)) >> 4; /* port 25/49 rx_los */
rx_los |= (status & BIT(0)) << 1; /* port 26/50 rx_los */
break;
case 1:
rx_los |= (status & BIT(4)) >> 2; /* port 27/51 rx_los */
rx_los |= (status & BIT(0)) << 3; /* port 28/52 rx_los */
break;
default:
break;
}
}
mutex_unlock(&data->update_lock);
/* Return values 25/49 -> 28/52 in order */
return sprintf(buf, "%.2x\n", rx_los);
exit:
mutex_unlock(&data->update_lock);
return status;
}
static ssize_t show_status(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
struct i2c_client *client = to_i2c_client(dev);
struct as4610_54_cpld_data *data = i2c_get_clientdata(client);
int status = 0;
u8 reg = 0, mask = 0;
switch (attr->index) {
case MODULE_PRESENT_1:
reg = 0x2;
mask = 0x40;
break;
case MODULE_PRESENT_2:
reg = 0x2;
mask = 0x4;
break;
case MODULE_PRESENT_3:
reg = 0x3;
mask = 0x40;
break;
case MODULE_PRESENT_4:
reg = 0x3;
mask = 0x4;
break;
case MODULE_PRESENT_5:
reg = 0x21;
mask = 0x1;
break;
case MODULE_PRESENT_6:
reg = 0x21;
mask = 0x10;
break;
case MODULE_TXFAULT_1:
reg = 0x2;
mask = 0x20;
break;
case MODULE_TXFAULT_2:
reg = 0x2;
mask = 0x2;
break;
case MODULE_TXFAULT_3:
reg = 0x3;
mask = 0x20;
break;
case MODULE_TXFAULT_4:
reg = 0x3;
mask = 0x2;
break;
case MODULE_RXLOS_1:
reg = 0x2;
mask = 0x10;
break;
case MODULE_RXLOS_2:
reg = 0x2;
mask = 0x1;
break;
case MODULE_RXLOS_3:
reg = 0x3;
mask = 0x10;
break;
case MODULE_RXLOS_4:
reg = 0x3;
mask = 0x1;
break;
default:
return 0;
}
mutex_lock(&data->update_lock);
status = as4610_54_cpld_read_internal(client, reg);
if (unlikely(status < 0)) {
goto exit;
}
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", !!(status & mask));
exit:
mutex_unlock(&data->update_lock);
return status;
}
static ssize_t access(struct device *dev, struct device_attribute *da,
const char *buf, size_t count)
{
int status;
u32 addr, val;
struct i2c_client *client = to_i2c_client(dev);
struct as4610_54_cpld_data *data = i2c_get_clientdata(client);
if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) {
return -EINVAL;
}
if (addr > 0xFF || val > 0xFF) {
return -EINVAL;
}
mutex_lock(&data->update_lock);
status = as4610_54_cpld_write_internal(client, addr, val);
if (unlikely(status < 0)) {
goto exit;
}
mutex_unlock(&data->update_lock);
return count;
exit:
mutex_unlock(&data->update_lock);
return status;
}
static void as4610_54_cpld_add_client(struct i2c_client *client)
{
struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL);
if (!node) {
dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr);
return;
}
node->client = client;
mutex_lock(&list_lock);
list_add(&node->list, &cpld_client_list);
mutex_unlock(&list_lock);
}
static void as4610_54_cpld_remove_client(struct i2c_client *client)
{
struct list_head *list_node = NULL;
struct cpld_client_node *cpld_node = NULL;
int found = 0;
mutex_lock(&list_lock);
list_for_each(list_node, &cpld_client_list)
{
cpld_node = list_entry(list_node, struct cpld_client_node, list);
if (cpld_node->client == client) {
found = 1;
break;
}
}
if (found) {
list_del(list_node);
kfree(cpld_node);
}
mutex_unlock(&list_lock);
}
static ssize_t show_product_id(struct device *dev, struct device_attribute *attr, char *buf)
{
int val = 0;
struct i2c_client *client = to_i2c_client(dev);
val = i2c_smbus_read_byte_data(client, 0x1);
if (val < 0) {
dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", client->addr, val);
}
return sprintf(buf, "%d\n", (val & 0xF));
}
static ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf)
{
int val = 0;
struct i2c_client *client = to_i2c_client(dev);
val = i2c_smbus_read_byte_data(client, 0xB);
if (val < 0) {
dev_dbg(&client->dev, "cpld(0x%x) reg(0xB) err %d\n", client->addr, val);
}
return sprintf(buf, "%d", val);
}
/* I2C init/probing/exit functions */
static int as4610_54_cpld_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
struct as4610_54_cpld_data *data;
int ret = -ENODEV;
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
goto exit;
data = kzalloc(sizeof(struct as4610_54_cpld_data), GFP_KERNEL);
if (!data) {
ret = -ENOMEM;
goto exit;
}
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
data->type = id->driver_data;
/* Bring QSFPs out of reset */
as4610_54_cpld_write_internal(client, 0x2A, 0);
ret = sysfs_create_group(&client->dev.kobj, &as4610_54_cpld_group);
if (ret) {
goto exit_free;
}
as4610_54_cpld_add_client(client);
return 0;
exit_free:
kfree(data);
exit:
return ret;
}
static int as4610_54_cpld_remove(struct i2c_client *client)
{
struct as4610_54_cpld_data *data = i2c_get_clientdata(client);
as4610_54_cpld_remove_client(client);
/* Remove sysfs hooks */
sysfs_remove_group(&client->dev.kobj, &as4610_54_cpld_group);
kfree(data);
return 0;
}
static int as4610_54_cpld_read_internal(struct i2c_client *client, u8 reg)
{
int status = 0, retry = I2C_RW_RETRY_COUNT;
while (retry) {
status = i2c_smbus_read_byte_data(client, reg);
if (unlikely(status < 0)) {
msleep(I2C_RW_RETRY_INTERVAL);
retry--;
continue;
}
break;
}
return status;
}
static int as4610_54_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value)
{
int status = 0, retry = I2C_RW_RETRY_COUNT;
while (retry) {
status = i2c_smbus_write_byte_data(client, reg, value);
if (unlikely(status < 0)) {
msleep(I2C_RW_RETRY_INTERVAL);
retry--;
continue;
}
break;
}
return status;
}
int as4610_54_cpld_read(unsigned short cpld_addr, u8 reg)
{
struct list_head *list_node = NULL;
struct cpld_client_node *cpld_node = NULL;
int ret = -EPERM;
mutex_lock(&list_lock);
list_for_each(list_node, &cpld_client_list)
{
cpld_node = list_entry(list_node, struct cpld_client_node, list);
if (cpld_node->client->addr == cpld_addr) {
ret = as4610_54_cpld_read_internal(cpld_node->client, reg);
break;
}
}
mutex_unlock(&list_lock);
return ret;
}
EXPORT_SYMBOL(as4610_54_cpld_read);
int as4610_54_cpld_write(unsigned short cpld_addr, u8 reg, u8 value)
{
struct list_head *list_node = NULL;
struct cpld_client_node *cpld_node = NULL;
int ret = -EIO;
mutex_lock(&list_lock);
list_for_each(list_node, &cpld_client_list)
{
cpld_node = list_entry(list_node, struct cpld_client_node, list);
if (cpld_node->client->addr == cpld_addr) {
ret = as4610_54_cpld_write_internal(cpld_node->client, reg, value);
break;
}
}
mutex_unlock(&list_lock);
return ret;
}
EXPORT_SYMBOL(as4610_54_cpld_write);
int as4610_product_id(void)
{
int pid = as4610_54_cpld_read(AS4610_CPLD_SLAVE_ADDR, AS4610_CPLD_PID_OFFSET);
pid &= 0xF;
if (pid < PID_AS4610_30T || pid > PID_AS4610_54T_B || pid == PID_RESERVED) {
return PID_UNKNOWN;
}
return pid;
}
EXPORT_SYMBOL(as4610_product_id);
int as4610_is_poe_system(void)
{
int pid = as4610_product_id();
return (pid == PID_AS4610_30P || pid == PID_AS4610_54P);
}
EXPORT_SYMBOL(as4610_is_poe_system);
static struct i2c_driver as4610_54_cpld_driver = {
.driver = {
.name = "as4610_54_cpld",
.owner = THIS_MODULE,
},
.probe = as4610_54_cpld_probe,
.remove = as4610_54_cpld_remove,
.id_table = as4610_54_cpld_id,
};
static int __init as4610_54_cpld_init(void)
{
mutex_init(&list_lock);
return i2c_add_driver(&as4610_54_cpld_driver);
}
static void __exit as4610_54_cpld_exit(void)
{
i2c_del_driver(&as4610_54_cpld_driver);
}
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("Accton I2C CPLD driver");
MODULE_LICENSE("GPL");
module_init(as4610_54_cpld_init);
module_exit(as4610_54_cpld_exit);

View File

@@ -29,15 +29,16 @@
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include "accton_i2c_cpld.h"
#define DRVNAME "as4610_fan"
static struct as4610_fan_data *as4610_fan_update_device(struct device *dev);
static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, char *buf);
static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da,
const char *buf, size_t count);
extern int as4610_54_cpld_read(unsigned short cpld_addr, u8 reg);
extern int as4610_54_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
extern int as4610_product_id(void);
/* fan related data, the index should match sysfs_fan_attributes
*/
@@ -74,6 +75,16 @@ enum sysfs_fan_attributes {
FAN2_FAULT
};
enum as4610_product_id_e {
PID_AS4610_30T,
PID_AS4610_30P,
PID_AS4610_54T,
PID_AS4610_54P,
PID_RESERVED,
PID_AS4610_54T_B,
PID_UNKNOWN
};
/* Define attributes
*/
#define DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(index) \
@@ -113,12 +124,12 @@ static struct attribute *as4610_fan_attributes[] = {
static int as4610_fan_read_value(u8 reg)
{
return accton_i2c_cpld_read(AS4610_CPLD_SLAVE_ADDR, reg);
return as4610_54_cpld_read(0x30, reg);
}
static int as4610_fan_write_value(u8 reg, u8 value)
{
return accton_i2c_cpld_write(AS4610_CPLD_SLAVE_ADDR, reg, value);
return as4610_54_cpld_write(0x30, reg, value);
}
/* fan utility functions
@@ -290,6 +301,27 @@ static struct platform_driver as4610_fan_driver = {
},
};
static int as4610_number_of_system_fan(void)
{
int nFan = 0;
int pid = as4610_product_id();
switch (pid) {
case PID_AS4610_30P:
case PID_AS4610_54P:
nFan = 1;
break;
case PID_AS4610_54T_B:
nFan = 2;
break;
default:
nFan = 0;
break;
}
return nFan;
}
static int __init as4610_fan_init(void)
{
int ret;
@@ -342,3 +374,4 @@ module_exit(as4610_fan_exit);
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("as4610_fan driver");
MODULE_LICENSE("GPL");

View File

@@ -29,10 +29,10 @@
#include <linux/leds.h>
#include <linux/slab.h>
#include <linux/bitops.h>
#include "accton_i2c_cpld.h"
//extern void led_classdev_unregister(struct led_classdev *led_cdev);
//extern int led_classdev_register(struct device *parent, struct led_classdev *led_cdev);
extern int as4610_54_cpld_read (unsigned short cpld_addr, u8 reg);
extern int as4610_54_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
extern int as4610_product_id(void);
#define DRVNAME "as4610_led"
@@ -93,6 +93,16 @@ static const u8 led_reg[] = {
0x33, /* STK1-2/Fan/PoE/Alarm LED */
};
enum as4610_product_id_e {
PID_AS4610_30T,
PID_AS4610_30P,
PID_AS4610_54T,
PID_AS4610_54P,
PID_RESERVED,
PID_AS4610_54T_B,
PID_UNKNOWN
};
enum led_type {
LED_TYPE_SYS,
LED_TYPE_PRI,
@@ -145,12 +155,12 @@ enum led_light_mode {
static int as4610_led_read_value(u8 reg)
{
return accton_i2c_cpld_read(0x30, reg);
return as4610_54_cpld_read(0x30, reg);
}
static int as4610_led_write_value(u8 reg, u8 value)
{
return accton_i2c_cpld_write(0x30, reg, value);
return as4610_54_cpld_write(0x30, reg, value);
}
static void as4610_led_update(void)
@@ -672,3 +682,4 @@ module_exit(as4610_led_exit);
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("as4610_led driver");
MODULE_LICENSE("GPL");

View File

@@ -37,7 +37,7 @@
static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf);
static ssize_t show_model_name(struct device *dev, struct device_attribute *da, char *buf);
static int as4610_psu_read_data(struct i2c_client *client, u8 command, u8 *data,int data_len);
extern int accton_i2c_cpld_read(unsigned short cpld_addr, u8 reg);
extern int as4610_54_cpld_read(unsigned short cpld_addr, u8 reg);
/* Addresses scanned
*/
@@ -227,7 +227,7 @@ static struct as4610_psu_data *as4610_psu_update_device(struct device *dev)
dev_dbg(&client->dev, "Starting as4610 update\n");
/* Read psu status */
status = accton_i2c_cpld_read(0x30, 0x11);
status = as4610_54_cpld_read(0x30, 0x11);
if (status < 0) {
dev_dbg(&client->dev, "cpld reg 0x30 err %d\n", status);

View File

@@ -1,284 +0,0 @@
/*
* A hwmon driver for the accton_i2c_cpld
*
* Copyright (C) 2013 Accton Technology Corporation.
* Brandon Chuang <brandon_chuang@accton.com.tw>
*
* Based on ad7414.c
* Copyright 2006 Stefan Roese <sr at denx.de>, DENX Software Engineering
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/dmi.h>
#include "accton_i2c_cpld.h"
static LIST_HEAD(cpld_client_list);
static struct mutex list_lock;
enum cpld_device_id {
as4610_30_cpld,
as4610_54_cpld
};
struct cpld_data {
enum cpld_device_id id;
};
struct cpld_client_node {
struct i2c_client *client;
struct list_head list;
};
/* Addresses scanned for accton_i2c_cpld
*/
static const unsigned short normal_i2c[] = { 0x31, 0x35, 0x60, 0x61, 0x62, I2C_CLIENT_END };
static u8 cpld_product_id_offset(enum cpld_device_id id)
{
switch (id) {
case as4610_30_cpld:
case as4610_54_cpld:
return 0x1;
}
return 0;
}
static int cpld_has_product_id(const struct i2c_device_id *dev_id)
{
return (dev_id->driver_data == as4610_30_cpld) ||
(dev_id->driver_data == as4610_54_cpld);
}
static ssize_t show_cpld_product_id(struct device *dev, struct device_attribute *attr, char *buf)
{
int val = 0;
struct i2c_client *client = to_i2c_client(dev);
struct cpld_data *data = i2c_get_clientdata(client);
val = i2c_smbus_read_byte_data(client, cpld_product_id_offset(data->id));
if (val < 0) {
dev_dbg(&client->dev, "cpld(0x%x) reg(0x%x) err %d\n", client->addr, cpld_product_id_offset(data->id), val);
}
return sprintf(buf, "%d\n", (val & 0xF));
}
static u8 cpld_version_offset(enum cpld_device_id id)
{
switch (id) {
case as4610_30_cpld:
case as4610_54_cpld:
return 0xB;
}
return 0;
}
static ssize_t show_cpld_version(struct device *dev, struct device_attribute *attr, char *buf)
{
int val = 0;
struct i2c_client *client = to_i2c_client(dev);
struct cpld_data *data = i2c_get_clientdata(client);
val = i2c_smbus_read_byte_data(client, cpld_version_offset(data->id));
if (val < 0) {
dev_dbg(&client->dev, "cpld(0x%x) reg(0xB) err %d\n", client->addr, val);
}
return sprintf(buf, "%d\n", val);
}
static void accton_i2c_cpld_add_client(struct i2c_client *client, enum cpld_device_id id)
{
struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL);
struct cpld_data *data = kzalloc(sizeof(struct cpld_data), GFP_KERNEL);
if (!node) {
dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr);
return;
}
if (!data) {
dev_dbg(&client->dev, "Can't allocate cpld_client_data (0x%x)\n", client->addr);
return;
}
data->id = id;
i2c_set_clientdata(client, data);
node->client = client;
mutex_lock(&list_lock);
list_add(&node->list, &cpld_client_list);
mutex_unlock(&list_lock);
}
static void accton_i2c_cpld_remove_client(struct i2c_client *client)
{
struct list_head *list_node = NULL;
struct cpld_client_node *cpld_node = NULL;
int found = 0;
mutex_lock(&list_lock);
list_for_each(list_node, &cpld_client_list)
{
cpld_node = list_entry(list_node, struct cpld_client_node, list);
if (cpld_node->client == client) {
found = 1;
break;
}
}
if (found) {
list_del(list_node);
kfree(cpld_node);
}
mutex_unlock(&list_lock);
}
static struct device_attribute ver = __ATTR(version, 0600, show_cpld_version, NULL);
static struct device_attribute pid = __ATTR(product_id, 0600, show_cpld_product_id, NULL);
static int accton_i2c_cpld_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
{
int status;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_dbg(&client->dev, "i2c_check_functionality failed (0x%x)\n", client->addr);
status = -EIO;
goto exit;
}
status = sysfs_create_file(&client->dev.kobj, &ver.attr);
if (status) {
goto exit;
}
if (cpld_has_product_id(dev_id)) {
status = sysfs_create_file(&client->dev.kobj, &pid.attr);
if (status) {
goto exit;
}
}
dev_info(&client->dev, "chip found\n");
accton_i2c_cpld_add_client(client, (enum cpld_device_id)dev_id->driver_data);
return 0;
exit:
return status;
}
static int accton_i2c_cpld_remove(struct i2c_client *client)
{
sysfs_remove_file(&client->dev.kobj, &ver.attr);
accton_i2c_cpld_remove_client(client);
return 0;
}
static const struct i2c_device_id accton_i2c_cpld_id[] = {
{ "as4610_30_cpld", as4610_30_cpld },
{ "as4610_54_cpld", as4610_54_cpld },
{ /* LIST END */}
};
MODULE_DEVICE_TABLE(i2c, accton_i2c_cpld_id);
static struct i2c_driver accton_i2c_cpld_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "accton_i2c_cpld",
},
.probe = accton_i2c_cpld_probe,
.remove = accton_i2c_cpld_remove,
.id_table = accton_i2c_cpld_id,
.address_list = normal_i2c,
};
int accton_i2c_cpld_read(unsigned short cpld_addr, u8 reg)
{
struct list_head *list_node = NULL;
struct cpld_client_node *cpld_node = NULL;
int ret = -EPERM;
mutex_lock(&list_lock);
list_for_each(list_node, &cpld_client_list)
{
cpld_node = list_entry(list_node, struct cpld_client_node, list);
if (cpld_node->client->addr == cpld_addr) {
ret = i2c_smbus_read_byte_data(cpld_node->client, reg);
break;
}
}
mutex_unlock(&list_lock);
return ret;
}
EXPORT_SYMBOL(accton_i2c_cpld_read);
int accton_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value)
{
struct list_head *list_node = NULL;
struct cpld_client_node *cpld_node = NULL;
int ret = -EIO;
mutex_lock(&list_lock);
list_for_each(list_node, &cpld_client_list)
{
cpld_node = list_entry(list_node, struct cpld_client_node, list);
if (cpld_node->client->addr == cpld_addr) {
ret = i2c_smbus_write_byte_data(cpld_node->client, reg, value);
break;
}
}
mutex_unlock(&list_lock);
return ret;
}
EXPORT_SYMBOL(accton_i2c_cpld_write);
static int __init accton_i2c_cpld_init(void)
{
mutex_init(&list_lock);
return i2c_add_driver(&accton_i2c_cpld_driver);
}
static void __exit accton_i2c_cpld_exit(void)
{
i2c_del_driver(&accton_i2c_cpld_driver);
}
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
MODULE_DESCRIPTION("accton_i2c_cpld driver");
MODULE_LICENSE("GPL");
module_init(accton_i2c_cpld_init);
module_exit(accton_i2c_cpld_exit);

View File

@@ -1,76 +0,0 @@
/*
* A hwmon driver for the accton_i2c_cpld
*
* Copyright (C) 2016 Accton Technology Corporation.
* Brandon Chuang <brandon_chuang@accton.com.tw>
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
extern int accton_i2c_cpld_read(unsigned short cpld_addr, u8 reg);
extern int accton_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
#define AS4610_CPLD_SLAVE_ADDR 0x30
#define AS4610_CPLD_PID_OFFSET 0x01 /* Product ID offset */
enum as4610_product_id_e {
PID_AS4610_30T,
PID_AS4610_30P,
PID_AS4610_54T,
PID_AS4610_54P,
PID_RESERVED,
PID_AS4610_54T_B,
PID_UNKNOWN
};
static inline int as4610_product_id(void)
{
int pid = accton_i2c_cpld_read(AS4610_CPLD_SLAVE_ADDR, AS4610_CPLD_PID_OFFSET);
pid &= 0xF;
if (pid < PID_AS4610_30T || pid > PID_AS4610_54T_B || pid == PID_RESERVED) {
return PID_UNKNOWN;
}
return pid;
}
static inline int as4610_is_poe_system(void)
{
int pid = as4610_product_id();
return (pid == PID_AS4610_30P || pid == PID_AS4610_54P);
}
static inline int as4610_number_of_system_fan(void)
{
int nFan = 0;
int pid = as4610_product_id();
switch (pid) {
case PID_AS4610_30P:
case PID_AS4610_54P:
nFan = 1;
break;
case PID_AS4610_54T_B:
nFan = 2;
break;
default:
nFan = 0;
break;
}
return nFan;
}