Skip to content

Commit

Permalink
Merge pull request #1779 from mudsut4ke/202012.7eb6abdc_blackstone-de…
Browse files Browse the repository at this point in the history
…v-switch-driver

[device/celestica-blackstone]: Update switch CPLD driver follow FPGA i2c buses
  • Loading branch information
Wirut Getbamrung authored Sep 29, 2021
2 parents f7b0da1 + 656c763 commit deef22e
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 129 deletions.
Original file line number Diff line number Diff line change
@@ -1 +1 @@
obj-m := baseboard-lpc.o mc24lc64t.o cls-fpga.o xcvr-cls.o switch_cpld.o cls-i2c-ocores.o
obj-m := baseboard-lpc.o mc24lc64t.o cls-fpga.o xcvr-cls.o misc_cpld.o cls-i2c-ocores.o
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
/*
* switch_cpld.c - i2c driver for Blackstone DP switchboard CPLD1/CPLD2
* misc_cpld.c - i2c driver for Blackstone MISC CPLD1/CPLD2
* provides sysfs interfaces to access CPLD register and control port LEDs
*
* Author: Budsakol Sirirattanasakul
*
* Copyright (C) 2021 Celestica Corp.
*
* This program is free software; you can redistribute it and/or modify
Expand All @@ -17,27 +15,22 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/hwmon.h>

#define CPLD1_ADDR 0x30
#define CPLD2_ADDR 0x31

#define SCRATCH_ADDR 0x01
#define LED_OPMODE 0x09
#define LED_TEST 0x0A

struct switch_cpld_data {
struct mutex lock;
struct misc_cpld_data {
struct i2c_client *client;
struct i2c_client *client2;
uint8_t read_addr;
};

static ssize_t getreg_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct switch_cpld_data *data = dev_get_drvdata(dev);
struct misc_cpld_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
int value;

Expand All @@ -53,7 +46,7 @@ static ssize_t getreg_store(struct device *dev, struct device_attribute *attr,
{
uint8_t value;
ssize_t status;
struct switch_cpld_data *data = dev_get_drvdata(dev);
struct misc_cpld_data *data = dev_get_drvdata(dev);

status = kstrtou8(buf, 0, &value);
if (status != 0)
Expand All @@ -69,7 +62,7 @@ static ssize_t setreg_store(struct device *dev, struct device_attribute *attr,
{
uint8_t addr, value;
ssize_t status;
struct switch_cpld_data *data = dev_get_drvdata(dev);
struct misc_cpld_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
char *tok;

Expand All @@ -96,7 +89,7 @@ static ssize_t setreg_store(struct device *dev, struct device_attribute *attr,
static ssize_t scratch_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct switch_cpld_data *data = dev_get_drvdata(dev);
struct misc_cpld_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
int value;

Expand All @@ -112,7 +105,7 @@ static ssize_t scratch_store(struct device *dev, struct device_attribute *attr,
{
uint8_t value;
ssize_t status;
struct switch_cpld_data *data = dev_get_drvdata(dev);
struct misc_cpld_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;

status = kstrtou8(buf, 0, &value);
Expand All @@ -128,30 +121,25 @@ DEVICE_ATTR_RW(getreg);
DEVICE_ATTR_WO(setreg);
DEVICE_ATTR_RW(scratch);

static struct attribute *switch_cpld_attrs[] = {
static struct attribute *misc_cpld_attrs[] = {
&dev_attr_getreg.attr,
&dev_attr_setreg.attr,
&dev_attr_scratch.attr,
NULL,
};
ATTRIBUTE_GROUPS(switch_cpld);
ATTRIBUTE_GROUPS(misc_cpld);

static ssize_t port_led_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int led_mode_1, led_mode_2;
struct switch_cpld_data *data = dev_get_drvdata(dev);
struct misc_cpld_data *data = dev_get_drvdata(dev);
struct i2c_client *client1 = data->client;
struct i2c_client *client2 = data->client2;

led_mode_1 = i2c_smbus_read_byte_data(client1, LED_OPMODE);
if (led_mode_1 < 0)
return led_mode_1;

led_mode_2 = i2c_smbus_read_byte_data(client2, LED_OPMODE);
if (led_mode_2 < 0)
return led_mode_2;

return sprintf(buf, "%s %s\n",
led_mode_1 ? "test" : "normal",
led_mode_2 ? "test" : "normal");
Expand All @@ -163,9 +151,8 @@ static ssize_t port_led_mode_store(struct device *dev,
{
int status;
uint8_t led_mode;
struct switch_cpld_data *data = dev_get_drvdata(dev);
struct misc_cpld_data *data = dev_get_drvdata(dev);
struct i2c_client *client1 = data->client;
struct i2c_client *client2 = data->client2;

if (sysfs_streq(buf, "test"))
led_mode = 0x01;
Expand All @@ -179,30 +166,20 @@ static ssize_t port_led_mode_store(struct device *dev,
return status;
}

status = i2c_smbus_write_byte_data(client2, LED_OPMODE, led_mode);
if (status != 0) {
return status;
}

return size;
}

static ssize_t port_led_color_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int led_color1, led_color2;
struct switch_cpld_data *data = dev_get_drvdata(dev);
struct misc_cpld_data *data = dev_get_drvdata(dev);
struct i2c_client *client1 = data->client;
struct i2c_client *client2 = data->client2;

led_color1 = i2c_smbus_read_byte_data(client1, LED_TEST);
if (led_color1 < 0)
return led_color1;

led_color2 = i2c_smbus_read_byte_data(client2, LED_TEST);
if (led_color2 < 0)
return led_color2;

return sprintf(buf, "%s %s\n",
led_color1 == 0x02 ? "green" :
led_color1 == 0x01 ? "amber" : "off",
Expand All @@ -222,9 +199,8 @@ static ssize_t port_led_color_store(struct device *dev,
{
int status;
uint8_t led_color1, led_color2;
struct switch_cpld_data *data = dev_get_drvdata(dev);
struct misc_cpld_data *data = dev_get_drvdata(dev);
struct i2c_client *client1 = data->client;
struct i2c_client *client2 = data->client2;

if (sysfs_streq(buf, "off")) {
led_color1 = 0x07;
Expand Down Expand Up @@ -259,11 +235,6 @@ static ssize_t port_led_color_store(struct device *dev,
return status;
}

status = i2c_smbus_write_byte_data(client2, LED_TEST, led_color2);
if (status != 0) {
return status;
}

return size;
}

Expand All @@ -280,149 +251,87 @@ static struct attribute_group sff_led_groups = {
.attrs = sff_led_attrs,
};

static int switch_cpld_probe(struct i2c_client *client,
static int misc_cpld_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int err;
struct switch_cpld_data *drvdata1, *drvdata2;
struct device *hwmon_dev1, *hwmon_dev2;
struct i2c_client *client2;

if (client->addr != CPLD1_ADDR) {
dev_err(&client->dev, "probe, bad i2c addr: 0x%x\n",
client->addr);
err = -EINVAL;
goto exit;
}
struct misc_cpld_data *drvdata1;
struct device *hwmon_dev1;

if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -EPFNOSUPPORT;

/* CPLD1 */
drvdata1 = devm_kzalloc(&client->dev,
sizeof(struct switch_cpld_data), GFP_KERNEL);
sizeof(struct misc_cpld_data), GFP_KERNEL);

