35
35
#include <linux/list.h>
36
36
#include <linux/of_device.h>
37
37
#include <linux/of_gpio.h>
38
+ #include <linux/amlogic/aml_gpio_consumer.h>
39
+ #include <linux/amlogic/pinctrl_amlogic.h>
40
+ /* AMLogic GPIO irq bank start offset */
41
+ #define AMLGPIO_IRQ_BASE 96
38
42
39
43
/* Info for each registered platform device */
40
- struct pps_gpio_device_data {
44
+ static struct pps_gpio_device_data {
41
45
int irq ; /* IRQ used as PPS source */
42
46
struct pps_device * pps ; /* PPS source device */
43
47
struct pps_source_info info ; /* PPS source information */
44
- bool assert_falling_edge ;
45
48
bool capture_clear ;
46
49
unsigned int gpio_pin ;
47
- };
50
+ } pps_data ;
51
+
52
+ // Default GPIO. Use parameters during module load to override.
53
+ // note: this only handles one instance of pps-gpio. If you want more, use the devicetree version
54
+ static int gpio_pin = 238 ; // GPIOX_10 / pin 12
55
+ module_param (gpio_pin , int , S_IRUSR | S_IRGRP | S_IROTH );
56
+ MODULE_PARM_DESC (gpio_pin , "GPIO pin number (\"Export GPIO\" type), default=238 (GPIOX_10 / pin 12)" );
57
+
58
+ static int assert_falling_edge = 0 ;
59
+ module_param (assert_falling_edge , int , S_IRUSR | S_IRGRP | S_IROTH );
60
+ MODULE_PARM_DESC (assert_falling_edge , "use the falling edge instead of the rising edge, default=0 (rising)" );
48
61
49
62
/*
50
63
* Report the PPS event
51
64
*/
52
65
53
66
static irqreturn_t pps_gpio_irq_handler (int irq , void * data )
54
67
{
55
- const struct pps_gpio_device_data * info ;
56
68
struct pps_event_time ts ;
57
69
int rising_edge ;
58
70
59
71
/* Get the time stamp first */
60
72
pps_get_ts (& ts );
61
73
62
- info = data ;
63
-
64
- rising_edge = gpio_get_value (info -> gpio_pin );
65
- if ((rising_edge && !info -> assert_falling_edge ) ||
66
- (!rising_edge && info -> assert_falling_edge ))
67
- pps_event (info -> pps , & ts , PPS_CAPTUREASSERT , NULL );
68
- else if (info -> capture_clear &&
69
- ((rising_edge && info -> assert_falling_edge ) ||
70
- (!rising_edge && !info -> assert_falling_edge )))
71
- pps_event (info -> pps , & ts , PPS_CAPTURECLEAR , NULL );
74
+ rising_edge = gpio_get_value (pps_data .gpio_pin );
75
+ if ((rising_edge && !assert_falling_edge ) ||
76
+ (!rising_edge && assert_falling_edge ))
77
+ pps_event (pps_data .pps , & ts , PPS_CAPTUREASSERT , NULL );
78
+ else if (pps_data .capture_clear &&
79
+ ((rising_edge && assert_falling_edge ) ||
80
+ (!rising_edge && !assert_falling_edge )))
81
+ pps_event (pps_data .pps , & ts , PPS_CAPTURECLEAR , NULL );
72
82
73
83
return IRQ_HANDLED ;
74
84
}
75
85
76
86
static unsigned long
77
87
get_irqf_trigger_flags (const struct pps_gpio_device_data * data )
78
88
{
79
- unsigned long flags = data -> assert_falling_edge ?
89
+ unsigned long flags = assert_falling_edge ?
80
90
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING ;
81
91
82
92
if (data -> capture_clear ) {
@@ -87,125 +97,143 @@ get_irqf_trigger_flags(const struct pps_gpio_device_data *data)
87
97
return flags ;
88
98
}
89
99
90
- static int pps_gpio_probe (struct platform_device * pdev )
100
+ static int pps_gpio_irq_setup (unsigned int gpio_pin )
101
+ {
102
+ struct gpio_chip * chip ;
103
+ int ret ;
104
+ unsigned long irq_flags ;
105
+ int irq_banks [2 ] = {0 , 0 };
106
+
107
+ chip = gpio_to_chip (gpio_pin );
108
+ if (!chip )
109
+ return - EINVAL ;
110
+
111
+ // gpio_to_irq translates from global GPIO # to chip offset, which meson_setup_irq wants
112
+ gpio_pin = gpio_to_irq (gpio_pin );
113
+
114
+ irq_flags = assert_falling_edge ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING ;
115
+ ret = meson_setup_irq (chip , gpio_pin , irq_flags , & irq_banks [0 ]);
116
+ if (ret < 0 )
117
+ return - EINVAL ;
118
+
119
+ if (irq_banks [0 ] != -1 )
120
+ return irq_banks [0 ] + AMLGPIO_IRQ_BASE ;
121
+ if (irq_banks [1 ] != -1 )
122
+ return irq_banks [1 ] + AMLGPIO_IRQ_BASE ;
123
+
124
+ return - EINVAL ;
125
+ }
126
+
127
+ static void pps_gpio_release (struct device * dev ) {
128
+ // does nothing, everything is allocated as part of the module
129
+ }
130
+
131
+ static struct device pps_gpio_dev = {
132
+ .id = 0 ,
133
+ .parent = & platform_bus ,
134
+ .release = & pps_gpio_release
135
+ };
136
+
137
+ static int __init pps_gpio_init (void )
91
138
{
92
- struct pps_gpio_device_data * data ;
93
- const char * gpio_label ;
94
139
int ret ;
95
140
int pps_default_params ;
96
- const struct pps_gpio_platform_data * pdata = pdev -> dev .platform_data ;
97
- struct device_node * np = pdev -> dev .of_node ;
98
-
99
- /* allocate space for device info */
100
- data = devm_kzalloc (& pdev -> dev , sizeof (struct pps_gpio_device_data ),
101
- GFP_KERNEL );
102
- if (!data )
103
- return - ENOMEM ;
104
-
105
- if (pdata ) {
106
- data -> gpio_pin = pdata -> gpio_pin ;
107
- gpio_label = pdata -> gpio_label ;
108
-
109
- data -> assert_falling_edge = pdata -> assert_falling_edge ;
110
- data -> capture_clear = pdata -> capture_clear ;
111
- } else {
112
- ret = of_get_gpio (np , 0 );
113
- if (ret < 0 ) {
114
- dev_err (& pdev -> dev , "failed to get GPIO from device tree\n" );
115
- return ret ;
116
- }
117
- data -> gpio_pin = ret ;
118
- gpio_label = PPS_GPIO_NAME ;
119
-
120
- if (of_get_property (np , "assert-falling-edge" , NULL ))
121
- data -> assert_falling_edge = true;
141
+
142
+ /* register the device */
143
+ ret = dev_set_name (& pps_gpio_dev , "%s%d" , PPS_GPIO_NAME , pps_gpio_dev .id );
144
+ if (ret < 0 ) {
145
+ pr_err ("dev_set_name failed with %d\n" , ret );
146
+ return ret ;
147
+ }
148
+ ret = device_register (& pps_gpio_dev );
149
+ if (ret < 0 ) {
150
+ pr_err ("device_register failed with %d\n" , ret );
151
+ return ret ;
122
152
}
123
153
154
+ pps_data .gpio_pin = gpio_pin ;
155
+
124
156
/* GPIO setup */
125
- ret = devm_gpio_request (& pdev -> dev , data -> gpio_pin , gpio_label );
157
+ ret = devm_gpio_request (& pps_gpio_dev , pps_data . gpio_pin , "PPS-GPIO" );
126
158
if (ret ) {
127
- dev_err (& pdev -> dev , "failed to request GPIO %u\n" ,
128
- data -> gpio_pin );
159
+ dev_err (& pps_gpio_dev , "failed to request GPIO %u\n" ,
160
+ pps_data . gpio_pin );
129
161
return ret ;
130
162
}
131
163
132
- ret = gpio_direction_input (data -> gpio_pin );
164
+ ret = gpio_direction_input (pps_data . gpio_pin );
133
165
if (ret ) {
134
- dev_err (& pdev -> dev , "failed to set pin direction\n" );
166
+ dev_err (& pps_gpio_dev , "failed to set pin direction\n" );
135
167
return - EINVAL ;
136
168
}
137
169
138
170
/* IRQ setup */
139
- ret = gpio_to_irq ( data -> gpio_pin );
171
+ ret = pps_gpio_irq_setup ( pps_data . gpio_pin );
140
172
if (ret < 0 ) {
141
- dev_err (& pdev -> dev , "failed to map GPIO to IRQ: %d\n" , ret );
173
+ dev_err (& pps_gpio_dev , "failed to map GPIO to IRQ: %d\n" , ret );
142
174
return - EINVAL ;
143
175
}
144
- data -> irq = ret ;
176
+ pps_data . irq = ret ;
145
177
146
178
/* initialize PPS specific parts of the bookkeeping data structure. */
147
- data -> info .mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
179
+ pps_data . info .mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
148
180
PPS_ECHOASSERT | PPS_CANWAIT | PPS_TSFMT_TSPEC ;
149
- if (data -> capture_clear )
150
- data -> info .mode |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR |
181
+ if (pps_data . capture_clear )
182
+ pps_data . info .mode |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR |
151
183
PPS_ECHOCLEAR ;
152
- data -> info .owner = THIS_MODULE ;
153
- snprintf (data -> info .name , PPS_MAX_NAME_LEN - 1 , "%s.%d" ,
154
- pdev -> name , pdev -> id );
184
+ pps_data . info .owner = THIS_MODULE ;
185
+ snprintf (pps_data . info .name , PPS_MAX_NAME_LEN - 1 , "%s.%d" ,
186
+ PPS_GPIO_NAME , pps_gpio_dev . id );
155
187
156
188
/* register PPS source */
157
189
pps_default_params = PPS_CAPTUREASSERT | PPS_OFFSETASSERT ;
158
- if (data -> capture_clear )
190
+ if (pps_data . capture_clear )
159
191
pps_default_params |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR ;
160
- data -> pps = pps_register_source (& data -> info , pps_default_params );
161
- if (data -> pps == NULL ) {
162
- dev_err (& pdev -> dev , "failed to register IRQ %d as PPS source\n" ,
163
- data -> irq );
192
+ pps_data . pps = pps_register_source (& pps_data . info , pps_default_params );
193
+ if (pps_data . pps == NULL ) {
194
+ dev_err (& pps_gpio_dev , "failed to register IRQ %d as PPS source\n" ,
195
+ pps_data . irq );
164
196
return - EINVAL ;
165
197
}
166
198
167
199
/* register IRQ interrupt handler */
168
- ret = devm_request_irq (& pdev -> dev , data -> irq , pps_gpio_irq_handler ,
169
- get_irqf_trigger_flags (data ), data -> info .name , data );
200
+ #if 0
201
+ IRQF_DISABLED | IRQF_ONESHOT
202
+ ret = devm_request_irq (& pps_gpio_dev , pps_data .irq , pps_gpio_irq_handler ,
203
+ get_irqf_trigger_flags (& pps_data ), pps_data .info .name , NULL );
204
+ #endif
205
+ ret = devm_request_irq (& pps_gpio_dev , pps_data .irq , pps_gpio_irq_handler ,
206
+ IRQF_DISABLED | IRQF_ONESHOT , pps_data .info .name , NULL );
170
207
if (ret ) {
171
- pps_unregister_source (data -> pps );
172
- dev_err (& pdev -> dev , "failed to acquire IRQ %d\n" , data -> irq );
208
+ pps_unregister_source (pps_data . pps );
209
+ dev_err (& pps_gpio_dev , "failed to acquire IRQ %d\n" , pps_data . irq );
173
210
return - EINVAL ;
174
211
}
175
212
176
- platform_set_drvdata (pdev , data );
177
- dev_info (data -> pps -> dev , "Registered IRQ %d as PPS source\n" ,
178
- data -> irq );
213
+ dev_info (pps_data .pps -> dev , "Registered IRQ %d as PPS source. (gpio = %d, edge = %s)\n" ,
214
+ pps_data .irq , pps_data .gpio_pin , assert_falling_edge ? "falling" : "rising" );
179
215
180
216
return 0 ;
181
217
}
182
218
183
- static int pps_gpio_remove ( struct platform_device * pdev )
219
+ static void __exit pps_gpio_exit ( void )
184
220
{
185
- struct pps_gpio_device_data * data = platform_get_drvdata (pdev );
221
+ unsigned int gpio_pin ;
222
+ int irq_banks [2 ] = {0 , 0 };
186
223
187
- pps_unregister_source (data -> pps );
188
- dev_info (& pdev -> dev , "removed IRQ %d as PPS source\n" , data -> irq );
189
- return 0 ;
224
+ // gpio_to_irq translates from global GPIO # to chip offset, which meson_free_irq wants
225
+ gpio_pin = gpio_to_irq (pps_data .gpio_pin );
226
+ meson_free_irq (gpio_pin , irq_banks );
227
+
228
+ pps_unregister_source (pps_data .pps );
229
+ dev_info (& pps_gpio_dev , "removed IRQ %d as PPS source\n" , pps_data .irq );
230
+
231
+ device_unregister (& pps_gpio_dev );
190
232
}
191
233
192
- static const struct of_device_id pps_gpio_dt_ids [] = {
193
- { .compatible = "pps-gpio" , },
194
- { /* sentinel */ }
195
- };
196
- MODULE_DEVICE_TABLE (of , pps_gpio_dt_ids );
197
-
198
- static struct platform_driver pps_gpio_driver = {
199
- .probe = pps_gpio_probe ,
200
- .remove = pps_gpio_remove ,
201
- .driver = {
202
- .name = PPS_GPIO_NAME ,
203
- .owner = THIS_MODULE ,
204
- .of_match_table = pps_gpio_dt_ids ,
205
- },
206
- };
234
+ module_init (pps_gpio_init );
235
+ module_exit (pps_gpio_exit );
207
236
208
- module_platform_driver (pps_gpio_driver );
209
237
MODULE_AUTHOR (
"Ricardo Martins <[email protected] >" );
210
238
MODULE_AUTHOR (
"James Nuss <[email protected] >" );
211
239
MODULE_DESCRIPTION ("Use GPIO pin as PPS source" );
0 commit comments