1a1a503a8SSean Wang // SPDX-License-Identifier: GPL-2.0 2a1a503a8SSean Wang /* 3a1a503a8SSean Wang * Copyright (C) 2018 MediaTek Inc. 4a1a503a8SSean Wang * 5a1a503a8SSean Wang * Author: Sean Wang <sean.wang@mediatek.com> 6a1a503a8SSean Wang * 7a1a503a8SSean Wang */ 8a1a503a8SSean Wang 9a1a503a8SSean Wang #include <linux/device.h> 10a1a503a8SSean Wang #include <linux/err.h> 11a1a503a8SSean Wang #include <linux/gpio.h> 12a1a503a8SSean Wang #include <linux/io.h> 13a1a503a8SSean Wang 14a1a503a8SSean Wang #include "pinctrl-mtk-common-v2.h" 15a1a503a8SSean Wang 16a1a503a8SSean Wang static void mtk_w32(struct mtk_pinctrl *pctl, u32 reg, u32 val) 17a1a503a8SSean Wang { 18a1a503a8SSean Wang writel_relaxed(val, pctl->base + reg); 19a1a503a8SSean Wang } 20a1a503a8SSean Wang 21a1a503a8SSean Wang static u32 mtk_r32(struct mtk_pinctrl *pctl, u32 reg) 22a1a503a8SSean Wang { 23a1a503a8SSean Wang return readl_relaxed(pctl->base + reg); 24a1a503a8SSean Wang } 25a1a503a8SSean Wang 26a1a503a8SSean Wang void mtk_rmw(struct mtk_pinctrl *pctl, u32 reg, u32 mask, u32 set) 27a1a503a8SSean Wang { 28a1a503a8SSean Wang u32 val; 29a1a503a8SSean Wang 30a1a503a8SSean Wang val = mtk_r32(pctl, reg); 31a1a503a8SSean Wang val &= ~mask; 32a1a503a8SSean Wang val |= set; 33a1a503a8SSean Wang mtk_w32(pctl, reg, val); 34a1a503a8SSean Wang } 35a1a503a8SSean Wang 36a1a503a8SSean Wang static int mtk_hw_pin_field_lookup(struct mtk_pinctrl *hw, int pin, 37a1a503a8SSean Wang const struct mtk_pin_reg_calc *rc, 38a1a503a8SSean Wang struct mtk_pin_field *pfd) 39a1a503a8SSean Wang { 40a1a503a8SSean Wang const struct mtk_pin_field_calc *c, *e; 41a1a503a8SSean Wang u32 bits; 42a1a503a8SSean Wang 43a1a503a8SSean Wang c = rc->range; 44a1a503a8SSean Wang e = c + rc->nranges; 45a1a503a8SSean Wang 46a1a503a8SSean Wang while (c < e) { 47a1a503a8SSean Wang if (pin >= c->s_pin && pin <= c->e_pin) 48a1a503a8SSean Wang break; 49a1a503a8SSean Wang c++; 50a1a503a8SSean Wang } 51a1a503a8SSean Wang 52a1a503a8SSean Wang if (c >= e) { 53a1a503a8SSean Wang dev_err(hw->dev, "Out of range for pin = %d\n", pin); 54a1a503a8SSean Wang return -EINVAL; 55a1a503a8SSean Wang } 56a1a503a8SSean Wang 57*b906faf7SSean Wang /* Calculated bits as the overall offset the pin is located at, 58*b906faf7SSean Wang * if c->fixed is held, that determines the all the pins in the 59*b906faf7SSean Wang * range use the same field with the s_pin. 60*b906faf7SSean Wang */ 61*b906faf7SSean Wang bits = c->fixed ? c->s_bit : c->s_bit + (pin - c->s_pin) * (c->x_bits); 62a1a503a8SSean Wang 63*b906faf7SSean Wang /* Fill pfd from bits. For example 32-bit register applied is assumed 64*b906faf7SSean Wang * when c->sz_reg is equal to 32. 65*b906faf7SSean Wang */ 66*b906faf7SSean Wang pfd->offset = c->s_addr + c->x_addrs * (bits / c->sz_reg); 67*b906faf7SSean Wang pfd->bitpos = bits % c->sz_reg; 68a1a503a8SSean Wang pfd->mask = (1 << c->x_bits) - 1; 69a1a503a8SSean Wang 70a1a503a8SSean Wang /* pfd->next is used for indicating that bit wrapping-around happens 71a1a503a8SSean Wang * which requires the manipulation for bit 0 starting in the next 72a1a503a8SSean Wang * register to form the complete field read/write. 73a1a503a8SSean Wang */ 74*b906faf7SSean Wang pfd->next = pfd->bitpos + c->x_bits > c->sz_reg ? c->x_addrs : 0; 75a1a503a8SSean Wang 76a1a503a8SSean Wang return 0; 77a1a503a8SSean Wang } 78a1a503a8SSean Wang 79a1a503a8SSean Wang static int mtk_hw_pin_field_get(struct mtk_pinctrl *hw, int pin, 80a1a503a8SSean Wang int field, struct mtk_pin_field *pfd) 81a1a503a8SSean Wang { 82a1a503a8SSean Wang const struct mtk_pin_reg_calc *rc; 83a1a503a8SSean Wang 84a1a503a8SSean Wang if (field < 0 || field >= PINCTRL_PIN_REG_MAX) { 85a1a503a8SSean Wang dev_err(hw->dev, "Invalid Field %d\n", field); 86a1a503a8SSean Wang return -EINVAL; 87a1a503a8SSean Wang } 88a1a503a8SSean Wang 89a1a503a8SSean Wang if (hw->soc->reg_cal && hw->soc->reg_cal[field].range) { 90a1a503a8SSean Wang rc = &hw->soc->reg_cal[field]; 91a1a503a8SSean Wang } else { 92a1a503a8SSean Wang dev_err(hw->dev, "Undefined range for field %d\n", field); 93a1a503a8SSean Wang return -EINVAL; 94a1a503a8SSean Wang } 95a1a503a8SSean Wang 96a1a503a8SSean Wang return mtk_hw_pin_field_lookup(hw, pin, rc, pfd); 97a1a503a8SSean Wang } 98a1a503a8SSean Wang 99a1a503a8SSean Wang static void mtk_hw_bits_part(struct mtk_pin_field *pf, int *h, int *l) 100a1a503a8SSean Wang { 101a1a503a8SSean Wang *l = 32 - pf->bitpos; 102a1a503a8SSean Wang *h = get_count_order(pf->mask) - *l; 103a1a503a8SSean Wang } 104a1a503a8SSean Wang 105a1a503a8SSean Wang static void mtk_hw_write_cross_field(struct mtk_pinctrl *hw, 106a1a503a8SSean Wang struct mtk_pin_field *pf, int value) 107a1a503a8SSean Wang { 108a1a503a8SSean Wang int nbits_l, nbits_h; 109a1a503a8SSean Wang 110a1a503a8SSean Wang mtk_hw_bits_part(pf, &nbits_h, &nbits_l); 111a1a503a8SSean Wang 112a1a503a8SSean Wang mtk_rmw(hw, pf->offset, pf->mask << pf->bitpos, 113a1a503a8SSean Wang (value & pf->mask) << pf->bitpos); 114a1a503a8SSean Wang 115a1a503a8SSean Wang mtk_rmw(hw, pf->offset + pf->next, BIT(nbits_h) - 1, 116a1a503a8SSean Wang (value & pf->mask) >> nbits_l); 117a1a503a8SSean Wang } 118a1a503a8SSean Wang 119a1a503a8SSean Wang static void mtk_hw_read_cross_field(struct mtk_pinctrl *hw, 120a1a503a8SSean Wang struct mtk_pin_field *pf, int *value) 121a1a503a8SSean Wang { 122a1a503a8SSean Wang int nbits_l, nbits_h, h, l; 123a1a503a8SSean Wang 124a1a503a8SSean Wang mtk_hw_bits_part(pf, &nbits_h, &nbits_l); 125a1a503a8SSean Wang 126a1a503a8SSean Wang l = (mtk_r32(hw, pf->offset) >> pf->bitpos) & (BIT(nbits_l) - 1); 127a1a503a8SSean Wang h = (mtk_r32(hw, pf->offset + pf->next)) & (BIT(nbits_h) - 1); 128a1a503a8SSean Wang 129a1a503a8SSean Wang *value = (h << nbits_l) | l; 130a1a503a8SSean Wang } 131a1a503a8SSean Wang 132a1a503a8SSean Wang int mtk_hw_set_value(struct mtk_pinctrl *hw, int pin, int field, int value) 133a1a503a8SSean Wang { 134a1a503a8SSean Wang struct mtk_pin_field pf; 135a1a503a8SSean Wang int err; 136a1a503a8SSean Wang 137a1a503a8SSean Wang err = mtk_hw_pin_field_get(hw, pin, field, &pf); 138a1a503a8SSean Wang if (err) 139a1a503a8SSean Wang return err; 140a1a503a8SSean Wang 141a1a503a8SSean Wang if (!pf.next) 142a1a503a8SSean Wang mtk_rmw(hw, pf.offset, pf.mask << pf.bitpos, 143a1a503a8SSean Wang (value & pf.mask) << pf.bitpos); 144a1a503a8SSean Wang else 145a1a503a8SSean Wang mtk_hw_write_cross_field(hw, &pf, value); 146a1a503a8SSean Wang 147a1a503a8SSean Wang return 0; 148a1a503a8SSean Wang } 149a1a503a8SSean Wang 150a1a503a8SSean Wang int mtk_hw_get_value(struct mtk_pinctrl *hw, int pin, int field, int *value) 151a1a503a8SSean Wang { 152a1a503a8SSean Wang struct mtk_pin_field pf; 153a1a503a8SSean Wang int err; 154a1a503a8SSean Wang 155a1a503a8SSean Wang err = mtk_hw_pin_field_get(hw, pin, field, &pf); 156a1a503a8SSean Wang if (err) 157a1a503a8SSean Wang return err; 158a1a503a8SSean Wang 159a1a503a8SSean Wang if (!pf.next) 160a1a503a8SSean Wang *value = (mtk_r32(hw, pf.offset) >> pf.bitpos) & pf.mask; 161a1a503a8SSean Wang else 162a1a503a8SSean Wang mtk_hw_read_cross_field(hw, &pf, value); 163a1a503a8SSean Wang 164a1a503a8SSean Wang return 0; 165a1a503a8SSean Wang } 166