blob: 57e865d7439b4e56c1a2508d4f02f6bb669fa3ac [file] [log] [blame]
/*
* This file is part of the coreboot project.
*
* Copyright 2014 Google 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; version 2 of the License.
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <boot/coreboot_tables.h>
#include <console/console.h>
#include <delay.h>
#include <gpio.h>
#include <string.h>
#include <vendorcode/google/chromeos/chromeos.h>
#define FAKE_GPIO_NUM -1
struct gpio_desc {
gpio_t gpio_num;
const char *gpio_name;
uint32_t fake_value;
int last_reported;
};
/* Actual GPIO switch names */
#define DEVELOPER_GPIO_NAME "developer"
#define RECOVERY_GPIO_NAME "recovery"
#define WRITE_PROTECT_GPIO_NAME "write protect"
static struct gpio_desc descriptors[] = {
{ 15, DEVELOPER_GPIO_NAME },
{ 16, RECOVERY_GPIO_NAME },
{ 17, WRITE_PROTECT_GPIO_NAME },
{ FAKE_GPIO_NUM, "power", 1 }, /* Power never pressed. */
{ FAKE_GPIO_NUM, "lid", 0 } /* Lid always open. */
};
static void fill_lb_gpio(struct lb_gpio *pgpio, struct gpio_desc *pdesc)
{
gpio_t gpio_num = pdesc->gpio_num;
pgpio->port = gpio_num;
if (gpio_num == FAKE_GPIO_NUM) {
pgpio->value = pdesc->fake_value;
} else {
gpio_tlmm_config_set(gpio_num, GPIO_FUNC_DISABLE,
GPIO_NO_PULL, GPIO_2MA, GPIO_DISABLE);
udelay(10); /* Should be enough to settle. */
pgpio->value = gpio_get(gpio_num);
}
pgpio->polarity = ACTIVE_LOW;
strncpy((char *)pgpio->name, pdesc->gpio_name, sizeof(pgpio->name));
if (pdesc->last_reported != (pgpio->value + 1)) {
pdesc->last_reported = (pgpio->value + 1);
printk(BIOS_INFO, "%s: %s: port %d value %d\n",
__func__, pgpio->name, pgpio->port, pgpio->value);
}
}
void fill_lb_gpios(struct lb_gpios *gpios)
{
int i;
for (i = 0; i < ARRAY_SIZE(descriptors); i++)
fill_lb_gpio(gpios->gpios + i, descriptors + i);
gpios->size = sizeof(*gpios) + sizeof(struct lb_gpio) * i;
gpios->count = i;
}
static int get_switch_value(const char *switch_name)
{
int i;
for (i = 0; i < ARRAY_SIZE(descriptors); i++)
if (!strcmp(descriptors[i].gpio_name, switch_name)) {
struct lb_gpio gpio;
fill_lb_gpio(&gpio, descriptors + i);
return gpio.value ^ !gpio.polarity;
}
return -1;
}
int get_developer_mode_switch(void)
{
return get_switch_value(DEVELOPER_GPIO_NAME);
}
int get_recovery_mode_switch(void)
{
return get_switch_value(RECOVERY_GPIO_NAME);
}
int get_write_protect_state(void)
{
return get_switch_value(WRITE_PROTECT_GPIO_NAME);
}