66 */
77
88#include <linux/clk.h>
9- #include <linux/clk-provider.h>
109#include <linux/console.h>
1110#include <linux/delay.h>
1211#include <linux/init.h>
6665#define AML_UART_RECV_IRQ (c ) ((c) & 0xff)
6766
6867/* AML_UART_REG5 bits */
68+ #define AML_UART_BAUD_MASK 0x7fffff
6969#define AML_UART_BAUD_USE BIT(23)
70+ #define AML_UART_BAUD_XTAL BIT(24)
7071
7172#define AML_UART_PORT_NUM 12
7273#define AML_UART_PORT_OFFSET 6
7576#define AML_UART_POLL_USEC 5
7677#define AML_UART_TIMEOUT_USEC 10000
7778
78- struct meson_uart_data {
79- struct clk * baud_clk ;
80- bool use_xtal_clk ;
81- };
82-
8379static struct uart_driver meson_uart_driver ;
8480
8581static struct uart_port * meson_ports [AML_UART_PORT_NUM ];
@@ -297,17 +293,19 @@ static int meson_uart_startup(struct uart_port *port)
297293
298294static void meson_uart_change_speed (struct uart_port * port , unsigned long baud )
299295{
300- struct meson_uart_data * private_data = port -> private_data ;
301296 u32 val ;
302297
303298 while (!meson_uart_tx_empty (port ))
304299 cpu_relax ();
305300
306- val = readl (port -> membase + AML_UART_REG5 );
301+ if (port -> uartclk == 24000000 ) {
302+ val = ((port -> uartclk / 3 ) / baud ) - 1 ;
303+ val |= AML_UART_BAUD_XTAL ;
304+ } else {
305+ val = ((port -> uartclk * 10 / (baud * 4 ) + 5 ) / 10 ) - 1 ;
306+ }
307307 val |= AML_UART_BAUD_USE ;
308308 writel (val , port -> membase + AML_UART_REG5 );
309-
310- clk_set_rate (private_data -> baud_clk , baud );
311309}
312310
313311static void meson_uart_set_termios (struct uart_port * port ,
@@ -365,13 +363,8 @@ static void meson_uart_set_termios(struct uart_port *port,
365363 writel (val , port -> membase + AML_UART_CONTROL );
366364
367365 baud = uart_get_baud_rate (port , termios , old , 50 , 4000000 );
368-
369- spin_unlock_irqrestore (& port -> lock , flags );
370-
371366 meson_uart_change_speed (port , baud );
372367
373- spin_lock_irqsave (& port -> lock , flags );
374-
375368 port -> read_status_mask = AML_UART_TX_FIFO_WERR ;
376369 if (iflags & INPCK )
377370 port -> read_status_mask |= AML_UART_PARITY_ERR |
@@ -402,19 +395,23 @@ static int meson_uart_verify_port(struct uart_port *port,
402395
403396static void meson_uart_release_port (struct uart_port * port )
404397{
405- struct meson_uart_data * private_data = port -> private_data ;
406-
407- clk_disable_unprepare ( private_data -> baud_clk );
398+ devm_iounmap ( port -> dev , port -> membase ) ;
399+ port -> membase = NULL ;
400+ devm_release_mem_region ( port -> dev , port -> mapbase , port -> mapsize );
408401}
409402
410403static int meson_uart_request_port (struct uart_port * port )
411404{
412- struct meson_uart_data * private_data = port -> private_data ;
413- int ret ;
405+ if (!devm_request_mem_region (port -> dev , port -> mapbase , port -> mapsize ,
406+ dev_name (port -> dev ))) {
407+ dev_err (port -> dev , "Memory region busy\n" );
408+ return - EBUSY ;
409+ }
414410
415- ret = clk_prepare_enable (private_data -> baud_clk );
416- if (ret )
417- return ret ;
411+ port -> membase = devm_ioremap (port -> dev , port -> mapbase ,
412+ port -> mapsize );
413+ if (!port -> membase )
414+ return - ENOMEM ;
418415
419416 return 0 ;
420417}
@@ -645,106 +642,57 @@ static struct uart_driver meson_uart_driver = {
645642 .cons = MESON_SERIAL_CONSOLE ,
646643};
647644
648- static const struct clk_div_table xtal_div_table [] = {
649- { 0 , 3 },
650- { 1 , 1 },
651- { 2 , 2 },
652- { 3 , 2 },
653- };
645+ static inline struct clk * meson_uart_probe_clock (struct device * dev ,
646+ const char * id )
647+ {
648+ struct clk * clk = NULL ;
649+ int ret ;
650+
651+ clk = devm_clk_get (dev , id );
652+ if (IS_ERR (clk ))
653+ return clk ;
654+
655+ ret = clk_prepare_enable (clk );
656+ if (ret ) {
657+ dev_err (dev , "couldn't enable clk\n" );
658+ return ERR_PTR (ret );
659+ }
660+
661+ devm_add_action_or_reset (dev ,
662+ (void (* )(void * ))clk_disable_unprepare ,
663+ clk );
654664
655- static u32 use_xtal_mux_table ;
665+ return clk ;
666+ }
656667
657- static int meson_uart_probe_clocks (struct uart_port * port )
668+ static int meson_uart_probe_clocks (struct platform_device * pdev ,
669+ struct uart_port * port )
658670{
659- struct meson_uart_data * private_data = port -> private_data ;
660- struct clk * clk_baud , * clk_xtal ;
661- struct clk_hw * hw , * clk81_div4_hw ;
662- char clk_name [32 ];
663- struct clk_parent_data use_xtal_mux_parents ;
671+ struct clk * clk_xtal = NULL ;
672+ struct clk * clk_pclk = NULL ;
673+ struct clk * clk_baud = NULL ;
664674
665- clk_baud = devm_clk_get (port -> dev , "baud" );
666- if (IS_ERR (clk_baud )) {
667- dev_err (port -> dev , "Failed to get the 'baud' clock\n" );
668- return PTR_ERR (clk_baud );
669- }
675+ clk_pclk = meson_uart_probe_clock (& pdev -> dev , "pclk" );
676+ if (IS_ERR (clk_pclk ))
677+ return PTR_ERR (clk_pclk );
670678
671- clk_xtal = devm_clk_get ( port -> dev , "xtal" );
679+ clk_xtal = meson_uart_probe_clock ( & pdev -> dev , "xtal" );
672680 if (IS_ERR (clk_xtal ))
673- return dev_err_probe (port -> dev , PTR_ERR (clk_xtal ),
674- "Failed to get the 'xtal' clock\n" );
675-
676- snprintf (clk_name , sizeof (clk_name ), "%s#%s" , dev_name (port -> dev ),
677- "clk81_div4" );
678- clk81_div4_hw = devm_clk_hw_register_fixed_factor (port -> dev ,
679- clk_name ,
680- __clk_get_name (clk_baud ),
681- CLK_SET_RATE_NO_REPARENT ,
682- 1 , 4 );
683- if (IS_ERR (clk81_div4_hw ))
684- return PTR_ERR (clk81_div4_hw );
685-
686- snprintf (clk_name , sizeof (clk_name ), "%s#%s" , dev_name (port -> dev ),
687- "xtal_div" );
688- hw = devm_clk_hw_register_divider_table (port -> dev ,
689- clk_name ,
690- __clk_get_name (clk_baud ),
691- CLK_SET_RATE_NO_REPARENT ,
692- port -> membase + AML_UART_REG5 ,
693- 26 , 2 ,
694- CLK_DIVIDER_ROUND_CLOSEST ,
695- xtal_div_table , NULL );
696- if (IS_ERR (hw ))
697- return PTR_ERR (hw );
698-
699- if (private_data -> use_xtal_clk ) {
700- use_xtal_mux_table = 1 ;
701- use_xtal_mux_parents .hw = hw ;
702- } else {
703- use_xtal_mux_parents .hw = clk81_div4_hw ;
704- }
681+ return PTR_ERR (clk_xtal );
682+
683+ clk_baud = meson_uart_probe_clock (& pdev -> dev , "baud" );
684+ if (IS_ERR (clk_baud ))
685+ return PTR_ERR (clk_baud );
705686
706- snprintf (clk_name , sizeof (clk_name ), "%s#%s" , dev_name (port -> dev ),
707- "use_xtal" );
708- hw = __devm_clk_hw_register_mux (port -> dev , NULL ,
709- clk_name ,
710- 1 ,
711- NULL , NULL ,
712- & use_xtal_mux_parents ,
713- CLK_SET_RATE_PARENT ,
714- port -> membase + AML_UART_REG5 ,
715- 24 , 0x1 ,
716- CLK_MUX_ROUND_CLOSEST ,
717- & use_xtal_mux_table , NULL );
718-
719- if (IS_ERR (hw ))
720- return PTR_ERR (hw );
721-
722- port -> uartclk = clk_hw_get_rate (hw );
723-
724- snprintf (clk_name , sizeof (clk_name ), "%s#%s" , dev_name (port -> dev ),
725- "baud_div" );
726- hw = devm_clk_hw_register_divider (port -> dev ,
727- clk_name ,
728- clk_hw_get_name (hw ),
729- CLK_SET_RATE_PARENT ,
730- port -> membase + AML_UART_REG5 ,
731- 0 , 23 ,
732- CLK_DIVIDER_ROUND_CLOSEST ,
733- NULL );
734- if (IS_ERR (hw ))
735- return PTR_ERR (hw );
736-
737- private_data -> baud_clk = hw -> clk ;
687+ port -> uartclk = clk_get_rate (clk_baud );
738688
739689 return 0 ;
740690}
741691
742692static int meson_uart_probe (struct platform_device * pdev )
743693{
744- struct meson_uart_data * private_data ;
745694 struct resource * res_mem ;
746695 struct uart_port * port ;
747- struct clk * pclk ;
748696 u32 fifosize = 64 ; /* Default is 64, 128 for EE UART_0 */
749697 int ret = 0 ;
750698 int irq ;
@@ -770,15 +718,6 @@ static int meson_uart_probe(struct platform_device *pdev)
770718 if (!res_mem )
771719 return - ENODEV ;
772720
773- pclk = devm_clk_get (& pdev -> dev , "pclk" );
774- if (IS_ERR (pclk ))
775- return dev_err_probe (& pdev -> dev , PTR_ERR (pclk ),
776- "Failed to get the 'pclk' clock\n" );
777-
778- ret = clk_prepare_enable (pclk );
779- if (ret )
780- return ret ;
781-
782721 irq = platform_get_irq (pdev , 0 );
783722 if (irq < 0 )
784723 return irq ;
@@ -794,17 +733,9 @@ static int meson_uart_probe(struct platform_device *pdev)
794733 if (!port )
795734 return - ENOMEM ;
796735
797- port -> membase = devm_ioremap_resource (& pdev -> dev , res_mem );
798- if (IS_ERR (port -> membase ))
799- return PTR_ERR (port -> membase );
800-
801- private_data = devm_kzalloc (& pdev -> dev , sizeof (* private_data ),
802- GFP_KERNEL );
803- if (!private_data )
804- return - ENOMEM ;
805-
806- if (device_get_match_data (& pdev -> dev ))
807- private_data -> use_xtal_clk = true;
736+ ret = meson_uart_probe_clocks (pdev , port );
737+ if (ret )
738+ return ret ;
808739
809740 port -> iotype = UPIO_MEM ;
810741 port -> mapbase = res_mem -> start ;
@@ -818,17 +749,15 @@ static int meson_uart_probe(struct platform_device *pdev)
818749 port -> x_char = 0 ;
819750 port -> ops = & meson_uart_ops ;
820751 port -> fifosize = fifosize ;
821- port -> private_data = private_data ;
822-
823- ret = meson_uart_probe_clocks (port );
824- if (ret )
825- return ret ;
826752
827753 meson_ports [pdev -> id ] = port ;
828754 platform_set_drvdata (pdev , port );
829755
830756 /* reset port before registering (and possibly registering console) */
831- meson_uart_reset (port );
757+ if (meson_uart_request_port (port ) >= 0 ) {
758+ meson_uart_reset (port );
759+ meson_uart_release_port (port );
760+ }
832761
833762 ret = uart_add_one_port (& meson_uart_driver , port );
834763 if (ret )
@@ -849,26 +778,10 @@ static int meson_uart_remove(struct platform_device *pdev)
849778}
850779
851780static const struct of_device_id meson_uart_dt_match [] = {
852- {
853- .compatible = "amlogic,meson6-uart" ,
854- .data = (void * )false,
855- },
856- {
857- .compatible = "amlogic,meson8-uart" ,
858- .data = (void * )false,
859- },
860- {
861- .compatible = "amlogic,meson8b-uart" ,
862- .data = (void * )false,
863- },
864- {
865- .compatible = "amlogic,meson-gx-uart" ,
866- .data = (void * )true,
867- },
868- {
869- .compatible = "amlogic,meson-s4-uart" ,
870- .data = (void * )true,
871- },
781+ { .compatible = "amlogic,meson6-uart" },
782+ { .compatible = "amlogic,meson8-uart" },
783+ { .compatible = "amlogic,meson8b-uart" },
784+ { .compatible = "amlogic,meson-gx-uart" },
872785 { /* sentinel */ },
873786};
874787MODULE_DEVICE_TABLE (of , meson_uart_dt_match );
0 commit comments