Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
L
linux-next
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Sebastian Krzyszkowiak
linux-next
Commits
e256d3a1
Verified
Commit
e256d3a1
authored
May 22, 2020
by
Sebastian Krzyszkowiak
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'mr-origin-77' into HEAD
parents
ef903bb1
980137a5
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
440 additions
and
2 deletions
+440
-2
arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi
arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi
+26
-1
arch/arm64/configs/librem5_defconfig
arch/arm64/configs/librem5_defconfig
+2
-1
include/dt-bindings/rfkill/rfkill.h
include/dt-bindings/rfkill/rfkill.h
+20
-0
include/linux/rfkill.h
include/linux/rfkill.h
+16
-0
include/uapi/linux/rfkill.h
include/uapi/linux/rfkill.h
+2
-0
net/rfkill/Kconfig
net/rfkill/Kconfig
+6
-0
net/rfkill/Makefile
net/rfkill/Makefile
+1
-0
net/rfkill/core.c
net/rfkill/core.c
+32
-0
net/rfkill/rfkill-hks.c
net/rfkill/rfkill-hks.c
+335
-0
No files found.
arch/arm64/boot/dts/freescale/imx8mq-librem5.dtsi
View file @
e256d3a1
...
...
@@ -9,6 +9,7 @@
#
include
"dt-bindings/leds/common.h"
#
include
"dt-bindings/pwm/pwm.h"
#
include
"dt-bindings/usb/pd.h"
#
include
"dt-bindings/rfkill/rfkill.h"
#
include
"imx8mq.dtsi"
#
define
GPIO_CONTROL
...
...
@@ -40,7 +41,7 @@ chosen {
gpio
-
keys
{
compatible
=
"gpio-keys"
;
pinctrl
-
names
=
"default"
;
pinctrl
-
0
=
<&
pinctrl_keys
>
,
<&
pinctrl_hsw
>
;
pinctrl
-
0
=
<&
pinctrl_keys
>;
vol
-
down
{
label
=
"VOL_DOWN"
;
...
...
@@ -362,6 +363,30 @@ rfkill-wwan {
};
#
endif
rfkill
-
hks
{
compatible
=
"rfkill-hks"
;
pinctrl
-
names
=
"default"
;
pinctrl
-
0
=
<&
pinctrl_hsw
>;
camera
{
gpios
=
<&
gpio4
1
GPIO_ACTIVE_LOW
>;
name
=
"camera"
;
type
=
<
RFKILL_CAMERA
>;
};
wlan
{
gpios
=
<&
gpio4
10
GPIO_ACTIVE_LOW
>;
name
=
"wlan"
;
type
=
<
RFKILL_WLAN
>;
};
wwan
{
gpios
=
<&
gpio4
0
GPIO_ACTIVE_LOW
>;
name
=
"wwan"
;
type
=
<
RFKILL_WWAN
>;
};
};
sound
{
compatible
=
"simple-audio-card"
;
pinctrl
-
0
=
<&
pinctrl_hp
>;
...
...
arch/arm64/configs/librem5_defconfig
View file @
e256d3a1
...
...
@@ -246,8 +246,9 @@ CONFIG_CFG80211_WEXT=y
CONFIG_MAC80211=m
CONFIG_MAC80211_LEDS=y
CONFIG_MAC80211_DEBUGFS=y
CONFIG_RFKILL=
m
CONFIG_RFKILL=
y
CONFIG_RFKILL_GPIO=m
CONFIG_RFKILL_HKS=y
CONFIG_NET_9P=y
CONFIG_NET_9P_VIRTIO=y
CONFIG_FAILOVER=y
...
...
include/dt-bindings/rfkill/rfkill.h
0 → 100644
View file @
e256d3a1
/* SPDX-License-Identifier: GPL-2.0 */
/*
* This header provides constants for rfkill keys bindings.
*/
#ifndef _DT_BINDINGS_RFKILL_H
#define _DT_BINDINGS_RFKILL_H
#define RFKILL_ALL 0
#define RFKILL_WLAN 1
#define RFKILL_BLUETOOTH 2
#define RFKILL_UWB 3
#define RFKILL_WIMAX 4
#define RFKILL_WWAN 5
#define RFKILL_GPS 6
#define RFKILL_FM 7
#define RFKILL_NFC 8
#define RFKILL_CAMERA 9
#endif
/* _DT_BINDINGS_RFKILL_H */
include/linux/rfkill.h
View file @
e256d3a1
...
...
@@ -82,6 +82,22 @@ struct rfkill * __must_check rfkill_alloc(const char *name,
const
struct
rfkill_ops
*
ops
,
void
*
ops_data
);
/**
* devm_rfkill_alloc - resource managed rfkill_alloc()
* @name: name of the struct -- the string is not copied internally
* @parent: device that has rf switch on it
* @type: type of the switch (RFKILL_TYPE_*)
* @ops: rfkill methods
* @ops_data: data passed to each method
*
* See rfkill_alloc() for more information.
*/
struct
rfkill
*
__must_check
devm_rfkill_alloc
(
const
char
*
name
,
struct
device
*
parent
,
const
enum
rfkill_type
type
,
const
struct
rfkill_ops
*
ops
,
void
*
ops_data
);
/**
* rfkill_register - Register a rfkill structure.
* @rfkill: rfkill structure to be registered
...
...
include/uapi/linux/rfkill.h
View file @
e256d3a1
...
...
@@ -38,6 +38,7 @@
* @RFKILL_TYPE_GPS: switch is on a GPS device.
* @RFKILL_TYPE_FM: switch is on a FM radio device.
* @RFKILL_TYPE_NFC: switch is on an NFC device.
* @RFKILL_TYPE_NFC: switch is on a camera device.
* @NUM_RFKILL_TYPES: number of defined rfkill types
*/
enum
rfkill_type
{
...
...
@@ -50,6 +51,7 @@ enum rfkill_type {
RFKILL_TYPE_GPS
,
RFKILL_TYPE_FM
,
RFKILL_TYPE_NFC
,
RFKILL_TYPE_CAMERA
,
NUM_RFKILL_TYPES
,
};
...
...
net/rfkill/Kconfig
View file @
e256d3a1
...
...
@@ -32,3 +32,9 @@ config RFKILL_GPIO
help
If you say yes here you get support of a generic gpio RFKILL
driver.
config RFKILL_HKS
tristate "RFKILL driver for hardware kill swiches"
depends on RFKILL
depends on GPIOLIB
default n
net/rfkill/Makefile
View file @
e256d3a1
...
...
@@ -7,3 +7,4 @@ rfkill-y += core.o
rfkill-$(CONFIG_RFKILL_INPUT)
+=
input.o
obj-$(CONFIG_RFKILL)
+=
rfkill.o
obj-$(CONFIG_RFKILL_GPIO)
+=
rfkill-gpio.o
obj-$(CONFIG_RFKILL_HKS)
+=
rfkill-hks.o
net/rfkill/core.c
View file @
e256d3a1
...
...
@@ -648,6 +648,7 @@ static const char * const rfkill_types[] = {
"gps"
,
"fm"
,
"nfc"
,
"camera"
,
};
enum
rfkill_type
rfkill_find_type
(
const
char
*
name
)
...
...
@@ -960,6 +961,37 @@ struct rfkill * __must_check rfkill_alloc(const char *name,
}
EXPORT_SYMBOL
(
rfkill_alloc
);
static
void
devm_rfkill_consume
(
struct
device
*
dev
,
void
*
res
)
{
struct
rfkill
*
rfkill
=
*
(
struct
rfkill
**
)
res
;
rfkill_destroy
(
rfkill
);
}
struct
rfkill
*
__must_check
devm_rfkill_alloc
(
const
char
*
name
,
struct
device
*
parent
,
const
enum
rfkill_type
type
,
const
struct
rfkill_ops
*
ops
,
void
*
ops_data
)
{
struct
rfkill
**
ptr
,
*
rfkill
;
ptr
=
devres_alloc
(
devm_rfkill_consume
,
sizeof
(
*
ptr
),
GFP_KERNEL
);
if
(
!
ptr
)
return
ERR_PTR
(
-
ENOMEM
);
rfkill
=
rfkill_alloc
(
name
,
parent
,
type
,
ops
,
ops_data
);
if
(
!
IS_ERR
(
rfkill
))
{
*
ptr
=
rfkill
;
devres_add
(
parent
,
ptr
);
}
else
{
devres_free
(
ptr
);
}
return
rfkill
;
}
EXPORT_SYMBOL_GPL
(
devm_rfkill_alloc
);
static
void
rfkill_poll
(
struct
work_struct
*
work
)
{
struct
rfkill
*
rfkill
;
...
...
net/rfkill/rfkill-hks.c
0 → 100644
View file @
e256d3a1
// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for rfkill status on GPIO lines capable of generating
* interrupts.
*
* Copyright 2020 Purism SPC
*
* Somewhat based on gpio-keys which is:
*
* Copyright 2005 Phil Blundell
* Copyright 2010, 2011 David Jander <david@protonic.nl>
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/rfkill.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/spinlock.h>
#include <dt-bindings/rfkill/rfkill.h>
struct
rfkill_hks_switch_pdata
{
int
gpio
;
int
active_low
;
int
debounce_interval
;
enum
rfkill_type
type
;
const
char
*
name
;
};
struct
rfkill_hks_pdata
{
const
struct
rfkill_hks_switch_pdata
*
switches
;
int
nswitches
;
const
char
*
name
;
};
struct
rfkill_hks_data
{
const
struct
rfkill_hks_switch_pdata
*
hks
;
struct
device
*
dev
;
struct
gpio_desc
*
gpiod
;
struct
rfkill
*
rfkill
;
struct
delayed_work
work
;
unsigned
int
software_debounce
;
/* in msecs, for GPIO-driven buttons */
unsigned
int
irq
;
spinlock_t
lock
;
};
struct
rfkill_hks
{
const
struct
rfkill_hks_pdata
*
pdata
;
struct
rfkill_hks_data
data
[];
};
static
void
rfkill_hks_gpio_report_event
(
struct
rfkill_hks_data
*
sdata
)
{
int
blocked
;
blocked
=
gpiod_get_value_cansleep
(
sdata
->
gpiod
);
if
(
blocked
<
0
)
{
dev_err
(
sdata
->
dev
,
"failed to get gpio state: %d
\n
"
,
blocked
);
return
;
}
dev_dbg
(
sdata
->
dev
,
"HKS %s blocked: %d
\n
"
,
sdata
->
hks
->
name
,
blocked
);
rfkill_set_hw_state
(
sdata
->
rfkill
,
blocked
);
}
static
void
rfkill_hks_gpio_work_func
(
struct
work_struct
*
work
)
{
struct
rfkill_hks_data
*
sdata
=
container_of
(
work
,
struct
rfkill_hks_data
,
work
.
work
);
rfkill_hks_gpio_report_event
(
sdata
);
}
static
irqreturn_t
rfkill_hks_gpio_isr
(
int
irq
,
void
*
dev_id
)
{
struct
rfkill_hks_data
*
sdata
=
dev_id
;
BUG_ON
(
irq
!=
sdata
->
irq
);
mod_delayed_work
(
system_wq
,
&
sdata
->
work
,
msecs_to_jiffies
(
sdata
->
software_debounce
));
return
IRQ_HANDLED
;
}
static
void
rfkill_hks_quiesce_key
(
void
*
data
)
{
struct
rfkill_hks_data
*
sdata
=
data
;
cancel_delayed_work_sync
(
&
sdata
->
work
);
}
static
int
rfkill_hks_set
(
void
*
data
,
bool
blocked
)
{
struct
rfkill_hks_data
*
sdata
=
data
;
/*
* Nothing to do here
*/
dev_dbg
(
sdata
->
dev
,
"%s: rfkill %s, blocked: %d
\n
"
,
__func__
,
sdata
->
hks
->
name
,
blocked
);
return
0
;
}
static
const
struct
rfkill_ops
rfkill_hks_ops
=
{
.
set_block
=
rfkill_hks_set
,
};
static
int
rfkill_hks_setup_rfkill
(
struct
platform_device
*
pdev
,
struct
rfkill_hks
*
ddata
,
const
struct
rfkill_hks_switch_pdata
*
hks
,
int
idx
,
struct
fwnode_handle
*
child
)
{
const
char
*
desc
=
hks
->
name
?
hks
->
name
:
"rfkill_hks"
;
struct
device
*
dev
=
&
pdev
->
dev
;
struct
rfkill_hks_data
*
sdata
=
&
ddata
->
data
[
idx
];
bool
active_low
;
int
ret
;
sdata
->
hks
=
hks
;
spin_lock_init
(
&
sdata
->
lock
);
sdata
->
dev
=
dev
;
sdata
->
gpiod
=
devm_fwnode_gpiod_get
(
dev
,
child
,
NULL
,
GPIOD_IN
,
desc
);
if
(
IS_ERR
(
sdata
->
gpiod
))
{
ret
=
PTR_ERR
(
sdata
->
gpiod
);
if
(
ret
!=
-
EPROBE_DEFER
)
dev_err
(
dev
,
"failed to get gpio: %d
\n
"
,
ret
);
return
ret
;
}
active_low
=
gpiod_is_active_low
(
sdata
->
gpiod
);
if
(
hks
->
debounce_interval
)
{
ret
=
gpiod_set_debounce
(
sdata
->
gpiod
,
hks
->
debounce_interval
*
1000
);
/* use timer if gpiolib doesn't provide debounce */
if
(
ret
<
0
)
sdata
->
software_debounce
=
hks
->
debounce_interval
;
}
ret
=
gpiod_to_irq
(
sdata
->
gpiod
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"Unable to get irq number for GPIO %d, error %d
\n
"
,
hks
->
gpio
,
ret
);
return
ret
;
}
sdata
->
irq
=
ret
;
INIT_DELAYED_WORK
(
&
sdata
->
work
,
rfkill_hks_gpio_work_func
);
/*
* Install custom action to cancel release timer and
* workqueue item.
*/
ret
=
devm_add_action
(
dev
,
rfkill_hks_quiesce_key
,
sdata
);
if
(
ret
)
{
dev_err
(
dev
,
"failed to register quiesce action, error: %d
\n
"
,
ret
);
return
ret
;
}
ret
=
devm_request_any_context_irq
(
dev
,
sdata
->
irq
,
rfkill_hks_gpio_isr
,
IRQF_TRIGGER_RISING
|
IRQF_TRIGGER_FALLING
,
desc
,
sdata
);
if
(
ret
<
0
)
{
dev_err
(
dev
,
"Unable to claim irq %d; error %d
\n
"
,
sdata
->
irq
,
ret
);
return
ret
;
}
sdata
->
rfkill
=
devm_rfkill_alloc
(
sdata
->
hks
->
name
,
dev
,
sdata
->
hks
->
type
,
&
rfkill_hks_ops
,
sdata
);
if
(
!
sdata
->
rfkill
)
return
-
ENOMEM
;
ret
=
rfkill_register
(
sdata
->
rfkill
);
if
(
ret
)
return
ret
;
rfkill_hks_gpio_report_event
(
sdata
);
return
0
;
}
/*
* Translate properties into platform_data
*/
static
struct
rfkill_hks_pdata
*
rfkill_hks_get_devtree_pdata
(
struct
device
*
dev
)
{
struct
rfkill_hks_pdata
*
pdata
;
struct
rfkill_hks_switch_pdata
*
hks
;
struct
fwnode_handle
*
child
;
int
nswitches
;
nswitches
=
device_get_child_node_count
(
dev
);
if
(
nswitches
==
0
)
return
ERR_PTR
(
-
ENODEV
);
pdata
=
devm_kzalloc
(
dev
,
sizeof
(
*
pdata
)
+
nswitches
*
sizeof
(
*
hks
),
GFP_KERNEL
);
if
(
!
pdata
)
return
ERR_PTR
(
-
ENOMEM
);
hks
=
(
struct
rfkill_hks_switch_pdata
*
)(
pdata
+
1
);
pdata
->
switches
=
hks
;
pdata
->
nswitches
=
nswitches
;
device_for_each_child_node
(
dev
,
child
)
{
int
ret
;
fwnode_property_read_string
(
child
,
"name"
,
&
hks
->
name
);
ret
=
fwnode_property_read_u32
(
child
,
"type"
,
&
hks
->
type
);
if
(
ret
)
{
dev_err
(
dev
,
"Missing rfkill type for %s"
,
hks
->
name
);
return
ERR_PTR
(
ret
);
}
if
(
hks
->
type
>=
NUM_RFKILL_TYPES
)
{
dev_err
(
dev
,
"Inalid rfkill type %d for %s"
,
hks
->
type
,
hks
->
name
);
return
ERR_PTR
(
-
EINVAL
);
}
if
(
fwnode_property_read_u32
(
child
,
"debounce-interval"
,
&
hks
->
debounce_interval
))
hks
->
debounce_interval
=
5
;
hks
++
;
}
return
pdata
;
}
static
const
struct
of_device_id
rfkill_hks_of_match
[]
=
{
{
.
compatible
=
"rfkill-hks"
,
},
{
},
};
MODULE_DEVICE_TABLE
(
of
,
rfkill_hks_of_match
);
static
int
rfkill_hks_probe
(
struct
platform_device
*
pdev
)
{
struct
device
*
dev
=
&
pdev
->
dev
;
const
struct
rfkill_hks_pdata
*
pdata
=
dev_get_platdata
(
dev
);
struct
fwnode_handle
*
child
=
NULL
;
struct
rfkill_hks
*
ddata
;
int
i
,
ret
;
if
(
!
pdata
)
{
pdata
=
rfkill_hks_get_devtree_pdata
(
dev
);
if
(
IS_ERR
(
pdata
))
return
PTR_ERR
(
pdata
);
}
ddata
=
devm_kzalloc
(
dev
,
struct_size
(
ddata
,
data
,
pdata
->
nswitches
),
GFP_KERNEL
);
if
(
!
ddata
)
{
dev_err
(
dev
,
"failed to allocate state
\n
"
);
return
-
ENOMEM
;
}
ddata
->
pdata
=
pdata
;
platform_set_drvdata
(
pdev
,
ddata
);
for
(
i
=
0
;
i
<
pdata
->
nswitches
;
i
++
)
{
const
struct
rfkill_hks_switch_pdata
*
hks
=
&
pdata
->
switches
[
i
];
if
(
!
dev_get_platdata
(
dev
))
{
child
=
device_get_next_child_node
(
dev
,
child
);
if
(
!
child
)
{
dev_err
(
dev
,
"missing child device node for entry %d
\n
"
,
i
);
return
-
EINVAL
;
}
}
ret
=
rfkill_hks_setup_rfkill
(
pdev
,
ddata
,
hks
,
i
,
child
);
if
(
ret
)
{
fwnode_handle_put
(
child
);
return
ret
;
}
}
fwnode_handle_put
(
child
);
return
0
;
}
static
struct
platform_driver
rfkill_hks_device_driver
=
{
.
probe
=
rfkill_hks_probe
,
.
driver
=
{
.
name
=
"rfkill-hks"
,
.
of_match_table
=
rfkill_hks_of_match
,
}
};
static
int
__init
rfkill_hks_init
(
void
)
{
return
platform_driver_register
(
&
rfkill_hks_device_driver
);
}
static
void
__exit
rfkill_hks_exit
(
void
)
{
platform_driver_unregister
(
&
rfkill_hks_device_driver
);
}
late_initcall
(
rfkill_hks_init
);
module_exit
(
rfkill_hks_exit
);
MODULE_LICENSE
(
"GPL"
);
MODULE_AUTHOR
(
"Guido Günther <agx@sigxcpu.org>"
);
MODULE_DESCRIPTION
(
"Hardware kill switch rfkill driver"
);
MODULE_ALIAS
(
"platform:rfkill-hks"
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment