2 * Qualcomm pm8916 pmic gpio driver - part of Qualcomm PM8916 PMIC
4 * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
6 * SPDX-License-Identifier: GPL-2.0+
11 #include <power/pmic.h>
12 #include <spmi/spmi.h>
15 #include <linux/bitops.h>
17 DECLARE_GLOBAL_DATA_PTR
;
19 /* Register offset for each gpio */
20 #define REG_OFFSET(x) ((x) * 0x100)
24 /* Type and subtype are shared for all pm8916 peripherals */
26 #define REG_SUBTYPE 0x5
28 #define REG_STATUS 0x08
29 #define REG_STATUS_VAL_MASK 0x1
33 #define REG_CTL_MODE_MASK 0x70
34 #define REG_CTL_MODE_INPUT 0x00
35 #define REG_CTL_MODE_INOUT 0x20
36 #define REG_CTL_MODE_OUTPUT 0x10
37 #define REG_CTL_OUTPUT_MASK 0x0F
39 #define REG_DIG_VIN_CTL 0x41
40 #define REG_DIG_VIN_VIN0 0
42 #define REG_DIG_PULL_CTL 0x42
43 #define REG_DIG_PULL_NO_PU 0x5
45 #define REG_DIG_OUT_CTL 0x45
46 #define REG_DIG_OUT_CTL_CMOS (0x0 << 4)
47 #define REG_DIG_OUT_CTL_DRIVE_L 0x1
49 #define REG_EN_CTL 0x46
50 #define REG_EN_CTL_ENABLE (1 << 7)
52 struct pm8916_gpio_bank
{
53 uint16_t pid
; /* Peripheral ID on SPMI bus */
56 static int pm8916_gpio_set_direction(struct udevice
*dev
, unsigned offset
,
57 bool input
, int value
)
59 struct pm8916_gpio_bank
*priv
= dev_get_priv(dev
);
60 uint32_t gpio_base
= priv
->pid
+ REG_OFFSET(offset
);
63 /* Disable the GPIO */
64 ret
= pmic_clrsetbits(dev
->parent
, gpio_base
+ REG_EN_CTL
,
65 REG_EN_CTL_ENABLE
, 0);
71 ret
= pmic_reg_write(dev
->parent
, gpio_base
+ REG_CTL
,
74 ret
= pmic_reg_write(dev
->parent
, gpio_base
+ REG_CTL
,
75 REG_CTL_MODE_INOUT
| (value
? 1 : 0));
79 /* Set the right pull (no pull) */
80 ret
= pmic_reg_write(dev
->parent
, gpio_base
+ REG_DIG_PULL_CTL
,
85 /* Configure output pin drivers if needed */
87 /* Select the VIN - VIN0, pin is input so it doesn't matter */
88 ret
= pmic_reg_write(dev
->parent
, gpio_base
+ REG_DIG_VIN_CTL
,
93 /* Set the right dig out control */
94 ret
= pmic_reg_write(dev
->parent
, gpio_base
+ REG_DIG_OUT_CTL
,
95 REG_DIG_OUT_CTL_CMOS
|
96 REG_DIG_OUT_CTL_DRIVE_L
);
101 /* Enable the GPIO */
102 return pmic_clrsetbits(dev
->parent
, gpio_base
+ REG_EN_CTL
, 0,
106 static int pm8916_gpio_direction_input(struct udevice
*dev
, unsigned offset
)
108 return pm8916_gpio_set_direction(dev
, offset
, true, 0);
111 static int pm8916_gpio_direction_output(struct udevice
*dev
, unsigned offset
,
114 return pm8916_gpio_set_direction(dev
, offset
, false, value
);
117 static int pm8916_gpio_get_function(struct udevice
*dev
, unsigned offset
)
119 struct pm8916_gpio_bank
*priv
= dev_get_priv(dev
);
120 uint32_t gpio_base
= priv
->pid
+ REG_OFFSET(offset
);
123 /* Set the output value of the gpio */
124 reg
= pmic_reg_read(dev
->parent
, gpio_base
+ REG_CTL
);
128 switch (reg
& REG_CTL_MODE_MASK
) {
129 case REG_CTL_MODE_INPUT
:
131 case REG_CTL_MODE_INOUT
: /* Fallthrough */
132 case REG_CTL_MODE_OUTPUT
:
135 return GPIOF_UNKNOWN
;
139 static int pm8916_gpio_get_value(struct udevice
*dev
, unsigned offset
)
141 struct pm8916_gpio_bank
*priv
= dev_get_priv(dev
);
142 uint32_t gpio_base
= priv
->pid
+ REG_OFFSET(offset
);
145 reg
= pmic_reg_read(dev
->parent
, gpio_base
+ REG_STATUS
);
149 return !!(reg
& REG_STATUS_VAL_MASK
);
152 static int pm8916_gpio_set_value(struct udevice
*dev
, unsigned offset
,
155 struct pm8916_gpio_bank
*priv
= dev_get_priv(dev
);
156 uint32_t gpio_base
= priv
->pid
+ REG_OFFSET(offset
);
158 /* Set the output value of the gpio */
159 return pmic_clrsetbits(dev
->parent
, gpio_base
+ REG_CTL
,
160 REG_CTL_OUTPUT_MASK
, !!value
);
163 static const struct dm_gpio_ops pm8916_gpio_ops
= {
164 .direction_input
= pm8916_gpio_direction_input
,
165 .direction_output
= pm8916_gpio_direction_output
,
166 .get_value
= pm8916_gpio_get_value
,
167 .set_value
= pm8916_gpio_set_value
,
168 .get_function
= pm8916_gpio_get_function
,
171 static int pm8916_gpio_probe(struct udevice
*dev
)
173 struct pm8916_gpio_bank
*priv
= dev_get_priv(dev
);
176 priv
->pid
= dev_get_addr(dev
);
177 if (priv
->pid
== FDT_ADDR_T_NONE
)
180 /* Do a sanity check */
181 reg
= pmic_reg_read(dev
->parent
, priv
->pid
+ REG_TYPE
);
185 reg
= pmic_reg_read(dev
->parent
, priv
->pid
+ REG_SUBTYPE
);
192 static int pm8916_gpio_ofdata_to_platdata(struct udevice
*dev
)
194 struct gpio_dev_priv
*uc_priv
= dev_get_uclass_priv(dev
);
196 uc_priv
->gpio_count
= fdtdec_get_int(gd
->fdt_blob
, dev
->of_offset
,
198 uc_priv
->bank_name
= fdt_getprop(gd
->fdt_blob
, dev
->of_offset
,
199 "gpio-bank-name", NULL
);
200 if (uc_priv
->bank_name
== NULL
)
201 uc_priv
->bank_name
= "pm8916";
206 static const struct udevice_id pm8916_gpio_ids
[] = {
207 { .compatible
= "qcom,pm8916-gpio" },
211 U_BOOT_DRIVER(gpio_pm8916
) = {
212 .name
= "gpio_pm8916",
214 .of_match
= pm8916_gpio_ids
,
215 .ofdata_to_platdata
= pm8916_gpio_ofdata_to_platdata
,
216 .probe
= pm8916_gpio_probe
,
217 .ops
= &pm8916_gpio_ops
,
218 .priv_auto_alloc_size
= sizeof(struct pm8916_gpio_bank
),
222 /* Add pmic buttons as GPIO as well - there is no generic way for now */
223 #define PON_INT_RT_STS 0x10
224 #define KPDPWR_ON_INT_BIT 0
225 #define RESIN_ON_INT_BIT 1
227 static int pm8941_pwrkey_get_function(struct udevice
*dev
, unsigned offset
)
232 static int pm8941_pwrkey_get_value(struct udevice
*dev
, unsigned offset
)
234 struct pm8916_gpio_bank
*priv
= dev_get_priv(dev
);
236 int reg
= pmic_reg_read(dev
->parent
, priv
->pid
+ PON_INT_RT_STS
);
242 case 0: /* Power button */
243 return (reg
& BIT(KPDPWR_ON_INT_BIT
)) != 0;
245 case 1: /* Reset button */
247 return (reg
& BIT(RESIN_ON_INT_BIT
)) != 0;
252 static const struct dm_gpio_ops pm8941_pwrkey_ops
= {
253 .get_value
= pm8941_pwrkey_get_value
,
254 .get_function
= pm8941_pwrkey_get_function
,
257 static int pm8941_pwrkey_probe(struct udevice
*dev
)
259 struct pm8916_gpio_bank
*priv
= dev_get_priv(dev
);
262 priv
->pid
= dev_get_addr(dev
);
263 if (priv
->pid
== FDT_ADDR_T_NONE
)
266 /* Do a sanity check */
267 reg
= pmic_reg_read(dev
->parent
, priv
->pid
+ REG_TYPE
);
271 reg
= pmic_reg_read(dev
->parent
, priv
->pid
+ REG_SUBTYPE
);
278 static int pm8941_pwrkey_ofdata_to_platdata(struct udevice
*dev
)
280 struct gpio_dev_priv
*uc_priv
= dev_get_uclass_priv(dev
);
282 uc_priv
->gpio_count
= 2;
283 if (uc_priv
->bank_name
== NULL
)
284 uc_priv
->bank_name
= "pm8916_key";
289 static const struct udevice_id pm8941_pwrkey_ids
[] = {
290 { .compatible
= "qcom,pm8916-pwrkey" },
294 U_BOOT_DRIVER(pwrkey_pm8941
) = {
295 .name
= "pwrkey_pm8916",
297 .of_match
= pm8941_pwrkey_ids
,
298 .ofdata_to_platdata
= pm8941_pwrkey_ofdata_to_platdata
,
299 .probe
= pm8941_pwrkey_probe
,
300 .ops
= &pm8941_pwrkey_ops
,
301 .priv_auto_alloc_size
= sizeof(struct pm8916_gpio_bank
),