mirror of
https://github.com/Telecominfraproject/OpenNetworkLinux.git
synced 2026-01-09 16:51:30 +00:00
AS4610-54 Kernel Module builds. The source should be migrated to common for 54/30 after all of this is sorted.
This commit is contained in:
@@ -1 +1 @@
|
||||
!include $ONL_TEMPLATES/no-platform-modules.yml ARCH=armel VENDOR=accton BASENAME=arm-accton-as4610-54
|
||||
!include $ONL_TEMPLATES/platform-modules.yml ARCH=armel VENDOR=accton BASENAME=arm-accton-as4610-54 KERNELS="onl-kernel-4.14-lts-arm-iproc-all:armel"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
lib
|
||||
@@ -0,0 +1,7 @@
|
||||
KERNELS := onl-kernel-4.14-lts-arm-iproc-all:armel
|
||||
KMODULES := $(wildcard *.c)
|
||||
KINCLUDES := $(wildcard *.h)
|
||||
VENDOR := accton
|
||||
BASENAME := arm-accton-as4610-54
|
||||
ARCH := arm
|
||||
include $(ONL)/make/kmodule.mk
|
||||
@@ -0,0 +1,344 @@
|
||||
/*
|
||||
* A hwmon driver for the Accton as4610 fan
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#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);
|
||||
|
||||
/* fan related data, the index should match sysfs_fan_attributes
|
||||
*/
|
||||
static const u8 fan_reg[] = {
|
||||
0x2B, /* fan PWM(for all fan) */
|
||||
0x2D, /* fan 1 speed(rpm) */
|
||||
0x2C, /* fan 2 speed(rpm) */
|
||||
0x11, /* fan1-2 operating status */
|
||||
};
|
||||
|
||||
static struct as4610_fan_data *fan_data = NULL;
|
||||
|
||||
/* Each client has this additional data */
|
||||
struct as4610_fan_data {
|
||||
struct platform_device *pdev;
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* != 0 if registers are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
u8 reg_val[ARRAY_SIZE(fan_reg)]; /* Register value */
|
||||
};
|
||||
|
||||
enum fan_id {
|
||||
FAN1_ID,
|
||||
FAN2_ID
|
||||
};
|
||||
|
||||
enum sysfs_fan_attributes {
|
||||
FAN_DUTY_CYCLE_PERCENTAGE, /* Only one CPLD register to control duty cycle for all fans */
|
||||
FAN1_SPEED_RPM,
|
||||
FAN2_SPEED_RPM,
|
||||
FAN_FAULT,
|
||||
FAN1_FAULT,
|
||||
FAN2_FAULT
|
||||
};
|
||||
|
||||
/* Define attributes
|
||||
*/
|
||||
#define DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(index) \
|
||||
static SENSOR_DEVICE_ATTR(fan##index##_fault, S_IRUGO, fan_show_value, NULL, FAN##index##_FAULT)
|
||||
#define DECLARE_FAN_FAULT_ATTR(index) &sensor_dev_attr_fan##index##_fault.dev_attr.attr
|
||||
|
||||
#define DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(index) \
|
||||
static SENSOR_DEVICE_ATTR(fan##index##_duty_cycle_percentage, S_IWUSR | S_IRUGO, fan_show_value, set_duty_cycle, FAN##index##_DUTY_CYCLE_PERCENTAGE)
|
||||
#define DECLARE_FAN_DUTY_CYCLE_ATTR(index) &sensor_dev_attr_fan##index##_duty_cycle_percentage.dev_attr.attr
|
||||
|
||||
#define DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(index) \
|
||||
static SENSOR_DEVICE_ATTR(fan##index##_speed_rpm, S_IRUGO, fan_show_value, NULL, FAN##index##_SPEED_RPM)
|
||||
#define DECLARE_FAN_SPEED_RPM_ATTR(index) &sensor_dev_attr_fan##index##_speed_rpm.dev_attr.attr
|
||||
|
||||
/* fan fault attributes in this platform */
|
||||
DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(1);
|
||||
DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(2);
|
||||
/* fan speed(rpm) attributes in this platform */
|
||||
DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(1);
|
||||
DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(2);
|
||||
/* 1 fan duty cycle attribute in this platform */
|
||||
DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR();
|
||||
|
||||
static struct attribute *as4610_fan_attributes[] = {
|
||||
/* fan related attributes */
|
||||
DECLARE_FAN_FAULT_ATTR(1),
|
||||
DECLARE_FAN_FAULT_ATTR(2),
|
||||
DECLARE_FAN_SPEED_RPM_ATTR(1),
|
||||
DECLARE_FAN_SPEED_RPM_ATTR(2),
|
||||
DECLARE_FAN_DUTY_CYCLE_ATTR(),
|
||||
NULL
|
||||
};
|
||||
|
||||
#define FAN_DUTY_CYCLE_REG_MASK 0xF
|
||||
#define FAN_MAX_DUTY_CYCLE 100
|
||||
#define FAN_REG_VAL_TO_SPEED_RPM_STEP 100
|
||||
|
||||
static int as4610_fan_read_value(u8 reg)
|
||||
{
|
||||
return accton_i2c_cpld_read(AS4610_CPLD_SLAVE_ADDR, reg);
|
||||
}
|
||||
|
||||
static int as4610_fan_write_value(u8 reg, u8 value)
|
||||
{
|
||||
return accton_i2c_cpld_write(AS4610_CPLD_SLAVE_ADDR, reg, value);
|
||||
}
|
||||
|
||||
/* fan utility functions
|
||||
*/
|
||||
static u32 reg_val_to_duty_cycle(u8 reg_val)
|
||||
{
|
||||
reg_val &= FAN_DUTY_CYCLE_REG_MASK;
|
||||
return (u32)((reg_val * 125 + 5)/10);
|
||||
}
|
||||
|
||||
static u8 duty_cycle_to_reg_val(u8 duty_cycle)
|
||||
{
|
||||
return ((u32)duty_cycle * 10 / 125);
|
||||
}
|
||||
|
||||
static u32 reg_val_to_speed_rpm(u8 reg_val)
|
||||
{
|
||||
/* Count Frequency is 1.515KHz= 0.66ms
|
||||
* Count Period = 400 cycle = 400*0.66ms = 264ms
|
||||
* R.P.M value = read value x3.79*60/2
|
||||
* 3.79 = 1000ms/264ms
|
||||
* 60 = 1min =60s
|
||||
* 2 = 1 rotation of fan has two pulses.
|
||||
*/
|
||||
return (u32)reg_val * 379 * 60 / 2 / 100;
|
||||
}
|
||||
|
||||
static u8 is_fan_fault(struct as4610_fan_data *data, enum fan_id id)
|
||||
{
|
||||
u8 mask = (id == FAN1_ID) ? 0x20 : 0x10;
|
||||
|
||||
return !(data->reg_val[FAN_FAULT] & mask);
|
||||
}
|
||||
|
||||
static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int error, value;
|
||||
|
||||
error = kstrtoint(buf, 10, &value);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (value < 0 || value > FAN_MAX_DUTY_CYCLE)
|
||||
return -EINVAL;
|
||||
|
||||
as4610_fan_write_value(fan_reg[FAN_DUTY_CYCLE_PERCENTAGE], duty_cycle_to_reg_val(value));
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t fan_show_value(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct as4610_fan_data *data = as4610_fan_update_device(dev);
|
||||
ssize_t ret = 0;
|
||||
|
||||
if (data->valid) {
|
||||
switch (attr->index) {
|
||||
case FAN_DUTY_CYCLE_PERCENTAGE:
|
||||
{
|
||||
u32 duty_cycle = reg_val_to_duty_cycle(data->reg_val[attr->index]);
|
||||
ret = sprintf(buf, "%u\n", duty_cycle);
|
||||
break;
|
||||
}
|
||||
case FAN1_SPEED_RPM:
|
||||
case FAN2_SPEED_RPM:
|
||||
ret = sprintf(buf, "%u\n", reg_val_to_speed_rpm(data->reg_val[attr->index]));
|
||||
break;
|
||||
case FAN1_FAULT:
|
||||
case FAN2_FAULT:
|
||||
ret = sprintf(buf, "%d\n", is_fan_fault(data, attr->index - FAN1_FAULT));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct attribute_group as4610_fan_group = {
|
||||
.attrs = as4610_fan_attributes,
|
||||
};
|
||||
|
||||
static struct as4610_fan_data *as4610_fan_update_device(struct device *dev)
|
||||
{
|
||||
mutex_lock(&fan_data->update_lock);
|
||||
|
||||
if (time_after(jiffies, fan_data->last_updated + HZ + HZ / 2) ||
|
||||
!fan_data->valid) {
|
||||
int i;
|
||||
|
||||
dev_dbg(fan_data->hwmon_dev, "Starting as4610_fan update\n");
|
||||
fan_data->valid = 0;
|
||||
|
||||
/* Update fan data
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(fan_data->reg_val); i++) {
|
||||
int status = as4610_fan_read_value(fan_reg[i]);
|
||||
|
||||
if (status < 0) {
|
||||
fan_data->valid = 0;
|
||||
mutex_unlock(&fan_data->update_lock);
|
||||
dev_dbg(fan_data->hwmon_dev, "reg %d, err %d\n", fan_reg[i], status);
|
||||
return fan_data;
|
||||
}
|
||||
else {
|
||||
fan_data->reg_val[i] = status;
|
||||
}
|
||||
}
|
||||
|
||||
fan_data->last_updated = jiffies;
|
||||
fan_data->valid = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&fan_data->update_lock);
|
||||
|
||||
return fan_data;
|
||||
}
|
||||
|
||||
static int as4610_fan_probe(struct platform_device *pdev)
|
||||
{
|
||||
int status = -1;
|
||||
|
||||
/* Register sysfs hooks */
|
||||
status = sysfs_create_group(&pdev->dev.kobj, &as4610_fan_group);
|
||||
if (status) {
|
||||
goto exit;
|
||||
|
||||
}
|
||||
|
||||
fan_data->hwmon_dev = hwmon_device_register(&pdev->dev);
|
||||
if (IS_ERR(fan_data->hwmon_dev)) {
|
||||
status = PTR_ERR(fan_data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "accton_as4610_fan\n");
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&pdev->dev.kobj, &as4610_fan_group);
|
||||
exit:
|
||||
return status;
|
||||
}
|
||||
|
||||
static int as4610_fan_remove(struct platform_device *pdev)
|
||||
{
|
||||
hwmon_device_unregister(fan_data->hwmon_dev);
|
||||
sysfs_remove_group(&pdev->dev.kobj, &as4610_fan_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id as4610_fan_id[] = {
|
||||
{ "as4610_fan", 0 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, as4610_fan_id);
|
||||
|
||||
static struct platform_driver as4610_fan_driver = {
|
||||
.probe = as4610_fan_probe,
|
||||
.remove = as4610_fan_remove,
|
||||
.driver = {
|
||||
.name = DRVNAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init as4610_fan_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (as4610_number_of_system_fan() == 0) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = platform_driver_register(&as4610_fan_driver);
|
||||
if (ret < 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
fan_data = kzalloc(sizeof(struct as4610_fan_data), GFP_KERNEL);
|
||||
if (!fan_data) {
|
||||
ret = -ENOMEM;
|
||||
platform_driver_unregister(&as4610_fan_driver);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mutex_init(&fan_data->update_lock);
|
||||
fan_data->valid = 0;
|
||||
|
||||
fan_data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0);
|
||||
if (IS_ERR(fan_data->pdev)) {
|
||||
ret = PTR_ERR(fan_data->pdev);
|
||||
platform_driver_unregister(&as4610_fan_driver);
|
||||
kfree(fan_data);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit as4610_fan_exit(void)
|
||||
{
|
||||
if (!fan_data) {
|
||||
return;
|
||||
}
|
||||
|
||||
platform_device_unregister(fan_data->pdev);
|
||||
platform_driver_unregister(&as4610_fan_driver);
|
||||
kfree(fan_data);
|
||||
}
|
||||
|
||||
late_initcall(as4610_fan_init);
|
||||
module_exit(as4610_fan_exit);
|
||||
|
||||
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
|
||||
MODULE_DESCRIPTION("as4610_fan driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,674 @@
|
||||
/*
|
||||
* A LED driver for the accton_as4610_led
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*#define DEBUG*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/err.h>
|
||||
#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);
|
||||
|
||||
#define DRVNAME "as4610_led"
|
||||
|
||||
struct as4610_led_data {
|
||||
struct platform_device *pdev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* != 0 if registers are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
int led_map;
|
||||
u8 reg_val[5]; /* Register value, 0 = (0x1A) Blinking function
|
||||
1 = (0x30) 7-seg 2
|
||||
2 = (0x31) 7-seg 1
|
||||
3 = (0x32) SYS/PRI/PSU1-2 LED
|
||||
4 = (0x33) STK1-2/Fan/PoE/Alarm LED */
|
||||
};
|
||||
|
||||
static struct as4610_led_data *ledctl = NULL;
|
||||
|
||||
/* LED related data
|
||||
*/
|
||||
#define LED_7SEG_REG_MASK 0x0F
|
||||
#define LED_7SEG_POINT_REG_MASK 0x10
|
||||
|
||||
#define LED_NORMAL_MASK 0x03
|
||||
#define LED_NORMAL_GREEN_VALUE 0x02
|
||||
#define LED_NORMAL_AMBER_VALUE 0x01
|
||||
#define LED_NORMAL_OFF_VALUE 0x00
|
||||
|
||||
#define LED_TYPE_SYS_REG_MASK 0xC0
|
||||
#define LED_MODE_SYS_BLINK_MASK 0x80
|
||||
|
||||
#define LED_TYPE_PRI_REG_MASK 0x30
|
||||
#define LED_MODE_PRI_BLINK_MASK 0x40
|
||||
|
||||
#define LED_TYPE_PSU1_REG_MASK 0x0C
|
||||
#define LED_MODE_PSU1_BLINK_MASK 0x20
|
||||
|
||||
#define LED_TYPE_PSU2_REG_MASK 0x03
|
||||
#define LED_MODE_PSU2_BLINK_MASK 0x10
|
||||
|
||||
#define LED_TYPE_STK1_REG_MASK 0xC0
|
||||
#define LED_MODE_STK1_BLINK_MASK 0x08
|
||||
|
||||
#define LED_TYPE_STK2_REG_MASK 0x30
|
||||
#define LED_MODE_STK2_BLINK_MASK 0x04
|
||||
|
||||
#define LED_TYPE_FAN_REG_MASK 0x0C
|
||||
#define LED_MODE_FAN_BLINK_MASK 0x02
|
||||
|
||||
#define LED_TYPE_POE_ALARM_REG_MASK 0x03
|
||||
#define LED_MODE_POE_ALARM_BLINK_MASK 0x01
|
||||
|
||||
static const u8 led_reg[] = {
|
||||
0x1A, /* Blinking function */
|
||||
0x30, /* 7-seg 1 */
|
||||
0x31, /* 7-seg 2 */
|
||||
0x32, /* SYS/PRI/PSU1-2 LED */
|
||||
0x33, /* STK1-2/Fan/PoE/Alarm LED */
|
||||
};
|
||||
|
||||
enum led_type {
|
||||
LED_TYPE_SYS,
|
||||
LED_TYPE_PRI,
|
||||
LED_TYPE_PSU1,
|
||||
LED_TYPE_PSU2,
|
||||
LED_TYPE_STK1,
|
||||
LED_TYPE_STK2,
|
||||
LED_TYPE_7SEG_TENS,
|
||||
LED_TYPE_7SEG_TENS_POINT,
|
||||
LED_TYPE_7SEG_DIGITS,
|
||||
LED_TYPE_7SEG_DIGITS_POINT,
|
||||
LED_TYPE_FAN,
|
||||
LED_TYPE_POE,
|
||||
LED_TYPE_ALARM,
|
||||
NUM_OF_LED
|
||||
};
|
||||
|
||||
#define AS4610_COMMON_LED_MAP (BIT(LED_TYPE_SYS) | BIT(LED_TYPE_PRI) | BIT(LED_TYPE_PSU1) | \
|
||||
BIT(LED_TYPE_PSU2)| BIT(LED_TYPE_STK1)| BIT(LED_TYPE_STK2))
|
||||
#define AS4610_NPOE_LED_MAP (AS4610_COMMON_LED_MAP | BIT(LED_TYPE_7SEG_TENS) | \
|
||||
BIT(LED_TYPE_7SEG_TENS_POINT) | BIT(LED_TYPE_7SEG_DIGITS) | \
|
||||
BIT(LED_TYPE_7SEG_DIGITS_POINT))
|
||||
#define AS4610_POE_LED_MAP (AS4610_NPOE_LED_MAP | BIT(LED_TYPE_FAN) | BIT(LED_TYPE_POE))
|
||||
#define AS4610_54T_B_LED_MAP (AS4610_COMMON_LED_MAP | BIT(LED_TYPE_FAN) | BIT(LED_TYPE_ALARM))
|
||||
|
||||
static int as4610_ledmaps[] = {
|
||||
[PID_AS4610_30T] = AS4610_NPOE_LED_MAP,
|
||||
[PID_AS4610_30P] = AS4610_POE_LED_MAP,
|
||||
[PID_AS4610_54T] = AS4610_NPOE_LED_MAP,
|
||||
[PID_AS4610_54P] = AS4610_POE_LED_MAP,
|
||||
[PID_AS4610_54T_B] = AS4610_54T_B_LED_MAP,
|
||||
[PID_RESERVED] = 0,
|
||||
};
|
||||
|
||||
enum led_light_mode {
|
||||
LED_MODE_OFF = 0,
|
||||
LED_MODE_GREEN,
|
||||
LED_MODE_GREEN_BLINK,
|
||||
LED_MODE_AMBER,
|
||||
LED_MODE_AMBER_BLINK,
|
||||
LED_MODE_RED,
|
||||
LED_MODE_RED_BLINK,
|
||||
LED_MODE_BLUE,
|
||||
LED_MODE_BLUE_BLINK,
|
||||
LED_MODE_AUTO,
|
||||
LED_MODE_AUTO_BLINKING,
|
||||
LED_MODE_UNKNOWN,
|
||||
LED_MODE_SEVEN_SEGMENT_MAX = 9,
|
||||
};
|
||||
|
||||
static int as4610_led_read_value(u8 reg)
|
||||
{
|
||||
return accton_i2c_cpld_read(0x30, reg);
|
||||
}
|
||||
|
||||
static int as4610_led_write_value(u8 reg, u8 value)
|
||||
{
|
||||
return accton_i2c_cpld_write(0x30, reg, value);
|
||||
}
|
||||
|
||||
static void as4610_led_update(void)
|
||||
{
|
||||
mutex_lock(&ledctl->update_lock);
|
||||
|
||||
if (time_after(jiffies, ledctl->last_updated + HZ + HZ / 2)
|
||||
|| !ledctl->valid) {
|
||||
int i;
|
||||
|
||||
dev_dbg(&ledctl->pdev->dev, "Starting as4610_led update\n");
|
||||
|
||||
/* Update LED data
|
||||
*/
|
||||
for (i = 0; i < ARRAY_SIZE(ledctl->reg_val); i++) {
|
||||
int status = as4610_led_read_value(led_reg[i]);
|
||||
|
||||
if (status < 0) {
|
||||
ledctl->valid = 0;
|
||||
dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", led_reg[i], status);
|
||||
goto exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
ledctl->reg_val[i] = status;
|
||||
}
|
||||
}
|
||||
|
||||
ledctl->last_updated = jiffies;
|
||||
ledctl->valid = 1;
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ledctl->update_lock);
|
||||
}
|
||||
|
||||
static enum led_brightness seven_segment_get(struct led_classdev *cdev, u8 reg_id)
|
||||
{
|
||||
as4610_led_update();
|
||||
return (ledctl->reg_val[reg_id] & LED_7SEG_REG_MASK);
|
||||
}
|
||||
|
||||
static void seven_segment_set(struct led_classdev *cdev, enum led_brightness mode, u8 reg_id)
|
||||
{
|
||||
if (mode > cdev->max_brightness) {
|
||||
return;
|
||||
}
|
||||
|
||||
ledctl->reg_val[reg_id] &= 0xF0;
|
||||
ledctl->reg_val[reg_id] |= mode;
|
||||
as4610_led_write_value(led_reg[reg_id], ledctl->reg_val[reg_id]);
|
||||
}
|
||||
|
||||
static enum led_brightness seven_segment_digits_get(struct led_classdev *cdev)
|
||||
{
|
||||
return seven_segment_get(cdev, 1);
|
||||
}
|
||||
|
||||
static void seven_segment_digits_set(struct led_classdev *cdev, enum led_brightness mode)
|
||||
{
|
||||
seven_segment_set(cdev, mode, 1);
|
||||
}
|
||||
|
||||
static enum led_brightness seven_segment_tens_get(struct led_classdev *cdev)
|
||||
{
|
||||
return seven_segment_get(cdev, 2);
|
||||
}
|
||||
|
||||
static void seven_segment_tens_set(struct led_classdev *cdev, enum led_brightness mode)
|
||||
{
|
||||
seven_segment_set(cdev, mode, 2);
|
||||
}
|
||||
|
||||
static enum led_brightness seven_segment_point_get(struct led_classdev *cdev, u8 reg_id)
|
||||
{
|
||||
as4610_led_update();
|
||||
return (ledctl->reg_val[reg_id] & LED_7SEG_POINT_REG_MASK) ? LED_MODE_GREEN : LED_MODE_OFF;
|
||||
}
|
||||
|
||||
static void seven_segment_point_set(struct led_classdev *cdev,
|
||||
enum led_brightness mode, u8 reg_id)
|
||||
{
|
||||
/* Validate brightness */
|
||||
if ((int)mode < LED_MODE_OFF || mode > cdev->max_brightness) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((int)mode == (int)LED_MODE_OFF) {
|
||||
ledctl->reg_val[reg_id] &= ~LED_7SEG_POINT_REG_MASK;
|
||||
}
|
||||
else { /* LED_MODE_GREEN */
|
||||
ledctl->reg_val[reg_id] |= LED_7SEG_POINT_REG_MASK;
|
||||
}
|
||||
|
||||
as4610_led_write_value(led_reg[reg_id], ledctl->reg_val[reg_id]);
|
||||
}
|
||||
|
||||
static enum led_brightness seven_segment_tens_point_get(struct led_classdev *cdev)
|
||||
{
|
||||
return seven_segment_point_get(cdev, 2);
|
||||
}
|
||||
|
||||
static void seven_segment_tens_point_set(struct led_classdev *cdev,
|
||||
enum led_brightness mode)
|
||||
{
|
||||
seven_segment_point_set(cdev, mode, 2);
|
||||
}
|
||||
|
||||
static enum led_brightness seven_segment_digits_point_get(struct led_classdev *cdev)
|
||||
{
|
||||
return seven_segment_point_get(cdev, 1);
|
||||
}
|
||||
|
||||
static void seven_segment_digits_point_set(struct led_classdev *cdev,
|
||||
enum led_brightness mode)
|
||||
{
|
||||
seven_segment_point_set(cdev, mode, 1);
|
||||
}
|
||||
|
||||
static u8 led_is_blinking_mode(enum led_brightness mode)
|
||||
{
|
||||
return ((int)mode == (int)LED_MODE_GREEN_BLINK ||
|
||||
(int)mode == (int)LED_MODE_AMBER_BLINK ||
|
||||
(int)mode == (int)LED_MODE_AUTO_BLINKING);
|
||||
}
|
||||
|
||||
static enum led_brightness as4610_led_auto_get(u8 blink_mask)
|
||||
{
|
||||
as4610_led_update();
|
||||
return (ledctl->reg_val[0] & blink_mask) ? LED_MODE_AUTO_BLINKING : LED_MODE_AUTO;
|
||||
}
|
||||
|
||||
static void as4610_led_auto_set(struct led_classdev *cdev,
|
||||
enum led_brightness mode, u8 blink_mask)
|
||||
{
|
||||
/* Validate brightness */
|
||||
if ((int)mode < (int)LED_MODE_AUTO || mode > cdev->max_brightness) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set blinking */
|
||||
if (led_is_blinking_mode(mode)) {
|
||||
ledctl->reg_val[0] |= blink_mask;
|
||||
}
|
||||
else {
|
||||
ledctl->reg_val[0] &= ~blink_mask;
|
||||
}
|
||||
as4610_led_write_value(led_reg[0], ledctl->reg_val[0]);
|
||||
}
|
||||
|
||||
static enum led_brightness as4610_led_psu1_get(struct led_classdev *cdev)
|
||||
{
|
||||
return as4610_led_auto_get(LED_MODE_PSU1_BLINK_MASK);
|
||||
}
|
||||
|
||||
static void as4610_led_psu1_set(struct led_classdev *cdev,
|
||||
enum led_brightness mode)
|
||||
{
|
||||
as4610_led_auto_set(cdev, mode, LED_MODE_PSU1_BLINK_MASK);
|
||||
}
|
||||
|
||||
static enum led_brightness as4610_led_psu2_get(struct led_classdev *cdev)
|
||||
{
|
||||
return as4610_led_auto_get(LED_MODE_PSU2_BLINK_MASK);
|
||||
}
|
||||
|
||||
static void as4610_led_psu2_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness mode)
|
||||
{
|
||||
as4610_led_auto_set(led_cdev, mode, LED_MODE_PSU2_BLINK_MASK);
|
||||
}
|
||||
|
||||
static enum led_brightness as4610_led_fan_get(struct led_classdev *cdev)
|
||||
{
|
||||
return as4610_led_auto_get(LED_MODE_FAN_BLINK_MASK);
|
||||
}
|
||||
|
||||
static void as4610_led_fan_set(struct led_classdev *cdev,
|
||||
enum led_brightness mode)
|
||||
{
|
||||
as4610_led_auto_set(cdev, mode, LED_MODE_FAN_BLINK_MASK);
|
||||
}
|
||||
|
||||
static u8 led_normal_light_mode_to_reg_val(enum led_brightness mode)
|
||||
{
|
||||
if (led_is_blinking_mode(mode)) {
|
||||
mode -= 1; /* convert blinking mode to non-blinking mode */
|
||||
}
|
||||
|
||||
if ((int)mode == (int)LED_MODE_GREEN) {
|
||||
return LED_NORMAL_GREEN_VALUE;
|
||||
}
|
||||
else if ((int)mode == (int)LED_MODE_AMBER) {
|
||||
return LED_NORMAL_AMBER_VALUE;
|
||||
}
|
||||
|
||||
return LED_NORMAL_OFF_VALUE;
|
||||
}
|
||||
|
||||
static enum led_brightness led_normal_reg_val_to_light_mode(u8 reg_val)
|
||||
{
|
||||
reg_val &= LED_NORMAL_MASK;
|
||||
|
||||
if (reg_val & LED_NORMAL_GREEN_VALUE) {
|
||||
return LED_MODE_GREEN;
|
||||
}
|
||||
else if (reg_val & LED_NORMAL_AMBER_VALUE) {
|
||||
return LED_MODE_AMBER;
|
||||
}
|
||||
|
||||
return LED_MODE_OFF;
|
||||
}
|
||||
|
||||
static void as4610_led_normal_set(struct led_classdev *cdev,
|
||||
enum led_brightness mode, u8 blink_mask, u8 reg_id, u8 reg_mask, u8 shift)
|
||||
{
|
||||
/* Validate brightness */
|
||||
if (mode > cdev->max_brightness) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set blinking */
|
||||
if (led_is_blinking_mode(mode)) {
|
||||
ledctl->reg_val[0] |= blink_mask;
|
||||
}
|
||||
else {
|
||||
ledctl->reg_val[0] &= ~blink_mask;
|
||||
}
|
||||
as4610_led_write_value(led_reg[0], ledctl->reg_val[0]);
|
||||
|
||||
/* Set color */
|
||||
ledctl->reg_val[reg_id] &= ~reg_mask;
|
||||
ledctl->reg_val[reg_id] |= (led_normal_light_mode_to_reg_val(mode) << shift);
|
||||
as4610_led_write_value(led_reg[reg_id], ledctl->reg_val[reg_id]);
|
||||
}
|
||||
|
||||
static enum led_brightness as4610_led_normal_get(u8 reg_id, u8 blink_mask, u8 shift)
|
||||
{
|
||||
u8 blinking = 0;
|
||||
enum led_brightness mode;
|
||||
|
||||
as4610_led_update();
|
||||
|
||||
mode = led_normal_reg_val_to_light_mode(ledctl->reg_val[reg_id] >> shift);
|
||||
if ((int)mode == (int)LED_MODE_OFF) {
|
||||
return mode;
|
||||
}
|
||||
|
||||
/* Checking blinking */
|
||||
if (ledctl->reg_val[0] & blink_mask) {
|
||||
blinking = 1;
|
||||
}
|
||||
|
||||
return blinking ? (mode+1) : mode;
|
||||
}
|
||||
|
||||
static void as4610_led_sys_set(struct led_classdev *cdev,
|
||||
enum led_brightness mode)
|
||||
{
|
||||
as4610_led_normal_set(cdev, mode, LED_MODE_SYS_BLINK_MASK,
|
||||
3, LED_TYPE_SYS_REG_MASK, 6);
|
||||
}
|
||||
|
||||
static enum led_brightness as4610_led_sys_get(struct led_classdev *cdev)
|
||||
{
|
||||
return as4610_led_normal_get(3, LED_MODE_SYS_BLINK_MASK, 6);
|
||||
}
|
||||
|
||||
static void as4610_led_pri_set(struct led_classdev *cdev,
|
||||
enum led_brightness mode)
|
||||
{
|
||||
as4610_led_normal_set(cdev, mode, LED_MODE_PRI_BLINK_MASK,
|
||||
3, LED_TYPE_PRI_REG_MASK, 4);
|
||||
}
|
||||
|
||||
static enum led_brightness as4610_led_pri_get(struct led_classdev *cdev)
|
||||
{
|
||||
return as4610_led_normal_get(3, LED_MODE_PRI_BLINK_MASK, 4);
|
||||
}
|
||||
|
||||
static void as4610_led_poe_alarm_set(struct led_classdev *cdev,
|
||||
enum led_brightness mode)
|
||||
{
|
||||
as4610_led_normal_set(cdev, mode, LED_MODE_POE_ALARM_BLINK_MASK,
|
||||
4, LED_TYPE_POE_ALARM_REG_MASK, 0);
|
||||
}
|
||||
|
||||
static enum led_brightness as4610_led_poe_alarm_get(struct led_classdev *cdev)
|
||||
{
|
||||
return as4610_led_normal_get(4, LED_MODE_POE_ALARM_BLINK_MASK, 0);
|
||||
}
|
||||
|
||||
static void as4610_led_stk1_set(struct led_classdev *cdev,
|
||||
enum led_brightness mode)
|
||||
{
|
||||
as4610_led_normal_set(cdev, mode, LED_MODE_STK1_BLINK_MASK,
|
||||
4, LED_TYPE_STK1_REG_MASK, 6);
|
||||
}
|
||||
|
||||
static enum led_brightness as4610_led_stk1_get(struct led_classdev *cdev)
|
||||
{
|
||||
return as4610_led_normal_get(4, LED_MODE_STK1_BLINK_MASK, 6);
|
||||
}
|
||||
|
||||
static void as4610_led_stk2_set(struct led_classdev *cdev,
|
||||
enum led_brightness mode)
|
||||
{
|
||||
as4610_led_normal_set(cdev, mode, LED_MODE_STK2_BLINK_MASK,
|
||||
4, LED_TYPE_STK2_REG_MASK, 4);
|
||||
}
|
||||
|
||||
static enum led_brightness as4610_led_stk2_get(struct led_classdev *cdev)
|
||||
{
|
||||
return as4610_led_normal_get(4, LED_MODE_STK2_BLINK_MASK, 4);
|
||||
}
|
||||
|
||||
static struct led_classdev as4610_leds[] = {
|
||||
[LED_TYPE_SYS] = {
|
||||
.name = "as4610::sys",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = as4610_led_sys_set,
|
||||
.brightness_get = as4610_led_sys_get,
|
||||
.max_brightness = LED_MODE_AMBER_BLINK,
|
||||
},
|
||||
[LED_TYPE_PRI] = {
|
||||
.name = "as4610::pri",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = as4610_led_pri_set,
|
||||
.brightness_get = as4610_led_pri_get,
|
||||
.max_brightness = LED_MODE_AMBER_BLINK,
|
||||
},
|
||||
[LED_TYPE_PSU1] = {
|
||||
.name = "as4610::psu1",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = as4610_led_psu1_set,
|
||||
.brightness_get = as4610_led_psu1_get,
|
||||
.max_brightness = LED_MODE_AUTO_BLINKING,
|
||||
},
|
||||
[LED_TYPE_PSU2] = {
|
||||
.name = "as4610::psu2",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = as4610_led_psu2_set,
|
||||
.brightness_get = as4610_led_psu2_get,
|
||||
.max_brightness = LED_MODE_AUTO_BLINKING,
|
||||
},
|
||||
[LED_TYPE_STK1] = {
|
||||
.name = "as4610::stk1",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = as4610_led_stk1_set,
|
||||
.brightness_get = as4610_led_stk1_get,
|
||||
.max_brightness = LED_MODE_AMBER_BLINK,
|
||||
},
|
||||
[LED_TYPE_STK2] = {
|
||||
.name = "as4610::stk2",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = as4610_led_stk2_set,
|
||||
.brightness_get = as4610_led_stk2_get,
|
||||
.max_brightness = LED_MODE_AMBER_BLINK,
|
||||
},
|
||||
[LED_TYPE_7SEG_TENS] = {
|
||||
.name = "as4610::7seg_tens",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = seven_segment_tens_set,
|
||||
.brightness_get = seven_segment_tens_get,
|
||||
.max_brightness = LED_MODE_SEVEN_SEGMENT_MAX,
|
||||
},
|
||||
[LED_TYPE_7SEG_TENS_POINT] = {
|
||||
.name = "as4610::7seg_tens_point",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = seven_segment_tens_point_set,
|
||||
.brightness_get = seven_segment_tens_point_get,
|
||||
.max_brightness = LED_MODE_GREEN,
|
||||
},
|
||||
[LED_TYPE_7SEG_DIGITS] = {
|
||||
.name = "as4610::7seg_digits",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = seven_segment_digits_set,
|
||||
.brightness_get = seven_segment_digits_get,
|
||||
.max_brightness = LED_MODE_SEVEN_SEGMENT_MAX,
|
||||
},
|
||||
[LED_TYPE_7SEG_DIGITS_POINT] = {
|
||||
.name = "as4610::7seg_digits_point",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = seven_segment_digits_point_set,
|
||||
.brightness_get = seven_segment_digits_point_get,
|
||||
.max_brightness = LED_MODE_GREEN,
|
||||
},
|
||||
[LED_TYPE_FAN] = {
|
||||
.name = "as4610::fan",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = as4610_led_fan_set,
|
||||
.brightness_get = as4610_led_fan_get,
|
||||
.max_brightness = LED_MODE_AUTO_BLINKING,
|
||||
},
|
||||
[LED_TYPE_POE] = {
|
||||
.name = "as4610::poe",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = as4610_led_poe_alarm_set,
|
||||
.brightness_get = as4610_led_poe_alarm_get,
|
||||
.max_brightness = LED_MODE_AMBER_BLINK,
|
||||
},
|
||||
[LED_TYPE_ALARM] = {
|
||||
.name = "as4610::alarm",
|
||||
.default_trigger = "unused",
|
||||
.brightness_set = as4610_led_poe_alarm_set,
|
||||
.brightness_get = as4610_led_poe_alarm_get,
|
||||
.max_brightness = LED_MODE_AMBER_BLINK,
|
||||
},
|
||||
};
|
||||
|
||||
static int as4610_led_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret = 0, i;
|
||||
|
||||
for (i = 0; i < NUM_OF_LED; i++) {
|
||||
if (!(ledctl->led_map & BIT(i))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = led_classdev_register(&pdev->dev, &as4610_leds[i]);
|
||||
if (ret < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
for (i = i-1; i >= 0; i--) {
|
||||
/* only unregister the LEDs that were successfully registered */
|
||||
if (!(ledctl->led_map & BIT(i))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
led_classdev_unregister(&as4610_leds[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int as4610_led_remove(struct platform_device *pdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_OF_LED; i++) {
|
||||
if (!(ledctl->led_map & BIT(i))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
led_classdev_unregister(&as4610_leds[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver as4610_led_driver = {
|
||||
.probe = as4610_led_probe,
|
||||
.remove = as4610_led_remove,
|
||||
.driver = {
|
||||
.name = DRVNAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init as4610_led_init(void)
|
||||
{
|
||||
int ret, pid;
|
||||
|
||||
if (as4610_product_id() == PID_UNKNOWN) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = platform_driver_register(&as4610_led_driver);
|
||||
if (ret < 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ledctl = kzalloc(sizeof(struct as4610_led_data), GFP_KERNEL);
|
||||
if (!ledctl) {
|
||||
ret = -ENOMEM;
|
||||
platform_driver_unregister(&as4610_led_driver);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
pid = as4610_product_id();
|
||||
if (pid == PID_UNKNOWN) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ledctl->led_map = as4610_ledmaps[pid];
|
||||
mutex_init(&ledctl->update_lock);
|
||||
|
||||
ledctl->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0);
|
||||
if (IS_ERR(ledctl->pdev)) {
|
||||
ret = PTR_ERR(ledctl->pdev);
|
||||
platform_driver_unregister(&as4610_led_driver);
|
||||
kfree(ledctl);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit as4610_led_exit(void)
|
||||
{
|
||||
if (!ledctl) {
|
||||
return;
|
||||
}
|
||||
|
||||
platform_device_unregister(ledctl->pdev);
|
||||
platform_driver_unregister(&as4610_led_driver);
|
||||
kfree(ledctl);
|
||||
}
|
||||
|
||||
late_initcall(as4610_led_init);
|
||||
module_exit(as4610_led_exit);
|
||||
|
||||
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
|
||||
MODULE_DESCRIPTION("as4610_led driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* An hwmon driver for accton as4610 Power Module
|
||||
*
|
||||
* Copyright (C) 2016 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/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmi.h>
|
||||
|
||||
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);
|
||||
|
||||
/* Addresses scanned
|
||||
*/
|
||||
static const unsigned short normal_i2c[] = { 0x50, 0x53, I2C_CLIENT_END };
|
||||
|
||||
/* Each client has this additional data
|
||||
*/
|
||||
struct as4610_psu_data {
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
char valid; /* !=0 if registers are valid */
|
||||
unsigned long last_updated; /* In jiffies */
|
||||
u8 index; /* PSU index */
|
||||
u8 status; /* Status(present/power_good) register read from CPLD */
|
||||
char model_name[9]; /* Model name, read from eeprom */
|
||||
};
|
||||
|
||||
static struct as4610_psu_data *as4610_psu_update_device(struct device *dev);
|
||||
|
||||
enum as4610_psu_sysfs_attributes {
|
||||
PSU_PRESENT,
|
||||
PSU_MODEL_NAME,
|
||||
PSU_POWER_GOOD
|
||||
};
|
||||
|
||||
/* sysfs attributes for hwmon
|
||||
*/
|
||||
static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT);
|
||||
static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_model_name,NULL, PSU_MODEL_NAME);
|
||||
static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD);
|
||||
|
||||
static struct attribute *as4610_psu_attributes[] = {
|
||||
&sensor_dev_attr_psu_present.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_model_name.dev_attr.attr,
|
||||
&sensor_dev_attr_psu_power_good.dev_attr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
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 as4610_psu_data *data = as4610_psu_update_device(dev);
|
||||
u8 status = 0;
|
||||
|
||||
if (attr->index == PSU_PRESENT) {
|
||||
status = (data->status >> (data->index*2) & 0x1);
|
||||
}
|
||||
else { /* PSU_POWER_GOOD */
|
||||
status = (data->status >> (data->index*2 + 1) & 0x1);
|
||||
}
|
||||
|
||||
return sprintf(buf, "%d\n", status);
|
||||
}
|
||||
|
||||
static ssize_t show_model_name(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct as4610_psu_data *data = as4610_psu_update_device(dev);
|
||||
|
||||
return sprintf(buf, "%s\n", data->model_name);
|
||||
}
|
||||
|
||||
static const struct attribute_group as4610_psu_group = {
|
||||
.attrs = as4610_psu_attributes,
|
||||
};
|
||||
|
||||
static int as4610_psu_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *dev_id)
|
||||
{
|
||||
struct as4610_psu_data *data;
|
||||
int status;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||
status = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
data = kzalloc(sizeof(struct as4610_psu_data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
status = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
data->valid = 0;
|
||||
data->index = dev_id->driver_data;
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
dev_info(&client->dev, "chip found\n");
|
||||
|
||||
/* Register sysfs hooks */
|
||||
status = sysfs_create_group(&client->dev.kobj, &as4610_psu_group);
|
||||
if (status) {
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
status = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "%s: psu '%s'\n",
|
||||
dev_name(data->hwmon_dev), client->name);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove:
|
||||
sysfs_remove_group(&client->dev.kobj, &as4610_psu_group);
|
||||
exit_free:
|
||||
kfree(data);
|
||||
exit:
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int as4610_psu_remove(struct i2c_client *client)
|
||||
{
|
||||
struct as4610_psu_data *data = i2c_get_clientdata(client);
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
sysfs_remove_group(&client->dev.kobj, &as4610_psu_group);
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum psu_index
|
||||
{
|
||||
as4610_psu1,
|
||||
as4610_psu2
|
||||
};
|
||||
|
||||
static const struct i2c_device_id as4610_psu_id[] = {
|
||||
{ "as4610_psu1", as4610_psu1 },
|
||||
{ "as4610_psu2", as4610_psu2 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, as4610_psu_id);
|
||||
|
||||
static struct i2c_driver as4610_psu_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "as4610_psu",
|
||||
},
|
||||
.probe = as4610_psu_probe,
|
||||
.remove = as4610_psu_remove,
|
||||
.id_table = as4610_psu_id,
|
||||
.address_list = normal_i2c,
|
||||
};
|
||||
|
||||
static int as4610_psu_read_data(struct i2c_client *client, u8 command, u8 *data,
|
||||
int count)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
while (count) {
|
||||
status = i2c_smbus_read_byte_data(client, command);
|
||||
if (unlikely(status < 0)) {
|
||||
break;
|
||||
}
|
||||
|
||||
*data = (u8)status;
|
||||
data += 1;
|
||||
command += 1;
|
||||
count -= 1;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct as4610_psu_data *as4610_psu_update_device(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct as4610_psu_data *data = i2c_get_clientdata(client);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
|
||||
|| !data->valid) {
|
||||
int status;
|
||||
int present = 0;
|
||||
|
||||
data->valid = 0;
|
||||
data->status = 0;
|
||||
dev_dbg(&client->dev, "Starting as4610 update\n");
|
||||
|
||||
/* Read psu status */
|
||||
status = accton_i2c_cpld_read(0x30, 0x11);
|
||||
|
||||
if (status < 0) {
|
||||
dev_dbg(&client->dev, "cpld reg 0x30 err %d\n", status);
|
||||
goto exit;
|
||||
}
|
||||
else {
|
||||
data->status = status;
|
||||
}
|
||||
|
||||
/* Read model name */
|
||||
memset(data->model_name, 0, sizeof(data->model_name));
|
||||
present = (data->status >> (data->index*2) & 0x1);
|
||||
|
||||
if (present) {
|
||||
int len = ARRAY_SIZE(data->model_name)-1;
|
||||
|
||||
status = as4610_psu_read_data(client, 0x20, data->model_name,
|
||||
ARRAY_SIZE(data->model_name)-1);
|
||||
|
||||
if (status < 0) {
|
||||
data->model_name[0] = '\0';
|
||||
dev_dbg(&client->dev, "unable to read model name from (0x%x)\n", client->addr);
|
||||
goto exit;
|
||||
}
|
||||
else {
|
||||
data->model_name[ARRAY_SIZE(data->model_name)-1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
data->last_updated = jiffies;
|
||||
data->valid = 1;
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(&data->update_lock);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static int __init as4610_psu_init(void)
|
||||
{
|
||||
return i2c_add_driver(&as4610_psu_driver);
|
||||
}
|
||||
|
||||
static void __exit as4610_psu_exit(void)
|
||||
{
|
||||
i2c_del_driver(&as4610_psu_driver);
|
||||
}
|
||||
|
||||
module_init(as4610_psu_init);
|
||||
module_exit(as4610_psu_exit);
|
||||
|
||||
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
|
||||
MODULE_DESCRIPTION("as4610_psu driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
* 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);
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
*.dtb
|
||||
dts
|
||||
include
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
INCLUDES=include .
|
||||
KERNEL := onl-kernel-4.14-lts-arm-iproc-all:armel
|
||||
DTS_LIST := arm-accton-as4610.dts
|
||||
VPATH := ../../../../../src
|
||||
include $(ONL)/make/dtbs.mk
|
||||
|
||||
#
|
||||
# The 4610 DTS relies on the common arm devices tree includes. These are linked here from the kernel package.
|
||||
#
|
||||
setup::
|
||||
onlpm --link-dir onl-kernel-3.2-lts-arm-iproc-all:armel /usr/share/onl/packages/armel/onl-kernel-3.2-lts-arm-iproc-all/mbuilds/arch/arm/boot/dts dts
|
||||
onlpm --link-dir onl-kernel-4.14-lts-arm-iproc-all:armel /usr/share/onl/packages/armel/onl-kernel-4.14-lts-arm-iproc-all/mbuilds/arch/arm/boot/dts dts
|
||||
onlpm --link-dir onl-kernel-4.14-lts-arm-iproc-all:armel /usr/share/onl/packages/armel/onl-kernel-4.14-lts-arm-iproc-all/mbuilds/include include
|
||||
|
||||
clean::
|
||||
rm -rf fsl
|
||||
setup-clean::
|
||||
#rm -rf dts include
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
|
||||
######################################################################
|
||||
#
|
||||
# platform-config for AS4610
|
||||
# platform-config for AS4610-54
|
||||
#
|
||||
######################################################################
|
||||
|
||||
arm-accton-as4610-54-r0:
|
||||
flat_image_tree:
|
||||
kernel:
|
||||
<<: *arm-iproc-kernel
|
||||
<<: *arm-iproc-4-14-kernel
|
||||
dtb:
|
||||
=: arm-accton-as4610-54-r0.dtb
|
||||
=: arm-accton-as4610.dtb
|
||||
package: onl-platform-build-arm-accton-as4610-54-r0:armel
|
||||
|
||||
itb:
|
||||
|
||||
@@ -6,3 +6,30 @@ class OnlPlatform_arm_accton_as4610_54_r0(OnlPlatformAccton,
|
||||
PLATFORM='arm-accton-as4610-54-r0'
|
||||
MODEL="AS4610-54"
|
||||
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_psu")
|
||||
self.insmod("accton_as4610_fan")
|
||||
self.insmod("ym2651y")
|
||||
self.new_i2c_devices(
|
||||
[
|
||||
("pca9548", 0x70, 1),
|
||||
("as4610_sfp1", 0x50, 2),
|
||||
("as4610_sfp2", 0x50, 3),
|
||||
("as4610_sfp3", 0x50, 4),
|
||||
("as4610_sfp4", 0x50, 5),
|
||||
("as4610_sfp5", 0x50, 6),
|
||||
("as4610_sfp6", 0x50, 7),
|
||||
("as4610_psu1", 0x50, 8),
|
||||
("as4610_psu2", 0x51, 8),
|
||||
("ym1921", 0x58, 8),
|
||||
("ym1921", 0x59, 8),
|
||||
("lm77", 0x48, 9),
|
||||
# ("ds1307", 0x68, 9),
|
||||
("24c04", 0x50, 9),
|
||||
]
|
||||
)
|
||||
return True
|
||||
|
||||
Reference in New Issue
Block a user