1 // SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause
3 * Copyright 2023 Schweitzer Engineering Laboratories, Inc.
4 * 2350 NE Hopkins Court, Pullman, WA 99163 USA
6 * Platform support for the b2093 mainboard used in SEL-3350 computers.
7 * Consumes GPIO from the SoC to provide standard LED and power supply
11 #include <linux/acpi.h>
12 #include <linux/gpio/consumer.h>
13 #include <linux/gpio/machine.h>
14 #include <linux/leds.h>
15 #include <linux/module.h>
16 #include <linux/platform_device.h>
17 #include <linux/power_supply.h>
19 /* Broxton communities */
20 #define BXT_NW "INT3452:01"
21 #define BXT_W "INT3452:02"
22 #define BXT_SW "INT3452:03"
24 #define B2093_GPIO_ACPI_ID "SEL0003"
26 #define SEL_PS_A "sel_ps_a"
27 #define SEL_PS_A_DETECT "sel_ps_a_detect"
28 #define SEL_PS_A_GOOD "sel_ps_a_good"
29 #define SEL_PS_B "sel_ps_b"
30 #define SEL_PS_B_DETECT "sel_ps_b_detect"
31 #define SEL_PS_B_GOOD "sel_ps_b_good"
34 static const struct gpio_led sel3350_leds
[] = {
35 { .name
= "sel:green:aux1" },
36 { .name
= "sel:green:aux2" },
37 { .name
= "sel:green:aux3" },
38 { .name
= "sel:green:aux4" },
39 { .name
= "sel:red:alarm" },
40 { .name
= "sel:green:enabled",
41 .default_state
= LEDS_GPIO_DEFSTATE_ON
},
42 { .name
= "sel:red:aux1" },
43 { .name
= "sel:red:aux2" },
44 { .name
= "sel:red:aux3" },
45 { .name
= "sel:red:aux4" },
48 static const struct gpio_led_platform_data sel3350_leds_pdata
= {
49 .num_leds
= ARRAY_SIZE(sel3350_leds
),
53 /* Map GPIOs to LEDs */
54 static struct gpiod_lookup_table sel3350_leds_table
= {
55 .dev_id
= "leds-gpio",
57 GPIO_LOOKUP_IDX(BXT_NW
, 49, NULL
, 0, GPIO_ACTIVE_HIGH
),
58 GPIO_LOOKUP_IDX(BXT_NW
, 50, NULL
, 1, GPIO_ACTIVE_HIGH
),
59 GPIO_LOOKUP_IDX(BXT_NW
, 51, NULL
, 2, GPIO_ACTIVE_HIGH
),
60 GPIO_LOOKUP_IDX(BXT_NW
, 52, NULL
, 3, GPIO_ACTIVE_HIGH
),
61 GPIO_LOOKUP_IDX(BXT_W
, 20, NULL
, 4, GPIO_ACTIVE_HIGH
),
62 GPIO_LOOKUP_IDX(BXT_W
, 21, NULL
, 5, GPIO_ACTIVE_HIGH
),
63 GPIO_LOOKUP_IDX(BXT_SW
, 37, NULL
, 6, GPIO_ACTIVE_HIGH
),
64 GPIO_LOOKUP_IDX(BXT_SW
, 38, NULL
, 7, GPIO_ACTIVE_HIGH
),
65 GPIO_LOOKUP_IDX(BXT_SW
, 39, NULL
, 8, GPIO_ACTIVE_HIGH
),
66 GPIO_LOOKUP_IDX(BXT_SW
, 40, NULL
, 9, GPIO_ACTIVE_HIGH
),
71 /* Map GPIOs to power supplies */
72 static struct gpiod_lookup_table sel3350_gpios_table
= {
73 .dev_id
= B2093_GPIO_ACPI_ID
":00",
75 GPIO_LOOKUP(BXT_NW
, 44, SEL_PS_A_DETECT
, GPIO_ACTIVE_LOW
),
76 GPIO_LOOKUP(BXT_NW
, 45, SEL_PS_A_GOOD
, GPIO_ACTIVE_LOW
),
77 GPIO_LOOKUP(BXT_NW
, 46, SEL_PS_B_DETECT
, GPIO_ACTIVE_LOW
),
78 GPIO_LOOKUP(BXT_NW
, 47, SEL_PS_B_GOOD
, GPIO_ACTIVE_LOW
),
85 struct sel3350_power_cfg_data
{
86 struct gpio_desc
*ps_detect
;
87 struct gpio_desc
*ps_good
;
90 static int sel3350_power_get_property(struct power_supply
*psy
,
91 enum power_supply_property psp
,
92 union power_supply_propval
*val
)
94 struct sel3350_power_cfg_data
*data
= power_supply_get_drvdata(psy
);
97 case POWER_SUPPLY_PROP_HEALTH
:
98 if (gpiod_get_value(data
->ps_detect
)) {
99 if (gpiod_get_value(data
->ps_good
))
100 val
->intval
= POWER_SUPPLY_HEALTH_GOOD
;
102 val
->intval
= POWER_SUPPLY_HEALTH_UNSPEC_FAILURE
;
104 val
->intval
= POWER_SUPPLY_HEALTH_UNKNOWN
;
107 case POWER_SUPPLY_PROP_PRESENT
:
108 val
->intval
= gpiod_get_value(data
->ps_detect
);
110 case POWER_SUPPLY_PROP_ONLINE
:
111 val
->intval
= gpiod_get_value(data
->ps_good
);
119 static const enum power_supply_property sel3350_power_properties
[] = {
120 POWER_SUPPLY_PROP_HEALTH
,
121 POWER_SUPPLY_PROP_PRESENT
,
122 POWER_SUPPLY_PROP_ONLINE
,
125 static const struct power_supply_desc sel3350_ps_a_desc
= {
127 .type
= POWER_SUPPLY_TYPE_MAINS
,
128 .properties
= sel3350_power_properties
,
129 .num_properties
= ARRAY_SIZE(sel3350_power_properties
),
130 .get_property
= sel3350_power_get_property
,
133 static const struct power_supply_desc sel3350_ps_b_desc
= {
135 .type
= POWER_SUPPLY_TYPE_MAINS
,
136 .properties
= sel3350_power_properties
,
137 .num_properties
= ARRAY_SIZE(sel3350_power_properties
),
138 .get_property
= sel3350_power_get_property
,
141 struct sel3350_data
{
142 struct platform_device
*leds_pdev
;
143 struct power_supply
*ps_a
;
144 struct power_supply
*ps_b
;
145 struct sel3350_power_cfg_data ps_a_cfg_data
;
146 struct sel3350_power_cfg_data ps_b_cfg_data
;
149 static int sel3350_probe(struct platform_device
*pdev
)
152 struct sel3350_data
*sel3350
;
153 struct power_supply_config ps_cfg
= {};
155 sel3350
= devm_kzalloc(&pdev
->dev
, sizeof(struct sel3350_data
), GFP_KERNEL
);
159 platform_set_drvdata(pdev
, sel3350
);
161 gpiod_add_lookup_table(&sel3350_leds_table
);
162 gpiod_add_lookup_table(&sel3350_gpios_table
);
164 sel3350
->leds_pdev
= platform_device_register_data(
169 sizeof(sel3350_leds_pdata
));
170 if (IS_ERR(sel3350
->leds_pdev
)) {
171 rs
= PTR_ERR(sel3350
->leds_pdev
);
172 dev_err(&pdev
->dev
, "Failed registering platform device: %d\n", rs
);
177 sel3350
->ps_a_cfg_data
.ps_detect
= devm_gpiod_get(&pdev
->dev
,
180 sel3350
->ps_a_cfg_data
.ps_good
= devm_gpiod_get(&pdev
->dev
,
183 ps_cfg
.drv_data
= &sel3350
->ps_a_cfg_data
;
184 sel3350
->ps_a
= devm_power_supply_register(&pdev
->dev
,
187 if (IS_ERR(sel3350
->ps_a
)) {
188 rs
= PTR_ERR(sel3350
->ps_a
);
189 dev_err(&pdev
->dev
, "Failed registering power supply A: %d\n", rs
);
194 sel3350
->ps_b_cfg_data
.ps_detect
= devm_gpiod_get(&pdev
->dev
,
197 sel3350
->ps_b_cfg_data
.ps_good
= devm_gpiod_get(&pdev
->dev
,
200 ps_cfg
.drv_data
= &sel3350
->ps_b_cfg_data
;
201 sel3350
->ps_b
= devm_power_supply_register(&pdev
->dev
,
204 if (IS_ERR(sel3350
->ps_b
)) {
205 rs
= PTR_ERR(sel3350
->ps_b
);
206 dev_err(&pdev
->dev
, "Failed registering power supply B: %d\n", rs
);
213 platform_device_unregister(sel3350
->leds_pdev
);
215 gpiod_remove_lookup_table(&sel3350_gpios_table
);
216 gpiod_remove_lookup_table(&sel3350_leds_table
);
221 static void sel3350_remove(struct platform_device
*pdev
)
223 struct sel3350_data
*sel3350
= platform_get_drvdata(pdev
);
225 platform_device_unregister(sel3350
->leds_pdev
);
226 gpiod_remove_lookup_table(&sel3350_gpios_table
);
227 gpiod_remove_lookup_table(&sel3350_leds_table
);
230 static const struct acpi_device_id sel3350_device_ids
[] = {
231 { B2093_GPIO_ACPI_ID
, 0 },
234 MODULE_DEVICE_TABLE(acpi
, sel3350_device_ids
);
236 static struct platform_driver sel3350_platform_driver
= {
237 .probe
= sel3350_probe
,
238 .remove
= sel3350_remove
,
240 .name
= "sel3350-platform",
241 .acpi_match_table
= sel3350_device_ids
,
244 module_platform_driver(sel3350_platform_driver
);
246 MODULE_AUTHOR("Schweitzer Engineering Laboratories");
247 MODULE_DESCRIPTION("SEL-3350 platform driver");
248 MODULE_LICENSE("Dual BSD/GPL");
249 MODULE_SOFTDEP("pre: pinctrl_broxton leds-gpio");