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