if (!drvdata1) {
err = -ENOMEM;
goto exit;
}

mutex_init(&drvdata1->lock);
drvdata1->client = client;
drvdata1->read_addr = 0x00;
i2c_set_clientdata(client, drvdata1);
hwmon_dev1 = devm_hwmon_device_register_with_groups(&client->dev,
"CPLD1",
"MISC_CPLD",
drvdata1,
switch_cpld_groups);
misc_cpld_groups);

if (IS_ERR(hwmon_dev1)) {
err = PTR_ERR(hwmon_dev1);
goto exit;
}

err = sysfs_create_link(&client->dev.kobj, &hwmon_dev1->kobj, "CPLD1");
err = sysfs_create_link(&client->dev.kobj, &hwmon_dev1->kobj, "MISC_CPLD");
if (err) {
goto exit;
}

/* CPLD2 */
drvdata2 = devm_kzalloc(&client->dev,
sizeof(struct switch_cpld_data), GFP_KERNEL);

if (!drvdata2) {
err = -ENOMEM;
goto err_link;
}

client2 = i2c_new_dummy(client->adapter, CPLD2_ADDR);
if (!client2) {
dev_err(&client->dev, "address 0x%02x unavailable\n",
CPLD2_ADDR);
err = -EADDRINUSE;
goto err_link;
}

