Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mfd: Add Gateworks System Controller core driver

The Gateworks System Controller (GSC) is an I2C slave controller
implemented with an MSP430 micro-controller whose firmware embeds the
following features:
- I/O expander (16 GPIO's) using PCA955x protocol
- Real Time Clock using DS1672 protocol
- User EEPROM using AT24 protocol
- HWMON using custom protocol
- Interrupt controller with tamper detect, user pushbotton
- Watchdog controller capable of full board power-cycle
- Power Control capable of full board power-cycle

see http://trac.gateworks.com/wiki/gsc for more details

Signed-off-by: Tim Harvey <tharvey@gateworks.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>

authored by

Tim Harvey and committed by
Lee Jones
d8523499 3e6cae8e

+377
+8
MAINTAINERS
··· 7028 7028 F: tools/perf/bench/futex* 7029 7029 F: tools/testing/selftests/futex/ 7030 7030 7031 + GATEWORKS SYSTEM CONTROLLER (GSC) DRIVER 7032 + M: Tim Harvey <tharvey@gateworks.com> 7033 + M: Robert Jones <rjones@gateworks.com> 7034 + S: Maintained 7035 + F: Documentation/devicetree/bindings/mfd/gateworks-gsc.yaml 7036 + F: drivers/mfd/gateworks-gsc.c 7037 + F: include/linux/mfd/gsc.h 7038 + 7031 7039 GASKET DRIVER FRAMEWORK 7032 7040 M: Rob Springer <rspringer@google.com> 7033 7041 M: Todd Poynor <toddpoynor@google.com>
+15
drivers/mfd/Kconfig
··· 407 407 Select this option to enable support for Samsung Exynos Low Power 408 408 Audio Subsystem. 409 409 410 + config MFD_GATEWORKS_GSC 411 + tristate "Gateworks System Controller" 412 + depends on (I2C && OF) 413 + select MFD_CORE 414 + select REGMAP_I2C 415 + select REGMAP_IRQ 416 + help 417 + Enable support for the Gateworks System Controller (GSC) found 418 + on Gateworks Single Board Computers supporting system functions 419 + such as push-button monitor, multiple ADC's for voltage and 420 + temperature monitoring, fan controller and watchdog monitor. 421 + This driver provides common support for accessing the device. 422 + Additional drivers must be enabled in order to use the 423 + functionality of the device. 424 + 410 425 config MFD_MC13XXX 411 426 tristate 412 427 depends on (SPI_MASTER || I2C)
+1
drivers/mfd/Makefile
··· 15 15 obj-$(CONFIG_MFD_BD9571MWV) += bd9571mwv.o 16 16 obj-$(CONFIG_MFD_CROS_EC_DEV) += cros_ec_dev.o 17 17 obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o 18 + obj-$(CONFIG_MFD_GATEWORKS_GSC) += gateworks-gsc.o 18 19 19 20 obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o 20 21 obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o
+277
drivers/mfd/gateworks-gsc.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * The Gateworks System Controller (GSC) is a multi-function 4 + * device designed for use in Gateworks Single Board Computers. 5 + * The control interface is I2C, with an interrupt. The device supports 6 + * system functions such as push-button monitoring, multiple ADC's for 7 + * voltage and temperature monitoring, fan controller and watchdog monitor. 8 + * 9 + * Copyright (C) 2020 Gateworks Corporation 10 + */ 11 + 12 + #include <linux/device.h> 13 + #include <linux/i2c.h> 14 + #include <linux/interrupt.h> 15 + #include <linux/mfd/gsc.h> 16 + #include <linux/module.h> 17 + #include <linux/mutex.h> 18 + #include <linux/of.h> 19 + #include <linux/of_platform.h> 20 + #include <linux/platform_device.h> 21 + #include <linux/regmap.h> 22 + 23 + #include <asm/unaligned.h> 24 + 25 + /* 26 + * The GSC suffers from an errata where occasionally during 27 + * ADC cycles the chip can NAK I2C transactions. To ensure we have reliable 28 + * register access we place retries around register access. 29 + */ 30 + #define I2C_RETRIES 3 31 + 32 + int gsc_write(void *context, unsigned int reg, unsigned int val) 33 + { 34 + struct i2c_client *client = context; 35 + int retry, ret; 36 + 37 + for (retry = 0; retry < I2C_RETRIES; retry++) { 38 + ret = i2c_smbus_write_byte_data(client, reg, val); 39 + /* 40 + * -EAGAIN returned when the i2c host controller is busy 41 + * -EIO returned when i2c device is busy 42 + */ 43 + if (ret != -EAGAIN && ret != -EIO) 44 + break; 45 + } 46 + 47 + return 0; 48 + } 49 + EXPORT_SYMBOL_GPL(gsc_write); 50 + 51 + int gsc_read(void *context, unsigned int reg, unsigned int *val) 52 + { 53 + struct i2c_client *client = context; 54 + int retry, ret; 55 + 56 + for (retry = 0; retry < I2C_RETRIES; retry++) { 57 + ret = i2c_smbus_read_byte_data(client, reg); 58 + /* 59 + * -EAGAIN returned when the i2c host controller is busy 60 + * -EIO returned when i2c device is busy 61 + */ 62 + if (ret != -EAGAIN && ret != -EIO) 63 + break; 64 + } 65 + *val = ret & 0xff; 66 + 67 + return 0; 68 + } 69 + EXPORT_SYMBOL_GPL(gsc_read); 70 + 71 + /* 72 + * gsc_powerdown - API to use GSC to power down board for a specific time 73 + * 74 + * secs - number of seconds to remain powered off 75 + */ 76 + static int gsc_powerdown(struct gsc_dev *gsc, unsigned long secs) 77 + { 78 + int ret; 79 + unsigned char regs[4]; 80 + 81 + dev_info(&gsc->i2c->dev, "GSC powerdown for %ld seconds\n", 82 + secs); 83 + 84 + put_unaligned_le32(secs, regs); 85 + ret = regmap_bulk_write(gsc->regmap, GSC_TIME_ADD, regs, 4); 86 + if (ret) 87 + return ret; 88 + 89 + ret = regmap_update_bits(gsc->regmap, GSC_CTRL_1, 90 + BIT(GSC_CTRL_1_SLEEP_ADD), 91 + BIT(GSC_CTRL_1_SLEEP_ADD)); 92 + if (ret) 93 + return ret; 94 + 95 + ret = regmap_update_bits(gsc->regmap, GSC_CTRL_1, 96 + BIT(GSC_CTRL_1_SLEEP_ACTIVATE) | 97 + BIT(GSC_CTRL_1_SLEEP_ENABLE), 98 + BIT(GSC_CTRL_1_SLEEP_ACTIVATE) | 99 + BIT(GSC_CTRL_1_SLEEP_ENABLE)); 100 + 101 + 102 + return ret; 103 + } 104 + 105 + static ssize_t gsc_show(struct device *dev, struct device_attribute *attr, 106 + char *buf) 107 + { 108 + struct gsc_dev *gsc = dev_get_drvdata(dev); 109 + const char *name = attr->attr.name; 110 + int rz = 0; 111 + 112 + if (strcasecmp(name, "fw_version") == 0) 113 + rz = sprintf(buf, "%d\n", gsc->fwver); 114 + else if (strcasecmp(name, "fw_crc") == 0) 115 + rz = sprintf(buf, "0x%04x\n", gsc->fwcrc); 116 + else 117 + dev_err(dev, "invalid command: '%s'\n", name); 118 + 119 + return rz; 120 + } 121 + 122 + static ssize_t gsc_store(struct device *dev, struct device_attribute *attr, 123 + const char *buf, size_t count) 124 + { 125 + struct gsc_dev *gsc = dev_get_drvdata(dev); 126 + const char *name = attr->attr.name; 127 + long value; 128 + 129 + if (strcasecmp(name, "powerdown") == 0) { 130 + if (kstrtol(buf, 0, &value) == 0) 131 + gsc_powerdown(gsc, value); 132 + } else { 133 + dev_err(dev, "invalid command: '%s\n", name); 134 + } 135 + 136 + return count; 137 + } 138 + 139 + static struct device_attribute attr_fwver = 140 + __ATTR(fw_version, 0440, gsc_show, NULL); 141 + static struct device_attribute attr_fwcrc = 142 + __ATTR(fw_crc, 0440, gsc_show, NULL); 143 + static struct device_attribute attr_pwrdown = 144 + __ATTR(powerdown, 0220, NULL, gsc_store); 145 + 146 + static struct attribute *gsc_attrs[] = { 147 + &attr_fwver.attr, 148 + &attr_fwcrc.attr, 149 + &attr_pwrdown.attr, 150 + NULL, 151 + }; 152 + 153 + static struct attribute_group attr_group = { 154 + .attrs = gsc_attrs, 155 + }; 156 + 157 + static const struct of_device_id gsc_of_match[] = { 158 + { .compatible = "gw,gsc", }, 159 + { } 160 + }; 161 + MODULE_DEVICE_TABLE(of, gsc_of_match); 162 + 163 + static struct regmap_bus gsc_regmap_bus = { 164 + .reg_read = gsc_read, 165 + .reg_write = gsc_write, 166 + }; 167 + 168 + static const struct regmap_config gsc_regmap_config = { 169 + .reg_bits = 8, 170 + .val_bits = 8, 171 + .cache_type = REGCACHE_NONE, 172 + .max_register = GSC_WP, 173 + }; 174 + 175 + static const struct regmap_irq gsc_irqs[] = { 176 + REGMAP_IRQ_REG(GSC_IRQ_PB, 0, BIT(GSC_IRQ_PB)), 177 + REGMAP_IRQ_REG(GSC_IRQ_KEY_ERASED, 0, BIT(GSC_IRQ_KEY_ERASED)), 178 + REGMAP_IRQ_REG(GSC_IRQ_EEPROM_WP, 0, BIT(GSC_IRQ_EEPROM_WP)), 179 + REGMAP_IRQ_REG(GSC_IRQ_RESV, 0, BIT(GSC_IRQ_RESV)), 180 + REGMAP_IRQ_REG(GSC_IRQ_GPIO, 0, BIT(GSC_IRQ_GPIO)), 181 + REGMAP_IRQ_REG(GSC_IRQ_TAMPER, 0, BIT(GSC_IRQ_TAMPER)), 182 + REGMAP_IRQ_REG(GSC_IRQ_WDT_TIMEOUT, 0, BIT(GSC_IRQ_WDT_TIMEOUT)), 183 + REGMAP_IRQ_REG(GSC_IRQ_SWITCH_HOLD, 0, BIT(GSC_IRQ_SWITCH_HOLD)), 184 + }; 185 + 186 + static const struct regmap_irq_chip gsc_irq_chip = { 187 + .name = "gateworks-gsc", 188 + .irqs = gsc_irqs, 189 + .num_irqs = ARRAY_SIZE(gsc_irqs), 190 + .num_regs = 1, 191 + .status_base = GSC_IRQ_STATUS, 192 + .mask_base = GSC_IRQ_ENABLE, 193 + .mask_invert = true, 194 + .ack_base = GSC_IRQ_STATUS, 195 + .ack_invert = true, 196 + }; 197 + 198 + static int gsc_probe(struct i2c_client *client) 199 + { 200 + struct device *dev = &client->dev; 201 + struct gsc_dev *gsc; 202 + struct regmap_irq_chip_data *irq_data; 203 + int ret; 204 + unsigned int reg; 205 + 206 + gsc = devm_kzalloc(dev, sizeof(*gsc), GFP_KERNEL); 207 + if (!gsc) 208 + return -ENOMEM; 209 + 210 + gsc->dev = &client->dev; 211 + gsc->i2c = client; 212 + i2c_set_clientdata(client, gsc); 213 + 214 + gsc->regmap = devm_regmap_init(dev, &gsc_regmap_bus, client, 215 + &gsc_regmap_config); 216 + if (IS_ERR(gsc->regmap)) 217 + return PTR_ERR(gsc->regmap); 218 + 219 + if (regmap_read(gsc->regmap, GSC_FW_VER, &reg)) 220 + return -EIO; 221 + gsc->fwver = reg; 222 + 223 + regmap_read(gsc->regmap, GSC_FW_CRC, &reg); 224 + gsc->fwcrc = reg; 225 + regmap_read(gsc->regmap, GSC_FW_CRC + 1, &reg); 226 + gsc->fwcrc |= reg << 8; 227 + 228 + gsc->i2c_hwmon = devm_i2c_new_dummy_device(dev, client->adapter, 229 + GSC_HWMON); 230 + if (IS_ERR(gsc->i2c_hwmon)) { 231 + dev_err(dev, "Failed to allocate I2C device for HWMON\n"); 232 + return PTR_ERR(gsc->i2c_hwmon); 233 + } 234 + 235 + ret = devm_regmap_add_irq_chip(dev, gsc->regmap, client->irq, 236 + IRQF_ONESHOT | IRQF_SHARED | 237 + IRQF_TRIGGER_FALLING, 0, 238 + &gsc_irq_chip, &irq_data); 239 + if (ret) 240 + return ret; 241 + 242 + dev_info(dev, "Gateworks System Controller v%d: fw 0x%04x\n", 243 + gsc->fwver, gsc->fwcrc); 244 + 245 + ret = sysfs_create_group(&dev->kobj, &attr_group); 246 + if (ret) 247 + dev_err(dev, "failed to create sysfs attrs\n"); 248 + 249 + ret = devm_of_platform_populate(dev); 250 + if (ret) { 251 + sysfs_remove_group(&dev->kobj, &attr_group); 252 + return ret; 253 + } 254 + 255 + return 0; 256 + } 257 + 258 + static int gsc_remove(struct i2c_client *client) 259 + { 260 + sysfs_remove_group(&client->dev.kobj, &attr_group); 261 + 262 + return 0; 263 + } 264 + 265 + static struct i2c_driver gsc_driver = { 266 + .driver = { 267 + .name = "gateworks-gsc", 268 + .of_match_table = gsc_of_match, 269 + }, 270 + .probe_new = gsc_probe, 271 + .remove = gsc_remove, 272 + }; 273 + module_i2c_driver(gsc_driver); 274 + 275 + MODULE_AUTHOR("Tim Harvey <tharvey@gateworks.com>"); 276 + MODULE_DESCRIPTION("I2C Core interface for GSC"); 277 + MODULE_LICENSE("GPL v2");
+76
include/linux/mfd/gsc.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 2 + * 3 + * Copyright (C) 2020 Gateworks Corporation 4 + */ 5 + #ifndef __LINUX_MFD_GSC_H_ 6 + #define __LINUX_MFD_GSC_H_ 7 + 8 + #include <linux/regmap.h> 9 + 10 + /* Device Addresses */ 11 + #define GSC_MISC 0x20 12 + #define GSC_UPDATE 0x21 13 + #define GSC_GPIO 0x23 14 + #define GSC_HWMON 0x29 15 + #define GSC_EEPROM0 0x50 16 + #define GSC_EEPROM1 0x51 17 + #define GSC_EEPROM2 0x52 18 + #define GSC_EEPROM3 0x53 19 + #define GSC_RTC 0x68 20 + 21 + /* Register offsets */ 22 + enum { 23 + GSC_CTRL_0 = 0x00, 24 + GSC_CTRL_1 = 0x01, 25 + GSC_TIME = 0x02, 26 + GSC_TIME_ADD = 0x06, 27 + GSC_IRQ_STATUS = 0x0A, 28 + GSC_IRQ_ENABLE = 0x0B, 29 + GSC_FW_CRC = 0x0C, 30 + GSC_FW_VER = 0x0E, 31 + GSC_WP = 0x0F, 32 + }; 33 + 34 + /* Bit definitions */ 35 + #define GSC_CTRL_0_PB_HARD_RESET 0 36 + #define GSC_CTRL_0_PB_CLEAR_SECURE_KEY 1 37 + #define GSC_CTRL_0_PB_SOFT_POWER_DOWN 2 38 + #define GSC_CTRL_0_PB_BOOT_ALTERNATE 3 39 + #define GSC_CTRL_0_PERFORM_CRC 4 40 + #define GSC_CTRL_0_TAMPER_DETECT 5 41 + #define GSC_CTRL_0_SWITCH_HOLD 6 42 + 43 + #define GSC_CTRL_1_SLEEP_ENABLE 0 44 + #define GSC_CTRL_1_SLEEP_ACTIVATE 1 45 + #define GSC_CTRL_1_SLEEP_ADD 2 46 + #define GSC_CTRL_1_SLEEP_NOWAKEPB 3 47 + #define GSC_CTRL_1_WDT_TIME 4 48 + #define GSC_CTRL_1_WDT_ENABLE 5 49 + #define GSC_CTRL_1_SWITCH_BOOT_ENABLE 6 50 + #define GSC_CTRL_1_SWITCH_BOOT_CLEAR 7 51 + 52 + #define GSC_IRQ_PB 0 53 + #define GSC_IRQ_KEY_ERASED 1 54 + #define GSC_IRQ_EEPROM_WP 2 55 + #define GSC_IRQ_RESV 3 56 + #define GSC_IRQ_GPIO 4 57 + #define GSC_IRQ_TAMPER 5 58 + #define GSC_IRQ_WDT_TIMEOUT 6 59 + #define GSC_IRQ_SWITCH_HOLD 7 60 + 61 + int gsc_read(void *context, unsigned int reg, unsigned int *val); 62 + int gsc_write(void *context, unsigned int reg, unsigned int val); 63 + 64 + struct gsc_dev { 65 + struct device *dev; 66 + 67 + struct i2c_client *i2c; /* 0x20: interrupt controller, WDT */ 68 + struct i2c_client *i2c_hwmon; /* 0x29: hwmon, fan controller */ 69 + 70 + struct regmap *regmap; 71 + 72 + unsigned int fwver; 73 + unsigned short fwcrc; 74 + }; 75 + 76 + #endif /* __LINUX_MFD_GSC_H_ */