1313#include <linux/module.h>
1414#include <linux/of.h>
1515#include <linux/of_address.h>
16+ #include <linux/of_device.h>
1617#include <linux/platform_device.h>
1718#include <linux/poll.h>
1819#include <linux/regmap.h>
@@ -63,6 +64,10 @@ struct aspeed_kcs_bmc {
6364 struct regmap * map ;
6465};
6566
67+ struct aspeed_kcs_of_ops {
68+ int (* get_channel )(struct platform_device * pdev );
69+ int (* get_io_address )(struct platform_device * pdev );
70+ };
6671
6772static u8 aspeed_kcs_inb (struct kcs_bmc * kcs_bmc , u32 reg )
6873{
@@ -231,119 +236,92 @@ static const struct kcs_ioreg ast_kcs_bmc_ioregs[KCS_CHANNEL_MAX] = {
231236 { .idr = LPC_IDR4 , .odr = LPC_ODR4 , .str = LPC_STR4 },
232237};
233238
234- static struct kcs_bmc * aspeed_kcs_probe_of_v1 (struct platform_device * pdev )
239+ static int aspeed_kcs_of_v1_get_channel (struct platform_device * pdev )
235240{
236- struct aspeed_kcs_bmc * priv ;
237241 struct device_node * np ;
238- struct kcs_bmc * kcs ;
239242 u32 channel ;
240- u32 slave ;
241243 int rc ;
242244
243245 np = pdev -> dev .of_node ;
244246
245247 rc = of_property_read_u32 (np , "kcs_chan" , & channel );
246248 if ((rc != 0 ) || (channel == 0 || channel > KCS_CHANNEL_MAX )) {
247249 dev_err (& pdev -> dev , "no valid 'kcs_chan' configured\n" );
248- return ERR_PTR (- EINVAL );
249- }
250-
251- kcs = kcs_bmc_alloc (& pdev -> dev , sizeof (struct aspeed_kcs_bmc ), channel );
252- if (!kcs )
253- return ERR_PTR (- ENOMEM );
254-
255- priv = kcs_bmc_priv (kcs );
256- priv -> map = syscon_node_to_regmap (pdev -> dev .parent -> of_node );
257- if (IS_ERR (priv -> map )) {
258- dev_err (& pdev -> dev , "Couldn't get regmap\n" );
259- return ERR_PTR (- ENODEV );
260- }
261-
262- rc = of_property_read_u32 (np , "kcs_addr" , & slave );
263- if (rc ) {
264- dev_err (& pdev -> dev , "no valid 'kcs_addr' configured\n" );
265- return ERR_PTR (- EINVAL );
250+ return - EINVAL ;
266251 }
267252
268- kcs -> ioreg = ast_kcs_bmc_ioregs [channel - 1 ];
269- aspeed_kcs_set_address (kcs , slave );
270-
271- return kcs ;
253+ return channel ;
272254}
273255
274- static int aspeed_kcs_calculate_channel ( const struct kcs_ioreg * regs )
256+ static int aspeed_kcs_of_v1_get_io_address ( struct platform_device * pdev )
275257{
276- int i ;
258+ u32 slave ;
259+ int rc ;
277260
278- for (i = 0 ; i < ARRAY_SIZE (ast_kcs_bmc_ioregs ); i ++ ) {
279- if (!memcmp (& ast_kcs_bmc_ioregs [i ], regs , sizeof (* regs )))
280- return i + 1 ;
261+ rc = of_property_read_u32 (pdev -> dev .of_node , "kcs_addr" , & slave );
262+ if (rc || slave > 0xffff ) {
263+ dev_err (& pdev -> dev , "no valid 'kcs_addr' configured\n" );
264+ return - EINVAL ;
281265 }
282266
283- return - EINVAL ;
267+ return slave ;
284268}
285269
286- static struct kcs_bmc * aspeed_kcs_probe_of_v2 (struct platform_device * pdev )
270+ static int aspeed_kcs_of_v2_get_channel (struct platform_device * pdev )
287271{
288- struct aspeed_kcs_bmc * priv ;
289272 struct device_node * np ;
290273 struct kcs_ioreg ioreg ;
291- struct kcs_bmc * kcs ;
292274 const __be32 * reg ;
293- int channel ;
294- u32 slave ;
295- int rc ;
275+ int i ;
296276
297277 np = pdev -> dev .of_node ;
298278
299279 /* Don't translate addresses, we want offsets for the regmaps */
300280 reg = of_get_address (np , 0 , NULL , NULL );
301281 if (!reg )
302- return ERR_PTR ( - EINVAL ) ;
282+ return - EINVAL ;
303283 ioreg .idr = be32_to_cpup (reg );
304284
305285 reg = of_get_address (np , 1 , NULL , NULL );
306286 if (!reg )
307- return ERR_PTR ( - EINVAL ) ;
287+ return - EINVAL ;
308288 ioreg .odr = be32_to_cpup (reg );
309289
310290 reg = of_get_address (np , 2 , NULL , NULL );
311291 if (!reg )
312- return ERR_PTR ( - EINVAL ) ;
292+ return - EINVAL ;
313293 ioreg .str = be32_to_cpup (reg );
314294
315- channel = aspeed_kcs_calculate_channel (& ioreg );
316- if (channel < 0 )
317- return ERR_PTR (channel );
295+ for (i = 0 ; i < ARRAY_SIZE (ast_kcs_bmc_ioregs ); i ++ ) {
296+ if (!memcmp (& ast_kcs_bmc_ioregs [i ], & ioreg , sizeof (ioreg )))
297+ return i + 1 ;
298+ }
318299
319- kcs = kcs_bmc_alloc (& pdev -> dev , sizeof (struct aspeed_kcs_bmc ), channel );
320- if (!kcs )
321- return ERR_PTR (- ENOMEM );
300+ return - EINVAL ;
301+ }
322302
323- kcs -> ioreg = ioreg ;
303+ static int aspeed_kcs_of_v2_get_io_address (struct platform_device * pdev )
304+ {
305+ uint32_t slave ;
306+ int rc ;
324307
325- priv = kcs_bmc_priv (kcs );
326- priv -> map = syscon_node_to_regmap (pdev -> dev .parent -> of_node );
327- if (IS_ERR (priv -> map )) {
328- dev_err (& pdev -> dev , "Couldn't get regmap\n" );
329- return ERR_PTR (- ENODEV );
308+ rc = of_property_read_u32 (pdev -> dev .of_node , "aspeed,lpc-io-reg" , & slave );
309+ if (rc || slave > 0xffff ) {
310+ dev_err (& pdev -> dev , "no valid 'aspeed,lpc-io-reg' configured\n" );
311+ return - EINVAL ;
330312 }
331313
332- rc = of_property_read_u32 (np , "aspeed,lpc-io-reg" , & slave );
333- if (rc )
334- return ERR_PTR (rc );
335-
336- aspeed_kcs_set_address (kcs , slave );
337-
338- return kcs ;
314+ return slave ;
339315}
340316
341317static int aspeed_kcs_probe (struct platform_device * pdev )
342318{
319+ const struct aspeed_kcs_of_ops * ops ;
343320 struct device * dev = & pdev -> dev ;
321+ struct aspeed_kcs_bmc * priv ;
344322 struct kcs_bmc * kcs_bmc ;
345323 struct device_node * np ;
346- int rc ;
324+ int rc , channel , addr ;
347325
348326 np = dev -> of_node -> parent ;
349327 if (!of_device_is_compatible (np , "aspeed,ast2400-lpc-v2" ) &&
@@ -352,23 +330,35 @@ static int aspeed_kcs_probe(struct platform_device *pdev)
352330 dev_err (dev , "unsupported LPC device binding\n" );
353331 return - ENODEV ;
354332 }
355-
356- np = dev -> of_node ;
357- if (of_device_is_compatible (np , "aspeed,ast2400-kcs-bmc" ) ||
358- of_device_is_compatible (np , "aspeed,ast2500-kcs-bmc" ))
359- kcs_bmc = aspeed_kcs_probe_of_v1 (pdev );
360- else if (of_device_is_compatible (np , "aspeed,ast2400-kcs-bmc-v2" ) ||
361- of_device_is_compatible (np , "aspeed,ast2500-kcs-bmc-v2" ))
362- kcs_bmc = aspeed_kcs_probe_of_v2 (pdev );
363- else
333+ ops = of_device_get_match_data (& pdev -> dev );
334+ if (!ops )
364335 return - EINVAL ;
365336
366- if (IS_ERR (kcs_bmc ))
367- return PTR_ERR (kcs_bmc );
337+ channel = ops -> get_channel (pdev );
338+ if (channel < 0 )
339+ return channel ;
340+
341+ kcs_bmc = kcs_bmc_alloc (& pdev -> dev , sizeof (struct aspeed_kcs_bmc ), channel );
342+ if (!kcs_bmc )
343+ return - ENOMEM ;
368344
345+ kcs_bmc -> ioreg = ast_kcs_bmc_ioregs [channel - 1 ];
369346 kcs_bmc -> io_inputb = aspeed_kcs_inb ;
370347 kcs_bmc -> io_outputb = aspeed_kcs_outb ;
371348
349+ addr = ops -> get_io_address (pdev );
350+ if (addr < 0 )
351+ return addr ;
352+
353+ priv = kcs_bmc_priv (kcs_bmc );
354+ priv -> map = syscon_node_to_regmap (pdev -> dev .parent -> of_node );
355+ if (IS_ERR (priv -> map )) {
356+ dev_err (& pdev -> dev , "Couldn't get regmap\n" );
357+ return - ENODEV ;
358+ }
359+
360+ aspeed_kcs_set_address (kcs_bmc , addr );
361+
372362 rc = aspeed_kcs_config_irq (kcs_bmc , pdev );
373363 if (rc )
374364 return rc ;
@@ -400,11 +390,21 @@ static int aspeed_kcs_remove(struct platform_device *pdev)
400390 return 0 ;
401391}
402392
393+ static const struct aspeed_kcs_of_ops of_v1_ops = {
394+ .get_channel = aspeed_kcs_of_v1_get_channel ,
395+ .get_io_address = aspeed_kcs_of_v1_get_io_address ,
396+ };
397+
398+ static const struct aspeed_kcs_of_ops of_v2_ops = {
399+ .get_channel = aspeed_kcs_of_v2_get_channel ,
400+ .get_io_address = aspeed_kcs_of_v2_get_io_address ,
401+ };
402+
403403static const struct of_device_id ast_kcs_bmc_match [] = {
404- { .compatible = "aspeed,ast2400-kcs-bmc" },
405- { .compatible = "aspeed,ast2500-kcs-bmc" },
406- { .compatible = "aspeed,ast2400-kcs-bmc-v2" },
407- { .compatible = "aspeed,ast2500-kcs-bmc-v2" },
404+ { .compatible = "aspeed,ast2400-kcs-bmc" , . data = & of_v1_ops },
405+ { .compatible = "aspeed,ast2500-kcs-bmc" , . data = & of_v1_ops },
406+ { .compatible = "aspeed,ast2400-kcs-bmc-v2" , . data = & of_v2_ops },
407+ { .compatible = "aspeed,ast2500-kcs-bmc-v2" , . data = & of_v2_ops },
408408 { }
409409};
410410MODULE_DEVICE_TABLE (of , ast_kcs_bmc_match );
0 commit comments