mutex_init(&drvdata2->lock);
drvdata2->read_addr = 0x00;
drvdata2->client = client2;
i2c_set_clientdata(client2, drvdata2);

/* attach client2 to be client2 of CPLD1
for later use on port led sysfs */
drvdata1->client2 = client2;

hwmon_dev2 = devm_hwmon_device_register_with_groups(&client2->dev,
"CPLD2",
drvdata2,
switch_cpld_groups);

if (IS_ERR(hwmon_dev2)) {
err = PTR_ERR(hwmon_dev2);
goto err_client2;
}

err = sysfs_create_link(&client->dev.kobj, &hwmon_dev2->kobj, "CPLD2");
if (err) {
goto err_client2;
}

//port led
err = sysfs_create_group(&client->dev.kobj, &sff_led_groups);
if (err) {
dev_err(&client->dev,
"failed to create sysfs attribute group.\n");
goto err_link2;
goto err_link;
}

return 0;

err_link2:
sysfs_remove_link(&client->dev.kobj, "CPLD2");

err_client2:
if (client2)
i2c_unregister_device(client2);

err_link:
sysfs_remove_link(&client->dev.kobj, "CPLD1");
sysfs_remove_link(&client->dev.kobj, "MISC_CPLD");

exit:
dev_err(&client->dev, "probe error %d\n", err);
return err;
}

static int switch_cpld_remove(struct i2c_client *client)
static int misc_cpld_remove(struct i2c_client *client)
{
struct switch_cpld_data *data = i2c_get_clientdata(client);

sysfs_remove_group(&client->dev.kobj, &sff_led_groups);
sysfs_remove_link(&data->client->dev.kobj, "CPLD2");
sysfs_remove_link(&client->dev.kobj, "CPLD1");
i2c_unregister_device(data->client2);
sysfs_remove_link(&client->dev.kobj, "MISC_CPLD");
return 0;
}

static const struct i2c_device_id switch_cpld_ids[] = {
{ "switch_cpld", 0x30 },
static const struct i2c_device_id misc_cpld_ids[] = {
{ "misc_cpld", CPLD1_ADDR },
{ }
};

MODULE_DEVICE_TABLE(i2c, switch_cpld_ids);
MODULE_DEVICE_TABLE(i2c, misc_cpld_ids);

static struct i2c_driver switch_cpld_driver = {
static struct i2c_driver misc_cpld_driver = {
.driver = {
.name = "switch_cpld",
.name = "misc_cpld",
.owner = THIS_MODULE,
},
.probe = switch_cpld_probe,
.remove = switch_cpld_remove,
.id_table = switch_cpld_ids,
.probe = misc_cpld_probe,
.remove = misc_cpld_remove,
.id_table = misc_cpld_ids,
};

module_i2c_driver(switch_cpld_driver);
module_i2c_driver(misc_cpld_driver);

MODULE_AUTHOR("Budsakol Sirirattanasakul<bsirir@celestica.com>");
MODULE_DESCRIPTION("Celestica Blackstone Switchboard CPLD driver");
MODULE_AUTHOR("Wirut Getbamrung<wgetbumr@celestica.com>");
MODULE_DESCRIPTION("Celestica Blackstone MISC_CPLD driver");
MODULE_VERSION("1.0.0");
MODULE_LICENSE("GPL");
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ start)
modprobe cls-i2c-ocores
modprobe cls-fpga
modprobe xcvr-cls
modprobe switch_cpld
modprobe misc_cpld
modprobe i2c-mux-pca954x force_deselect_on_exit=1

# Instantiate TLV EEPROM device on I801 bus
Expand All @@ -37,7 +37,8 @@ start)
decode-syseeprom --init 2> /dev/null &

# Attach switchboard CPLD i2c device
echo switch_cpld 0x30 > /sys/bus/i2c/devices/i2c-3/new_device
echo misc_cpld 0x30 > /sys/bus/i2c/devices/i2c-2/new_device
echo misc_cpld 0x31 > /sys/bus/i2c/devices/i2c-3/new_device

# Attach QSFP-DD i2c devices
echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-1/new_device
Expand Down

0 comments on commit deef22e

Please sign in to comment.