blob: 3e16484583763845479da1810ea3deb186c443be [file] [log] [blame]
#include <boardEnv/mvBoardEnvLib.h>
#include <gpp/mvGpp.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/leds.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/sysfs.h>
#include <linux/ctype.h>
#include "gflt.h"
#define GPIO_PON_PWR_EN 37
struct gflt_led_data {
unsigned gpio;
unsigned active_low;
struct led_classdev cdev;
};
struct board_gpio {
unsigned gpio;
const char *label;
};
static struct board_gpio gflt110_board_gpios[] = {
{
.gpio = GPIO_PON_PWR_EN,
.label = "power-enable",
},
};
static struct board_gpio gflt300_board_gpios[] = {
{
.gpio = GPIO_PON_PWR_EN,
.label = "power-enable",
},
};
static struct board_gpio gflt400_board_gpios[] = {
// GFLT400 doesn't use Pin 37 (NC)
};
static int board_gpio_export(struct board_gpio *gpio, struct device *dev, char *boardName)
{
int rc;
rc = gpio_request(gpio->gpio, gpio->label);
if (rc) {
pr_err("%s: error %d requesting gpio %u (%s)\n", boardName, rc,
gpio->gpio, gpio->label);
goto exit;
}
/* this is needed to set gpiolib's out flag for the gpio */
rc = gpio_direction_output(gpio->gpio, gpio_get_value(gpio->gpio));
if (rc) {
pr_err("%s: error %d setting gpio %u (%s) direction\n",
boardName, rc, gpio->gpio, gpio->label);
goto exit;
}
rc = gpio_export(gpio->gpio, false);
if (rc) {
pr_err("%s: error %d exporting gpio %u (%s)\n", boardName, rc,
gpio->gpio, gpio->label);
goto exit;
}
rc = gpio_export_link(dev, gpio->label, gpio->gpio);
if (rc) {
pr_err("%s: error %d linking gpio %u (%s)\n", boardName, rc,
gpio->gpio, gpio->label);
goto exit;
}
rc = 0;
exit:
return rc;
}
static ssize_t board_hw_ver_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "1.0\n");
}
static DEVICE_ATTR(hw_ver, S_IRUGO, board_hw_ver_show, NULL);
static void gflt_led_brightness_set(struct led_classdev *led_cdev,
enum led_brightness enum_brightness);
static struct gflt_led_data gflt110_board_gpio_leds[] = {
{
.gpio = 12,
.cdev = {
.name = "sys-blue",
.brightness_set = gflt_led_brightness_set,
.max_brightness = 100,
},
},
{
.gpio = 13,
.cdev = {
.name = "sys-red",
.brightness_set = gflt_led_brightness_set,
.max_brightness = 100,
},
},
};
static struct gflt_led_data gflt300_board_gpio_leds[] = {
{
.gpio = 9,
.active_low = 1,
.cdev = {
.name = "sys-blue",
.brightness_set = gflt_led_brightness_set,
.max_brightness = 100,
},
},
{
.gpio = 10,
.active_low = 1,
.cdev = {
.name = "sys-red",
.brightness_set = gflt_led_brightness_set,
.max_brightness = 100,
},
},
};
static struct gflt_led_data gflt400_board_gpio_leds[] = {
{
.gpio = 9,
.active_low = 1,
.cdev = {
.name = "sys-blue",
.brightness_set = gflt_led_brightness_set,
.max_brightness = 100,
},
},
{
.gpio = 10,
.active_low = 1,
.cdev = {
.name = "sys-red",
.brightness_set = gflt_led_brightness_set,
.max_brightness = 100,
},
},
};
static void gflt_led_brightness_set(struct led_classdev *led_cdev,
enum led_brightness enum_brightness)
{
struct gflt_led_data *led_data =
container_of(led_cdev, struct gflt_led_data, cdev);
unsigned gpio = led_data->gpio;
unsigned brightness = (unsigned)enum_brightness;
MV_U32 mask = 1 << (gpio % 32);
MV_U32 group = gpio / 32;
MV_U32 cycles_per_ms = mvBoardTclkGet() / 1000;
if (brightness && brightness < led_cdev->max_brightness) {
unsigned long delay_on;
unsigned long delay_off;
delay_on = cycles_per_ms * brightness / led_cdev->max_brightness;
delay_off = cycles_per_ms - delay_on;
if (led_data->active_low)
mvGppBlinkCntrSet(MV_GPP_BLINK_CNTR_A,
delay_off,
delay_on);
else
mvGppBlinkCntrSet(MV_GPP_BLINK_CNTR_A,
delay_on,
delay_off);
mvGppBlinkEn(group, mask, mask);
} else if(brightness) {
mvGppValueSet(group, mask, led_data->active_low ? 0 : mask);
mvGppBlinkEn(group, mask, 0);
} else {
mvGppValueSet(group, mask, led_data->active_low ? mask : 0);
mvGppBlinkEn(group, mask, 0);
}
}
static int register_gfltleds(struct platform_device *pdev,
struct gflt_led_data* gflt_leds,
unsigned gflt_leds_num_leds)
{
int ret;
int i;
for (i = 0; i < gflt_leds_num_leds; i++) {
ret = led_classdev_register(&pdev->dev, &gflt_leds[i].cdev);
if (ret)
goto err_reg;
}
return 0;
err_reg:
for (i-- ; i >= 0; i--) {
led_classdev_unregister(&gflt_leds[i].cdev);
}
return ret;
}
#define BOARDNAME_LEN 32
int __init board_init(void)
{
struct platform_device *pdev;
MV_U32 boardID;
MV_BOARD_INFO *pBoardInfo;
char boardName[BOARDNAME_LEN];
int rc, i;
char c;
struct gflt_led_data *led_data;
int led_data_max;
struct board_gpio *board_gpios;
int board_gpios_len;
boardID = mvBoardIdGet();
if (!gfiber_is_any_jack()) {
printk("Unsupported board id:%d\n", boardID);
return -1;
}
pBoardInfo = mvBoardInfoGet();
for(i = 0; i < (BOARDNAME_LEN -1); i++) {
c = pBoardInfo->boardName[i];
if (!c)
break;
boardName[i] = tolower(c);
}
boardName[i] = 0;
printk("Detected board id:%x name:%s\n", boardID, boardName);
/* /sys/devices/platform/<board_name> */
pdev = platform_device_register_simple(boardName, -1, NULL, 0);
if (IS_ERR(pdev)) {
rc = PTR_ERR(pdev);
pr_err("%s: error %d registering device\n", boardName, rc);
return rc;
}
/* /sys/devices/platform/board -> /sys/devices/platform/<board_name> */
rc = sysfs_create_link(&pdev->dev.parent->kobj, &pdev->dev.kobj,
"board");
if (rc)
pr_err("%s: error %d creating link 'board'\n", boardName, rc);
/* /sys/devices/platform/board/hw_ver */
rc = device_create_file(&pdev->dev, &dev_attr_hw_ver);
if (rc)
pr_err("%s: error %d creating attribute 'hw_ver'\n", boardName, rc);
if (boardID == GFLT110_ID) {
led_data = gflt110_board_gpio_leds;
led_data_max = ARRAY_SIZE(gflt110_board_gpio_leds);
} else if (boardID == GFLT300_ID) {
led_data = gflt300_board_gpio_leds;
led_data_max = ARRAY_SIZE(gflt300_board_gpio_leds);
} else if (boardID == GFLT400_ID) {
led_data = gflt400_board_gpio_leds;
led_data_max = ARRAY_SIZE(gflt400_board_gpio_leds);
}
rc = register_gfltleds(pdev, led_data, led_data_max);
if (rc)
pr_err("%s: error %d registering GFLT LED device\n", boardName, rc);
if (boardID == GFLT110_ID) {
board_gpios = gflt110_board_gpios;
board_gpios_len = ARRAY_SIZE(gflt110_board_gpios);
} else if (boardID == GFLT300_ID) {
board_gpios = gflt300_board_gpios;
board_gpios_len = ARRAY_SIZE(gflt300_board_gpios);
} else if (boardID == GFLT400_ID) {
board_gpios = gflt400_board_gpios;
board_gpios_len = ARRAY_SIZE(gflt400_board_gpios);
}
/* /sys/devices/platform/board/<gpio_name> */
for (i = 0; i < board_gpios_len; i++)
board_gpio_export(&board_gpios[i], &pdev->dev, boardName);
return 0;
}
device_initcall(board_init);