diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/modules/PKG.yml b/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/modules/PKG.yml index 81c95537..8788e199 100644 --- a/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/modules/PKG.yml +++ b/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/modules/PKG.yml @@ -1 +1 @@ -!include $ONL_TEMPLATES/no-platform-modules.yml ARCH=amd64 VENDOR=quanta BASENAME=x86-64-quanta-ly6-rangeley +!include $ONL_TEMPLATES/platform-modules.yml ARCH=amd64 VENDOR=quanta BASENAME=x86-64-quanta-ly6-rangeley KERNELS="onl-kernel-3.16-lts-x86-64-all:amd64" diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/modules/builds/.gitignore b/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/modules/builds/.gitignore new file mode 100644 index 00000000..a65b4177 --- /dev/null +++ b/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/modules/builds/.gitignore @@ -0,0 +1 @@ +lib diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/modules/builds/Makefile b/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/modules/builds/Makefile new file mode 100644 index 00000000..21339f1b --- /dev/null +++ b/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/modules/builds/Makefile @@ -0,0 +1,6 @@ +KERNELS := onl-kernel-3.16-lts-x86-64-all:amd64 +KMODULES := $(wildcard *.c) +VENDOR := quanta +BASENAME := x86-64-quanta-ly6-rangeley +ARCH := x86_64 +include $(ONL)/make/kmodule.mk diff --git a/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/modules/builds/quanta-ly6-i2c-mux.c b/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/modules/builds/quanta-ly6-i2c-mux.c new file mode 100644 index 00000000..2ec38866 --- /dev/null +++ b/packages/platforms/quanta/x86-64/x86-64-quanta-ly6-rangeley/modules/builds/quanta-ly6-i2c-mux.c @@ -0,0 +1,293 @@ +/* + * + * + * 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. + * + * + * + * + * An I2C multiplexer driver for the Quanta LY6 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Disable QSFP module reset (n=1..16) + * RST_N_Px1 INTL_Px1 MOD_ASB_Px1 LPMODE_Px1 RST_N_Px2 INTL_Px2 MOD_ASB_Px2 LPMODE_Px2 + * 7 6 5 4 3 2 1 0 + * port 2(n-1)+1 2(n-1)+1 2(n-1)+1 2(n-1)+1 2(n-1) 2(n-1) 2(n-1) 2(n-1) + */ +#define QUANTA_LY6_I2C_MUX_NUM_READ_GPIOS 32 +#define QUANTA_LY6_I2C_MUX_NUM_WRITE_GPIOS 32 +#define QUANTA_LY6_I2C_MUX_NUM_GPIO_GROUPS 4 +#define QUANTA_LY6_I2C_MUX_NUM_GPIOS (QUANTA_LY6_I2C_MUX_NUM_READ_GPIOS + QUANTA_LY6_I2C_MUX_NUM_WRITE_GPIOS) +#define QUANTA_LY6_I2C_MUX_NUM_GPIO_PINS_PER_GROUP (QUANTA_LY6_I2C_MUX_NUM_GPIOS / QUANTA_LY6_I2C_MUX_NUM_GPIO_GROUPS) + +struct quanta_ly6_i2c_mux { + struct i2c_client *client; + struct gpio_chip gpio_chip; + u16 gpio_write_val; +}; + +static const struct i2c_device_id quanta_ly6_i2c_mux_id[] = { + {"quanta_ly6_i2c_mux", 0xf600}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, quanta_ly6_i2c_mux_id); + +/* + * Read 2 bytes once per command, and command should be group 1~4 + */ +static int quanta_ly6_i2c_mux_reg_read(struct i2c_adapter *adap, + struct i2c_client *client, + u8 command, u16 *val) +{ + int ret = -ENODEV; + + if (adap->algo->master_xfer) { + struct i2c_msg msg[2]; + char buf[4]; + + msg[0].addr = client->addr; + msg[0].flags = 0; + msg[0].len = 1; + buf[0] = command; + msg[0].buf = &buf[0]; + + /* always receive 3 bytes, else the PLD freaks out */ + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 3; + msg[1].buf = &buf[1]; + + ret = adap->algo->master_xfer(adap, msg, 2); + if (val != NULL && ret > -1) + *val = ((buf[2] << 8) | buf[1]); + } else { + union i2c_smbus_data data; + data.block[0] = 3; /* block transfer length */ + ret = adap->algo->smbus_xfer(adap, client->addr, + client->flags, + I2C_SMBUS_READ, + command, + I2C_SMBUS_I2C_BLOCK_DATA, &data); + if (val != NULL) + *val = ((data.block[2] << 8) | data.block[1]); + } + + return ret; +} + +/* + * Write 3 bytes once per command, and command should be group 1~4 + */ +static int quanta_ly6_i2c_mux_reg_write(struct i2c_adapter *adap, + struct i2c_client *client, + u8 command, u16 val) +{ + int ret = -ENODEV; + + if (adap->algo->master_xfer) { + struct i2c_msg msg; + char buf[4]; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = 3; + buf[0] = command; + buf[1] = (val & 0xff); + buf[2] = ((val >> 8) & 0xff); + buf[3] = 0; + msg.buf = buf; + ret = adap->algo->master_xfer(adap, &msg, 1); + } else { + union i2c_smbus_data data; + + data.block[0] = 3; + data.block[1] = (val & 0xff); + data.block[2] = ((val >> 8) & 0xff); + data.block[3] = 0; + + ret = adap->algo->smbus_xfer(adap, client->addr, + client->flags, + I2C_SMBUS_WRITE, + command, + I2C_SMBUS_I2C_BLOCK_DATA, &data); + } + + return ret; +} + +static void quanta_ly6_i2c_mux_gpio_set(struct gpio_chip *gc, unsigned offset, + int val) +{ + struct quanta_ly6_i2c_mux *data = container_of( + gc, struct quanta_ly6_i2c_mux, gpio_chip); + int ret; + u32 group; + + /* ignore write attempts to input GPIOs */ + if ((offset % 4) == 1 || (offset % 4) == 2) { + dev_warn(&data->client->dev, + "ignoring GPIO write for input for pin %d\n", + offset); + return; + } + + group = (offset / QUANTA_LY6_I2C_MUX_NUM_GPIO_PINS_PER_GROUP) + 1; + ret = quanta_ly6_i2c_mux_reg_read(data->client->adapter, + data->client, + group, + &data->gpio_write_val); + + if (ret < 0) { + dev_err(&data->client->dev, + "quanta_ly6_i2c_mux_reg_read failed\n"); + return; + } + + if (val) + data->gpio_write_val |= (1 << (offset % QUANTA_LY6_I2C_MUX_NUM_GPIO_PINS_PER_GROUP)); + else + data->gpio_write_val &= ~(1 << (offset % QUANTA_LY6_I2C_MUX_NUM_GPIO_PINS_PER_GROUP)); + + quanta_ly6_i2c_mux_reg_write( + data->client->adapter, data->client, + group, + data->gpio_write_val); +} + +static int quanta_ly6_i2c_mux_gpio_get(struct gpio_chip *gc, unsigned offset) +{ + int ret; + u16 buf; + u32 group; + struct quanta_ly6_i2c_mux *data = container_of( + gc, struct quanta_ly6_i2c_mux, gpio_chip); + + if (offset >= (QUANTA_LY6_I2C_MUX_NUM_GPIOS)) { + offset -= (QUANTA_LY6_I2C_MUX_NUM_GPIOS); + } + + group = (offset / QUANTA_LY6_I2C_MUX_NUM_GPIO_PINS_PER_GROUP) + 1; + buf = 0; + ret = quanta_ly6_i2c_mux_reg_read(data->client->adapter, + data->client, + group, + &buf); + + if (ret < 0) { + dev_err(&data->client->dev, + "quanta_ly6_i2c_mux_reg_read failed\n"); + return 0; + } + return (buf & (1 << (offset % QUANTA_LY6_I2C_MUX_NUM_GPIO_PINS_PER_GROUP))) ? 1 : 0; +} + +static struct gpio_chip quanta_ly6_i2c_mux_gpio_chip = { + .label = "quanta_ly6_i2c_mux_gpio_chip", + .owner = THIS_MODULE, + .ngpio = QUANTA_LY6_I2C_MUX_NUM_READ_GPIOS + QUANTA_LY6_I2C_MUX_NUM_WRITE_GPIOS, + .base = -1, + .set = quanta_ly6_i2c_mux_gpio_set, + .get = quanta_ly6_i2c_mux_gpio_get, +}; + +static int quanta_ly6_i2c_mux_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adap = client->adapter; + struct pca953x_platform_data *pdata; + struct quanta_ly6_i2c_mux *data; + int ret = -ENODEV, gpio_base = -1; + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA)) + goto err; + + data = kzalloc(sizeof(struct quanta_ly6_i2c_mux), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto err; + } + + i2c_set_clientdata(client, data); + data->client = client; + + if (i2c_smbus_write_byte(client, 0) < 0) { + dev_warn(&client->dev, "probe failed\n"); + goto exit_free; + } + + data->gpio_chip = quanta_ly6_i2c_mux_gpio_chip; + data->gpio_chip.dev = &client->dev; + data->gpio_write_val = 0xff; + + pdata = client->dev.platform_data; + if(pdata) { + gpio_base = (int) pdata->gpio_base; + } + data->gpio_chip.base = gpio_base; + + ret = gpiochip_add(&data->gpio_chip); + if (ret) { + dev_err(&client->dev, "failed to register GPIOs\n"); + goto exit_free; + } + + dev_info(&client->dev, + "registered GPIOs for I2C mux %s (%d read, %d write)\n", + client->name, + QUANTA_LY6_I2C_MUX_NUM_READ_GPIOS, + QUANTA_LY6_I2C_MUX_NUM_WRITE_GPIOS); + + return 0; + +exit_free: + kfree(data); +err: + return ret; +} + +static int quanta_ly6_i2c_mux_remove(struct i2c_client *client) +{ + struct quanta_ly6_i2c_mux *data = i2c_get_clientdata(client); + int ret; + + ret = gpiochip_remove(&data->gpio_chip); + if (ret) + return ret; + + kfree(data); + return 0; +} + +static struct i2c_driver quanta_ly6_i2c_mux_driver = { + .driver = { + .name = "quanta_ly6_i2c_mux", + .owner = THIS_MODULE, + }, + .probe = quanta_ly6_i2c_mux_probe, + .remove = quanta_ly6_i2c_mux_remove, + .id_table = quanta_ly6_i2c_mux_id, +}; + +module_i2c_driver(quanta_ly6_i2c_mux_driver); + +MODULE_AUTHOR("QCT Technical "); +MODULE_DESCRIPTION("Quanta LY6 I2C multiplexer driver"); +MODULE_LICENSE("GPL");