mirror of
https://github.com/Telecominfraproject/OpenNetworkLinux.git
synced 2025-12-25 01:07:01 +00:00
workaround to avoid the conflict while merging with master (will revert them back later)
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
/*
|
||||
* An I2C multiplexer dirver for accton as5712 CPLD
|
||||
* I2C multiplexer
|
||||
*
|
||||
* Copyright (C) 2015 Accton Technology Corporation.
|
||||
* Brandon Chuang <brandon_chuang@accton.com.tw>
|
||||
* 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.
|
||||
@@ -47,6 +46,8 @@
|
||||
#define CPLD_CHANNEL_SELECT_REG 0x2
|
||||
#define CPLD_DESELECT_CHANNEL 0xFF
|
||||
|
||||
#define ACCTON_I2C_CPLD_MUX_MAX_NCHANS NUM_OF_CPLD3_CHANS
|
||||
|
||||
static LIST_HEAD(cpld_client_list);
|
||||
static struct mutex list_lock;
|
||||
|
||||
@@ -63,7 +64,7 @@ enum cpld_mux_type {
|
||||
|
||||
struct as5712_54x_cpld_data {
|
||||
enum cpld_mux_type type;
|
||||
struct i2c_client *client;
|
||||
struct i2c_adapter *virt_adaps[ACCTON_I2C_CPLD_MUX_MAX_NCHANS];
|
||||
u8 last_chan; /* last register value */
|
||||
|
||||
struct device *hwmon_dev;
|
||||
@@ -594,9 +595,8 @@ static ssize_t show_present_all(struct device *dev, struct device_attribute *da,
|
||||
int i, status, num_regs = 0;
|
||||
u8 values[4] = {0};
|
||||
u8 regs[] = {0x6, 0x7, 0x8, 0x14};
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
struct as5712_54x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct as5712_54x_cpld_data *data = i2c_get_clientdata(client);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
@@ -638,9 +638,8 @@ static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da,
|
||||
int i, status;
|
||||
u8 values[3] = {0};
|
||||
u8 regs[] = {0xF, 0x10, 0x11};
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
struct as5712_54x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct as5712_54x_cpld_data *data = i2c_get_clientdata(client);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
@@ -669,8 +668,7 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da,
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
struct as5712_54x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct as5712_54x_cpld_data *data = i2c_get_clientdata(client);
|
||||
int status = 0;
|
||||
u8 reg = 0, mask = 0, revert = 0;
|
||||
|
||||
@@ -821,9 +819,8 @@ static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
struct as5712_54x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct as5712_54x_cpld_data *data = i2c_get_clientdata(client);
|
||||
long disable;
|
||||
int status;
|
||||
u8 reg = 0, mask = 0;
|
||||
@@ -893,11 +890,10 @@ exit:
|
||||
static ssize_t access(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
struct as5712_54x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
int status;
|
||||
u32 addr, val;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct as5712_54x_cpld_data *data = i2c_get_clientdata(client);
|
||||
|
||||
if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) {
|
||||
return -EINVAL;
|
||||
@@ -953,34 +949,32 @@ static int as5712_54x_cpld_mux_reg_write(struct i2c_adapter *adap,
|
||||
return res;
|
||||
}
|
||||
|
||||
static int as5712_54x_cpld_mux_select_chan(struct i2c_mux_core *muxc,
|
||||
u32 chan)
|
||||
static int as5712_54x_cpld_mux_select_chan(struct i2c_adapter *adap,
|
||||
void *client, u32 chan)
|
||||
{
|
||||
struct as5712_54x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = data->client;
|
||||
struct as5712_54x_cpld_data *data = i2c_get_clientdata(client);
|
||||
u8 regval;
|
||||
int ret = 0;
|
||||
|
||||
regval = chan;
|
||||
/* Only select the channel if its different from the last channel */
|
||||
|
||||
/* Only select the channel if its different from the last channel */
|
||||
if (data->last_chan != regval) {
|
||||
ret = as5712_54x_cpld_mux_reg_write(muxc->parent, client, regval);
|
||||
ret = as5712_54x_cpld_mux_reg_write(adap, client, regval);
|
||||
data->last_chan = regval;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int as5712_54x_cpld_mux_deselect_mux(struct i2c_mux_core *muxc,
|
||||
u32 chan)
|
||||
static int as5712_54x_cpld_mux_deselect_mux(struct i2c_adapter *adap,
|
||||
void *client, u32 chan)
|
||||
{
|
||||
struct as5712_54x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = data->client;
|
||||
struct as5712_54x_cpld_data *data = i2c_get_clientdata(client);
|
||||
|
||||
/* Deselect active channel */
|
||||
data->last_chan = chips[data->type].deselectChan;
|
||||
|
||||
return as5712_54x_cpld_mux_reg_write(muxc->parent, client, data->last_chan);
|
||||
return as5712_54x_cpld_mux_reg_write(adap, client, data->last_chan);
|
||||
}
|
||||
|
||||
static void as5712_54x_cpld_add_client(struct i2c_client *client)
|
||||
@@ -1007,7 +1001,8 @@ static void as5712_54x_cpld_remove_client(struct i2c_client *client)
|
||||
|
||||
mutex_lock(&list_lock);
|
||||
|
||||
list_for_each(list_node, &cpld_client_list) {
|
||||
list_for_each(list_node, &cpld_client_list)
|
||||
{
|
||||
cpld_node = list_entry(list_node, struct cpld_client_node, list);
|
||||
|
||||
if (cpld_node->client == client) {
|
||||
@@ -1044,44 +1039,45 @@ static ssize_t show_version(struct device *dev, struct device_attribute *attr, c
|
||||
static int as5712_54x_cpld_mux_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
|
||||
int num, force, class;
|
||||
struct i2c_mux_core *muxc;
|
||||
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
|
||||
int chan=0;
|
||||
struct as5712_54x_cpld_data *data;
|
||||
int ret = 0;
|
||||
const struct attribute_group *group = NULL;
|
||||
int ret = -ENODEV;
|
||||
const struct attribute_group *group = NULL;
|
||||
|
||||
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
|
||||
return -ENODEV;
|
||||
goto exit;
|
||||
|
||||
muxc = i2c_mux_alloc(adap, &client->dev,
|
||||
chips[id->driver_data].nchans, sizeof(*data), 0,
|
||||
as5712_54x_cpld_mux_select_chan, as5712_54x_cpld_mux_deselect_mux);
|
||||
if (!muxc)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, muxc);
|
||||
data = i2c_mux_priv(muxc);
|
||||
data->client = client;
|
||||
data->type = id->driver_data;
|
||||
data->last_chan = chips[data->type].deselectChan; /* force the first selection */
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Now create an adapter for each channel */
|
||||
for (num = 0; num < chips[data->type].nchans; num++) {
|
||||
force = 0; /* dynamic adap number */
|
||||
class = 0; /* no class by default */
|
||||
|
||||
ret = i2c_mux_add_adapter(muxc, force, num, class);
|
||||
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"failed to register multiplexed adapter"
|
||||
" %d as bus %d\n", num, force);
|
||||
goto add_mux_failed;
|
||||
}
|
||||
data = kzalloc(sizeof(struct as5712_54x_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;
|
||||
|
||||
if (data->type == as5712_54x_cpld2 || data->type == as5712_54x_cpld3) {
|
||||
data->last_chan = chips[data->type].deselectChan; /* force the first selection */
|
||||
|
||||
/* Now create an adapter for each channel */
|
||||
for (chan = 0; chan < chips[data->type].nchans; chan++) {
|
||||
data->virt_adaps[chan] = i2c_add_mux_adapter(adap, &client->dev, client, 0, chan, 0,
|
||||
as5712_54x_cpld_mux_select_chan,
|
||||
as5712_54x_cpld_mux_deselect_mux);
|
||||
|
||||
if (data->virt_adaps[chan] == NULL) {
|
||||
ret = -ENODEV;
|
||||
dev_err(&client->dev, "failed to register multiplexed adapter %d\n", chan);
|
||||
goto exit_mux_register;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "registered %d multiplexed busses for I2C mux %s\n",
|
||||
chan, client->name);
|
||||
}
|
||||
|
||||
/* Register sysfs hooks */
|
||||
switch (data->type) {
|
||||
case as5712_54x_cpld1:
|
||||
@@ -1099,37 +1095,33 @@ static int as5712_54x_cpld_mux_probe(struct i2c_client *client,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (group) {
|
||||
ret = sysfs_create_group(&client->dev.kobj, group);
|
||||
if (ret) {
|
||||
goto add_mux_failed;
|
||||
goto exit_mux_register;
|
||||
}
|
||||
}
|
||||
|
||||
if (chips[data->type].nchans) {
|
||||
dev_info(&client->dev,
|
||||
"registered %d multiplexed busses for I2C %s\n",
|
||||
num, client->name);
|
||||
}
|
||||
else {
|
||||
dev_info(&client->dev,
|
||||
"device %s registered\n", client->name);
|
||||
}
|
||||
|
||||
as5712_54x_cpld_add_client(client);
|
||||
|
||||
return 0;
|
||||
|
||||
add_mux_failed:
|
||||
i2c_mux_del_adapters(muxc);
|
||||
exit_mux_register:
|
||||
for (chan--; chan >= 0; chan--) {
|
||||
i2c_del_mux_adapter(data->virt_adaps[chan]);
|
||||
}
|
||||
kfree(data);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int as5712_54x_cpld_mux_remove(struct i2c_client *client)
|
||||
{
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
struct as5712_54x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct as5712_54x_cpld_data *data = i2c_get_clientdata(client);
|
||||
const struct chip_desc *chip = &chips[data->type];
|
||||
int chan;
|
||||
const struct attribute_group *group = NULL;
|
||||
|
||||
as5712_54x_cpld_remove_client(client);
|
||||
@@ -1153,7 +1145,14 @@ static int as5712_54x_cpld_mux_remove(struct i2c_client *client)
|
||||
sysfs_remove_group(&client->dev.kobj, group);
|
||||
}
|
||||
|
||||
i2c_mux_del_adapters(muxc);
|
||||
for (chan = 0; chan < chip->nchans; ++chan) {
|
||||
if (data->virt_adaps[chan]) {
|
||||
i2c_del_mux_adapter(data->virt_adaps[chan]);
|
||||
data->virt_adaps[chan] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1202,7 +1201,8 @@ int as5712_54x_cpld_read(unsigned short cpld_addr, u8 reg)
|
||||
|
||||
mutex_lock(&list_lock);
|
||||
|
||||
list_for_each(list_node, &cpld_client_list) {
|
||||
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) {
|
||||
@@ -1225,7 +1225,8 @@ int as5712_54x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value)
|
||||
|
||||
mutex_lock(&list_lock);
|
||||
|
||||
list_for_each(list_node, &cpld_client_list) {
|
||||
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) {
|
||||
@@ -1262,7 +1263,7 @@ static void __exit as5712_54x_cpld_mux_exit(void)
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
|
||||
MODULE_DESCRIPTION("Accton as5712-54x CPLD driver");
|
||||
MODULE_DESCRIPTION("Accton I2C CPLD mux driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(as5712_54x_cpld_mux_init);
|
||||
|
||||
@@ -32,6 +32,11 @@
|
||||
extern int as5712_54x_cpld_read (unsigned short cpld_addr, u8 reg);
|
||||
extern int as5712_54x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
|
||||
|
||||
extern void led_classdev_unregister(struct led_classdev *led_cdev);
|
||||
extern int led_classdev_register(struct device *parent, struct led_classdev *led_cdev);
|
||||
extern void led_classdev_resume(struct led_classdev *led_cdev);
|
||||
extern void led_classdev_suspend(struct led_classdev *led_cdev);
|
||||
|
||||
#define DRVNAME "as5712_54x_led"
|
||||
|
||||
struct accton_as5712_54x_led_data {
|
||||
|
||||
@@ -32,6 +32,11 @@
|
||||
extern int as5812_54t_cpld_read(unsigned short cpld_addr, u8 reg);
|
||||
extern int as5812_54t_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
|
||||
|
||||
extern void led_classdev_unregister(struct led_classdev *led_cdev);
|
||||
extern int led_classdev_register(struct device *parent, struct led_classdev *led_cdev);
|
||||
extern void led_classdev_resume(struct led_classdev *led_cdev);
|
||||
extern void led_classdev_suspend(struct led_classdev *led_cdev);
|
||||
|
||||
#define DRVNAME "as5812_54t_led"
|
||||
|
||||
struct accton_as5812_54t_led_data {
|
||||
|
||||
@@ -65,7 +65,7 @@ enum cpld_mux_type {
|
||||
|
||||
struct as5812_54x_cpld_data {
|
||||
enum cpld_mux_type type;
|
||||
struct i2c_client *client;
|
||||
struct i2c_adapter *virt_adaps[ACCTON_I2C_CPLD_MUX_MAX_NCHANS];
|
||||
u8 last_chan; /* last register value */
|
||||
|
||||
struct device *hwmon_dev;
|
||||
@@ -100,6 +100,7 @@ static const struct i2c_device_id as5812_54x_cpld_mux_id[] = {
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, as5812_54x_cpld_mux_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
|
||||
@@ -595,9 +596,8 @@ static ssize_t show_present_all(struct device *dev, struct device_attribute *da,
|
||||
int i, status, num_regs = 0;
|
||||
u8 values[4] = {0};
|
||||
u8 regs[] = {0x6, 0x7, 0x8, 0x14};
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
struct as5812_54x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct as5812_54x_cpld_data *data = i2c_get_clientdata(client);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
@@ -639,9 +639,8 @@ static ssize_t show_rxlos_all(struct device *dev, struct device_attribute *da,
|
||||
int i, status;
|
||||
u8 values[3] = {0};
|
||||
u8 regs[] = {0xF, 0x10, 0x11};
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
struct as5812_54x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct as5812_54x_cpld_data *data = i2c_get_clientdata(client);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
@@ -670,8 +669,7 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da,
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
struct as5812_54x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct as5812_54x_cpld_data *data = i2c_get_clientdata(client);
|
||||
int status = 0;
|
||||
u8 reg = 0, mask = 0, revert = 0;
|
||||
|
||||
@@ -822,9 +820,8 @@ static ssize_t set_tx_disable(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
struct as5812_54x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct as5812_54x_cpld_data *data = i2c_get_clientdata(client);
|
||||
long disable;
|
||||
int status;
|
||||
u8 reg = 0, mask = 0;
|
||||
@@ -894,11 +891,10 @@ exit:
|
||||
static ssize_t access(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
struct as5812_54x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
int status;
|
||||
u32 addr, val;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct as5812_54x_cpld_data *data = i2c_get_clientdata(client);
|
||||
|
||||
if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) {
|
||||
return -EINVAL;
|
||||
@@ -920,6 +916,7 @@ exit:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer()
|
||||
for this as they will try to lock adapter a second time */
|
||||
static int as5812_54x_cpld_mux_reg_write(struct i2c_adapter *adap,
|
||||
@@ -953,35 +950,32 @@ static int as5812_54x_cpld_mux_reg_write(struct i2c_adapter *adap,
|
||||
return res;
|
||||
}
|
||||
|
||||
static int as5812_54x_cpld_mux_select_chan(struct i2c_mux_core *muxc,
|
||||
u32 chan)
|
||||
static int as5812_54x_cpld_mux_select_chan(struct i2c_adapter *adap,
|
||||
void *client, u32 chan)
|
||||
{
|
||||
struct as5812_54x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = data->client;
|
||||
struct as5812_54x_cpld_data *data = i2c_get_clientdata(client);
|
||||
u8 regval;
|
||||
int ret = 0;
|
||||
|
||||
regval = chan;
|
||||
|
||||
/* Only select the channel if its different from the last channel */
|
||||
if (data->last_chan != regval) {
|
||||
ret = as5812_54x_cpld_mux_reg_write(muxc->parent, client, regval);
|
||||
ret = as5812_54x_cpld_mux_reg_write(adap, client, regval);
|
||||
data->last_chan = regval;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int as5812_54x_cpld_mux_deselect_mux(struct i2c_mux_core *muxc,
|
||||
u32 chan)
|
||||
static int as5812_54x_cpld_mux_deselect_mux(struct i2c_adapter *adap,
|
||||
void *client, u32 chan)
|
||||
{
|
||||
struct as5812_54x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = data->client;
|
||||
struct as5812_54x_cpld_data *data = i2c_get_clientdata(client);
|
||||
|
||||
/* Deselect active channel */
|
||||
data->last_chan = chips[data->type].deselectChan;
|
||||
|
||||
return as5812_54x_cpld_mux_reg_write(muxc->parent, client, data->last_chan);
|
||||
return as5812_54x_cpld_mux_reg_write(adap, client, data->last_chan);
|
||||
}
|
||||
|
||||
static void as5812_54x_cpld_add_client(struct i2c_client *client)
|
||||
@@ -1008,7 +1002,8 @@ static void as5812_54x_cpld_remove_client(struct i2c_client *client)
|
||||
|
||||
mutex_lock(&list_lock);
|
||||
|
||||
list_for_each(list_node, &cpld_client_list) {
|
||||
list_for_each(list_node, &cpld_client_list)
|
||||
{
|
||||
cpld_node = list_entry(list_node, struct cpld_client_node, list);
|
||||
|
||||
if (cpld_node->client == client) {
|
||||
@@ -1045,44 +1040,45 @@ static ssize_t show_version(struct device *dev, struct device_attribute *attr, c
|
||||
static int as5812_54x_cpld_mux_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
|
||||
int num, force, class;
|
||||
struct i2c_mux_core *muxc;
|
||||
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
|
||||
int chan=0;
|
||||
struct as5812_54x_cpld_data *data;
|
||||
int ret = 0;
|
||||
const struct attribute_group *group = NULL;
|
||||
int ret = -ENODEV;
|
||||
const struct attribute_group *group = NULL;
|
||||
|
||||
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
|
||||
return -ENODEV;
|
||||
goto exit;
|
||||
|
||||
muxc = i2c_mux_alloc(adap, &client->dev,
|
||||
chips[id->driver_data].nchans, sizeof(*data), 0,
|
||||
as5812_54x_cpld_mux_select_chan, as5812_54x_cpld_mux_deselect_mux);
|
||||
if (!muxc)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, muxc);
|
||||
data = i2c_mux_priv(muxc);
|
||||
data->client = client;
|
||||
data->type = id->driver_data;
|
||||
data->last_chan = CPLD_DESELECT_CHANNEL; /* force the first selection */
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Now create an adapter for each channel */
|
||||
for (num = 0; num < chips[data->type].nchans; num++) {
|
||||
force = 0; /* dynamic adap number */
|
||||
class = 0; /* no class by default */
|
||||
|
||||
ret = i2c_mux_add_adapter(muxc, force, num, class);
|
||||
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"failed to register multiplexed adapter"
|
||||
" %d as bus %d\n", num, force);
|
||||
goto add_mux_failed;
|
||||
}
|
||||
data = kzalloc(sizeof(struct as5812_54x_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;
|
||||
|
||||
if (data->type == as5812_54x_cpld2 || data->type == as5812_54x_cpld3) {
|
||||
data->last_chan = chips[data->type].deselectChan; /* force the first selection */
|
||||
|
||||
/* Now create an adapter for each channel */
|
||||
for (chan = 0; chan < chips[data->type].nchans; chan++) {
|
||||
data->virt_adaps[chan] = i2c_add_mux_adapter(adap, &client->dev, client, 0, chan, 0,
|
||||
as5812_54x_cpld_mux_select_chan,
|
||||
as5812_54x_cpld_mux_deselect_mux);
|
||||
|
||||
if (data->virt_adaps[chan] == NULL) {
|
||||
ret = -ENODEV;
|
||||
dev_err(&client->dev, "failed to register multiplexed adapter %d\n", chan);
|
||||
goto exit_mux_register;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "registered %d multiplexed busses for I2C mux %s\n",
|
||||
chan, client->name);
|
||||
}
|
||||
|
||||
/* Register sysfs hooks */
|
||||
switch (data->type) {
|
||||
case as5812_54x_cpld1:
|
||||
@@ -1100,37 +1096,33 @@ static int as5812_54x_cpld_mux_probe(struct i2c_client *client,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (group) {
|
||||
ret = sysfs_create_group(&client->dev.kobj, group);
|
||||
if (ret) {
|
||||
goto add_mux_failed;
|
||||
goto exit_mux_register;
|
||||
}
|
||||
}
|
||||
|
||||
if (chips[data->type].nchans) {
|
||||
dev_info(&client->dev,
|
||||
"registered %d multiplexed busses for I2C %s\n",
|
||||
num, client->name);
|
||||
}
|
||||
else {
|
||||
dev_info(&client->dev,
|
||||
"device %s registered\n", client->name);
|
||||
}
|
||||
|
||||
as5812_54x_cpld_add_client(client);
|
||||
|
||||
return 0;
|
||||
|
||||
add_mux_failed:
|
||||
i2c_mux_del_adapters(muxc);
|
||||
exit_mux_register:
|
||||
for (chan--; chan >= 0; chan--) {
|
||||
i2c_del_mux_adapter(data->virt_adaps[chan]);
|
||||
}
|
||||
kfree(data);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int as5812_54x_cpld_mux_remove(struct i2c_client *client)
|
||||
{
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
struct as5812_54x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct as5812_54x_cpld_data *data = i2c_get_clientdata(client);
|
||||
const struct chip_desc *chip = &chips[data->type];
|
||||
int chan;
|
||||
const struct attribute_group *group = NULL;
|
||||
|
||||
as5812_54x_cpld_remove_client(client);
|
||||
@@ -1154,7 +1146,14 @@ static int as5812_54x_cpld_mux_remove(struct i2c_client *client)
|
||||
sysfs_remove_group(&client->dev.kobj, group);
|
||||
}
|
||||
|
||||
i2c_mux_del_adapters(muxc);
|
||||
for (chan = 0; chan < chip->nchans; ++chan) {
|
||||
if (data->virt_adaps[chan]) {
|
||||
i2c_del_mux_adapter(data->virt_adaps[chan]);
|
||||
data->virt_adaps[chan] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1203,7 +1202,8 @@ int as5812_54x_cpld_read(unsigned short cpld_addr, u8 reg)
|
||||
|
||||
mutex_lock(&list_lock);
|
||||
|
||||
list_for_each(list_node, &cpld_client_list) {
|
||||
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) {
|
||||
@@ -1226,7 +1226,8 @@ int as5812_54x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value)
|
||||
|
||||
mutex_lock(&list_lock);
|
||||
|
||||
list_for_each(list_node, &cpld_client_list) {
|
||||
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) {
|
||||
@@ -1263,7 +1264,7 @@ static void __exit as5812_54x_cpld_mux_exit(void)
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Brandon Chuang <brandon_chuang@accton.com.tw>");
|
||||
MODULE_DESCRIPTION("Accton as5812-54x CPLD driver");
|
||||
MODULE_DESCRIPTION("Accton I2C CPLD mux driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_init(as5812_54x_cpld_mux_init);
|
||||
|
||||
@@ -32,6 +32,11 @@
|
||||
extern int as5812_54x_cpld_read (unsigned short cpld_addr, u8 reg);
|
||||
extern int as5812_54x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
|
||||
|
||||
extern void led_classdev_unregister(struct led_classdev *led_cdev);
|
||||
extern int led_classdev_register(struct device *parent, struct led_classdev *led_cdev);
|
||||
extern void led_classdev_resume(struct led_classdev *led_cdev);
|
||||
extern void led_classdev_suspend(struct led_classdev *led_cdev);
|
||||
|
||||
#define DRVNAME "as5812_54x_led"
|
||||
|
||||
struct accton_as5812_54x_led_data {
|
||||
|
||||
@@ -45,6 +45,9 @@
|
||||
#define NUM_OF_CPLD2_CHANS 0x10
|
||||
#define NUM_OF_CPLD3_CHANS 0x10
|
||||
#define CPLD_CHANNEL_SELECT_REG 0x2
|
||||
#define CPLD_DESELECT_CHANNEL 0xFF
|
||||
|
||||
#define ACCTON_I2C_CPLD_MUX_MAX_NCHANS NUM_OF_CPLD3_CHANS
|
||||
|
||||
static LIST_HEAD(cpld_client_list);
|
||||
static struct mutex list_lock;
|
||||
@@ -62,7 +65,7 @@ enum cpld_mux_type {
|
||||
|
||||
struct as6812_32x_cpld_data {
|
||||
enum cpld_mux_type type;
|
||||
struct i2c_client *client;
|
||||
struct i2c_adapter *virt_adaps[ACCTON_I2C_CPLD_MUX_MAX_NCHANS];
|
||||
u8 last_chan; /* last register value */
|
||||
|
||||
struct device *hwmon_dev;
|
||||
@@ -271,9 +274,8 @@ static ssize_t show_present_all(struct device *dev, struct device_attribute *da,
|
||||
int i, status;
|
||||
u8 values[2] = {0};
|
||||
u8 regs[] = {0xA, 0xB};
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
struct as6812_32x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct as6812_32x_cpld_data *data = i2c_get_clientdata(client);
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
@@ -302,8 +304,7 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da,
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
struct as6812_32x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct as6812_32x_cpld_data *data = i2c_get_clientdata(client);
|
||||
int status = 0;
|
||||
u8 reg = 0, mask = 0;
|
||||
|
||||
@@ -345,11 +346,10 @@ exit:
|
||||
static ssize_t access(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
struct as6812_32x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
int status;
|
||||
u32 addr, val;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct as6812_32x_cpld_data *data = i2c_get_clientdata(client);
|
||||
|
||||
if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) {
|
||||
return -EINVAL;
|
||||
@@ -405,34 +405,32 @@ static int as6812_32x_cpld_mux_reg_write(struct i2c_adapter *adap,
|
||||
return res;
|
||||
}
|
||||
|
||||
static int as6812_32x_cpld_mux_select_chan(struct i2c_mux_core *muxc,
|
||||
u32 chan)
|
||||
static int as6812_32x_cpld_mux_select_chan(struct i2c_adapter *adap,
|
||||
void *client, u32 chan)
|
||||
{
|
||||
struct as6812_32x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = data->client;
|
||||
struct as6812_32x_cpld_data *data = i2c_get_clientdata(client);
|
||||
u8 regval;
|
||||
int ret = 0;
|
||||
regval = chan;
|
||||
|
||||
/* Only select the channel if its different from the last channel */
|
||||
if (data->last_chan != regval) {
|
||||
ret = as6812_32x_cpld_mux_reg_write(muxc->parent, client, regval);
|
||||
ret = as6812_32x_cpld_mux_reg_write(adap, client, regval);
|
||||
data->last_chan = regval;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int as6812_32x_cpld_mux_deselect_mux(struct i2c_mux_core *muxc,
|
||||
u32 chan)
|
||||
static int as6812_32x_cpld_mux_deselect_mux(struct i2c_adapter *adap,
|
||||
void *client, u32 chan)
|
||||
{
|
||||
struct as6812_32x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct i2c_client *client = data->client;
|
||||
struct as6812_32x_cpld_data *data = i2c_get_clientdata(client);
|
||||
|
||||
/* Deselect active channel */
|
||||
data->last_chan = chips[data->type].deselectChan;
|
||||
|
||||
return as6812_32x_cpld_mux_reg_write(muxc->parent, client, data->last_chan);
|
||||
return as6812_32x_cpld_mux_reg_write(adap, client, data->last_chan);
|
||||
}
|
||||
|
||||
static void as6812_32x_cpld_add_client(struct i2c_client *client)
|
||||
@@ -459,8 +457,9 @@ static void as6812_32x_cpld_remove_client(struct i2c_client *client)
|
||||
|
||||
mutex_lock(&list_lock);
|
||||
|
||||
list_for_each(list_node, &cpld_client_list) {
|
||||
cpld_node = list_entry(list_node, struct cpld_client_node, list);
|
||||
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;
|
||||
@@ -496,44 +495,45 @@ static ssize_t show_version(struct device *dev, struct device_attribute *attr, c
|
||||
static int as6812_32x_cpld_mux_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
|
||||
int num, force, class;
|
||||
struct i2c_mux_core *muxc;
|
||||
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
|
||||
int chan=0;
|
||||
struct as6812_32x_cpld_data *data;
|
||||
int ret = 0;
|
||||
const struct attribute_group *group = NULL;
|
||||
int ret = -ENODEV;
|
||||
const struct attribute_group *group = NULL;
|
||||
|
||||
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
|
||||
return -ENODEV;
|
||||
goto exit;
|
||||
|
||||
muxc = i2c_mux_alloc(adap, &client->dev,
|
||||
chips[id->driver_data].nchans, sizeof(*data), 0,
|
||||
as6812_32x_cpld_mux_select_chan, as6812_32x_cpld_mux_deselect_mux);
|
||||
if (!muxc)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, muxc);
|
||||
data = i2c_mux_priv(muxc);
|
||||
data->client = client;
|
||||
data->type = id->driver_data;
|
||||
data->last_chan = chips[data->type].deselectChan; /* force the first selection */
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
/* Now create an adapter for each channel */
|
||||
for (num = 0; num < chips[data->type].nchans; num++) {
|
||||
force = 0; /* dynamic adap number */
|
||||
class = 0; /* no class by default */
|
||||
|
||||
ret = i2c_mux_add_adapter(muxc, force, num, class);
|
||||
|
||||
if (ret) {
|
||||
dev_err(&client->dev,
|
||||
"failed to register multiplexed adapter"
|
||||
" %d as bus %d\n", num, force);
|
||||
goto add_mux_failed;
|
||||
}
|
||||
data = kzalloc(sizeof(struct as6812_32x_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;
|
||||
|
||||
if (data->type == as6812_32x_cpld2 || data->type == as6812_32x_cpld3) {
|
||||
data->last_chan = chips[data->type].deselectChan; /* force the first selection */
|
||||
|
||||
/* Now create an adapter for each channel */
|
||||
for (chan = 0; chan < chips[data->type].nchans; chan++) {
|
||||
data->virt_adaps[chan] = i2c_add_mux_adapter(adap, &client->dev, client, 0, chan, 0,
|
||||
as6812_32x_cpld_mux_select_chan,
|
||||
as6812_32x_cpld_mux_deselect_mux);
|
||||
|
||||
if (data->virt_adaps[chan] == NULL) {
|
||||
ret = -ENODEV;
|
||||
dev_err(&client->dev, "failed to register multiplexed adapter %d\n", chan);
|
||||
goto exit_mux_register;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "registered %d multiplexed busses for I2C mux %s\n",
|
||||
chan, client->name);
|
||||
}
|
||||
|
||||
/* Register sysfs hooks */
|
||||
switch (data->type) {
|
||||
case as6812_32x_cpld1:
|
||||
@@ -553,33 +553,28 @@ static int as6812_32x_cpld_mux_probe(struct i2c_client *client,
|
||||
if (group) {
|
||||
ret = sysfs_create_group(&client->dev.kobj, group);
|
||||
if (ret) {
|
||||
goto add_mux_failed;
|
||||
goto exit_mux_register;
|
||||
}
|
||||
}
|
||||
|
||||
if (chips[data->type].nchans) {
|
||||
dev_info(&client->dev,
|
||||
"registered %d multiplexed busses for I2C %s\n",
|
||||
num, client->name);
|
||||
}
|
||||
else {
|
||||
dev_info(&client->dev,
|
||||
"device %s registered\n", client->name);
|
||||
}
|
||||
|
||||
as6812_32x_cpld_add_client(client);
|
||||
|
||||
return 0;
|
||||
|
||||
add_mux_failed:
|
||||
i2c_mux_del_adapters(muxc);
|
||||
exit_mux_register:
|
||||
for (chan--; chan >= 0; chan--) {
|
||||
i2c_del_mux_adapter(data->virt_adaps[chan]);
|
||||
}
|
||||
kfree(data);
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int as6812_32x_cpld_mux_remove(struct i2c_client *client)
|
||||
{
|
||||
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||
struct as6812_32x_cpld_data *data = i2c_mux_priv(muxc);
|
||||
struct as6812_32x_cpld_data *data = i2c_get_clientdata(client);
|
||||
const struct chip_desc *chip = &chips[data->type];
|
||||
int chan;
|
||||
const struct attribute_group *group = NULL;
|
||||
|
||||
as6812_32x_cpld_remove_client(client);
|
||||
@@ -603,7 +598,14 @@ static int as6812_32x_cpld_mux_remove(struct i2c_client *client)
|
||||
sysfs_remove_group(&client->dev.kobj, group);
|
||||
}
|
||||
|
||||
i2c_mux_del_adapters(muxc);
|
||||
for (chan = 0; chan < chip->nchans; ++chan) {
|
||||
if (data->virt_adaps[chan]) {
|
||||
i2c_del_mux_adapter(data->virt_adaps[chan]);
|
||||
data->virt_adaps[chan] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -652,7 +654,8 @@ int as6812_32x_cpld_read(unsigned short cpld_addr, u8 reg)
|
||||
|
||||
mutex_lock(&list_lock);
|
||||
|
||||
list_for_each(list_node, &cpld_client_list) {
|
||||
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) {
|
||||
|
||||
@@ -396,7 +396,7 @@ static struct platform_driver accton_as6812_32x_fan_driver = {
|
||||
static int __init accton_as6812_32x_fan_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
||||
ret = platform_driver_register(&accton_as6812_32x_fan_driver);
|
||||
if (ret < 0) {
|
||||
goto exit;
|
||||
|
||||
@@ -32,6 +32,11 @@
|
||||
extern int as6812_32x_cpld_read (unsigned short cpld_addr, u8 reg);
|
||||
extern int as6812_32x_cpld_write(unsigned short cpld_addr, u8 reg, u8 value);
|
||||
|
||||
extern void led_classdev_unregister(struct led_classdev *led_cdev);
|
||||
extern int led_classdev_register(struct device *parent, struct led_classdev *led_cdev);
|
||||
extern void led_classdev_resume(struct led_classdev *led_cdev);
|
||||
extern void led_classdev_suspend(struct led_classdev *led_cdev);
|
||||
|
||||
#define DRVNAME "as6812_32x_led"
|
||||
|
||||
struct accton_as6812_32x_led_data {
|
||||
|
||||
Reference in New Issue
Block a user