Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
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
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
11438237
Commit
11438237
authored
Aug 31, 2023
by
Benjamin Tissoires
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'for-6.6/cp2112' into for-linus
Cleanup of the hid-cp2112 driver by Andy Shevchenko
parents
0c4b9411
a6a5eccc
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
58 additions
and
112 deletions
+58
-112
drivers/hid/hid-cp2112.c
drivers/hid/hid-cp2112.c
+57
-112
include/linux/string_choices.h
include/linux/string_choices.h
+1
-0
No files found.
drivers/hid/hid-cp2112.c
View file @
11438237
...
...
@@ -16,14 +16,14 @@
* https://www.silabs.com/documents/public/application-notes/an495-cp2112-interface-specification.pdf
*/
#include <linux/gpio/consumer.h>
#include <linux/gpio/machine.h>
#include <linux/bitops.h>
#include <linux/gpio/driver.h>
#include <linux/hid.h>
#include <linux/hidraw.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/nls.h>
#include <linux/string_choices.h>
#include <linux/usb/ch9.h>
#include "hid-ids.h"
...
...
@@ -31,6 +31,8 @@
#define CP2112_GPIO_CONFIG_LENGTH 5
#define CP2112_GPIO_GET_LENGTH 2
#define CP2112_GPIO_SET_LENGTH 3
#define CP2112_GPIO_MAX_GPIO 8
#define CP2112_GPIO_ALL_GPIO_MASK GENMASK(7, 0)
enum
{
CP2112_GPIO_CONFIG
=
0x02
,
...
...
@@ -163,19 +165,17 @@ struct cp2112_device {
atomic_t
read_avail
;
atomic_t
xfer_avail
;
struct
gpio_chip
gc
;
struct
irq_chip
irq
;
u8
*
in_out_buffer
;
struct
mutex
lock
;
struct
gpio_desc
*
desc
[
8
];
bool
gpio_poll
;
struct
delayed_work
gpio_poll_worker
;
unsigned
long
irq_mask
;
u8
gpio_prev_state
;
};
static
int
gpio_push_pull
=
0xFF
;
module_param
(
gpio_push_pull
,
int
,
S_IRUGO
|
S_IWUSR
);
static
int
gpio_push_pull
=
CP2112_GPIO_ALL_GPIO_MASK
;
module_param
(
gpio_push_pull
,
int
,
0644
);
MODULE_PARM_DESC
(
gpio_push_pull
,
"GPIO push-pull configuration bitmask"
);
static
int
cp2112_gpio_direction_input
(
struct
gpio_chip
*
chip
,
unsigned
offset
)
...
...
@@ -197,7 +197,7 @@ static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
goto
exit
;
}
buf
[
1
]
&=
~
(
1
<<
offset
);
buf
[
1
]
&=
~
BIT
(
offset
);
buf
[
2
]
=
gpio_push_pull
;
ret
=
hid_hw_raw_request
(
hdev
,
CP2112_GPIO_CONFIG
,
buf
,
...
...
@@ -227,8 +227,8 @@ static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
mutex_lock
(
&
dev
->
lock
);
buf
[
0
]
=
CP2112_GPIO_SET
;
buf
[
1
]
=
value
?
0xff
:
0
;
buf
[
2
]
=
1
<<
offset
;
buf
[
1
]
=
value
?
CP2112_GPIO_ALL_GPIO_MASK
:
0
;
buf
[
2
]
=
BIT
(
offset
)
;
ret
=
hid_hw_raw_request
(
hdev
,
CP2112_GPIO_SET
,
buf
,
CP2112_GPIO_SET_LENGTH
,
HID_FEATURE_REPORT
,
...
...
@@ -532,15 +532,13 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
hid_dbg
(
hdev
,
"I2C %d messages
\n
"
,
num
);
if
(
num
==
1
)
{
hid_dbg
(
hdev
,
"I2C %s %#04x len %d
\n
"
,
str_read_write
(
msgs
->
flags
&
I2C_M_RD
),
msgs
->
addr
,
msgs
->
len
);
if
(
msgs
->
flags
&
I2C_M_RD
)
{
hid_dbg
(
hdev
,
"I2C read %#04x len %d
\n
"
,
msgs
->
addr
,
msgs
->
len
);
read_length
=
msgs
->
len
;
read_buf
=
msgs
->
buf
;
count
=
cp2112_read_req
(
buf
,
msgs
->
addr
,
msgs
->
len
);
}
else
{
hid_dbg
(
hdev
,
"I2C write %#04x len %d
\n
"
,
msgs
->
addr
,
msgs
->
len
);
count
=
cp2112_i2c_write_req
(
buf
,
msgs
->
addr
,
msgs
->
buf
,
msgs
->
len
);
}
...
...
@@ -648,7 +646,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr,
int
ret
;
hid_dbg
(
hdev
,
"%s addr 0x%x flags 0x%x cmd 0x%x size %d
\n
"
,
read_write
==
I2C_SMBUS_WRITE
?
"write"
:
"read"
,
str_write_read
(
read_write
==
I2C_SMBUS_WRITE
)
,
addr
,
flags
,
command
,
size
);
switch
(
size
)
{
...
...
@@ -895,7 +893,7 @@ static ssize_t name##_show(struct device *kdev, \
int ret = cp2112_get_usb_config(hdev, &cfg); \
if (ret) \
return ret; \
return s
cnprintf(buf, PAGE_SIZE
, format, ##__VA_ARGS__); \
return s
ysfs_emit(buf
, format, ##__VA_ARGS__); \
} \
static DEVICE_ATTR_RW(name);
...
...
@@ -946,18 +944,10 @@ CP2112_CONFIG_ATTR(release_version, ({
#undef CP2112_CONFIG_ATTR
struct
cp2112_pstring_attribute
{
struct
device_attribute
attr
;
unsigned
char
report
;
};
static
ssize_t
pstr_store
(
struct
device
*
kdev
,
struct
device_attribute
*
kattr
,
const
char
*
buf
,
size_t
count
)
static
ssize_t
pstr_store
(
struct
device
*
kdev
,
struct
device_attribute
*
kattr
,
const
char
*
buf
,
size_t
count
,
int
number
)
{
struct
hid_device
*
hdev
=
to_hid_device
(
kdev
);
struct
cp2112_pstring_attribute
*
attr
=
container_of
(
kattr
,
struct
cp2112_pstring_attribute
,
attr
);
struct
cp2112_string_report
report
;
int
ret
;
...
...
@@ -965,7 +955,7 @@ static ssize_t pstr_store(struct device *kdev,
ret
=
utf8s_to_utf16s
(
buf
,
count
,
UTF16_LITTLE_ENDIAN
,
report
.
string
,
ARRAY_SIZE
(
report
.
string
));
report
.
report
=
attr
->
report
;
report
.
report
=
number
;
report
.
length
=
ret
*
sizeof
(
report
.
string
[
0
])
+
2
;
report
.
type
=
USB_DT_STRING
;
...
...
@@ -983,17 +973,15 @@ static ssize_t pstr_store(struct device *kdev,
return
count
;
}
static
ssize_t
pstr_show
(
struct
device
*
kdev
,
struct
device_attribute
*
kattr
,
char
*
buf
)
static
ssize_t
pstr_show
(
struct
device
*
kdev
,
struct
device_attribute
*
kattr
,
char
*
buf
,
int
number
)
{
struct
hid_device
*
hdev
=
to_hid_device
(
kdev
);
struct
cp2112_pstring_attribute
*
attr
=
container_of
(
kattr
,
struct
cp2112_pstring_attribute
,
attr
);
struct
cp2112_string_report
report
;
u8
length
;
int
ret
;
ret
=
cp2112_hid_get
(
hdev
,
attr
->
report
,
(
u8
*
)
&
report
.
contents
,
ret
=
cp2112_hid_get
(
hdev
,
number
,
(
u8
*
)
&
report
.
contents
,
sizeof
(
report
.
contents
),
HID_FEATURE_REPORT
);
if
(
ret
<
3
)
{
hid_err
(
hdev
,
"error reading %s string: %d
\n
"
,
kattr
->
attr
.
name
,
...
...
@@ -1018,10 +1006,16 @@ static ssize_t pstr_show(struct device *kdev,
}
#define CP2112_PSTR_ATTR(name, _report) \
static struct cp2112_pstring_attribute dev_attr_##name = { \
.attr = __ATTR(name, (S_IWUSR | S_IRUGO), pstr_show, pstr_store), \
.report = _report, \
};
static ssize_t name##_store(struct device *kdev, struct device_attribute *kattr, \
const char *buf, size_t count) \
{ \
return pstr_store(kdev, kattr, buf, count, _report); \
} \
static ssize_t name##_show(struct device *kdev, struct device_attribute *kattr, char *buf) \
{ \
return pstr_show(kdev, kattr, buf, _report); \
} \
static DEVICE_ATTR_RW(name);
CP2112_PSTR_ATTR
(
manufacturer
,
CP2112_MANUFACTURER_STRING
);
CP2112_PSTR_ATTR
(
product
,
CP2112_PRODUCT_STRING
);
...
...
@@ -1036,9 +1030,9 @@ static const struct attribute_group cp2112_attr_group = {
&
dev_attr_max_power
.
attr
,
&
dev_attr_power_mode
.
attr
,
&
dev_attr_release_version
.
attr
,
&
dev_attr_manufacturer
.
attr
.
attr
,
&
dev_attr_product
.
attr
.
attr
,
&
dev_attr_serial
.
attr
.
attr
,
&
dev_attr_manufacturer
.
attr
,
&
dev_attr_product
.
attr
,
&
dev_attr_serial
.
attr
,
NULL
}
};
...
...
@@ -1063,7 +1057,7 @@ static void chmod_sysfs_attrs(struct hid_device *hdev)
}
for
(
attr
=
cp2112_attr_group
.
attrs
;
*
attr
;
++
attr
)
{
umode_t
mode
=
(
buf
[
1
]
&
1
)
?
S_IWUSR
|
S_IRUGO
:
S_IRUGO
;
umode_t
mode
=
(
buf
[
1
]
&
1
)
?
0644
:
0444
;
ret
=
sysfs_chmod_file
(
&
hdev
->
dev
.
kobj
,
*
attr
,
mode
);
if
(
ret
<
0
)
hid_err
(
hdev
,
"error chmoding sysfs file %s
\n
"
,
...
...
@@ -1080,16 +1074,20 @@ static void cp2112_gpio_irq_mask(struct irq_data *d)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
cp2112_device
*
dev
=
gpiochip_get_data
(
gc
);
irq_hw_number_t
hwirq
=
irqd_to_hwirq
(
d
);
__clear_bit
(
d
->
hwirq
,
&
dev
->
irq_mask
);
__clear_bit
(
hwirq
,
&
dev
->
irq_mask
);
gpiochip_disable_irq
(
gc
,
hwirq
);
}
static
void
cp2112_gpio_irq_unmask
(
struct
irq_data
*
d
)
{
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
cp2112_device
*
dev
=
gpiochip_get_data
(
gc
);
irq_hw_number_t
hwirq
=
irqd_to_hwirq
(
d
);
__set_bit
(
d
->
hwirq
,
&
dev
->
irq_mask
);
gpiochip_enable_irq
(
gc
,
hwirq
);
__set_bit
(
hwirq
,
&
dev
->
irq_mask
);
}
static
void
cp2112_gpio_poll_callback
(
struct
work_struct
*
work
)
...
...
@@ -1098,7 +1096,6 @@ static void cp2112_gpio_poll_callback(struct work_struct *work)
gpio_poll_worker
.
work
);
struct
irq_data
*
d
;
u8
gpio_mask
;
u8
virqs
=
(
u8
)
dev
->
irq_mask
;
u32
irq_type
;
int
irq
,
virq
,
ret
;
...
...
@@ -1109,15 +1106,10 @@ static void cp2112_gpio_poll_callback(struct work_struct *work)
goto
exit
;
gpio_mask
=
ret
;
while
(
virqs
)
{
virq
=
ffs
(
virqs
)
-
1
;
virqs
&=
~
BIT
(
virq
);
if
(
!
dev
->
gc
.
to_irq
)
break
;
irq
=
dev
->
gc
.
to_irq
(
&
dev
->
gc
,
virq
);
for_each_set_bit
(
virq
,
&
dev
->
irq_mask
,
CP2112_GPIO_MAX_GPIO
)
{
irq
=
irq_find_mapping
(
dev
->
gc
.
irq
.
domain
,
virq
);
if
(
!
irq
)
continue
;
d
=
irq_get_irq_data
(
irq
);
if
(
!
d
)
...
...
@@ -1175,6 +1167,7 @@ static void cp2112_gpio_irq_shutdown(struct irq_data *d)
struct
gpio_chip
*
gc
=
irq_data_get_irq_chip_data
(
d
);
struct
cp2112_device
*
dev
=
gpiochip_get_data
(
gc
);
cp2112_gpio_irq_mask
(
d
);
cancel_delayed_work_sync
(
&
dev
->
gpio_poll_worker
);
}
...
...
@@ -1183,50 +1176,17 @@ static int cp2112_gpio_irq_type(struct irq_data *d, unsigned int type)
return
0
;
}
static
int
__maybe_unused
cp2112_allocate_irq
(
struct
cp2112_device
*
dev
,
int
pin
)
{
int
ret
;
if
(
dev
->
desc
[
pin
])
return
-
EINVAL
;
dev
->
desc
[
pin
]
=
gpiochip_request_own_desc
(
&
dev
->
gc
,
pin
,
"HID/I2C:Event"
,
GPIO_ACTIVE_HIGH
,
GPIOD_IN
);
if
(
IS_ERR
(
dev
->
desc
[
pin
]))
{
dev_err
(
dev
->
gc
.
parent
,
"Failed to request GPIO
\n
"
);
return
PTR_ERR
(
dev
->
desc
[
pin
]);
}
ret
=
cp2112_gpio_direction_input
(
&
dev
->
gc
,
pin
);
if
(
ret
<
0
)
{
dev_err
(
dev
->
gc
.
parent
,
"Failed to set GPIO to input dir
\n
"
);
goto
err_desc
;
}
ret
=
gpiochip_lock_as_irq
(
&
dev
->
gc
,
pin
);
if
(
ret
)
{
dev_err
(
dev
->
gc
.
parent
,
"Failed to lock GPIO as interrupt
\n
"
);
goto
err_desc
;
}
ret
=
gpiod_to_irq
(
dev
->
desc
[
pin
]);
if
(
ret
<
0
)
{
dev_err
(
dev
->
gc
.
parent
,
"Failed to translate GPIO to IRQ
\n
"
);
goto
err_lock
;
}
return
ret
;
err_lock:
gpiochip_unlock_as_irq
(
&
dev
->
gc
,
pin
);
err_desc:
gpiochip_free_own_desc
(
dev
->
desc
[
pin
]);
dev
->
desc
[
pin
]
=
NULL
;
return
ret
;
}
static
const
struct
irq_chip
cp2112_gpio_irqchip
=
{
.
name
=
"cp2112-gpio"
,
.
irq_startup
=
cp2112_gpio_irq_startup
,
.
irq_shutdown
=
cp2112_gpio_irq_shutdown
,
.
irq_ack
=
cp2112_gpio_irq_ack
,
.
irq_mask
=
cp2112_gpio_irq_mask
,
.
irq_unmask
=
cp2112_gpio_irq_unmask
,
.
irq_set_type
=
cp2112_gpio_irq_type
,
.
flags
=
IRQCHIP_MASK_ON_SUSPEND
|
IRQCHIP_IMMUTABLE
,
GPIOCHIP_IRQ_RESOURCE_HELPERS
,
};
static
int
cp2112_probe
(
struct
hid_device
*
hdev
,
const
struct
hid_device_id
*
id
)
{
...
...
@@ -1333,21 +1293,12 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
dev
->
gc
.
set
=
cp2112_gpio_set
;
dev
->
gc
.
get
=
cp2112_gpio_get
;
dev
->
gc
.
base
=
-
1
;
dev
->
gc
.
ngpio
=
8
;
dev
->
gc
.
ngpio
=
CP2112_GPIO_MAX_GPIO
;
dev
->
gc
.
can_sleep
=
1
;
dev
->
gc
.
parent
=
&
hdev
->
dev
;
dev
->
irq
.
name
=
"cp2112-gpio"
;
dev
->
irq
.
irq_startup
=
cp2112_gpio_irq_startup
;
dev
->
irq
.
irq_shutdown
=
cp2112_gpio_irq_shutdown
;
dev
->
irq
.
irq_ack
=
cp2112_gpio_irq_ack
;
dev
->
irq
.
irq_mask
=
cp2112_gpio_irq_mask
;
dev
->
irq
.
irq_unmask
=
cp2112_gpio_irq_unmask
;
dev
->
irq
.
irq_set_type
=
cp2112_gpio_irq_type
;
dev
->
irq
.
flags
=
IRQCHIP_MASK_ON_SUSPEND
;
girq
=
&
dev
->
gc
.
irq
;
g
irq
->
chip
=
&
dev
->
irq
;
g
pio_irq_chip_set_chip
(
girq
,
&
cp2112_gpio_irqchip
)
;
/* The event comes from the outside so no parent handler */
girq
->
parent_handler
=
NULL
;
girq
->
num_parents
=
0
;
...
...
@@ -1389,7 +1340,6 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
static
void
cp2112_remove
(
struct
hid_device
*
hdev
)
{
struct
cp2112_device
*
dev
=
hid_get_drvdata
(
hdev
);
int
i
;
sysfs_remove_group
(
&
hdev
->
dev
.
kobj
,
&
cp2112_attr_group
);
i2c_del_adapter
(
&
dev
->
adap
);
...
...
@@ -1399,11 +1349,6 @@ static void cp2112_remove(struct hid_device *hdev)
cancel_delayed_work_sync
(
&
dev
->
gpio_poll_worker
);
}
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
dev
->
desc
);
i
++
)
{
gpiochip_unlock_as_irq
(
&
dev
->
gc
,
i
);
gpiochip_free_own_desc
(
dev
->
desc
[
i
]);
}
gpiochip_remove
(
&
dev
->
gc
);
/* i2c_del_adapter has finished removing all i2c devices from our
* adapter. Well behaved devices should no longer call our cp2112_xfer
...
...
include/linux/string_choices.h
View file @
11438237
...
...
@@ -30,6 +30,7 @@ static inline const char *str_read_write(bool v)
{
return
v
?
"read"
:
"write"
;
}
#define str_write_read(v) str_read_write(!(v))
static
inline
const
char
*
str_on_off
(
bool
v
)
{
...
...
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