1d33776e4SMateusz Kulikowski /* 2d33776e4SMateusz Kulikowski * Sample SPMI bus driver 3d33776e4SMateusz Kulikowski * 4d33776e4SMateusz Kulikowski * It emulates bus with single pm8916-like pmic that has only GPIO reigsters. 5d33776e4SMateusz Kulikowski * 6d33776e4SMateusz Kulikowski * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com> 7d33776e4SMateusz Kulikowski * 8d33776e4SMateusz Kulikowski * SPDX-License-Identifier: GPL-2.0+ 9d33776e4SMateusz Kulikowski */ 10d33776e4SMateusz Kulikowski 11d33776e4SMateusz Kulikowski #include <common.h> 12d33776e4SMateusz Kulikowski #include <dm.h> 13d33776e4SMateusz Kulikowski #include <errno.h> 14d33776e4SMateusz Kulikowski #include <spmi/spmi.h> 15d33776e4SMateusz Kulikowski #include <asm/gpio.h> 16d33776e4SMateusz Kulikowski #include <asm/io.h> 17d33776e4SMateusz Kulikowski 18d33776e4SMateusz Kulikowski DECLARE_GLOBAL_DATA_PTR; 19d33776e4SMateusz Kulikowski 20d33776e4SMateusz Kulikowski #define EMUL_GPIO_PID_START 0xC0 21d33776e4SMateusz Kulikowski #define EMUL_GPIO_PID_END 0xC3 22d33776e4SMateusz Kulikowski 23d33776e4SMateusz Kulikowski #define EMUL_GPIO_COUNT 4 24d33776e4SMateusz Kulikowski 25d33776e4SMateusz Kulikowski #define EMUL_GPIO_REG_END 0x46 /* Last valid register */ 26d33776e4SMateusz Kulikowski 27d33776e4SMateusz Kulikowski #define EMUL_PERM_R 0x1 28d33776e4SMateusz Kulikowski #define EMUL_PERM_W 0x2 29d33776e4SMateusz Kulikowski #define EMUL_PERM_RW (EMUL_PERM_R | EMUL_PERM_W) 30d33776e4SMateusz Kulikowski 31d33776e4SMateusz Kulikowski struct sandbox_emul_fake_regs { 32d33776e4SMateusz Kulikowski u8 value; 33d33776e4SMateusz Kulikowski u8 access_mask; 34d33776e4SMateusz Kulikowski u8 perms; /* Access permissions */ 35d33776e4SMateusz Kulikowski }; 36d33776e4SMateusz Kulikowski 37d33776e4SMateusz Kulikowski struct sandbox_emul_gpio { 38*aafa6482SMateusz Kulikowski /* Fake registers - need one more entry as REG_END is valid address. */ 39*aafa6482SMateusz Kulikowski struct sandbox_emul_fake_regs r[EMUL_GPIO_REG_END + 1]; 40d33776e4SMateusz Kulikowski }; 41d33776e4SMateusz Kulikowski 42d33776e4SMateusz Kulikowski struct sandbox_spmi_priv { 43d33776e4SMateusz Kulikowski struct sandbox_emul_gpio gpios[EMUL_GPIO_COUNT]; 44d33776e4SMateusz Kulikowski }; 45d33776e4SMateusz Kulikowski 46d33776e4SMateusz Kulikowski /* Check if valid register was requested */ 47d33776e4SMateusz Kulikowski static bool check_address_valid(int usid, int pid, int off) 48d33776e4SMateusz Kulikowski { 49d33776e4SMateusz Kulikowski if (usid != 0) 50d33776e4SMateusz Kulikowski return false; 51d33776e4SMateusz Kulikowski if (pid < EMUL_GPIO_PID_START || pid > EMUL_GPIO_PID_END) 52d33776e4SMateusz Kulikowski return false; 53d33776e4SMateusz Kulikowski if (off > EMUL_GPIO_REG_END) 54d33776e4SMateusz Kulikowski return false; 55d33776e4SMateusz Kulikowski return true; 56d33776e4SMateusz Kulikowski } 57d33776e4SMateusz Kulikowski 58d33776e4SMateusz Kulikowski static int sandbox_spmi_write(struct udevice *dev, int usid, int pid, int off, 59d33776e4SMateusz Kulikowski uint8_t val) 60d33776e4SMateusz Kulikowski { 61d33776e4SMateusz Kulikowski struct sandbox_spmi_priv *priv = dev_get_priv(dev); 62d33776e4SMateusz Kulikowski struct sandbox_emul_fake_regs *regs; 63d33776e4SMateusz Kulikowski 64d33776e4SMateusz Kulikowski if (!check_address_valid(usid, pid, off)) 65d33776e4SMateusz Kulikowski return -EIO; 66d33776e4SMateusz Kulikowski 67d33776e4SMateusz Kulikowski regs = priv->gpios[pid & 0x3].r; /* Last 3 bits of pid are gpio # */ 68d33776e4SMateusz Kulikowski 69d33776e4SMateusz Kulikowski switch (off) { 70d33776e4SMateusz Kulikowski case 0x40: /* Control */ 71d33776e4SMateusz Kulikowski val &= regs[off].access_mask; 72d33776e4SMateusz Kulikowski if (((val & 0x30) == 0x10) || ((val & 0x30) == 0x20)) { 73d33776e4SMateusz Kulikowski /* out/inout - set status register */ 74d33776e4SMateusz Kulikowski regs[0x8].value &= ~0x1; 75d33776e4SMateusz Kulikowski regs[0x8].value |= val & 0x1; 76d33776e4SMateusz Kulikowski } 77d33776e4SMateusz Kulikowski break; 78d33776e4SMateusz Kulikowski default: 79d33776e4SMateusz Kulikowski if (regs[off].perms & EMUL_PERM_W) 80d33776e4SMateusz Kulikowski regs[off].value = val & regs[off].access_mask; 81d33776e4SMateusz Kulikowski } 82d33776e4SMateusz Kulikowski return 0; 83d33776e4SMateusz Kulikowski } 84d33776e4SMateusz Kulikowski 85d33776e4SMateusz Kulikowski static int sandbox_spmi_read(struct udevice *dev, int usid, int pid, int off) 86d33776e4SMateusz Kulikowski { 87d33776e4SMateusz Kulikowski struct sandbox_spmi_priv *priv = dev_get_priv(dev); 88d33776e4SMateusz Kulikowski struct sandbox_emul_fake_regs *regs; 89d33776e4SMateusz Kulikowski 90d33776e4SMateusz Kulikowski if (!check_address_valid(usid, pid, off)) 91d33776e4SMateusz Kulikowski return -EIO; 92d33776e4SMateusz Kulikowski 93d33776e4SMateusz Kulikowski regs = priv->gpios[pid & 0x3].r; /* Last 3 bits of pid are gpio # */ 94d33776e4SMateusz Kulikowski 95d33776e4SMateusz Kulikowski if (regs[0x46].value == 0) /* Block disabled */ 96d33776e4SMateusz Kulikowski return 0; 97d33776e4SMateusz Kulikowski 98d33776e4SMateusz Kulikowski switch (off) { 99d33776e4SMateusz Kulikowski case 0x8: /* Status */ 100d33776e4SMateusz Kulikowski if (regs[0x46].value == 0) /* Block disabled */ 101d33776e4SMateusz Kulikowski return 0; 102d33776e4SMateusz Kulikowski return regs[off].value; 103d33776e4SMateusz Kulikowski default: 104d33776e4SMateusz Kulikowski if (regs[off].perms & EMUL_PERM_R) 105d33776e4SMateusz Kulikowski return regs[off].value; 106d33776e4SMateusz Kulikowski else 107d33776e4SMateusz Kulikowski return 0; 108d33776e4SMateusz Kulikowski } 109d33776e4SMateusz Kulikowski } 110d33776e4SMateusz Kulikowski 111d33776e4SMateusz Kulikowski static struct dm_spmi_ops sandbox_spmi_ops = { 112d33776e4SMateusz Kulikowski .read = sandbox_spmi_read, 113d33776e4SMateusz Kulikowski .write = sandbox_spmi_write, 114d33776e4SMateusz Kulikowski }; 115d33776e4SMateusz Kulikowski 116d33776e4SMateusz Kulikowski static int sandbox_spmi_probe(struct udevice *dev) 117d33776e4SMateusz Kulikowski { 118d33776e4SMateusz Kulikowski struct sandbox_spmi_priv *priv = dev_get_priv(dev); 119d33776e4SMateusz Kulikowski int i; 120d33776e4SMateusz Kulikowski 121d33776e4SMateusz Kulikowski for (i = 0; i < EMUL_GPIO_COUNT; ++i) { 122d33776e4SMateusz Kulikowski struct sandbox_emul_fake_regs *regs = priv->gpios[i].r; 123d33776e4SMateusz Kulikowski regs[4].perms = EMUL_PERM_R; 124d33776e4SMateusz Kulikowski regs[4].value = 0x10; 125d33776e4SMateusz Kulikowski regs[5].perms = EMUL_PERM_R; 126d33776e4SMateusz Kulikowski regs[5].value = 0x5; 127d33776e4SMateusz Kulikowski regs[8].access_mask = 0x81; 128d33776e4SMateusz Kulikowski regs[8].perms = EMUL_PERM_RW; 129d33776e4SMateusz Kulikowski regs[0x40].access_mask = 0x7F; 130d33776e4SMateusz Kulikowski regs[0x40].perms = EMUL_PERM_RW; 131d33776e4SMateusz Kulikowski regs[0x41].access_mask = 7; 132d33776e4SMateusz Kulikowski regs[0x41].perms = EMUL_PERM_RW; 133d33776e4SMateusz Kulikowski regs[0x42].access_mask = 7; 134d33776e4SMateusz Kulikowski regs[0x42].perms = EMUL_PERM_RW; 135d33776e4SMateusz Kulikowski regs[0x42].value = 0x4; 136d33776e4SMateusz Kulikowski regs[0x45].access_mask = 0x3F; 137d33776e4SMateusz Kulikowski regs[0x45].perms = EMUL_PERM_RW; 138d33776e4SMateusz Kulikowski regs[0x45].value = 0x1; 139d33776e4SMateusz Kulikowski regs[0x46].access_mask = 0x80; 140d33776e4SMateusz Kulikowski regs[0x46].perms = EMUL_PERM_RW; 141d33776e4SMateusz Kulikowski regs[0x46].value = 0x80; 142d33776e4SMateusz Kulikowski } 143d33776e4SMateusz Kulikowski return 0; 144d33776e4SMateusz Kulikowski } 145d33776e4SMateusz Kulikowski 146d33776e4SMateusz Kulikowski static const struct udevice_id sandbox_spmi_ids[] = { 147d33776e4SMateusz Kulikowski { .compatible = "sandbox,spmi" }, 148d33776e4SMateusz Kulikowski { } 149d33776e4SMateusz Kulikowski }; 150d33776e4SMateusz Kulikowski 151d33776e4SMateusz Kulikowski U_BOOT_DRIVER(msm_spmi) = { 152d33776e4SMateusz Kulikowski .name = "sandbox_spmi", 153d33776e4SMateusz Kulikowski .id = UCLASS_SPMI, 154d33776e4SMateusz Kulikowski .of_match = sandbox_spmi_ids, 155d33776e4SMateusz Kulikowski .ops = &sandbox_spmi_ops, 156d33776e4SMateusz Kulikowski .probe = sandbox_spmi_probe, 157d33776e4SMateusz Kulikowski .priv_auto_alloc_size = sizeof(struct sandbox_spmi_priv), 158d33776e4SMateusz Kulikowski }; 159