diff --git a/packages/platforms/quanta/x86-64/modules/PKG.yml b/packages/platforms/quanta/x86-64/modules/PKG.yml index dfa9155b..fcb0bda9 100644 --- a/packages/platforms/quanta/x86-64/modules/PKG.yml +++ b/packages/platforms/quanta/x86-64/modules/PKG.yml @@ -1 +1 @@ -!include $ONL_TEMPLATES/no-arch-vendor-modules.yml ARCH=amd64 VENDOR=quanta +!include $ONL_TEMPLATES/arch-vendor-modules.yml ARCH=amd64 VENDOR=quanta KERNELS="onl-kernel-3.16-lts-x86-64-all:amd64" diff --git a/packages/platforms/quanta/x86-64/modules/builds/.gitignore b/packages/platforms/quanta/x86-64/modules/builds/.gitignore new file mode 100644 index 00000000..a65b4177 --- /dev/null +++ b/packages/platforms/quanta/x86-64/modules/builds/.gitignore @@ -0,0 +1 @@ +lib diff --git a/packages/platforms/quanta/x86-64/modules/builds/Makefile b/packages/platforms/quanta/x86-64/modules/builds/Makefile new file mode 100644 index 00000000..979fc3fe --- /dev/null +++ b/packages/platforms/quanta/x86-64/modules/builds/Makefile @@ -0,0 +1,6 @@ +KERNELS := onl-kernel-3.16-lts-x86-64-all:amd64 +KMODULES := $(wildcard *.c) +VENDOR := quanta +BASENAME := common +ARCH := x86_64 +include $(ONL)/make/kmodule.mk diff --git a/packages/platforms/quanta/x86-64/modules/builds/qci_cpld.c b/packages/platforms/quanta/x86-64/modules/builds/qci_cpld.c new file mode 100755 index 00000000..678b1dc1 --- /dev/null +++ b/packages/platforms/quanta/x86-64/modules/builds/qci_cpld.c @@ -0,0 +1,603 @@ +/* + * A CPLD driver for monitor QSFP28 module I/O + * + * The CPLD is customize by Quanta for controlling QSFP28 module signals, + * they are RESET , INTERREPT , Module_Present, LPMODE + * Each CPLD control 16 modules, each module use 4 bits in register. + * + * Copyright (C) 2015 Quanta Inc. + * + * Author: Luffy Cheng + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static DEFINE_IDA(cpld_ida); + +enum platform_type { + SFP = 0, + QSFP, + QSFP28, + NONE +}; + +static struct class *cpld_class = NULL; + +struct sfp_data { + struct i2c_client *cpld_client; + char name[8]; + char type[8]; + u8 port_id; + u8 cpld_port; +}; + +struct cpld_data { + struct mutex lock; + struct device *port_dev[16]; + struct sfp_data *port_data[16]; +}; + +static int cpld_probe(struct i2c_client *client, + const struct i2c_device_id *id); +static int cpld_remove(struct i2c_client *client); + +static const struct i2c_device_id cpld_id[] = { + { "CPLD-SFP", SFP }, + { "CPLD-QSFP", QSFP }, + { "CPLD-QSFP28", QSFP28 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cpld_id); + +static struct i2c_driver cpld_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "qci_cpld", + }, + .probe = cpld_probe, + .remove = cpld_remove, + .id_table = cpld_id, +// .address_list = normal_i2c, +}; + +#define CPLD_ID_PREFIX "port-" +#define CPLD_ID_FORMAT CPLD_ID_PREFIX "%d" + +#define RESET_MASK 0x08 +#define INTERRUPT_MASK 0x04 +#define MODULE_PRESENT_MASK 0x02 +#define LPMODE_MASK 0x01 +//#define I2C_MONITOR_MASK 0x01 + +static inline u8 get_group_cmd(u8 group) +{ + //FIXME: if group cmd change + return (group + 1); +} + +static inline u8 port_remapping(u8 phy_port) +{ + /* FIXME: implement by hardware design */ + /* The CPLD register port mapping is weird : + * MSB -------- LSB (word data) + * P3 P4 P1 P2 (per port 4 bits) + * For easy coding bit shift, we treat it as hw port swap + */ + return (phy_port % 2) ? (phy_port - 1) : (phy_port + 1); +} + +static ssize_t get_reset(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sfp_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = (u8)(data->cpld_port / 4); + u8 group_port = data->cpld_port % 4; + s32 value; + + dev_dbg(&client->dev, "port_id %d => cpld_port %d, group %d(%d)\n", data->port_id, + data->cpld_port + 1, group + 1, group_port + 1); + + value = i2c_smbus_read_word_data(client, get_group_cmd(group)); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group + 1, value); + + value >>= (group_port * 4); + value &= RESET_MASK; + + return sprintf(buf, "%d\n", value ? 1 : 0); +} + +static ssize_t get_interrupt(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sfp_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = (u8)(data->cpld_port / 4); + u8 group_port = data->cpld_port % 4; + s32 value; + + dev_dbg(&client->dev, "port_id %d => cpld_port %d, group %d(%d)\n", data->port_id, + data->cpld_port + 1, group + 1, group_port + 1); + + value = i2c_smbus_read_word_data(client, get_group_cmd(group)); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group + 1, value); + + value >>= (group_port * 4); + value &= INTERRUPT_MASK; + + return sprintf(buf, "%d\n", value ? 1 : 0); +} + +static ssize_t get_module_present(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sfp_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = (u8)(data->cpld_port / 4); + u8 group_port = data->cpld_port % 4; + s32 value; + + dev_dbg(&client->dev, "port_id %d => cpld_port %d, group %d(%d)\n", data->port_id, + data->cpld_port + 1, group + 1, group_port + 1); + + value = i2c_smbus_read_word_data(client, get_group_cmd(group)); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group + 1, value); + + value >>= (group_port * 4); + value &= MODULE_PRESENT_MASK; + + //FIXME: if present is not low active + return sprintf(buf, "%d\n", value ? 0 : 1); +} + +static ssize_t get_lpmode(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sfp_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = (u8)(data->cpld_port / 4); + u8 group_port = data->cpld_port % 4; + s32 value; + + dev_dbg(&client->dev, "port_id %d => cpld_port %d, group %d(%d)\n", data->port_id, + data->cpld_port + 1, group + 1, group_port + 1); + + value = i2c_smbus_read_word_data(client, get_group_cmd(group)); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group + 1, value); + + value >>= (group_port * 4); + value &= LPMODE_MASK; + + return sprintf(buf, "%d\n", value ? 1 : 0); +} + +static ssize_t set_reset(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sfp_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = (u8)(data->cpld_port / 4); + u8 group_port = data->cpld_port % 4; + s32 value; + long disable; + + dev_dbg(&client->dev, "port_id %d => cpld_port %d, group %d(%d)\n", data->port_id, + data->cpld_port + 1, group + 1, group_port + 1); + + if (kstrtol(buf, 0, &disable)) + return -EINVAL; + + if ((disable != 1) && (disable != 0)) + return -EINVAL; + +// mutex_lock(&data->lock); + value = i2c_smbus_read_word_data(client, get_group_cmd(group)); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group + 1, value); + + value &= ~(RESET_MASK << (group_port * 4)); + if (disable) + value |= (RESET_MASK << (group_port * 4)); + + dev_dbg(&client->dev, "write group%d value= %x\n", group + 1, value); + + i2c_smbus_write_word_data(client, get_group_cmd(group), (u16)value); +// mutex_unlock(&data->lock); + + return count; +} + +static ssize_t set_lpmode(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sfp_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = (u8)(data->cpld_port / 4); + u8 group_port = data->cpld_port % 4; + s32 value; + long disable; + + dev_dbg(&client->dev, "port_id %d => cpld_port %d, group %d(%d)\n", data->port_id, + data->cpld_port + 1, group + 1, group_port + 1); + + if (kstrtol(buf, 0, &disable)) + return -EINVAL; + + if ((disable != 1) && (disable != 0)) + return -EINVAL; + +// mutex_lock(&data->lock); + value = i2c_smbus_read_word_data(client, get_group_cmd(group)); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group + 1, value); + + value &= ~(LPMODE_MASK << (group_port * 4)); + if (disable) + value |= (LPMODE_MASK << (group_port * 4)); + + dev_dbg(&client->dev, "write group%d value= %x\n", group + 1, value); + + i2c_smbus_write_word_data(client, get_group_cmd(group), (u16)value); +// mutex_unlock(&data->lock); + + return count; +} + +#if 0 +static ssize_t get_led_enable(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sfp_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = 3; + u8 group_port = data->cpld_port; + s32 value; + + dev_dbg(&client->dev, "get_led_enable port_id %d => cpld_port %d, group %d(%d)\n", data->port_id, + data->cpld_port + 1, group, group_port + 1); + + value = i2c_smbus_read_word_data(client, group); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group, value); + + value >>= (group_port); + value &= LED_ENABLE_MASK; + + return sprintf(buf, "%d\n", value ? 1 : 0); +} + +static ssize_t set_led_enable(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sfp_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = 3; + u8 group_port = data->cpld_port; + s32 value; + long disable; + + dev_dbg(&client->dev, "set_led_enable port_id %d => cpld_port %d, group %d(%d)\n", data->port_id, + data->cpld_port + 1, group, group_port + 1); + + if (kstrtol(buf, 0, &disable)) + return -EINVAL; + + if ((disable != 1) && (disable != 0)) + return -EINVAL; + +// mutex_lock(&data->lock); + value = i2c_smbus_read_word_data(client, group); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group, value); + + value &= ~(LED_ENABLE_MASK << group_port); + if (disable) + value |= (LED_ENABLE_MASK << group_port); + + dev_dbg(&client->dev, "write group%d value= %x\n", group, value); + + i2c_smbus_write_word_data(client, group, (u16)value); +// mutex_unlock(&data->lock); + + return count; +} +#endif + +#if 0 +static ssize_t get_monitor_enable(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct i2c_monitor_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = 4; + s32 value; + + value = i2c_smbus_read_word_data(client, group); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group, value); + + value &= I2C_MONITOR_MASK; + + return sprintf(buf, "%d\n", value ? 1 : 0); +} + +static ssize_t set_monitor_enable(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct i2c_monitor_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = 4; + s32 value; + long disable; + + if (kstrtol(buf, 0, &disable)) + return -EINVAL; + + if ((disable != 1) && (disable != 0)) + return -EINVAL; + +// mutex_lock(&data->lock); + value = i2c_smbus_read_word_data(client, group); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group, value); + + value &= ~(I2C_MONITOR_MASK); + if (disable) + value |= (I2C_MONITOR_MASK); + + dev_dbg(&client->dev, "write group%d value= %x\n", group, value); + + i2c_smbus_write_word_data(client, group, (u16)value); +// mutex_unlock(&data->lock); + + return count; +} +#endif + +static DEVICE_ATTR(reset, S_IWUSR | S_IRUGO, get_reset, set_reset); +static DEVICE_ATTR(lpmode, S_IWUSR | S_IRUGO, get_lpmode, set_lpmode); +static DEVICE_ATTR(module_present, S_IRUGO, get_module_present, NULL); +static DEVICE_ATTR(interrupt, S_IRUGO, get_interrupt, NULL); +//static DEVICE_ATTR(led_enable, S_IWUSR | S_IRUGO, get_led_enable, set_led_enable); +//static DEVICE_ATTR(monitor_enable, S_IWUSR | S_IRUGO, get_monitor_enable, set_monitor_enable); + +static const struct attribute *sfp_attrs[] = { + &dev_attr_reset.attr, + &dev_attr_lpmode.attr, + &dev_attr_module_present.attr, + &dev_attr_interrupt.attr, +// &dev_attr_led_enable.attr, + NULL, +}; + +static const struct attribute_group sfp_attr_group = { + .attrs = (struct attribute **) sfp_attrs, +}; + +#if 0 +static const struct attribute *i2c_monitor_attrs[] = { + &dev_attr_monitor_enable.attr, + NULL, +}; + +static const struct attribute_group i2c_monitor_attr_group = { + .attrs = (struct attribute **) i2c_monitor_attrs, +}; +#endif + +static int cpld_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct cpld_data *data; + struct sfp_data *port_data; +// struct i2c_monitor_data *monitor_data; + struct device *port_dev; +// struct device *i2c_dev; + int port_nr, i=0, err, max_port_num; + char name[I2C_NAME_SIZE], type[I2C_NAME_SIZE]; + + printk("cpld cpld_probe\n"); + + while(id->name[i]) + { + name[i]=tolower(id->name[i]); + i++; + } + name[i]='\0'; + strncpy(type,name+5,strlen(name)-5); + type[strlen(name)-5]='\0'; + + if (!cpld_class) + { + cpld_class = class_create(THIS_MODULE, name); + if (IS_ERR(cpld_class)) { + pr_err("couldn't create sysfs class\n"); + return PTR_ERR(cpld_class); + } + } + + data = devm_kzalloc(&client->dev, sizeof(struct cpld_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + if(!strcmp(client->name, "CPLD-QSFP28")){ + max_port_num = 16; + } + else{ + max_port_num = 4; + } + + /* register sfp port data to sysfs */ + for (i = 0; i < max_port_num; i++) + { + port_nr = ida_simple_get(&cpld_ida, 1, 99, GFP_KERNEL); + if (port_nr < 0) + return ERR_PTR(port_nr); + + port_data = kzalloc(sizeof(struct sfp_data), GFP_KERNEL); + + port_dev = device_create(cpld_class, &client->dev, MKDEV(0,0), port_data, CPLD_ID_FORMAT, port_nr); + if (IS_ERR(port_dev)) { + err = PTR_ERR(port_dev); + printk("err_status\n"); + } + + data->port_dev[i] = port_dev; + data->port_data[i] = port_data; + + strcpy(port_data->type, type); + + dev_info(&client->dev, "Register %s port-%d\n", port_data->type , port_nr); + + /* FIXME: implement Logical/Physical port remapping */ + //port_data->cpld_port = i; + port_data->cpld_port = port_remapping(i); + sprintf(port_data->name, "port-%d", port_nr); + port_data->port_id = port_nr; + dev_set_drvdata(port_dev, port_data); + port_dev->init_name = port_data->name; + port_data->cpld_client = client; + + err = sysfs_create_group(&port_dev->kobj, &sfp_attr_group); + // if (status) printk("err status\n"); + } +#if 0 + /* register i2c monitor to sysfs */ + monitor_data = kzalloc(sizeof(struct i2c_monitor_data), GFP_KERNEL); + + i2c_dev = device_create(cpld_class, &client->dev, MKDEV(0, 0), monitor_data, "i2c_monitor"); + if (IS_ERR(i2c_dev)) { + err = PTR_ERR(i2c_dev); + printk("i2c_dev err_status\n"); + } + + monitor_data->cpld_client = client; + err = sysfs_create_group(&i2c_dev->kobj, &i2c_monitor_attr_group); + if (err) + printk("err sysfs\n"); +#endif + i2c_set_clientdata(client, data); + mutex_init(&data->lock); + + dev_info(&client->dev, "%s device found\n", client->name); + + + return 0; + +//FIXME: implement error check +//exit_remove: +// sysfs_remove_group(&client->dev.kobj, &data->attrs); + return err; +} + +/* FIXME: for older kernel doesn't with idr_is_empty function, implement here */ +#if 1 +static int idr_has_entry(int id, void *p, void *data) +{ + return 1; +} + +static bool cpld_idr_is_empty(struct idr *idp) +{ + return !idr_for_each(idp, idr_has_entry, NULL); +} +#endif + +static int cpld_remove(struct i2c_client *client) +{ + struct cpld_data *data = i2c_get_clientdata(client); + int i, max_port_num; +// int id; + + if(!strcmp(client->name, "CPLD-QSFP28")){ + max_port_num = 16; + } + else{ + max_port_num = 4; + } + + for (i = (max_port_num - 1); i >= 0; i--) + { + dev_info(data->port_dev[i], "Remove %s port-%d\n", data->port_data[i]->type , data->port_data[i]->port_id); + device_unregister(data->port_dev[i]); + ida_simple_remove(&cpld_ida, data->port_data[i]->port_id); + kfree(data->port_data[i]); + } + + if (cpld_idr_is_empty(&cpld_ida.idr)) + class_destroy(cpld_class); + + return 0; +} + +module_i2c_driver(cpld_driver); + +MODULE_AUTHOR("Luffy Cheng "); +MODULE_DESCRIPTION("Quanta Switch QSFP28 CPLD driver"); +MODULE_LICENSE("GPL"); diff --git a/packages/platforms/quanta/x86-64/modules/builds/quanta_hwmon.c b/packages/platforms/quanta/x86-64/modules/builds/quanta_hwmon.c new file mode 100644 index 00000000..244d9a9e --- /dev/null +++ b/packages/platforms/quanta/x86-64/modules/builds/quanta_hwmon.c @@ -0,0 +1,250 @@ +/* + * + * + * Copyright 2013, 2014 BigSwitch Networks, Inc. + * + * This program is free software; you can redistribute it + * and/or modify it under the terms ofthe GNU General Public License as + * published by the Free Software Foundation; either version 2 of the License, + * or (at your option) any later version. + * + * + * + * + * A hwmon driver for the Quanta LY6 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const unsigned short normal_i2c[] = { 0x4E, I2C_CLIENT_END }; + +#define QUANTA_HWMON_REG_TEMP_INPUT_BASE 0x20 +#define QUANTA_HWMON_REG_FAN_MODE 0x33 +#define QUANTA_HWMON_REG_FAN_DIR 0x56 +#define QUANTA_HWMON_REG_FAN_PWM_BASE 0x3C +#define QUANTA_HWMON_REG_FAN_INPUT_BASE 0x40 + +#define QUANTA_HWMON_FAN_MANUAL_MODE 1 +#define QUANTA_HWMON_FAN_SMART_MODE 3 + +#define QUANTA_HWMON_NUM_FANS 6 + +struct quanta_hwmon_data { + struct device *hwmon_dev; + struct attribute_group attrs; + struct mutex lock; +}; + +enum quanta_hwmon_s { + quanta_ly6_hwmon, + quanta_ly6f_hwmon, + quanta_ly8_hwmon, + quanta_ly9_hwmon, +}; + +static int quanta_hwmon_probe(struct i2c_client *client, + const struct i2c_device_id *id); +static int quanta_hwmon_remove(struct i2c_client *client); + +static const struct i2c_device_id quanta_hwmon_id[] = { + { "quanta_ly6_hwmon", quanta_ly6_hwmon }, + { "quanta_ly6f_hwmon", quanta_ly6f_hwmon }, + { "quanta_ly8_hwmon", quanta_ly8_hwmon }, + { "quanta_ly9_hwmon", quanta_ly9_hwmon }, + { } +}; +MODULE_DEVICE_TABLE(i2c, quanta_hwmon_id); + +static struct i2c_driver quanta_hwmon_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "quanta_hwmon", + }, + .probe = quanta_hwmon_probe, + .remove = quanta_hwmon_remove, + .id_table = quanta_hwmon_id, + .address_list = normal_i2c, +}; + +static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct quanta_hwmon_data *data = i2c_get_clientdata(client); + int temp; + + mutex_lock(&data->lock); + temp = i2c_smbus_read_byte_data(client, + QUANTA_HWMON_REG_TEMP_INPUT_BASE + + attr->index); + mutex_unlock(&data->lock); + return sprintf(buf, "%d\n", 1000 * temp); +} + +static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct quanta_hwmon_data *data = i2c_get_clientdata(client); + int fan; + + mutex_lock(&data->lock); + fan = i2c_smbus_read_word_swapped(client, + QUANTA_HWMON_REG_FAN_INPUT_BASE + + 2 * attr->index); + mutex_unlock(&data->lock); + return sprintf(buf, "%d\n", fan); +} + +static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct quanta_hwmon_data *data = i2c_get_clientdata(client); + int pwm; + + mutex_lock(&data->lock); + pwm = i2c_smbus_read_word_swapped(client, + QUANTA_HWMON_REG_FAN_PWM_BASE + + 2 * attr->index); + mutex_unlock(&data->lock); + return sprintf(buf, "%d\n", pwm * 255 / 10000); +} + +static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct i2c_client *client = to_i2c_client(dev); + struct quanta_hwmon_data *data = i2c_get_clientdata(client); + long val; + int ret; + + ret = kstrtol(buf, 10, &val); + if (ret) + return ret; + mutex_lock(&data->lock); + i2c_smbus_write_word_swapped(client, + QUANTA_HWMON_REG_FAN_PWM_BASE + + 2 * attr->index, val * 10000 / 255); + mutex_unlock(&data->lock); + return count; +} + +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2); +static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3);//For LY9 +static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4); +static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5); +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); +static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); +static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2); +static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4); +static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, show_fan, NULL, 5); +static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, show_fan, NULL, 6); +static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0); + +static struct attribute *quanta_hwmon_attr[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp5_input.dev_attr.attr, + &sensor_dev_attr_temp6_input.dev_attr.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan5_input.dev_attr.attr, + &sensor_dev_attr_fan6_input.dev_attr.attr, + &sensor_dev_attr_fan7_input.dev_attr.attr, + &sensor_dev_attr_pwm1.dev_attr.attr, + NULL +}; + +static struct attribute *quanta_hwmon_attr_6temps_3fans[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp5_input.dev_attr.attr, + &sensor_dev_attr_temp6_input.dev_attr.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_fan2_input.dev_attr.attr, + &sensor_dev_attr_fan3_input.dev_attr.attr, + &sensor_dev_attr_fan5_input.dev_attr.attr, + &sensor_dev_attr_fan6_input.dev_attr.attr, + &sensor_dev_attr_fan7_input.dev_attr.attr, + &sensor_dev_attr_pwm1.dev_attr.attr, + NULL +}; + +static int quanta_hwmon_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct quanta_hwmon_data *data; + int err; + + data = devm_kzalloc(&client->dev, sizeof(struct quanta_hwmon_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + i2c_set_clientdata(client, data); + mutex_init(&data->lock); + + dev_info(&client->dev, "%s chip found\n", client->name); + + if(!strcmp(client->name, "quanta_ly9_hwmon")){ + data->attrs.attrs = quanta_hwmon_attr_6temps_3fans; + } + else{ + data->attrs.attrs = quanta_hwmon_attr; + } + err = sysfs_create_group(&client->dev.kobj, &data->attrs); + if (err) + return err; + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + err = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + i2c_smbus_write_byte_data(client, + QUANTA_HWMON_REG_FAN_MODE, + QUANTA_HWMON_FAN_SMART_MODE); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &data->attrs); + return err; +} + +static int quanta_hwmon_remove(struct i2c_client *client) +{ + struct quanta_hwmon_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &data->attrs); + return 0; +} + +module_i2c_driver(quanta_hwmon_driver); + +MODULE_AUTHOR("QCT Technical "); +MODULE_DESCRIPTION("Quanta LY6 hardware monitor driver"); +MODULE_LICENSE("GPL"); diff --git a/packages/platforms/quanta/x86-64/modules/builds/quanta_switch.c b/packages/platforms/quanta/x86-64/modules/builds/quanta_switch.c new file mode 100644 index 00000000..979b32af --- /dev/null +++ b/packages/platforms/quanta/x86-64/modules/builds/quanta_switch.c @@ -0,0 +1,499 @@ +/* + * Quanta Switch platform driver + * + * + * Copyright (C) 2014 Quanta Computer inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define DRIVER_NAME "quanta-switch" +#define VENDOR_NAME "Quanta" +#define PRODUCT_NAME_LY6 "Quanta LY6" +#define PRODUCT_NAME_LY8 "Quanta LY8" +#define PRODUCT_NAME_LY9 "Quanta LY9" + +#define MAX_I2C_CLIENTS 512 +#define I2C_GPIO_BASE 0x80 +#define XSTR(x) STR(X) +#define STR(x) #x + +enum i2c_types { + i2c_type_spd, + i2c_type_rtc, + i2c_type_pca9546, + i2c_type_pca9548, + i2c_type_pca9554, + i2c_type_pca9555, + i2c_type_pca9698, + i2c_type_quanta_ly6_i2c_mux, + i2c_type_qci_cpld_4_ports, + i2c_type_24c02, + i2c_type_pmbus, + i2c_type_emerson700, + i2c_type_quanta_ly6_hwmon, + i2c_type_quanta_ly8_hwmon, + i2c_type_quanta_ly9_hwmon, +}; + +char *i2c_type_names[] = { + "spd", + "ds1339", + "pca9546", + "pca9548", + "pca9554", + "pca9555", + "pca9698", + "quanta_ly6_i2c_mux", + "CPLD-QSFP", + "24c02", + "pmbus", + "emerson700", + "quanta_ly6_hwmon", + "quanta_ly8_hwmon", + "quanta_ly9_hwmon", +}; + +struct i2c_init_data { + int parent_bus; + int type; + int addr; + int busno; + int gpio_base; + char name[I2C_NAME_SIZE]; +}; + +static struct i2c_init_data quanta_ly6_i2c_init_data[] = { + { .parent_bus = (0x00 + 0), .type = i2c_type_pca9546, .addr = 0x71, .busno = 0x02, .name = "PCA9546(CPU)\0" }, + { .parent_bus = (0x02 + 0), .type = i2c_type_pca9555, .addr = 0x20, .gpio_base = 0x40, .name = "PCA9555_1(CPU)\0" }, + + { .parent_bus = (0x00 + 0), .type = i2c_type_quanta_ly6_hwmon, .addr = 0x4e, .name = "PSoc\0" }, + { .parent_bus = (0x00 + 0), .type = i2c_type_spd, .addr = 0x52, .name = "SPD\0" }, + { .parent_bus = (0x00 + 0), .type = i2c_type_rtc, .addr = 0x68, .name = "RTC\0" }, + { .parent_bus = (0x00 + 0), .type = i2c_type_pca9548, .addr = 0x77, .busno = 0x10, .name = "PCA9548_1\0" }, + + { .parent_bus = (0x10 + 0), .type = i2c_type_pca9548, .addr = 0x73, .busno = 0x20, .name = "PCA9548(SFP_1-8)\0" }, + { .parent_bus = (0x10 + 1), .type = i2c_type_pca9548, .addr = 0x74, .busno = 0x28, .name = "PCA9548(SFP_9-16)\0" }, + { .parent_bus = (0x10 + 2), .type = i2c_type_pca9548, .addr = 0x75, .busno = 0x30, .name = "PCA9548(SFP_17-24)\0" }, + { .parent_bus = (0x10 + 3), .type = i2c_type_pca9548, .addr = 0x76, .busno = 0x38, .name = "PCA9548(SFP_25-32)\0" }, + { .parent_bus = (0x10 + 4), .type = i2c_type_quanta_ly6_i2c_mux, .addr = 0x3a, .name = "quanta_ly6_i2c_mux1\0" }, + { .parent_bus = (0x10 + 5), .type = i2c_type_quanta_ly6_i2c_mux, .addr = 0x3b, .name = "quanta_ly6_i2c_mux2\0" }, + { .parent_bus = (0x10 + 6), .type = i2c_type_pca9555, .addr = 0x24, .name = "PCA9555_3(FAN)\0" }, + { .parent_bus = (0x10 + 7), .type = i2c_type_pca9555, .addr = 0x23, .name = "PCA9555_4(QSFP_EN)\0" }, + { .parent_bus = (0x20 + 0), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_1_EEPROM\0" }, + { .parent_bus = (0x20 + 1), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_2_EEPROM\0" }, + { .parent_bus = (0x20 + 2), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_3_EEPROM\0" }, + { .parent_bus = (0x20 + 3), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_4_EEPROM\0" }, + { .parent_bus = (0x20 + 4), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_5_EEPROM\0" }, + { .parent_bus = (0x20 + 5), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_6_EEPROM\0" }, + { .parent_bus = (0x20 + 6), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_7_EEPROM\0" }, + { .parent_bus = (0x20 + 7), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_8_EEPROM\0" }, + { .parent_bus = (0x28 + 0), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_9_EEPROM\0" }, + { .parent_bus = (0x28 + 1), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_10_EEPROM\0" }, + { .parent_bus = (0x28 + 2), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_11_EEPROM\0" }, + { .parent_bus = (0x28 + 3), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_12_EEPROM\0" }, + { .parent_bus = (0x28 + 4), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_13_EEPROM\0" }, + { .parent_bus = (0x28 + 5), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_14_EEPROM\0" }, + { .parent_bus = (0x28 + 6), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_15_EEPROM\0" }, + { .parent_bus = (0x28 + 7), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_16_EEPROM\0" }, + { .parent_bus = (0x30 + 0), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_17_EEPROM\0" }, + { .parent_bus = (0x30 + 1), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_18_EEPROM\0" }, + { .parent_bus = (0x30 + 2), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_19_EEPROM\0" }, + { .parent_bus = (0x30 + 3), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_20_EEPROM\0" }, + { .parent_bus = (0x30 + 4), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_21_EEPROM\0" }, + { .parent_bus = (0x30 + 5), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_22_EEPROM\0" }, + { .parent_bus = (0x30 + 6), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_23_EEPROM\0" }, + { .parent_bus = (0x30 + 7), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_24_EEPROM\0" }, + { .parent_bus = (0x38 + 0), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_25_EEPROM\0" }, + { .parent_bus = (0x38 + 1), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_26_EEPROM\0" }, + { .parent_bus = (0x38 + 2), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_27_EEPROM\0" }, + { .parent_bus = (0x38 + 3), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_28_EEPROM\0" }, + { .parent_bus = (0x38 + 4), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_29_EEPROM\0" }, + { .parent_bus = (0x38 + 5), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_30_EEPROM\0" }, + { .parent_bus = (0x38 + 6), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_31_EEPROM\0" }, + { .parent_bus = (0x38 + 7), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_32_EEPROM\0" }, + + { .parent_bus = (0x00 + 0), .type = i2c_type_pca9546, .addr = 0x72, .busno = 0x18, .name = "PCA9546\0" }, + { .parent_bus = (0x18 + 0), .type = i2c_type_pmbus, .addr = 0x58, .name = "PSU_1\0" }, /* RPSU 1 */ + { .parent_bus = (0x18 + 1), .type = i2c_type_pmbus, .addr = 0x59, .name = "PSU_2\0" }, /* RPSU 2 */ + { .parent_bus = (0x18 + 2), .type = i2c_type_pca9555, .addr = 0x26, .name = "PCA9555_PSU\0" }, + { .parent_bus = (0x18 + 3), .type = i2c_type_24c02, .addr = 0x54, .name = "Board_EEPROM\0" }, +}; + +static struct i2c_init_data quanta_ly8_i2c_init_data[] = { + { .parent_bus = (0x00 + 0), .type = i2c_type_pca9546, .addr = 0x71, .busno = 0x02, .name = "PCA9546(CPU)\0" }, + { .parent_bus = (0x02 + 0), .type = i2c_type_pca9555, .addr = 0x20, .gpio_base = 0x40, .name = "PCA9555_1(CPU)\0" }, + + { .parent_bus = (0x00 + 0), .type = i2c_type_quanta_ly8_hwmon, .addr = 0x4e, .name = "PSoc\0" }, + { .parent_bus = (0x00 + 0), .type = i2c_type_spd, .addr = 0x52, .name = "SPD\0" }, + { .parent_bus = (0x00 + 0), .type = i2c_type_rtc, .addr = 0x68, .name = "RTC\0" }, + { .parent_bus = (0x00 + 0), .type = i2c_type_pca9548, .addr = 0x77, .busno = 0x10, .name = "PCA9548_1\0" }, + + { .parent_bus = (0x10 + 1), .type = i2c_type_pca9548, .addr = 0x73, .busno = 0x20, .name = "PCA9548(SFP_1-8)\0" }, + { .parent_bus = (0x10 + 1), .type = i2c_type_pca9548, .addr = 0x74, .busno = 0x28, .name = "PCA9548(SFP_9-16)\0" }, + { .parent_bus = (0x10 + 1), .type = i2c_type_pca9548, .addr = 0x76, .busno = 0x30, .name = "PCA9548(SFP_17-24)\0" }, + { .parent_bus = (0x10 + 2), .type = i2c_type_pca9548, .addr = 0x73, .busno = 0x38, .name = "PCA9548(SFP_25-32)\0" }, + { .parent_bus = (0x10 + 2), .type = i2c_type_pca9548, .addr = 0x74, .busno = 0x40, .name = "PCA9548(SFP_33-40)\0" }, + { .parent_bus = (0x10 + 2), .type = i2c_type_pca9548, .addr = 0x75, .busno = 0x48, .name = "PCA9548(SFP_41-48)\0" }, + { .parent_bus = (0x10 + 0), .type = i2c_type_pca9554, .addr = 0x25, .name = "PCA9554(PCA9698INT)\0" }, + { .parent_bus = (0x10 + 0), .type = i2c_type_pca9555, .addr = 0x24, .name = "PCA9555_3(FAN)\0" }, + { .parent_bus = (0x10 + 0), .type = i2c_type_pca9555, .addr = 0x23, .name = "PCA9555_4(QSFP_EN)\0" }, + { .parent_bus = (0x20 + 0), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_1_EEPROM\0" }, + { .parent_bus = (0x20 + 1), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_2_EEPROM\0" }, + { .parent_bus = (0x20 + 2), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_3_EEPROM\0" }, + { .parent_bus = (0x20 + 3), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_4_EEPROM\0" }, + { .parent_bus = (0x20 + 4), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_5_EEPROM\0" }, + { .parent_bus = (0x20 + 5), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_6_EEPROM\0" }, + { .parent_bus = (0x20 + 6), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_7_EEPROM\0" }, + { .parent_bus = (0x20 + 7), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_8_EEPROM\0" }, + { .parent_bus = (0x28 + 0), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_9_EEPROM\0" }, + { .parent_bus = (0x28 + 1), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_10_EEPROM\0" }, + { .parent_bus = (0x28 + 2), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_11_EEPROM\0" }, + { .parent_bus = (0x28 + 3), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_12_EEPROM\0" }, + { .parent_bus = (0x28 + 4), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_13_EEPROM\0" }, + { .parent_bus = (0x28 + 5), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_14_EEPROM\0" }, + { .parent_bus = (0x28 + 6), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_15_EEPROM\0" }, + { .parent_bus = (0x28 + 7), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_16_EEPROM\0" }, + { .parent_bus = (0x30 + 0), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_17_EEPROM\0" }, + { .parent_bus = (0x30 + 1), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_18_EEPROM\0" }, + { .parent_bus = (0x30 + 2), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_19_EEPROM\0" }, + { .parent_bus = (0x30 + 3), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_20_EEPROM\0" }, + { .parent_bus = (0x30 + 4), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_21_EEPROM\0" }, + { .parent_bus = (0x30 + 5), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_22_EEPROM\0" }, + { .parent_bus = (0x30 + 6), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_23_EEPROM\0" }, + { .parent_bus = (0x30 + 7), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_24_EEPROM\0" }, + { .parent_bus = (0x38 + 0), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_25_EEPROM\0" }, + { .parent_bus = (0x38 + 1), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_26_EEPROM\0" }, + { .parent_bus = (0x38 + 2), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_27_EEPROM\0" }, + { .parent_bus = (0x38 + 3), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_28_EEPROM\0" }, + { .parent_bus = (0x38 + 4), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_29_EEPROM\0" }, + { .parent_bus = (0x38 + 5), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_30_EEPROM\0" }, + { .parent_bus = (0x38 + 6), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_31_EEPROM\0" }, + { .parent_bus = (0x38 + 7), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_32_EEPROM\0" }, + { .parent_bus = (0x40 + 0), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_33_EEPROM\0" }, + { .parent_bus = (0x40 + 1), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_34_EEPROM\0" }, + { .parent_bus = (0x40 + 2), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_35_EEPROM\0" }, + { .parent_bus = (0x40 + 3), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_36_EEPROM\0" }, + { .parent_bus = (0x40 + 4), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_37_EEPROM\0" }, + { .parent_bus = (0x40 + 5), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_38_EEPROM\0" }, + { .parent_bus = (0x40 + 6), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_39_EEPROM\0" }, + { .parent_bus = (0x40 + 7), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_40_EEPROM\0" }, + { .parent_bus = (0x48 + 0), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_41_EEPROM\0" }, + { .parent_bus = (0x48 + 1), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_42_EEPROM\0" }, + { .parent_bus = (0x48 + 2), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_43_EEPROM\0" }, + { .parent_bus = (0x48 + 3), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_44_EEPROM\0" }, + { .parent_bus = (0x48 + 4), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_45_EEPROM\0" }, + { .parent_bus = (0x48 + 5), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_46_EEPROM\0" }, + { .parent_bus = (0x48 + 6), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_47_EEPROM\0" }, + { .parent_bus = (0x48 + 7), .type = i2c_type_24c02, .addr = 0x50, .name = "SFP_48_EEPROM\0" }, + + { .parent_bus = (0x10 + 3), .type = i2c_type_pca9698, .addr = 0x23, .name = "PCA9698(SFP_1-8)\0" }, + { .parent_bus = (0x10 + 3), .type = i2c_type_pca9698, .addr = 0x21, .name = "PCA9698(SFP_9-16)\0" }, + { .parent_bus = (0x10 + 3), .type = i2c_type_pca9698, .addr = 0x22, .name = "PCA9698(SFP_17-24)\0" }, + { .parent_bus = (0x10 + 4), .type = i2c_type_pca9698, .addr = 0x23, .name = "PCA9698(SFP_25-32)\0" }, + { .parent_bus = (0x10 + 4), .type = i2c_type_pca9698, .addr = 0x24, .name = "PCA9698(SFP_33-40)\0" }, + { .parent_bus = (0x10 + 4), .type = i2c_type_pca9698, .addr = 0x25, .name = "PCA9698(SFP_41-48)\0" }, + + { .parent_bus = (0x10 + 5), .type = i2c_type_pca9548, .addr = 0x76, .busno = 0x50, .name = "PCA9548_8\0" }, + { .parent_bus = (0x50 + 0), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_1_EEPROM\0" }, + { .parent_bus = (0x50 + 1), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_2_EEPROM\0" }, + { .parent_bus = (0x50 + 2), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_3_EEPROM\0" }, + { .parent_bus = (0x50 + 3), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_4_EEPROM\0" }, + + { .parent_bus = (0x10 + 5), .type = i2c_type_pca9555, .addr = 0x24, .name = "PCA9555_1(LED)\0" }, + { .parent_bus = (0x10 + 6), .type = i2c_type_pca9555, .addr = 0x23, .name = "PCA9555_2(QSFP)\0" }, + + /* QSFP+ DB */ + { .parent_bus = (0x10 + 7), .type = i2c_type_pca9555, .addr = 0x23, .name = "PCA9555(QDB)\0" }, + { .parent_bus = (0x10 + 7), .type = i2c_type_pca9546, .addr = 0x76, .busno = 0x58, .name = "PCA9546(QDB)\0" }, + { .parent_bus = (0x58 + 0), .type = i2c_type_24c02, .addr = 0x50, .name = "QDB_QSFP_1_EEPROM\0" }, + { .parent_bus = (0x58 + 1), .type = i2c_type_24c02, .addr = 0x50, .name = "QDB_QSFP_2_EEPROM\0" }, + + { .parent_bus = (0x00 + 0), .type = i2c_type_pca9546, .addr = 0x72, .busno = 0x18, .name = "PCA9546\0" }, + { .parent_bus = (0x18 + 0), .type = i2c_type_emerson700, .addr = 0x6f, .name = "PSU_1\0" }, /* RPSU 1 */ + { .parent_bus = (0x18 + 1), .type = i2c_type_emerson700, .addr = 0x69, .name = "PSU_2\0" }, /* RPSU 2 */ + { .parent_bus = (0x18 + 2), .type = i2c_type_pca9555, .addr = 0x26, .name = "PCA9555_5(PSU)\0" }, + { .parent_bus = (0x18 + 3), .type = i2c_type_24c02, .addr = 0x54, .name = "Board_EEPROM\0" }, +}; + +static struct i2c_init_data quanta_ly9_i2c_init_data[] = { + { .parent_bus = (0x00 + 0), .type = i2c_type_pca9546, .addr = 0x71, .busno = 0x02, .name = "PCA9546(CPU)\0" }, + { .parent_bus = (0x02 + 0), .type = i2c_type_pca9555, .addr = 0x20, .gpio_base = 0x40, .name = "PCA9555_1(CPU)\0" }, + + { .parent_bus = (0x00 + 0), .type = i2c_type_quanta_ly9_hwmon, .addr = 0x4e, .name = "PSoc\0" }, + { .parent_bus = (0x00 + 0), .type = i2c_type_spd, .addr = 0x52, .name = "SPD\0" }, + { .parent_bus = (0x00 + 0), .type = i2c_type_rtc, .addr = 0x68, .name = "RTC\0" }, + { .parent_bus = (0x00 + 0), .type = i2c_type_pca9548, .addr = 0x77, .busno = 0x10, .name = "PCA9548APW1\0" }, + + { .parent_bus = (0x10 + 5), .type = i2c_type_pca9548, .addr = 0x76, .busno = 0x20, .name = "PCA9548APW2\0" }, + { .parent_bus = (0x00 + 0), .type = i2c_type_qci_cpld_4_ports, .addr = 0x3a, .name = "quanta_ly9_cpld\0" }, + { .parent_bus = (0x10 + 0), .type = i2c_type_pca9555, .addr = 0x24, .name = "PCA9555_3(FAN)\0" }, + { .parent_bus = (0x10 + 0), .type = i2c_type_pca9555, .addr = 0x23, .name = "PCA9555_4(QSFP_EN)\0" }, + { .parent_bus = (0x20 + 0), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_49_EEPROM\0" }, + { .parent_bus = (0x20 + 1), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_50_EEPROM\0" }, + { .parent_bus = (0x20 + 2), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_51_EEPROM\0" }, + { .parent_bus = (0x20 + 3), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_52_EEPROM\0" }, + + /* QSFP+ DB */ + { .parent_bus = (0x10 + 7), .type = i2c_type_pca9555, .addr = 0x23, .name = "PCA9555(QDB)\0" }, + { .parent_bus = (0x10 + 7), .type = i2c_type_pca9546, .addr = 0x76, .busno = 0x30, .name = "PCA9546(QDB)\0" }, + { .parent_bus = (0x30 + 0), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_53_EEPROM\0" }, + { .parent_bus = (0x30 + 1), .type = i2c_type_24c02, .addr = 0x50, .name = "QSFP_54_EEPROM\0" }, + + { .parent_bus = (0x00 + 0), .type = i2c_type_pca9546, .addr = 0x72, .busno = 0x18, .name = "PCA9546\0" }, + { .parent_bus = (0x18 + 0), .type = i2c_type_emerson700, .addr = 0x6f, .name = "PSU_1\0" }, /* RPSU 1 */ + { .parent_bus = (0x18 + 1), .type = i2c_type_emerson700, .addr = 0x69, .name = "PSU_2\0" }, /* RPSU 2 */ + { .parent_bus = (0x18 + 2), .type = i2c_type_pca9555, .addr = 0x26, .name = "PCA9555_1(PSU)\0" }, + { .parent_bus = (0x18 + 3), .type = i2c_type_24c02, .addr = 0x54, .name = "Board_EEPROM\0" }, +}; +static inline struct pca954x_platform_data *pca954x_platform_data_get(int type, int busno) { + static struct pca954x_platform_mode platform_modes[8]; + static struct pca954x_platform_data platform_data; + int num_modes, i; + + switch(type) { + case i2c_type_pca9546: + num_modes = 4; + break; + + case i2c_type_pca9548: + num_modes = 8; + break; + + default: + return (struct pca954x_platform_data *) NULL; + break; + } + + for(i=0;i