1212#include <linux/of.h>
1313#include <linux/of_graph.h>
1414#include <linux/of_platform.h>
15+ #include <linux/pci.h>
1516#include <linux/platform_device.h>
1617#include <linux/pwrseq/provider.h>
1718#include <linux/regulator/consumer.h>
19+ #include <linux/serdev.h>
1820#include <linux/slab.h>
1921
2022struct pwrseq_pcie_m2_pdata {
@@ -30,6 +32,9 @@ struct pwrseq_pcie_m2_ctx {
3032 struct notifier_block nb ;
3133 struct gpio_desc * w_disable1_gpio ;
3234 struct gpio_desc * w_disable2_gpio ;
35+ struct serdev_device * serdev ;
36+ struct of_changeset * ocs ;
37+ struct device * dev ;
3338};
3439
3540static int pwrseq_pcie_m2_vregs_enable (struct pwrseq_device * pwrseq )
@@ -172,11 +177,202 @@ static int pwrseq_pcie_m2_match(struct pwrseq_device *pwrseq,
172177 return PWRSEQ_NO_MATCH ;
173178}
174179
175- static void pwrseq_pcie_m2_free_regulators (void * data )
180+ static int pwrseq_m2_pcie_create_bt_node (struct pwrseq_pcie_m2_ctx * ctx ,
181+ struct device_node * parent )
176182{
177- struct pwrseq_pcie_m2_ctx * ctx = data ;
183+ struct device * dev = ctx -> dev ;
184+ struct device_node * np ;
185+ int ret ;
178186
179- regulator_bulk_free (ctx -> num_vregs , ctx -> regs );
187+ ctx -> ocs = kzalloc_obj (* ctx -> ocs );
188+ if (!ctx -> ocs )
189+ return - ENOMEM ;
190+
191+ of_changeset_init (ctx -> ocs );
192+
193+ np = of_changeset_create_node (ctx -> ocs , parent , "bluetooth" );
194+ if (!np ) {
195+ dev_err (dev , "Failed to create bluetooth node\n" );
196+ ret = - ENODEV ;
197+ goto err_destroy_changeset ;
198+ }
199+
200+ ret = of_changeset_add_prop_string (ctx -> ocs , np , "compatible" , "qcom,wcn7850-bt" );
201+ if (ret ) {
202+ dev_err (dev , "Failed to add bluetooth compatible: %d\n" , ret );
203+ goto err_destroy_changeset ;
204+ }
205+
206+ ret = of_changeset_apply (ctx -> ocs );
207+ if (ret ) {
208+ dev_err (dev , "Failed to apply changeset: %d\n" , ret );
209+ goto err_destroy_changeset ;
210+ }
211+
212+ ret = device_add_of_node (& ctx -> serdev -> dev , np );
213+ if (ret ) {
214+ dev_err (dev , "Failed to add OF node: %d\n" , ret );
215+ goto err_revert_changeset ;
216+ }
217+
218+ return 0 ;
219+
220+ err_revert_changeset :
221+ of_changeset_revert (ctx -> ocs );
222+ err_destroy_changeset :
223+ of_changeset_destroy (ctx -> ocs );
224+ kfree (ctx -> ocs );
225+ ctx -> ocs = NULL ;
226+
227+ return ret ;
228+ }
229+
230+ static int pwrseq_pcie_m2_create_serdev (struct pwrseq_pcie_m2_ctx * ctx )
231+ {
232+ struct serdev_controller * serdev_ctrl ;
233+ struct device * dev = ctx -> dev ;
234+ int ret ;
235+
236+ struct device_node * serdev_parent __free (device_node ) =
237+ of_graph_get_remote_node (dev_of_node (ctx -> dev ), 3 , 0 );
238+ if (!serdev_parent )
239+ return 0 ;
240+
241+ serdev_ctrl = of_find_serdev_controller_by_node (serdev_parent );
242+ if (!serdev_ctrl )
243+ return 0 ;
244+
245+ /* Bail out if the device was already attached to this controller */
246+ if (serdev_ctrl -> serdev ) {
247+ serdev_controller_put (serdev_ctrl );
248+ return 0 ;
249+ }
250+
251+ ctx -> serdev = serdev_device_alloc (serdev_ctrl );
252+ if (!ctx -> serdev ) {
253+ ret = - ENOMEM ;
254+ goto err_put_ctrl ;
255+ }
256+
257+ ret = pwrseq_m2_pcie_create_bt_node (ctx , serdev_parent );
258+ if (ret )
259+ goto err_free_serdev ;
260+
261+ ret = serdev_device_add (ctx -> serdev );
262+ if (ret ) {
263+ dev_err (dev , "Failed to add serdev for WCN7850: %d\n" , ret );
264+ goto err_free_dt_node ;
265+ }
266+
267+ serdev_controller_put (serdev_ctrl );
268+
269+ return 0 ;
270+
271+ err_free_dt_node :
272+ device_remove_of_node (& ctx -> serdev -> dev );
273+ of_changeset_revert (ctx -> ocs );
274+ of_changeset_destroy (ctx -> ocs );
275+ kfree (ctx -> ocs );
276+ ctx -> ocs = NULL ;
277+ err_free_serdev :
278+ serdev_device_put (ctx -> serdev );
279+ ctx -> serdev = NULL ;
280+ err_put_ctrl :
281+ serdev_controller_put (serdev_ctrl );
282+
283+ return ret ;
284+ }
285+
286+ static void pwrseq_pcie_m2_remove_serdev (struct pwrseq_pcie_m2_ctx * ctx )
287+ {
288+ if (ctx -> serdev ) {
289+ device_remove_of_node (& ctx -> serdev -> dev );
290+ serdev_device_remove (ctx -> serdev );
291+ ctx -> serdev = NULL ;
292+ }
293+
294+ if (ctx -> ocs ) {
295+ of_changeset_revert (ctx -> ocs );
296+ of_changeset_destroy (ctx -> ocs );
297+ kfree (ctx -> ocs );
298+ ctx -> ocs = NULL ;
299+ }
300+ }
301+
302+ static int pwrseq_m2_pcie_notify (struct notifier_block * nb , unsigned long action ,
303+ void * data )
304+ {
305+ struct pwrseq_pcie_m2_ctx * ctx = container_of (nb , struct pwrseq_pcie_m2_ctx , nb );
306+ struct pci_dev * pdev = to_pci_dev (data );
307+ int ret ;
308+
309+ /*
310+ * Check whether the PCI device is associated with this M.2 connector or
311+ * not, by comparing the OF node of the PCI device parent and the Port 0
312+ * (PCIe) remote node parent OF node.
313+ */
314+ struct device_node * pci_parent __free (device_node ) =
315+ of_graph_get_remote_node (dev_of_node (ctx -> dev ), 0 , 0 );
316+ if (!pci_parent || (pci_parent != pdev -> dev .parent -> of_node ))
317+ return NOTIFY_DONE ;
318+
319+ switch (action ) {
320+ case BUS_NOTIFY_ADD_DEVICE :
321+ /* Create serdev device for WCN7850 */
322+ if (pdev -> vendor == PCI_VENDOR_ID_QCOM && pdev -> device == 0x1107 ) {
323+ ret = pwrseq_pcie_m2_create_serdev (ctx );
324+ if (ret )
325+ return notifier_from_errno (ret );
326+ }
327+ break ;
328+ case BUS_NOTIFY_REMOVED_DEVICE :
329+ /* Destroy serdev device for WCN7850 */
330+ if (pdev -> vendor == PCI_VENDOR_ID_QCOM && pdev -> device == 0x1107 )
331+ pwrseq_pcie_m2_remove_serdev (ctx );
332+
333+ break ;
334+ }
335+
336+ return NOTIFY_OK ;
337+ }
338+
339+ static bool pwrseq_pcie_m2_check_remote_node (struct device * dev , u8 port , u8 endpoint ,
340+ const char * node )
341+ {
342+ struct device_node * remote __free (device_node ) =
343+ of_graph_get_remote_node (dev_of_node (dev ), port , endpoint );
344+
345+ if (remote && of_node_name_eq (remote , node ))
346+ return true;
347+
348+ return false;
349+ }
350+
351+ /*
352+ * If the connector exposes a non-discoverable bus like UART, the respective
353+ * protocol device needs to be created manually with the help of the notifier
354+ * of the discoverable bus like PCIe.
355+ */
356+ static int pwrseq_pcie_m2_register_notifier (struct pwrseq_pcie_m2_ctx * ctx , struct device * dev )
357+ {
358+ int ret ;
359+
360+ /*
361+ * Register a PCI notifier for Key E connector that has PCIe as Port
362+ * 0/Endpoint 0 interface and Serial as Port 3/Endpoint 0 interface.
363+ */
364+ if (pwrseq_pcie_m2_check_remote_node (dev , 3 , 0 , "serial" )) {
365+ if (pwrseq_pcie_m2_check_remote_node (dev , 0 , 0 , "pcie" )) {
366+ ctx -> dev = dev ;
367+ ctx -> nb .notifier_call = pwrseq_m2_pcie_notify ;
368+ ret = bus_register_notifier (& pci_bus_type , & ctx -> nb );
369+ if (ret )
370+ return dev_err_probe (dev , ret ,
371+ "Failed to register notifier for serdev\n" );
372+ }
373+ }
374+
375+ return 0 ;
180376}
181377
182378static int pwrseq_pcie_m2_probe (struct platform_device * pdev )
@@ -190,6 +386,7 @@ static int pwrseq_pcie_m2_probe(struct platform_device *pdev)
190386 if (!ctx )
191387 return - ENOMEM ;
192388
389+ platform_set_drvdata (pdev , ctx );
193390 ctx -> of_node = of_node_get (dev -> of_node );
194391 ctx -> pdata = device_get_match_data (dev );
195392 if (!ctx -> pdata )
@@ -206,21 +403,21 @@ static int pwrseq_pcie_m2_probe(struct platform_device *pdev)
206403 return dev_err_probe (dev , ret ,
207404 "Failed to get all regulators\n" );
208405
406+ ctx -> num_vregs = ret ;
407+
209408 ctx -> w_disable1_gpio = devm_gpiod_get_optional (dev , "w-disable1" , GPIOD_OUT_HIGH );
210- if (IS_ERR (ctx -> w_disable1_gpio ))
211- return dev_err_probe (dev , PTR_ERR (ctx -> w_disable1_gpio ),
409+ if (IS_ERR (ctx -> w_disable1_gpio )) {
410+ ret = dev_err_probe (dev , PTR_ERR (ctx -> w_disable1_gpio ),
212411 "Failed to get the W_DISABLE_1# GPIO\n" );
412+ goto err_free_regulators ;
413+ }
213414
214415 ctx -> w_disable2_gpio = devm_gpiod_get_optional (dev , "w-disable2" , GPIOD_OUT_HIGH );
215- if (IS_ERR (ctx -> w_disable2_gpio ))
216- return dev_err_probe (dev , PTR_ERR (ctx -> w_disable2_gpio ),
416+ if (IS_ERR (ctx -> w_disable2_gpio )) {
417+ ret = dev_err_probe (dev , PTR_ERR (ctx -> w_disable2_gpio ),
217418 "Failed to get the W_DISABLE_2# GPIO\n" );
218-
219- ctx -> num_vregs = ret ;
220-
221- ret = devm_add_action_or_reset (dev , pwrseq_pcie_m2_free_regulators , ctx );
222- if (ret )
223- return ret ;
419+ goto err_free_regulators ;
420+ }
224421
225422 config .parent = dev ;
226423 config .owner = THIS_MODULE ;
@@ -229,11 +426,36 @@ static int pwrseq_pcie_m2_probe(struct platform_device *pdev)
229426 config .targets = ctx -> pdata -> targets ;
230427
231428 ctx -> pwrseq = devm_pwrseq_device_register (dev , & config );
232- if (IS_ERR (ctx -> pwrseq ))
233- return dev_err_probe (dev , PTR_ERR (ctx -> pwrseq ),
429+ if (IS_ERR (ctx -> pwrseq )) {
430+ ret = dev_err_probe (dev , PTR_ERR (ctx -> pwrseq ),
234431 "Failed to register the power sequencer\n" );
432+ goto err_free_regulators ;
433+ }
434+
435+ /*
436+ * Register a notifier for creating protocol devices for
437+ * non-discoverable busses like UART.
438+ */
439+ ret = pwrseq_pcie_m2_register_notifier (ctx , dev );
440+ if (ret )
441+ goto err_free_regulators ;
235442
236443 return 0 ;
444+
445+ err_free_regulators :
446+ regulator_bulk_free (ctx -> num_vregs , ctx -> regs );
447+
448+ return ret ;
449+ }
450+
451+ static void pwrseq_pcie_m2_remove (struct platform_device * pdev )
452+ {
453+ struct pwrseq_pcie_m2_ctx * ctx = platform_get_drvdata (pdev );
454+
455+ bus_unregister_notifier (& pci_bus_type , & ctx -> nb );
456+ pwrseq_pcie_m2_remove_serdev (ctx );
457+
458+ regulator_bulk_free (ctx -> num_vregs , ctx -> regs );
237459}
238460
239461static const struct of_device_id pwrseq_pcie_m2_of_match [] = {
@@ -255,6 +477,7 @@ static struct platform_driver pwrseq_pcie_m2_driver = {
255477 .of_match_table = pwrseq_pcie_m2_of_match ,
256478 },
257479 .probe = pwrseq_pcie_m2_probe ,
480+ .remove = pwrseq_pcie_m2_remove ,
258481};
259482module_platform_driver (pwrseq_pcie_m2_driver );
260483
0 commit comments